using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.DotNetBar.SuperGrid.Style;
using DevComponents.SuperGrid.TextMarkup;
namespace DevComponents.DotNetBar.SuperGrid
{
    /// 
    /// Defines the grid GridGroupBy Row
    /// 
    public class GridGroupByRow : GridTextRow
    {
        #region Constants
        const int MarkerWidth = 13;
        const int MarkerHeight = 7;
        const int MarkerHPad = 10;
        const int MarkerVPad = 12;
        const int TextPad = 3;
        const int TextHPad = 6;
        const int TextVPad = 6;
        const int BoxSpacing = 8;
        const int DefaultMinRowHeight = 35;
        #endregion
        #region Private variables
        private bool _Visible;
        private bool _UseColumnHeaderColors = true;
        private bool _AllowUserSort = true;
        private bool _RemoveGroupOnDoubleClick = true;
        private GroupBoxLayout _GroupBoxLayout = GroupBoxLayout.Hierarchical;
        private GroupBoxStyle _GroupBoxStyle = GroupBoxStyle.Rectangular;
        private List _GroupBoxes;
        private GroupBoxEffects _GroupBoxEffects = GroupBoxEffects.NotSet;
        private bool _Dragging;
        private Image _InsertMarker;
        private GridGroupBox _HitGroupBox;
        private GridGroupBox _LastHitGroupBox;
        private GridGroupBox _MouseDownHitBox;
        private HeaderArea _HitArea;
        private HeaderArea _LastHitArea;
        private GridColumn _HitColumn;
        private FloatWindow _GroupBoxWindow;
        private GridGroupBox _AfterGroupBox;
        private Rectangle _InsertRect;
        private FilterPopup _FilterMenu;
        private ImageVisibility _FilterImageVisibility = ImageVisibility.NotSet;
        private string _WatermarkText;
        private int _MaxGroupBoxWidth = 200;
        private int _CornerRadius = 5;
        #endregion
        #region Constructors
        ///
        /// GridHeader
        ///
        public GridGroupByRow()
            : this(null)
        {
        }
        ///
        /// GridHeader
        ///
        ///
        public GridGroupByRow(string text)
            : base(text)
        {
        }
        #endregion
        #region Public properties
        #region AllowUserSort
        ///
        /// Gets or sets whether the user can change the group
        /// sort direction by clicking on the associated GroupBox
        ///
        [DefaultValue(true), Category("Behavior")]
        [Description("Indicates whether the user can change the group sort direction by clicking on the associated GroupBox.")]
        public bool AllowUserSort
        {
            get { return (_AllowUserSort); }
            set
            {
                if (_AllowUserSort != value)
                {
                    _AllowUserSort = value;
                    OnPropertyChanged("AllowUserSort");
                }
            }
        }
        #endregion
        #region CornerRadius
        ///
        /// Gets or sets the corner radius to
        /// use when GroupBoxStyle is RoundedRectangular
        ///
        [DefaultValue(5), Category("Behavior")]
        [Description("Indicates the corner radius to use when GroupBoxStyle is RoundedRectangular.")]
        public int CornerRadius
        {
            get { return (_CornerRadius); }
            set
            {
                if (_CornerRadius != value)
                {
                    _CornerRadius = value;
                    OnPropertyChangedEx("CornerRadius", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region FilterImageVisibility
        /// 
        /// Gets or sets the visibility of the header filter image
        /// 
        [DefaultValue(ImageVisibility.NotSet), Category("Appearance")]
        [Description("Indicates the visibility of the filter image.")]
        public ImageVisibility FilterImageVisibility
        {
            get { return (_FilterImageVisibility); }
            set
            {
                if (_FilterImageVisibility != value)
                {
                    _FilterImageVisibility = value;
                    OnPropertyChangedEx("FilterImageVisibility", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region GroupBoxEffects
        /// 
        /// Gets or sets the default for how columns interact with the GroupBox
        /// 
        [DefaultValue(GroupBoxEffects.NotSet), Category("Grouping")]
        [Description("Indicates the default for how columns interact with the GroupBox.")]
        public GroupBoxEffects GroupBoxEffects
        {
            get { return (_GroupBoxEffects); }
            set
            {
                if (_GroupBoxEffects != value)
                {
                    _GroupBoxEffects = value;
                    OnPropertyChanged("GroupBoxEffects");
                }
            }
        }
        #endregion
        #region GroupBoxLayout
        /// 
        /// Gets or sets the group box layout (Flat, Hierarchical) 
        /// 
        [DefaultValue(GroupBoxLayout.Hierarchical), Category("Appearance")]
        [Description("Indicates the group box layout (Flat, Hierarchical)")]
        public GroupBoxLayout GroupBoxLayout
        {
            get { return (_GroupBoxLayout); }
            set
            {
                if (_GroupBoxLayout != value)
                {
                    _GroupBoxLayout = value;
                    OnPropertyChangedEx("GroupBoxLayout", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region GroupBoxStyle
        /// 
        /// Gets or sets the group box Style (Rectangular, RoundedRect) 
        /// 
        [DefaultValue(GroupBoxStyle.Rectangular), Category("Appearance")]
        [Description("Indicates the group box Style (Rectangular, RoundedRect)")]
        public GroupBoxStyle GroupBoxStyle
        {
            get { return (_GroupBoxStyle); }
            set
            {
                if (_GroupBoxStyle != value)
                {
                    _GroupBoxStyle = value;
                    OnPropertyChangedEx("GroupBoxStyle", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region IsEmpty
        /// 
        /// Gets whether the item is empty
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override bool IsEmpty
        {
            get { return (false); }
        }
        #endregion
        #region MaxGroupBoxWidth
        /// 
        /// Gets or sets the maximum GroupBox width, in pixels 
        /// 
        [DefaultValue(200), Category("Appearance")]
        [Description("Indicates the maximum GroupBox width, in pixels.")]
        public int MaxGroupBoxWidth
        {
            get { return (_MaxGroupBoxWidth); }
            set
            {
                if (_MaxGroupBoxWidth != value)
                {
                    _MaxGroupBoxWidth = value;
                    OnPropertyChangedEx("MaxGroupBoxWidth", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region RemoveGroupOnDoubleClick
        ///
        /// Gets or sets whether the grouping column is removed
        /// when the user double clicks on the associated GroupBox
        ///
        [DefaultValue(true), Category("Behavior")]
        [Description("Indicates whether the grouping column is removed when the user double clicks on the associated GroupBox.")]
        public bool RemoveGroupOnDoubleClick
        {
            get { return (_RemoveGroupOnDoubleClick); }
            set
            {
                if (_RemoveGroupOnDoubleClick != value)
                {
                    _RemoveGroupOnDoubleClick = value;
                    OnPropertyChanged("RemoveGroupOnDoubleClick");
                }
            }
        }
        #endregion
        #region Visible
        /// 
        /// Visible
        /// 
        [DefaultValue(false), Category("Appearance")]
        [Description("Indicates whether the item is visible")]
        public override bool Visible
        {
            get { return (_Visible); }
            set
            {
                if (_Visible != value)
                {
                    _Visible = value;
                    OnPropertyChangedEx("Visible", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region UseColumnHeaderColors
        ///
        /// Gets or sets whether Column Header color definitions are used
        ///
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether Column Header color definitions are used")]
        public bool UseColumnHeaderColors
        {
            get { return (_UseColumnHeaderColors); }
            set
            {
                if (_UseColumnHeaderColors != value)
                {
                    _UseColumnHeaderColors = value;
                    OnPropertyChangedEx("UseColumnHeaderColors", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region WatermarkText
        /// 
        /// Gets or sets the Watermark text to use when no Grouping is active 
        /// 
        [DefaultValue(null), Category("Appearance")]
        [Description("Indicates the Watermark text to use when no Grouping is active")]
        public string WatermarkText
        {
            get { return (_WatermarkText); }
            set
            {
                if (_WatermarkText != value)
                {
                    _WatermarkText = value;
                    OnPropertyChangedEx("WatermarkText", VisualChangeType.Render);
                }
            }
        }
        #region GetWatermarkText
        private string GetWatermarkText()
        {
            return (_WatermarkText ?? SuperGrid.GroupByWaterMarkText);
        }
        #endregion
        #endregion
        #endregion
        #region Private properties
        #region InsertMarker
        private Image InsertMarker
        {
            get
            {
                if (_InsertMarker == null)
                    _InsertMarker = CreateInsertMarker();
                return (_InsertMarker);
            }
            set
            {
                if (_InsertMarker != null)
                    _InsertMarker.Dispose();
                _InsertMarker = value;
            }
        }
        #region CreateInsertMarker
        private Image CreateInsertMarker()
        {
            GroupByVisualStyle style = (GroupByVisualStyle)GetEffectiveStyle();
            Image image = new Bitmap(MarkerWidth, MarkerHeight);
            using (Graphics g = Graphics.FromImage(image))
            {
                Point[] pts =
                    {
                        new Point(0, 0),
                        new Point(MarkerWidth - 1, 0),
                        new Point(MarkerHeight - 1, MarkerHeight - 1),
                        new Point(0, 0),
                    };
                using (GraphicsPath path = new GraphicsPath())
                {
                    path.AddLines(pts);
                    Rectangle r = new Rectangle(0, 0, MarkerWidth, MarkerHeight);
                    using (Brush br = style.InsertMarkerBackground.GetBrush(r))
                        g.FillPath(br, path);
                    using (Pen pen = new Pen(style.InsertMarkerBorderColor))
                        g.DrawPath(pen, path);
                }
            }
            return (image);
        }
        #endregion
        #endregion
        #endregion
        #region MeasureRow
        /// 
        /// MeasureRow
        /// 
        /// 
        /// 
        /// 
        /// 
        protected override Size MeasureRow(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Size constraintSize)
        {
            Size sizeNeeded = base.MeasureRow(layoutInfo, stateInfo, constraintSize);
            GridPanel panel = stateInfo.GridPanel;
            int height = GetGroupByHeight(panel);
            if (RowHeight == 0)
            {
                int n = Dpi.Height(DefaultMinRowHeight);
                if (height < n)
                    height = n;
            }
            if (height > sizeNeeded.Height)
                sizeNeeded.Height = height;
            return (sizeNeeded);
        }
        #region GetGroupByHeight
        private int GetGroupByHeight(GridPanel panel)
        {
            if (_GroupBoxes == null)
                _GroupBoxes = new List();
            else
                _GroupBoxes.Clear();
            GridGroupBox box = new GridGroupBox(this, null);
            _GroupBoxes.Add(box);
            int rowHeight = (GroupBoxLayout == GroupBoxLayout.Hierarchical)
                                ? GetHierarchicalHeight(panel)
                                : GetFlatHeight(panel);
            rowHeight += Dpi.Height(MarkerVPad * 2);
            TextRowVisualStyle tstyle = GetEffectiveStyle();
            rowHeight += Dpi.Height(tstyle.BorderThickness.Vertical +
                tstyle.Padding.Vertical + tstyle.Margin.Vertical);
            return (rowHeight);
        }
        #region GetHierarchicalHeight
        private int GetHierarchicalHeight(GridPanel panel)
        {
            int rowHeight = 0;
            int lastHeight = 0;
            foreach (GridColumn column in panel.GroupColumns)
            {
                GridGroupBox box = new GridGroupBox(this, column);
                box.GroupBoxStyle = GroupBoxStyle;
                box.CornerRadius = CornerRadius;
                _GroupBoxes.Add(box);
                Size size = GetGroupBoxSize(box);
                if (rowHeight == 0)
                {
                    rowHeight = size.Height;
                }
                else
                {
                    if (size.Height > lastHeight)
                        rowHeight += (size.Height - lastHeight / 2);
                    else
                        rowHeight += (size.Height / 2);
                }
                lastHeight = size.Height;
            }
            return (rowHeight);
        }
        #endregion
        #region GetFlatHeight
        private int GetFlatHeight(GridPanel panel)
        {
            int rowHeight = 0;
            foreach (GridColumn column in panel.GroupColumns)
            {
                GridGroupBox box = new GridGroupBox(this, column);
                box.GroupBoxStyle = GroupBoxStyle;
                box.CornerRadius = CornerRadius;
                _GroupBoxes.Add(box);
                Size size = GetGroupBoxSize(box);
                if (size.Height > rowHeight)
                    rowHeight = size.Height;
            }
            return (rowHeight);
        }
        #endregion
        #region GetGroupBoxSize
        private Size GetGroupBoxSize(GridGroupBox box)
        {
            Size size = new Size();
            size.Width = box.Column.HeaderTextSize.Width + Dpi.Width(TextHPad);
            size.Height = box.Column.HeaderTextSize.Height + Dpi.Height(TextVPad);
            box.ContentSize = size;
            SuperGrid.DoConfigureGroupBoxEvent(this, box);
            size = box.ContentSize;
            size.Width += Dpi.Width(box.Padding.Horizontal);
            size.Height += Dpi.Height(box.Padding.Vertical);
            int n = Dpi.Width(_MaxGroupBoxWidth);
            if (size.Width > n)
                size.Width = n;
            size.Width += Dpi.Width(MarkerHPad + TextHPad);
            if (size.Width < Dpi.Width20)
                size.Width = Dpi.Width20;
            if (size.Height < Dpi.Height15)
                size.Height = Dpi.Height15;
            box.RelativeBounds = new Rectangle(Point.Empty, size);
            return (size);
        }
        #endregion
        #endregion
        #endregion
        #region ArrangeRow
        /// 
        /// ArrangeRow
        /// 
        /// 
        /// 
        /// 
        /// 
        protected override Size ArrangeRow(GridLayoutInfo layoutInfo,
            GridLayoutStateInfo stateInfo, Rectangle layoutBounds)
        {
            UpdateGroupBoxes(stateInfo.GridPanel, layoutBounds);
            return (base.ArrangeRow(layoutInfo, stateInfo, layoutBounds));
        }
        #region UpdateGroupBoxes
        private void UpdateGroupBoxes(GridPanel panel, Rectangle r)
        {
            TextRowVisualStyle tstyle = GetEffectiveStyle();
            r = GetAdjustedBounds(tstyle, r);
            r.Size = Size.Empty;
            if (CanShowRowHeader(panel) == true)
                r.X += panel.RowHeaderWidthEx;
            r.X += Dpi.Width(MarkerWidth - MarkerHPad);
            r.Y += Dpi.Height(MarkerVPad - MarkerHeight + TextPad);
            GridGroupBox box = _GroupBoxes[0];
            box.RelativeBounds = r;
            int lastHeight = Dpi.Width(MarkerHeight);
            int midline = Bounds.Y + Bounds.Height / 2 - 1;
            for (int i = 1; i < _GroupBoxes.Count; i++)
            {
                box = _GroupBoxes[i];
                r.X += (r.Width + Dpi.Width(BoxSpacing));
                r.Size = box.RelativeBounds.Size;
                if (GroupBoxLayout == GroupBoxLayout.Hierarchical)
                {
                    r.Y += (r.Height > lastHeight)
                        ? lastHeight / 2 : lastHeight - r.Height / 2;
                }
                else
                {
                    r.Y = midline - (r.Height / 2);
                }
                UpdateGroupBoxRects(panel, box, ref r);
                lastHeight = r.Height;
            }
            _AfterGroupBox = null;
        }
        #region UpdateGroupBoxRects
        private void UpdateGroupBoxRects(
            GridPanel panel, GridGroupBox box, ref Rectangle r)
        {
            Rectangle t = r;
            Rectangle ts = GetSortImageBounds(panel, box.Column, t);
            Rectangle tf = GetFilterImageBounds(panel, box.Column, t);
            if (ts.Width > 0)
                r.Width += (ts.Width + TextPad);
            if (tf.Width > 0)
                r.Width += (tf.Width + TextPad);
            r.Width += 3;
            box.RelativeBounds = r;
            if (tf.IsEmpty == false && ts.IsEmpty == false)
            {
                if (ts.X == tf.X)
                {
                    if (tf.X < r.X + r.Width / 2)
                        tf.X += ts.Width + TextPad;
                    else
                        ts.X += tf.Width + TextPad;
                }
                else
                {
                    if (tf.X < r.X + r.Width / 2)
                        ts.X = r.Right - (ts.Width + TextPad);
                    else
                        tf.X = r.Right - (tf.Width + TextPad);
                }
            }
            else
            {
                if (ts.Width > 0 && ts.X > r.X + r.Width / 2)
                    ts.X = r.Right - (ts.Width + TextPad);
                if (tf.Width > 0 && tf.X > r.X + r.Width / 2)
                    tf.X = r.Right - (tf.Width + TextPad);
            }
            box.FilterImageRelBounds = tf;
            box.SortImageRelBounds = ts;
        }
        #region GetSortImageBounds
        private Rectangle GetSortImageBounds(
            GridPanel panel, GridColumn column, Rectangle r)
        {
            if (AllowUserSort == true)
            {
                Image sortImage = panel.ColumnHeader.GetColumnSortImage(panel, column);
                if (sortImage != null)
                {
                    Alignment alignment = (panel.ColumnHeader.SortImageAlignment == Alignment.NotSet)
                        ? Alignment.MiddleLeft : panel.ColumnHeader.SortImageAlignment;
                    return (GetImageBoundsEx(sortImage, alignment, r));
                }
            }
            return (Rectangle.Empty);
        }
        #endregion
        #region GetFilterImageBounds
        private Rectangle GetFilterImageBounds(
            GridPanel panel, GridColumn column, Rectangle r)
        {
            Image filterImage = null;
            switch (_FilterImageVisibility)
            {
                case ImageVisibility.Auto:
                case ImageVisibility.Always:
                    if (column.IsFilteringEnabled == true)
                        filterImage = panel.ColumnHeader.GetFilterImage(column);
                    break;
                case ImageVisibility.NotSet:
                    filterImage = panel.ColumnHeader.GetColumnFilterImage(column);
                    break;
            }
            if (filterImage != null)
            {
                Alignment alignment = panel.ColumnHeader.FilterImageAlignment;
                if (alignment == Alignment.NotSet)
                    alignment = Alignment.MiddleLeft;
                return (GetImageBoundsEx(filterImage, alignment, r));
            }
            return (Rectangle.Empty);
        }
        #endregion
        #region GetImageBoundsEx
        private Rectangle GetImageBoundsEx(
            Image image, Alignment alignment, Rectangle r)
        {
            Rectangle t = r;
            t.Size = image.Size;
            t.X += Dpi.Width6;
            t.Y += (r.Height - t.Height) / 2;
            switch (alignment)
            {
                case Alignment.TopLeft:
                case Alignment.MiddleLeft:
                case Alignment.BottomLeft:
                    break;
                default:
                    t.X = r.Right + Dpi.Width3;
                    break;
            }
            return (t);
        }
        #endregion
        #endregion
        #endregion
        #endregion
        #region RenderRow
        /// 
        /// RenderRow
        /// 
        /// 
        /// 
        /// 
        protected override void RenderRow(
            GridRenderInfo renderInfo, GridPanel panel, Rectangle r)
        {
            base.RenderRow(renderInfo, panel, r);
            Graphics g = renderInfo.Graphics;
            if (CanShowRowHeader(panel) == true)
            {
                r.X += panel.RowHeaderWidthEx;
                r.Width -= panel.RowHeaderWidthEx;
            }
            Region oldClip = g.Clip;
            try
            {
                g.SetClip(r, CombineMode.Intersect);
                if (_GroupBoxes.Count > 1)
                {
                    GridPanelVisualStyle pstyle = panel.GetEffectiveStyle();
                    GridGroupBox lastBox = null;
                    foreach (GridGroupBox box in _GroupBoxes)
                    {
                        if (box.Column != null)
                        {
                            RenderGroupBox(panel, box, lastBox, g, pstyle);
                            lastBox = box;
                        }
                    }
                }
                else
                {
                    RenderWaterMarkText(panel, g);
                }
            }
            finally
            {
                g.Clip = oldClip;
            }
            if (_InsertRect.IsEmpty == false)
                g.DrawImageUnscaled(InsertMarker, _InsertRect);
        }
        #region RenderGroupBox
        private void RenderGroupBox(GridPanel panel,
            GridGroupBox box, GridGroupBox lastBox, Graphics g, GridPanelVisualStyle pstyle)
        {
            StyleType type = GetGroupByStyleType(box);
            ColumnHeaderVisualStyle cstyle = panel.ColumnHeader.GetEffectiveStyle(box.Column, type);
            GroupByVisualStyle style = GetGroupByEffectiveStyle(box);
            Rectangle r = box.Bounds;
            if (r.Width > 0 && r.Height > 0)
            {
                if (SuperGrid.DoPreRenderGroupBoxEvent(g,
                    this, box, RenderParts.Background, r) == false)
                {
                    int radius = GetCornerRadius(box);
                    if (radius > 0 && box.GroupBoxStyle == GroupBoxStyle.RoundedRectangular)
                        RenderRoundedBox(g, style, cstyle, pstyle, lastBox, box, radius);
                    else
                        RenderRectBox(g, style, cstyle, pstyle, lastBox, box);
                    SuperGrid.DoPostRenderGroupBoxEvent(g,
                        this, box, RenderParts.Background, r);
                }
                Rectangle t = r;
                RenderSortImage(g, panel, box, ref t);
                RenderFilterImage(g, panel, box, ref t);
                int n = box.Padding.Left + TextHPad;
                t.X += n;
                t.Width -= n;
                if (t.Width - box.ContentSize.Width > 0)
                    t.Width = box.ContentSize.Width;
                if (SuperGrid.DoPreRenderGroupBoxEvent(g,
                    this, box, RenderParts.Content, t) == false)
                {
                    Rectangle t2 = t;
                    t.Y += box.Padding.Top;
                    t.Height = box.Column.HeaderTextSize.Height + 6;
                    RenderText(g, box.Column, style, cstyle, t);
                    SuperGrid.DoPostRenderGroupBoxEvent(g,
                        this, box, RenderParts.Content, t2);
                }
            }
        }
        #region GetCornerRadius
        internal int GetCornerRadius(GridGroupBox box)
        {
            int maxRadius = Math.Min(
                box.RelativeBounds.Width, box.RelativeBounds.Height) / 2;
            int radius = Math.Min(box.CornerRadius, maxRadius);
            return (radius > 0 ? radius : 0);
        }
        #endregion
        #region RenderRoundedBox
        private void RenderRoundedBox(Graphics g, GroupByVisualStyle style,
            ColumnHeaderVisualStyle cstyle, GridPanelVisualStyle pstyle,
            GridGroupBox leftBox, GridGroupBox box, int radius)
        {
            Rectangle r = box.Bounds;
            using (GraphicsPath path = GetRoundedPath(r, radius))
            {
                SmoothingMode sm = g.SmoothingMode;
                g.SmoothingMode = SmoothingMode.AntiAlias;
                if (_UseColumnHeaderColors == true)
                {
                    using (Brush br = cstyle.Background.GetBrush(r))
                        g.FillPath(br, path);
                    using (Pen pen = new Pen(pstyle.HeaderLineColor))
                        g.DrawPath(pen, path);
                }
                else
                {
                    using (Brush br = style.GroupBoxBackground.GetBrush(r))
                        g.FillPath(br, path);
                    using (Pen pen = new Pen(style.GroupBoxBorderColor))
                        g.DrawPath(pen, path);
                }
                if (leftBox != null)
                {
                    Region oldClip = g.Clip;
                    Region newClip = new Region(Bounds);
                    newClip.Exclude(path);
                    g.SetClip(newClip, CombineMode.Intersect);
                    try
                    {
                        if (SuperGrid.DoPreRenderGroupBoxConnectorEvent(g, this, leftBox, box) == false)
                        {
                            RenderBoxConnector(g, style, leftBox.Bounds, box.Bounds, true);
                            SuperGrid.DoPostRenderGroupBoxConnectorEvent(g, this, leftBox, box);
                        }
                    }
                    finally
                    {
                        g.Clip = oldClip;
                    }
                }
                g.SmoothingMode = sm;
            }
        }
        #region GetRoundedPath
        private GraphicsPath GetRoundedPath(Rectangle r, int radius)
        {
            int diameter = radius << 1;
            Rectangle t = r;
            t.Size = new Size(diameter, diameter);
            GraphicsPath path = new GraphicsPath();
            path.AddArc(t, 180, 90);
            t.X = r.Right - diameter;
            path.AddArc(t, 270, 90);
            t.Y = r.Bottom - diameter;
            path.AddArc(t, 0, 90);
            t.X = r.X;
            path.AddArc(t, 90, 90);
            path.CloseAllFigures();
            return (path);
        }
        #endregion
        #endregion
        #region RenderRectBox
        private void RenderRectBox(Graphics g, GroupByVisualStyle style,
            ColumnHeaderVisualStyle cstyle, GridPanelVisualStyle pstyle,
            GridGroupBox leftBox, GridGroupBox box)
        {
            Rectangle r = box.Bounds;
            if (_UseColumnHeaderColors == true)
            {
                using (Brush br = cstyle.Background.GetBrush(r))
                    g.FillRectangle(br, r);
                using (Pen pen = new Pen(pstyle.HeaderLineColor))
                    g.DrawRectangle(pen, r);
            }
            else
            {
                using (Brush br = style.GroupBoxBackground.GetBrush(r))
                    g.FillRectangle(br, r);
                using (Pen pen = new Pen(style.GroupBoxBorderColor))
                    g.DrawRectangle(pen, r);
            }
            if (leftBox != null)
            {
                if (SuperGrid.DoPreRenderGroupBoxConnectorEvent(g, this, leftBox, box) == false)
                {
                    RenderBoxConnector(g, style, leftBox.Bounds, r, false);
                    SuperGrid.DoPostRenderGroupBoxConnectorEvent(g, this, leftBox, box);
                }
            }
        }
        #endregion
        #region RenderBoxConnector
        private void RenderBoxConnector(Graphics g,
            GroupByVisualStyle style, Rectangle l, Rectangle r, bool extend)
        {
            using (Pen pen = new Pen(style.GroupBoxConnectorColor))
            {
                if (GroupBoxLayout == GroupBoxLayout.Hierarchical)
                {
                    Point pt1 = new Point(l.X + l.Width / 2, l.Bottom + 1);
                    Point pt2 = new Point(pt1.X, l.Bottom + (r.Bottom - l.Bottom) / 2);
                    Point pt3 = new Point(r.X + (extend ? 10 : -1), pt2.Y);
                    g.DrawLines(pen, new Point[] { pt1, pt2, pt3 });
                }
                else
                {
                    Point pt1 = new Point(l.Right + 1, l.Y + l.Height / 2 + 1);
                    Point pt2 = new Point(r.X - 1, pt1.Y);
                    g.DrawLine(pen, pt1, pt2);
                }
            }
        }
        #endregion
        #endregion
        #region Render Filter/Sort Image
        #region RenderSortImage
        private void RenderSortImage(
            Graphics g, GridPanel panel, GridGroupBox box, ref Rectangle t)
        {
            GridColumn column = box.Column;
            Rectangle bounds = box.SortImageBounds;
            if (bounds.IsEmpty == false)
            {                
                Image sortImage =
                    panel.ColumnHeader.GetColumnSortImage(panel, column);
                RenderImage(g, sortImage, bounds, ref t);
            }
        }
        #endregion
        #region RenderFilterImage
        private void RenderFilterImage(
            Graphics g, GridPanel panel, GridGroupBox box, ref Rectangle t)
        {
            GridColumn column = box.Column;
            Rectangle bounds = box.FilterImageBounds;
            if (bounds.IsEmpty == false)
            {
                if (CanShowFilterImage(panel, box) == true)
                {
                    bool inFilter;
                    StyleState state = GetFilterImageState(box, out inFilter);
                    Image filterImage =
                        panel.ColumnHeader.GetFilterImage(column, state, inFilter);
                    RenderImage(g, filterImage, bounds, ref t);
                }
            }
        }
        #region CanShowFilterImage
        private bool CanShowFilterImage(GridPanel panel, GridGroupBox box)
        {
            switch (_FilterImageVisibility)
            {
                case ImageVisibility.Auto:
                    if (box.Column.IsFilteringEnabled == true)
                    {
                        if (string.IsNullOrEmpty(box.Column.FilterExpr) == false)
                            return (true);
                        return (_Dragging == false && box.IsEqualTo(_HitGroupBox) == true);
                    }
                    break;
                case ImageVisibility.Always:
                    if (box.Column.IsFilteringEnabled == true)
                        return (true);
                    break;
                case ImageVisibility.NotSet:
                    switch (panel.ColumnHeader.FilterImageVisibility)
                    {
                        case ImageVisibility.Always:
                            return (true);
                        case ImageVisibility.Never:
                            return (false);
                        case ImageVisibility.Auto:
                            if (string.IsNullOrEmpty(box.Column.FilterExpr) == false)
                                return (true);
                            return (_Dragging == false && box.IsEqualTo(_HitGroupBox) == true);
                    }
                    break;
            }
            return (false);
        }
        #endregion
        #region GetFilterImageState
        private StyleState GetFilterImageState(GridGroupBox box, out bool inFilter)
        {
            inFilter = false;
            StyleState state = StyleState.Default;
            if (box.IsEqualTo(_HitGroupBox) == true)
            {
                state = StyleState.MouseOver;
                if (_HitArea == HeaderArea.InFilterMenu)
                    inFilter = true;
            }
            if (string.IsNullOrEmpty(box.Column.FilterExpr) == false)
                state |= StyleState.Selected;
            return (state);
        }
        #endregion
        #endregion
        #region RenderImage
        private void RenderImage(Graphics g,
            Image image, Rectangle r, ref Rectangle t)
        {
            if (image != null)
            {
                g.DrawImageUnscaledAndClipped(image, r);
                if (r.X < t.X + t.Width / 2)
                {
                    int n = t.Right - r.Right;
                    t.X = r.Right;
                    t.Width = n;
                }
                else
                {
                    int n = t.Right - r.Left;
                    t.Width -= n;
                }
            }
        }
        #endregion
        #endregion
        #region RenderText
        private void RenderText(Graphics g, GridColumn column,
            GroupByVisualStyle style, ColumnHeaderVisualStyle cstyle, Rectangle bounds)
        {
            string s = column.GetHeaderText();
            if (s != null)
            {
                if (column.HeaderTextMarkup != null)
                {
                    RenderTextMarkup(g, column.HeaderTextMarkup, cstyle, bounds);
                }
                else
                {
                    if (_UseColumnHeaderColors == true)
                    {
                        eTextFormat tf = cstyle.GetTextFormatFlags();
                        TextDrawing.DrawString(g, s,
                            cstyle.Font, cstyle.TextColor, bounds, tf);
                    }
                    else
                    {
                        eTextFormat tf = style.GetTextFormatFlags();
                        TextDrawing.DrawString(g, s,
                            cstyle.Font, style.GroupBoxTextColor, bounds, tf);
                    }
                }
            }
        }
        #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 RenderWaterMarkText
        private void RenderWaterMarkText(GridPanel panel, Graphics g)
        {
            if (AllowSelection == true)
            {
                string s = GetWatermarkText();
                if (string.IsNullOrEmpty(s) == false)
                {
                    GroupByVisualStyle style = (GroupByVisualStyle)GetEffectiveStyle();
                    Rectangle t = GetAdjustedBounds(style, Bounds);
                    if (CanShowRowHeader(panel) == true)
                    {
                        t.X += panel.RowHeaderWidthEx;
                        t.Width -= panel.RowHeaderWidthEx;
                    }
                    TextDrawing.DrawString(g, s, style.WatermarkFont, style.WatermarkTextColor,
                        t, eTextFormat.VerticalCenter | eTextFormat.Left);
                }
            }
        }
        #endregion
        #endregion
        #region GroupBoxWindowPaint
        void GroupBoxWindowPaint(object sender, PaintEventArgs e)
        {
            GridPanel panel = GridPanel;
            GridPanelVisualStyle pstyle = panel.GetEffectiveStyle();
            RenderGroupBox(panel,
                (GridGroupBox)_GroupBoxWindow.Tag, null, e.Graphics, pstyle);
        }
        #endregion
        #region Mouse support
        #region InternalMouseLeave
        internal override void InternalMouseLeave(EventArgs e)
        {
            base.InternalMouseLeave(e);
            if (_LockedColumn == false)
                _HitGroupBox = null;
        }
        #endregion
        #region InternalMouseMove
        internal override void InternalMouseMove(MouseEventArgs e)
        {
            base.InternalMouseMove(e);
            SuperGrid.GridCursor = Cursors.Default;
            if (AllowSelection == true)
            {
                Point pt = e.Location;
                _LastHitArea = _HitArea;
                _LastHitGroupBox = _HitGroupBox;
                _HitGroupBox = GetGroupBoxAt(pt);
                _HitArea = GetHitArea(pt);
                if (IsMouseDown == true)
                {
                    if (_Dragging == true)
                    {
                        DragContinue(pt);
                    }
                    else if (_MouseDownHitBox != null)
                    {
                        if (Math.Abs(MouseDownPoint.X - pt.X) > 5 ||
                            Math.Abs(MouseDownPoint.Y - pt.Y) > 5)
                        {
                            DragStart(_MouseDownHitBox.Column);
                        }
                    }
                }
                else
                {
                    switch (_HitArea)
                    {
                        case HeaderArea.InFilterMenu:
                            SuperGrid.GridCursor = Cursors.Hand;
                            break;
                        default:
                            SuperGrid.GridCursor = Cursors.Default;
                            break;
                    }
                }
                if (_HitArea != _LastHitArea || _LastHitGroupBox != _HitGroupBox)
                {
                    if (_LastHitGroupBox != null)
                        InvalidateRender(_LastHitGroupBox.Bounds);
                    if (_HitGroupBox != null)
                    {
                        if ((_LastHitGroupBox != _HitGroupBox) ||
                            (_HitArea == HeaderArea.InFilterMenu || _LastHitArea == HeaderArea.InFilterMenu))
                        {
                            InvalidateRender(_HitGroupBox.Bounds);
                        }
                    }
                }
            }
        }
        #endregion
        #region InternalMouseDown
        internal override void InternalMouseDown(MouseEventArgs e)
        {
            base.InternalMouseDown(e);
            if (e.Button == MouseButtons.Left)
            {
                _MouseDownHitBox = _HitGroupBox;
                if (_MouseDownHitBox != null)
                {
                    Capture = true;
                    if (_HitGroupBox.FilterImageRelBounds.Contains(e.Location) == true)
                        ProcessFilterHit(_MouseDownHitBox);
                    else
                        ProcessContentHit();
                    InvalidateRender(_MouseDownHitBox.Bounds);
                }
            }
        }
        #region ProcessContentHit
        private void ProcessContentHit()
        {
            _Dragging = false;
        }
        #endregion
        #region ProcessFilterHit
        private bool _LockedColumn = true;
        private void ProcessFilterHit(GridGroupBox box)
        {
            if (_FilterMenu != null)
                _FilterMenu.Dispose();
            _LockedColumn = true;
            _FilterMenu = new FilterPopup(GridPanel);
            _FilterMenu.ActivatePopup(box.Column, box.FilterImageRelBounds, ResetState);
        }
        #endregion
        #region ResetState
        internal void ResetState()
        {
            _HitGroupBox = null;
            _LockedColumn = false;
        }
        #endregion
        #endregion
        #region InternalMouseUp
        internal override void InternalMouseUp(MouseEventArgs e)
        {
            base.InternalMouseUp(e);
            GridPanel panel = GridPanel;
            if (_GroupBoxWindow != null)
            {
                GridGroupBox box = (GridGroupBox)_GroupBoxWindow.Tag;
                if (_AfterGroupBox != null)
                {
                    int index = _GroupBoxes.IndexOf(_AfterGroupBox);
                    if (box.Column.GroupBoxEffectsEx == GroupBoxEffects.Move)
                        box.Column.Visible = false;
                    panel.InsertGroup(box.Column, index);
                }
                else if (box.Column.GroupBoxEffectsEx != GroupBoxEffects.None)
                {
                    if (_HitColumn != null)
                    {
                        box.Column.Visible = true;
                        if (_HitColumn != box.Column)
                            ReorderColumn(panel, box.Column);
                        panel.RemoveGroup(box.Column);
                        panel.NeedsSorted = true;
                    }
                }
                DragEnd();
            }
            else
            {
                if (_HitGroupBox != null && _HitGroupBox == _MouseDownHitBox)
                {
                    if (_HitArea == HeaderArea.InContent)
                    {
                        if (panel.IsSortable == true && _AllowUserSort == true)
                        {
                            if ((Control.ModifierKeys & Keys.Control) != Keys.Control)
                            {
                                panel.ColumnHeader.SortColumn(panel, _HitGroupBox.Column);
                                SuperGrid.PostInternalMouseMove();
                            }
                        }
                    }
                }
            }
            if (_MouseDownHitBox != null)
            {
                InvalidateRender(_MouseDownHitBox.Bounds);
                _MouseDownHitBox = null;
            }
        }
        #region ReorderColumn
        private void ReorderColumn(GridPanel panel, GridColumn column)
        {
            GridColumnCollection columns = panel.Columns;
            int[] map = columns.DisplayIndexMap;
            int curIndex = columns.GetDisplayIndex(column);
            int sepIndex = columns.GetDisplayIndex(_HitColumn);
            bool isRight = (_InsertRect.X >
                _HitColumn.Bounds.X + _HitColumn.Bounds.Width / 2);
            if (curIndex > sepIndex && isRight == true && sepIndex < map.Length - 1)
                sepIndex++;
            else if (curIndex < sepIndex && isRight == false && sepIndex > 0)
                sepIndex--;
            if (sepIndex != curIndex)
            {
                if (sepIndex < curIndex)
                {
                    for (int i = curIndex; i > sepIndex; i--)
                        map[i] = map[i - 1];
                }
                else
                {
                    for (int i = curIndex; i < sepIndex; i++)
                        map[i] = map[i + 1];
                }
                map[sepIndex] = column.ColumnIndex;
                for (int i = 0; i < map.Length; i++)
                    columns[map[i]].DisplayIndex = i;
                SuperGrid.UpdateStyleCount();
                SuperGrid.PrimaryGrid.InvalidateRender();
                SuperGrid.DoColumnMovedEvent(panel, column);
            }
        }
        #endregion
        #endregion
        #region InternalMouseDoubleClick
        internal override void InternalMouseDoubleClick(MouseEventArgs e)
        {
            base.InternalMouseDoubleClick(e);
            if (_RemoveGroupOnDoubleClick == true)
            {
                GridGroupBox box = _HitGroupBox;
                if (box != null && box == _MouseDownHitBox)
                {
                    GridPanel panel = GridPanel;
                    if (panel.IsSortable == false || _AllowUserSort == false ||
                        (Control.ModifierKeys & Keys.Control) == Keys.Control)
                    {
                        panel.RemoveGroup(box.Column);
                        panel.NeedsSorted = true;
                        box.Column.Visible = true;
                    }
                }
            }
        }
        #endregion
        #endregion
        #region GetHitArea
        /// 
        /// GetHitArea
        /// 
        /// 
        /// 
        public override HeaderArea GetHitArea(Point pt)
        {
            if (_HitGroupBox != null)
            {
                if (_HitGroupBox.FilterImageRelBounds.Contains(pt))
                    return (HeaderArea.InFilterMenu);
                return (HeaderArea.InContent);
            }
            HeaderArea area = base.GetHitArea(pt);
            if (area != HeaderArea.InContent)
                return (area);
            return (HeaderArea.InWhitespace);
        }
        #endregion
        #region GetAdjustedBounds
        private Rectangle GetAdjustedBounds(TextRowVisualStyle style, Rectangle r)
        {
            r.X += (style.BorderThickness.Left + style.Margin.Left + style.Padding.Left);
            r.Width -= (style.BorderThickness.Horizontal + style.Margin.Horizontal + style.Padding.Horizontal);
            r.Y += (style.BorderThickness.Top + style.Margin.Top + style.Padding.Top);
            r.Height -= (style.BorderThickness.Vertical + style.Margin.Vertical + style.Padding.Vertical);
            return (r);
        }
        #endregion
        #region GetScrollBounds
        internal Rectangle GetScrollBounds(Rectangle r)
        {
            if (IsVFrozen == false)
                r.Y -= VScrollOffset;
            r.X -= HScrollOffset;
            return (r);
        }
        #endregion
        #region GetGroupBoxAt
        ///
        /// Gets the GroupBox containing the given point
        ///
        ///
        ///GroupBox, or null
        public GridGroupBox GetGroupBoxAt(Point pt)
        {
            foreach (GridGroupBox box in _GroupBoxes)
            {
                if (box.Bounds.Contains(pt) == true)
                    return (box);
            }
            return (null);
        }
        #endregion
        #region FindGroupPartition
        private GridGroupBox FindGroupPartition(Point pt)
        {
            for (int i = _GroupBoxes.Count - 1; i >= 0; i--)
            {
                GridGroupBox box = _GroupBoxes[i];
                if (pt.X > box.Bounds.X + box.Bounds.Width / 2)
                    return (box);
            }
            return (_GroupBoxes[0]);
        }
        #endregion
        #region Drag support
        #region DragStart
        internal bool DragStart(GridColumn column)
        {
            GridPanel panel = GridPanel;
            if (panel.VirtualMode == true)
                return (false);
            if (AllowSelection == true && panel.ColumnHeader.Visible == true &&
                column.GroupBoxEffectsEx != GroupBoxEffects.None)
            {
                Capture = true;
                _Dragging = true;
                _GroupBoxWindow = new FloatWindow();
                _GroupBoxWindow.Opacity = .5;
                _GroupBoxWindow.Owner = SuperGrid.FindForm();
                _GroupBoxWindow.Paint += GroupBoxWindowPaint;
                GridGroupBox box = new GridGroupBox(this, column);
                box.GroupBoxStyle = GroupBoxStyle;
                box.CornerRadius = CornerRadius;
                Size size = GetGroupBoxSize(box);
                Rectangle r = new Rectangle(Point.Empty, size);
                UpdateGroupBoxRects(GridPanel, box, ref r);
                box.RelativeBounds = r;
                box.IsDragBox = true;
                _GroupBoxWindow.Size = r.Size;
                int radius = GetCornerRadius(box);
                if (radius > 0 && box.GroupBoxStyle == GroupBoxStyle.RoundedRectangular)
                {
                    using (GraphicsPath path = GetRoundedPath(r, radius))
                    {
                        GraphicsPath cpath = (GraphicsPath)path.Clone();
                        using (Pen pen = new Pen(Color.Black, 2))
                            cpath.Widen(pen);
                        Region rgn = new Region(path);
                        rgn.Union(cpath);
                        _GroupBoxWindow.Region = rgn;
                    }
                }
                _GroupBoxWindow.Tag = box;
                return (true);
            }
            return (false);
        }
        #endregion
        #region DragContinue
        private void DragContinue(Point pt)
        {
            GridGroupBox box = _GroupBoxWindow.Tag as GridGroupBox;
            if (box != null)
            {
                Point ptStart = pt;
                Size size = box.RelativeBounds.Size;
                size.Width++;
                size.Height++;
                pt.X -= (size.Width / 2);
                pt.Y -= (size.Height / 2);
                pt = SuperGrid.PointToScreen(pt);
                Rectangle r = new Rectangle(pt, size);
                _GroupBoxWindow.Bounds = r;
                if (_GroupBoxWindow.Visible == false)
                    _GroupBoxWindow.Show();
                Rectangle t = GetInsertRect(ptStart);
                if (t.Equals(_InsertRect) == false)
                {
                    InvalidateRender(_InsertRect);
                    _InsertRect = t;
                    InvalidateRender(_InsertRect);
                }
            }
        }
        #region GetInsertRect
        private Rectangle GetInsertRect(Point pt)
        {
            _HitColumn = null;
            _AfterGroupBox = null;
            if (Bounds.Contains(pt) == true)
                return (GetGroupBoxInsertRect(pt));
            return (GetColumnInsertRect(pt));
        }
        #region GetColumnInsertRect
        private Rectangle GetColumnInsertRect(Point pt)
        {
            GridPanel panel = GridPanel;
            if (panel.Bounds.Contains(pt) == true)
            {
                if (pt.Y >= Bounds.Bottom && pt.Y < Bounds.Bottom + 50)
                {
                    _HitColumn = GetHitColumn(panel, pt);
                    if (_HitColumn == null)
                        _HitColumn = panel.Columns[0];
                    Rectangle t = Bounds;
                    Rectangle s = SViewRect;
                    if (panel.ShowRowHeaders == true &&
                        RowHeaderVisibility != RowHeaderVisibility.Never)
                    {
                        t.X += panel.RowHeaderWidthEx;
                    }
                    t.X += Dpi.Width2;
                    t.Width = s.Right - t.X - Dpi.Width2;
                    Rectangle r = _HitColumn.Bounds;
                    if (pt.X > r.X + r.Width / 2)
                        r.X = r.Right;
                    r.X -= (MarkerWidth / 2 + 1);
                    r.Y = t.Bottom - MarkerHeight - 2;
                    r.Width = MarkerWidth;
                    r.Height = MarkerHeight;
                    if (r.X < t.X)
                        r.X = t.X;
                    if (r.X > t.Right - MarkerWidth)
                        r.X = t.Right - MarkerWidth;
                    return (r);
                }
            }
            return (Rectangle.Empty);
        }
        #region GetHitColumn
        private GridColumn GetHitColumn(GridPanel panel, Point pt)
        {
            if (panel.Bounds.Contains(pt) == true)
            {
                if (pt.Y >= Bounds.Bottom && pt.Y < Bounds.Bottom + 50)
                {
                    if (panel.FirstVisibleColumn != null && pt.X < panel.FirstVisibleColumn.Bounds.X)
                        return (panel.FirstVisibleColumn);
                    foreach (GridColumn col in panel.Columns)
                    {
                        if (col.Visible == true)
                        {
                            if (pt.X >= col.Bounds.X && pt.X <= col.Bounds.Right)
                                return (col);
                        }
                    }
                    return (panel.LastVisibleColumn);
                }
            }
            return (null);
        }
        #endregion
        #endregion
        #region GetGroupBoxInsertRect
        private Rectangle GetGroupBoxInsertRect(Point pt)
        {
            Rectangle t = Bounds;
            _AfterGroupBox = FindGroupPartition(pt);
            pt = new Point(_AfterGroupBox.Bounds.Right, _AfterGroupBox.Bounds.Y);
            if (GroupBoxLayout == GroupBoxLayout.Flat)
            {
                int index = _GroupBoxes.IndexOf(_AfterGroupBox);
                if (index + 1 < _GroupBoxes.Count)
                {
                    GridGroupBox beforeBox = _GroupBoxes[index + 1];
                    if (index == 0 || beforeBox.Bounds.Y < pt.Y)
                        pt.Y = beforeBox.Bounds.Y;
                }
                pt.X -= 2;
                pt.Y -= 9;
                if (pt.Y < t.Y + 6)
                    pt.Y = t.Y + 6;
            }
            else
            {
                pt.X += 2;
                pt.Y -= 6;
                if (pt.Y < t.Y + 2)
                    pt.Y = t.Y + 2;
            }
            pt.X = Math.Max(pt.X, t.X + 2);
            if (pt.X + MarkerWidth + 2 > ViewRect.Right)
                pt.X = ViewRect.Right - MarkerWidth - 2;
            return (new Rectangle(pt.X, pt.Y, MarkerWidth, MarkerHeight));
        }
        #endregion
        #endregion
        #endregion
        #region DragEnd
        private void DragEnd()
        {
            _Dragging = false;
            if (_GroupBoxWindow != null)
            {
                _GroupBoxWindow.Close();
                _GroupBoxWindow = null;
                _MouseDownHitBox = null;
                InvalidateRender(_InsertRect);
                _InsertRect = Rectangle.Empty;
                SuperGrid.PostInternalMouseMove();
            }
        }
        #endregion
        #endregion
        #region CancelCapture
        /// 
        /// CancelCapture
        /// 
        public override void CancelCapture()
        {
            if (CapturedItem == this)
            {
                Capture = false;
                DragEnd();
            }
        }
        #endregion
        #region Style support
        #region GetNewVisualStyle
        /// 
        /// GetNewVisualStyle
        /// 
        /// 
        protected override TextRowVisualStyle GetNewVisualStyle()
        {
            return (new GroupByVisualStyle());
        }
        #endregion
        #region ApplyStyleEx
        /// 
        /// ApplyStyleEx
        /// 
        /// 
        /// 
        protected override void ApplyStyleEx(TextRowVisualStyle style, StyleType[] css)
        {
            GroupByVisualStyle gstyle = style as GroupByVisualStyle;
            if (gstyle != null)
            {
                foreach (StyleType cs in css)
                {
                    gstyle.ApplyStyle(SuperGrid.BaseVisualStyles.GroupByStyles[cs]);
                    gstyle.ApplyStyle(SuperGrid.DefaultVisualStyles.GroupByStyles[cs]);
                    gstyle.ApplyStyle(GridPanel.DefaultVisualStyles.GroupByStyles[cs]);
                }
                if (gstyle.GroupBoxBorderColor == Color.Empty)
                    gstyle.GroupBoxBorderColor = Color.Blue;
                if (gstyle.WatermarkTextColor == Color.Empty)
                    gstyle.WatermarkTextColor = Color.Gray;
                if (gstyle.WatermarkFont == null)
                    gstyle.WatermarkFont = SystemFonts.DefaultFont;
            }
            InsertMarker = null;
        }
        #endregion
        #region GetGroupByEffectiveStyle
        private GroupByVisualStyle GetGroupByEffectiveStyle(GridGroupBox box)
        {
            return ((GroupByVisualStyle)
                GetEffectiveStyle(GetGroupByStyleType(box)));
        }
        #endregion
        #region GetGroupByStyleType
        private StyleType GetGroupByStyleType(GridGroupBox box)
        {
            if (IsMouseDown == true)
            {
                Point pt = Control.MousePosition;
                pt = SuperGrid.PointToClient(pt);
                if (box.FilterImageBounds.Contains(pt) == false)
                {
                    if (box.IsDragBox == true || box.IsEqualTo(_MouseDownHitBox))
                    {
                        if (box.IsEqualTo(_HitGroupBox) == true)
                            return (StyleType.SelectedMouseOver);
                        return (StyleType.Selected);
                    }
                    return (StyleType.Default);
                }
            }
            if (box.IsEqualTo(_HitGroupBox) == true)
                return (StyleType.MouseOver);
            return (StyleType.Default);
        }
        #endregion
        #endregion
    }
    #region GridGroupBox
    ///
    /// GroupBox definition
    ///
    public class GridGroupBox
    {
        #region Private properties
        private GridGroupByRow _GridGroupBy;
        private GridColumn _Column;
        private Rectangle _RelativeBounds;
        private Rectangle _SortImageRelBounds;
        private Rectangle _FilterImageRelBounds;
        private Padding _Padding = new Padding(0);
        private GroupBoxStyle _GroupBoxStyle = GroupBoxStyle.Rectangular;
        private bool _IsDragBox;
        private Size _ContentSize;
        private int _CornerRadius;
        #endregion
        #region Public properties
        #region Bounds
        ///
        /// Gets the associated Bounds
        ///
        public Rectangle Bounds
        {
            get
            {
                if (_IsDragBox == true)
                    return (_RelativeBounds);
                return (_GridGroupBy.GetScrollBounds(_RelativeBounds));
            }
        }
        #endregion
        #region Column
        ///
        /// Gets the associated GridColumn
        ///
        public GridColumn Column
        {
            get { return (_Column); }
            internal set { _Column = value; }
        }
        #endregion
        #region ContentSize
        ///
        /// Gets the associated Content Size
        ///
        public Size ContentSize
        {
            get { return (_ContentSize); }
            set { _ContentSize = value; }
        }
        #endregion
        #region CornerRadius
        ///
        /// Gets or sets the corner radius to
        /// use when GroupBoxStyle is RoundedRectangular
        ///
        public int CornerRadius
        {
            get { return (_CornerRadius); }
            set { _CornerRadius = value; }
        }
            #endregion
        #region GridGroupBy
        ///
        /// Gets the associated GridGroupBy object
        ///
        public GridGroupByRow GridGroupBy
        {
            get { return (_GridGroupBy); }
            internal set { _GridGroupBy = value; }
        }
        #endregion
        #region GroupBoxStyle
        ///
        /// GroupBox Style
        ///
        public GroupBoxStyle GroupBoxStyle
        {
            get { return (_GroupBoxStyle); }
            set { _GroupBoxStyle = value; }
        }
        #endregion
        #region Padding
        ///
        /// Content padding
        ///
        public Padding Padding
        {
            get { return (_Padding); }
            set { _Padding = value; }
        }
        #endregion
        #endregion
        #region Internal properties
        #region FilterImageBounds
        internal Rectangle FilterImageBounds
        {
            get
            {
                if (_IsDragBox == true || _FilterImageRelBounds.IsEmpty)
                    return (_FilterImageRelBounds);
                return (_GridGroupBy.GetScrollBounds(_FilterImageRelBounds));
            }
        }
        #endregion
        #region FilterImageRelBounds
        internal Rectangle FilterImageRelBounds
        {
            get { return (_FilterImageRelBounds); }
            set { _FilterImageRelBounds = value; }
        }
        #endregion
        #region IsDragBox
        internal bool IsDragBox
        {
            get { return (_IsDragBox); }
            set { _IsDragBox = value; }
        }
        #endregion
        #region RelativeBounds
        internal Rectangle RelativeBounds
        {
            get { return (_RelativeBounds); }
            set { _RelativeBounds = value; }
        }
        #endregion
        #region SortImageBounds
        internal Rectangle SortImageBounds
        {
            get
            {
                if (_IsDragBox == true || _SortImageRelBounds.IsEmpty)
                    return (_SortImageRelBounds);
                return (_GridGroupBy.GetScrollBounds(_SortImageRelBounds));
            }
        }
        #endregion
        #region SortImageRelBounds
        internal Rectangle SortImageRelBounds
        {
            get { return (_SortImageRelBounds); }
            set { _SortImageRelBounds = value; }
        }
        #endregion
        #endregion
        internal GridGroupBox(GridGroupByRow groupBy, GridColumn column)
        {
            _GridGroupBy = groupBy;
            _Column = column;
            _GroupBoxStyle = groupBy.GroupBoxStyle;
        }
        #region IsEqualTo
        internal bool IsEqualTo(GridGroupBox box)
        {
            return (box != null && box.Column == Column);
        }
        #endregion
    }
    #endregion
    #region enums
    #region GroupBoxEffects
    ///
    /// GroupBoxEffects
    ///
    public enum GroupBoxEffects
    {
        ///
        /// Not set.
        ///
        NotSet = -1,
        ///
        /// The Column will not interact with the GroupBox.
        ///
        None,
        ///
        /// The Column presentation will be copied to and
        /// from the grid and associated GroupBox.
        ///
        Copy,
        ///
        /// The Column presentation will be moved to and
        /// from the grid and associated GroupBox.
        ///
        Move,
    }
    #endregion
    #region GroupBoxLayout
    ///
    /// GroupBox Layout
    ///
    public enum GroupBoxLayout
    {
        ///
        /// Group boxes are Flat, all on the same layout row
        ///
        Flat,
        ///
        /// Group boxes are oriented Hierarchically
        ///
        Hierarchical,
    }
    #endregion
    #region GroupBoxStyle
    ///
    /// GroupBox Style
    ///
    public enum GroupBoxStyle
    {
        ///
        /// Group boxes are drawn Rectangular
        ///
        Rectangular,
        ///
        /// Group boxes are drawn Rounded Rectangular
        ///
        RoundedRectangular,
    }
    #endregion
    #endregion
}