using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.DotNetBar.SuperGrid.Primitives;
using DevComponents.DotNetBar.SuperGrid.Style;
using DevComponents.SuperGrid.TextMarkup;
namespace DevComponents.DotNetBar.SuperGrid
{
    /// 
    /// Represents a layout of column headers
    /// 
    [TypeConverter(typeof(BlankExpandableObjectConverter))]
    public class GridColumnHeader : GridElement
    {
        #region Constants
        private const int SeparatorWidth = 2;
        private const int ImageCacheSize = 8;
        #endregion
        #region Static data
        private static object _lastSelectedItem;
        #endregion
        #region Private variables
        private GridColumnCollection _Columns;
        private ColumnGroupHeaderCollection _GroupHeaders;
        private HeaderArea _HitArea;
        private object _HitItem;
        private HeaderArea _LastHitArea;
        private object _LastHitItem;
        private GridColumn _ResizeColumn;
        private int _MouseDownDelta;
        private HeaderArea _MouseDownHitArea;
        private object _MouseDownHitItem;
        private Point _MouseDownPoint;
        private MouseButtons _MouseDownButtons;
        private bool _DragSelection;
        private bool _DragStarted;
        private bool _Reordering;
        private bool _Resizing;
        private int _ResizeWidth;
        private int _MinRowHeight;
        private int _RowHeight;
        private GridColumn _SeparatorColumn;
        private bool _SeparatorIsRight;
        private FloatWindow _HeaderFw;
        private FloatWindow _SeparatorFw;
        private int _OrderTextOffset;
        private int _SelectAllCount;
        private ColumnHeaderRowVisualStyles _EffectiveRowHeaderStyles;
        private int _StyleUpdateCount;
        private bool _ShowHeaderImages = true;
        private Image _AscendingSortImage;
        private int _AscendingSortImageIndex = -1;
        private Image[] _AscendingSortCacheImages = new Image[ImageCacheSize];
        private Image _DescendingSortImage;
        private int _DescendingSortImageIndex = -1;
        private Image[] _DescendingSortCacheImages = new Image[ImageCacheSize];
        private Alignment _SortImageAlignment = Alignment.NotSet;
        private Image _FilterImage;
        private int _FilterImageIndex = -1;
        private Image[] _FilterCacheImages = new Image[ImageCacheSize * 2];
        private ImageVisibility _FilterImageVisibility = ImageVisibility.Auto;
        private Alignment _FilterImageAlignment = Alignment.NotSet;
        private FilterPopup _FilterMenu;
        private bool _LockedColumn;
        private bool _ShowFilterToolTips = true;
        private bool _ShowToolTips = true;
        private bool _ShowGroupColumnHeaders = true;
        private bool _AutoApplyGroupColors = true;
        private string _RowHeaderText;
        #endregion
        #region Internal properties
        #region Columns
        internal GridColumnCollection Columns
        {
            get { return (_Columns); }
            set { _Columns = value; }
        }
        #endregion
        #region RowHeaderBounds
        internal Rectangle RowHeaderBounds
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    Rectangle r = Bounds;
                    r.Width = panel.RowHeaderWidthEx;
                    return (r);
                }
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region SelectAllCount
        internal int SelectAllCount
        {
            get { return (_SelectAllCount); }
            set { _SelectAllCount = value; }
        }
        #endregion
        #endregion
        #region Public properties
        #region AscendingSortImage
        /// 
        /// Gets or sets the Ascending sort image
        /// 
        [DefaultValue(null), Category("Appearance")]
        [Description("Indicates the Ascending sort image.")]
        public Image AscendingSortImage
        {
            get { return (_AscendingSortImage); }
            set
            {
                if (_AscendingSortImage != value)
                {
                    _AscendingSortImage = value;
                    OnPropertyChangedEx("AscendingSortImage", VisualChangeType.Render);
                }
            }
        }
        #region GetAscendingSortImage
        internal Image GetAscendingSortImage(GridColumn column)
        {
            if (_AscendingSortImage != null)
                return (_AscendingSortImage);
            if (_AscendingSortImageIndex >= 0)
            {
                ImageList imageList = GridPanel.ImageList;
                if (imageList != null && _AscendingSortImageIndex < imageList.Images.Count)
                    return (imageList.Images[_AscendingSortImageIndex]);
            }
            return (GetAscendingSortImageEx(column));
        }
        #region GetAscendingSortImageEx
        internal Image GetAscendingSortImageEx(GridColumn column)
        {
            StyleState state = GetStyleState(column, column.IsSelected);
            Image cacheImage = _AscendingSortCacheImages[(int)state];
            if (cacheImage == null)
            {
                int width = Dpi.Width5;
                int height = Dpi.Height3;
                if ((width % 2) == 0)
                    width++;
                Rectangle r = new Rectangle(0, 0, width, height);
                Image image = new Bitmap(width, height);
                using (Graphics g = Graphics.FromImage(image))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        Point pt = new Point(r.X + r.Width / 2, r.Top);
                        Point[] pts =
                        {
                            pt,
                            new Point(r.Right - 1, r.Bottom - 1),
                            new Point(r.Left, r.Bottom - 1),
                            pt
                        };
                        path.AddLines(pts);
                        ColumnHeaderRowVisualStyle style = GetEffectiveRowHeaderStyleEx(state);
                        Color color = style.SortIndicatorColor;
                        if (color.IsEmpty)
                            color = Color.Black;
                        using (Brush br = new SolidBrush(color))
                            g.FillPath(br, path);
                        using (Pen pen = new Pen(color))
                            g.DrawPath(pen, path);
                    }
                }
                _AscendingSortCacheImages[(int)state] = image;
                cacheImage = image;
            }
            return (cacheImage);
        }
        #endregion
        #endregion
        #endregion
        #region AscendingSortImageIndex
        /// 
        /// Gets or sets the Ascending Sort Image index
        /// 
        [Browsable(true), DefaultValue(-1)]
        [Category("Appearance"), Description("Indicates the Ascending Sort Image index.")]
        [Editor("DevComponents.SuperGrid.Design.ImageIndexEditor, DevComponents.SuperGrid.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=26d81176cfa2b486", typeof(UITypeEditor))]
        [TypeConverter(typeof(ImageIndexConverter))]
        public int AscendingSortImageIndex
        {
            get { return (_AscendingSortImageIndex); }
            set
            {
                if (_AscendingSortImageIndex != value)
                {
                    _AscendingSortImageIndex = value;
                    OnPropertyChangedEx("AscendingSortImageIndex", VisualChangeType.Layout);
                }
            }
        }
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        private void ResetAscendingSortImageIndex()
        {
            _AscendingSortImageIndex = -1;
        }
        #endregion
        #region AutoApplyGroupColors
        /// 
        /// Gets or sets whether Group Header color properties
        /// (ie. Background and TextColor) are automatically
        /// applied to group Column Headers.
        /// 
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether Group Header color properties (ie. Background and TextColor) are automatically applied to group Column Headers.")]
        public bool AutoApplyGroupColors
        {
            get { return (_AutoApplyGroupColors); }
            set
            {
                if (_AutoApplyGroupColors != value)
                {
                    _AutoApplyGroupColors = value;
                    OnPropertyChangedEx("AutoApplyGroupColors", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region Bounds
        ///
        /// Gets the scroll adjusted bounds
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Rectangle Bounds
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    Rectangle r = BoundsRelative;
                    if (panel.IsSubPanel == true)
                    {
                        r.X -= HScrollOffset;
                        if (IsVFrozen == false)
                            r.Y -= VScrollOffset;
                    }
                    return (r);
                }
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region DescendingSortImage
        /// 
        /// Gets or sets the Descending sort image
        /// 
        [DefaultValue(null), Category("Appearance")]
        [Description("Indicates the Descending sort image.")]
        public Image DescendingSortImage
        {
            get { return (_DescendingSortImage); }
            set
            {
                if (_DescendingSortImage != value)
                {
                    _DescendingSortImage = value;
                    OnPropertyChangedEx("DescendingSortImage", VisualChangeType.Render);
                }
            }
        }
        #region GetDescendingSortImage
        internal Image GetDescendingSortImage(GridColumn column)
        {
            if (_DescendingSortImage != null)
                return (_DescendingSortImage);
            if (_DescendingSortImageIndex >= 0)
            {
                ImageList imageList = GridPanel.ImageList;
                if (imageList != null && _DescendingSortImageIndex < imageList.Images.Count)
                    return (imageList.Images[_DescendingSortImageIndex]);
            }
            return (GetDescendingSortImageEx(column));
        }
        #region GetDescendingSortImageEx
        internal Image GetDescendingSortImageEx(GridColumn column)
        {
            StyleState state = GetStyleState(column, column.IsSelected);
            Image cacheImage = _DescendingSortCacheImages[(int)state];
            if (cacheImage == null)
            {
                int width = Dpi.Width5;
                int height = Dpi.Height3;
                if ((width % 2) == 0)
                    width++;
                Rectangle r = new Rectangle(0, 0, width, height);
                Image image = new Bitmap(width, height);
                using (Graphics g = Graphics.FromImage(image))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        Point pt = new Point(r.X + width / 2, r.Bottom - 1);
                        Point[] pts =
                        {
                            pt,
                            new Point(r.Right - 1, r.Top),
                            new Point(r.Left, r.Top),
                            pt
                        };
                        path.AddLines(pts);
                        ColumnHeaderRowVisualStyle style = GetEffectiveRowHeaderStyleEx(state);
                        Color color = style.SortIndicatorColor;
                        if (color.IsEmpty)
                            color = Color.Black;
                        using (Brush br = new SolidBrush(color))
                            g.FillPath(br, path);
                        using (Pen pen = new Pen(color))
                            g.DrawPath(pen, path);
                    }
                }
                _DescendingSortCacheImages[(int)state] = image;
                cacheImage = image;
            }
            return (cacheImage);
        }
        #endregion
        #endregion
        #endregion
        #region DescendingSortImageIndex
        /// 
        /// Gets or sets the Descending Sort Image index
        /// 
        [Browsable(true), DefaultValue(-1)]
        [Category("Appearance"), Description("Indicates the Descending Sort Image index.")]
        [Editor("DevComponents.SuperGrid.Design.ImageIndexEditor, DevComponents.SuperGrid.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=26d81176cfa2b486", typeof(UITypeEditor))]
        [TypeConverter(typeof(ImageIndexConverter))]
        public int DescendingSortImageIndex
        {
            get { return (_DescendingSortImageIndex); }
            set
            {
                if (_DescendingSortImageIndex != value)
                {
                    _DescendingSortImageIndex = value;
                    OnPropertyChangedEx("DescendingSortImageIndex", VisualChangeType.Layout);
                }
            }
        }
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        private void ResetDescendingSortImageIndex()
        {
            _DescendingSortImageIndex = -1;
        }
        #endregion
        #region FilterImage
        /// 
        /// Gets or sets the default
        /// image to display in the column header.
        /// 
        [DefaultValue(null), Category("Filtering")]
        [Description("Indicates the default image to display in the column header.")]
        public Image FilterImage
        {
            get { return (_FilterImage); }
            set
            {
                if (_FilterImage != value)
                {
                    _FilterImage = value;
                    NeedsMeasured = true;
                    OnPropertyChangedEx("FilterImage", VisualChangeType.Layout);
                }
            }
        }
        #region GetFilterImage
        internal Image GetFilterImage(GridColumn column)
        {
            bool inFilter;
            StyleState state = GetFilterImageState(column, out inFilter);
            return (GetFilterImage(column, state, inFilter));
        }
        internal Image GetFilterImage(
            GridColumn column, StyleState state, bool inFilter)
        {
            if (_FilterImage != null)
                return (_FilterImage);
            if (_FilterImageIndex >= 0)
            {
                ImageList imageList = GridPanel.ImageList;
                if (imageList != null && _FilterImageIndex < imageList.Images.Count)
                    return (imageList.Images[_FilterImageIndex]);
            }
            return (GetFilterImageEx(state, inFilter));
        }
        #region GetFilterImageEx
        private Image GetFilterImageEx(StyleState state, bool inFilter)
        {
            int n = (int)state;
            if (inFilter == true)
                n += ImageCacheSize;
            Image cacheImage = _FilterCacheImages[n];
            if (cacheImage == null)
            {
                Image image = new Bitmap(Dpi.Width8, Dpi.Height8);
                using (Graphics g = Graphics.FromImage(image))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        Point[] pts =
                        {
                            new Point(0, 0),
                            new Point(Dpi.Width7, 0),
                            new Point(Dpi.Width7, Dpi.Height1),
                            new Point(Dpi.Width4, Dpi.Height4),
                            new Point(Dpi.Width4, Dpi.Height7),
                            new Point(Dpi.Width3, Dpi.Height6),
                            new Point(Dpi.Width3, Dpi.Height4),
                            new Point(0, Dpi.Height1),
                            new Point(0, 0),
                        };
                        path.AddLines(pts);
                        Rectangle r = new Rectangle(Dpi.Width1, Dpi.Height1, Dpi.Width6, Dpi.Height3);
                        ColumnHeaderRowVisualStyle style = GetEffectiveRowHeaderStyleEx(state);
                        Color color = style.FilterBorderColor;
                        if (color.IsEmpty)
                            color = Color.DimGray;
                        if (inFilter == false)
                            style = GetEffectiveRowHeaderStyleEx(state & ~StyleState.MouseOver);
                        Background back = (style.FilterBackground != null && style.FilterBackground.IsEmpty == false)
                            ? style.FilterBackground : new Background(Color.White);
                        using (Brush br = back.GetBrush(r))
                            g.FillPath(br, path);
                        using (Pen pen = new Pen(color))
                            g.DrawPath(pen, path);
                    }
                }
                _FilterCacheImages[n] = image;
                cacheImage = image;
            }
            return (cacheImage);
        }
        #region GetFilterImageState
        private StyleState GetFilterImageState(GridColumn column, out bool inFilter)
        {
            inFilter = false;
            StyleState state = GetRowHeaderState();
            state &= ~(StyleState.MouseOver | StyleState.Selected);
            GridColumn hitColumn = _HitItem as GridColumn;
            if (column == hitColumn)
            {
                state |= StyleState.MouseOver;
                if (_HitArea == HeaderArea.InFilterMenu)
                    inFilter = true;
            }
            if (column != null && string.IsNullOrEmpty(column.FilterExpr) == false)
                state |= StyleState.Selected;
            return (state);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region FilterImageAlignment
        /// 
        /// Gets or sets the alignment of the filter Image
        /// 
        [DefaultValue(Alignment.NotSet), Category("Appearance")]
        [Description("Indicates the alignment of the filter Image.")]
        public Alignment FilterImageAlignment
        {
            get { return (_FilterImageAlignment); }
            set
            {
                if (_FilterImageAlignment != value)
                {
                    _FilterImageAlignment = value;
                    OnPropertyChangedEx("FilterImageAlignment", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region FilterImageIndex
        /// 
        /// Gets or sets the Filter image index
        /// 
        [Browsable(true), DefaultValue(-1)]
        [Category("Appearance"), Description("Indicates the Filter Row image index.")]
        [Editor("DevComponents.SuperGrid.Design.ImageIndexEditor, DevComponents.SuperGrid.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=26d81176cfa2b486", typeof(UITypeEditor))]
        [TypeConverter(typeof(ImageIndexConverter))]
        public int FilterImageIndex
        {
            get { return (_FilterImageIndex); }
            set
            {
                if (_FilterImageIndex != value)
                {
                    _FilterImageIndex = value;
                    OnPropertyChangedEx("FilterImageIndex", VisualChangeType.Layout);
                }
            }
        }
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        private void ResetFilterImageIndex()
        {
            _FilterImageIndex = -1;
        }
        #endregion
        #region FilterImageVisibility
        /// 
        /// Gets or sets the visibility of the header filter image
        /// 
        [DefaultValue(ImageVisibility.Auto), Category("Filtering")]
        [Description("Indicates the visibility of the header filter image.")]
        public ImageVisibility FilterImageVisibility
        {
            get { return (_FilterImageVisibility); }
            set
            {
                if (_FilterImageVisibility != value)
                {
                    _FilterImageVisibility = value;
                    OnPropertyChangedEx("FilterImageVisibility", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region GroupHeaders
        /// 
        /// Gets a reference to the collection of grid columns
        /// 
        [Category("Appearance")]
        [Description("Indicates the collection of grid columns.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ColumnGroupHeaderCollection GroupHeaders
        {
            get
            {
                if (_GroupHeaders == null)
                {
                    _GroupHeaders = new ColumnGroupHeaderCollection();
                    _GroupHeaders.Parent = this;
                    _GroupHeaders.CollectionChanged += GroupHeadersCollectionChanged;
                    _GroupHeaders.PropertyChanged += GroupHeadersPropertyChanged;
                    _GroupHeaders.GroupHeaderMarkupLinkClick += GroupHeaderMarkupLinkClick;
                }
                return (_GroupHeaders);
            }
        }
        #region GroupHeadersCollectionChanged
        void GroupHeadersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            NeedsMeasured = true;
            SuperGrid.StyleUpdateCount++;
            InvalidateLayout();
        }
        #endregion
        #region GroupHeadersPropertyChanged
        void GroupHeadersPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NeedsMeasured = true;
            InvalidateStyle();
            InvalidateLayout();
        }
        #endregion
        #region GroupHeadersMarkupLinkClick
        void GroupHeaderMarkupLinkClick(object sender, GroupHeaderMarkupLinkClickEventArgs e)
        {
            SuperGrid.DoColumnGroupHeaderMarkupLinkClickEvent(
                GridPanel, this, e.GroupHeader, e.HyperLink);
        }
        #endregion
        #endregion
        #region MinRowHeight
        ///
        /// Gets or sets the minimum height of the ColumnHeader row
        ///
        [DefaultValue(0), Category("Style")]
        [Description("Indicates the minimum height of the ColumnHeader row")]
        public int MinRowHeight
        {
            get { return (_MinRowHeight); }
            set
            {
                if (_MinRowHeight != value)
                {
                    if (value < 0)
                        throw new Exception("MinRowHeight cannot be negative");
                    _MinRowHeight = value;
                    NeedsMeasured = true;
                    OnPropertyChangedEx("MinRowHeight", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region RowHeaderText
        ///
        /// Gets or sets the associated row header text (only
        /// displayed if TopLeftHeaderSelectBehavior is set to NoSelection).
        ///
        [DefaultValue(null), Category("Appearance")]
        [Description("Indicates the associated row header text (only displayed if TopLeftHeaderSelectBehavior is set to NoSelection).")]
        public string RowHeaderText
        {
            get { return (_RowHeaderText); }
            set
            {
                if (_RowHeaderText != value)
                {
                    _RowHeaderText = value;
                    NeedsMeasured = true;
                    OnPropertyChangedEx("RowHeaderText", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region RowHeight
        ///
        /// Gets or sets the height of the ColumnHeader row
        ///
        [DefaultValue(0), Category("Style")]
        [Description("Indicates the height of the ColumnHeader row")]
        public int RowHeight
        {
            get { return (_RowHeight); }
            set
            {
                if (_RowHeight != value)
                {
                    if (value < 0)
                        throw new Exception("RowHeight cannot be negative");
                    _RowHeight = value;
                    NeedsMeasured = true;
                    OnPropertyChangedEx("RowHeight", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region ShowFilterToolTips
        /// 
        /// Gets or sets whether tooltips are shown when over the filter image
        /// 
        [DefaultValue(true), Category("Filtering")]
        [Description("Indicates whether tooltips are shown when over the filter image.")]
        public bool ShowFilterToolTips
        {
            get { return (_ShowFilterToolTips); }
            set
            {
                if (value != _ShowFilterToolTips)
                {
                    _ShowFilterToolTips = value;
                    OnPropertyChanged("ShowFilterToolTips");
                }
            }
        }
        #endregion
        #region ShowHeaderImages
        /// 
        /// Gets or sets whether Column Header images are displayed
        /// 
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether Column Header images are displayed.")]
        public bool ShowHeaderImages
        {
            get { return (_ShowHeaderImages); }
            set
            {
                if (_ShowHeaderImages != value)
                {
                    _ShowHeaderImages = value;
                    NeedsMeasured = true;
                    OnPropertyChangedEx("ShowHeaderImages", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region ShowGroupColumnHeaders
        ///
        /// Gets or sets whether column headers are shown
        /// by default when the columns are within a grouped header
        ///
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether column headers are shown by default when the columns are within a grouped header.")]
        public bool ShowGroupColumnHeaders
        {
            get { return (_ShowGroupColumnHeaders); }
            set
            {
                if (_ShowGroupColumnHeaders != value)
                {
                    _ShowGroupColumnHeaders = value;
                    OnPropertyChangedEx("ShowGroupColumnHeaders", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region ShowToolTips
        /// 
        /// Gets or sets whether tooltips are shown for the column header
        /// 
        [DefaultValue(true), Category("Filtering")]
        [Description("Indicates whether tooltips are shown for the column header.")]
        public bool ShowToolTips
        {
            get { return (_ShowToolTips); }
            set
            {
                if (value != _ShowToolTips)
                {
                    _ShowToolTips = value;
                    OnPropertyChanged("ShowToolTips");
                }
            }
        }
        #endregion
        #region SortImageAlignment
        /// 
        /// Gets or sets the alignment of the Sort Images
        /// 
        [DefaultValue(Alignment.NotSet), Category("Appearance")]
        [Description("Indicates the alignment of the Sort Images.")]
        public Alignment SortImageAlignment
        {
            get { return (_SortImageAlignment); }
            set
            {
                if (_SortImageAlignment != value)
                {
                    _SortImageAlignment = value;
                    OnPropertyChangedEx("SortImageAlignment", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #endregion
        #region MeasureOverride
        /// 
        /// Performs the layout of the item and sets
        /// the Size property to size that item will take.
        /// 
        /// Layout information.
        /// 
        /// 
        protected override void MeasureOverride(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Size constraintSize)
        {
            GridPanel panel = stateInfo.GridPanel;
            ResetProcessStates(panel);
            Size sizeNeeded = MeasureGroupHeaders(layoutInfo, constraintSize, panel);
            MeasureColumnHeaders(layoutInfo, constraintSize, panel, ref sizeNeeded);
            if (panel.ShowRowHeaders == true)
                sizeNeeded.Width += panel.RowHeaderWidthEx;
            Size = sizeNeeded;
        }
        #region MeasureGroupHeaders
        private Size MeasureGroupHeaders(
            GridLayoutInfo layoutInfo, Size constraintSize, GridPanel panel)
        {
            Size sizeNeeded = Size.Empty;
            if (_GroupHeaders != null)
            {
                foreach (ColumnGroupHeader cgh in _GroupHeaders)
                {
                    if (cgh.Visible == true)
                    {
                        Size size = MeasureGroupHeader(layoutInfo, constraintSize, panel, cgh);
                        sizeNeeded.Width += size.Width;
                        sizeNeeded.Height = Math.Max(size.Height, sizeNeeded.Height);
                    }
                }
            }
            return (sizeNeeded);
        }
        #region MeasureGroupHeader
        private Size MeasureGroupHeader(GridLayoutInfo layoutInfo,
            Size constraintSize, GridPanel panel, ColumnGroupHeader cgh)
        {
            Size sizeNeeded = MeasureGroupHeaderColumn(layoutInfo, constraintSize, panel, cgh);
            if (cgh.RowHeight > 0)
            {
                sizeNeeded.Height = Dpi.Height(cgh.RowHeight);
            }
            else
            {
                int mrh = Dpi.Height(cgh.MinRowHeight);
                if (sizeNeeded.Height < mrh)
                    sizeNeeded.Height = mrh;
            }
            cgh.ContentSize = sizeNeeded;
            if (cgh.GroupHeaders.Count > 0)
            {
                Size subSize = Size.Empty;
                foreach (ColumnGroupHeader gh in cgh.GroupHeaders)
                {
                    Size size = MeasureGroupHeader(layoutInfo, constraintSize, panel, gh);
                    subSize.Height = Math.Max(subSize.Height, size.Height);
                    subSize.Width += size.Width;
                }
                sizeNeeded.Height += subSize.Height;
                sizeNeeded.Width = Math.Max(sizeNeeded.Width, subSize.Width);
            }
            else
            {
                Size baseSize = Size.Empty;
                GridColumnCollection columns = _Columns;
                bool showColumnHeaders = GetShowRootColumnHeaders(cgh);
                int[] map = columns.DisplayIndexMap;
                for (int i = cgh.StartDisplayIndex; i <= cgh.EndDisplayIndex; i++)
                {
                    if ((uint)i >= map.Length)
                        break;
                    int index = map[i];
                    GridColumn column = columns[index];
                    if (column.Visible == true)
                    {
                        if (showColumnHeaders == true)
                        {
                            Size size = MeasureHeader(layoutInfo, constraintSize, panel, column);
                            baseSize.Width += size.Width;
                            baseSize.Height = Math.Max(baseSize.Height, size.Height);
                        }
                    }
                }
                sizeNeeded.Height += baseSize.Height;
                if (constraintSize.Width > 0)
                    sizeNeeded.Width = baseSize.Width;
                else
                    sizeNeeded.Width = Math.Max(sizeNeeded.Width, baseSize.Width);
            }
            cgh.Size = sizeNeeded;
            return (sizeNeeded);
        }
        #region MeasureGroupHeaderColumn
        private Size MeasureGroupHeaderColumn(GridLayoutInfo layoutInfo,
            Size constraintSize, GridPanel panel, ColumnGroupHeader cgh)
        {
            ColumnHeaderVisualStyle style = GetSizingStyle(panel, cgh);
            Size sizeNeeded = MeasureGroupHeaderTextAndImage(layoutInfo, constraintSize, panel, cgh, style);
            sizeNeeded.Width += Dpi.Width8;
            sizeNeeded.Height += Dpi.Height4;
            return (sizeNeeded);
        }
        #region MeasureGroupHeaderTextAndImage
        private Size MeasureGroupHeaderTextAndImage(GridLayoutInfo layoutInfo, Size constraintSize,
            GridPanel panel, ColumnGroupHeader cgh, ColumnHeaderVisualStyle style)
        {
            Size sizeNeeded = Size.Empty;
            object figure = (_ShowHeaderImages == true) ? style.GetFigure(panel) : null;
            Size figureSize = style.GetFigureSize(panel);
            Alignment imageAlignment = style.ImageAlignment;
            if (style.IsOverlayImage == true)
                imageAlignment = Alignment.MiddleCenter;
            Size borderSize = style.GetBorderSize(true);
            int bwidth = (borderSize.Width * 2);
            int bheight = (borderSize.Height * 2);
            int width = constraintSize.Width > 0 ? GetDefaultGroupHeaderWidth(panel, cgh) : 0;
            if (width > 0)
            {
                width -= bwidth;
                switch (imageAlignment)
                {
                    case Alignment.TopCenter:
                    case Alignment.MiddleCenter:
                    case Alignment.BottomCenter:
                        break;
                    default:
                        width -= figureSize.Width;
                        break;
                }
            }
            Size contentSize =
                MeasureGroupHeaderText(layoutInfo.Graphics, cgh, style, new Size(width, 0));
            switch (imageAlignment)
            {
                case Alignment.MiddleCenter:
                    sizeNeeded.Height = Math.Max(figureSize.Height, contentSize.Height) + bheight;
                    sizeNeeded.Width = Math.Max(figureSize.Width, contentSize.Width) + bwidth;
                    break;
                case Alignment.TopCenter:
                case Alignment.BottomCenter:
                    sizeNeeded.Width = Math.Max(figureSize.Width, contentSize.Width) + bwidth;
                    sizeNeeded.Height = contentSize.Height + figureSize.Height + bheight;
                    break;
                default:
                    sizeNeeded.Width = contentSize.Width + figureSize.Width + bwidth;
                    sizeNeeded.Height = Math.Max(figureSize.Height, contentSize.Height) + bheight;
                    break;
            }
            return (sizeNeeded);
        }
        #region GetDefaultGroupHeaderWidth
        private int GetDefaultGroupHeaderWidth(
            GridPanel panel, ColumnGroupHeader cgh)
        {
            int width = 0;
            GridColumnCollection columns = panel.Columns;
            int[] map = columns.DisplayIndexMap;
            for (int i = cgh.StartDisplayIndex; i <= cgh.EndDisplayIndex; i++)
            {
                if ((uint)i >= map.Length)
                    break;
                int index = map[i];
                GridColumn column = columns[index];
                if (column.Visible == true)
                    width += column.Size.Width;
            }
            return (width);
        }
        #endregion
        #region MeasureGroupHeaderText
        private Size MeasureGroupHeaderText(Graphics g,
            ColumnGroupHeader cgh, CellVisualStyle style, Size constraintSize)
        {
            Size size = Size.Empty;
            string s = GetHeaderText(cgh);
            if (string.IsNullOrEmpty(s) == false)
            {
                if (cgh.HeaderTextMarkup != null)
                {
                    size = GetMarkupTextSize(g,
                        cgh.HeaderTextMarkup, style, constraintSize.Width);
                    cgh.HeaderTextSize = size;
                }
                else
                {
                    eTextFormat tf = style.GetTextFormatFlags();
                    size = (constraintSize.IsEmpty == true)
                               ? TextHelper.MeasureText(g, s, style.Font)
                               : TextHelper.MeasureText(g, s, style.Font, constraintSize, tf);
                }
            }
            return (size);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #endregion
        #region MeasureColumnHeaders
        private void MeasureColumnHeaders(
            GridLayoutInfo layoutInfo, Size constraintSize, GridPanel panel, ref Size sizeNeeded)
        {
            GridColumnCollection columns = _Columns;
            for (int i = 0; i < columns.Count; i++)
            {
                GridColumn column = columns[i];
                if (column.Processed == false)
                {
                    Size size = MeasureHeader(layoutInfo, constraintSize, panel, column);
                    sizeNeeded.Width += size.Width;
                    sizeNeeded.Height = Math.Max(size.Height, sizeNeeded.Height);
                }
            }
        }
        #endregion
        #region MeasureHeader
        internal Size MeasureHeader(GridLayoutInfo layoutInfo,
            Size constraintSize, GridPanel panel, GridColumn column)
        {
            Size sizeNeeded = Size.Empty;
            ColumnHeaderVisualStyle style = GetSizingStyle(panel, column);
            MeasureTextAndImage(layoutInfo, constraintSize, panel, column, style, ref sizeNeeded);
            MeasureSortAndFilter(panel, column, style, ref sizeNeeded);
            sizeNeeded.Width += Dpi.Width8;
            sizeNeeded.Height += Dpi.Height4;
            if (Dpi.Height(_RowHeight) > 0)
                sizeNeeded.Height = Dpi.Height(_RowHeight);
            else if (sizeNeeded.Height < Dpi.Height(_MinRowHeight))
                sizeNeeded.Height = Dpi.Height(_MinRowHeight);
            column.HeaderSize = sizeNeeded;
            column.Processed = true;
            return (sizeNeeded);
        }
        #region MeasureTextAndImage
        private void MeasureTextAndImage(GridLayoutInfo layoutInfo, Size constraintSize,
            GridPanel panel, GridColumn column, ColumnHeaderVisualStyle style, ref Size sizeNeeded)
        {
            Size figureSize = (_ShowHeaderImages == true)
                ? style.GetFigureSize(panel) : Size.Empty;
            Alignment imageAlignment = style.ImageAlignment;
            if (style.IsOverlayImage == true)
                imageAlignment = Alignment.MiddleCenter;
            Size borderSize = style.GetBorderSize(true);
            int bwidth = (borderSize.Width * 2);
            int bheight = (borderSize.Height * 2);
            int width = constraintSize.Width > 0 ? column.Size.Width : 0;
            if (width > 0)
            {
                width -= bwidth;
                switch (imageAlignment)
                {
                    case Alignment.TopCenter:
                    case Alignment.MiddleCenter:
                    case Alignment.BottomCenter:
                        break;
                    default:
                        width -= figureSize.Width;
                        break;
                }
            }
            Size contentSize =
                MeasureHeaderText(layoutInfo.Graphics, column, style, new Size(width, 0));
            if (width == 0)
                column.HeaderTextSize = contentSize;
            switch (imageAlignment)
            {
                case Alignment.MiddleCenter:
                    sizeNeeded.Height = Math.Max(figureSize.Height, contentSize.Height) + bheight;
                    sizeNeeded.Width = Math.Max(figureSize.Width, contentSize.Width) + bwidth;
                    break;
                case Alignment.TopCenter:
                case Alignment.BottomCenter:
                    sizeNeeded.Width = Math.Max(figureSize.Width, contentSize.Width) + bwidth;
                    sizeNeeded.Height = contentSize.Height + figureSize.Height + bheight;
                    break;
                default:
                    sizeNeeded.Width = contentSize.Width + figureSize.Width + bwidth;
                    sizeNeeded.Height = Math.Max(figureSize.Height, contentSize.Height) + bheight;
                    break;
            }
        }
        #region MeasureHeaderText
        private Size MeasureHeaderText(Graphics g,
            GridColumn column, CellVisualStyle style, Size constraintSize)
        {
            Size size = Size.Empty;
            string s = column.GetHeaderText();
            if (string.IsNullOrEmpty(s) == false)
            {
                if (column.HeaderTextMarkup != null)
                {
                    size = GetMarkupTextSize(g,
                        column.HeaderTextMarkup, style, constraintSize.Width > 0 ? constraintSize.Width : 10000);
                    column.HeaderTextSize = size;
                }
                else
                {
                    eTextFormat tf = style.GetTextFormatFlags();
                    size = (constraintSize.IsEmpty == true)
                               ? TextHelper.MeasureText(g, s, style.Font)
                               : TextHelper.MeasureText(g, s, style.Font, constraintSize, tf);
                }
            }
            return (size);
        }
        #region GetMarkupTextSize
        private Size GetMarkupTextSize(Graphics g,
            BodyElement textMarkup, CellVisualStyle style, int width)
        {
            MarkupDrawContext d =
                new MarkupDrawContext(g, style.Font, style.TextColor, false);
            textMarkup.InvalidateElementsSize();
            textMarkup.Measure(new Size(width, 0), d);
            return (textMarkup.Bounds.Size);
        }
        #endregion
        #endregion
        #endregion
        #region MeasureSortAndFilter
        private void MeasureSortAndFilter(GridPanel panel,
            GridColumn column, ColumnHeaderVisualStyle style, ref Size sizeNeeded)
        {
            Alignment sortAlignment = (_SortImageAlignment == Alignment.NotSet)
                ? Alignment.TopCenter : _SortImageAlignment;
            Alignment filterAlignment = (_FilterImageAlignment == Alignment.NotSet)
                ? Alignment.MiddleLeft : _FilterImageAlignment;
            int imsHeight = 0;
            if (panel.SortLevel != SortLevel.None)
            {
                imsHeight = GetPartSizeNeeded(
                    GetAscendingSortImage(column), style, sortAlignment, ref sizeNeeded);
            }
            int imfHeight = 0;
            if (FilterCanBeVisible(panel) == true)
            {
                imfHeight = GetPartSizeNeeded(
                    GetFilterImage(column), style, filterAlignment, ref sizeNeeded);
            }
            if (imsHeight > 0 && imfHeight > 0)
            {
                if (VAlignment(sortAlignment) == VAlignment(filterAlignment))
                {
                    int n = Math.Max(imsHeight, imfHeight);
                    sizeNeeded.Height += n;
                    if (VAlignment(style.Alignment) == 1)
                        sizeNeeded.Height += n;
                }
                else
                    sizeNeeded.Height += (imsHeight + imfHeight);
            }
            else
            {
                int n = imsHeight + imfHeight;
                sizeNeeded.Height += n;
                if (VAlignment(style.Alignment) == 1)
                    sizeNeeded.Height += n;
            }
        }
        #region GetPartSizeNeeded
        private int GetPartSizeNeeded(Image image,
            ColumnHeaderVisualStyle style, Alignment alignment, ref Size sizeNeeded)
        {
            int height = 0;
            if (image != null)
            {
                if (alignment != Alignment.TopCenter &&
                    alignment != Alignment.MiddleCenter &&
                    alignment != Alignment.BottomCenter)
                {
                    sizeNeeded.Width += (image.Width + 4);
                }
                if (alignment == Alignment.MiddleLeft ||
                    alignment == Alignment.MiddleCenter ||
                    alignment == Alignment.MiddleRight ||
                    VAlignment(alignment) == VAlignment(style.Alignment))
                {
                    sizeNeeded.Height = Math.Max(sizeNeeded.Height, image.Height);
                }
                else
                {
                    height = (image.Height + 2);
                }
            }
            return (height);
        }
        #endregion
        #region FilterCanBeVisible
        private bool FilterCanBeVisible(GridPanel panel)
        {
            if (panel.EnableFiltering == true && panel.EnableColumnFiltering == true)
            {
                if (FilterImageVisibility != ImageVisibility.Never)
                    return (true);
            }
            return (false);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region ArrangeOverride
        /// 
        /// Performs the arrange pass layout of the item
        /// when final position and size of the item has been set.
        /// 
        /// Layout information.
        /// 
        /// Layout bounds
        protected override void ArrangeOverride(GridLayoutInfo layoutInfo,
            GridLayoutStateInfo stateInfo, Rectangle layoutBounds)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                ArrangeGroupHeader(panel, GroupHeaders, 0);
                foreach (GridColumn col in panel.Columns)
                {
                    if (col.Visible == true)
                        UpdateImageBounds(panel, col);
                }
            }
        }
        #region ArrangeGroupHeader
        private void ArrangeGroupHeader(
            GridPanel panel, IEnumerable csc, int dy)
        {
            if (csc != null)
            {
                foreach (ColumnGroupHeader cgh in csc)
                {
                    if (cgh.Visible == true)
                    {
                        Size oldSize = cgh.BoundsRelative.Size;
                        cgh.BoundsRelative = GetGroupHeaderBounds(panel, cgh, dy);
                        cgh.Size = new Size(cgh.Size.Width, Bounds.Height - dy);
                        ArrangeGroupHeader(panel, cgh.GroupHeaders, dy + cgh.BoundsRelative.Height);
                        if (oldSize != cgh.BoundsRelative.Size)
                            SuperGrid.DoColumnGroupHeaderResizedEvent(panel, cgh, oldSize);
                    }
                }
            }
        }
        #region GetGroupHeaderBounds
        private Rectangle GetGroupHeaderBounds(
            GridPanel panel, ColumnGroupHeader cgh, int dy)
        {
            GridColumnCollection columns = panel.Columns;
            Rectangle r = Rectangle.Empty;
            int[] map = columns.DisplayIndexMap;
            bool showColHeaders = GetShowRootColumnHeaders(cgh) && cgh.GroupHeaders.Count == 0;
            for (int i = cgh.StartDisplayIndex; i <= cgh.EndDisplayIndex; i++)
            {
                if ((uint)i < columns.Count)
                {
                    GridColumn column = columns[map[i]];
                    if (column.Visible == true)
                    {
                        Rectangle q = GetRelativeBounds(panel, column);
                        r = (r.IsEmpty == true) ? q : Rectangle.Union(r, q);
                        r.Height = (showColHeaders == true) ? column.HeaderSize.Height : 0;
                    }
                }
            }
            r.Y += dy;
            if (cgh.GroupHeaders.Count > 0)
            {
                r.Height = cgh.ContentSize.Height;
            }
            else
            {
                if (showColHeaders == true && cgh.RowHeight > 0)
                    r.Height = Dpi.Height(cgh.RowHeight);
                else
                    r.Height = (Bounds.Bottom - r.Bottom);
            }
            return (r);
        }
        #endregion
        #endregion
        #endregion
        #region RenderOverride
        /// 
        /// Performs drawing of the item and its children.
        /// 
        /// Holds contextual rendering information.
        protected override void RenderOverride(GridRenderInfo renderInfo)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                ResetProcessStates(panel);
                Graphics g = renderInfo.Graphics;
                Rectangle bounds = Bounds;
                ColumnHeaderRowVisualStyle style = GetEffectiveRowHeaderStyle();
                GridPanelVisualStyle pstyle = panel.GetEffectiveStyle();
                if (SuperGrid.DoPreRenderColumnHeaderEvent(g,
                    this, null, RenderParts.Background, bounds) == false)
                {
                    RenderRowBackground(g, style, bounds);
                    SuperGrid.DoPostRenderColumnHeaderEvent(g,
                        this, null, RenderParts.Background, bounds);
                }
                RenderColumnBorder(g, panel, bounds);
                if (HScrollOffset == 0 || panel.IsSubPanel || panel.FrozenColumnCount <= 0)
                {
                    RenderHeaders(panel, renderInfo, false, false);
                }
                else
                {
                    RenderHeaders(panel, renderInfo, true, false);
                    RenderHeaders(panel, renderInfo, true, true);
                }
                if (panel.FrozenColumnCount > 0)
                    RenderFrozenColumnMarker(g, panel, pstyle);
                RenderRowHeader(g, panel, style, pstyle);
            }
        }
        #region RenderRowBackground
        private void RenderRowBackground(
            Graphics g, ColumnHeaderRowVisualStyle style, Rectangle bounds)
        {
            using (Brush br = style.WhiteSpaceBackground.GetBrush(bounds))
                g.FillRectangle(br, bounds);
        }
        #endregion
        #region RenderColumnBorder
        private void RenderColumnBorder(
            Graphics g, GridPanel panel, Rectangle bounds)
        {
            Rectangle r = bounds;
            SmoothingMode sm = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.None;
            GridPanelVisualStyle pstyle = panel.GetEffectiveStyle();
            if (pstyle.HeaderHLinePattern != LinePattern.None &&
                pstyle.HeaderHLinePattern != LinePattern.NotSet)
            {
                using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Height1))
                {
                    pen.DashStyle = (DashStyle)pstyle.HeaderHLinePattern;
                    g.DrawLine(pen, r.X, r.Bottom - 1, r.Right - 1, r.Bottom - 1);
                    g.DrawLine(pen, r.X, r.Top - 1, r.Right - 1, r.Top - 1);
                }
            }
            if (pstyle.HeaderVLinePattern != LinePattern.None &&
                pstyle.HeaderVLinePattern != LinePattern.NotSet)
            {
                using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Width1))
                {
                    pen.DashStyle = (DashStyle)pstyle.HeaderVLinePattern;
                    g.DrawLine(pen, r.Right - 1, r.Top - 1, r.Right - 1, r.Bottom - 1);
                }
            }
            g.SmoothingMode = sm;
        }
        #endregion
        #region RenderHeaders
        private void RenderHeaders(GridPanel panel,
            GridRenderInfo renderInfo, bool chkFrozen, bool frozen)
        {
            Graphics g = renderInfo.Graphics;
            Rectangle clip = renderInfo.ClipRectangle;
            RenderGroupHeaders(g, panel, clip, GroupHeaders, chkFrozen, frozen);
            RenderColumnHeaders(g, panel, clip, chkFrozen, frozen);
        }
        #region RenderGroupHeaders
        private void RenderGroupHeaders(Graphics g, GridPanel panel,
            Rectangle clip, IEnumerable csc, bool chkFrozen, bool frozen)
        {
            if (csc != null)
            {
                foreach (ColumnGroupHeader cgh in csc)
                {
                    if (cgh.Visible == true)
                    {
                        if (chkFrozen == false || (IsGroupHeaderHFrozen(panel, cgh) == frozen))
                        {
                            Rectangle r = GetSubContScrollBounds(panel, cgh);
                            if (clip.IsEmpty == true || r.IntersectsWith(clip) == true)
                            {
                                Rectangle bounds = GetSubScrollBounds(panel, cgh);
                                RenderGroupHeader(g, panel, cgh, bounds);
                                if (cgh.GroupHeaders.Count > 0)
                                    RenderGroupHeaders(g, panel, Rectangle.Empty, cgh.GroupHeaders, chkFrozen, frozen);
                                RenderBaseHeaders(g, panel, cgh);
                            }
                            else
                            {
                                if (cgh.GroupHeaders.Count > 0)
                                    RenderGroupHeaders(g, panel, Rectangle.Empty, cgh.GroupHeaders, chkFrozen, frozen);
                            }
                        }
                    }
                }
            }
        }
        #region RenderGroupHeader
        private void RenderGroupHeader(
            Graphics g, GridPanel panel, ColumnGroupHeader cgh, Rectangle bounds)
        {
            if (bounds.IsEmpty == false)
            {
                ColumnHeaderVisualStyle style = GetEffectiveStyle(cgh);
                if (bounds.Width > 0 && bounds.Height > 0)
                {
                    if (SuperGrid.DoPreRenderColumnGroupHeaderEvent(g,
                        this, cgh, RenderParts.Background, bounds) == false)
                    {
                        RenderBackground(g, style, bounds);
                        SuperGrid.DoPostRenderColumnGroupHeaderEvent(g,
                            this, cgh, RenderParts.Background, bounds);
                    }
                    RenderColumnBorder(g, panel, bounds);
                    Rectangle r = bounds;
                    Rectangle t = GetContentBounds(panel, style, r);
                    t = GetAdjustedBounds(style, t);
                    if (style.ImageOverlay == ImageOverlay.None ||
                        style.ImageOverlay == ImageOverlay.Bottom)
                    {
                        RenderHeaderImage(g, panel, style, bounds, t);
                    }
                    if (SuperGrid.DoPreRenderColumnGroupHeaderEvent(g,
                        this, cgh, RenderParts.Content, t) == false)
                    {
                        RenderGroupHeaderText(g, style, cgh, t);
                        SuperGrid.DoPostRenderColumnGroupHeaderEvent(g,
                            this, cgh, RenderParts.Content, t);
                    }
                    if (style.ImageOverlay == ImageOverlay.Top)
                        RenderHeaderImage(g, panel, style, bounds, t);
                    r = GetBorderRect(style, r);
                    if (SuperGrid.DoPreRenderColumnGroupHeaderEvent(g,
                        this, cgh, RenderParts.Border, r) == false)
                    {
                        if (r.Width > 0 && r.Height > 0)
                            style.RenderBorder(g, r);
                        SuperGrid.DoPostRenderColumnGroupHeaderEvent(g,
                            this, cgh, RenderParts.Border, r);
                    }
                }
            }
        }
        #region RenderGroupHeaderText
        private void RenderGroupHeaderText(Graphics g,
            ColumnHeaderVisualStyle style, ColumnGroupHeader cgh, Rectangle r)
        {
            if (_MouseDownButtons == MouseButtons.Left)
                r = AdjustTextHeaderBounds(cgh, r, GridPanel.ColumnGroupHeaderClickBehavior);
            if (cgh.HeaderTextMarkup != null)
            {
                RenderTextMarkup(g, cgh.HeaderTextMarkup, style, r);
            }
            else
            {
                string s = GetHeaderText(cgh);
                if (string.IsNullOrEmpty(s) == false)
                {
                    TextDrawing.DrawString(g, s,
                        style.Font, style.TextColor, r, style.GetTextFormatFlags());
                }
            }
        }
        #region GetHeaderText
        private string GetHeaderText(ColumnGroupHeader cgh)
        {
            return (cgh.HeaderText ?? cgh.Name);
        }
        #endregion
        #endregion
        #endregion
        #region RenderBaseHeaders
        private void RenderBaseHeaders(Graphics g, GridPanel panel, ColumnGroupHeader cgh)
        {
            int[] map = panel.Columns.DisplayIndexMap;
            for (int i = cgh.StartDisplayIndex; i <= cgh.EndDisplayIndex; i++)
            {
                if ((uint)i >= map.Length)
                    break;
                RenderBaseHeader(g, panel, cgh, map[i]);
            }
        }
        #region RenderBaseHeader
        private void RenderBaseHeader(Graphics g,
            GridPanel panel, ColumnGroupHeader cgh, int i)
        {
            GridColumn col = panel.Columns[i];
            if (col.Visible == true && col.Processed == false)
            {
                Rectangle r = GetBounds(panel, col);
                int n = cgh.Size.Height - cgh.BoundsRelative.Height;
                r.Y = r.Bottom - n;
                r.Height = n;
                if (GetShowRootColumnHeaders(cgh) == true || cgh.GroupHeaders.Count > 0)
                {
                    RenderColumnHeader(g, panel, col, r, true);
                }
                else
                {
                    RenderColumnBorder(g, panel, r);
                    col.Processed = true;
                }
            }
        }
        #endregion
        #endregion
        #endregion
        #region RenderColumnHeaders
        private void RenderColumnHeaders(Graphics g,
            GridPanel panel, Rectangle clip, bool chkFrozen, bool frozen)
        {
            GridColumnCollection columns = _Columns;
            int[] map = columns.DisplayIndexMap;
            for (int i = 0; i < map.Length; i++)
            {
                int index = map[i];
                GridColumn column = columns[index];
                if (column.Visible == true && column.Processed == false)
                {
                    if ((chkFrozen == false) || (frozen == column.IsHFrozen))
                    {
                        Rectangle r = GetBounds(panel, column);
                        if (r.IntersectsWith(clip) == true)
                            RenderColumnHeader(g, panel, column, r, true);
                    }
                }
            }
        }
        #region RenderColumnHeader
        private void RenderColumnHeader(Graphics g,
            GridPanel panel, GridColumn column, Rectangle bounds, bool fullRender)
        {
            ColumnHeaderVisualStyle style = GetEffectiveStyle(column);
            if (bounds.Width > 0 && bounds.Height > 0)
            {
                if (SuperGrid.DoPreRenderColumnHeaderEvent(g,
                    this, column, RenderParts.Background, bounds) == false)
                {
                    RenderBackground(g, style, bounds);
                    SuperGrid.DoPostRenderColumnHeaderEvent(g,
                        this, column, RenderParts.Background, bounds);
                }
                RenderColumnBorder(g, panel, bounds);
                Rectangle r = bounds;
                Rectangle t = GetContentBounds(panel, style, r);
                t = GetAdjustedBounds(style, t);
                if (style.ImageOverlay == ImageOverlay.None ||
                    style.ImageOverlay == ImageOverlay.Bottom)
                {
                    RenderHeaderImage(g, panel, style, bounds, t);
                }
                if (fullRender == true)
                    t = RenderSortAndFilterImage(g, column, style, t);
                if (SuperGrid.DoPreRenderColumnHeaderEvent(g,
                    this, column, RenderParts.Content, t) == false)
                {
                    RenderText(g, panel, column, style, t);
                    SuperGrid.DoPostRenderColumnHeaderEvent(g,
                        this, column, RenderParts.Content, t);
                }
                if (style.ImageOverlay == ImageOverlay.Top)
                    RenderHeaderImage(g, panel, style, bounds, t);
                r = GetBorderRect(style, r);
                if (SuperGrid.DoPreRenderColumnHeaderEvent(g,
                    this, column, RenderParts.Border, r) == false)
                {
                    if (r.Width > 0 && r.Height > 0)
                        style.RenderBorder(g, r);
                    SuperGrid.DoPostRenderColumnHeaderEvent(g,
                        this, column, RenderParts.Border, r);
                }
                column.Processed = true;
            }
        }
        #region GetBorderRect
        private Rectangle GetBorderRect(
            ColumnHeaderVisualStyle style, Rectangle r)
        {
            r.X += style.Margin.Left;
            r.Width -= style.Margin.Horizontal;
            r.Y += style.Margin.Top;
            r.Height -= style.Margin.Vertical;
            return (r);
        }
        #endregion
        #region RenderBackground
        private void RenderBackground(Graphics g,
            VisualStyle style, Rectangle r)
        {
            using (Brush br = style.Background.GetBrush(r))
                g.FillRectangle(br, r);
        }
        #endregion
        #region RenderSortAndFilterImage
        private Rectangle RenderSortAndFilterImage(
            Graphics g, GridColumn column, ColumnHeaderVisualStyle style, Rectangle t)
        {
            GridPanel panel = column.Parent as GridPanel;
            if (panel != null)
            {
                Alignment falign = (_FilterImageAlignment == Alignment.NotSet)
                    ? Alignment.MiddleLeft : _FilterImageAlignment;
                Alignment salign = (_SortImageAlignment == Alignment.NotSet)
                    ? Alignment.TopCenter : _SortImageAlignment;
                Rectangle rf = GetFilterImageBounds(panel, column);
                if (rf.IsEmpty == false)
                {
                    Image filterImage = GetColumnFilterImage(column);
                    if (filterImage != null)
                        g.DrawImageUnscaledAndClipped(filterImage, rf);
                }
                Rectangle rs = GetSortImageBounds(panel, column, salign, falign, rf);
                if (rs.IsEmpty == false)
                {
                    Image sortImage = GetColumnSortImage(panel, column);
                    if (sortImage != null)
                        g.DrawImageUnscaledAndClipped(sortImage, rs);
                }
                if (rf.IsEmpty == false)
                    t = UpdateContentRect(rf, t, falign, style, column);
                if (rs.IsEmpty == false)
                    t = UpdateContentRect(rs, t, salign, style, column);
            }
            t.X += 2;
            t.Width -= 4;
            return (t);
        }
        #region GetFilterImageBounds
        private Rectangle GetFilterImageBounds(GridPanel panel, GridColumn column)
        {
            if (column != null)
            {
                GridColumn hitColumn = _HitItem as GridColumn;
                if (_FilterImageVisibility == ImageVisibility.Always ||
                    (column == hitColumn) || (string.IsNullOrEmpty(column.FilterExpr) == false))
                {
                    return (GetScrollBounds(panel, column, column.FilterImageBounds));
                }
            }
            return (Rectangle.Empty);
        }
        #endregion
        #region GetSortImageBounds
        private Rectangle GetSortImageBounds(GridPanel panel,
            GridColumn column, Alignment salign, Alignment falign, Rectangle rf)
        {
            Rectangle r = GetScrollBounds(panel, column, column.SortImageBounds);
            if (r.IsEmpty == false)
            {
                if (falign == salign && r.IsEmpty == false)
                {
                    if (salign == Alignment.TopCenter ||
                        salign == Alignment.MiddleCenter ||
                        salign == Alignment.BottomCenter)
                    {
                        r.X = rf.X - (r.Width + 1);
                    }
                }
            }
            return (r);
        }
        #endregion
        #region UpdateContentRect
        private Rectangle UpdateContentRect(Rectangle r,
            Rectangle t, Alignment alignment, ColumnHeaderVisualStyle style, GridColumn column)
        {
            switch (GetStringAlignment(alignment))
            {
                case StringAlignment.Near:
                    int n1 = r.Right - t.Left;
                    switch (GetStringAlignment(style.Alignment))
                    {
                        case StringAlignment.Center:
                            if (n1 + 3 > (t.Width - column.HeaderTextSize.Width) / 2)
                            {
                                t.X = r.Right;
                                t.Width -= n1;
                            }
                            break;
                        default:
                            t.X = r.Right;
                            t.Width -= n1;
                            break;
                    }
                    break;
                case StringAlignment.Far:
                    int n2 = t.Right - r.Left;
                    switch (GetStringAlignment(style.Alignment))
                    {
                        case StringAlignment.Center:
                            if (n2 + 3 > (t.Width - column.HeaderTextSize.Width) / 2)
                                t.Width -= n2;
                            break;
                        default:
                            t.Width -= n2;
                            break;
                    }
                    break;
            }
            return (t);
        }
        #region GetStringAlignment
        private StringAlignment GetStringAlignment(Alignment alignment)
        {
            switch (alignment)
            {
                case Alignment.TopLeft:
                case Alignment.MiddleLeft:
                case Alignment.BottomLeft:
                    return (StringAlignment.Near);
                case Alignment.TopCenter:
                case Alignment.MiddleCenter:
                case Alignment.BottomCenter:
                    return (StringAlignment.Center);
                default:
                    return (StringAlignment.Far);
            }
        }
        #endregion
        #endregion
        #endregion
        #region RenderText
        private void RenderText(Graphics g, GridPanel panel,
            GridColumn column, CellVisualStyle style, Rectangle r)
        {
            string s = column.GetHeaderText();
            if (s != null)
            {
                if (_MouseDownButtons == MouseButtons.Left)
                    r = AdjustTextHeaderBounds(column, r, panel.ColumnHeaderClickBehavior);
                if (column.HeaderTextMarkup != null)
                {
                    RenderTextMarkup(g, column.HeaderTextMarkup, style, r);
                }
                else
                {
                    TextDrawing.DrawString(g, s,
                        style.Font, style.TextColor, r, style.GetTextFormatFlags());
                }
            }
        }
        #region RenderTextMarkup
        private void RenderTextMarkup(Graphics g,
            BodyElement textMarkup, CellVisualStyle style, Rectangle r)
        {
            MarkupDrawContext d =
                new MarkupDrawContext(g, style.Font, style.TextColor, false);
            textMarkup.Arrange(new Rectangle(r.Location, r.Size), d);
            Size size = textMarkup.Bounds.Size;
            switch (style.Alignment)
            {
                case Alignment.MiddleLeft:
                case Alignment.MiddleCenter:
                case Alignment.MiddleRight:
                    if (r.Height > size.Height)
                        r.Y += (r.Height - size.Height) / 2;
                    break;
                default:
                    if (r.Height > size.Height)
                        r.Y = r.Bottom - size.Height;
                    break;
            }
            textMarkup.Bounds = new Rectangle(r.Location, size);
            Region oldClip = g.Clip;
            try
            {
                g.SetClip(r, CombineMode.Intersect);
                textMarkup.Render(d);
            }
            finally
            {
                g.Clip = oldClip;
            }
        }
        #endregion
        #endregion
        #region VAlignment
        private int VAlignment(Alignment alignment)
        {
            switch (alignment)
            {
                case Alignment.TopLeft:
                case Alignment.TopCenter:
                case Alignment.TopRight:
                    return (0);
                case Alignment.MiddleLeft:
                case Alignment.MiddleCenter:
                case Alignment.MiddleRight:
                    return (1);
                default:
                    return (2);
            }
        }
        #endregion
        #region GetColumnSortImage
        internal Image GetColumnSortImage(GridPanel panel, GridColumn column)
        {
            SortDirection sortDirection = SortDirection.None;
            if (panel.GroupColumns != null &&
                panel.GroupColumns.Contains(column) == true)
            {
                sortDirection = column.GroupDirection;
            }
            else if (panel.SortLevel != SortLevel.None)
            {
                sortDirection = column.SortDirection;
                switch (column.SortIndicator)
                {
                    case SortIndicator.None:
                        sortDirection = SortDirection.None;
                        break;
                    case SortIndicator.Ascending:
                        sortDirection = SortDirection.Ascending;
                        break;
                    case SortIndicator.Descending:
                        sortDirection = SortDirection.Descending;
                        break;
                }
            }
            switch (sortDirection)
            {
                case SortDirection.Ascending:
                    return (GetAscendingSortImage(column));
                case SortDirection.Descending:
                    return (GetDescendingSortImage(column));
            }
            return (null);
        }
        #endregion
        #region GetFilterImage
        internal Image GetColumnFilterImage(GridColumn column)
        {
            if (column.IsFilteringEnabled == true)
            {
                if (_FilterImageVisibility != ImageVisibility.Never)
                    return (GetFilterImage(column));
            }
            return (null);
        }
        #endregion
        #region GetImageBounds
        private Rectangle GetImageBounds(
            Image image1, Alignment alignment, ref Rectangle r)
        {
            Rectangle u = r;
            Rectangle t = r;
            t.Size = image1.Size;
            switch (alignment)
            {
                case Alignment.TopLeft:
                    r.X += t.Width + 2;
                    r.Width -= (t.Width + 2);
                    break;
                case Alignment.NotSet:
                case Alignment.TopCenter:
                    t.X += (r.Width - t.Width) / 2;
                    break;
                case Alignment.TopRight:
                    t.X = r.Right - t.Width;
                    r.Width -= (t.Width + 2);
                    break;
                case Alignment.MiddleLeft:
                    t.Y += (r.Height - t.Height) / 2;
                    r.X += t.Width + 2;
                    r.Width -= (t.Width + 2);
                    break;
                case Alignment.MiddleCenter:
                    t.X += (r.Width - t.Width) / 2;
                    t.Y += (r.Height - t.Height) / 2;
                    break;
                case Alignment.MiddleRight:
                    t.X = r.Right - t.Width;
                    t.Y += (r.Height - t.Height) / 2;
                    r.Width -= (t.Width + 2);
                    break;
                case Alignment.BottomLeft:
                    r.X += t.Width + 2;
                    r.Width -= (t.Width + 2);
                    t.Y = r.Bottom - t.Height;
                    break;
                case Alignment.BottomCenter:
                    t.X += (r.Width - t.Width) / 2;
                    t.Y = r.Bottom - t.Height;
                    break;
                case Alignment.BottomRight:
                    t.X = r.Right - t.Width;
                    t.Y = r.Bottom - t.Height;
                    r.Width -= (t.Width + 2);
                    break;
            }
            t.Intersect(u);
            return (t);
        }
        #endregion
        #endregion
        #endregion
        #region AdjustTextHeaderBounds
        private Rectangle AdjustTextHeaderBounds(
            object item, Rectangle r, ColumnHeaderClickBehavior cmode)
        {
            if (_Reordering == false && item == _MouseDownHitItem)
            {
                if (_MouseDownHitArea == HeaderArea.InMarkup ||
                    (_MouseDownHitArea == HeaderArea.InContent && cmode == ColumnHeaderClickBehavior.SortAndReorder))
                {
                    r.X++;
                    r.Y += 2;
                    r.Height -= 2;
                }
            }
            return (r);
        }
        #endregion
        #region RenderHeaderImage
        private void RenderHeaderImage(Graphics g, GridPanel panel,
            ColumnHeaderVisualStyle style, Rectangle bounds, Rectangle r)
        {
            if (_ShowHeaderImages == true)
            {
                object figure = style.GetFigure(panel);
                if (figure != null)
                {
                    Rectangle t = style.GetFigureBounds(panel, r);
                    bounds.Inflate(-1, -1);
                    t.Intersect(bounds);
                    style.RenderFigure(g, panel, t);
                }
            }
        }
        #endregion
        #endregion
        #region RenderFrozenColumnMarker
        private void RenderFrozenColumnMarker(
            Graphics g, GridPanel panel, GridPanelVisualStyle pstyle)
        {
            GridColumn col = panel.Columns.GetLastVisibleFrozenColumn();
            if (col != null)
            {
                Rectangle bounds = GetBounds(panel, col);
                bounds.Y = Bounds.Y;
                bounds.Height = Bounds.Height;
                Rectangle r = col.BoundsRelative;
                r.Y = bounds.Y + Dpi.Width3;
                r.Height = bounds.Height - Dpi.Width5;
                if (panel.IsSubPanel == true)
                    r.X -= HScrollOffset;
                if (r.Height > 0 && r.Width > 0)
                {
                    using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Width1))
                    {
                        g.DrawLine(pen, r.Right - Dpi.Width3,
                            r.Top - 1, r.Right - Dpi.Width3, r.Bottom - 1);
                    }
                }
            }
        }
        #endregion
        #region RenderRowHeader
        private void RenderRowHeader(Graphics g,
            GridPanel panel, ColumnHeaderRowVisualStyle style, GridPanelVisualStyle pstyle)
        {
            Rectangle r = GetRowHeaderBounds(panel);
            if (r.Width > 0 && r.Height > 0)
            {
                if (SuperGrid.DoPreRenderColumnHeaderEvent(g,
                    this, null, RenderParts.RowHeader, r) == false)
                {
                    SmoothingMode sm = g.SmoothingMode;
                    g.SmoothingMode = SmoothingMode.None;
                    using (Brush br = style.RowHeader.Background.GetBrush(r))
                        g.FillRectangle(br, r);
                    using (Pen pen = new Pen(style.RowHeader.BorderHighlightColor, Dpi.Height1))
                        g.DrawLine(pen, r.X, r.Top, r.Right - 1, r.Top);
                    using (Pen pen = new Pen(style.RowHeader.BorderHighlightColor, Dpi.Height1))
                        g.DrawLine(pen, r.X + 1, r.Top, r.X + 1, r.Bottom - 1);
                    using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Height1))
                    {
                        g.DrawLine(pen, r.X, r.Top - 1, r.Right - 1, r.Top - 1);
                        g.DrawLine(pen, r.X, r.Bottom - 1, r.Right - 1, r.Bottom - 1);
                    }
                    using (Pen pen = new Pen(pstyle.HeaderLineColor, Dpi.Width1))
                        g.DrawLine(pen, r.Right - 1, r.Top, r.Right - 1, r.Bottom - 1);
                    if (panel.TopLeftHeaderSelectBehavior != TopLeftHeaderSelectBehavior.NoSelection)
                    {
                        RenderRowHeaderIndicator(g, panel, style, r);
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(_RowHeaderText) == false)
                            RenderRowHeaderText(g, _RowHeaderText, style, r);
                    }
                    SuperGrid.DoPostRenderColumnHeaderEvent(g,
                        this, null, RenderParts.RowHeader, r);
                    g.SmoothingMode = sm;
                }
            }
        }
        #region RenderRowHeaderIndicator
        private void RenderRowHeaderIndicator(Graphics g,
            GridPanel panel, ColumnHeaderRowVisualStyle style, Rectangle r)
        {
            r.Inflate(-Dpi.Width3, -Dpi.Height3);
            if (r.Width > 0 && r.Height > 0)
            {
                using (GraphicsPath path = new GraphicsPath())
                {
                    int n = Math.Min(r.Width, r.Height);
                    if (n > Dpi.Width10)
                        n = Dpi.Width10;
                    Point[] pts = new Point[3];
                    if (_SelectAllCount != panel.SelectionUpdateCount)
                    {
                        r.X--;
                        r.Y--;
                        pts[0] = new Point(r.Right, r.Bottom - n);
                        pts[1] = new Point(r.Right, r.Bottom);
                        pts[2] = new Point(r.Right - n, r.Bottom);
                    }
                    else
                    {
                        pts[0] = new Point(r.X, r.Y);
                        pts[1] = new Point(r.X + n, r.Y);
                        pts[2] = new Point(r.X, r.Y + n);
                        r.X++;
                        r.Y++;
                    }
                    path.AddPolygon(pts);
                    path.CloseFigure();
                    if (style.IndicatorBackground.GradientAngle % 45 == 0)
                        n /= 2;
                    r.Width = n - 1;
                    r.Height = n - 1;
                    if (n > 0)
                    {
                        g.SmoothingMode = SmoothingMode.AntiAlias;
                        using (Brush br = style.IndicatorBackground.GetBrush(r))
                        {
                            if (br is LinearGradientBrush)
                                ((LinearGradientBrush)br).WrapMode = WrapMode.Tile;
                            g.FillPath(br, path);
                        }
                        using (Pen pen = new Pen(style.IndicatorBorderColor))
                            g.DrawPath(pen, path);
                    }
                }
            }
        }
        #endregion
        #region RenderRowHeaderText
        private void RenderRowHeaderText(Graphics g,
            string text, ColumnHeaderRowVisualStyle style, Rectangle r)
        {
            Font font = style.RowHeader.Font ?? SystemFonts.DefaultFont;
            Size tSize = TextHelper.MeasureText(g, text, font);
            r.Inflate(-Dpi.Width2, -Dpi.Height2);
            eTextFormat tf = ((r.Width <= tSize.Width)
                  ? eTextFormat.Left
                  : eTextFormat.HorizontalCenter) | eTextFormat.NoPadding;
            tf |= eTextFormat.WordBreak | eTextFormat.VerticalCenter;
            TextDrawing.DrawString(g, text,
                font, style.RowHeader.TextColor, r, tf);
        }
        #endregion
        #endregion
        #endregion
        #region ResetProcessStates
        private void ResetProcessStates(GridPanel panel)
        {
            for (int i = 0; i < panel.Columns.Count; i++)
                panel.Columns[i].Processed = false;
        }
        #endregion
        #region Mouse support
        #region InternalMouseEnter
        internal override void InternalMouseEnter(EventArgs e)
        {
            SuperGrid.ToolTipText = "";
            SuperGrid.DoColumnHeaderMouseEnterEvent(this);
            base.InternalMouseEnter(e);
        }
        #endregion
        #region InternalMouseLeave
        internal override void InternalMouseLeave(EventArgs e)
        {
            if (_LockedColumn == false)
            {
                ResetColumnState();
                _HitArea = HeaderArea.NoWhere;
                _HitItem = null;
            }
            SuperGrid.ToolTipText = "";
            SuperGrid.DoColumnHeaderMouseLeaveEvent(this);
            base.InternalMouseLeave(e);
        }
        #region ResetColumnState
        internal void ResetColumnState()
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                if (_MouseDownHitItem != null)
                    InvalidateItem(panel, _MouseDownHitItem);
                if (_HitItem != null && (_MouseDownHitItem != _HitItem))
                    InvalidateItem(panel, _HitItem);
                if (_HitArea == HeaderArea.InRowHeader)
                    InvalidateRowHeader();
                if (_HitArea == HeaderArea.InWhitespace)
                    InvalidateWhitespace();
                _MouseDownHitItem = null;
            }
            _LockedColumn = false;
        }
        internal void ResetColumnStateEx()
        {
            ResetColumnState();
            _HitItem = null;
            _HitArea = HeaderArea.NoWhere;
        }
        #endregion
        #endregion
        #region InternalMouseMove
        internal override void InternalMouseMove(MouseEventArgs e)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                if (AllowSelection == true)
                {
                    if (_Resizing == false)
                    {
                        _LastHitArea = _HitArea;
                        _LastHitItem = _HitItem;
                        _HitArea = GetHitArea(e.Location, ref _HitItem, IsMouseDown);
                        if (_Reordering == false)
                        {
                            if (_HitItem is GridColumn)
                                ProcessColumnMouseMove(e, panel);
                            else if (_HitItem is ColumnGroupHeader)
                                ProcessGroupHeaderMouseMove(e, panel);
                            else
                                ProcessRowHeaderMouseMove(panel);
                            if (_HitArea != _LastHitArea || _LastHitItem != _HitItem)
                            {
                                if (_LastHitItem != null)
                                    InvalidateItem(panel, _LastHitItem);
                                if (_HitItem != null)
                                    InvalidateItem(panel, _HitItem);
                                if (_HitArea == HeaderArea.InRowHeader || _LastHitArea == HeaderArea.InRowHeader)
                                    InvalidateRowHeader();
                                if (_HitArea == HeaderArea.InWhitespace || _LastHitArea == HeaderArea.InWhitespace)
                                    InvalidateWhitespace();
                            }
                        }
                    }
                    if (IsMouseDown == true)
                    {
                        if (ProcessMouseDownMove(e) == false)
                        {
                            if (_MouseDownHitItem != null)
                            {
                                SuperGrid.EnableAutoScrolling(AutoScrollEnable.Horizontal, ViewRect);
                                StopResize();
                                StopReorder();
                            }
                        }
                    }
                }
                SuperGrid.DoColumnHeaderMouseMoveEvent(this, e);
                base.InternalMouseMove(e);
            }
        }
        #region ProcessColumnMouseMove
        private void ProcessColumnMouseMove(MouseEventArgs e, GridPanel panel)
        {
            GridColumn hitColumn = (GridColumn) _HitItem;
            switch (_HitArea)
            {
                case HeaderArea.InContent:
                    SuperGrid.GridCursor = Cursors.Default;
                    if (hitColumn.HeaderTextMarkup != null)
                    {
                        hitColumn.HeaderTextMarkup.MouseMove(SuperGrid, e);
                        if (hitColumn.HeaderTextMarkup.MouseOverElement != null)
                            _HitArea = HeaderArea.InMarkup;
                    }
                    if (_ShowToolTips == true)
                        UpdateToolTip(panel, hitColumn.ToolTip);
                    break;
                case HeaderArea.InResize:
                    SuperGrid.GridCursor = Cursors.VSplit;
                    SuperGrid.ToolTipText = "";
                    break;
                case HeaderArea.InFilterMenu:
                    SuperGrid.GridCursor = Cursors.Hand;
                    if (_ShowFilterToolTips == true && hitColumn.IsFilteringEnabled == true)
                        UpdateToolTip(panel, hitColumn.FilterExpr);
                    break;
                default:
                    SuperGrid.GridCursor = Cursors.Default;
                    SuperGrid.ToolTipText = "";
                    break;
            }
        }
        #endregion
        #region ProcessGroupHeaderMouseMove
        private void ProcessGroupHeaderMouseMove(MouseEventArgs e, GridPanel panel)
        {
            switch (_HitArea)
            {
                case HeaderArea.InContent:
                    SuperGrid.GridCursor = Cursors.Default;
                    ColumnGroupHeader cgh = (ColumnGroupHeader)_HitItem;
                    if (cgh.HeaderTextMarkup != null)
                    {
                        cgh.HeaderTextMarkup.MouseMove(SuperGrid, e);
                        if (cgh.HeaderTextMarkup.MouseOverElement != null)
                            _HitArea = HeaderArea.InMarkup;
                    }
                    if (_ShowToolTips == true)
                        UpdateToolTip(panel, cgh.ToolTip);
                    break;
                case HeaderArea.InResize:
                    SuperGrid.GridCursor = Cursors.VSplit;
                    SuperGrid.ToolTipText = "";
                    break;
                default:
                    SuperGrid.GridCursor = Cursors.Default;
                    SuperGrid.ToolTipText = "";
                    break;
            }
        }
        #endregion
        #region ProcessRowHeaderMouseMove
        private void ProcessRowHeaderMouseMove(GridPanel panel)
        {
            switch (_HitArea)
            {
                case HeaderArea.InRowHeaderResize:
                    SuperGrid.GridCursor = Cursors.VSplit;
                    SuperGrid.ToolTipText = "";
                    break;
                case HeaderArea.InRowHeader:
                    SuperGrid.GridCursor =
                        (panel.TopLeftHeaderSelectBehavior != TopLeftHeaderSelectBehavior.NoSelection)
                            ? Cursors.Hand
                            : Cursors.Default;
                    UpdateToolTip(panel, "");
                    break;
                default:
                    SuperGrid.GridCursor = Cursors.Default;
                    SuperGrid.ToolTipText = "";
                    break;
            }
        }
        #endregion
        #endregion
        #region UpdateToolTip
        private void UpdateToolTip(GridPanel panel, string toolTip)
        {
            if (_HitArea != _LastHitArea || _LastHitItem != _HitItem)
                panel.SetHeaderTooltip(this, _HitItem, _HitArea, toolTip);
        }
        #endregion
        #region ProcessMouseDownMove
        private bool ProcessMouseDownMove(MouseEventArgs e)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                if (_MouseDownHitArea == HeaderArea.InRowHeaderResize)
                    return (InRowHeaderResize(e.Location, e));
                if (_MouseDownHitItem is GridColumn)
                    return (ColumnMouseDownMove(e, panel));
                if (_MouseDownHitItem is ColumnGroupHeader)
                    return (GroupHeaderMouseDownMove(e, panel));
            }
            return (false);
        }
        #region InRowHeaderResize
        private bool InRowHeaderResize(Point pt, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                GridPanel panel = Parent as GridPanel;
                if (panel != null)
                {
                    if (_Resizing == false)
                    {
                        _Resizing = true;
                        _ResizeWidth = panel.RowHeaderWidthEx;
                        if (panel.ImmediateResize == false)
                        {
                            _SeparatorFw = new FloatWindow();
                            _SeparatorFw.Opacity = .5;
                            _SeparatorFw.BackColor = Color.Black;
                            _SeparatorFw.Owner = SuperGrid.FindForm();
                        }
                    }
                    else
                    {
                        if (panel.ImmediateResize == false)
                            ContinueRowHeaderResize(panel, pt);
                        else
                            ResizeRowHeader(panel, pt.X - MouseDownPoint.X);
                    }
                }
                return (true);
            }
            return (false);
        }
        #endregion
        #region ColumnMouseDownMove
        private bool ColumnMouseDownMove(MouseEventArgs e, GridPanel panel)
        {
            GridColumn hitColumn = (GridColumn)_MouseDownHitItem;
            Rectangle r = ViewRect;
            if ((_MouseDownHitArea == HeaderArea.InResize) ||
                (_MouseDownHitArea == HeaderArea.InRowHeaderResize) ||
                (e.X >= r.X && e.X < r.Right) ||
                (hitColumn.IsHFrozen == true && panel.IsSubPanel == false))
            {
                SuperGrid.DisableAutoScrolling();
                switch (_MouseDownHitArea)
                {
                    case HeaderArea.InContent:
                        hitColumn = _MouseDownHitItem as GridColumn;
                        if (hitColumn != null)
                        {
                            if (_HitArea == HeaderArea.InGroupBox &&
                                hitColumn.GroupBoxEffectsEx != GroupBoxEffects.None)
                            {
                                if (ColumnInGroupBox(panel, e, hitColumn) == true)
                                    return (true);
                            }
                        }
                        if (_HitItem == null)
                            return (false);
                        ColumnInContent(e);
                        break;
                    case HeaderArea.InResize:
                        ColumnInResize(e.Location, e);
                        break;
                }
                return (true);
            }
            return (false);
        }
        #region ColumnInGroupBox
        private bool ColumnInGroupBox(
            GridPanel panel, MouseEventArgs e, GridColumn hitColumn)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (hitColumn != null)
                {
                    if (panel.VisibleColumnCount > 1)
                    {
                        if (panel.GroupByRow.DragStart(hitColumn) == true)
                        {
                            ResetColumnState();
                            StopReorder();
                            _MouseDownHitItem = null;
                            _HitArea = HeaderArea.NoWhere;
                            _HitItem = null;
                            return (true);
                        }
                    }
                }
            }
            return (false);
        }
        #endregion
        #region ColumnInContent
        private void ColumnInContent(MouseEventArgs e)
        {
            if (IsDesignerHosted == false)
            {
                if (e.Button == MouseButtons.Left)
                {
                    GridPanel panel = Parent as GridPanel;
                    if (panel != null)
                    {
                        if (DragStarted(panel, e) == false)
                        {
                            if (panel.ColumnDragBehavior == ColumnDragBehavior.ExtendClickBehavior)
                            {
                                switch (panel.ColumnHeaderClickBehavior)
                                {
                                    case ColumnHeaderClickBehavior.SortAndReorder:
                                        ProcessMove(e.Location);
                                        break;
                                    case ColumnHeaderClickBehavior.Select:
                                        if (_HitItem != _LastHitItem)
                                            ProcessExtendSelection(panel, true);
                                        break;
                                }
                            }
                        }
                    }
                }
            }
        }
        #region DragStarted
        private bool DragStarted(GridPanel panel, MouseEventArgs e)
        {
            if (_HitItem is GridColumn)
            {
                if (_DragSelection == true)
                {
                    if (_DragStarted == false)
                    {
                        if (DragDrop.DragStarted(_MouseDownPoint, e.Location) == true)
                        {
                            _DragStarted = true;
                            if (SuperGrid.DoItemDragEvent((GridColumn)_HitItem, e) == true)
                            {
                                _DragSelection = false;
                                ExtendSelection(panel, true);
                            }
                        }
                    }
                    return (true);
                }
            }
            return (false);
        }
        #endregion
        #region ProcessMove
        private void ProcessMove(Point pt)
        {
            if (_Reordering == false)
                StartReorder(pt);
            else
                ContinueReorder(pt);
        }
        #endregion
        #region ProcessExtendSelection
        private void ProcessExtendSelection(GridPanel panel, bool extend)
        {
            bool ckey = (panel.MultiSelect == true) ?
                ((Control.ModifierKeys & Keys.Control) == Keys.Control) : false;
            if (ckey == true)
                ProcessControlExtend(panel);
            else
                ProcessNonControlExtend(panel, extend);
            _lastSelectedItem = _HitItem;
        }
        #region ProcessControlExtend
        private void ProcessControlExtend(GridPanel panel)
        {
            int startIndex = 0;
            int endIndex = 0;
            if (GetSelectionIndicees(panel,
                _lastSelectedItem, _HitItem, ref startIndex, ref endIndex, false) == true)
            {
                int mdStart = 0;
                int mdEnd = 0;
                GetSelectionIndicees(panel,
                    _MouseDownHitItem, _MouseDownHitItem, ref mdStart, ref mdEnd, true);
                panel.NormalizeIndices(true, mdStart, ref startIndex, ref endIndex);
                int[] map = panel.Columns.DisplayIndexMap;
                for (int j = startIndex; j <= endIndex; j++)
                {
                    GridColumn column = panel.Columns[map[j]];
                    if (j < mdStart || j > mdEnd)
                        column.IsSelected = !column.IsSelected;
                }
            }
        }
        #endregion
        #region ProcessNonControlExtend
        private void ProcessNonControlExtend(GridPanel panel, bool extend)
        {
            int startIndex = 0;
            int endIndex = 0;
            if (GetSelectionIndicees(panel,
                panel.SelectionColumnAnchor, _HitItem, ref startIndex, ref endIndex, true) == true)
            {
                int[] map = panel.Columns.DisplayIndexMap;
                if (panel.OnlyColumnsSelected(startIndex, endIndex) == false)
                {
                    if (extend == false)
                        panel.ClearAll();
                    
                    for (int i = 0; i < map.Length; i++)
                    {
                        int index = map[i];
                        GridColumn column = panel.Columns[index];
                        if (column.Visible == true)
                            column.IsSelected = (i >= startIndex && i <= endIndex);
                    }
                }
            }
        }
        #endregion
        #region GetSelectionIndicees
        private bool GetSelectionIndicees(GridPanel panel,
            object start, object end, ref int startIndex, ref int endIndex, bool reorder)
        {
            if (GetSelectionStartIndex(panel, start, ref startIndex) == false)
                return (false);
            if (GetSelectionEndIndex(panel, end, ref endIndex) == false)
                return (false);
            if (startIndex > endIndex)
            {
                if (start is ColumnGroupHeader)
                    startIndex = ((ColumnGroupHeader)start).EndDisplayIndex;
                if (end is ColumnGroupHeader)
                    endIndex = ((ColumnGroupHeader)end).StartDisplayIndex;
                if (reorder == true)
                {
                    int tempIndex = startIndex;
                    startIndex = endIndex;
                    endIndex = tempIndex;
                }
            }
            return (true);
        }
        #endregion
        #region GetSelectionStartIndex
        private bool GetSelectionStartIndex(GridPanel panel, object item, ref int startIndex)
        {
            startIndex = -1;
            if (item is ColumnGroupHeader)
                startIndex = ((ColumnGroupHeader) item).StartDisplayIndex;
            else if (item is GridColumn)
                startIndex = panel.Columns.GetDisplayIndex(((GridColumn) item).ColumnIndex);
            return (startIndex >= 0);
        }
        #endregion
        #region GetSelectionEndIndex
        private bool GetSelectionEndIndex(GridPanel panel, object item, ref int endIndex)
        {
            endIndex = -1;
            if (item is ColumnGroupHeader)
                endIndex = ((ColumnGroupHeader)item).EndDisplayIndex;
            else if (item is GridColumn)
                endIndex = panel.Columns.GetDisplayIndex(((GridColumn) item).ColumnIndex);
            return (endIndex >= 0);
        }
        #endregion
        #endregion
        #endregion
        #region ColumnInResize
        private void ColumnInResize(Point pt, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (_Resizing == false)
                {
                    StartResize();
                }
                else
                {
                    GridPanel panel = Parent as GridPanel;
                    if (panel != null)
                    {
                        if (panel.ImmediateResize == false)
                            ContinueResize(panel, pt);
                        else
                            ResizeColumn(panel, pt.X - MouseDownPoint.X);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region GroupHeaderMouseDownMove
        private bool GroupHeaderMouseDownMove(MouseEventArgs e, GridPanel panel)
        {
            ColumnGroupHeader cgh = (ColumnGroupHeader)_MouseDownHitItem;
            Rectangle r = ViewRect;
            if ((_MouseDownHitArea == HeaderArea.InResize) ||
                (_MouseDownHitArea == HeaderArea.InRowHeaderResize) || (e.X >= r.X && e.X < r.Right) ||
                (panel.IsSubPanel == false && IsGroupHeaderHFrozen(panel, cgh) == true))
            {
                SuperGrid.DisableAutoScrolling();
                switch (_MouseDownHitArea)
                {
                    case HeaderArea.InContent:
                        GroupHeaderInContent(e);
                        break;
                }
                return (true);
            }
            return (false);
        }
        #region GroupHeaderInContent
        private void GroupHeaderInContent(MouseEventArgs e)
        {
            if (IsDesignerHosted == false)
            {
                if (e.Button == MouseButtons.Left)
                {
                    GridPanel panel = Parent as GridPanel;
                    if (panel != null)
                    {
                        if (DragStarted(panel, e) == false)
                        {
                            if (panel.ColumnDragBehavior == ColumnDragBehavior.ExtendClickBehavior)
                            {
                                switch (panel.ColumnGroupHeaderClickBehavior)
                                {
                                    case ColumnHeaderClickBehavior.SortAndReorder:
                                        ProcessMove(e.Location);
                                        break;
                                    case ColumnHeaderClickBehavior.Select:
                                        if (_HitItem != _LastHitItem)
                                            ProcessExtendSelection(panel, true);
                                        break;
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #endregion
        #endregion
        #region InternalMouseDown
        internal override void InternalMouseDown(MouseEventArgs e)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                if (EndCurrentOp() == true)
                {
                    _MouseDownPoint = e.Location;
                    _MouseDownButtons = e.Button;
                    _MouseDownHitItem = _HitItem;
                    _MouseDownHitArea = _HitArea;
                    _DragSelection = false;
                    _DragStarted = false;
                    if (_HitItem is GridColumn)
                        ColumnMouseDown(e, panel);
                    else if (_HitItem is ColumnGroupHeader)
                        GroupHeaderMouseDown(e, panel);
                    else
                        RowHeaderMouseDown(e, panel);
                    _lastSelectedItem = _HitItem;
                }
                SuperGrid.DoColumnHeaderMouseDownEvent(this, e);
                base.InternalMouseDown(e);
            }
        }
        #region EndCurrentOp
        private bool EndCurrentOp()
        {
            GridCell ecell = SuperGrid.EditorCell;
            if (ecell != null)
            {
                if (ecell.EndEdit() == false)
                {
                    _MouseDownHitArea = HeaderArea.NoWhere;
                    return (false);
                }
            }
            if (_Reordering == true || _Resizing == true)
            {
                StopResize();
                StopReorder();
                InvalidateRender();
            }
            return (true);
        }
        #endregion
        #region ColumnMouseDown
        private void ColumnMouseDown(MouseEventArgs e, GridPanel panel)
        {
            GridColumn hitColumn = (GridColumn)_HitItem;
            if (_HitArea == HeaderArea.InContent)
            {
                Capture = true;
                ColumnInContentMouseDown(e, panel, hitColumn);
            }
            else if (_HitArea == HeaderArea.InMarkup)
            {
                InvalidateHeader(panel, hitColumn);
            }
            else
            {
                if (e.Button == MouseButtons.Left)
                {
                    Capture = true;
                    switch (_HitArea)
                    {
                        case HeaderArea.InResize:
                            ColumnInResizeMouseDown(e, panel);
                            break;
                        case HeaderArea.InFilterMenu:
                            ColumnInFilterMouseDown(panel, hitColumn);
                            break;
                    }
                }
            }
        }
        #region ColumnInContentMouseDown
        private void ColumnInContentMouseDown(
            MouseEventArgs e, GridPanel panel, GridColumn hitColumn)
        {
            _MouseDownDelta = e.X - hitColumn.BoundsRelative.X;
            if (panel.IsSubPanel == true || hitColumn.IsHFrozen == false)
                _MouseDownDelta += HScrollOffset;
            if (hitColumn.AllowSelection == true)
            {
                _LastHitItem = null;
                _Reordering = false;
                if (panel.ColumnHeaderClickBehavior == ColumnHeaderClickBehavior.Select)
                {
                    if (hitColumn.IsSelected == false ||
                        ((Control.ModifierKeys & (Keys.Control | Keys.Shift)) != Keys.None))
                    {
                        ExtendSelection(panel, true);
                    }
                    else
                    {
                        _DragSelection = true;
                    }
                }
                else
                {
                    InvalidateItem(panel, _MouseDownHitItem);
                }
            }
        }
        #region ExtendSelection
        private void ExtendSelection(GridPanel panel, bool capture)
        {
            if (capture == true)
                Capture = true;
            if (panel.SelectionColumnAnchor == null ||
                (Control.ModifierKeys & Keys.Shift) != Keys.Shift)
            {
                panel.SelectionColumnAnchor = _MouseDownHitItem;
            }
            if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
            {
                int startIndex = 0;
                int endIndex = 0;
                if (GetSelectionIndicees(panel, _MouseDownHitItem,
                    _MouseDownHitItem, ref startIndex, ref endIndex, true) == true)
                {
                    int[] map = panel.Columns.DisplayIndexMap;
                    for (int i = startIndex; i <= endIndex; i++)
                    {
                        GridColumn column = panel.Columns[map[i]];
                        column.IsSelected = !column.IsSelected;
                    }
                }
            }
            else
            {
                ProcessNonControlExtend(panel, false);
            }
        }
        #endregion
        #endregion
        #region ColumnInResizeMouseDown
        private void ColumnInResizeMouseDown(MouseEventArgs e, GridPanel panel)
        {
            GridColumn hitColumn = _HitItem as GridColumn;
            if (hitColumn != null)
            {
                Capture = true;
                _MouseDownDelta = e.X - hitColumn.BoundsRelative.X;
                if (panel.IsSubPanel == true || hitColumn.IsHFrozen == false)
                    _MouseDownDelta += HScrollOffset;
                _Resizing = false;
                _LastHitItem = null;
            }
        }
        #endregion
        #region ColumnInFilterMouseDown
        private void ColumnInFilterMouseDown(GridPanel panel, GridColumn column)
        {
            ActivateFilterPopup(panel, column);
        }
        #endregion
        #endregion
        #region GroupHeaderMouseDown
        private void GroupHeaderMouseDown(MouseEventArgs e, GridPanel panel)
        {
            ColumnGroupHeader cgh = (ColumnGroupHeader)_HitItem;
            if (_HitArea == HeaderArea.InContent)
            {
                Capture = true;
                GroupHeaderInContentMouseDown(e, panel, cgh);
            }
            else if (_HitArea == HeaderArea.InMarkup)
            {
                InvalidateHeader(panel, cgh);
            }
            else
            {
                if (e.Button == MouseButtons.Left)
                {
                    Capture = true;
                    switch (_HitArea)
                    {
                        case HeaderArea.InResize:
                            ColumnInResizeMouseDown(e, panel);
                            break;
                    }
                }
            }
        }
        #region GroupHeaderInContentMouseDown
        private void GroupHeaderInContentMouseDown(
            MouseEventArgs e, GridPanel panel, ColumnGroupHeader cgh)
        {
            _MouseDownDelta = e.X - cgh.BoundsRelative.X;
            if (panel.IsSubPanel == true || IsGroupHeaderHFrozen(panel, cgh) == false)
                _MouseDownDelta += HScrollOffset;
            if (cgh.AllowSelection == true)
            {
                _LastHitItem = null;
                _Reordering = false;
                if (panel.ColumnGroupHeaderClickBehavior == ColumnHeaderClickBehavior.Select)
                {
                    if (IsGroupHeaderSelected(cgh) == false ||
                        ((Control.ModifierKeys & (Keys.Control | Keys.Shift)) != Keys.None))
                    {
                        ExtendSelection(panel, true);
                    }
                    else
                    {
                        _DragSelection = true;
                    }
                }
                else
                {
                    InvalidateItem(panel, _MouseDownHitItem);
                }
            }
        }
        #endregion
        #endregion
        #region RowHeaderMouseDown
        private void RowHeaderMouseDown(MouseEventArgs e, GridPanel panel)
        {
            if (e.Button == MouseButtons.Left)
            {
                Capture = true;
                switch (_HitArea)
                {
                    case HeaderArea.InRowHeader:
                        InRowHeaderMouseDown(panel);
                        break;
                    case HeaderArea.InRowHeaderResize:
                        InRowHeaderResizeMouseDown();
                        break;
                }
            }
        }
        #region InRowHeaderMouseDown
        private void InRowHeaderMouseDown(GridPanel panel)
        {
            if (panel.TopLeftHeaderSelectBehavior != TopLeftHeaderSelectBehavior.NoSelection)
            {
                bool select = (_SelectAllCount != panel.SelectionUpdateCount);
                if (select == true)
                {
                    if (panel.MultiSelect == true)
                    {
                        panel.SelectAll();
                    }
                    else if (panel.ActiveRow != null)
                    {
                        panel.ClearAll();
                        panel.ActiveRow.IsSelected = true;
                    }
                }
                else
                {
                    panel.ClearAll();
                }
            }
        }
        #endregion
        #region InRowHeaderResizeMouseDown
        private void InRowHeaderResizeMouseDown()
        {
            Capture = true;
            _Resizing = false;
        }
        #endregion
        #endregion
        #endregion
        #region InternalMouseUp
        internal override void InternalMouseUp(MouseEventArgs e)
        {
            SuperGrid.DisableAutoScrolling();
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                if (_Reordering == true)
                {
                    StopReorder();
                    if (_SeparatorColumn != null && _HitItem != _MouseDownHitItem)
                        ReorderItem(panel);
                }
                else if (_Resizing == true && _ResizeColumn != null)
                {
                    StopResize();
                    if (panel.ImmediateResize == false)
                        ResizeColumn(panel, e.Location.X - MouseDownPoint.X);
                }
                else
                {
                    if (_HitItem is GridColumn)
                        ColumnMouseUp(e, panel);
                    else if (_HitItem is ColumnGroupHeader)
                        GroupHeaderMouseUp(e, panel);
                    else
                        RowHeaderMouseUp(e, panel);
                }
            }
            _MouseDownHitItem = null;
            SuperGrid.DoColumnHeaderMouseUpEvent(this, e);
            base.InternalMouseUp(e);
        }
        #region ColumnMouseUp
        private void ColumnMouseUp(MouseEventArgs e, GridPanel panel)
        {
            GridColumn hitColumn = (GridColumn)_HitItem;
            switch (_MouseDownHitArea)
            {
                case HeaderArea.InContent:
                case HeaderArea.InMarkup:
                    if (hitColumn != null && hitColumn == _MouseDownHitItem)
                    {
                        if (SuperGrid.DoColumnHeaderClickEvent(panel, hitColumn, e) == false)
                        {
                            if (e.Button == MouseButtons.Left)
                            {
                                DoHeaderMouseUp(panel, panel.ColumnHeaderClickBehavior,
                                                hitColumn.HeaderTextMarkup, hitColumn);
                                InvalidateHeader(panel, hitColumn);
                            }
                        }
                    }
                    break;
            }
        }
        #endregion
        #region GroupHeaderMouseUp
        private void GroupHeaderMouseUp(MouseEventArgs e, GridPanel panel)
        {
            ColumnGroupHeader cgh = (ColumnGroupHeader)_HitItem;
            switch (_MouseDownHitArea)
            {
                case HeaderArea.InContent:
                case HeaderArea.InMarkup:
                    if (_HitItem == _MouseDownHitItem)
                    {
                        if (SuperGrid.DoColumnGroupHeaderClickEvent(panel, this, cgh, e) == false)
                        {
                            if (e.Button == MouseButtons.Left)
                            {
                                DoHeaderMouseUp(panel, panel.ColumnGroupHeaderClickBehavior,
                                                cgh.HeaderTextMarkup,
                                                panel.Columns.ColumnAtDisplayIndex(cgh.StartDisplayIndex));
                                InvalidateHeader(panel, cgh);
                            }
                        }
                    }
                    break;
            }
        }
        #endregion
        #region DoHeaderMouseUp
        private void DoHeaderMouseUp(GridPanel panel,
            ColumnHeaderClickBehavior cmode, BodyElement bodyElement, GridColumn hitColumn)
        {
            if (panel.FlushActiveRow() == true)
            {
                if (DoMarkupClick(bodyElement) == false)
                {
                    if (_DragSelection == true)
                        ExtendSelection(panel, false);
                    if (cmode == ColumnHeaderClickBehavior.SortAndReorder && panel.IsSortable == true)
                        SortColumn(panel, hitColumn);
                }
            }
        }
        #region DoMarkupClick
        private bool DoMarkupClick(BodyElement bodyElement)
        {
            if (bodyElement != null)
            {
                if (bodyElement.MouseOverElement != null)
                {
                    bodyElement.Click(SuperGrid);
                    SuperGrid.Cursor = Cursors.Default;
                    return (true);
                }
            }
            return (false);
        }
        #endregion
        #endregion
        #region RowHeaderMouseUp
        private void RowHeaderMouseUp(MouseEventArgs e, GridPanel panel)
        {
            switch (_MouseDownHitArea)
            {
                case HeaderArea.InRowHeader:
                    SuperGrid.DoColumnRowHeaderClickEvent(panel);
                    break;
                case HeaderArea.InRowHeaderResize:
                    if (_Resizing == true)
                    {
                        StopResize();
                        if (panel.ImmediateResize == false)
                            ResizeRowHeader(panel, e.Location.X - MouseDownPoint.X);
                    }
                    break;
            }
        }
        #endregion
        #endregion
        #region InternalMouseDoubleClick
        internal override void InternalMouseDoubleClick(MouseEventArgs e)
        {
            GridColumn hitColumn = _HitItem as GridColumn;
            if (hitColumn != null)
            {
                if (SuperGrid.DoColumnHeaderDoubleClickEvent(hitColumn, e) == false)
                {
                    switch (_HitArea)
                    {
                        case HeaderArea.InResize:
                            if (hitColumn.GetAutoSizeMode() == ColumnAutoSizeMode.None)
                            {
                                RowScope scope = (GridPanel.VirtualMode == true || hitColumn.GridPanel.Rows.Count > 1000)
                                                     ? RowScope.OnScreenRows
                                                     : RowScope.AllRows;
                                hitColumn.Width = Dpi.DescaleWidth(hitColumn.GetMaximumCellSize(scope, true).Width);
                            }
                            break;
                    }
                }
            }
            else
            {
                if (_HitArea == HeaderArea.InRowHeader)
                    SuperGrid.DoColumnRowHeaderDoubleClickEvent(GridPanel);
            }
            base.InternalMouseDoubleClick(e);
        }
        #endregion
        #endregion
        #region Column Reorder
        #region StartReorder
        private void StartReorder(Point pt)
        {
            if (_MouseDownHitItem != null && Math.Abs(MouseDownPoint.X - pt.X) > 5)
            {
                Capture = true;
                _Reordering = true;
                _SeparatorColumn = null;
                _HeaderFw = new FloatWindow();
                _HeaderFw.Opacity = .3;
                _HeaderFw.Owner = SuperGrid.FindForm();
                _HeaderFw.Paint += ColumnHeaderFwPaint;
                _SeparatorFw = new FloatWindow();
                _SeparatorFw.Opacity = .5;
                _SeparatorFw.BackColor = Color.Black;
                _SeparatorFw.Owner = SuperGrid.FindForm();
            }
        }
        #endregion
        #region StopReorder
        private void StopReorder()
        {
            _Reordering = false;
            if (_HeaderFw != null)
            {
                _HeaderFw.Close();
                _HeaderFw.Paint -= ColumnHeaderFwPaint;
                _HeaderFw.Dispose();
                _HeaderFw = null;
            }
            if (_SeparatorFw != null)
            {
                HideSeparator();
                _SeparatorFw.Close();
                _SeparatorFw.Dispose();
                _SeparatorFw = null;
            }
            if (_MouseDownHitItem != null)
                InvalidateItem(GridPanel, _MouseDownHitItem);
            if (_HitItem != null)
                InvalidateItem(GridPanel, _HitItem);
        }
        #endregion
        #region ContinueReorder
        private void ContinueReorder(Point pt)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                if (_HitItem != null && _MouseDownHitItem != null)
                {
                    ReorderHeader(pt);
                    if (ValidReorder() == true)
                    {
                        ReorderSeparator(pt);
                    }
                    else if (_SeparatorFw != null)
                    {
                        HideSeparator();
                        _SeparatorColumn = null;
                    }
                }
            }
        }
        #region ValidReorder
        private bool ValidReorder()
        {
            if (IsItemHFrozen(_HitItem) == IsItemHFrozen(_MouseDownHitItem))
            {
                object o1 = GetParent(_HitItem);
                object o2 = GetParent(_MouseDownHitItem);
                if (o1 is GridColumnHeader)
                    o1 = null;
                if (o2 is GridColumnHeader)
                    o2 = null;
                return (o1 == o2);
            }
            return (false);
        }
        #endregion
        #region ReorderHeader
        private void ReorderHeader(Point pt)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                Rectangle r = GetReorderWindowBounds(panel, pt);
                if (r.Width <= 0 || r.Height <= 0)
                {
                    _HeaderFw.Hide();
                }
                else
                {
                    r.Location = SuperGrid.PointToScreen(r.Location);
                    Size size = _HeaderFw.Size;
                    _HeaderFw.Bounds = r;
                    if (_HeaderFw.Visible == false)
                        _HeaderFw.Show();
                    else if (r.Size.Equals(size) == false)
                        _HeaderFw.Refresh();
                }
            }
        }
        #region GetReorderWindowBounds
        private Rectangle GetReorderWindowBounds(GridPanel panel, Point pt)
        {
            Rectangle r = GetReorderBounds(panel, _MouseDownHitItem);
            Rectangle t = SViewRect;
            r.X = (pt.X - _MouseDownDelta);
            int x = Math.Max(r.X, t.X);
            if (r.X < x)
            {
                _OrderTextOffset = r.X - x;
                r.X = x;
                r.Width += _OrderTextOffset;
            }
            else
            {
                _OrderTextOffset = 0;
            }
            int n = r.Right;
            x = Math.Min(n, t.Right);
            if (r.Right > x)
                r.Width -= (r.Right - x);
            if (r.Bottom > t.Bottom)
                r.Height -= (r.Bottom - t.Bottom);
            return (r);
        }
        #endregion
        #endregion
        #region ReorderSeparator
        private void ReorderSeparator(Point pt)
        {
            GridPanel panel = GridPanel;
            Rectangle r = GetReorderBounds(panel, _HitItem);
            Rectangle t = SViewRect;
            if (r.Right > t.Right)
                r.Width = t.Right - r.X;
            bool isRight = (pt.X > r.X + r.Width / 2);
            GridColumn column = GetSeparatorColumn(panel, isRight);
            if (_SeparatorColumn != column || _SeparatorIsRight != isRight)
            {
                _SeparatorColumn = column;
                _SeparatorIsRight = isRight;
                if (column != null)
                {
                    r = GetReorderSeparatorBounds(panel, r, isRight);
                    r.Location = SuperGrid.PointToScreen(r.Location);
                    _SeparatorFw.Show();
                    _SeparatorFw.Bounds = r;
                    _SeparatorFw.Size = r.Size;
                }
                else
                {
                    HideSeparator();
                }
            }
            else
            {
                if (_SeparatorColumn!= null)
                    _SeparatorFw.Show();
            }
        }
        #region HideSeparator
        private void HideSeparator()
        {
            if (_SeparatorFw != null)
                _SeparatorFw.Hide();
        }
        #endregion
        #region GetSeparatorColumn
        private GridColumn GetSeparatorColumn(GridPanel panel, bool isRight)
        {
            if (_HitItem is GridColumn)
                return ((GridColumn) _HitItem);
            ColumnGroupHeader cgh = (ColumnGroupHeader)_HitItem;
            if (cgh != null)
            {
                GridColumnCollection columns = panel.Columns;
                int index = (isRight == true)
                    ? cgh.EndDisplayIndex : cgh.StartDisplayIndex;
                return (columns[columns.DisplayIndexMap[index]]);
            }
            return (null);
        }
        #endregion
        #region GetReorderSeparatorBounds
        private Rectangle GetReorderSeparatorBounds(
            GridPanel panel, Rectangle r, bool isRight)
        {
            if (isRight == true)
                r.X = r.Right - (SeparatorWidth >> 1);
            else
                r.X -= (SeparatorWidth >> 1);
            r.Width = SeparatorWidth;
            if (r.X >= panel.BoundsRelative.Right - 2)
                r.X = panel.BoundsRelative.Right - 3;
            Rectangle t = SViewRect;
            if (r.Bottom > t.Bottom)
                r.Height -= (r.Bottom - t.Bottom);
            if (r.X < t.X)
                r.X = t.X;
            else if (r.Right > t.Right)
                r.X = t.Right - SeparatorWidth;
            return (r);
        }
        #endregion
        #endregion
        #endregion
        #region GetReorderBounds
        private Rectangle GetReorderBounds(GridPanel panel, object item)
        {
            Rectangle r = BoundsRelative;
            if (item is GridColumn)
            {
                GridColumn column = (GridColumn)item;
                int index = panel.Columns.GetDisplayIndex(column);
                ColumnGroupHeader cgh = GetParentHeader(index);
                if (cgh != null)
                    r.Y = r.Bottom - (cgh.Size.Height - cgh.BoundsRelative.Height);
                r.Height = (panel.BoundsRelative.Height - (r.Y - panel.BoundsRelative.Y));
                r.X = column.BoundsRelative.X;
                r.Width = column.BoundsRelative.Width;
                if (panel.IsSubPanel == true || column.IsHFrozen == false)
                    r.X -= HScrollOffset;
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                return (r);
            }
            if (item is ColumnGroupHeader)
            {
                ColumnGroupHeader cgh = (ColumnGroupHeader)item;
                r.Y = r.Bottom - cgh.Size.Height;
                r.Height = (panel.BoundsRelative.Height - (r.Y - panel.BoundsRelative.Y));
                r.X = cgh.BoundsRelative.X;
                r.Width = cgh.BoundsRelative.Width;
                if (panel.IsSubPanel == true || IsGroupHeaderHFrozen(panel, cgh) == false)
                    r.X -= HScrollOffset;
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
            }
            return (r);
        }
        #endregion
        #region ReorderItem
        private void ReorderItem(GridPanel panel)
        {
            if (_MouseDownHitItem is GridColumn)
                ReorderColumn(panel);
            if (_MouseDownHitItem is ColumnGroupHeader)
                ReorderGroupHeader(panel);
        }
        #region ReorderColumn
        private void ReorderColumn(GridPanel panel)
        {
            GridColumn hitColumn = (GridColumn)_MouseDownHitItem;
            GridColumnCollection columns = _Columns;
            int[] map = columns.DisplayIndexMap;
            int curIndex = columns.GetDisplayIndex(hitColumn);
            int sepIndex = columns.GetDisplayIndex(_SeparatorColumn);
            if (curIndex > sepIndex && _SeparatorIsRight == true && sepIndex < map.Length - 1)
                sepIndex++;
            else if (curIndex < sepIndex && _SeparatorIsRight == false && sepIndex > 0)
                sepIndex--;
            if (sepIndex != curIndex)
            {
                ColumnGroupHeader parent = GetParent(hitColumn) as ColumnGroupHeader;
                int[] dmap = new int[map.Length];
                if (sepIndex < curIndex)
                {
                    for (int i = curIndex; i > sepIndex; i--)
                    {
                        map[i] = map[i - 1];
                        dmap[i - 1] = 1;
                    }
                }
                else
                {
                    for (int i = curIndex; i < sepIndex; i++)
                    {
                        map[i] = map[i + 1];
                        dmap[i + 1] = -1;
                    }
                }
                map[sepIndex] = hitColumn.ColumnIndex;
                dmap[curIndex] = sepIndex - curIndex;
                for (int i = 0; i < map.Length; i++)
                    columns[map[i]].DisplayIndex = i;
                UpdateGroupHeaderRanges(parent != null ? parent.GroupHeaders : GroupHeaders, dmap);
                SuperGrid.UpdateStyleCount();
                SuperGrid.PrimaryGrid.InvalidateRender();
                SuperGrid.DoColumnMovedEvent(panel, hitColumn);
            }
        }
        #endregion
        #region ReorderGroupHeader
        private void ReorderGroupHeader(GridPanel panel)
        {
            ColumnGroupHeader cgh = (ColumnGroupHeader)_MouseDownHitItem;
            GridColumnCollection columns = _Columns;
            int[] map = columns.DisplayIndexMap;
            int curStartIndex = cgh.StartDisplayIndex;
            int curEndIndex = cgh.EndDisplayIndex;
            int sepIndex = columns.GetDisplayIndex(_SeparatorColumn);
            if (curStartIndex > sepIndex && _SeparatorIsRight == true && sepIndex < map.Length - 1)
                sepIndex++;
            else if (curEndIndex < sepIndex && _SeparatorIsRight == false && sepIndex > 0)
                sepIndex--;
            if (sepIndex != curStartIndex && sepIndex != curEndIndex)
            {
                ColumnGroupHeader parent = GetParent(cgh) as ColumnGroupHeader;
                int n = curEndIndex - curStartIndex + 1;
                int[] temp = new int[n];
                int[] dmap = new int[map.Length];
                for (int i = 0; i < n; i++)
                    temp[i] = map[curStartIndex + i];
                for (int i = 0; i < dmap.Length; i++)
                    dmap[i] = 0;
                if (sepIndex < curStartIndex)
                {
                    for (int i = curStartIndex - 1; i >= sepIndex; i--)
                    {
                        map[i + n] = map[i];
                        dmap[i] = n;
                    }
                    for (int i = 0; i < n; i++)
                        map[sepIndex + i] = temp[i];
                    for (int i = curStartIndex; i <= curEndIndex; i++)
                        dmap[i] = sepIndex - curStartIndex;
                }
                else
                {
                    for (int i = curEndIndex + 1; i <= sepIndex; i++)
                    {
                        map[i - n] = map[i];
                        dmap[i] = -n;
                    }
                    for (int i = 0; i < n; i++)
                        map[sepIndex - n + i + 1] = temp[i];
                    for (int i = curStartIndex; i <= curEndIndex; i++)
                        dmap[i] = sepIndex - curEndIndex;
                }
                for (int i = 0; i < map.Length; i++)
                    columns[map[i]].DisplayIndex = i;
                UpdateGroupHeaderRanges(parent != null ? parent.GroupHeaders : cgh.Collection, dmap);
                SuperGrid.UpdateStyleCount();
                SuperGrid.PrimaryGrid.InvalidateRender();
                for (int i = curStartIndex; i <= curEndIndex; i++)
                    SuperGrid.DoColumnMovedEvent(panel, columns[map[i]]);
            }
        }
        #endregion
        #region UpdateGroupHeaderRanges
        private void UpdateGroupHeaderRanges(ColumnGroupHeaderCollection csc, int[] dmap)
        {
            foreach (ColumnGroupHeader cgh in csc)
            {
                if (cgh.Visible == true)
                {
                    UpdateGroupHeaderRanges(cgh.GroupHeaders, dmap);
                    cgh.StartDisplayIndex += dmap[cgh.StartDisplayIndex];
                    cgh.EndDisplayIndex += dmap[cgh.EndDisplayIndex];
                }
            }
        }
        #endregion
        #endregion
        #region ColumnHeaderFwPaint
        void ColumnHeaderFwPaint(object sender, PaintEventArgs e)
        {
            GridPanel panel = GridPanel;
            if (_MouseDownHitItem is GridColumn)
            {
                GridColumn mouseDownHitColumn = (GridColumn)_MouseDownHitItem;
                Rectangle r = mouseDownHitColumn.BoundsRelative;
                r.Y = 0;
                r.X = _OrderTextOffset;
                r.Height = e.ClipRectangle.Height;
                RenderColumnHeader(e.Graphics, panel, mouseDownHitColumn, r, false);
                r.Width--;
                r.Height--;
                e.Graphics.DrawRectangle(Pens.DimGray, r);
            }
            else if (_MouseDownHitItem is ColumnGroupHeader)
            {
                ColumnGroupHeader cgh = (ColumnGroupHeader)_MouseDownHitItem;
                Rectangle r = cgh.BoundsRelative;
                r.Y = 0;
                r.X = _OrderTextOffset;
                r.Height = e.ClipRectangle.Height;
                RenderGroupHeader(e.Graphics, panel, cgh, r);
                r.Width--;
                r.Height--;
                e.Graphics.DrawRectangle(Pens.DimGray, r);
            }
        }
        #endregion
        #region SortColumn
        internal void SortColumn(GridPanel panel, GridColumn column)
        {
            if (panel.IsSortable == true)
            {
                if (column.IsGroupColumn == true)
                {
                    column.GroupDirection =
                        ToggleSortDirection(panel, column.GroupDirection, column.SortCycle);
                    SuperGrid.DoSortChangedEvent(panel);
                }
                else if (column.ColumnSortMode != ColumnSortMode.None)
                {
                    SortDirection sortDirection =
                        ToggleSortDirection(panel, column.SortDirection, column.SortCycle);
                    if (column.ColumnSortMode == ColumnSortMode.Multiple &&
                         ((Control.ModifierKeys & Keys.Shift) == Keys.Shift))
                    {
                        panel.AddSort(column, sortDirection);
                    }
                    else
                    {
                        if (panel.SortColumns.Count > 1)
                            sortDirection = SortDirection.Ascending;
                        panel.SetSort(column, sortDirection);
                    }
                    SuperGrid.DoSortChangedEvent(panel);
                }
                else
                {
                    InvalidateHeader(panel, column);
                }
            }
            else
            {
                InvalidateHeader(panel, column);
            }
        }
        #region ToggleSortDirection
        private SortDirection ToggleSortDirection(
            GridPanel panel, SortDirection dir, SortCycle sortCycle)
        {
            if (dir == SortDirection.Ascending)
                return (SortDirection.Descending);
            if (dir == SortDirection.None)
                return (SortDirection.Ascending);
            if (sortCycle == SortCycle.NotSet)
            {
                sortCycle = panel.SortCycle;
                if (sortCycle == SortCycle.NotSet)
                    sortCycle = SortCycle.AscDesc;
            }
            return (sortCycle == SortCycle.AscDescNone ? SortDirection.None : SortDirection.Ascending);
        }
        #endregion
        #endregion
        #endregion
        #region Column Resize
        #region StartResize
        private void StartResize()
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                _ResizeColumn = _MouseDownHitItem as GridColumn;
                if (_ResizeColumn != null)
                {
                    _Resizing = true;
                    _ResizeWidth = _ResizeColumn.Size.Width;
                    _HitItem = _ResizeColumn;
                    _HitArea = HeaderArea.InResize;
                    if (panel.ImmediateResize == false)
                    {
                        _SeparatorFw = new FloatWindow();
                        _SeparatorFw.Opacity = .5;
                        _SeparatorFw.BackColor = Color.Black;
                        _SeparatorFw.Owner = SuperGrid.FindForm();
                    }
                }
            }
        }
        #endregion
        #region StopResize
        private void StopResize()
        {
            _Resizing = false;
            if (_SeparatorFw != null)
            {
                HideSeparator();
                _SeparatorFw.Close();
                _SeparatorFw.Dispose();
                _SeparatorFw = null;
            }
        }
        #endregion
        #region ContinueResize
        private void ContinueResize(GridPanel panel, Point pt)
        {
            Rectangle r = panel.BoundsRelative;
            r.Y = BoundsRelative.Y;
            if (panel.IsSubPanel == true)
                r.Y -= VScrollOffset;
            r.X -= HScrollOffset;
            if (pt.X > r.X)
            {
                Rectangle t = _ResizeColumn.BoundsRelative;
                t.X -= HScrollOffset;
                int width = pt.X - t.X;
                int n = Dpi.Width(_ResizeColumn.MinimumWidth);
                if (width < n)
                    pt.X = t.X + n;
                if (pt.X >= SuperGrid.PrimaryGrid.BoundsRelative.Right - Dpi.Width2)
                {
                    HideSeparator();
                }
                else
                {
                    if (pt.X == panel.BoundsRelative.Right - 1)
                        pt.X -= 1;
                    r.X = pt.X;
                    r.Width = Dpi.Width(SeparatorWidth);
                    r.Height -= (BoundsRelative.Y - panel.BoundsRelative.Y);
                    t = SViewRect;
                    if (r.Bottom > t.Bottom)
                        r.Height -= (r.Bottom - t.Bottom);
                    r.Location = SuperGrid.PointToScreen(r.Location);
                    _SeparatorFw.Show();
                    _SeparatorFw.Bounds = r;
                    _SeparatorFw.Size = r.Size;
                }
            }
        }
        #endregion
        #region ResizeColumn
        #region ResizeColumn
        private void ResizeColumn(GridPanel panel, int width)
        {
            ColumnAutoSizeMode autoSizeMode = _ResizeColumn.GetAutoSizeMode();
            if (autoSizeMode == ColumnAutoSizeMode.None)
                ResizeNoneColumn(panel, width);
            else if (autoSizeMode == ColumnAutoSizeMode.Fill)
                ResizeFillColumn(panel, width);
        }
        #endregion
        #region ResizeNoneColumn
        private void ResizeNoneColumn(GridPanel panel, int width)
        {
            int newWidth = _ResizeWidth + width;
            int n = Dpi.Width(_ResizeColumn.MinimumWidth);
            if (newWidth < n)
                newWidth = n;
            if (_ResizeColumn.ResizeMode == ColumnResizeMode.MoveFollowingElements)
            {
                _ResizeColumn.Width = Dpi.DescaleWidth(newWidth);
            }
            else if (_ResizeColumn.ResizeMode == ColumnResizeMode.MaintainTotalWidth)
            {
                GridColumn ncolumn = panel.Columns.GetNextVisibleColumn(_ResizeColumn);
                if ((ncolumn == null) || (ncolumn.GetAutoSizeMode() != ColumnAutoSizeMode.None))
                {
                    _ResizeColumn.Width = Dpi.DescaleWidth(newWidth);
                }
                else
                {
                    int twidth = _ResizeColumn.Size.Width + ncolumn.Size.Width;
                    int nwidth = twidth - newWidth;
                    int n2 = Dpi.Width(ncolumn.MinimumWidth);
                    if (nwidth < n2)
                        nwidth = n2;
                    newWidth = twidth - nwidth;
                    _ResizeColumn.Width = Dpi.DescaleWidth(newWidth);
                    ncolumn.Width = Dpi.DescaleWidth(nwidth);
                }
            }
        }
        #endregion
        #region ResizeFillColumn
        private void ResizeFillColumn(GridPanel panel, int width)
        {
            int fillWeight = 0;
            int fillWidth = 0;
            GridColumnCollection columns = _Columns;
            int colDisplayIndex = columns.GetDisplayIndex(_ResizeColumn);
            int[] map = columns.DisplayIndexMap;
            for (int i = 0; i < map.Length; i++)
            {
                int index = map[i];
                GridColumn column = columns[index];
                if (column.Visible == true)
                {
                    if (column.GetAutoSizeMode() == ColumnAutoSizeMode.Fill)
                    {
                        fillWidth += column.Size.Width;
                        if (i != colDisplayIndex)
                            fillWeight += column.FillWeight;
                    }
                }
            }
            if (fillWidth > 0 && fillWeight > 0)
            {
                int nw = _ResizeWidth + width;
                int newFillWidth = fillWidth - nw;
                for (int i = 0; i < map.Length; i++)
                {
                    int index = map[i];
                    GridColumn column = columns[index];
                    if (column.Visible == true)
                    {
                        if (column.GetAutoSizeMode() == ColumnAutoSizeMode.Fill)
                        {
                            float colWidth;
                            if (i != colDisplayIndex)
                                colWidth = (int)(newFillWidth * (float)column.FillWeight / fillWeight);
                            else
                                colWidth = nw;
                            int n = Dpi.Width(column.MinimumWidth);
                            if (colWidth < n)
                                colWidth = n;
                            column.FillWeight = (int)((colWidth * 1000) / fillWidth);
                        }
                    }
                }
                panel.SuperGrid.Invalidate();
            }
        }
        #endregion
        #endregion
        #endregion
        #region RowHeader Resize
        #region ContinueRowHeaderResize
        private void ContinueRowHeaderResize(GridPanel panel, Point pt)
        {
            Rectangle r = panel.BoundsRelative;
            r.Y = BoundsRelative.Y;
            if (panel.IsSubPanel == true)
                r.Y -= VScrollOffset;
            r.X -= HScrollOffset;
            if (pt.X > r.X)
            {
                int width = pt.X - r.X;
                if (width < 5)
                    pt.X = r.X + 5;
                if (pt.X >= SuperGrid.PrimaryGrid.BoundsRelative.Right - 2)
                {
                    HideSeparator();
                }
                else
                {
                    if (pt.X == panel.BoundsRelative.Right - 1)
                        pt.X--;
                    r.X = pt.X;
                    r.Width = SeparatorWidth;
                    r.Height -= (BoundsRelative.Y - panel.BoundsRelative.Y);
                    Rectangle t = SViewRect;
                    if (r.Bottom > t.Bottom)
                        r.Height -= (r.Bottom - t.Bottom);
                    r.Location = SuperGrid.PointToScreen(r.Location);
                    _SeparatorFw.Show();
                    _SeparatorFw.Bounds = r;
                    _SeparatorFw.Size = r.Size;
                }
            }
        }
        #endregion
        #region ResizeRowHeader
        private void ResizeRowHeader(GridPanel panel, int width)
        {
            Rectangle t = panel.ViewRect;
            int n = Math.Max(5, _ResizeWidth + width);
            if (t.Right - 10 < n)
                n = t.Right - 10;
            n = Dpi.DescaleWidth(n);
            if (panel.RowHeaderWidth != n)
            {
                panel.RowHeaderWidth = n;
                panel.SuperGrid.Invalidate();
                SuperGrid.DoRowHeaderResizedEvent(panel);
            }
        }
        #endregion
        #endregion
        #region ActivateFilterPopup
        internal void ActivateFilterPopup(GridPanel panel, GridColumn column)
        {
            if (_FilterMenu != null)
                _FilterMenu.Dispose();
            _FilterMenu = new FilterPopup(panel);
            _LockedColumn = true;
            _HitArea = HeaderArea.NoWhere;
            _FilterMenu.ActivatePopup(column, ResetColumnState);
        }
        #endregion
        #region DeactivateFilterPopup
        internal void DeactivateFilterPopup(GridPanel panel, GridColumn column)
        {
            FilterPopup fm = _FilterMenu;
            if (fm != null)
                fm.DeactivatePopup();
        }
        #endregion
        #region GetHitArea
        ///
        /// Returns the ColumnHeader hit area
        /// and column for the given Point
        ///
        ///
        ///
        ///HeaderArea
        public HeaderArea GetHitArea(Point pt, ref GridColumn column)
        {
            object hitItem = null;
            HeaderArea area = GetHitArea(pt, ref hitItem, false);
            column = hitItem as GridColumn;
            return (area);
        }
        ///
        /// Returns the ColumnHeader hit area
        /// and hit object for the given Point
        ///
        ///
        ///
        ///
        public HeaderArea GetHitArea(Point pt, ref object hitItem)
        {
            return (GetHitArea(pt, ref hitItem, false));
        }
        private HeaderArea GetHitArea(
            Point pt, ref object hitItem, bool isMouseDown)
        {
            GridPanel panel = Parent as GridPanel;
            if (panel != null)
            {
                GridElement hitObject = GetHitObject(panel, pt, isMouseDown);
                if (hitObject == this)
                    return (GetHeaderHitArea(panel, pt, ref hitItem, isMouseDown));
                if (hitObject == panel.GroupByRow)
                    return (HeaderArea.InGroupBox);
            }
            return (HeaderArea.NoWhere);
        }
        #region GetHitObject
        private GridElement GetHitObject(
            GridPanel panel, Point pt, bool isMouseDown)
        {
            if (isMouseDown == true && panel.GroupByRow.Visible == true)
            {
                if (panel.GroupByRow.Bounds.Contains(pt) == true)
                    return (panel.GroupByRow);
            }
            if (Capture == true || Bounds.Contains(pt) == true)
                return (this);
            return (null);
        }
        #endregion
        #region GetHeaderHitArea
        private HeaderArea GetHeaderHitArea(GridPanel panel,
            Point pt, ref object hitItem, bool isMouseDown)
        {
            hitItem = null;
            HeaderArea area = GetRowHeaderArea(panel, pt);
            if (area != HeaderArea.NoWhere)
                return (area);
            area = GetGroupHeaderArea(panel, pt, ref hitItem);
            if (area != HeaderArea.NoWhere)
                return (area);
            GridColumn column = GetHitColumn(panel, pt, isMouseDown, false);
            area = GetHeaderArea(panel, pt, ref column);
            hitItem = column;
            return (area);
        }
        #region GetGroupHeaderArea
        private HeaderArea GetGroupHeaderArea(GridPanel panel, Point pt, ref object hitItem)
        {
            ColumnGroupHeader cgh = GetHitGroupHeader(panel, pt, _GroupHeaders);
            if (cgh != null)
            {
                if (GetShowRootColumnHeaders(cgh) == false)
                {
                    GridColumn coll = GetHitColumn(panel, pt, false, true);
                    if (coll != null)
                    {
                        HeaderArea area = GetHeaderArea(panel, pt, ref coll);
                        if (area == HeaderArea.InResize)
                        {
                            hitItem = coll;
                            return (area);
                        }
                    }
                }
                hitItem = cgh;
                if (IsMouseDown == false)
                {
                    int[] map = panel.Columns.DisplayIndexMap;
                    Rectangle r = GetSubScrollBounds(panel, cgh);
                    if (pt.X < r.Left + 3 && pt.X >= r.Left)
                    {
                        if ((uint)cgh.StartDisplayIndex < map.Length)
                        {
                            GridColumn column = panel.Columns[map[cgh.StartDisplayIndex]];
                            if (InLeftResizeArea(ref column, panel) == true)
                            {
                                hitItem = column;
                                return (HeaderArea.InResize);
                            }
                        }
                    }
                    if ((pt.X > r.Right - 5) && (pt.X < r.Right + 3))
                    {
                        if ((uint)cgh.EndDisplayIndex < map.Length)
                        {
                            GridColumn column = panel.Columns[map[cgh.EndDisplayIndex]];
                            if (InRightResizeArea(ref column, panel) == true)
                            {
                                hitItem = column;
                                return (HeaderArea.InResize);
                            }
                        }
                    }
                }
                if (cgh.AllowSelection == true)
                    return (HeaderArea.InContent);
                return (HeaderArea.NoWhere);
            }
            return (HeaderArea.NoWhere);
        }
        #endregion
        #region GetHitGroupHeader
        private ColumnGroupHeader GetHitGroupHeader(
            GridPanel panel, Point pt, ColumnGroupHeaderCollection csc)
        {
            if (csc != null)
            {
                foreach (ColumnGroupHeader cgh in csc)
                {
                    if (cgh.Visible == true)
                    {
                        Rectangle r = GetSubScrollBounds(panel, cgh);
                        if (r.Contains(pt) == true)
                            return (cgh);
                        ColumnGroupHeader csh2 = GetHitGroupHeader(panel, pt, cgh.GroupHeaders);
                        if (csh2 != null)
                            return (csh2);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region GetRowHeaderArea
        private HeaderArea GetRowHeaderArea(GridPanel panel, Point pt)
        {
            Rectangle r = GetRowHeaderBounds(panel);
            r.Width += Dpi.Width2;
            if (r.Contains(pt) == true)
            {
                if (Capture == true)
                    return (_HitArea);
                r.Width -= Dpi.Width2;
                if (panel.AllowRowHeaderResize == true)
                {
                    if (pt.X >= r.Right - Dpi.Width5)
                        return (HeaderArea.InRowHeaderResize);
                }
                return (HeaderArea.InRowHeader);
            }
            return (HeaderArea.NoWhere);
        }
        #endregion
        #region GetHitColumn
        ///
        /// Gets the associated column at the given location
        ///
        ///
        ///
        ///
        public GridColumn GetHitColumn(int x, int y)
        {
            return (GetHitColumn(new Point(x, y)));
        }
        ///
        /// Gets the associated column at the given point
        ///
        ///
        ///
        public GridColumn GetHitColumn(Point pt)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
                return (GetHitColumn(panel, pt, false, false));
            return (null);
        }
        private GridColumn GetHitColumn(
            GridPanel panel, Point pt, bool isMouseDown, bool limit)
        {
            int dy = (isMouseDown == true) ? 50 : 0;
            GridColumnCollection columns = _Columns;
            foreach (GridColumn column in columns)
            {
                if (column.Visible == true)
                {
                    Rectangle r = GetBounds(panel, column);
                    if (pt.X >= r.Left && pt.X < r.Right)
                    {
                        int top = limit ? r.Bottom - 10 : r.Top;
                        if (pt.Y >= top && pt.Y < r.Bottom + dy)
                            return (column);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region GetHeaderArea
        private HeaderArea GetHeaderArea(GridPanel panel, Point pt, ref GridColumn column)
        {
            GridColumn hcolumn = column;
            if (column == null)
                column = panel.Columns.LastVisibleColumn;
            if (column != null)
            {
                Rectangle r = column.BoundsRelative;
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                if (panel.IsSubPanel == true || column.IsHFrozen == false)
                    r.X -= HScrollOffset;
                if (pt.X < r.Left + 3 && pt.X >= r.Left)
                {
                    if (InLeftResizeArea(ref column, panel) == true)
                        return (HeaderArea.InResize);
                }
                if ((pt.X > r.Right - 5) && (pt.X < r.Right + 3))
                {
                    if (InRightResizeArea(ref column, panel) == true)
                        return (HeaderArea.InResize);
                }
                if (column.FilterImageBounds.IsEmpty == false)
                {
                    Rectangle t = GetScrollBounds(
                        panel, column, column.FilterImageBounds);
                    t.Inflate(2, 2);
                    if (t.Contains(pt) == true)
                        return (HeaderArea.InFilterMenu);
                }
                column = hcolumn;
                if (hcolumn != null)
                {
                    if (column.AllowSelection == true)
                        return (HeaderArea.InContent);
                    return (HeaderArea.NoWhere);
                }
            }
            return (HeaderArea.InWhitespace);
        }
        #region InLeftResizeArea
        private bool InLeftResizeArea(ref GridColumn column, GridPanel panel)
        {
            GridColumn pcolumn =
                panel.Columns.GetPrevVisibleColumn(column);
            if (pcolumn != null)
            {
                if (pcolumn.CanResize == true && pcolumn.ResizeMode != ColumnResizeMode.None)
                {
                    column = pcolumn;
                    return (true);
                }
            }
            return (false);
        }
        #endregion
        #region InRightResizeArea
        private bool InRightResizeArea(ref GridColumn column, GridPanel panel)
        {
            GridColumn nColumn =
                panel.Columns.GetNextVisibleColumn(column);
            if (nColumn != null && nColumn.Size.Width < 5)
            {
                if (nColumn.CanResize == true && nColumn.ResizeMode != ColumnResizeMode.None)
                    column = nColumn;
            }
            if (column.CanResize == true && column.ResizeMode != ColumnResizeMode.None)
                return (true);
            return (false);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region GetParent
        ///
        ///Gets the object that is the "parent" of the given item
        ///(either a GridColumn or ColumnGroupHeader).
        ///
        ///
        ///Parent or null
        public object GetParent(object item)
        {
            if (item is GridColumn)
                return (GetParentHeader((GridColumn) item));
            ColumnGroupHeader cgh = item as ColumnGroupHeader;
            if (cgh != null)
                return (cgh.Collection.Parent);
            return (null);
        }
        #endregion
        #region GetParentHeader
        ///
        ///Gets the object that is the "parent" of the given column.
        ///
        ///
        ///parent or null
        public object GetParentHeader(GridColumn column)
        {
            int index = GridPanel.Columns.GetDisplayIndex(column);
            return (GetParentHeader(index));
        }
        ///
        ///Gets the ColumnGroupHeader that is the "parent" of the column at
        ///the given DISPLAY index.
        ///
        ///DISPLAY INDEX
        ///parent object or null
        public ColumnGroupHeader GetParentHeader(int displayIndex)
        {
            ColumnGroupHeader tcsh = GetColumnGroupHeader(GroupHeaders, displayIndex);
            if (tcsh != null)
            {
                while (tcsh.GroupHeaders != null)
                {
                    ColumnGroupHeader fcsh = GetColumnGroupHeader(tcsh.GroupHeaders, displayIndex);
                    if (fcsh == null || fcsh.Visible == false)
                        break;
                    tcsh = fcsh;
                }
            }
            return (tcsh);
        }
        #endregion
        #region GetColumnGroupHeader
        internal ColumnGroupHeader GetColumnGroupHeader(int index)
        {
            return (GetColumnGroupHeader(GroupHeaders, index));
        }
        private ColumnGroupHeader GetColumnGroupHeader(IEnumerable csc, int index)
        {
            if (csc != null)
            {
                foreach (ColumnGroupHeader cgh in csc)
                {
                    if (cgh.Contains(index))
                        return (cgh.Visible == true ? cgh : null);
                }
            }
            return (null);
        }
        #endregion
        #region UpdateImageBounds
        internal void UpdateImageBounds(GridPanel panel, GridColumn column)
        {
            Rectangle r = GetColumnHeaderBounds(panel, column);
            if (column.AdjustSortImagePositionByMargin == true)
            {
                VisualStyle style = GetEffectiveStyle(column);
                r.X += (style.BorderThickness.Left + style.Margin.Left);
                r.Width -= (style.BorderThickness.Horizontal + style.Margin.Horizontal);
                r.Y += (style.BorderThickness.Top + style.Margin.Top);
                r.Height -= (style.BorderThickness.Vertical + style.Margin.Vertical);
            }
            r.Inflate(-3, -3);
            r.Width--;
            Alignment sortAlignment = (_SortImageAlignment == Alignment.NotSet)
                ? Alignment.TopCenter : _SortImageAlignment;
            Alignment filterAlignment = (_FilterImageAlignment == Alignment.NotSet)
                ? Alignment.MiddleLeft : _FilterImageAlignment;
            Rectangle rt = r;
            column.SortImageBounds = Rectangle.Empty;
            column.FilterImageBounds = Rectangle.Empty;
            Image sortImage = GetColumnSortImage(panel, column);
            if (sortImage != null)
            {
                Rectangle t = GetImageBounds(sortImage, sortAlignment, ref r);
                column.SortImageBounds = t;
            }
            Image filterImage = GetColumnFilterImage(column);
            if (filterImage != null)
            {
                Rectangle t;
                if (sortImage != null && filterAlignment == sortAlignment)
                {
                    t = GetImageBounds(filterImage, filterAlignment, ref r);
                    switch (filterAlignment)
                    {
                        case Alignment.TopCenter:
                        case Alignment.MiddleCenter:
                        case Alignment.BottomCenter:
                            t.X = rt.X + (r.Width - (sortImage.Width +
                                filterImage.Width)) / 2 + sortImage.Width;
                            break;
                        case Alignment.TopLeft:
                        case Alignment.MiddleLeft:
                        case Alignment.BottomLeft:
                            break;
                    }
                }
                else
                {
                    t = GetImageBounds(filterImage, filterAlignment, ref rt);
                    r.Intersect(rt);
                }
                column.FilterImageBounds = t;
            }
        }
        #endregion
        #region GetColumnHeaderBounds
        private Rectangle GetColumnHeaderBounds(GridPanel panel, GridColumn column)
        {
            Rectangle r = GetRelativeBounds(panel, column);
            r.X = column.BoundsRelative.X;
            r.Width = column.BoundsRelative.Width;
            ColumnGroupHeader cgh = GetParentHeader(panel.Columns.GetDisplayIndex(column.ColumnIndex));
            if (cgh != null)
            {
                int n = cgh.Size.Height - cgh.BoundsRelative.Height;
                r.Y = r.Bottom - n;
                r.Height = n;
            }
            return (r);
        }
        #endregion
        #region GetRelativeSubSize
        internal int GetRelativeSubSize(ColumnGroupHeader cgh, int index)
        {
            int n = cgh.BoundsRelative.Height;
            foreach (ColumnGroupHeader sub in cgh.GroupHeaders)
            {
                if (sub.Contains(index) == true)
                    n += GetRelativeSubSize(sub, index);
            }
            return (n);
        }
        #endregion
        #region GetRowHeaderBounds
        private Rectangle GetRowHeaderBounds(GridPanel panel)
        {
            if (panel.ShowRowHeaders == true)
            {
                Rectangle r = Bounds;
                r.Width = panel.RowHeaderWidthEx;
                Rectangle p = panel.PanelBounds;
                if (r.Y < p.Y)
                {
                    r.Height -= (p.Y - r.Y + 1);
                    r.Y = p.Y + 1;
                }
                return (r);
            }
            return (Rectangle.Empty);
        }
        #endregion
        #region Style support
        #region GroupHeader Style support
        #region InvalidateStyle
        ///
        ///Invalidates the cached Style
        ///definition for all defined StyleTypes
        ///
        public void InvalidateStyle()
        {
            GridColumnCollection columns = GridPanel.Columns;
            foreach (GridColumn column in columns)
                column.InvalidateStyle();
            InvalidateStyle(GroupHeaders);
        }
        ///
        ///Invalidates the cached Style
        ///definition for all GroupHeader defined StyleTypes
        ///
        ///
        public void InvalidateStyle(ColumnGroupHeader cgh)
        {
            if (cgh.EffectiveStyles != null)
            {
                cgh.EffectiveStyles.Dispose();
                cgh.EffectiveStyles = null;
            }
            InvalidateStyle(cgh.GroupHeaders);
        }
        private void InvalidateStyle(IEnumerable groups)
        {
            foreach (ColumnGroupHeader cgh in groups)
                InvalidateStyle(cgh);
        }
        ///
        ///Invalidate the cached Style
        ///definition for the given StyleType
        ///
        ///
        public void InvalidateStyle(StyleType type)
        {
            GridColumnCollection columns = GridPanel.Columns;
            foreach (GridColumn column in columns)
                column.InvalidateStyle(type);
            InvalidateStyle(GroupHeaders, type);
        }
        ///
        ///Invalidate the cached Style
        ///definition for the given GroupHeader StyleType
        ///
        ///
        ///
        public void InvalidateStyle(ColumnGroupHeader cgh, StyleType type)
        {
            if (cgh.EffectiveStyles != null)
            {
                cgh.EffectiveStyles[type].Dispose();
                cgh.EffectiveStyles[type] = null;
            }
            InvalidateStyle(cgh.GroupHeaders, type);
        }
        private void InvalidateStyle(IEnumerable groups, StyleType type)
        {
            foreach (ColumnGroupHeader cgh in groups)
                InvalidateStyle(cgh, type);
        }
        #endregion
        #region GetSizingStyle
        private ColumnHeaderVisualStyle GetSizingStyle(GridPanel panel, ColumnGroupHeader cgh)
        {
            StyleType style = panel.GetSizingStyle();
            if (style == StyleType.NotSet)
                style = StyleType.Default;
            return (GetEffectiveStyle(cgh, style));
        }
        #endregion
        #region GetGroupHeaderStyleState
        private StyleState GetGroupHeaderStyleState(ColumnGroupHeader cgh)
        {
            StyleState state = StyleState.Default;
            if (_Reordering == true)
            {
                if (cgh == _MouseDownHitItem)
                    state |= StyleState.MouseOver;
            }
            else if (_HitItem == cgh)
            {
                state |= StyleState.MouseOver;
            }
            if (IsGroupHeaderSelected(cgh) == true)
                state |= StyleState.Selected;
            if (IsGroupHeaderReadOnly(cgh) == true)
                state |= StyleState.ReadOnly;
            return (state);
        }
        #endregion
        #region GetEffectiveStyle
        ///
        /// GetEffectiveStyle
        ///
        ///
        ///
        public ColumnHeaderVisualStyle GetEffectiveStyle(ColumnGroupHeader cgh)
        {
            StyleState styleState = GetGroupHeaderStyleState(cgh);
            ColumnHeaderVisualStyle style = GetEffectiveStyle(cgh, styleState);
            return (style);
        }
        ///
        ///Gets the EffectiveStyle for the given StyleState
        ///
        ///
        ///
        ///
        public ColumnHeaderVisualStyle
            GetEffectiveStyle(ColumnGroupHeader cgh, StyleState cellState)
        {
            StyleType type = GetStyleType(cellState);
            return (GetEffectiveStyle(cgh, type));
        }
        internal ColumnHeaderVisualStyle
            GetEffectiveStyle(ColumnGroupHeader cgh, StyleType sizingStyle)
        {
            return (GetGroupHeaderStyle(cgh, sizingStyle));
        }
        #region GetGroupHeaderStyle
        internal ColumnHeaderVisualStyle GetGroupHeaderStyle(ColumnGroupHeader cgh, StyleType e)
        {
            ValidateGroupHeaderStyle(cgh);
            if (cgh.EffectiveStyles == null)
                cgh.EffectiveStyles = new ColumnHeaderVisualStyles();
            if (cgh.EffectiveStyles.IsValid(e) == false)
            {
                GridPanel panel = GridPanel;
                ColumnHeaderVisualStyle style = new ColumnHeaderVisualStyle();
                StyleType[] css = style.GetApplyStyleTypes(e);
                if (css != null)
                {
                    ColumnGroupHeader pcgh = GetParent(cgh) as ColumnGroupHeader;
                    if (pcgh != null)
                    {
                        if (GetAutoApplyGroupColor(cgh) != true)
                            pcgh = null;
                    }
                    foreach (StyleType cs in css)
                    {
                        style.ApplyStyle(SuperGrid.BaseVisualStyles.ColumnHeaderStyles[cs]);
                        style.ApplyStyle(SuperGrid.DefaultVisualStyles.ColumnHeaderStyles[cs]);
                        style.ApplyStyle(GridPanel.DefaultVisualStyles.ColumnHeaderStyles[cs]);
                        style.ApplyStyle(cgh.HeaderStyles[cs]);
                        if (pcgh != null)
                        {
                            ColumnHeaderVisualStyle gstyle = GetEffectiveStyle(pcgh, cs);
                            if (gstyle.Background != null)
                            {
                                if (cgh.HeaderStyles[cs].Background == null || cgh.HeaderStyles[cs].Background.IsEmpty)
                                    style.Background = gstyle.Background.Copy();
                            }
                            if (gstyle.TextColor.IsEmpty == false)
                            {
                                if (cgh.HeaderStyles[cs].TextColor.IsEmpty)
                                    style.TextColor = gstyle.TextColor;
                            }
                        }
                    }
                }
                SuperGrid.DoGetColumnGroupHeaderStyleEvent(panel, cgh, e, ref style);
                if (style.Background == null || style.Background.IsEmpty == true)
                    style.Background = new Background(Color.White);
                if (style.Font == null)
                    style.Font = SystemFonts.DefaultFont;
                cgh.EffectiveStyles[e] = style;
            }
            return (cgh.EffectiveStyles[e]);
        }
        #region ValidateGroupHeaderStyle
        private void ValidateGroupHeaderStyle(ColumnGroupHeader cgh)
        {
            if (cgh.StyleUpdateCount != SuperGrid.StyleUpdateCount)
            {
                if (cgh.EffectiveStyles != null)
                {
                    cgh.EffectiveStyles.Dispose();
                    cgh.EffectiveStyles = null;
                }
                cgh.StyleUpdateCount = SuperGrid.StyleUpdateCount;
            }
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region ColumnHeader Style support
        #region GetSizingStyle
        private ColumnHeaderVisualStyle GetSizingStyle(GridPanel panel, GridColumn column)
        {
            StyleType style = panel.GetSizingStyle();
            if (style == StyleType.NotSet)
                style = StyleType.Default;
            return (GetEffectiveStyle(column, style));
        }
        #endregion
        #region GetStyleState
        private StyleState GetStyleState(GridColumn column, bool selected)
        {
            StyleState state = StyleState.Default;
            if (_Reordering == true)
            {
                if (column == _MouseDownHitItem)
                    state |= StyleState.MouseOver;
            }
            else if (_HitItem == column)
            {
                state |= StyleState.MouseOver;
            }
            if (selected == true)
                state |= StyleState.Selected;
            if (column.IsReadOnly == true)
                state |= StyleState.ReadOnly;
            return (state);
        }
        #endregion
        #region GetStyleType
        private StyleType GetStyleType(StyleState state)
        {
            switch (state)
            {
                case StyleState.MouseOver:
                    return (StyleType.MouseOver);
                case StyleState.Selected:
                    return (StyleType.Selected);
                case StyleState.Selected | StyleState.MouseOver:
                    return (StyleType.SelectedMouseOver);
                case StyleState.ReadOnly:
                    return (StyleType.ReadOnly);
                case StyleState.ReadOnly | StyleState.MouseOver:
                    return (StyleType.ReadOnlyMouseOver);
                case StyleState.ReadOnly | StyleState.Selected:
                    return (StyleType.ReadOnlySelected);
                case StyleState.ReadOnly | StyleState.MouseOver | StyleState.Selected:
                    return (StyleType.ReadOnlySelectedMouseOver);
                default:
                    return (StyleType.Default);
            }
        }
        #endregion
        #region GetEffectiveStyle
        ///
        /// GetEffectiveStyle
        ///
        ///
        ///
        public ColumnHeaderVisualStyle GetEffectiveStyle(GridColumn column)
        {
            StyleState styleState = GetStyleState(column, column.IsSelected);
            ColumnHeaderVisualStyle style = GetEffectiveStyle(column, styleState);
            return (style);
        }
        ///
        ///Gets the EffectiveStyle for the given StyleState
        ///
        ///
        ///
        ///
        public ColumnHeaderVisualStyle
            GetEffectiveStyle(GridColumn column, StyleState cellState)
        {
            StyleType type = GetStyleType(cellState);
            return (GetEffectiveStyle(column, type));
        }
        internal ColumnHeaderVisualStyle
            GetEffectiveStyle(GridColumn column, StyleType type)
        {
            return (column.GetHeaderStyle(type));
        }
        #endregion
        #region GetEffectiveRowHeaderStyle
        internal ColumnHeaderRowVisualStyle GetEffectiveRowHeaderStyle()
        {
            return (GetEffectiveRowHeaderStyleEx(GetRowHeaderState()));
        }
        internal ColumnHeaderRowVisualStyle
            GetEffectiveRowHeaderStyleEx(StyleState rowState)
        {
            ValidateRowHeaderStyle();
            StyleType type = GetStyleType(rowState);
            return (GetRowHeaderStyle(type));
        }
        #region ValidateRowHeaderStyle
        private void ValidateRowHeaderStyle()
        {
            if (_StyleUpdateCount != SuperGrid.StyleUpdateCount)
            {
                _EffectiveRowHeaderStyles = null;
                _StyleUpdateCount = SuperGrid.StyleUpdateCount;
            }
        }
        #endregion
        #region GetRowHeaderState
        private StyleState GetRowHeaderState()
        {
            StyleState rowState = StyleState.Default;
            if (_HitArea == HeaderArea.InRowHeader || _HitArea == HeaderArea.InWhitespace)
                rowState |= StyleState.MouseOver;
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                if (panel.ReadOnly == true)
                    rowState |= StyleState.ReadOnly;
                if (panel == SuperGrid.ActiveGrid)
                    rowState |= StyleState.Selected;
            }
            return (rowState);
        }
        #endregion
        #region GetRowHeaderStyle
        private ColumnHeaderRowVisualStyle GetRowHeaderStyle(StyleType e)
        {
            if (_EffectiveRowHeaderStyles == null)
                _EffectiveRowHeaderStyles = new ColumnHeaderRowVisualStyles();
            if (_EffectiveRowHeaderStyles.IsValid(e) == false)
            {
                ColumnHeaderRowVisualStyle style = new ColumnHeaderRowVisualStyle();
                StyleType[] css = style.GetApplyStyleTypes(e);
                if (css != null)
                {
                    foreach (StyleType cs in css)
                    {
                        style.ApplyStyle(SuperGrid.BaseVisualStyles.ColumnHeaderRowStyles[cs]);
                        style.ApplyStyle(SuperGrid.DefaultVisualStyles.ColumnHeaderRowStyles[cs]);
                        style.ApplyStyle(GridPanel.DefaultVisualStyles.ColumnHeaderRowStyles[cs]);
                    }
                }
                SuperGrid.DoGetColumnHeaderRowHeaderStyleEvent(this, e, ref style);
                if (style.RowHeader.Background == null || style.RowHeader.Background.IsEmpty == true)
                    style.RowHeader.Background = new Background(Color.WhiteSmoke);
                _EffectiveRowHeaderStyles[e] = style;
            }
            return (_EffectiveRowHeaderStyles[e]);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region GetShowRootColumnHeaders
        private bool GetShowRootColumnHeaders(ColumnGroupHeader cgh)
        {
            while (cgh != null)
            {
                if (cgh.ShowColumnHeaders != Tbool.NotSet)
                    return (cgh.ShowColumnHeaders == Tbool.True);
                cgh = cgh.Collection.Parent as ColumnGroupHeader;
            }
            return (_ShowGroupColumnHeaders);
        }
        #endregion
        #region GetAutoApplyGroupColor
        internal bool GetAutoApplyGroupColor(ColumnGroupHeader cgh)
        {
            if (cgh.AutoApplyGroupColors != Tbool.NotSet)
                return (cgh.AutoApplyGroupColors == Tbool.True);
            return (AutoApplyGroupColors);
        }
        #endregion
        #region IsGroupHeaderSelected
        ///
        ///Returns whether the given GroupHeader is selected (ie. all
        ///visible columns/headers it encompasses must be selected)
        ///
        ///GroupHeader
        ///true, if all selected
        public bool IsGroupHeaderSelected(ColumnGroupHeader cgh)
        {
            GridPanel panel = GridPanel;
            GridColumnCollection columns = panel.Columns;
            int[] map = columns.DisplayIndexMap;
            bool selected = false;
            for (int i = cgh.StartDisplayIndex; i <= cgh.EndDisplayIndex; i++)
            {
                if ((uint) i < map.Length)
                {
                    GridColumn column = columns[map[i]];
                    if (column.Visible == true)
                    {
                        if (column.IsSelected == false)
                            return (false);
                        selected = true;
                    }
                }
            }
            return (selected);
        }
        #endregion
        #region IsGroupHeaderReadOnly
        /// 
        ///Returns whether the given GroupHeader is ReadOnly (ie. all
        ///visible columns/headers it encompasses must be ReadOnly)
        /// 
        /// 
        /// 
        public bool IsGroupHeaderReadOnly(ColumnGroupHeader cgh)
        {
            GridPanel panel = GridPanel;
            GridColumnCollection columns = panel.Columns;
            int[] map = columns.DisplayIndexMap;
            bool readOnly = false;
            for (int i = cgh.StartDisplayIndex; i <= cgh.EndDisplayIndex; i++)
            {
                if ((uint)i >= map.Length)
                    break;
                GridColumn column = columns[map[i]];
                if (column.Visible == true)
                {
                    if (column.IsReadOnly == false)
                        return (false);
                    readOnly = true;
                }
            }
            return (readOnly);
        }
        #endregion
        #region IsItemHFrozen
        internal bool IsItemHFrozen(object item)
        {
            if (item is GridColumn)
                return ((GridColumn)item).IsHFrozenEx;
            if (item is ColumnGroupHeader)
                return (IsGroupHeaderHFrozen(GridPanel, (ColumnGroupHeader)item));
            return (false);
        }
        #endregion
        #region IsGroupHeaderHFrozen
        internal bool IsGroupHeaderHFrozen(GridPanel panel, ColumnGroupHeader cgh)
        {
            if (panel.IsSubPanel == false)
            {
                if (cgh != null)
                    return (cgh.StartDisplayIndex < panel.FrozenColumnCount);
            }
            return (false);
        }
        #endregion
        #region GetBounds
        internal Rectangle GetBounds(GridPanel panel, GridColumn column)
        {
            Rectangle r = GetRelativeBounds(panel, column);
            return (GetScrollBounds(panel, column, r));
        }
        #endregion
        #region GetRelativeBounds
        internal Rectangle GetRelativeBounds(GridPanel panel, GridColumn column)
        {
            Rectangle r = BoundsRelative;
            r.X = column.BoundsRelative.X;
            r.Width = column.BoundsRelative.Width;
            return (r);
        }
        #endregion
        #region GetScrollBounds
        internal Rectangle GetScrollBounds(
            GridPanel panel, GridColumn column, Rectangle r)
        {
            if (r.IsEmpty == false)
            {
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                if (panel.IsSubPanel == true || column.IsHFrozen == false)
                    r.X -= HScrollOffset;
            }
            return (r);
        }
        #endregion
        #region GetSubScrollBounds
        internal Rectangle GetSubScrollBounds(GridPanel panel, ColumnGroupHeader cgh)
        {
            Rectangle r = cgh.BoundsRelative;
            if (r.IsEmpty == false)
            {
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                if (panel.IsSubPanel == true || IsGroupHeaderHFrozen(panel, cgh) == false)
                    r.X -= HScrollOffset;
            }
            return (r);
        }
        #endregion
        #region GetSubContScrollBounds
        internal Rectangle GetSubContScrollBounds(GridPanel panel, ColumnGroupHeader cgh)
        {
            Rectangle r = cgh.BoundsRelative;
            r.Height = cgh.Size.Height;
            if (r.IsEmpty == false)
            {
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                if (panel.IsSubPanel == true || IsGroupHeaderHFrozen(panel, cgh) == false)
                    r.X -= HScrollOffset;
            }
            return (r);
        }
        #endregion
        #region GetContentBounds
        internal Rectangle GetContentBounds(GridPanel panel, ColumnHeaderVisualStyle style, Rectangle r)
        {
            if (_ShowHeaderImages == true)
            {
                object figure = style.GetFigure(panel);
                if (figure != null)
                {
                    Size size = style.GetFigureSize(panel);
                    if (style.IsOverlayImage != true)
                    {
                        switch (style.ImageAlignment)
                        {
                            case Alignment.TopCenter:
                                r.Y += size.Height;
                                r.Height -= size.Height;
                                break;
                            case Alignment.MiddleCenter:
                                break;
                            case Alignment.BottomCenter:
                                r.Height -= size.Height;
                                break;
                            case Alignment.TopRight:
                            case Alignment.MiddleRight:
                            case Alignment.BottomRight:
                                r.Width -= size.Width;
                                break;
                            default:
                                r.X += size.Width;
                                r.Width -= size.Width;
                                break;
                        }
                    }
                }
            }
            return (r);
        }
        #endregion
        #region GetAdjustedBounds
        private Rectangle GetAdjustedBounds(VisualStyle style, Rectangle r)
        {
            r.X += Dpi.Width(style.BorderThickness.Left + style.Margin.Left + style.Padding.Left);
            r.Width -= Dpi.Width(style.BorderThickness.Horizontal + style.Margin.Horizontal + style.Padding.Horizontal);
            r.Y += Dpi.Height(style.BorderThickness.Top + style.Margin.Top + style.Padding.Top);
            r.Height -= Dpi.Height(style.BorderThickness.Vertical + style.Margin.Vertical + style.Padding.Vertical);
            return (r);
        }
        #endregion
        #region GetImageBounds
        /// 
        /// Gets the bounding rectangle for the
        /// given column header image
        /// 
        /// 
        /// Bounding rectangle
        public Rectangle GetImageBounds(GridColumn column)
        {
            if (_ShowHeaderImages == true)
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    SuperGridControl sg = panel.SuperGrid;
                    if (sg != null)
                    {
                        ColumnHeaderVisualStyle style = GetEffectiveStyle(column);
                        object figure = style.GetFigure(panel);
                        if (figure != null)
                        {
                            Rectangle bounds = GetBounds(panel, column);
                            using (Graphics g = sg.CreateGraphics())
                            {
                                Rectangle t = GetAdjustedBounds(style,
                                    GetContentBounds(panel, style, bounds));
                                return (style.GetFigureBounds(panel, t));
                            }
                        }
                    }
                }
            }
            return (Rectangle.Empty);
        }
        #endregion
        #region InvalidateHeader
        internal void InvalidateHeader(GridPanel panel, GridColumn column)
        {
            Rectangle bounds = BoundsRelative;
            if (panel.IsVFrozen == false)
                bounds.Y -= VScrollOffset;
            bounds.X = column.BoundsRelative.X;
            bounds.Width = column.BoundsRelative.Width;
            if (panel.IsSubPanel == true || column.IsHFrozen == false)
                bounds.X -= HScrollOffset;
            InvalidateRender(bounds);
        }
        private void InvalidateHeader(GridPanel panel, ColumnGroupHeader cgh)
        {
            Rectangle r = GetSubScrollBounds(panel, cgh);
            InvalidateRender(r);
        }
        #endregion
        #region InvalidateRowHeader
        internal void InvalidateRowHeader()
        {
            InvalidateRender(RowHeaderBounds);
        }
        #endregion
        #region InvalidateWhitespace
        internal void InvalidateWhitespace()
        {
            Rectangle bounds = Bounds;
            GridColumn col = GridPanel.Columns.LastVisibleColumn;
            if (col != null)
            {
                if (col.Bounds.Right < bounds.Right)
                {
                    int n = bounds.Right - col.Bounds.Right;
                    bounds.X = col.Bounds.Right;
                    bounds.Width = n;
                }
                InvalidateRender(bounds);
            }
        }
        #endregion
        #region InvalidateItem
        private void InvalidateItem(GridPanel panel, object item)
        {
            if (item is GridColumn)
                InvalidateHeader(panel, (GridColumn)item);
            else if (item is ColumnGroupHeader)
                InvalidateHeader(panel, (ColumnGroupHeader)item);
        }
        #endregion
        #region CancelCapture
        /// 
        /// Cancels any in progress operations (resize, reorder)
        /// that may have the mouse captured.
        /// 
        public override void CancelCapture()
        {
            StopReorder();
            StopResize();
            _MouseDownHitItem = null;
            base.CancelCapture();
        }
        #endregion
    }
    #region enums
    #region HeaderArea
    ///
    /// HeaderArea
    ///
    public enum HeaderArea
    {
        ///
        /// NoWhere
        ///
        NoWhere,
        ///
        /// InContent
        ///
        InContent,
        ///
        /// InResize
        ///
        InResize,
        ///
        /// InRowHeader
        ///
        InRowHeader,
        ///
        /// InRowHeaderResize
        ///
        InRowHeaderResize,
        ///
        /// InWhitespace
        ///
        InWhitespace,
        ///
        /// InMarkup
        ///
        InMarkup,
        ///
        /// InFilterMenu
        ///
        InFilterMenu,
        ///
        /// InGroupBox
        ///
        InGroupBox,
    }
    #endregion
    #region ImageVisibility
    ///
    /// ImageVisibility
    ///
    public enum ImageVisibility
    {
        ///
        /// NotSet
        ///
        NotSet = -1,
        ///
        /// Auto
        ///
        Auto,
        ///
        /// Always
        ///
        Always,
        ///
        /// Never
        ///
        Never,
    }
    #endregion
    #endregion
}