//------------------------------------------------------------------------------
// <copyright file=”*.cs” company=”EhLib Team”>
//     Copyright (c) 2017 Dmitry V. Bolshakov   
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Windows.Forms.VisualStyles;
using System.Diagnostics;
using System.ComponentModel.Design;

namespace EhLib
{
  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridColumnTitle : DataAxisGridBarTitle, IGridLineHost, IGridRowHeightOptionsOwner
  {
    #region private consts
    private static readonly object EventKeyCellPaint = new object();
    private static readonly object EventKeyCellPaintCustomArea = new object();
    private static readonly object EventKeyCellQueryCursor = new object();
    //private static readonly object EventKeyCellCustomAreaMeasuresNeeded = new object();
    private static readonly object EventKeyCellClientRectNeeded = new object();

    private static readonly object EventKeyCellMouseDown = new object();
    private static readonly object EventKeyCellMouseMove = new object();
    private static readonly object EventKeyCellMouseUp = new object();
    private static readonly object EventKeyCellMouseClick = new object();
    private static readonly object EventKeyCellMouseDoubleClick = new object();
    private static readonly object EventKeyCellMouseEnter = new object();
    private static readonly object EventKeyCellMouseLeave = new object();
    private static readonly object EventKeyCellMouseHover = new object();
    private static readonly object EventKeyCellContextMenuStripNeeded = new object();
    #endregion private consts

    #region Privates
    //private string caption = string.Empty;
    //private readonly Padding defaultPadding = new Padding(4, 2, 4, 2);
    private readonly DataGridColumnTitleFilter filter;
    //private Color foreColor = Color.Empty;

    //private Padding padding = new Padding(0);
    private Orientation textOrientation = Orientation.Horizontal;
    private readonly InTitleFilterButtonMetrics filterButtonMetrics;
    private readonly GridLine vertLine;
    //private readonly CellBackFiller backFiller;
    private readonly GridRowHeightOptions heightOptions;

    private DataGridTitleNode titleNode;
    #endregion privates

    public DataGridColumnTitle(PropertyAxisBar propBar) : base(propBar)
    {
      filter = new DataGridColumnTitleFilter(this);
      filterButtonMetrics = new InTitleFilterButtonMetrics();
      this.vertLine = new GridLine(this);
      heightOptions = new GridRowHeightOptions(this);
      //titleCell = new DataGridTitleCell();
      //backFiller = new CellBackFiller(this);

      //InCellFilterBtnRect = Rectangle.Empty;
    }

    #region design-time properties
    [DefaultValue(null)]
    public virtual ContextMenuStrip ContextMenuStrip { get; set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridColumnTitleFilter Filter
    {
      get
      {
        return filter;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridRowHeightOptions HeightOptions
    {
      get
      {
        return heightOptions;
      }
    }

    [DefaultValue(Orientation.Horizontal)]
    public Orientation TextOrientation
    {
      get { return textOrientation; }
      set
      {
        if (textOrientation != value)
        {
          textOrientation = value;
          TextOrientationChanged();
        }
      }
    }
    #endregion

    #region events
    public event EventHandler<DataGridTitleCellPaintEventArgs> CellPaint
    {
      add
      {
        this.Events.AddHandler(EventKeyCellPaint, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellPaint, value);
      }
    }

    public event EventHandler<DataGridTitleCellPaintEventArgs> CellPaintCustomArea
    {
      add
      {
        this.Events.AddHandler(EventKeyCellPaintCustomArea, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellPaintCustomArea, value);
      }
    }

    public event EventHandler<BaseGridCellQueryCursorEventArgs> CellQueryCursor
    {
      add
      {
        this.Events.AddHandler(EventKeyCellQueryCursor, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellQueryCursor, value);
      }
    }

    //public event EventHandler<DataGridTitleCellCustomAreaMeasuresNeededEventArgs> CellCustomAreaMeasuresNeeded
    //{
    //  add
    //  {
    //    this.Events.AddHandler(EventKeyCellCustomAreaMeasuresNeeded, value);
    //  }
    //  remove
    //  {
    //    this.Events.RemoveHandler(EventKeyCellCustomAreaMeasuresNeeded, value);
    //  }
    //}

    public event EventHandler<DataGridTitleCellClientAreaNeededEventArgs> CellClientRectNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyCellClientRectNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellClientRectNeeded, value);
      }
    }

    public event EventHandler<DataGridTitleCellMouseEventArgs> CellMouseDown
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseDown, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseDown, value);
      }
    }

    public event EventHandler<DataGridTitleCellMouseEventArgs> CellMouseMove
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseMove, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseMove, value);
      }
    }

    public event EventHandler<DataGridTitleCellMouseEventArgs> CellMouseUp
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseUp, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseUp, value);
      }
    }

    public event EventHandler<DataGridTitleCellMouseEventArgs> CellMouseClick
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseClick, value);
      }
    }

    public event EventHandler<DataGridTitleCellMouseEventArgs> CellMouseDoubleClick
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseDoubleClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseDoubleClick, value);
      }
    }

    public event EventHandler<DataGridTitleCellEventArgs> CellMouseEnter
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseEnter, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseEnter, value);
      }
    }

    public event EventHandler<DataGridTitleCellEventArgs> CellMouseLeave
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseLeave, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseLeave, value);
      }
    }

    public event EventHandler<DataGridTitleCellMouseEventArgs> CellMouseHover
    {
      add
      {
        this.Events.AddHandler(EventKeyCellMouseHover, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellMouseHover, value);
      }
    }

    public event EventHandler<DataGridTitleCellContextMenuStripNeededEventArgs> CellContextMenuStripNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyCellContextMenuStripNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCellContextMenuStripNeeded, value);
      }
    }
    
    #endregion

    #region public properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public DataGridColumn Column
    {
      get { return (DataGridColumn)base.PropBar; }
    }

    [Browsable(false)]
    public bool Sortable
    {
      get
      {
        if (Column.Grid.Title.AutoSortMarking && Column.IsDataBound)
          return true;
        else
          return false;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public int SortIndex
    {
      get
      {
        return Column.Grid.SortMarkers.IndexOf(Column) + 1;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public SortOrder SortMarker
    {
      get
      {
        //return this.sortMarker;
        int smi = Column.Grid.SortMarkers.IndexOf(Column);
        if (smi >= 0)
        {
          if (Column.Grid.SortMarkers[smi].SortDirection == ListSortDirection.Ascending)
            return SortOrder.Ascending;
          else
            return SortOrder.Descending;
        }
        else
        {
          return SortOrder.None;
        }
      }
      //set
      //{
      //  if (value != sortMarker)
      //  {
      //    sortMarker = value;
      //    Column.Grid.ColumnTitleSortMarkerChanged(this);
      //  }
      //}
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridLine VertLine
    {
      get
      {
        return vertLine;
      }
    }
    #endregion

    #region internal properties
    [Browsable(false)]
    public new DataGridEh Grid
    {
      get
      {
        return (DataGridEh)base.Grid;
      }

      protected internal set
      {
        base.Grid = value;
      }
    }

    //protected internal DataGridTitleCell TitleCell
    //{
    //  get { return titleCell; }
    //}

    [Browsable(false)]
    public InTitleFilterButtonMetrics FilterButtonMetrics
    {
      get { return filterButtonMetrics; }
    }

    [Browsable(false)]
    public DataGridTitleNode TitleNode
    {
      get
      {
        if (titleNode == null)
        {
          titleNode = new DataGridTitleNode(DataGridTitleNodeType.ColumnTitle, this, null);
        }
        return titleNode;
      }
    }

    //internal Rectangle InCellFilterBtnRect
    //{ get; set; }

    #endregion

    #region methods
    //IGridRowHeightOptionsOwner
    void IGridRowHeightOptionsOwner.HeightOptionsChanged(GridRowHeightOptions heightOptions)
    {
      HeightAutoExpandChanged();
    }

    bool IGridRowHeightOptionsOwner.HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.Title.HeightOptions.AutoExpand;
      else
        return false;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        return Grid.Title.HeightOptions.ContentHeight;
      else
        return 1;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions)
    {
      return 0;
    }

    GridRowHeightUnit IGridRowHeightOptionsOwner.HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions)
    {
      return GridRowHeightUnit.TextLine;
    }

    ////ICellBackFillerOwner
    //void ICellBackFillerOwner.BackFillerChanged(CellBackFiller backFiller)
    //{
    //  if (Grid != null)
    //    Grid.Invalidate();
    //}

    //Color ICellBackFillerOwner.BackFillerDefaultColor(CellBackFiller backFiller)
    //{
    //  return Grid.Title.BackFiller.Color;
    //}

    //Color ICellBackFillerOwner.BackFillerDefaultSecondColor(CellBackFiller backFiller)
    //{
    //  return Grid.Title.BackFiller.SecondColor;
    //}

    //CellFillStyle ICellBackFillerOwner.BackFillerDefaultFillStyle(CellBackFiller backFiller)
    //{
    //  return Grid.Title.BackFiller.FillStyle;
    //}

    //CellInnerBorderStyle ICellBackFillerOwner.BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    //{
    //  return Grid.Title.BackFiller.InnerBorder;
    //}

    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      if (Grid != null)
        Grid.Invalidate();
    }

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      return Grid.Title.VertLine.Visible;
    }

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      return Grid.Title.VertLine.Color;
    }

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      return Grid.Title.VertLine.Style;
    }

    //Other
    public virtual int CalcDefaultWidth()
    {
      Graphics g = EhLibUtils.DisplayGraphicsCash;
      Size sz = TextRenderer.MeasureText(g, Text, Font);
      return sz.Width + Padding.Left + Padding.Right;
    }

    public virtual int CalcHeight()
    {
      Size sz;
      int th;
      int th1;

      if (HeightOptions.Unit == GridRowHeightUnit.TextLine)
      {

        sz = TextRenderer.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", Font);
        th = sz.Height * HeightOptions.ContentHeight;
        th = th + Padding.Top + Padding.Bottom;

        if (HeightOptions.AutoExpand)
        {
          if (TextOrientation == Orientation.Vertical)
          {
            using (var drawFormat = new StringFormat())
            {
              drawFormat.Trimming = StringTrimming.None;
              drawFormat.FormatFlags = StringFormatFlags.DirectionVertical | StringFormatFlags.NoWrap;

            SizeF sizef = EhLibUtils.DisplayGraphicsCash.MeasureString(Text, Font, 0, drawFormat);
              th1 = (int)sizef.Height;
              th1 = th1 + Padding.Top + Padding.Bottom;
              if (th1 > th)
                th = th1;
            }
          }
          else
          {
            Rectangle cellRect = new Rectangle(0, 0, Column.Width, 0);
            Rectangle mainContentRect = Grid.Title.CellMan.GetCellMainContentRect(this, cellRect);
            mainContentRect.Width = mainContentRect.Width - Padding.Left - Padding.Right;

            Size sz1 = EhLibUtils.MeasureText(EhLibUtils.DisplayGraphicsCash, Text, Font, mainContentRect.Size, Grid.Title.WrapMode);
            th1 = sz1.Height;
            th1 = th1 + Padding.Top + Padding.Bottom;
            if (th1 > th)
              th = th1;
          }
        }

        if (ImageBox.Visible)
        {
          int imageHeight = ImageBox.Size.Height;
          if (ImageBox.TextImageRelation == TextImageRelation.ImageBeforeText ||
              ImageBox.TextImageRelation == TextImageRelation.TextBeforeImage ||
              ImageBox.TextImageRelation == TextImageRelation.Overlay)
          {
            if (imageHeight > th)
              th = imageHeight;
          }
          else
          {
            th = th + imageHeight;
          }
        }
      }
      else
      {
        th = HeightOptions.ContentHeight;
        th = th + Padding.Top + Padding.Bottom;
      }
      return th;
    }

    public virtual bool CanBePressed()
    {
      return Sortable;
    }

    public virtual string DefaultCaption()
    {
      return Column.DataPropertyName;
    }

    //public virtual void ResetHeightAutoExpand()
    //{
    //  heightAutoExpandStored = false;
    //  HeightAutoExpandChanged();
    //}

    protected internal virtual void TitleFilterChanged()
    {
      Column.Grid.Invalidate();
    }

    private void HeightAutoExpandChanged()
    {
      if (Column.Grid != null)
        Column.Grid.UpdateBaseFixedBands();
    }

    protected internal override void PerformLayout()
    {
      Grid.titleCellMan.PerformLayout(this);
    }

    protected internal override void UpdateMetrics(Size cellSize)
    {
      if (Grid != null)
        Grid.GetDrawStyle().GetInTitleFilterButtonMetrics(Grid, cellSize, FilterButtonMetrics);
    }

    internal void HandlePaintEvent(DataGridTitleCellPaintEventArgs e)
    {
      var eh = this.Events[EventKeyCellPaint] as EventHandler<DataGridTitleCellPaintEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseDownEvent(DataGridTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseDown] as EventHandler<DataGridTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseMoveEvent(DataGridTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseMove] as EventHandler<DataGridTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseUpEvent(DataGridTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseUp] as EventHandler<DataGridTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseClickEvent(DataGridTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseClick] as EventHandler<DataGridTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseDoubleClickEvent(DataGridTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseDoubleClick] as EventHandler<DataGridTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseEnterEvent(DataGridTitleCellEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseEnter] as EventHandler<DataGridTitleCellEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleMouseLeaveEvent(DataGridTitleCellEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseLeave] as EventHandler<DataGridTitleCellEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    internal void HandleQueryCursorEvent(BaseGridCellQueryCursorEventArgs e)
    {
      var eh = this.Events[EventKeyCellQueryCursor] as EventHandler<BaseGridCellQueryCursorEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    //internal void HandleCellCustomAreaMeasuresNeededEvent(DataGridTitleCellCustomAreaMeasuresNeededEventArgs e)
    //{
    //  var eh = this.Events[EventKeyCellCustomAreaMeasuresNeeded] as EventHandler<DataGridTitleCellCustomAreaMeasuresNeededEventArgs>;
    //  if (eh != null)
    //  {
    //    eh(this, e);
    //  }
    //}

    internal void HandleMouseHoverEvent(DataGridTitleCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyCellMouseHover] as EventHandler<DataGridTitleCellMouseEventArgs>;
      if (eh != null)
        eh(this, e);
    }

    internal void HandleCellMouseContextMenuStripNeededEvent(DataGridTitleCellContextMenuStripNeededEventArgs e)
    {
      var eh = this.Events[EventKeyCellContextMenuStripNeeded] as EventHandler<DataGridTitleCellContextMenuStripNeededEventArgs>;
      if (eh != null)
      {
        eh(this, e);
      }
    }

    internal void HandleClientRectNeededEvent(DataGridTitleCellClientAreaNeededEventArgs e)
    {
      var eh = this.Events[EventKeyCellClientRectNeeded] as EventHandler<DataGridTitleCellClientAreaNeededEventArgs>;
      if (eh != null /*&& !this.IsDisposed*/)
      {
        eh(this, e);
      }
    }

    internal void HandlePaintCustomAreaEvent(DataGridTitleCellPaintEventArgs e)
    {
      var eh = this.Events[EventKeyCellPaintCustomArea] as EventHandler<DataGridTitleCellPaintEventArgs>;

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

    #endregion Methods

  }

  public class DataGridTitleCellMan : DataGridColumnCellMan
  {

    #region fields
    private int pressedColumTitleIndex = -1;
    private int filterButtonHotIndex = -1;
    //private bool filterButtonPressedState;
    private int filterButtonDownTitleIndex = -1;
    //private Rectangle InCellFilterBtnRect = Rectangle.Empty;
    #endregion fields

    public DataGridTitleCellMan()
    {
    }
                                                
    #region properites
    //public DataGridColumnTitle ColumnTitle
    //{
    //  get { return Column.Title; }
    //}
    #endregion properites

    #region methods
    //Paint
    protected internal override BaseGridCellPaintEventArgs GetCellPaintEmptyAreaEventArgs(
        Graphics graphics,
        int colIndex, int rowIndex,
        Rectangle paintRect,
        BasePaintCellStates state,
        int areaColIndex, int areaRowIndex,
        Point inCellMousePos
      )
    {
      return GetCellPaintParams(graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos);
    }

    public override BaseGridCellPaintEventArgs GetCellPaintParams(
        Graphics graphics,
        int colIndex, int rowIndex,
        Rectangle paintRect,
        BasePaintCellStates state,
        int areaColIndex, int areaRowIndex,
        Point inCellMousePos
      )
    {
      DataGridColumn column;
      if (areaColIndex >= 0 && areaColIndex < Grid.VisibleColumns.Count)
        column = Grid.VisibleColumns[areaColIndex];
      else
        column = null;

      var result = new DataGridTitleCellPaintEventArgs(
        this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos, column);

      if (column != null)
        result.CellClientRect = GetCellClientRect(column.Title, result.CellRect);
      FillPaintParams(result);

      return result;
    }

    protected internal override void HandlePaintEvent(BaseGridCellPaintEventArgs e)
    {
      var te = (DataGridTitleCellPaintEventArgs)e;
      Grid.Title.HandlePaintEvent(te);
      if (te.Column != null)
        te.Column.Title.HandlePaintEvent(te);
    }

    protected internal override void OnPaint(BaseGridCellPaintEventArgs e)
    {
      var tp = (DataGridTitleCellPaintEventArgs)e;

      OnPaintBackground(tp);
      OnPaintForeground(tp);

      if (Grid.DesignMode && Grid.Title.MultiTitle.Active)
      {
        IDesignerHost idh = (IDesignerHost)Grid.GetService(typeof(IDesignerHost));
        Debug.Assert(idh != null, "idh != null");
        var grd = idh.GetDesigner(Grid) as IDataGridDesigner;
        if (grd != null)
          grd.PaintCellDesignData(Grid, e.Graphics, e.ColIndex, e.RowIndex, e.CellClientRect, e.State);
      }
    }

    protected internal virtual void OnPaintBackground(DataGridTitleCellPaintEventArgs e)
    {
      object mouseObject;
      if (e.Column != null)
        mouseObject = e.Column.Title;
      else
        mouseObject = null;

      BaseGridFillFixedCellEventArgs styledPaintArgs = new BaseGridFillFixedCellEventArgs
      {
        CellRect = e.CellRect,
        Graphics = e.Graphics,
        IsHot = this.IsHot(e.AreaColIndex, e.AreaRowIndex) && 
                (Grid.Title.MouseHolderTitleItem == mouseObject) &&
                !Grid.DesignMode && 
                Grid.IsDrawHotState(),
        IsPressed = (pressedColumTitleIndex == e.AreaColIndex),
        IsSelected = (e.State & BasePaintCellStates.Selected) != 0,
        BackColor = e.BackColor
      };

      if (e.Column != null)
      {
        styledPaintArgs.FillStyle = e.Column.Title.BackFiller.FillStyle;
        styledPaintArgs.InnerBorder = e.Column.Title.BackFiller.InnerBorder;
        styledPaintArgs.FillColor = e.Column.Title.BackFiller.Color;
        styledPaintArgs.SecondFillColor = e.Column.Title.BackFiller.SecondColor;
      }
      else
      {
        styledPaintArgs.FillStyle = Grid.Title.BackFiller.FillStyle;
        styledPaintArgs.InnerBorder = Grid.Title.BackFiller.InnerBorder;
        styledPaintArgs.FillColor = Grid.Title.BackFiller.Color;
        styledPaintArgs.SecondFillColor = Grid.Title.BackFiller.SecondColor;
      }

      Grid.GetDrawStyle().FillTitleCell(Grid, styledPaintArgs);
    }

    protected internal virtual void OnPaintForeground(DataGridTitleCellPaintEventArgs e)
    {
      OnPaintClientRect(e);
      OnPaintCustomArea(e);
    }

    protected internal virtual void OnPaintClientRect(DataGridTitleCellPaintEventArgs e)
    {
      bool clipped = false;
      Region clientClip = null;
      Rectangle paintRect;

      e.ContentRect = EhLibUtils.TrimPadding(e.CellClientRect, e.Padding);
      OnPaintSurround(e);
      if (e.AreaColIndex >= 0)
        OnPaintContent(e);

      paintRect = e.CellRect;
      if (pressedColumTitleIndex == e.AreaColIndex)
      {
        clientClip = e.Graphics.Clip;
        e.Graphics.SetClip(e.CellRect, CombineMode.Intersect);
        clipped = true;
        paintRect.Offset(new Point(1, 1));
      }

      if (clipped)
      {
        e.Graphics.Clip = clientClip;
        paintRect.Offset(new Point(-1, -1));
      }
    }

    protected internal virtual void OnPaintCustomArea(DataGridTitleCellPaintEventArgs e)
    {
      HandlePaintCustomAreaEvent(e);
    }

    protected void HandlePaintCustomAreaEvent(DataGridTitleCellPaintEventArgs e)
    {
      Grid.Title.HandlePaintCustomAreaEvent(e);
      if (e.Column != null)
        e.Column.Title.HandlePaintCustomAreaEvent(e);
    }

    protected internal virtual void OnPaintContent(DataGridTitleCellPaintEventArgs e)
    {
      if (e.Column == null) return;

      if (e.TextOrientation == Orientation.Vertical)
      {
        DrawTextVertically(e.Graphics, e.ContentRect, e.State, e.AreaColIndex, e.AreaRowIndex);
      }
      else
      {
        bool wordBreak = CanDrawWordBreak(e.WrapMode, e.Graphics, e.ContentRect, e.Font);
        string text = GetDisplayText(e.AreaColIndex, e.AreaRowIndex);
        Grid.PaintingDrawText(e.Graphics, text, e.Font, e.ContentRect, e.ForeColor,
            e.Column.Title.HorzAlign, e.Column.Title.VertAlign, wordBreak);
      }
    }

    protected internal virtual void FillPaintParams(DataGridTitleCellPaintEventArgs e)
    {
      if (e.Column != null)
      {
        e.AlignFlags = EhLibUtils.TranslateAlignmentToTextFormatFlags(e.Column.Title.HorzAlign,
                                                                                e.Column.Title.VertAlign);
        //aligntFlags = EhLibUtils.TranslateContentAlignmentToTextFormatFlags(Column.Title.TextAlign);
        e.Padding = e.Column.Title.Padding;
        e.Font = e.Column.Title.Font;
        e.BackColor = e.Column.Title.BackFiller.Color;
        e.ForeColor = e.Column.Title.ForeColor;
        e.EndEllipsis = e.Column.Title.EndEllipsis;
        e.TextOrientation = e.Column.Title.TextOrientation;
      }
      else
      {
        e.AlignFlags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
        e.Padding = Grid.Title.Padding;
        e.Font = Grid.Title.Font;
        e.BackColor = Grid.Title.BackFiller.Color;
        e.ForeColor = Grid.Title.ForeColor;
        e.EndEllipsis = Grid.Title.EndEllipsis;
        e.TextOrientation = Orientation.Horizontal;
      }

      if ((e.State & BasePaintCellStates.Selected) != 0)
        e.ForeColor = Grid.GetDrawStyle().GetFixedSelectedForeColor(Grid, e.BackColor, e.ForeColor);

      e.ContentRect = e.CellClientRect;
      e.WrapMode = Grid.Title.WrapMode;
    }

    protected internal virtual void OnPaintSurround(DataGridTitleCellPaintEventArgs e)
    {
      Rectangle sortMarkerRect;
      Rectangle newContentRect;
      Rectangle filterButtonArea;
      Rectangle filterButtonRect;
      //Size filterButtonSize;
      //Size filterButtonSize;
      PushButtonState btnState;
      bool paintFilterButtonBack;
      bool isHaveFilterData;

      if ((e.Column != null) &&
          (e.Column.Title.Filter.IsShown) &&
          ((e.Column.Grid.Title.MouseInTitleRow && Grid.GridState == BaseGridState.Normal) ||
           !e.Column.Title.Filter.Expression.IsEmpty() ||
           (e.Column.Grid.Title.Filter.FilterDropDownFormColumn != null))
          )
      {
        InTitleFilterButtonMetrics fbm = e.Column.Title.FilterButtonMetrics;

        filterButtonRect = fbm.ButtonRect;
        filterButtonRect.Offset(e.CellRect.Location);

        filterButtonArea = new Rectangle(
          filterButtonRect.Left - fbm.Margin.Left,
          filterButtonRect.Top - fbm.Margin.Top,
          filterButtonRect.Width + fbm.Margin.Right + fbm.Margin.Left,
          filterButtonRect.Height + fbm.Margin.Top + fbm.Margin.Bottom
        );

        //filterButtonRect = new Rectangle(
        //  p.CellRect.Right - filterButtonSize.Width,
        //  p.CellRect.Top,
        //  filterButtonSize.Width,
        //  filterButtonSize.Height
        //);

        //filterButtonRect = EhLibUtils.RectCenter(filterButtonRect, filterButtonArea);

        if (filterButtonDownTitleIndex == e.AreaColIndex)
          btnState = PushButtonState.Pressed;
        else if ((filterButtonHotIndex == e.AreaColIndex) ||
                 //(filterButtonPressedState) ||
                 (e.Column.Grid.Title.Filter.FilterDropDownFormColumn == e.Column)
        )
          btnState = PushButtonState.Hot;
        else
          btnState = PushButtonState.Normal;

        if ((e.Column.Grid.Title.MouseInTitleRow ||
             (e.Column.Grid.Title.Filter.FilterDropDownFormColumn != null))
             &&
             (!Grid.DesignMode)
        /*||
       (!Column.Title.Filter.Expression.IsEmpty())*/
        )
          paintFilterButtonBack = true;
        else
          paintFilterButtonBack = false;

        isHaveFilterData = !e.Column.Title.Filter.Expression.IsEmpty();

        PaintFilterButton(e.Graphics, filterButtonRect, btnState, paintFilterButtonBack, isHaveFilterData);

        newContentRect = e.ContentRect;
        newContentRect.Width = e.CellRect.Width - filterButtonArea.Width - 2;
        e.ContentRect = newContentRect;
      }

      if ((e.Column != null) && (e.Column.Title.SortMarker != SortOrder.None))
      {
        OnPaintSortMarker(e.Graphics, e.ContentRect, e.State, e.AreaColIndex, e.AreaRowIndex, out sortMarkerRect);

        if (e.ContentRect.Right > sortMarkerRect.Left)
        {
          newContentRect = e.ContentRect;
          newContentRect.Width = newContentRect.Width - (newContentRect.Right - sortMarkerRect.Left) - 2;
          e.ContentRect = newContentRect;
        }
      }

      if ((e.Column != null) && (e.Column.Title.ImageBox.Visible))
      {
        Rectangle imageRect;
        Rectangle textRect;

        TextLayoutParams tlp = new TextLayoutParams()
        {
          Text = e.Column.Title.Text,
          Font = e.Column.Title.Font,
          HorzAlign = e.Column.Title.HorzAlign,
          VertAlign = e.Column.Title.VertAlign,
          WrapMode = Grid.Title.WrapMode
        };
        e.Column.Title.ImageBox.LayoutImageAndText(e.ContentRect, tlp, out imageRect, out textRect);

        CellImageBoxPaintEventArgs ibe = new CellImageBoxPaintEventArgs(e.Column.Title.ImageBox, e.Graphics, imageRect, e);
        e.Column.Title.ImageBox.ProcessPaint(ibe);

        e.ContentRect = textRect;
      }
    }

    protected internal override void OnPaintEmptyArea(BaseGridCellPaintEventArgs e)
    {
      OnPaint(e);
    }

    protected internal virtual void OnPaintSortMarker(Graphics graphics, Rectangle paintRect, BasePaintCellStates state,
      int dataColIndex, int dataRowIndex, out Rectangle sortMarkerRect)
    {
      int sortIndex;
      DataGridColumn column = Grid.VisibleColumns[dataColIndex];

      sortMarkerRect = paintRect;
      sortMarkerRect.X = sortMarkerRect.Right;
      sortMarkerRect.Width = 0;

      if (column.Title.SortMarker == SortOrder.None) return;

      Size smz = column.Grid.GetDrawStyle().GetSortMarkerAreaSize(Grid.Title.SortMarkerStyle);
      if (smz.Width > paintRect.Width / 2)
        smz.Width = paintRect.Width / 2;
      Rectangle smAreaRect = paintRect;
      smAreaRect.X = smAreaRect.Right - smz.Width;
      smAreaRect.Width = smz.Width;

      if (Grid.SortMarkers.Count > 1)
        sortIndex = column.Title.SortIndex;
      else
        sortIndex = 0;

      SortMarkerPaintEventArgs smArgs = new SortMarkerPaintEventArgs()
      {
        Graphics = graphics,
        MarkerAreaRect = smAreaRect,
        ControlBackColor = column.Grid.BackColor,
        ControlForeColor = column.Grid.ForeColor,
        SortMarkerStyle = Grid.Title.SortMarkerStyle,
        SortOrder = column.Title.SortMarker,
        SortIndex = sortIndex,
        SortMarkerColor = EhLibUtils.ApproximateColor(column.Grid.BackColor, column.Grid.ForeColor, 85)
        //      Grid.LineOptions.DefaultDarkColor()
      };
      Grid.GetDrawStyle().DrawSortMarkerArea(smArgs);

      sortMarkerRect = smAreaRect;
    }

    protected internal virtual void PaintFilterButton(Graphics gr, Rectangle btnRect, PushButtonState btnState, bool paintBack, bool isHaveFilterData)
    {
      if (Grid.UseRightToLeft)
        btnRect = EhLibUtils.RightToLeftFlipRectangle(Grid.ClientRectangle, btnRect);

      InTitleFilterButtonArgs e = new InTitleFilterButtonArgs(gr, btnRect, btnState, isHaveFilterData, paintBack);
      Grid.GetDrawStyle().DrawInTitleFilterButton(Grid, e);

      //if (drawBack)
      //  ButtonRenderer.DrawButton(gr, btnRect, btnState);
      //DrawFilterButtonSign(gr, btnRect, btnState, isHaveFilterData);
    }

    protected virtual void PaintFilterButtonSign(Graphics gr, Rectangle btnRect, PushButtonState btnState, bool isHaveFilterData)
    {
      Color fromColor, toColor;
      Point startPos;
      Rectangle signRect;

      if (isHaveFilterData)
      {
        Bitmap bmp = Properties.Resources.TitleFilterHave2;

        signRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        signRect = EhLibUtils.RectCenter(signRect, btnRect);

        gr.DrawImage(bmp, signRect);
      }
      else
      {
        signRect = new Rectangle(0, 0, 6, 3);
        signRect = EhLibUtils.RectCenter(signRect, btnRect);

        fromColor = EhLibUtils.ApproximateColor(SystemColors.ControlDarkDark, Color.Black, 30);
        toColor = EhLibUtils.ApproximateColor(SystemColors.ControlDarkDark, Color.White, 00);
        startPos = new Point((signRect.Right + signRect.Left - 7) / 2 + 1,
                             (signRect.Top + signRect.Bottom - 2) / 2);

        EhLibUtils.FillGradient(gr, startPos, new[]
          { new Point(0, 0), new Point(7, 0),
           new Point(1, 1), new Point(6, 1),
           new Point(2, 2), new Point(5, 2),
           new Point(3, 3), new Point(4, 3)
          },
          fromColor, toColor);
      }
    }

    protected internal virtual void DrawTextVertically(Graphics graphics, Rectangle paintRect, BasePaintCellStates state,
      int dataColIndex, int dataRowIndex)
    {

      StringAlignment align = StringAlignment.Center;
      Font font;
      Color foreColor;
      //bool endEllipsis;
      DataGridColumn column = Grid.VisibleColumns[dataColIndex];

      if (column != null)
      {
        switch (column.Title.HorzAlign)
        {
          case HorizontalAlignment.Left:
            {
              align = StringAlignment.Near;
              break;
            }
          case HorizontalAlignment.Center:
            {
              align = StringAlignment.Center;
              break;
            }
          case HorizontalAlignment.Right:
            {
              align = StringAlignment.Far;
              break;
            }
        }

        font = column.Title.Font;
        foreColor = column.Title.ForeColor;
        //endEllipsis = column.Title.EndEllipsis;
      }
      else
      {
        font = Grid.Title.Font;
        foreColor = Grid.Title.ForeColor;
        //endEllipsis = Grid.Title.EndEllipsis;
      }

      using (
        SolidBrush drawBrush = new SolidBrush(foreColor)
      )
      {
        string text = GetDisplayText(dataColIndex, dataRowIndex);

        RectangleF rectf = paintRect;

        StringFormat drawFormat = new StringFormat
        {
          Trimming = StringTrimming.None,
          FormatFlags = StringFormatFlags.DirectionVertical |
                        StringFormatFlags.NoWrap,
          LineAlignment = align
        };
        //        drawFormat.Alignment = StringAlignment.Center;

        graphics.DrawString(text, font, drawBrush, rectf, drawFormat);
      }
    }

    //MouseDown
    protected internal override void ProcessMouseDown(BaseGridCellMouseEventArgs e)
    {
      DataGridTitleCellMouseEventArgs titleEventArgs;
      DataGridSuperTitleCellMouseEventArgs supertitleEventArgs;

      GetTitleCellEvtArgsFromCellMouseEventArgs(e, out titleEventArgs, out supertitleEventArgs);
      if (titleEventArgs != null)
        ProcessMouseDown(titleEventArgs);
      else if (supertitleEventArgs != null)
        supertitleEventArgs.SuperTitle.ProcessMouseDown(supertitleEventArgs);
    }

    protected virtual void ProcessMouseDown(DataGridTitleCellMouseEventArgs e)
    {
      HandleMouseDownEvent(e);
      if (e.Handled) return;
      OnMouseDown(e);
    }

    protected virtual void HandleMouseDownEvent(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.HandleMouseDownEvent(e);
      if (!e.Handled && e.Column != null)
        e.Column.Title.HandleMouseDownEvent(e);
    }

    protected virtual void OnMouseDown(DataGridTitleCellMouseEventArgs e)
    {
      if (Grid.VisibleColumns.Count == 0) return;

      DataGridColumn column = Grid.VisibleColumns[e.BaseEventArgs.AreaColIndex];

      if (e.BaseEventArgs.GridMouseArgs.Button == MouseButtons.Left)
      {
        if (filterButtonHotIndex == e.BaseEventArgs.AreaColIndex)
        {
          //filterButtonPressedState = true;
          filterButtonDownTitleIndex = e.BaseEventArgs.AreaColIndex;
          Grid.InvalidateGrid();

          Rectangle screenFilterBtnRect = e.Column.Title.FilterButtonMetrics.ButtonRect;
          screenFilterBtnRect.X = screenFilterBtnRect.X + e.CellRect.X;
          screenFilterBtnRect.Y = screenFilterBtnRect.Y + e.CellRect.Y;
          screenFilterBtnRect.Location = Grid.PointToScreen(screenFilterBtnRect.Location);

          Grid.Title.Filter.ShowFilterDropDownForm(column, e.BaseEventArgs.CellRect, screenFilterBtnRect);
        }
        else if (Grid.Cursor == Grid.GetDrawStyle().DownArrowSelectCursor())
        {
          bool isAddSelection = ((Control.ModifierKeys & Keys.Control) != 0);
          Grid.StartColumnSelection(column, isAddSelection);
        }
        else if (column.Title.Sortable)
        {
          pressedColumTitleIndex = e.BaseEventArgs.AreaColIndex;
          Grid.InvalidateGrid();
        }
        else if (Grid.ColumnOptions.AllowMoveColumns)
        {
          CheckStartColMoving(e.BaseEventArgs);
        }
      }
    }

    //MouseMove
    protected internal override void ProcessMouseMove(BaseGridCellMouseEventArgs e)
    {
      //DataGridTitleCellMouseEventArgs te = GetTitleCellEvtArgsFromCellMouseEventArgs(e);
      DataGridTitleCellMouseEventArgs te;
      DataGridSuperTitleCellMouseEventArgs ste;

      GetTitleCellEvtArgsFromCellMouseEventArgs(e, out te, out ste);

      //if (Grid.Title.MultiTitle.Active == true)
      {
        object newMouseHolderTitleItem;

        if (ste != null)
          newMouseHolderTitleItem = ste.SuperTitle;
        else
          newMouseHolderTitleItem = te.ColumnTitle;

        if (Grid.Title.MouseHolderTitleItem != newMouseHolderTitleItem)
        {
          if (Grid.Title.MouseHolderTitleItem != null)
          {
            if (Grid.Title.MouseHolderTitleItem is DataGridColumnTitle)
            {
              DataGridColumnTitle colTitle = (DataGridColumnTitle)Grid.Title.MouseHolderTitleItem;
              var ce = CreateCellEventArgs(null, colTitle.Column, colTitle, null);
              ProcessMouseLeave(ce);
            }
            else
            {
              DataGridSuperTitle superTitle = (DataGridSuperTitle)Grid.Title.MouseHolderTitleItem;
              var be = new BaseGridCellEventArgs(e.ColIndex, e.RowIndex, e.AreaColIndex, e.AreaRowIndex, e.CellRect);
              var ce = Grid.Title.MultiTitle.CreateCellEventArgs(be, superTitle);
              superTitle.ProcessMouseLeave(ce);
              //var ce = CreateCellEventArgs(null, te.Column, null, superTitle);
              //superTitle.ProcessMouseLeave(ce);
            }
          }

          Grid.Title.MouseHolderTitleItem = newMouseHolderTitleItem;

          if (newMouseHolderTitleItem != null)
          {
            if (newMouseHolderTitleItem is DataGridColumnTitle)
            {
              BaseGridCellEventArgs baseEventArgs = new BaseGridCellEventArgs(te.BaseEventArgs.ColIndex,
                te.BaseEventArgs.RowIndex, te.BaseEventArgs.AreaColIndex, te.BaseEventArgs.AreaRowIndex,
                te.BaseEventArgs.CellRect);
              var ce = CreateCellEventArgs(baseEventArgs, te.Column, (DataGridColumnTitle)newMouseHolderTitleItem, null);
              ProcessMouseEnter(ce);
            }
            else
            {
              DataGridSuperTitle superTitle = (DataGridSuperTitle)newMouseHolderTitleItem;
              var be = new BaseGridCellEventArgs(e.ColIndex, e.RowIndex, e.AreaColIndex, e.AreaRowIndex, e.CellRect);
              var ce = Grid.Title.MultiTitle.CreateCellEventArgs(be, superTitle);
              superTitle.ProcessMouseEnter(ce);
              //var ce = CreateCellEventArgs(null, te.Column, null, superTitle);
              //superTitle.ProcessMouseEnter(ce);
            }
          }
        }
      }

      if (te != null)
        ProcessMouseMove(te);
      else if (ste != null)
        ste.SuperTitle.ProcessMouseMove(ste);
    }

    protected virtual void HandleMouseMoveEvent(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.HandleMouseMoveEvent(e);
      if (!e.Handled && e.Column != null)
        e.Column.Title.HandleMouseMoveEvent(e);
    }

    protected virtual void ProcessMouseMove(DataGridTitleCellMouseEventArgs e)
    {
      HandleMouseMoveEvent(e);
      if (e.Handled) return;
      OnMouseMove(e);
    }

    protected virtual void OnMouseMove(DataGridTitleCellMouseEventArgs e)
    {
      if (e.Column == null) return;

      if (Grid.ColumnOptions.AllowMoveColumns &&
          (pressedColumTitleIndex == e.BaseEventArgs.AreaColIndex) &&
          (e.BaseEventArgs.GridMouseArgs.Location != Grid.MouseDownPos) &&
          Grid.GridState == BaseGridState.Normal)
      {
        pressedColumTitleIndex = -1;
        Grid.InvalidateGrid();

        CheckStartColMoving(e.BaseEventArgs);
      }

      if (!e.Column.Title.Filter.IsShown)
      {
        filterButtonHotIndex = -1;
      }
      else if (e.Column.Title.FilterButtonMetrics.ButtonRect.Contains(e.InCellX, e.InCellY) &&
          (filterButtonHotIndex != e.BaseEventArgs.AreaColIndex)
         )
      {
        filterButtonHotIndex = e.BaseEventArgs.AreaColIndex;
        Grid.InvalidateGrid();
      }
      else if (!e.Column.Title.FilterButtonMetrics.ButtonRect.Contains(e.InCellX, e.InCellY) &&
               (filterButtonHotIndex == e.BaseEventArgs.AreaColIndex)
              )
      {
        filterButtonHotIndex = -1;
        Grid.InvalidateGrid();
      }
    }

    //MouseUp
    protected internal override void ProcessMouseUp(BaseGridCellMouseEventArgs e)
    {
      //DataGridTitleCellMouseEventArgs ta = GetTitleCellEvtArgsFromCellMouseEventArgs(e);
      DataGridTitleCellMouseEventArgs te;
      DataGridSuperTitleCellMouseEventArgs ste;

      GetTitleCellEvtArgsFromCellMouseEventArgs(e, out te, out ste);

      if (te != null)
        ProcessMouseUp(te);
      else if (ste != null)
        ste.SuperTitle.ProcessMouseUp(ste);
    }

    protected virtual void HandleMouseUpEvent(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.HandleMouseUpEvent(e);
      if (!e.Handled && e.Column != null)
        e.Column.Title.HandleMouseUpEvent(e);
    }

    protected virtual void ProcessMouseUp(DataGridTitleCellMouseEventArgs e)
    {
      HandleMouseUpEvent(e);
      if (e.Handled) return;
      OnMouseUp(e);
    }

    protected virtual void OnMouseUp(DataGridTitleCellMouseEventArgs e)
    {
      if (pressedColumTitleIndex >= 0)
      {
        pressedColumTitleIndex = -1;
        Grid.InvalidateGrid();
        Grid.AddChangeSortMarking(e.Column);
      }
      else if (filterButtonDownTitleIndex >= 0)
      {
        //filterButtonPressedState = false;
        filterButtonDownTitleIndex = -1;
        Grid.InvalidateGrid();
      }
    }

    //MouseClick
    protected internal override void ProcessMouseClick(BaseGridCellMouseEventArgs e)
    {
      //DataGridTitleCellMouseEventArgs ta = GetTitleCellEvtArgsFromCellMouseEventArgs(e);
      DataGridTitleCellMouseEventArgs te;
      DataGridSuperTitleCellMouseEventArgs ste;

      GetTitleCellEvtArgsFromCellMouseEventArgs(e, out te, out ste);

      if (te != null)
        ProcessMouseClick(te);
      else if (ste != null)
        ste.SuperTitle.ProcessMouseClick(ste);
    }

    protected virtual void HandleMouseClickEvent(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.HandleMouseClickEvent(e);
      if (!e.Handled && e.Column != null)
        e.Column.Title.HandleMouseClickEvent(e);
    }

    protected virtual void ProcessMouseClick(DataGridTitleCellMouseEventArgs e)
    {
      HandleMouseClickEvent(e);
      if (e.Handled) return;
      OnMouseClick(e);
    }

    protected virtual void OnMouseClick(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.OnCellMouseClick(e);
    }

    //MouseDoubleClick
    protected internal override void ProcessMouseDoubleClick(BaseGridCellMouseEventArgs e)
    {
      //DataGridTitleCellMouseEventArgs ta = GetTitleCellEvtArgsFromCellMouseEventArgs(e);

      DataGridTitleCellMouseEventArgs te;
      DataGridSuperTitleCellMouseEventArgs ste;

      GetTitleCellEvtArgsFromCellMouseEventArgs(e, out te, out ste);

      if (te != null)
        ProcessMouseDoubleClick(te);
      else if (ste != null)
        ste.SuperTitle.ProcessMouseDoubleClick(ste);
    }

    protected virtual void HandleMouseDoubleClickEvent(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.HandleMouseDoubleClickEvent(e);
      if (!e.Handled && e.Column != null)
        e.Column.Title.HandleMouseDoubleClickEvent(e);
    }

    protected virtual void ProcessMouseDoubleClick(DataGridTitleCellMouseEventArgs e)
    {
      HandleMouseClickEvent(e);
      if (e.Handled) return;
      OnMouseDoubleClick(e);
    }

    protected virtual void OnMouseDoubleClick(DataGridTitleCellMouseEventArgs e)
    {
    }

    //MouseEnter
    protected internal override void OnMouseEnter(BaseGridCellEnterEventArgs e)
    {
      base.OnMouseEnter(e);

      if (Grid.VisibleColumns.Count > 0)
      {
        DataGridColumn column = Grid.VisibleColumns[e.AreaColIndex];
        column.Grid.Title.MouseInTitleRow = true;
        column.Grid.Invalidate();
      }
    }

    protected virtual void ProcessMouseEnter(DataGridTitleCellEventArgs e)
    {
      HandleMouseEnterEvent(e);
      OnMouseEnter(e);
    }

    private void HandleMouseEnterEvent(DataGridTitleCellEventArgs e)
    {
      Grid.Title.HandleMouseEnterEvent(e);
      if (e.Column != null)
        e.Column.Title.HandleMouseEnterEvent(e);
    }

    private void OnMouseEnter(DataGridTitleCellEventArgs e)
    {
      Grid.Title.Invalidate();

      string cellText = GetCellNonfitToolTipText(e);

      if (!string.IsNullOrEmpty(cellText))
      {
        Grid.ShowCellNonFitToolTip(cellText, e.BaseEventArgs);
      }

      if (!string.IsNullOrEmpty(e.ColumnTitle.ToolTipText))
      {
        Grid.ShowCellHintTooltip(e.ColumnTitle.ToolTipText, -1);
      }
    }

    //MouseLeave
    protected internal override void OnMouseLeave(BaseGridCellLeaveEventArgs e)
    {
      base.OnMouseLeave(e);

      if (Grid.VisibleColumns.Count == 0) return;
      DataGridColumn column = Grid.VisibleColumns[e.AreaColIndex];

      filterButtonHotIndex = -1;
      column.Grid.Title.MouseInTitleRow = false;
      column.Grid.Invalidate();

      if (Grid.Title.MouseHolderTitleItem != null)
      {
        if (Grid.Title.MouseHolderTitleItem is DataGridColumnTitle)
        {
          var te = (DataGridColumnTitle)Grid.Title.MouseHolderTitleItem;
          var ce = CreateCellEventArgs(null, te.Column, te, null);
          ProcessMouseLeave(ce);
        }
        else
        {
          DataGridSuperTitle superTitle = (DataGridSuperTitle)Grid.Title.MouseHolderTitleItem;
          var ce = Grid.Title.MultiTitle.CreateCellEventArgs(null, superTitle);
          superTitle.ProcessMouseLeave(ce);
        }
        Grid.Title.MouseHolderTitleItem = null;
      }
    }

    protected virtual void ProcessMouseLeave(DataGridTitleCellEventArgs e)
    {
      HandleMouseLeaveEvent(e);
      OnMouseLeave(e);
    }

    protected virtual void HandleMouseLeaveEvent(DataGridTitleCellEventArgs e)
    {
      Grid.Title.HandleMouseLeaveEvent(e);
      if (e.Column != null)
        e.Column.Title.HandleMouseLeaveEvent(e);
    }

    protected virtual void OnMouseLeave(DataGridTitleCellEventArgs e)
    {
      Grid.Title.Invalidate();
      Grid.HideCellNonFitToolTip();
      Grid.HideCellHintToolTip();
    }

    //MouseHover
    protected internal override void ProcessMouseHover(BaseGridCellMouseEventArgs e)
    {
      DataGridTitleCellMouseEventArgs te;
      DataGridSuperTitleCellMouseEventArgs ste;

      GetTitleCellEvtArgsFromCellMouseEventArgs(e, out te, out ste);

      if (te != null)
        ProcessMouseHover(te);
      else if (ste != null)
        ste.SuperTitle.ProcessMouseHover(ste);
    }

    protected virtual void HandleMouseHoverEvent(DataGridTitleCellMouseEventArgs e)
    {
      Grid.Title.HandleMouseHoverEvent(e);
      if (!e.Handled && e.Column != null)
        e.Column.Title.HandleMouseHoverEvent(e);
    }

    protected virtual void ProcessMouseHover(DataGridTitleCellMouseEventArgs e)
    {
      HandleMouseHoverEvent(e);
      if (e.Handled) return;
      OnMouseHover(e);
    }

    protected virtual void OnMouseHover(DataGridTitleCellMouseEventArgs e)
    {
    }

    //CustomAreaMeasures
    //protected internal virtual DataGridTitleCellCustomAreaMeasuresNeededEventArgs CreateCellCustomAreaMeasuresEventArgs(
    //  CellCustomAreaMeasures areaMeasures, DataGridColumnTitle columnTitle)
    //{
    //  return new DataGridTitleCellCustomAreaMeasuresNeededEventArgs(areaMeasures, columnTitle);
    //}

    //protected internal virtual void OnCellCustomAreaMeasuresNeeded(DataGridTitleCellCustomAreaMeasuresNeededEventArgs e)
    //{
    //  Grid.Title.HandleCellCustomAreaMeasuresNeededEvent(e);
    //  if (e.ColumnTitle.Column != null)
    //    e.ColumnTitle.Column.Title.HandleCellCustomAreaMeasuresNeededEvent(e);
    //}

    //protected internal virtual void SetCellCustomAreaMeasures(CellCustomAreaMeasures areaMeasures, DataGridColumnTitle columnTitle)
    //{
    //  var e = CreateCellCustomAreaMeasuresEventArgs(areaMeasures, columnTitle);
    //  OnCellCustomAreaMeasuresNeeded(e);
    //}

    //ContextMenuStripNeeded
    protected internal override BaseGridCellContextMenuStripNeededEventArgs CreateCellContextMenuStripNeededEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, int mousePosX, int mousePosY)
    {
      DataGridTitleCellContextMenuStripNeededEventArgs titleEventArgs = null;
      DataGridSuperTitleCellContextMenuStripNeededEventArgs superTitleEventArgs = null;

      if (Grid.Title.MultiTitle.Active == true)
      {
        DataGridColumnTitle title;
        DataGridSuperTitle superTitle;
        Point inCellPos;
        Rectangle mtItemCellRect;

        GetMultiTitleObjectsByPos(new Point(mousePosX, mousePosY), out title, out superTitle, out inCellPos, out mtItemCellRect);

        if (superTitle != null)
        {
          superTitleEventArgs = new DataGridSuperTitleCellContextMenuStripNeededEventArgs(
            inCellX, inCellY, mtItemCellRect, mousePosX, mousePosY, superTitle);
        }
        else
        {
          titleEventArgs = new DataGridTitleCellContextMenuStripNeededEventArgs(
            this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellPos.X, inCellPos.Y, mtItemCellRect, mousePosX, mousePosY, title.Column);
        }
      }
      else
      {
        DataGridColumn column = Grid.VisibleColumns[areaColIndex];
        titleEventArgs = new DataGridTitleCellContextMenuStripNeededEventArgs(
          this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, mousePosX, mousePosY, column);
      }

      return new DataGridMultiTitleCellContextMenuStripNeededProvideEventArgs(
        this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, mousePosX, mousePosY, 
        titleEventArgs, superTitleEventArgs);
    }

    protected internal override void OnContextMenuStripNeeded(BaseGridCellContextMenuStripNeededEventArgs e)
    {
      var ea = e as DataGridMultiTitleCellContextMenuStripNeededProvideEventArgs;

      if (ea.SuperTitleEventArgs != null)
      {
        OnSuperTitleContextMenuStripNeeded(ea.SuperTitleEventArgs);
        e.ContextMenuStrip = ea.SuperTitleEventArgs.ContextMenuStrip;
      }
      else
      {
        Grid.Title.OnCellMouseContextMenuStripNeeded(ea.TitleEventArgs);
        e.ContextMenuStrip = ea.TitleEventArgs.ContextMenuStrip;
      }
    }

    protected internal virtual void OnSuperTitleContextMenuStripNeeded(DataGridSuperTitleCellContextMenuStripNeededEventArgs e)
    {
      e.ContextMenuStrip = e.SuperTitle.GetMouseContextMenuStrip(e);
    }

    protected internal virtual void OnTitleContextMenuStripNeeded(DataGridTitleCellContextMenuStripNeededEventArgs e)
    {
      Grid.Title.OnCellMouseContextMenuStripNeeded(e);
    }

    protected internal override void HandleMouseContextMenuStripNeededEvent(BaseGridCellContextMenuStripNeededEventArgs e)
    {
      var ea = e as DataGridMultiTitleCellContextMenuStripNeededProvideEventArgs;

      if (ea.SuperTitleEventArgs != null)
      {
        //Grid.Title.MultiTitle.HandleMouseContextMenuStripNeededEvent(ea.SuperTitleEventArgs);
        ea.SuperTitleEventArgs.SuperTitle.HandleMouseContextMenuStripNeededEvent(ea.SuperTitleEventArgs);
        e.ContextMenuStrip = ea.SuperTitleEventArgs.ContextMenuStrip;
        e.Handled = ea.SuperTitleEventArgs.Handled;
      }
      else
      {
        Grid.Title.HandleCellMouseContextMenuStripNeededEvent(ea.TitleEventArgs);
        ea.TitleEventArgs.Column.Title.HandleCellMouseContextMenuStripNeededEvent(ea.TitleEventArgs);
        e.ContextMenuStrip = ea.TitleEventArgs.ContextMenuStrip;
        e.Handled = ea.TitleEventArgs.Handled;
      }
    }

    //Other

    protected internal void GetTitleCellEvtArgsFromCellMouseEventArgs(BaseGridCellMouseEventArgs e, 
      out DataGridTitleCellMouseEventArgs titleEventArgs, out DataGridSuperTitleCellMouseEventArgs supertitleEventArgs)
    {
      DataGridColumnTitle title = null;
      DataGridSuperTitle superTitle;
      DataGridColumn column = null;
      Point inCellPos;
      Rectangle cellRect;

      if (Grid.VisibleColumns.Count > 0)
        column = Grid.VisibleColumns[e.AreaColIndex];

      if (Grid.Title.MultiTitle.Active == true)
      {
        GetMultiTitleObjectsByPos(e.GridMouseArgs.Location, out title, out superTitle, out inCellPos, out cellRect);
      }
      else
      {
        if (column != null)
          title = column.Title;
        superTitle = null;
        inCellPos = new Point(e.InCellX, e.InCellY);
        cellRect = e.CellRect;
      }

      if (superTitle != null)
      {
        titleEventArgs = null;
        supertitleEventArgs = new DataGridSuperTitleCellMouseEventArgs(e, superTitle, inCellPos.X, inCellPos.Y, cellRect);
      }
      else
      {
        titleEventArgs = new DataGridTitleCellMouseEventArgs(e, column, title, inCellPos.X, inCellPos.Y, cellRect);
        supertitleEventArgs = null;
      }
    }

    protected internal virtual DataGridTitleCellEventArgs CreateCellEventArgs(
      BaseGridCellEventArgs baseEventArgs, DataGridColumn column, DataGridColumnTitle columnTitle, DataGridSuperTitle superTitle)
    {
      return new DataGridTitleCellEventArgs(baseEventArgs, column, columnTitle, superTitle);
    }

    public override void AreaCellPosToGridCellPos(int areaColIndex, int areaRowIndex, out int gridColIndex, out int gridRowIndex)
    {
      gridColIndex = areaColIndex + Grid.FixedColCount;
      gridRowIndex = areaRowIndex;
    }

    protected internal override void OnGetCellBorderParams(BaseGridCellBorderEventArgs e)
    {
      //style = DashStyle.Solid;
      GridLine gl;

      if (e.BorderType == GridCellBorderType.Top || e.BorderType == GridCellBorderType.Bottom)
      {
        gl = Grid.Title.HorzLine;
      }
      else
      {
        if (e.ColIndex == -1 || Grid.VisibleColumns.Count == 0)
          gl = Grid.Title.VertLine;
        else
          gl = Grid.VisibleColumns[e.AreaColIndex].Title.VertLine;
      }

      if ((e.BorderType == GridCellBorderType.Left) || (e.BorderType == GridCellBorderType.Right))
      {
        if (Grid.Title.MultiTitle.Active)
          e.Visible = false;
        else
          e.Visible = gl.Visible;
        e.IsExtent = true;
      }
      else
      {
        e.Visible = gl.Visible;
        e.IsExtent = true;
      }

      e.Color = gl.Color;
      e.Style = gl.Style;
    }

    public override string GetDisplayText(DataGridColumn column, int dataRowIndex)
    {
      return column.Title.Text;
    }

    private void GetMultiTitleObjectsByPos(Point pos, out DataGridColumnTitle title, 
      out DataGridSuperTitle superTitle, out Point inCellPos, out Rectangle cellRect)
    {
      title = null;
      superTitle = null;

      inCellPos = new Point(-1, -1);
      cellRect = new Rectangle(-1, -1, -1, -1);

      if (Grid.Title.MultiTitle.Active == true)
      {
        DataGridTitleNode tn = Grid.Title.MultiTitle.GetNodeAtGridAtPos(pos, out inCellPos, out cellRect);
        if (tn == null) return;

        //Debug.Assert(tn != null, "tn != null");

        if (tn.NodeType == DataGridTitleNodeType.SuperTitle)
          superTitle = tn.SuperTitle;
        else
          title = tn.ColumnTitle;
      }
    }

    public virtual DataGridTitleNode GetMultiTitleNodeAtPos(Point pos)
    {
      Point inCellPos;
      Rectangle cellRect;

      return Grid.Title.MultiTitle.GetNodeAtGridAtPos(pos, out inCellPos, out cellRect);
    }

    public override void GridCellPosToAreaCellPos(int gridColIndex, int gridRowIndex, out int areaColIndex, out int areaRowIndex)
    {
      areaColIndex = gridColIndex - Grid.StartDataColIndex;
      areaRowIndex = gridRowIndex;
    }

    protected internal virtual bool CanDrawWordBreak(DataGridTextWrapMode wrapMode, Graphics graphics,
      Rectangle paintRect, Font font)
    {
      if (wrapMode == DataGridTextWrapMode.Auto)
      {
        Size sz = TextRenderer.MeasureText(EhLibUtils.DisplayGraphicsCash, "0", font);
        int th = paintRect.Height; // - padding.Top - padding.Bottom;

        if (th >= sz.Height * 2)
          return true;
        else
          return false;
      }
      else if (wrapMode == DataGridTextWrapMode.WordWrap)
        return true;
      else
        return false;
    }

    protected internal virtual bool CheckStartColMoving(BaseGridCellMouseEventArgs e)
    {
      int moveFromIndex = e.ColIndex;
      int moveToIndex;

      if (e.InCellX < e.CellRect.Width / 2)
        moveToIndex = e.ColIndex;
      else
        moveToIndex = e.ColIndex + 1;

      bool result = Grid.CheckBeginColumnDrag(ref moveFromIndex, ref moveToIndex, new Point(e.GridMouseArgs.X, e.GridMouseArgs.Y));
      if (result)
        Grid.StartColMoving(moveFromIndex, moveToIndex, e.GridMouseArgs.X, e.GridMouseArgs.Y);
      return result;
    }

    protected internal override void PrintCell(PrintServiceEventArgs e,
      Rectangle paintRect, int areaColIndex,
      int areaRowIndex,
      PrintServiceEventArgs printContext
        )
    {
      Rectangle textRect;
      DataGridColumn column = Grid.VisibleColumns[areaColIndex];

      Font drawFont = column.Title.Font;

      if (column.Title.TextOrientation == Orientation.Vertical)
      {
        DrawTextVertically(e.Graphics, paintRect, 0, areaColIndex, areaRowIndex);
      }
      else
      {
        TextFormatFlagsEh flags = 0;
        string text = GetDisplayText(areaColIndex, areaRowIndex);
        textRect = EhLibUtils.TrimPadding(paintRect, column.Title.Padding);
        if (CanDrawWordBreak(Grid.Title.WrapMode, e.Graphics, textRect, drawFont))
          flags = flags | TextFormatFlagsEh.WordBreak;

        e.PrintText(text, drawFont, textRect, Color.Black, column.Title.HorzAlign, column.Title.VertAlign, flags);
      }
    }

    protected internal override bool IsSelected(int areaColIndex, int areaRowIndex)
    {
      if (Grid.Selection.SelectionType == GridSelectionType.Columns)
        return Grid.VisibleColumns[areaColIndex].Selected;
      else if (Grid.Selection.SelectionType == GridSelectionType.All)
        return true;
      else
        return false;
    }
    
    protected internal override void OnMouseCaptureCanceled()
    {
      if (pressedColumTitleIndex >= 0 || filterButtonDownTitleIndex >= 0)
      {
        pressedColumTitleIndex = -1;
        filterButtonDownTitleIndex = -1;
        //filterButtonDown = false;
        Grid.InvalidateGrid();
      }
    }

    protected internal override void SetCursor(BaseGridCellMouseEventArgs de, ref Cursor cursor)
    {

      DataGridTitleCellMouseEventArgs te;
      DataGridSuperTitleCellMouseEventArgs ste;

      GetTitleCellEvtArgsFromCellMouseEventArgs(de, out te, out ste);

      if (te != null)
      {
        SetCursor(te, ref cursor);
        var ce = new BaseGridCellQueryCursorEventArgs(
          this, de.ColIndex, de.RowIndex, de.AreaColIndex, de.AreaRowIndex, te.InCellX, te.InCellY, te.CellRect, de.GridMouseArgs);
        ce.Cursor = cursor;
        HandleQueryCursorEvent(ce);
        cursor = ce.Cursor;
      }
      else if (ste != null)
      {
        ste.SuperTitle.SetCursor(ste, ref cursor);
      }
    }

    protected internal virtual void SetCursor(DataGridTitleCellMouseEventArgs de, ref Cursor cursor)
    {
      if (Grid.Selection.ColumnsSelectionIsAllowed &&
          (Grid.GridState == BaseGridState.Normal))
      {
        if (de.InCellX == 0) return;

        Rectangle selRect = de.CellRect;
        float tg = selRect.Height / (float)selRect.Width * 2;
        int a1 = (int)(tg * de.InCellX);
        if (a1 < de.InCellY)
          cursor = Grid.GetDrawStyle().DownArrowSelectCursor();
      }
    }

    protected internal override void HandleQueryCursorEvent(BaseGridCellQueryCursorEventArgs e)
    {
      DataGridColumn column;
      if (e.AreaColIndex >= 0 && Grid.VisibleColumns.Count > 0)
        column = Grid.VisibleColumns[e.AreaColIndex];
      else
        column = null;

      if (column != null)
        column.Title.HandleQueryCursorEvent(e);
    }

    private bool IsHot(int dataColIndex, int dataRowIndex)
    {
      if (dataColIndex < 0 || Grid.VisibleColumns.Count == 0) return false;

      DataGridColumn column = Grid.VisibleColumns[dataColIndex];

      int gridColIndex; int gridRowIndex;
      AreaCellPosToGridCellPos(dataColIndex, dataRowIndex, out gridColIndex, out gridRowIndex);
      if ((column.Grid.MouseHolderCellCoord.X == gridColIndex) &&
          (column.Grid.MouseHolderCellCoord.Y == gridRowIndex) &&
          column.Title.CanBePressed() &&
          !(pressedColumTitleIndex >= 0))
        return true;
      else
        return false;
    }

    protected internal virtual void PerformLayout(DataGridColumnTitle colTitle)
    {
      //UpdateCellFilterBtnRect(colTitle);
    }

    public virtual string GetCellNonfitToolTipText(DataGridTitleCellEventArgs e)
    {
      if (!Grid.Title.NonfitTooltips) return "";

      Size sf;
      Graphics g = EhLibUtils.DisplayGraphicsCash;
      string cellText = GetDisplayText(e.BaseEventArgs.AreaColIndex, e.BaseEventArgs.AreaRowIndex);
      Rectangle textRect = e.BaseEventArgs.CellRect;

      textRect = EhLibUtils.TrimPadding(textRect, e.ColumnTitle.Padding);

      bool wordWrap = CanDrawWordBreak(Grid.Title.WrapMode, g, textRect, e.ColumnTitle.Font);
      DataGridTextWrapMode wrapMode;
      if (wordWrap)
        wrapMode = DataGridTextWrapMode.WordWrap;
      else
        wrapMode = DataGridTextWrapMode.NoWrap;

      sf = EhLibUtils.MeasureText(g, cellText, Grid.Font, textRect.Size, wrapMode);

      if (sf.Width > textRect.Width)
        return cellText;
      else
        return "";
    }

    protected internal virtual Rectangle GetCellClientRect(DataGridColumnTitle columnTitle, Rectangle cellRect)
    {
      var e = new DataGridTitleCellClientAreaNeededEventArgs(columnTitle, cellRect);

      ProcessClientRectNeeded(e);
      return e.CellClientRect;
    }

    protected internal virtual Rectangle GetCellMainContentRect(DataGridColumnTitle columnTitle, Rectangle cellRect)
    {
      Rectangle clientRect = GetCellClientRect(columnTitle, cellRect);

      if (columnTitle.ImageBox.Visible)
      {
        Rectangle textRect;

        TextLayoutParams tlp = new TextLayoutParams()
        {
          Text = columnTitle.Text,
          Font = columnTitle.Font,
          HorzAlign = columnTitle.HorzAlign,
          VertAlign = columnTitle.VertAlign,
          WrapMode = Grid.Title.WrapMode
        };

        textRect = columnTitle.ImageBox.CalcTextRect(clientRect, tlp);
        return textRect;
      }
      else
      {
        return clientRect;
      }
    }

    private void ProcessClientRectNeeded(DataGridTitleCellClientAreaNeededEventArgs e)
    {
      Grid.Title.HandleClientRectNeededEvent(e);
      if (e.ColumnTitle != null)
        e.ColumnTitle.HandleClientRectNeededEvent(e);
    }
    #endregion

  }

}