//------------------------------------------------------------------------------
// <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.Security.Permissions;
using System.Drawing.Drawing2D;
using System.Windows.Forms.VisualStyles;
using System.Diagnostics;

namespace EhLib
{

  public enum BaseGridState
  {
    Normal,
    Selecting,
    RowSizing,
    ColSizing,
    RowMoving,
    ColMoving
  }

  /// <summary>
  ///    Specifies the size of the step that is used when 
  ///    scrolling data in the grid.
  /// </summary>
  public enum BaseGridScrollStepMode
  {
    ByPixel,
    ByCell
  }

  public enum ScrollBarVisibleMode
  {
    AlwaysShow,
    NeverShow,
    AutoShow
  }

  public enum CornerPaintPriority
  {
    HorizontalDataPriority,
    VerticalDataPriority
  }

  public enum GridCellBorderType
  {
    Top,
    Left,
    Bottom,
    Right
  }

  [Flags]
  public enum GridOptions
  {
    FixedVertLines = 1,
    FixedHorzLines = 2,
    VertLines = 4,
    HorzLines = 8,
    DrawFocusSelected = 16,
    RowSizing = 32,
    ColSizing = 64,
    RowMoving = 128,
    ColMoving = 256,
    Editing = 512,
    Tabs = 1024,
    RowSelect = 2048,
    AlwaysShowEditor = 4096,
    ThumbTracking = 8192,
    ExtendVertLines = 16384,
    ContraVertBoundaryLine = 32768,
    ContraHorzBoundaryLine = 65536,
    RangeSelect = 131072
  }

  [Flags]
  public enum BasePaintCellStates
  {
    Selected = 1,
    Focused = 2,
    Current = 4,
    Fixed = 8,
    RowSelected = 16,
    HotTrack = 32,
    Pressed = 64,
    CurrentCol = 128,
    CurrentRow = 256,
    ColHotTrack = 512,
    RowHotTrack = 1024
  }

  public enum InteractiveActionSource
  {
    Mouse,
    Keyboard,
    Other
  }

  /// <summary>
  ///    Specifies the fill style of the cell background in the grid.
  ///    Usually for cells in fixed area of the grid.
  /// </summary>
  public enum CellFillStyle
  {
    Solid,
    VertGradient,
    VisualStyles
  }

  public enum CellInnerBorderStyle
  {
    None,
    RaisedTopLeft,
    RaisedFull
  }

  public enum GridRowHeightUnit
  {
    TextLine,
    Pixel
  }

  public enum GridMoveCellDirection
  {
    /// <summary>
    ///  Backward - Move cell back to the previous column
    /// </summary>
    Backward,
    /// <summary>
    ///  Forward - Move cell forward to the next column
    /// </summary>
    Forward
  }

  public struct GridCoord
  {
    public int X;
    public int Y;

    public GridCoord(int x, int y)
    {
      X = x;
      Y = y;
    }

    public override bool Equals(object obj)
    {
      if (!(obj is GridCoord)) return false;
      GridCoord comp = (GridCoord)obj;
      return comp.X == X && comp.Y == Y;
    }

    public bool Equals(GridCoord gc)
    {
      return gc.X == X && gc.Y == Y;
    }

    public override int GetHashCode()
    {
      return base.GetHashCode();// return X ^ Y;
    }

    public static bool operator ==(GridCoord left, GridCoord right)
    {
      return left.X == right.X && left.Y == right.Y;
    }

    public static bool operator !=(GridCoord left, GridCoord right)
    {
      return !(left == right);
    }

    public override string ToString()
    {
      return string.Format("X = {0} Y = {1}", X, Y);
    }
  }

  public struct PointL
  {
    public long X;
    public long Y;
  }

  public struct GridRect
  {
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;

    public GridRect(int left, int top, int right, int bottom)
    {
      Left = left;
      Top = top;
      Right = right;
      Bottom = bottom;
    }

    public GridCoord TopLeft()
    {
      return new GridCoord() { X = Left, Y = Top };
    }
    public GridCoord BottomRight()
    {
      return new GridCoord() { X = Right, Y = Bottom };
    }
  }

  public delegate void MoveAndScrollServiceEventHandler(
    MoveAndScrollService service, MouseEventArgs e);

  public class MoveAndScrollService : IDisposable
  {

    #region Privates
    private MoveAndScrollServiceEventHandler _moveAndScrollEvent;
    private Rectangle _clientRect;
    private readonly Timer timer;
    private MouseEventArgs lastMouseEvArg;
    private bool active;
    private Rectangle screenForClientRect;
    private int toLeftScreenBound;
    private int toRightScreenBound;
    private int toTopScreenBound;
    private int toBottonScreenBound;
    private int ticks;
    private bool _horzOutMove;
    private bool _vertOutMove;
    private bool disposed;
    #endregion Privates

    public MoveAndScrollService()
    {
      timer = new Timer();
      timer.Tick += Timer_Elapsed;
      timer.Interval = 100;
      timer.Enabled = false;
    }

    #region Properties
    public Rectangle ClientRect { get { return _clientRect; } }
    public bool Active { get { return active; } }
    #endregion Properties

    #region Methods
    public void Capture(Control control, Rectangle clientRect,
      MoveAndScrollServiceEventHandler moveAndScrollEvent, bool horzOutMove, bool vertOutMove)
    {
      //Debug.Assert(this.Active == false, "MoveAndScrollHelpService already Active");
      int pointsPerInch = (int)(EhLibUtils.DisplayGraphicsCash.DpiX);

      //control.Capture = true;
      _moveAndScrollEvent = moveAndScrollEvent;
      _clientRect = clientRect;
      active = true;
      screenForClientRect = SystemInformation.VirtualScreen;
      _horzOutMove = horzOutMove;
      _vertOutMove = vertOutMove;

      Rectangle controlClientBounds = control.RectangleToScreen(clientRect);

      if (controlClientBounds.X - pointsPerInch > screenForClientRect.Left)
        toLeftScreenBound = pointsPerInch;
      else
        toLeftScreenBound = controlClientBounds.X;

      if (controlClientBounds.Right + pointsPerInch < screenForClientRect.Right)
        toRightScreenBound = pointsPerInch;
      else
        toRightScreenBound = screenForClientRect.Right - controlClientBounds.Right;

      if (controlClientBounds.Y - pointsPerInch > screenForClientRect.Top)
        toTopScreenBound = pointsPerInch;
      else
        toTopScreenBound = controlClientBounds.Y;

      if (controlClientBounds.Bottom + pointsPerInch < screenForClientRect.Bottom)
        toBottonScreenBound = pointsPerInch;
      else
        toBottonScreenBound = screenForClientRect.Bottom - controlClientBounds.Bottom;

    }

    public void MouseMove(MouseEventArgs e)
    {
      bool outbound = false;
      int newHorzInterval = 200;
      int newVertInterval = 200;
      float dividend;

      if (_horzOutMove && ((e.Location.X > _clientRect.Right) || (e.Location.X < _clientRect.Left)))
      {
        lastMouseEvArg = new MouseEventArgs(e.Button, e.Clicks, e.X, e.Y, e.Delta);
        if (e.Location.X > _clientRect.Right)
        {
          dividend = e.Location.X - _clientRect.Right;
          if (dividend > toRightScreenBound) dividend = toRightScreenBound;
          newHorzInterval = 200 - (int)(dividend / toRightScreenBound * 198);
        }
        else if (e.Location.X < _clientRect.Left)
        {
          dividend = -e.Location.X + _clientRect.Left;
          if (dividend > toLeftScreenBound) dividend = toLeftScreenBound;
          newHorzInterval = 200 - (int)(dividend / toLeftScreenBound * 198);
        }
        else
          newHorzInterval = 200;

        //        if (newHorzInterval <= 0) newHorzInterval = 0;
        outbound = true;
      }

      if (_vertOutMove && ((e.Location.Y > _clientRect.Bottom) || (e.Location.Y < _clientRect.Top)))
      {
        lastMouseEvArg = new MouseEventArgs(e.Button, e.Clicks, e.X, e.Y, e.Delta);
        if (e.Location.Y > _clientRect.Bottom)
        {
          dividend = e.Location.Y - _clientRect.Bottom;
          if (dividend > toBottonScreenBound) dividend = toBottonScreenBound;
          newVertInterval = 200 - (int)(dividend / toBottonScreenBound * 198);
        }
        else if (e.Location.Y < _clientRect.Top)
        {
          dividend = -e.Location.Y + _clientRect.Top;
          if (dividend > toTopScreenBound) dividend = toTopScreenBound;
          newVertInterval = 200 - (int)(dividend / toTopScreenBound * 198);
        }
        else
          newVertInterval = 200;

        outbound = true;
      }

      _moveAndScrollEvent(this, e);

      if (outbound)
      {

        timer.Interval = Math.Min(newHorzInterval, newVertInterval);
        timer.Enabled = true;

        //Debug.WriteLine(timer.Interval.ToString());
        if ((Environment.TickCount - ticks) > timer.Interval)
        {
          //Debug.WriteLine(timer.Interval.ToString() + ':' + (Environment.TickCount - ticks));
          Timer_Elapsed(this, e);
        }
      }
      else
      {
        timer.Enabled = false;
      //  _moveAndScrollEvent(this, e);
        ticks = Environment.TickCount;
      }
    }

    public void Release()
    {
      timer.Enabled = false;
      _moveAndScrollEvent = null;
      _clientRect = Rectangle.Empty;
      active = false;
    }

    void Timer_Elapsed(object myObject, EventArgs myEventArgs)
    {
      if (_moveAndScrollEvent != null)
        _moveAndScrollEvent(this, lastMouseEvArg);
      ticks = Environment.TickCount;
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposed)
        return;
      if (disposing)
        timer.Dispose();
      disposed = true;
    }

    #endregion Methods

  }

  public interface IGridLineHost
  {
    void GridLineChanged(GridLine gl);
    bool GridLineDefaultVisible(GridLine gl);
    Color GridLineDefaultColor(GridLine gl);
    DashStyle GridLineDefaultStyle(GridLine gl);
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridLine
  {
    #region privets
    private readonly IGridLineHost host;
    private bool visible;
    private bool visibleStored;
    private Color color;
    private bool colorStored;
    private DashStyle style;
    private bool styleStored;
    #endregion

    #region constructor
    public GridLine(IGridLineHost host)
    {
      this.host = host;
    }
    #endregion

    #region properties
    public bool Visible
    {
      get
      {
        if (visibleStored)
          return visible;
        else
          return DefaultVisible();
      }

      set
      {
        if (visible != value || !visibleStored)
        {
          visible = value;
          visibleStored = true;
          VisibleChanged();
        }
      }
    }

    public Color Color
    {
      get
      {
        if (colorStored)
          return color;
        else
          return DefaultColor();
      }

      set
      {
        if (color != value || !colorStored)
        {
          color = value;
          colorStored = true;
          OnGridLineChanged();
        }
      }
    }

    public DashStyle Style
    {
      get
      {
        if (styleStored)
          return style;
        else
          return DefaultStyle();
      }

      set
      {
        if (style != value || !styleStored)
        {
          style = value;
          styleStored = true;
          OnGridLineChanged();
        }
      }
    }
    #endregion

    #region methods
    //Visible
    public virtual bool DefaultVisible()
    {
      if (host != null)
        return host.GridLineDefaultVisible(this);
      else
        return false;
    }

    protected virtual void VisibleChanged()
    {
      OnGridLineChanged();
    }

    protected virtual bool ShouldSerializeVisible()
    {
      return (visibleStored == true);
    }

    public virtual void ResetVisible()
    {
      visibleStored = false;
      VisibleChanged();
    }

    //Color
    public virtual Color DefaultColor()
    {
      if (host != null)
        return host.GridLineDefaultColor(this);
      else
        return Color.Empty;
    }

    protected virtual void ColorChanged()
    {
      OnGridLineChanged();
    }

    protected virtual bool ShouldSerializeColor()
    {
      return (colorStored == true);
    }

    public virtual void ResetColor()
    {
      colorStored = false;
      ColorChanged();
    }

    //Style
    public virtual DashStyle DefaultStyle()
    {
      if (host != null)
        return host.GridLineDefaultStyle(this);
      else
        return DashStyle.Solid;
    }

    protected virtual void StyleChanged()
    {
      OnGridLineChanged();
    }

    protected virtual bool ShouldSerializeStyle()
    {
      return (styleStored == true);
    }

    public virtual void ResetStyle()
    {
      styleStored = false;
      StyleChanged();
    }

    //Other
    private void OnGridLineChanged()
    {
      if (host != null)
        host.GridLineChanged(this);
    }
    #endregion

  }

  public interface ICellBackFillerOwner
  {
    void BackFillerChanged(CellBackFiller backFiller);
    Color BackFillerDefaultColor(CellBackFiller backFiller);
    Color BackFillerDefaultSecondColor(CellBackFiller backFiller);
    CellFillStyle BackFillerDefaultFillStyle(CellBackFiller backFiller);
    CellInnerBorderStyle BackFillerDefaultInnerBorder(CellBackFiller backFiller);
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class CellBackFiller
  {
    #region privates
    private readonly ICellBackFillerOwner owner;
    private CellFillStyle fillStyle = CellFillStyle.VisualStyles;
    private bool fillStyleStored;
    private CellInnerBorderStyle innerBorder = CellInnerBorderStyle.RaisedTopLeft;
    private bool innerBorderStored;
    private Color color = SystemColors.ButtonFace;
    private bool colorStored;
    private Color secondColor;
    private bool secondColorStored;
    #endregion

    #region constructor
    public CellBackFiller(ICellBackFillerOwner owner)
    {
      this.owner = owner;
    }
    #endregion

    [Browsable(false)]
    public ICellBackFillerOwner Owner
    {
      get { return owner; }
    }

    #region design-time properties
    public CellFillStyle FillStyle
    {
      get
      {
        if (fillStyleStored)
          return fillStyle;
        else
          return DefaultFillStyle();
      }

      set
      {
        if ((fillStyleStored == false) || (fillStyle != value))
        {
          fillStyleStored = true;
          fillStyle = value;
          FillStyleChanged();
        }
      }
    }

    public CellInnerBorderStyle InnerBorder
    {
      get
      {
        if (innerBorderStored)
          return innerBorder;
        else
          return DefaultInnerBorder();
      }

      set
      {
        if ((innerBorderStored == false) || (innerBorder != value))
        {
          innerBorderStored = true;
          innerBorder = value;
          InnerBorderChanged();
        }
      }
    }

    public Color Color
    {
      get
      {
        if (colorStored)
          return color;
        else
          return DefaultColor();
      }

      set
      {
        if ((colorStored == false) || (color != value))
        {
          colorStored = true;
          color = value;
          ColorChanged();
        }
      }
    }

    public Color SecondColor
    {
      get
      {
        if (secondColorStored)
          return secondColor;
        else
          return DefaultSecondColor();
      }

      set
      {
        if ((secondColorStored == false) || (secondColor != value))
        {
          secondColorStored = true;
          secondColor = value;
          SecondColorChanged();
        }
      }
    }
    #endregion

    //Color
    protected virtual Color DefaultColor()
    {
      if (owner != null)
        return owner.BackFillerDefaultColor(this);
      else
        return SystemColors.ButtonFace;
    }

    protected virtual void ColorChanged()
    {
      BackFillerChanged();
    }

    protected virtual bool ShouldSerializeColor()
    {
      return colorStored;
    }

    public virtual void ResetColor()
    {
      if (colorStored)
      {
        colorStored = false;
        ColorChanged();
      }
    }

    //SecondColor
    private Color DefaultSecondColor()
    {
      if (owner != null)
        return owner.BackFillerDefaultSecondColor(this);
      else
        return SystemColors.ButtonFace;
    }

    private void SecondColorChanged()
    {
      BackFillerChanged();
    }

    protected virtual bool ShouldSerializeSecondColor()
    {
      return secondColorStored;
    }

    public virtual void ResetSecondColor()
    {
      if (secondColorStored)
      {
        secondColorStored = false;
        SecondColorChanged();
      }
    }

    //FillStyle
    private CellFillStyle DefaultFillStyle()
    {
      if (owner != null)
        return owner.BackFillerDefaultFillStyle(this);
      else
        return CellFillStyle.Solid;
    }

    protected virtual void FillStyleChanged()
    {
      BackFillerChanged();
    }

    protected virtual bool ShouldSerializeFillStyle()
    {
      return fillStyleStored;
    }

    public virtual void ResetFillStyle()
    {
      if (fillStyleStored)
      {
        fillStyleStored = false;
        FillStyleChanged();
      }
    }

    //InnerBorder
    private CellInnerBorderStyle DefaultInnerBorder()
    {
      if (owner != null)
        return owner.BackFillerDefaultInnerBorder(this);
      else
        return CellInnerBorderStyle.RaisedTopLeft;
    }

    protected virtual void InnerBorderChanged()
    {
      BackFillerChanged();
    }

    protected virtual bool ShouldSerializeInnerBorder()
    {
      return innerBorderStored;
    }

    public virtual void ResetInnerBorder()
    {
      if (innerBorderStored)
      {
        innerBorderStored = false;
        InnerBorderChanged();
      }
    }

    //Other
    private void BackFillerChanged()
    {
      if (owner != null)
        owner.BackFillerChanged(this);
    }
  }

  public interface IGridRowHeightOptionsOwner
  {
    void HeightOptionsChanged(GridRowHeightOptions heightOptions);
    bool HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions);
    int HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions);
    int HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions);
    GridRowHeightUnit HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions);
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridRowHeightOptions
  {
    #region privates
    private readonly IGridRowHeightOptionsOwner owner;
    private bool autoExpand;
    private bool autoExpandStored;
    private int contentHeight;
    private bool contentHeightStored;
    private int maxContentHeight;
    private bool maxContentHeightStored;
    private GridRowHeightUnit unit;
    private bool unitStored;
    #endregion

    #region constructor
    public GridRowHeightOptions(IGridRowHeightOptionsOwner owner)
    {
      this.owner = owner;
    }
    #endregion

    [Browsable(false)]
    public IGridRowHeightOptionsOwner Owner
    {
      get { return owner; }
    }

    #region design-time properties
    public bool AutoExpand
    {
      get
      {
        if (autoExpandStored)
          return autoExpand;
        else
          return DefaultAutoExpand();
      }

      set
      {
        if ((autoExpandStored == false) || (autoExpand != value))
        {
          autoExpandStored = true;
          autoExpand = value;
          HeightOptionsChanged();
        }
      }
    }

    public int ContentHeight
    {
      get
      {
        if (contentHeightStored)
          return contentHeight;
        else
          return DefaultContentHeight();
      }

      set
      {
        if ((contentHeightStored == false) || (contentHeight != value))
        {
          contentHeightStored = true;
          contentHeight = value;
          HeightOptionsChanged();
        }
      }
    }

    public int MaxContentHeight
    {
      get
      {
        if (maxContentHeightStored)
          return maxContentHeight;
        else
          return DefaultMaxContentHeight();
      }

      set
      {
        if ((maxContentHeightStored == false) || (maxContentHeight != value))
        {
          maxContentHeightStored = true;
          maxContentHeight = value;
          HeightOptionsChanged();
        }
      }
    }

    public GridRowHeightUnit Unit
    {
      get
      {
        if (unitStored)
          return unit;
        else
          return DefaultUnit();
      }

      set
      {
        if ((unitStored == false) || (unit != value))
        {
          unitStored = true;
          unit = value;
          HeightOptionsChanged();
        }
      }
    }
    #endregion

    //AutoExpand
    private bool DefaultAutoExpand()
    {
      if (owner != null)
        return owner.HeightOptionsDefaultAutoExpand(this);
      else
        return false;
    }

    protected virtual bool ShouldSerializeAutoExpand()
    {
      return autoExpandStored;
    }

    public virtual void ResetAutoExpand()
    {
      if (autoExpandStored)
      {
        autoExpandStored = false;
        AutoExpandChanged();
      }
    }

    protected virtual void AutoExpandChanged()
    {
      HeightOptionsChanged();
    }

    //ContentHeight
    private int DefaultContentHeight()
    {
      if (owner != null)
        return owner.HeightOptionsDefaultContentHeight(this);
      else
        return 1;
    }

    protected virtual bool ShouldSerializeContentHeight()
    {
      return contentHeightStored;
    }

    public virtual void ResetContentHeight()
    {
      if (contentHeightStored)
      {
        contentHeightStored = false;
        ContentHeightChanged();
      }
    }

    protected virtual void ContentHeightChanged()
    {
      HeightOptionsChanged();
    }

    //MaxContentHeight
    private int DefaultMaxContentHeight()
    {
      if (owner != null)
        return owner.HeightOptionsDefaultMaxContentHeight(this);
      else
        return 1;
    }

    protected virtual bool ShouldSerializeMaxContentHeight()
    {
      return maxContentHeightStored;
    }

    public virtual void ResetContentMaxHeight()
    {
      if (maxContentHeightStored)
      {
        maxContentHeightStored = false;
        MaxContentHeightChanged();
      }
    }

    protected virtual void MaxContentHeightChanged()
    {
      HeightOptionsChanged();
    }

    //Unit
    private GridRowHeightUnit DefaultUnit()
    {
      if (owner != null)
        return owner.HeightOptionsDefaultUnit(this);
      else
        return GridRowHeightUnit.TextLine;
    }

    protected virtual bool ShouldSerializeUnit()
    {
      return unitStored;
    }

    public virtual void ResetUnit()
    {
      if (unitStored)
      {
        unitStored = false;
        UnitChanged();
      }
    }

    protected virtual void UnitChanged()
    {
      HeightOptionsChanged();
    }

    //Other
    private void HeightOptionsChanged()
    {
      if (owner != null)
        owner.HeightOptionsChanged(this);
    }
  }

  public class GridLineColors
  {

    #region Consts
    #endregion

    #region Privates
    private readonly BaseGridControl grid;
    private Color brightColor = Color.Empty;
    private Color darkColor = Color.Empty;
    private bool darkColorStored;
    private bool brightColorStored;
    #endregion Privates

    public GridLineColors(BaseGridControl grid)
    {
      this.grid = grid;
    }

    #region Properties
    protected BaseGridControl Grid
    {
      get { return grid; }
    }

    protected internal Color DarkColor
    {
      get
      {
        if (darkColorStored)
          return darkColor;
        else
          return DefaultDarkColor();
      }
      set
      {
        if ((darkColorStored == false) || (darkColor != value))
        {
          darkColorStored = true;
          darkColor = value;
          DarkColorChanged();
        }
      }
    }

    protected internal Color BrightColor
    {
      get
      {
        if (brightColorStored)
          return brightColor;
        else
          return DefaultBrightColor();
      }
      set
      {
        if ((brightColorStored == false) || (brightColor != value))
        {
          brightColorStored = true;
          brightColor = value;
          BrightColorChanged();
        }
      }
    }
    #endregion Properties

    #region Methods
    public virtual Color DefaultBrightColor()
    {
      return Grid.ActualDrawStyle.DefaultBrightLineColor(Grid);
    }

    protected virtual void BrightColorChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual bool ShouldSerializeBrightColor()
    {
      return (brightColorStored == true);
    }

    public virtual void ResetBrightColor()
    {
      brightColorStored = false;
      BrightColorChanged();
    }

    public virtual Color DefaultDarkColor()
    {
      return Grid.ActualDrawStyle.DefaultDarkLineColor(Grid);
    }

    protected virtual void DarkColorChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual bool ShouldSerializeDarkColor()
    {
      return (darkColorStored == true);
    }

    public virtual void ResetDarkColor()
    {
      darkColorStored = false;
      DarkColorChanged();
    }
    #endregion Methods
  }

  [ToolboxItem(false)]
  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class BaseGridScrollBar : Component
  {
    #region private consts
    private static readonly object EventKeyScrollPosChanged = new object();
    private static readonly object EventKeyRollParamsChanged = new object();
    #endregion private consts

    #region Privates
    private readonly BaseGridControl grid;
    private readonly Orientation orientation;
    private bool tracking;
    private ScrollBarVisibleMode visibleMode;
    private bool smoothStep;
    private int size;
    int viewportSize;
    long rollSize;
    #endregion Privates

    public BaseGridScrollBar(BaseGridControl grid, Orientation kind)
    {
      this.grid = grid;
      orientation = kind;

      visibleMode = ScrollBarVisibleMode.AutoShow;
      tracking = true;
    }

    #region Properties
    [Browsable(false)]
    public BaseGridControl Grid
    {
      get { return grid; }
    }

    [Browsable(false)]
    public Orientation Kind
    {
      get { return orientation; }
    }

    protected int Size
    {
      get
      {
        return size;
      }
      set
      {
        if (value != size)
        {
          size = value;
          Grid.ScrollBarSizeChanged(this);
        }
      }
    }

    [DefaultValue(ScrollBarVisibleMode.AutoShow)]
    public ScrollBarVisibleMode VisibleMode
    {
      get { return visibleMode; }
      set { SetVisibleMode(value); }
    }

    [DefaultValue(false)]
    public virtual bool SmoothStep
    {
      get { return smoothStep; }
      set { smoothStep = value; }
    }

    [DefaultValue(true)]
    public bool Tracking
    {
      get { return tracking; }
      set { tracking = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    public long ScrollPos
    {
      get
      {
        if (Kind == Orientation.Horizontal)
          return Grid.HorzAxis.RollStartVisPos;
        else
          return Grid.VertAxis.RollStartVisPos;
      }

      set
      {
        if (Kind == Orientation.Horizontal)
          Grid.HorzAxis.RollStartVisPos = Grid.HorzAxis.CheckRollStartVisPos(value);
        else
          Grid.VertAxis.RollStartVisPos = Grid.VertAxis.CheckRollStartVisPos(value);
      }
    }

    [Browsable(false)]
    public long RollSize
    {
      get
      {
        if (Kind == Orientation.Horizontal)
          return Grid.HorzAxis.RollLen;
        else
          return Grid.VertAxis.RollLen;
      }
    }

    [Browsable(false)]
    public int ViewportSize
    {
      get
      {
        if (Kind == Orientation.Horizontal)
          return Grid.HorzAxis.RollClientLen;
        else
          return Grid.VertAxis.RollClientLen;
      }
    }
    #endregion

    #region events
    protected event EventHandler<EventArgs> ScrollPosChanged
    {
      add
      {
        this.Events.AddHandler(EventKeyScrollPosChanged, value);
      }

      remove
      {
        this.Events.RemoveHandler(EventKeyScrollPosChanged, value);
      }
    }

    protected event EventHandler<EventArgs> RollParamsChanged
    {
      add
      {
        this.Events.AddHandler(EventKeyRollParamsChanged, value);
      }

      remove
      {
        this.Events.RemoveHandler(EventKeyRollParamsChanged, value);
      }
    }
    
    #endregion

    #region Methods
    public bool IsKeepMaxSizeInDefault()
    {
      return false;
    }

    public bool IsScrollBarShowing()
    {
      return CheckScrollBarMustBeShown();
    }

    public virtual bool CheckScrollBarMustBeShown()
    {
      int position, min, max, pageSize;

      if (!Grid.CanShowScrollBar(Kind))
        return false;
      if (VisibleMode == ScrollBarVisibleMode.AlwaysShow)
        return true;
      else if (VisibleMode == ScrollBarVisibleMode.NeverShow)
        return false;
      else //sbAutoShowEh
      {
        if (Kind == Orientation.Horizontal)
          Grid.GetDataForHorzScrollBar(out position, out min, out max, out pageSize);
        else
          Grid.GetDataForVertScrollBar(out position, out min, out max, out pageSize);
        if ((max <= min) || (max - min < pageSize))
          return false;
        else
          return true;
      }
    }

    public bool CheckHideScrollBar()
    {
      return false;
    }

    public void SetVisibleMode(ScrollBarVisibleMode value)
    {
      if (visibleMode != value)
      {
        visibleMode = value;
        Grid.UpdateBoundaries();
      }
    }

    public void ScrollBarPanelChanged()
    {
    }

    public void SetParams(int position, int min, int max, int pageSize)
    {
      if (Kind == Orientation.Horizontal)
        Grid.HorzScrollBarPanelControl.SetParams(position, min, max, pageSize);
      else
        Grid.VertScrollBarPanelControl.SetParams(position, min, max, pageSize);
    }

    public void SmoothStepChanged()
    {

    }

    public bool ScrollBarPanel()
    {
      return false;
    }

    public int ActualSize()
    {
      if (Size > 0)
        return Size;
      else
        return Grid.ScrollBarSize;
    }

    public int ActualScrollBarBoxSize()
    {
      int result = ActualSize();
      if (IsKeepMaxSizeInDefault())
      {
        if (result > SystemInformation.HorizontalScrollBarHeight)
          result = SystemInformation.HorizontalScrollBarHeight;
      }
      return result;
    }

    protected internal virtual void OnScrollPosChanged()
    {
      var eh = this.Events[EventKeyScrollPosChanged] as EventHandler<EventArgs>;
      if (eh != null && !Grid.IsDisposed)
      {
        var e = new EventArgs();
        eh(this, e);
      }
    }

    protected internal virtual void OnRollParamsChanged()
    {
      var eh = this.Events[EventKeyRollParamsChanged] as EventHandler<EventArgs>;
      if (eh != null && !Grid.IsDisposed)
      {
        var e = new EventArgs();
        eh(this, e);
      }
    }

    internal void CheckRollParamsChanged()
    {
      int newViewportSize;
      long newRollSize;

      if (Kind == Orientation.Horizontal)
      {
        newViewportSize = Grid.HorzAxis.RollClientLen;
        newRollSize = Grid.HorzAxis.RollLen;
      }
      else
      {
        newViewportSize = Grid.VertAxis.RollClientLen;
        newRollSize = Grid.VertAxis.RollLen;
      }
      if (viewportSize != newViewportSize || newRollSize != rollSize)
      {
        viewportSize = newViewportSize;
        rollSize = newRollSize;
        OnRollParamsChanged();
      }
    }
    #endregion Methods

  }

  [ToolboxItem(false)]
  public class BaseGridHorzScrollBar : BaseGridScrollBar
  {

    //    #pragma warning disable CA2214
    public BaseGridHorzScrollBar(BaseGridControl grid, Orientation kind) :
      base(grid, kind)
    {
      base.SmoothStep = true;
    }

    #region Properties
    [DefaultValue(0)]
    public int Height
    {
      get { return Size; }
      set { Size = value; }
    }

    [DefaultValue(true)]
    public override bool SmoothStep
    {
      get { return base.SmoothStep; }
      set { base.SmoothStep = value; }
    }
    #endregion Properties
  }

  [ToolboxItem(false)]
  public class BaseGridVertScrollBar : BaseGridScrollBar
  {

    public BaseGridVertScrollBar(BaseGridControl grid, Orientation kind) :
      base(grid, kind)
    {
    }

    #region Properties
    [DefaultValue(0)]
    public int Width
    {
      get { return Size; }
      set { Size = value; }
    }
    #endregion Properties
  }

  public class GridOutBoundaryData
  {

    #region Privates
    private int leftIndent;
    private int topIndent;
    private int rightIndent;
    private int bottomIndent;
    private CornerPaintPriority leftTopPaintPriority;
    private CornerPaintPriority rightTopPaintPriority;
    private CornerPaintPriority leftBottomPaintPriority;
    private CornerPaintPriority rightBottomPaintPriority;
    private readonly BaseGridControl grid;
    #endregion Privates


    #region Properties
    protected BaseGridControl Grid
    {
      get { return grid; }
    }

    public int LeftIndent
    {
      get { return leftIndent; }
      set { SetLeftIndent(value); }
    }

    public int TopIndent
    {
      get { return topIndent; }
      set { SetTopIndent(value); }
    }

    public int RightIndent
    {
      get { return rightIndent; }
      set { SetRightIndent(value); }
    }

    public int BottomIndent
    {
      get { return bottomIndent; }
      set { SetBottomIndent(value); }
    }

    public CornerPaintPriority LeftTopPaintPriority
    {
      get { return leftTopPaintPriority; }
      set { SetLeftTopPaintPriority(value); }
    }

    public CornerPaintPriority RightTopPaintPriority
    {
      get { return rightTopPaintPriority; }
      set { SetRightTopPaintPriority(value); }
    }

    public CornerPaintPriority LeftBottomPaintPriority
    {
      get { return leftBottomPaintPriority; }
      set { SetLeftBottomPaintPriority(value); }
    }

    public CornerPaintPriority RightBottomPaintPriority
    {
      get { return rightBottomPaintPriority; }
      set { SetRightBottomPaintPriority(value); }
    }
    #endregion Properties


    #region Methods
    public GridOutBoundaryData(BaseGridControl grid)
    {
      this.grid = grid;
    }

    public void SetBottomIndent(int value)
    {
      bottomIndent = value;
    }

    public void SetLeftBottomPaintPriority(CornerPaintPriority value)
    {
      leftBottomPaintPriority = value;
    }

    public void SetLeftIndent(int value)
    {
      leftIndent = value;
    }

    public void SetLeftTopPaintPriority(CornerPaintPriority value)
    {
      leftTopPaintPriority = value;
    }

    public void SetRightBottomPaintPriority(CornerPaintPriority value)
    {
      rightBottomPaintPriority = value;
    }

    public void SetRightIndent(int value)
    {
      rightIndent = value;
    }

    public void SetRightTopPaintPriority(CornerPaintPriority value)
    {
      rightTopPaintPriority = value;
    }

    public void SetTopIndent(int value)
    {
      topIndent = value;
    }

    public bool GetOutBoundaryRect(ref Rectangle rect, CornerPaintPriority outBoundaryType)
    {
      return false;
    }

    public virtual void InvalidateOutBoundary(CornerPaintPriority outBoundaryType)
    {
    }
    #endregion Methods

  }

  public interface IBaseGridControlInternal
  {
    void MoveColumn(int fromIndex, int toIndex);
    void UpdateCursor(MouseEventArgs e);
  }

  [ToolboxItem(false)]
  public class BaseGridControl : Control, ICellBackFillerOwner, IBaseGridControlInternal
  {
    #region consts
    internal const string CharColonStr = ":";
    #endregion

    #region privates
    private readonly GridAxisData horzAxis;
    private readonly GridAxisData vertAxis;
    private GridCoord curCell;
    private GridCoord anchorCell;
    private GridOptions options;
    private Rectangle winClientBoundary;

    private BaseGridScrollBarPanelControl vertScrollBarPanelControl;
    private BaseGridScrollBarPanelControl horzScrollBarPanelControl;
    private SizeGripControl cornerScrollBarPanelControl;
    private readonly SizeGripControl extraSizeGripControl;
    private BaseGridVertScrollBar vertScrollBar;
    private BaseGridHorzScrollBar horzScrollBar;
    private bool vertScrollBarIsShowing;
    private bool horzScrollBarIsShowing;
    private int gridLineWidth = 1;
    private int scrollBarSize;
    private readonly GridOutBoundaryData outBoundaryData;
    private bool sizeGripAlwaysShow;
    private SizeGripPosition sizeGripPosition;
    private GridLineColors gridLineColors;
    private GridBackground backgroud;
    private BaseGridState gridState;
    private GridCoord mouseHolderCellCoord;
    private Point mouseHolderCellMousePos;

    //proptected fields
    internal bool EditorMode = false;
    protected int BoundariesUpdateCount;
    protected GridOptions DesignOptionsBoost = 0;
    protected Color FixedLineColor;
    protected int LockPaint;

    protected internal Point MouseDownPos;
    protected internal GridCoord MouseDownCellCoord;
    protected internal MouseButtons MouseDownButton;
    protected internal bool MouseDownCellCoordPressed;
    protected internal Point HotTrackInCellPos;

    //protected bool saveCellExtents;
    internal protected int SizingIndex;
    protected int SizingPos;
    protected int SizingOffset;
    protected bool SizingPosChanged;
    protected int DrawnSizingPos1;
    protected int DrawnSizingPos2;

    protected internal int MoveFromIndex;
    protected internal int MoveToIndex;
    protected internal int MoveFromCellOriginDistance;
    //protected bool moveFromPosLeftSite;
    //protected bool moveToPosLeftSite;
    //protected Color internalColor;
    //protected Color internalFontColor;
    //protected Color internalFixedColor;
    //protected Color internalFixedFontColor;
    private readonly Timer gridTimer = new Timer();

    protected bool ScrollBarInternalUpdating;
    private BaseGridDrawStyle drawStyle;
    private readonly ControlBorder border;
    protected Point HitTestPoint;
    protected internal MoveAndScrollService MoveNScrollService;
    private readonly CellBackFiller fixedBackFiller;
    private bool useVisualStylesStored;
    private bool useVisualStyles;
    private bool backColorStored;

    private BaseGridCellManager cellMan;
    #endregion

    #region constructor
    public BaseGridControl()
    {
      SetStyle(ControlStyles.ResizeRedraw, true);
      SetStyle(ControlStyles.Opaque, true);
      //this.SetStyle(ControlStyles.Selectable, true);
      if (!EhLibUtils.DebugPaint)
        SetStyle(ControlStyles.DoubleBuffer, true);

      horzAxis = new GridAxisData(this);
      vertAxis = new GridAxisData(this);
      outBoundaryData = new GridOutBoundaryData(this);

      extraSizeGripControl = new SizeGripControl();
      extraSizeGripControl.Visible = false;
      extraSizeGripControl.SetBounds(0, 0, 0, 0);
      extraSizeGripControl.GripActiveStatus = GripActiveStatus.Never;
      extraSizeGripControl.Parent = this;

      mouseHolderCellCoord = new GridCoord(-1, -1);
      MouseDownCellCoord = new GridCoord(-1, -1);
      MoveNScrollService = new MoveAndScrollService();

      DefaultColWidth = 50;
      DefaultRowHeight = 20;
      RollColCount = 5;
      RollRowCount = 5;
      FixedColCount = 1;
      FixedRowCount = 1;
      scrollBarSize = SystemInformation.HorizontalScrollBarHeight;
      sizeGripPosition = SizeGripPosition.BottomRight;
      options = GridOptions.FixedVertLines | GridOptions.FixedHorzLines | GridOptions.VertLines | GridOptions.HorzLines |
        GridOptions.DrawFocusSelected | GridOptions.Editing |
        GridOptions.RowSizing | GridOptions.ColSizing | GridOptions.RowMoving | GridOptions.ColMoving |
        GridOptions.ContraVertBoundaryLine | GridOptions.ContraHorzBoundaryLine;

      //borderStyle = defaultBorderStyle;
      border = new ControlBorder();
      border.BorderStateChanged += Border_BorderStateChanged;

      fixedBackFiller = new CellBackFiller(this);
      //BackColor = SystemColors.Window;

      cellMan = new BaseGridCellManager();
      cellMan.Grid = this;

      InitData();
    }

    private void InitData()
    {

      vertScrollBar = CreateVertScrollBar();
      horzScrollBar = CreateHorzScrollBar();
      gridLineColors = CreateGridLineColors();
      backgroud = CreateGridBackground();

      horzScrollBarPanelControl = CreateHorzScrollBarPanelControl();
      horzScrollBarPanelControl.Name = "HorzScrollBarPanelControl";
      horzScrollBarPanelControl.Visible = false;
      horzScrollBarPanelControl.SetBounds(0, 0, 0, 0);
      horzScrollBarPanelControl.Parent = this;

      vertScrollBarPanelControl = CreateVertScrollBarPanelControl();
      vertScrollBarPanelControl.Name = "VertScrollBarPanelControl";
      vertScrollBarPanelControl.Visible = false;
      vertScrollBarPanelControl.SetBounds(0, 0, 0, 0);
      vertScrollBarPanelControl.Parent = this;

      cornerScrollBarPanelControl = CreateSizeGripPanel();
      cornerScrollBarPanelControl.Name = "CornerScrollBarPanelControl";
      cornerScrollBarPanelControl.Visible = false;
      cornerScrollBarPanelControl.SetBounds(0, 0, 0, 0);
      cornerScrollBarPanelControl.Parent = this;
    }

    #endregion

    #region design properties
    public override Color BackColor
    {
      get
      {
        if (ShouldSerializeBackColor())
          return base.BackColor;
        else
          return SystemColors.Window;
      }
      set
      {
        if (BackColor != value)
        {
          backColorStored = true;
          base.BackColor = value;
        }
      }
    }

    #endregion

    #region public properties
    [Browsable(false)]
    public bool UseVisualStyles
    {
      get
      {
        if (useVisualStylesStored)
          return useVisualStyles;
        else
          return DefaultUseVisualStyles();
      }
      set
      {
        if ((useVisualStylesStored == false) || (useVisualStyles != value))
        {
          useVisualStylesStored = true;
          useVisualStyles = value;
          UseVisualStylesChanged();
        }
      }
    }

    [Browsable(false)]
    public GridCoord MouseHolderCellCoord
    {
      get { return mouseHolderCellCoord; }
    }

    [Browsable(false)]
    public Point MouseHolderCellMousePos
    {
      get { return mouseHolderCellMousePos; }
    }

    [Browsable(false)]
    public Rectangle ClientBounds
    {
      get
      {
        Rectangle rect = ClientRectangle;
        Border.ExcludeBorderRect(ref rect);
        return rect;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public ControlBorder Border
    {
      get { return border; }
    }

    [Browsable(false)]
    public Color FixedBackColor
    {
      get { return FixedBackFiller.Color; }
    }

    [Browsable(false)]
    public bool UseRightToLeft
    {
      get
      {
        return (RightToLeft == RightToLeft.Yes);
        //return false;
      }
    }

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Bindable(false)]
    public override string Text
    {
      get
      {
        return base.Text;
      }
      set
      {
        base.Text = value;
      }
    }
    #endregion

    #region inernal properties
    protected internal BaseGridCellManager CellMan
    {
      get { return cellMan; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BaseGridState GridState
    {
      get
      {
        return gridState;
      }
      set
      {
        if (value != gridState)
        {
          gridState = value;
          if (gridState == BaseGridState.ColMoving)
            Cursor = Cursors.HSplit;
          else if (gridState == BaseGridState.ColSizing)
            Cursor = Cursors.VSplit;
          else if (gridState == BaseGridState.Normal)
            Cursor = null;
        }
      }
    }

    protected internal GridAxisData HorzAxis
    {
      get { return horzAxis; }
    }

    protected internal GridAxisData VertAxis
    {
      get { return vertAxis; }
    }

    protected int RollColCount
    {
      get { return HorzAxis.RollCellCount; }
      set { HorzAxis.RollCellCount = value; }
    }

    protected int RollRowCount
    {
      get { return VertAxis.RollCellCount; }
      set { VertAxis.RollCellCount = value; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int FixedColCount
    {
      get { return HorzAxis.FixedCellCount; }
      set { HorzAxis.FixedCellCount = value; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int FixedRowCount
    {
      get { return vertAxis.FixedCellCount; }
      set { SetFixedRowCount(value); }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int ColCount
    {
      get { return FixedColCount + RollColCount; }
      set { RollColCount = value - FixedColCount; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int FrozenColCount
    {
      get { return HorzAxis.FrozenCellCount; }
      set { HorzAxis.FrozenCellCount = value; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int RowCount
    {
      get { return FixedRowCount + RollRowCount; }
      set { RollRowCount = value - FixedRowCount; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int FrozenRowCount
    {
      get { return VertAxis.FrozenCellCount; }
      set { VertAxis.FrozenCellCount = value; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int ContraColCount
    {
      get { return HorzAxis.ContraCellCount; }
      set { HorzAxis.ContraCellCount = value; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int ContraRowCount
    {
      get { return VertAxis.ContraCellCount; }
      set { VertAxis.ContraCellCount = value; }
    }

    protected internal int VisibleColCount
    {
      get
      {
        return HorzAxis.RollLastFullVisCell - HorzAxis.RollStartVisCell + 1;
      }
    }

    protected internal int VisibleRowCount
    {
      get
      {
        return VertAxis.RollLastFullVisCell - VertAxis.RollStartVisCell + 1;
      }
    }

    protected internal GridOptions Options
    {
      get
      {
        return options;
      }
      set
      {
        options = value;
      }
    }

    [Browsable(false)]
    public CellLensAccessClass RowHeights
    {
      get { return VertAxis.CellLens; }
    }

    [Browsable(false)]
    public CellLensAccessClass ColWidths
    {
      get { return HorzAxis.CellLens; }
    }

    protected int FullColCount
    {
      get { return ColCount + ContraColCount; }
    }

    protected int FullRowCount
    {
      get { return RowCount + ContraRowCount; }
    }

    protected internal int Row
    {
      get { return curCell.Y; }
      set { SetRow(value); }
    }

    protected internal int Col
    {
      get { return curCell.X; }
      set { SetCol(value); }
    }

    protected long RollStartVisPosX
    {
      get
      {
        HorzAxis.CheckUpdateRollCellPosArray();
        return HorzAxis.RollStartVisPos;
      }
      set { HorzAxis.RollStartVisPos = value; }
    }

    protected long RollStartVisPosY
    {
      get
      {
        VertAxis.CheckUpdateRollCellPosArray();
        return VertAxis.RollStartVisPos;
      }
      set { VertAxis.RollStartVisPos = value; }
    }

    protected GridOutBoundaryData OutBoundaryData
    {
      get { return outBoundaryData; }
      //      set { VertAxis.RollStartVisPos = value; }
    }

    protected internal int GridLineWidth
    {
      get { return gridLineWidth; }
      set { SetGridLineWidth(value); }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    protected internal BaseGridVertScrollBar VertScrollBar
    {
      get { return vertScrollBar; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    protected internal BaseGridHorzScrollBar HorzScrollBar
    {
      get { return horzScrollBar; }
    }

    protected internal BaseGridScrollBarPanelControl VertScrollBarPanelControl
    {
      get { return vertScrollBarPanelControl; }
    }

    protected internal BaseGridScrollBarPanelControl HorzScrollBarPanelControl
    {
      get { return horzScrollBarPanelControl; }
    }

    protected internal int DefaultColWidth
    {
      get { return HorzAxis.DefaultCellLen; }
      set { HorzAxis.DefaultCellLen = value; }
    }

    protected internal int DefaultRowHeight
    {
      get { return VertAxis.DefaultCellLen; }
      set { VertAxis.DefaultCellLen = value; }
    }

    protected override Size DefaultSize
    {
      get
      {
        return new Size(240, 150);
      }
    }

    protected SizeGripPosition SizeGripPosition
    {
      get { return sizeGripPosition; }
      set { SetSizeGripPosition(value); }
    }

    protected bool SizeGripAlwaysShow
    {
      get { return sizeGripAlwaysShow; }
      set { SetSizeGripAlwaysShow(value); }
    }

    protected int ClientWidth
    {
      get { return ClientSize.Width; }
    }

    protected int ClientHeight
    {
      get { return ClientSize.Height; }
    }

    protected virtual bool FullRedrawOnScroll
    {
      get { return Background.Visible || GridWaterMark.Visible; }
    }

    internal int ScrollBarSize
    {
      get { return scrollBarSize; }
      set { SetScrollBarSize(value); }
    }

    protected internal GridLineColors GridLineColors
    {
      get { return gridLineColors; }
    }

    protected internal GridBackground Background
    {
      get { return backgroud; }
    }

    //protected GridRect Selection
    //{
    //  get { return GetSelection(); }
    //  set { SetSelection(value); }
    //}

    protected bool RightToLeftLayout
    {
      get
      {
        return (RightToLeft == RightToLeft.Yes);
      }
    }

    protected int TopRow
    {
      get { return VertAxis.RollStartVisCell + VertAxis.FixedCellCount; }
      set { RollStartVisPosY = VertAxis.RollLocCellPosArr[value - VertAxis.FixedCellCount]; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BaseGridDrawStyle DrawStyle
    {
      get { return drawStyle; }
      set { drawStyle = value; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BaseGridDrawStyle ActualDrawStyle
    {
      get
      {
        if (drawStyle != null)
          return drawStyle;
        else
          return EhLibDrawStyle.DefaultBaseGridDrawStyle;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public CellBackFiller FixedBackFiller
    {
      get
      {
        return fixedBackFiller;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    protected BaseGridCellManager CurrentCellMan
    {
      get
      {
        return CellByColRow(Col, Row);
      }
    }
    #endregion

    #region methods 
    //BackColor

    private bool ShouldSerializeBackColor()
    {
      return backColorStored;
    }

    public override void ResetBackColor()
    {
      backColorStored = false;
      Invalidate();
    }

    //IBaseGridControlInternal
    void IBaseGridControlInternal.MoveColumn(int fromIndex, int toIndex)
    {
      MoveColumn(fromIndex, toIndex);
    }

    void IBaseGridControlInternal.UpdateCursor(MouseEventArgs e)
    {
      UpdateCursor(e);
    }

    //Other
    protected virtual void UseVisualStylesChanged()
    {
      Invalidate();
    }

    protected virtual bool DefaultUseVisualStyles()
    {
      return Application.RenderWithVisualStyles;
    }

    public virtual void ResetUseVisualStyles()
    {
      useVisualStylesStored = false;
      UseVisualStylesChanged();
    }

    protected virtual bool ShouldSerializeUseVisualStyles()
    {
      return (useVisualStylesStored == true);
    }

    protected virtual void OnBorderStyleChanged(EventArgs e)
    {
      UpdateBoundaries();
      InvalidateGrid();
    }

    protected virtual GridLineColors CreateGridLineColors()
    {
      return new GridLineColors(this);
    }

    protected virtual GridBackground CreateGridBackground()
    {
      return new GridBackground(this);
    }

    protected virtual BaseGridVertScrollBar CreateVertScrollBar()
    {
      return new BaseGridVertScrollBar(this, Orientation.Vertical);
    }

    protected virtual BaseGridHorzScrollBar CreateHorzScrollBar()
    {
      return new BaseGridHorzScrollBar(this, Orientation.Horizontal);
    }

    protected virtual SizeGripControl CreateSizeGripPanel()
    {
      return new SizeGripControl();
    }

    protected virtual BaseGridScrollBarPanelControl CreateVertScrollBarPanelControl()
    {
      return new BaseGridScrollBarPanelControl(this, Orientation.Vertical);
    }

    protected virtual BaseGridScrollBarPanelControl CreateHorzScrollBarPanelControl()
    {
      return new BaseGridScrollBarPanelControl(this, Orientation.Horizontal);
    }

    protected override CreateParams CreateParams
    {
      //[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
      get
      {
        CreateParams cp = base.CreateParams;
        //cp.Style |= WS_BORDER;
        //cp.ExStyle |= WS_EX_CLIENTEDGE;

        //if (RightToLeft == RightToLeft.Yes)
        //{
        //  //We want to turn on mirroring for Trackbar explicitly.
        //  cp.ExStyle |= NativeMethods.WS_EX_LAYOUTRTL | NativeMethods.WS_EX_NOINHERITLAYOUT;
        //  //cp.ExStyle |= NativeMethods.WS_EX_LAYOUTRTL;
        //  //Don't need these styles when mirroring is turned on.
        //  cp.ExStyle &= ~(NativeMethods.WS_EX_RTLREADING | NativeMethods.WS_EX_RIGHT | NativeMethods.WS_EX_LEFTSCROLLBAR);
        //}

        return cp;
      }
    }

    public void UpdateBoundaries()
    {
      int i;

      if (BoundariesUpdating() || !IsHandleCreated) return;

      UpdateOutBoundaryIndents();
      BeginUpdateBoundaries();
      try
      {

        if (IsHandleCreated)
        {
          winClientBoundary = ClientRectangle;
        }
        else
        {
          winClientBoundary = new Rectangle(new Point(0, 0), Size);
        }
        Border.ExcludeBorderRect(ref winClientBoundary);

        //  FGridClientBoundary = FWinClientBoundary;
        //  FGridScrolBoundary = FGridClientBoundary;

        horzAxis.WinClientBoundStart = winClientBoundary.Left;
        horzAxis.WinClientBoundStop = winClientBoundary.Right;
        vertAxis.WinClientBoundStart = winClientBoundary.Top;
        vertAxis.WinClientBoundStop = winClientBoundary.Bottom;

        horzAxis.GridClientStart = horzAxis.WinClientBoundStart + OutBoundaryData.LeftIndent;
        horzAxis.GridClientStop = horzAxis.WinClientBoundStop - OutBoundaryData.RightIndent;
        vertAxis.GridClientStart = vertAxis.WinClientBoundStart + OutBoundaryData.TopIndent;
        vertAxis.GridClientStop = vertAxis.WinClientBoundStop - OutBoundaryData.BottomIndent;

        horzAxis.ContraLen = 0;
        for (i = 0; i < ContraColCount; i++)
          horzAxis.ContraLen = horzAxis.ContraLen + HorzAxis.ContraCellLens[i];

        if ((ContraColCount > 0) && ((GridOptions.ContraVertBoundaryLine & Options) != 0))
          horzAxis.ContraLen = horzAxis.ContraLen + GridLineWidth;
        horzAxis.ContraStart = horzAxis.GridClientStop - horzAxis.ContraLen;

        vertAxis.ContraLen = 0;
        for (i = 0; i < ContraRowCount; i++)
          vertAxis.ContraLen = vertAxis.ContraLen + vertAxis.ContraCellLens[i];
        if ((ContraRowCount > 0) && ((GridOptions.ContraHorzBoundaryLine & Options) != 0))
          vertAxis.ContraLen = vertAxis.ContraLen + GridLineWidth;
        vertAxis.ContraStart = vertAxis.GridClientStop - vertAxis.ContraLen;

        horzAxis.FixedBoundary = horzAxis.GridClientStart;
        vertAxis.FixedBoundary = vertAxis.GridClientStart;

        for (i = 0; i < FixedColCount; i++)
          horzAxis.FixedBoundary = horzAxis.FixedBoundary + HorzAxis.FixedCellLens[i];

        for (i = 0; i < FixedRowCount; i++)
          vertAxis.FixedBoundary = vertAxis.FixedBoundary + VertAxis.FixedCellLens[i];

        horzAxis.FrozenLen = 0;
        for (i = FixedColCount - FrozenColCount; i < FixedColCount; i++)
          horzAxis.FrozenLen = horzAxis.FrozenLen + HorzAxis.FixedCellLens[i];

        vertAxis.FrozenLen = 0;
        for (i = FixedRowCount - FrozenRowCount; i < FixedRowCount; i++)
          vertAxis.FrozenLen = vertAxis.FrozenLen + VertAxis.FixedCellLens[i];

        if (HorzScrollBar.IsScrollBarShowing())
        {
          vertAxis.GridClientStop -= HorzScrollBar.ActualSize();
          vertAxis.ContraStart -= HorzScrollBar.ActualSize();
          if (VertScrollBar.IsScrollBarShowing())
          {
            horzAxis.GridClientStop -= VertScrollBar.ActualSize();
            horzAxis.ContraStart -= VertScrollBar.ActualSize();
          }
        }
        else if (VertScrollBar.IsScrollBarShowing())
        {
          horzAxis.GridClientStop -= VertScrollBar.ActualSize();
          horzAxis.ContraStart -= VertScrollBar.ActualSize();
          if (HorzScrollBar.IsScrollBarShowing())
          {
            vertAxis.GridClientStop -= HorzScrollBar.ActualSize();
            vertAxis.ContraStart -= HorzScrollBar.ActualSize();
          }
        }

        AdjustMaxTopLeft(true, true, !IsSmoothHorzScroll(), !IsSmoothVertScroll());

        int rlvc;
        int rlfvc;
        horzAxis.GetLastVisibleCell(out rlvc, out rlfvc);
        HorzAxis.RollLastVisCell = rlvc;
        HorzAxis.RollLastFullVisCell = rlfvc;

        vertAxis.GetLastVisibleCell(out rlvc, out rlfvc);
        VertAxis.RollLastVisCell = rlvc;
        VertAxis.RollLastFullVisCell = rlfvc;

        UpdateScrollBars();
        UpdateOutBoundaryIndents();

        //      if FInplaceEdit <> nil ) 
        //        UpdateEdit;

      }
      finally
      {
        EndUpdateBoundaries();
      }
      HorzScrollBar.CheckRollParamsChanged();
      VertScrollBar.CheckRollParamsChanged();

      InvalidateGrid();
    }

    private void BeginUpdateBoundaries()
    {
      BoundariesUpdateCount++;
    }

    private void EndUpdateBoundaries()
    {
      BoundariesUpdateCount--;
    }

    private bool BoundariesUpdating()
    {
      return (BoundariesUpdateCount > 0);
    }

    public bool CheckCellLine(int col, int row, GridCellBorderType borderType)
    {
      //BaseGridCellBorderEventArgs e = new BaseGridCellBorderEventArgs(col, row, col, row, borderType);
      bool isPaint;
      Color color;
      DashStyle style;
      bool isExtent;

      ProcessGetCellBorders(col, row, borderType, out isPaint, out color, out style, out isExtent);
      return isPaint;
    }

    protected internal virtual void ProcessGetCellBorders(int col, int row, GridCellBorderType borderType,
      out bool isPaint, out Color color, out DashStyle style, out bool isExtent)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(col, row, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "Grid.ProcessGetCellBorders Cell = null");

      BaseGridCellBorderEventArgs e = new BaseGridCellBorderEventArgs(col, row, areaColIndex, areaRowIndex, borderType);
      OnGetCellBorderParams(cell, e);

      isPaint = e.Visible;
      //-isPaint = false;
      color = e.Color;
      style = e.Style;
      isExtent = e.IsExtent;
    }

    protected internal virtual void OnGetCellBorderParams(BaseGridCellManager cell, BaseGridCellBorderEventArgs e)
    {

      e.Style = DashStyle.Solid;

      if ((e.BorderType == GridCellBorderType.Left) || (e.BorderType == GridCellBorderType.Right))
      {
        if ((e.ColIndex < FixedColCount) || (e.RowIndex < FixedRowCount))
          e.Visible = (GridOptions.FixedVertLines & Options) != 0;
        else
          e.Visible = (GridOptions.VertLines & Options) != 0;
        e.IsExtent = true;
      }
      else
      {
        if ((e.ColIndex < FixedColCount) || (e.RowIndex < FixedRowCount))
          e.Visible = (GridOptions.FixedHorzLines & Options) != 0;
        else
          e.Visible = (GridOptions.HorzLines & Options) != 0;
        e.IsExtent = true;
      }

      if ((e.BorderType == GridCellBorderType.Top || e.BorderType == GridCellBorderType.Left) && 
          ((e.ColIndex == ColCount) || (e.RowIndex == RowCount))
      )
        e.Color = GridLineColors.DarkColor;
      else if ((e.ColIndex < FixedColCount - FrozenColCount) || (e.RowIndex < FixedRowCount - FrozenRowCount))
        e.Color = GridLineColors.DarkColor;
      else if ((e.ColIndex == FixedColCount - 1) && (e.BorderType == GridCellBorderType.Right))
        e.Color = GridLineColors.DarkColor;
      else if ((e.RowIndex == FixedRowCount - 1) && (e.BorderType == GridCellBorderType.Bottom))
        e.Color = GridLineColors.DarkColor;
      else
        e.Color = GridLineColors.BrightColor;

      cell.OnGetCellBorderParams(e);
    }

    protected virtual void PaintEmptyAreaCell(Graphics g, int col, int row, Rectangle rect)
    {
      if (Background.Visible) return;

      SolidBrush brush = new SolidBrush(Color.White);
      try
      {
        g.FillRectangle(brush, rect);
      }
      finally
      {
        brush.Dispose();
      }
    }

    // protected methods
    protected bool PointInGridRect(int col, int row, GridRect rect)
    {
      return (col >= rect.Left) && (col <= rect.Right) && (row >= rect.Top) && (row <= rect.Bottom);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      ControlPaintEventArgs ce = CreateControlPaintEventArgs(e);
      HandlePaintEvent(ce);

      if (!ce.Handled)
        PaintInternal(e);
    }

    protected virtual ControlPaintEventArgs CreateControlPaintEventArgs(PaintEventArgs e)
    {
      return new BaseGridControlPaintEventArgs(e, this);
    }

    protected virtual void HandlePaintEvent(ControlPaintEventArgs e)
    {
    }

    internal void PaintInternal(PaintEventArgs e)
    {

      int colI, rowI;
      Rectangle cellRect = new Rectangle();
      Rectangle rec;
      int horzAxisContraBoundary;
      int vertAxisContraBoundary;
      Region oldClip;
      Region clientClip = null;
      Rectangle paintRect;
      Rectangle clipRect;

      if (EhLibUtils.DebugPaint && GetStyle(ControlStyles.DoubleBuffer) == true)
        SetStyle(ControlStyles.DoubleBuffer, false);
      else if (!EhLibUtils.DebugPaint && GetStyle(ControlStyles.DoubleBuffer) == false)
        SetStyle(ControlStyles.DoubleBuffer, true);

      InitPaintData();
      try
      {
        if (Border.HasAnyBorderSide())
        {
          clientClip = e.Graphics.Clip;
          Border.Paint(e.Graphics, ClientRectangle);
          e.Graphics.SetClip(ClientBounds, CombineMode.Intersect);
        }

        if (EhLibUtils.DebugPaint)
        {
          using (var sb = new SolidBrush(Color.FromArgb(192, 220, 192)))
          {
            e.Graphics.FillRectangle(sb, ClientBounds);
          }
        }

        if (Background.Visible)
          Background.OnPaint(e);

        try
        {

          PaintwOutBoundaryData();

          // Fixed Top-left area
          paintRect = Rectangle.FromLTRB(HorzAxis.GridClientStart, VertAxis.GridClientStart,
                                        HorzAxis.FixedBoundary, VertAxis.FixedBoundary);
          clipRect = paintRect;
          PaintCells(e, 0, 0, ColCount, RowCount, paintRect, clipRect, BasePaintCellStates.Fixed);

          // Fixed top area
          paintRect = Rectangle.FromLTRB(HorzAxis.FixedBoundary - HorzAxis.RollStartVisCellOffset, VertAxis.GridClientStart,
                                        HorzAxis.ContraStart, VertAxis.FixedBoundary);
          clipRect = Rectangle.FromLTRB(HorzAxis.FixedBoundary, 0, HorzAxis.ContraStart, VertAxis.ContraStart);
          PaintCells(e, FixedColCount + HorzAxis.RollStartVisCell, 0, ColCount, RowCount, paintRect, clipRect, BasePaintCellStates.Fixed);

          // Fixed left area
          paintRect = Rectangle.FromLTRB(HorzAxis.GridClientStart, VertAxis.FixedBoundary - VertAxis.RollStartVisCellOffset,
                                        HorzAxis.FixedBoundary, VertAxis.ContraStart);
          clipRect = Rectangle.FromLTRB(0, VertAxis.FixedBoundary, HorzAxis.ContraStart, VertAxis.ContraStart);
          PaintCells(e, 0, FixedRowCount + VertAxis.RollStartVisCell, ColCount, RowCount, paintRect, clipRect, BasePaintCellStates.Fixed);

          // Scroll Area
          paintRect = Rectangle.FromLTRB(HorzAxis.FixedBoundary - HorzAxis.RollStartVisCellOffset, VertAxis.FixedBoundary - VertAxis.RollStartVisCellOffset,
                                        HorzAxis.ContraStart, VertAxis.ContraStart);
          clipRect = Rectangle.FromLTRB(HorzAxis.FixedBoundary, VertAxis.FixedBoundary, HorzAxis.ContraStart, VertAxis.ContraStart);
          PaintCells(e, FixedColCount + HorzAxis.RollStartVisCell, FixedRowCount + VertAxis.RollStartVisCell, ColCount, RowCount, paintRect, clipRect, 0);

          // ContraColCount
          horzAxisContraBoundary = HorzAxis.ContraStart;
          if (ContraColCount > 0)
          {

            if ((GridOptions.ContraVertBoundaryLine & Options) != 0)
              horzAxisContraBoundary++;

            if ((GridOptions.ContraVertBoundaryLine & Options) != 0)
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Left, false,
                ColCount, 0, ColCount,
                HorzAxis.ContraStart,
                VertAxis.GridClientStart, VertAxis.FixedBoundary);
            }

            // Contra Area Right // Fixed top
            paintRect = Rectangle.FromLTRB(horzAxisContraBoundary, VertAxis.GridClientStart,
                                          HorzAxis.GridClientStop, VertAxis.FixedBoundary);
            clipRect = paintRect;
            PaintCells(e, ColCount, 0, FullColCount, RowCount, paintRect, clipRect, BasePaintCellStates.Fixed);

            if ((GridOptions.ContraVertBoundaryLine & Options) != 0)
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Left, false,
                ColCount, FixedRowCount + VertAxis.RollStartVisCell, RowCount,
                HorzAxis.ContraStart,
                VertAxis.FixedBoundary - VertAxis.RollStartVisCellOffset, VertAxis.ContraStart);
            }

            paintRect = Rectangle.FromLTRB(horzAxisContraBoundary, VertAxis.FixedBoundary - VertAxis.RollStartVisCellOffset,
                                          HorzAxis.GridClientStop, VertAxis.ContraStart);
            clipRect = Rectangle.FromLTRB(horzAxisContraBoundary, VertAxis.FixedBoundary,
                                          HorzAxis.GridClientStop, VertAxis.ContraStart);
            PaintCells(e, ColCount, FixedRowCount + VertAxis.RollStartVisCell, FullColCount, RowCount, paintRect, clipRect, BasePaintCellStates.Fixed);
          }

          // ContraRowCount
          vertAxisContraBoundary = VertAxis.ContraStart;
          if (ContraRowCount > 0)
          {
            // Contra Area Bottom Fixed Left
            if ((GridOptions.ContraHorzBoundaryLine & Options) != 0)
              vertAxisContraBoundary++;

            if ((GridOptions.ContraHorzBoundaryLine & Options) != 0)
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Top, false,
                0, RowCount, ColCount,
                HorzAxis.GridClientStart,
                VertAxis.ContraStart, HorzAxis.FixedBoundary);
            }

            paintRect = Rectangle.FromLTRB(HorzAxis.GridClientStart, vertAxisContraBoundary,
                                          HorzAxis.FixedBoundary, VertAxis.GridClientStop);
            clipRect = paintRect;
            PaintCells(e, 0, RowCount, ColCount, FullRowCount, paintRect, clipRect, BasePaintCellStates.Fixed);

            if ((GridOptions.ContraHorzBoundaryLine & Options) != 0)
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Top, false,
                FixedColCount + HorzAxis.RollStartVisCell, RowCount, ColCount,
                HorzAxis.FixedBoundary - HorzAxis.RollStartVisCellOffset,
                VertAxis.ContraStart, HorzAxis.ContraStart);
            }

            paintRect = Rectangle.FromLTRB(HorzAxis.FixedBoundary - HorzAxis.RollStartVisCellOffset, vertAxisContraBoundary,
                                          HorzAxis.ContraStart, VertAxis.GridClientStop);
            clipRect = Rectangle.FromLTRB(HorzAxis.FixedBoundary, vertAxisContraBoundary,
                                          HorzAxis.ContraStart, VertAxis.GridClientStop);
            PaintCells(e, FixedColCount + HorzAxis.RollStartVisCell, RowCount, ColCount, FullRowCount, paintRect, clipRect, BasePaintCellStates.Fixed);
          }

          // Contra Bottom-Right
          if ((ContraRowCount > 0) && (ContraColCount > 0))
          {

            if ((GridOptions.ContraVertBoundaryLine & Options) != 0)
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Left, false,
                ColCount, RowCount, FullRowCount,
                HorzAxis.ContraStart,
                vertAxisContraBoundary, VertAxis.GridClientStop);
            }

            if ((GridOptions.ContraHorzBoundaryLine & Options) != 0)
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Top, false,
                ColCount, RowCount, FullColCount,
                horzAxisContraBoundary,
                VertAxis.ContraStart, HorzAxis.GridClientStop);
            }

            if (((GridOptions.ContraVertBoundaryLine & Options) != 0) &&
                  ((GridOptions.ContraHorzBoundaryLine & Options) != 0))
            {
              PaintContraBorder(e.Graphics, GridCellBorderType.Top, true,
                ColCount, RowCount, FullColCount,
                HorzAxis.ContraStart,
                VertAxis.ContraStart, HorzAxis.ContraStart + 1);
            }

            paintRect = Rectangle.FromLTRB(horzAxisContraBoundary, vertAxisContraBoundary,
                                          HorzAxis.GridClientStop, VertAxis.GridClientStop);
            clipRect = paintRect;
            PaintCells(e, ColCount, RowCount, FullColCount, FullRowCount, paintRect, clipRect, BasePaintCellStates.Fixed);
          }

          // Empty Area Left + NO + Bottom for Contra
          if (HorzAxis.RollInClientBoundary < HorzAxis.ContraStart)
          {
            if (FixedRowCount > 0)
            {
              cellRect.X = HorzAxis.RollInClientBoundary;
              //      ACellRect.Top = 0;
              cellRect.Width = HorzAxis.ContraStart - cellRect.Left;
              cellRect.Height = VertAxis.GridClientStart - cellRect.Top;

              for (rowI = 0; rowI < FixedRowCount; rowI++)
              {
                cellRect.Y = cellRect.Bottom;
                cellRect.Height = RowHeights[rowI];
                PaintEmptyAreaCell(e.Graphics, -1, rowI, cellRect);
                //        OffsetRect(ACellRect, 0,  RowHeights[RowI]);
              }
            }

            cellRect.X = HorzAxis.RollInClientBoundary;
            cellRect.Height = VertAxis.FixedBoundary - VertAxis.RollStartVisCellOffset - cellRect.Top;
            cellRect.Width = HorzAxis.ContraStart - cellRect.Left;

            rec = Rectangle.FromLTRB(
                    HorzAxis.RollInClientBoundary, VertAxis.FixedBoundary,
                    cellRect.Right, VertAxis.ContraStart);
            oldClip = PaintingSetClip(e.Graphics, rec, CombineMode.Intersect);

            for (rowI = FixedRowCount + VertAxis.RollStartVisCell; rowI < RowCount; rowI++)
            {
              cellRect.Y = cellRect.Bottom;
              cellRect.Height = RowHeights[rowI];
              if (cellRect.Top > VertAxis.ContraStart)
                break;
              PaintEmptyAreaCell(e.Graphics, -1, rowI, cellRect);
            }

            PaintingSetClip(e.Graphics, oldClip, CombineMode.Replace);

            cellRect.X = HorzAxis.RollInClientBoundary;
            cellRect.Y = VertAxis.RollInClientBoundary;
            cellRect.Width = HorzAxis.ContraStart - cellRect.Left;
            cellRect.Height = VertAxis.ContraStart - cellRect.Top;
            PaintEmptyAreaCell(e.Graphics, -1, -1, cellRect);

            cellRect.X = HorzAxis.RollInClientBoundary;
            cellRect.Height = VertAxis.ContraStart - cellRect.Top;
            cellRect.Width = HorzAxis.ContraStart - cellRect.Left;

            for (rowI = RowCount; rowI < FullRowCount; rowI++)
            {
              cellRect.Y = cellRect.Bottom;
              cellRect.Height = RowHeights[rowI];

              if ((rowI == RowCount) && ((GridOptions.ContraHorzBoundaryLine & Options) != 0))
                cellRect.Height++;
              PaintEmptyAreaCell(e.Graphics, -1, rowI, cellRect);
            }

          }

          // Empty Area Bottom

          if (VertAxis.RollInClientBoundary < VertAxis.ContraStart)
          {
            if (FixedColCount > 0)
            {
              cellRect.Y = VertAxis.RollInClientBoundary;
              cellRect.Width = HorzAxis.GridClientStart - cellRect.Left;
              cellRect.Height = VertAxis.ContraStart - cellRect.Top;

              for (colI = 0; colI < FixedColCount; colI++)
              {
                cellRect.X = cellRect.Right;
                cellRect.Width = ColWidths[colI];
                PaintEmptyAreaCell(e.Graphics, colI, -1, cellRect);
              }
            }

            cellRect.X = HorzAxis.FixedBoundary - HorzAxis.RollStartVisCellOffset;
            cellRect.Y = VertAxis.RollInClientBoundary;
            cellRect.Width = 0;
            cellRect.Height = VertAxis.ContraStart - cellRect.Top;

            for (colI = HorzAxis.StartVisCell; colI < ColCount; colI++)
            {
              cellRect.X = cellRect.Right;
              cellRect.Width = ColWidths[colI];
              if (cellRect.Left > HorzAxis.ContraStart)
                break;
              PaintEmptyAreaCell(e.Graphics, colI, -1, cellRect);
            }

            cellRect.X = HorzAxis.ContraStart;
            cellRect.Y = VertAxis.RollInClientBoundary;
            cellRect.Width = 0;
            cellRect.Height = VertAxis.ContraStart - cellRect.Top;

            for (colI = ColCount; colI < FullColCount; colI++)
            {
              cellRect.X = cellRect.Right;
              cellRect.Width = ColWidths[colI];

              if ((colI == ColCount) && ((GridOptions.ContraVertBoundaryLine & Options) != 0))
                cellRect.Width++;
              PaintEmptyAreaCell(e.Graphics, colI, -1, cellRect);
            }

          }

          if ((gridState == BaseGridState.ColSizing) || (gridState == BaseGridState.RowSizing))
            PaintSizingLines(e.Graphics);

          PaintTrialInfo(e);

        }
        finally
        {
          if (clientClip != null)
            e.Graphics.Clip = clientClip;

        }
      }
      finally
      {
        ReleasePaintData();
      }
    }

    private void PaintTrialInfo(PaintEventArgs e)
    {
      Point pos = new Point(HorzAxis.ContraStart, VertAxis.ContraStart);
      GridWaterMark.PaintWaterMark(e.Graphics, this, pos);
    }

    protected virtual void InitPaintData()
    {
      if (ActualDrawStyle != null)
        ActualDrawStyle.CapturePaint(this);
    }

    protected virtual void ReleasePaintData()
    {
      if (ActualDrawStyle != null)
        ActualDrawStyle.ReleasePaint(this);
    }

    private void PaintCells(
      PaintEventArgs e,
      int col, int row,
      int stopCol, int stopRow,
      Rectangle paintRect,
      Rectangle clipRect,
      BasePaintCellStates cellTypeState)
    {
      int curCol;
      Rectangle calcPaintCellRect = new Rectangle();
      Rectangle paintCellRect;
      BasePaintCellStates cellPaintState;
      bool controlFocused;
      //GridRect sel = Selection;

      int startX = paintRect.Left;
      int startY = paintRect.Top;
      int stopX = paintRect.Right;
      int stopY = paintRect.Bottom;

      //clipRect = Rectangle.FromLTRB(StartX, StartY, StopX, StopY);

      Region oldClip = PaintingSetClip(e.Graphics, clipRect, CombineMode.Intersect);

      int curRow = row;
      calcPaintCellRect.Y = startY;
      while ((calcPaintCellRect.Top < stopY) && (curRow < stopRow))
      {
        curCol = col;
        calcPaintCellRect.X = startX;
        calcPaintCellRect.Height = RowHeights[curRow];
        while ((calcPaintCellRect.Left < stopX) && (curCol < stopCol))
        {
          calcPaintCellRect.Width = ColWidths[curCol];
          if ((calcPaintCellRect.Right > calcPaintCellRect.Left) && 
              PaintingClipRectangleIntersectsWith(e.ClipRectangle, calcPaintCellRect)) //&&&& RectVisible(Canvas.Handle, Where) )
          {
            cellPaintState = cellTypeState;
            controlFocused = Focused;

            cellPaintState = GetCellPaintState(curCol, curRow, controlFocused) | cellTypeState;

            paintCellRect = calcPaintCellRect;
            PaintCellArea(e.Graphics, curCol, curRow, paintCellRect, cellPaintState);
          }
          calcPaintCellRect.X = calcPaintCellRect.Right;
          curCol++;
        }
        calcPaintCellRect.Y = calcPaintCellRect.Bottom;
        curRow++;
      }

      PaintingSetClip(e.Graphics, oldClip, CombineMode.Replace);
    }

    protected virtual BasePaintCellStates GetCellPaintState(int col, int row, bool controlFocused)
    {
      BasePaintCellStates cellPaintState = 0;
      if (row == Row)
        cellPaintState = cellPaintState | BasePaintCellStates.CurrentRow;
      if (col == Col)
        cellPaintState = cellPaintState | BasePaintCellStates.CurrentCol;
      if ((row == Row) && (col == Col))
      {
        cellPaintState = cellPaintState | BasePaintCellStates.Current;
        cellPaintState = cellPaintState | BasePaintCellStates.Selected;
      }
      if ((col == MouseHolderCellCoord.X) && (row == MouseHolderCellCoord.Y))
        cellPaintState = cellPaintState | BasePaintCellStates.HotTrack;
      if (col == MouseHolderCellCoord.X)
        cellPaintState = cellPaintState | BasePaintCellStates.ColHotTrack;
      if (row == MouseHolderCellCoord.Y)
        cellPaintState = cellPaintState | BasePaintCellStates.RowHotTrack;
      if (controlFocused && ((BasePaintCellStates.Current & cellPaintState) != 0))
        cellPaintState = cellPaintState | BasePaintCellStates.Focused;
      if (Options.HasFlag(GridOptions.RowSelect) && (row == Row))
        cellPaintState = cellPaintState | BasePaintCellStates.RowSelected;
      //if (PointInGridRect(row, row, sel))
      //  cellState = cellState | BasePaintCellState.Selected;

      return cellPaintState;
    }

    public Region PaintingSetClip(Graphics graphics, Rectangle rect, CombineMode combineMode)
    {
      Rectangle absRect;

      if (UseRightToLeft)
        absRect = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, rect);
      else
        absRect = rect;

      Region oldClip = graphics.Clip;
      graphics.SetClip(absRect, combineMode);

      return oldClip;
    }

    public Region PaintingSetClip(Graphics graphics, Region region, CombineMode combineMode)
    {
      Region oldClip = graphics.Clip;
      graphics.SetClip(region, combineMode);
      return oldClip;
    }

    public bool PaintingClipRectangleIntersectsWith(Rectangle clipRectangle, Rectangle rect)
    {
      Rectangle absRect;

      if (UseRightToLeft)
        absRect = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, rect);
      else
        absRect = rect;
      return clipRectangle.IntersectsWith(absRect);
    }

    public void PaintingDrawLine(Graphics g, Color color, DashStyle style, Color backColor, Point startPos, Point finishPos)
    {
      Point absStartPos = startPos; 
      Point absFinishPos = finishPos;
      Pen pen = new Pen(color);
      try
      {
        if (style != DashStyle.Solid && backColor != Color.Empty)
        {
          PaintingDrawLine(g, backColor, DashStyle.Solid, Color.Empty, startPos, finishPos);
        }

        pen.DashStyle = style;
        if (UseRightToLeft)
        {
          absStartPos = EhLibUtils.RightToLeftFlipPoint(ClientRectangle, startPos);
          absFinishPos = EhLibUtils.RightToLeftFlipPoint(ClientRectangle, finishPos);
        }
        g.DrawLine(pen, absStartPos, absFinishPos);
      }
      finally
      {
        pen.Dispose();
      }
    }

    public void PaintingFillRectangle(Graphics g, Brush brush, Rectangle rect)
    {
      //-return;
      Rectangle absRect = rect;

      if (UseRightToLeft)
        absRect = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, rect);

      g.FillRectangle(brush, absRect);
    }

    public void PaintingDrawText(Graphics g, string text, Font font, Rectangle bounds,
      Color foreColor, HorizontalAlignment horzAlign, VerticalAlignment vertAlign, bool wordWrap)
    {
      //-return;
      TextFormatFlagsEh flags = TextFormatFlagsEh.None;

      Rectangle absRect = bounds;

      if (UseRightToLeft)
      {
        absRect = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, bounds);

        if (horzAlign == HorizontalAlignment.Left)
          horzAlign = HorizontalAlignment.Right;
        else if (horzAlign == HorizontalAlignment.Right)
          horzAlign = HorizontalAlignment.Left;
      }

      if (wordWrap)
        flags = flags | TextFormatFlagsEh.WordBreak;

      EhLibUtils.DrawText(g, text, font, absRect, foreColor, horzAlign, vertAlign, flags);
    }

    public void PaintingDrawImage(Graphics g, Image image, Rectangle rect)
    {
      if (UseRightToLeft)
        rect = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, rect);
      g.DrawImage(image, rect);
    }

    public bool PointInGridRect(int col, int row, Rectangle rect)
    {
      return (col >= rect.Left) && (col <= rect.Right) && (row >= rect.Top) && (row <= rect.Bottom);
    }

    public void PaintContraBorder(Graphics g, GridCellBorderType cellBorder, bool contraPoint, int col, int row,
      int stopCell, int startX, int startY, int stopPos)
    {
      bool isPaint;
      Color color;
      DashStyle style;
      bool isExtent;
      int i;
      Rectangle rectWhere = Rectangle.Empty;

      //dataColIndex dataRowIndex
      //BaseGridCellBorderEventArgs e = new BaseGridCellBorderEventArgs(col, row, col, row, cellBorder);

      if (contraPoint)
      {
        ProcessGetCellBorders(col, row, cellBorder, out isPaint, out color, out style, out isExtent);
        //OnGetCellBorderParams(e);
        if (isPaint)
        {
          //          Canvas.Pen.Color = BorderColor;
          //          DrawPolyline([Point(StartX, StartY), Point(StartX+1, StartY)]);
        }
      }
      else if (cellBorder == GridCellBorderType.Left)
      {
        rectWhere.Y = startY;
        rectWhere.X = startX;
        rectWhere.Width = startX - rectWhere.X;
        for (i = row; i < stopCell; i++)
        {
          //BaseGridCellBorderEventArgs ei = new BaseGridCellBorderEventArgs(col, i, col, i, cellBorder);

          rectWhere.Height = RowHeights[i];
          if (rectWhere.Top >= stopPos)
            return;
          ProcessGetCellBorders(col, i, cellBorder, out isPaint, out color, out style, out isExtent);
          //OnGetCellBorderParams(e);
          if (isPaint)
          {
            PaintingDrawLine(g, color, style, BackColor, new Point(rectWhere.Left, rectWhere.Top), new Point(rectWhere.Left, rectWhere.Bottom));
          }
          rectWhere.Y = rectWhere.Bottom;
        }
      }
      else if (cellBorder == GridCellBorderType.Top)
      {
        rectWhere.X = startX;
        rectWhere.Y = startY;
        rectWhere.Height = 0;
        for (i = col; i < stopCell; i++)
        {
          rectWhere.Width = ColWidths[i];
          if (rectWhere.Left >= stopPos)
            return;
          ProcessGetCellBorders(i, row, cellBorder, out isPaint, out color, out style, out isExtent);

          if (isPaint)
          {
            PaintingDrawLine(g, color, style, BackColor, new Point(rectWhere.Left, rectWhere.Top), new Point(rectWhere.Right, rectWhere.Top));
          }
          rectWhere.X = rectWhere.Right;
        }
      }
    }

    protected virtual void PaintCellArea(Graphics g, int colIndex, int rowIndex, Rectangle rect, BasePaintCellStates state)
    {
      DrawBordersForCellArea(g, colIndex, rowIndex, ref rect, state);
      PaintCell(g, colIndex, rowIndex, rect, state);
    }

    public void DrawBordersForCellArea(Graphics g, int col, int row, ref Rectangle rect, BasePaintCellStates state)
    {
      DrawBordersForCellArea(g, col, row, ref rect, state, true, true);
    }

    public void DrawBordersForCellArea(Graphics g, int col, int row, ref Rectangle rect, BasePaintCellStates state, bool drawRightBorder, bool drawBottomBorder)
    {
      bool rIsPaint = false;
      Color rColor = Color.Empty;
      DashStyle rStyle = DashStyle.Solid;
      bool rIsExtent = false;
      if (drawRightBorder)
        ProcessGetCellBorders(col, row, GridCellBorderType.Right, out rIsPaint, out rColor, out rStyle, out rIsExtent);

      bool bIsPaint = false;
      Color bColor = Color.Empty;
      DashStyle bStyle = DashStyle.Solid;
      bool bIsExtent = false;
      if (drawBottomBorder)
        ProcessGetCellBorders(col, row, GridCellBorderType.Bottom, out bIsPaint, out bColor, out bStyle, out bIsExtent);

      DrawBordersForRect(g, ref rect, rIsPaint, bIsPaint, rColor, bColor, rStyle, bStyle, rIsExtent, bIsExtent);
    }

    public void DrawBordersForRect(Graphics g, ref Rectangle rect, bool rIsDraw, bool bIsDraw,
      Color rBorderColor, Color bBorderColor, DashStyle rStyle, DashStyle bStyle, 
      bool rIsExtent, bool bIsExtent)
    {
      bool styleFactor = (rStyle != DashStyle.Solid);
      Rectangle rBorderRect, bBorderRect;
      if (rIsDraw && rIsExtent && bIsDraw && bIsExtent)
      {
        if (rStyle != bStyle)
        {
          if (styleFactor)
            rIsExtent = false;
          else
            bIsExtent = false;
        }
        else if (rBorderColor != bBorderColor)
        {
          float luminanceFactor = GetColorLuminance(rBorderColor) - GetColorLuminance(bBorderColor);
          if (luminanceFactor > 0)
            rIsExtent = false;
          else
            bIsExtent = false;
        }
      }

      if (rIsDraw)
      {
        rBorderRect = rect;
        if (rIsExtent)
          rBorderRect.Height++;
        PaintingDrawLine(g, rBorderColor, rStyle, BackColor, new Point(rBorderRect.Right - 1, rBorderRect.Top), new Point(rBorderRect.Right - 1, rBorderRect.Bottom - 2));
      }

      if (bIsDraw)
      {
        bBorderRect = rect;
        if (bIsExtent)
          bBorderRect.Width++;
        PaintingDrawLine(g, bBorderColor, bStyle, BackColor, new Point(bBorderRect.Left, bBorderRect.Bottom - 1), new Point(bBorderRect.Right - 2, bBorderRect.Bottom - 1));
      }

      if (rIsDraw)
        rect.Width--;
      if (bIsDraw)
        rect.Height--;
    }

    public void PrintBordersForRect(PrintServiceEventArgs e, ref Rectangle rect, bool rIsDraw, bool bIsDraw,
      Color rBorderColor, Color bBorderColor, DashStyle rStyle, DashStyle bStyle,
      bool rIsExtent, bool bIsExtent)
    {
      bool styleFactor = (rStyle != DashStyle.Solid);
      Rectangle rBorderRect, bBorderRect;
      if (rIsDraw && rIsExtent && bIsDraw && bIsExtent)
      {
        if (rStyle != bStyle)
        {
          if (styleFactor)
            rIsExtent = false;
          else
            bIsExtent = false;
        }
        else if (rBorderColor != bBorderColor)
        {
          float luminanceFactor = GetColorLuminance(rBorderColor) - GetColorLuminance(bBorderColor);
          if (luminanceFactor > 0)
            rIsExtent = false;
          else
            bIsExtent = false;
        }
      }

      if (rIsDraw)
      {
        rBorderRect = rect;
        if (rIsExtent)
          rBorderRect.Height++;
        e.PrintLine(rBorderColor, new Point(rBorderRect.Right - 1, rBorderRect.Top), new Point(rBorderRect.Right - 1, rBorderRect.Bottom - 2));
      }

      if (bIsDraw)
      {
        bBorderRect = rect;
        if (bIsExtent)
          bBorderRect.Width++;
        e.PrintLine(bBorderColor, new Point(bBorderRect.Left, bBorderRect.Bottom - 1), new Point(bBorderRect.Right - 2, bBorderRect.Bottom - 1));
      }

      if (rIsDraw)
        rect.Width--;
      if (bIsDraw)
        rect.Height--;
    }

    public static float GetColorLuminance(Color color)
    {
      return color.GetBrightness();
    }

    protected virtual void PaintCell(Graphics g, int colIndex, int rowIndex, Rectangle rect, BasePaintCellStates state)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      Point inCellMousePos;
      if ((BasePaintCellStates.HotTrack & state) != 0)
        inCellMousePos = MouseHolderCellMousePos;
      else
        inCellMousePos = new Point(-1, -1);

      BaseGridCellPaintEventArgs pea = cell.GetCellPaintParams(g, colIndex, rowIndex, rect, state, areaColIndex, areaRowIndex, inCellMousePos);

      cell.ProcessPaint(pea);
    }

    protected internal virtual bool IsActiveControl()
    {
      return ContainsFocus;
    }

    protected internal virtual void UpdateOutBoundaryIndents()
    {
      OutBoundaryData.TopIndent = 0;
      OutBoundaryData.LeftIndent = 0;
      OutBoundaryData.BottomIndent = 0;
      OutBoundaryData.RightIndent = 0;
    }

    private void PaintwOutBoundaryData()
    {

    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);
      UpdateBoundaries();
    }

    protected override void OnGotFocus(EventArgs e)
    {
      base.OnGotFocus(e);
      InvalidateGrid();
    }

    protected override void OnLostFocus(EventArgs e)
    {
      base.OnLostFocus(e);
      InvalidateGrid();
    }

    protected override void OnEnter(EventArgs e)
    {
      base.OnEnter(e);
      InvalidateGrid();
    }

    protected override void OnLeave(EventArgs e)
    {
      base.OnLeave(e);
      InvalidateGrid();
    }

    protected override void OnHandleCreated(EventArgs e)
    {
      base.OnHandleCreated(e);
      OnResize(e);
    }

    protected override bool IsInputKey(Keys keyData)
    {
      switch (keyData & Keys.KeyCode)
      {
        case Keys.Right:
        case Keys.Left:
        case Keys.Up:
        case Keys.Down:
          return true;
        case Keys.Tab:
          {
            Keys altData = (keyData & (Keys.Control | Keys.Shift | Keys.Alt));
            if ((altData == 0 || altData == Keys.Shift) && ((GridOptions.Tabs & Options) != 0))
              return true;
            else
              break;
          }
      }
      return base.IsInputKey(keyData);
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {

      int nextPageRow, prevPageRow;
      int rtlFactor;
      //bool needsInvalidating;
      GridCoord newAnchor;

      base.OnKeyDown(e);

      //if (!IsProcessKeyInBaseGrid(e.KeyData)) return;
      //needsInvalidating = false;

      CurrentCellMan.OnKeyDown(e);
      if (e.Handled) return;

      if (!UseRightToLeft)
        rtlFactor = 1;
      else
        rtlFactor = -1;
      GridCoord newCurrent = curCell;

      int pageWidth = 0;

      //      CalcPageExtents();
      if (e.Shift && ((GridOptions.RangeSelect & Options) != 0))
      {
        newAnchor = anchorCell;
        switch (e.KeyCode)
        {
          case Keys.Up:
            newAnchor.Y--;
            break;
          case Keys.Down:
            newAnchor.Y++;
            break;
          case Keys.Left:
            newAnchor.X--;
            break;
          case Keys.Right:
            newAnchor.X++;
            break;
        }
        Restrict(ref newAnchor,
          FixedColCount - FrozenColCount, FixedRowCount - FrozenRowCount,
          FullColCount - 1, FullRowCount - 1);
        MoveAnchorCell(newAnchor.X, newAnchor.Y, true);
      }
      else
      {
        if (e.Control)
        {
          switch (e.KeyCode)
          {
            case Keys.Up:
              break;
            case Keys.Down:
            {
              break;
            }
            case Keys.Left:
              newCurrent.X = newCurrent.X - pageWidth * rtlFactor;
              break;
            case Keys.Right:
              newCurrent.X = newCurrent.X + pageWidth * rtlFactor;
              break;
            case Keys.PageUp:
              //              NewCurrent.Y = TopRow;
              break;
            case Keys.PageDown:
              //              NewCurrent.Y = TopRow;
              break;
            case Keys.Home:
              newCurrent.X = FixedColCount;
              newCurrent.Y = FixedRowCount;
              //                NeedsInvalidating = UseRightToLeftAlignment;
              break;
            case Keys.End:
              newCurrent.X = ColCount - 1;
              newCurrent.Y = RowCount - 1;
              //                NeedsInvalidating = UseRightToLeftAlignment;
              break;
          }
        }
        else
        {
          switch (e.KeyCode)
          {
            case Keys.Up:
              if (!e.Shift)
                newCurrent.Y--;
              break;
            case Keys.Down:
              if (!e.Shift)
                newCurrent.Y++;
              break;
            case Keys.Left:
              if (!e.Shift)
              {
                if (Options.HasFlag(GridOptions.RowSelect))
                  ScrollMessage(Orientation.Horizontal, ScrollEventType.SmallDecrement);
                else
                  newCurrent.X = NextSelectableCellFor(GridCoord(newCurrent.X - rtlFactor, newCurrent.Y)).X;
              }
              break;
            case Keys.Right:
              if (!e.Shift)
              {
                if (Options.HasFlag(GridOptions.RowSelect))
                  ScrollMessage(Orientation.Horizontal, ScrollEventType.SmallIncrement);
                else
                  newCurrent.X = NextSelectableCellFor(GridCoord(newCurrent.X + rtlFactor, newCurrent.Y)).X;
              }
              break;
            case Keys.PageDown:
              if (!e.Shift)
              {
                CalcPageExtents(out nextPageRow, out prevPageRow);
                newCurrent.Y = nextPageRow;
              }
              break;
            case Keys.PageUp:
              if (!e.Shift)
              {
                CalcPageExtents(out nextPageRow, out prevPageRow);
                newCurrent.Y = prevPageRow;
              }
              break;
            case Keys.Home:
              if (!e.Shift)
              {
                if (Options.HasFlag(GridOptions.RowSelect))
                  ScrollMessage(Orientation.Horizontal, ScrollEventType.First);
                else
                  newCurrent.X = FixedColCount;
              }
              break;
            case Keys.End:
              if (!e.Shift)
              {
                if (Options.HasFlag(GridOptions.RowSelect))
                  ScrollMessage(Orientation.Horizontal, ScrollEventType.Last);
                else
                  newCurrent.X = ColCount - 1;
              }
              break;
            case Keys.Tab:
              //} while ( (/*TabStops[NewCurrent.X] ||*/ (NewCurrent.X == curCell.X)));
              e.Handled = ProcessTabKey(e.KeyData);
              if (e.Handled)
                return;
              else
                break;
            case Keys.F2:
              //              EditorMode = true; 
              break;
          }
        }
        Restrict(ref newCurrent,
          FixedColCount - FrozenColCount, FixedRowCount - FrozenRowCount,
          ColCount - 1, RowCount - 1);
        if ((newCurrent.X != Col) || (newCurrent.Y != Row))
          InteractiveFocusCell(newCurrent.X, newCurrent.Y, InteractiveActionSource.Keyboard);

        //if (needsInvalidating == true) InvalidateGrid();
      }
    }

    protected override void OnKeyPress(KeyPressEventArgs e)
    {
      base.OnKeyPress(e);
      if (e.Handled) return;

      CurrentCellMan.OnKeyPress(e);
    }

    protected override void OnKeyUp(KeyEventArgs e)
    {
      base.OnKeyUp(e);
      if (e.Handled) return;

      CurrentCellMan.OnKeyUp(e);
    }

    protected virtual bool ProcessTabKey(Keys keyData)
    {
      if ((keyData & Keys.Alt) != Keys.Alt)
      {
        GridMoveCellDirection direction;
        if ((keyData & Keys.Shift) == Keys.Shift)
          direction = GridMoveCellDirection.Backward;
        else
          direction = GridMoveCellDirection.Forward;

        bool result = NextCol(direction, true, true, false, true);
        return result;
      }

      return false;
    }

    protected virtual bool NextCol(GridMoveCellDirection direction, bool nextRowOnLastCol, bool circleCol, bool circleRow, bool interactive)
    {
      GridCoord newCurrent = curCell;

      if (direction == GridMoveCellDirection.Backward)
      {
        newCurrent.X--;
        if (newCurrent.X < FixedColCount)
        {
          newCurrent.X = ColCount - 1;
          newCurrent.Y--;
          if (newCurrent.Y < FixedRowCount)
            newCurrent.Y = RowCount - 1;
        }
      }
      else
      {
        newCurrent.X++;
        if (newCurrent.X >= ColCount)
        {
          newCurrent.X = FixedColCount;
          newCurrent.Y++;
          if (newCurrent.Y >= RowCount)
            newCurrent.Y = FixedRowCount;
        }
      }

      Restrict(ref newCurrent,
        FixedColCount - FrozenColCount, FixedRowCount - FrozenRowCount,
        ColCount - 1, RowCount - 1);
      if ((newCurrent.X != Col) || (newCurrent.Y != Row))
      {
        if (interactive)
          InteractiveFocusCell(newCurrent.X, newCurrent.Y, InteractiveActionSource.Keyboard);
        else
          FocusCell(newCurrent.X, newCurrent.Y, false);
      }

      return true;
    }

    protected virtual bool NextRow(GridMoveCellDirection direction, bool nextRowOnLastCol, bool circleCol, bool circleRow, bool interactive)
    {
      return true;
    }

    public void RestartMouseHoverEvent()
    {
      ResetMouseEventArgs();
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
      Point cellMousePos = new Point();
      Rectangle cellRect;
      BaseGridState newState;

      if (UseRightToLeft)
      {
        Point rtlPos = EhLibUtils.RightToLeftFlipPoint(ClientRectangle, e.Location);
        e = new MouseEventArgs(e.Button, e.Clicks, rtlPos.X, rtlPos.Y, e.Delta);
      }

      MouseDownPos = e.Location;

      base.OnMouseDown(e);

      //HideEdit(true);
      if (!DesignMode && (CanFocus | (FindForm() == null)))
      {
        FocusGrid();
        if (!IsActiveControl())
        {
          Capture = false;
          return;
        }
      }

      if (e.Button == MouseButtons.Left)
      {
        int sizingIndex;
        int sizingPos;
        int sizingOffset;
        CalcSizingState(e.X, e.Y, out newState, out sizingIndex, out sizingPos, out sizingOffset);
        if (newState != BaseGridState.Normal)
        {
          if (newState == BaseGridState.ColSizing)
            StartColSizing(sizingIndex, e.X, e.Y, sizingPos, sizingOffset);
          else if (newState == BaseGridState.RowSizing)
            StartRowSizing(sizingIndex, e.X, e.Y, sizingPos, sizingOffset);
          return;
        }
      }

      MouseDownCellCoord = CalcCellCoordFromPoint(e.X, e.Y);
      MouseDownButton = e.Button;
      if ((MouseDownCellCoord.X >= 0) && (MouseDownCellCoord.Y >= 0))
      {
        cellRect = CellRect(MouseDownCellCoord.X, MouseDownCellCoord.Y);
        cellMousePos.X = e.X - cellRect.Left;
        cellMousePos.Y = e.Y - cellRect.Top;
        ProcessCellMouseDown(MouseDownCellCoord.X, MouseDownCellCoord.Y, cellMousePos.X, cellMousePos.Y, cellRect, e);
        MouseDownCellCoordPressed = true;
      }
    }

    protected virtual void ProcessCellMouseDown(int colIndex, int rowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "Grid.OnCellMouseUp Cell = null");

      BaseGridCellMouseEventArgs e = cell.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);
      OnCellMouseDown(cell, e);
    }

    protected virtual void OnCellMouseDown(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      InvalidateCell(e.ColIndex, e.RowIndex);
      cell.ProcessMouseDown(e);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
      bool checkMoveAndScroll;
      GridCoord minCell, maxCell;
      Rectangle cellRect;
      Point cellMousePos = Point.Empty;

      if (UseRightToLeft)
      {
        Point rtlPos = EhLibUtils.RightToLeftFlipPoint(ClientRectangle, e.Location);
        e = new MouseEventArgs(e.Button, e.Clicks, rtlPos.X, rtlPos.Y, e.Delta);
      }

      GridCoord cellHit = CalcCellCoordFromPoint(e.X, e.Y);
      GridCoord cellHit2 = MouseCoord(e.X, e.Y, false);
      if ((cellHit.X < 0) || (cellHit.X >= FullColCount) || (cellHit.Y < 0) || (cellHit.Y >= FullRowCount))
      {
        cellHit2.X = -1;
        cellHit2.Y = -1;
      }

      switch (gridState)
      {
        case BaseGridState.Selecting:
        case BaseGridState.RowMoving:

          if (DesignMode)
            checkMoveAndScroll = true;
          else
          {
            checkMoveAndScroll = false;
            minCell.X = FixedColCount - FrozenColCount;
            maxCell.X = Math.Min(HorzAxis.RollLastFullVisCell + HorzAxis.FixedCellCount, HorzAxis.CellCount - 1);
            minCell.Y = FixedRowCount - FrozenRowCount;
            maxCell.Y = Math.Min(VertAxis.RollLastFullVisCell + VertAxis.FixedCellCount, VertAxis.CellCount - 1);
            if ((cellHit.X >= minCell.X) & (cellHit.X <= maxCell.X))
            {
              checkMoveAndScroll = true;
              if ((cellHit.Y < minCell.Y) || (cellHit.Y > maxCell.Y))
                cellHit.Y = anchorCell.Y;
            }
            else
            {
              if ((cellHit.Y >= minCell.Y) && (cellHit.Y <= maxCell.Y))
              {
                checkMoveAndScroll = true;
                if ((cellHit.X < minCell.X) || (cellHit.X > maxCell.X))
                  cellHit.X = anchorCell.X;
              }
            }
          }

          if (checkMoveAndScroll)
          {
            switch (gridState)
            {
              case BaseGridState.Selecting:
                if (((cellHit.X != anchorCell.X) || (cellHit.Y != anchorCell.Y)))
                  MoveAnchorCell(cellHit.X, cellHit.Y, true);
                break;
              case BaseGridState.ColMoving:
                MoveAndScroll(e.X, cellHit.X, HorzAxis, Orientation.Horizontal, new Point(e.X, e.Y));
                break;
              case BaseGridState.RowMoving:
                MoveAndScroll(e.Y, cellHit.Y, VertAxis, Orientation.Vertical, new Point(e.X, e.Y));
                break;
            }
          }
          break;

        case BaseGridState.ColMoving:

          if (MoveNScrollService.Active)
            MoveNScrollService.MouseMove(e);
          break;

        case BaseGridState.RowSizing:
        case BaseGridState.ColSizing:
          DrawSizingLine();
          if (gridState == BaseGridState.RowSizing)
            SizingPos = e.Y + SizingOffset;
          else
            SizingPos = e.X + SizingOffset;
          SizingPosChanged = true;
          DrawSizingLine();
          break;
        default:
          UpdateHotTackInfo(e.X, e.Y);
          break;
      }
      base.OnMouseMove(e);

      UpdateCursor(e);

//- Send mouse move to Captured cell
      if ((MouseDownCellCoord.X >= 0) && (MouseDownCellCoord.Y >= 0))
      {
        cellHit = MouseDownCellCoord;
        cellHit2 = MouseDownCellCoord;
      }

      if ((cellHit.X >= 0) && (cellHit.Y >= 0))
      {
        cellRect = CellRect(cellHit.X, cellHit.Y);
        cellMousePos.X = e.X - cellRect.Left;
        cellMousePos.Y = e.Y - cellRect.Top;
      }
      else
      {
        cellRect = Rectangle.Empty;
        cellMousePos.X = -1;
        cellMousePos.Y = -1;
      }

      if (MouseHolderCellCoord != cellHit2)
      {
        if (MouseHolderCellCoord != new GridCoord(-1, -1) &&
            MouseHolderCellCoord.X < FullColCount &&
            MouseHolderCellCoord.Y < FullRowCount)
        {
          ProcessCellMouseLeave(MouseHolderCellCoord.X, MouseHolderCellCoord.Y, cellRect, cellHit2.X, cellHit2.Y);
        }
      }

      if ((cellHit.X >= 0) && (cellHit.Y >= 0))
      {
        mouseHolderCellMousePos = cellMousePos;
        ProcessCellMouseMove(cellHit.X, cellHit.Y, cellMousePos.X, cellMousePos.Y, cellRect, e);
      }

      if (MouseHolderCellCoord != cellHit2)
      {
        GridCoord oldMouseHolderCellCoord = MouseHolderCellCoord;
        mouseHolderCellCoord = cellHit2;
        if (cellHit2 != new GridCoord(-1, -1))
        {
          ProcessCellMouseEnter(cellHit2.X, cellHit2.Y, cellRect, oldMouseHolderCellCoord.X, oldMouseHolderCellCoord.Y);
        }
      }

    }

    public void MoveAndScrollHelpServiceEventHandler(MoveAndScrollService service, MouseEventArgs e)
    {
      bool checkMoveAndScroll;
      GridCoord minCell, maxCell;

      GridCoord cellHit = CalcCellCoordFromPoint(e.X, e.Y);

      if (DesignMode)
        checkMoveAndScroll = true;
      else
      {
        checkMoveAndScroll = false;
        if (e.X > MoveNScrollService.ClientRect.Right)
        {
          checkMoveAndScroll = true;
          cellHit.X = HorzAxis.CellCount - 1;
        }
        else if (e.X < MoveNScrollService.ClientRect.Left)
        {
          checkMoveAndScroll = true;
          cellHit.X = HorzAxis.FixedCellCount - 1;
        }
        else
        {
          minCell.X = FixedColCount - FrozenColCount;
          maxCell.X = Math.Min(HorzAxis.RollLastVisCell + HorzAxis.FixedCellCount, HorzAxis.CellCount - 1);
          minCell.Y = FixedRowCount - FrozenRowCount;
          maxCell.Y = Math.Min(VertAxis.RollLastVisCell + VertAxis.FixedCellCount, VertAxis.CellCount - 1);
          if ((cellHit.X >= minCell.X) && (cellHit.X <= maxCell.X))
          {
            checkMoveAndScroll = true;
            if ((cellHit.Y < minCell.Y) || (cellHit.Y > maxCell.Y))
              cellHit.Y = anchorCell.Y;
          }
          else
          {
            if ((cellHit.Y >= minCell.Y) && (cellHit.Y <= maxCell.Y))
            {
              checkMoveAndScroll = true;
              if ((cellHit.X < minCell.X) || (cellHit.X > maxCell.X))
                cellHit.X = anchorCell.X;
            }
          }
        }
      }
      if (checkMoveAndScroll)
      {
        switch (gridState)
        {
          case BaseGridState.Selecting:
            if (((cellHit.X != anchorCell.X) || (cellHit.Y != anchorCell.Y)))
              MoveAnchorCell(cellHit.X, cellHit.Y, true);
            break;
          case BaseGridState.ColMoving:
            MoveAndScroll(e.X, cellHit.X, HorzAxis, Orientation.Horizontal, new Point(e.X, e.Y));
            break;
          case BaseGridState.RowMoving:
            MoveAndScroll(e.Y, cellHit.Y, VertAxis, Orientation.Vertical, new Point(e.X, e.Y));
            break;
        }
      }
    }

    protected virtual void ProcessCellMouseMove(int colIndex, int rowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "Grid.OnCellMouseUp Cell = null");

      BaseGridCellMouseEventArgs e = cell.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);
      OnCellMouseMove(cell, e);
    }

    protected virtual void OnCellMouseMove(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      if ((e.ColIndex == MouseDownCellCoord.X) &&
          (e.RowIndex == MouseDownCellCoord.Y) &&
          (e.InCellX >= 0) &&
          (e.InCellY >= 0) &&
          (e.InCellX < ColWidths[e.ColIndex]) &&
          (e.InCellY < RowHeights[e.RowIndex])
          )
      {
        //Debug.WriteLine("Down:" + e.InCellX.ToString() + ":" + e.InCellY.ToString());
        if (MouseDownCellCoordPressed == false)
        {
          MouseDownCellCoordPressed = true;
          InvalidateCell(e.ColIndex, e.RowIndex);
        }
      }
      else if (MouseDownCellCoordPressed == true)
      {
        MouseDownCellCoordPressed = false;
        InvalidateCell(e.ColIndex, e.RowIndex);
      }

      cell.ProcessMouseMove(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
      int newSize;
      Rectangle cellRect;
      Point cellMousePos;
      //GridCoord cellHit;

      if (UseRightToLeft)
      {
        Point rtlPos = EhLibUtils.RightToLeftFlipPoint(ClientRectangle, e.Location);
        e = new MouseEventArgs(e.Button, e.Clicks, rtlPos.X, rtlPos.Y, e.Delta);
      }

      //cellHit = CalcCellCoordFromPoint(e.X, e.Y);
      try
      {
        switch (gridState)
        {
          case BaseGridState.Selecting:
            OnMouseMove(e);
            SetGridTimer(false, 0);
            UpdateEdit();
            break;
          case BaseGridState.RowSizing:
          case BaseGridState.ColSizing:
            DrawSizingLine();
            //if ((gridState == BaseGridState.ColSizing) && UseRightToLeft)
            //  SizingPos = ClientWidth - SizingPos;
            if (SizingPosChanged)
            {
              if (gridState == BaseGridState.ColSizing)
              {
                newSize = ResizeLine(HorzAxis);
                if (newSize > 1)
                {
                  InteractiveSetColWidths(SizingIndex, newSize);
                }
              }
              else
              {
                newSize = ResizeLine(VertAxis);
                if (newSize > 1)
                {
                  RowHeights[SizingIndex] = newSize;
                }
              }
            }
            break;

          case BaseGridState.ColMoving:
            if (MoveNScrollService.Active)
              MoveNScrollService.Release();
            HideMove();
            SetGridTimer(false, 0);
            if (EndColumnDrag(ref MoveFromIndex, ref MoveToIndex, new Point(e.X, e.Y)) && 
                MoveFromIndex != MoveToIndex)
            {
              InteractiveMoveColumn(MoveFromIndex, MoveToIndex);
            }
            UpdateEdit();
            break;

          case BaseGridState.RowMoving:
            HideMove();
            SetGridTimer(false, 0);
            if (EndRowDrag(ref MoveFromIndex, ref MoveToIndex, new Point(e.X, e.Y)) && (MoveFromIndex != MoveToIndex))
            {
              MoveRow(MoveFromIndex, MoveToIndex);
              //            UpdateDesigner;
            }
            UpdateEdit();
            break;
          default:
            UpdateEdit();
            break;
        }
        base.OnMouseUp(e);
      }
      finally
      {
        if (GridState != BaseGridState.Normal)
        {
          GridState = BaseGridState.Normal;
          InvalidateGrid();
        }
        UpdateCursor(e);
        //Cursor = DefaultCursor;
      }

      if (MouseDownCellCoord.X >= 0 && MouseDownCellCoord.Y >= 0 && 
          MouseDownCellCoord.X < FullColCount && MouseDownCellCoord.Y < FullRowCount)
      {
        cellRect = CellRect(MouseDownCellCoord.X, MouseDownCellCoord.Y);
        cellMousePos = new Point(e.X - cellRect.Left, e.Y - cellRect.Top);
        ProcessCellMouseUp(MouseDownCellCoord.X, MouseDownCellCoord.Y, cellMousePos.X, cellMousePos.Y, cellRect, e);
      }
      MouseDownCellCoord = new GridCoord(-1, -1);
      MouseDownButton = MouseButtons.None;
      MouseDownCellCoordPressed = false;
    }

    protected virtual void ProcessCellMouseUp(int colIndex, int rowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "Grid.OnCellMouseUp Cell = null");

      BaseGridCellMouseEventArgs e = cell.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);
      OnCellMouseUp(cell, e);
    }

    protected virtual void OnCellMouseUp(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      InvalidateCell(e.ColIndex, e.RowIndex);
      cell.ProcessMouseUp(e);
    }

    protected override void OnMouseClick(MouseEventArgs e)
    {
      Rectangle cellRect;
      Point cellMousePos;

      base.OnMouseClick(e);

      GridCoord cellHit = CalcCellCoordFromPoint(e.X, e.Y);
      if ((cellHit.X >= 0) && (cellHit.Y >= 0))
      {
        cellRect = CellRect(cellHit.X, cellHit.Y);
        cellMousePos = new Point(e.X - cellRect.Left, e.Y - cellRect.Top);
        ProcessCellMouseClick(cellHit.X, cellHit.Y, cellMousePos.X, cellMousePos.Y, cellRect, e);
      }
    }

    protected virtual void ProcessCellMouseClick(int colIndex, int rowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "Grid.OnCellMouseClick Cell = null");

      BaseGridCellMouseEventArgs e = cell.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);
      OnCellMouseClick(cell, e);
    }

    protected virtual void OnCellMouseClick(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      cell.ProcessMouseClick(e);
    }

    protected override void OnMouseDoubleClick(MouseEventArgs e)
    {
      Rectangle cellRect;
      Point cellMousePos;

      base.OnMouseDoubleClick(e);

      GridCoord cellHit = CalcCellCoordFromPoint(e.X, e.Y);
      if ((cellHit.X >= 0) && (cellHit.Y >= 0))
      {
        cellRect = CellRect(cellHit.X, cellHit.Y);
        cellMousePos = new Point(e.X - cellRect.Left, e.Y - cellRect.Top);
        ProcessCellMouseDoubleClick(cellHit.X, cellHit.Y, cellMousePos.X, cellMousePos.Y, cellRect, e);
      }
    }

    protected virtual void ProcessCellMouseDoubleClick(int colIndex, int rowIndex, int inCellX, int inCellY,
      Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      BaseGridCellMouseEventArgs e = cell.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);
      OnCellMouseDoubleClick(cell, e);
    }

    protected virtual void OnCellMouseDoubleClick(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      cell.ProcessMouseDoubleClick(e);
    }

    protected override void OnMouseEnter(EventArgs e)
    {
      base.OnMouseEnter(e);

      Point mousePos = PointToClient(MousePosition);
      Rectangle cellRect;

      GridCoord cellHit = MouseCoord(mousePos.X, mousePos.Y);

      if ((cellHit.X >= 0) && (cellHit.Y >= 0))
        cellRect = CellRect(cellHit.X, cellHit.Y);
      else
        cellRect = Rectangle.Empty;

      if ((cellHit.X < 0) || (cellHit.Y < 0))
        cellHit = new GridCoord(-1, -1);
      if (MouseHolderCellCoord != cellHit)
      {
        GridCoord oldMouseHolderCellCoord = MouseHolderCellCoord;

        if (MouseHolderCellCoord != new GridCoord(-1, -1))
        {
          ProcessCellMouseLeave(MouseHolderCellCoord.X, MouseHolderCellCoord.Y, cellRect, cellHit.X, cellHit.Y);
        }
        mouseHolderCellCoord = cellHit;
        if (cellHit != new GridCoord(-1, -1))
        {
          ProcessCellMouseEnter(MouseHolderCellCoord.X, MouseHolderCellCoord.Y, cellRect, oldMouseHolderCellCoord.X, oldMouseHolderCellCoord.Y);
        }
      }
    }

    protected virtual void ProcessCellMouseEnter(int colIndex, int rowIndex, Rectangle cellRect, int leaveColIndex, int leaveRowIndex)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      BaseGridCellEnterEventArgs e = cell.CreateCellEnterEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex);
      OnCellMouseEnter(cell, e);
    }

    protected virtual void OnCellMouseEnter(BaseGridCellManager cell, BaseGridCellEnterEventArgs e)
    {
      ResetMouseEventArgs();
      InvalidateCell(e.ColIndex, e.RowIndex);
      cell.ProcessMouseEnter(e);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
      base.OnMouseLeave(e);
      if (!GridMouseSpecialStateActive())
        Cursor = null;
      if (MouseHolderCellCoord != new GridCoord(-1, -1) &&
          MouseHolderCellCoord.X < FullColCount &&
          MouseHolderCellCoord.Y < FullRowCount)
      {
        Rectangle cellRect = CellRect(MouseHolderCellCoord.X, MouseHolderCellCoord.Y);
        ProcessCellMouseLeave(MouseHolderCellCoord.X, MouseHolderCellCoord.Y, cellRect, -1, -1);
        mouseHolderCellCoord = new GridCoord(-1, -1);
      }
    }

    protected virtual void ProcessCellMouseLeave(int colIndex, int rowIndex, Rectangle cellRect, int enterColIndex, int enterRowIndex)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      BaseGridCellLeaveEventArgs e = cell.CreateCellLeaveEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex);
      OnCellMouseLeave(cell, e);
    }

    protected virtual void OnCellMouseLeave(BaseGridCellManager cell, BaseGridCellLeaveEventArgs e)
    {
      if (e.ColIndex < FullColCount && e.RowIndex < FullRowCount)
        InvalidateCell(e.ColIndex, e.RowIndex);
      cell.ProcessMouseLeave(e);
    }

    protected override void OnMouseHover(EventArgs e)
    {
      base.OnMouseHover(e);

      Rectangle cellRect;
      Point mousePos = PointToClient(MousePosition);
      GridCoord cellHit = MouseCoord(mousePos.X, mousePos.Y);

      if ((cellHit.X < 0) || (cellHit.Y < 0))
        cellHit = new GridCoord(-1, -1);

      if ((cellHit.X >= 0) && (cellHit.Y >= 0))
        cellRect = CellRect(cellHit.X, cellHit.Y);
      else
        cellRect = Rectangle.Empty;

      ProcessCellMouseHover(cellHit.X, cellHit.Y, cellRect);
    }

    protected virtual void ProcessCellMouseHover(int colIndex, int rowIndex, Rectangle cellRect)
    {
      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      Point mousePos = PointToClient(MousePosition);
      MouseEventArgs mouseEventArgs = new MouseEventArgs(MouseButtons, 0, mousePos.X, mousePos.Y, 0);
      Point cellMousePos = new Point(mousePos.X - cellRect.Left, mousePos.Y - cellRect.Top);

      BaseGridCellMouseEventArgs e = cell.CreateMouseEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellMousePos.X, cellMousePos.Y, cellRect, mouseEventArgs);
      OnCellMouseHover(cell, e);
    }

    protected virtual void OnCellMouseHover(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      cell.ProcessMouseHover(e);
    }

    protected virtual ContextMenuStrip GetCellContextMenuStrip(Point mousePos, int colIndex, int rowIndex)
    {
      int areaColIndex, areaRowIndex;
      Point cellMousePos = Point.Empty;
      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Rectangle cellRect = CellRect(colIndex, rowIndex);
      var me = new MouseEventArgs(MouseButtons.Right, 1, mousePos.X, mousePos.Y, 0);

      cellMousePos.X = me.X - cellRect.Left;
      cellMousePos.Y = me.Y - cellRect.Top;

      BaseGridCellContextMenuStripNeededEventArgs e = cell.CreateCellContextMenuStripNeededEventArgs(
        colIndex, rowIndex, areaColIndex, areaRowIndex, cellMousePos.X, cellMousePos.Y, cellRect, mousePos.X, mousePos.Y);
      //  colIndex, rowIndex, areaColIndex, areaRowIndex, cellMousePos.X, cellMousePos.Y, cellRect, me);
      //var e = new BaseGridCellMouseEventArgs(cell, col, row, areaColIndex, areaRowIndex, cellMousePos.X, cellMousePos.Y, cellRect, me);
      cell.ProcessMouseContextMenuStripNeeded(e);
      return e.ContextMenuStrip;
    }

    protected virtual void ShowContextMenuStrip(ContextMenuStrip contextMenuStrip, Point clientPos, int col, int row)
    {
      contextMenuStrip.Show(this, clientPos);
    }

    protected virtual void InteractiveSetColWidths(int colIndex, int newSize)
    {
      ColWidths[colIndex] = newSize;
    }

    protected override void OnMouseWheel(MouseEventArgs e)
    {
      base.OnMouseWheel(e);

      if (e.Delta < 0)
        VertAxis.SafeSetRollStartVisCell(TopRow + 1 - FixedRowCount);
      else if (e.Delta > 0)
        VertAxis.SafeSetRollStartVisCell(TopRow - 1 - FixedRowCount);
    }

    protected override void OnMouseCaptureChanged(EventArgs e)
    {
      if (Capture)
        EhLibUtils.DoNothing();
      else
        EhLibUtils.DoNothing();
      base.OnMouseCaptureChanged(e);
      CancelMode();
    }

    protected virtual void CancelMode()
    {
      if (EhLibUtils.DebugIgnoreMouseCancelMode) return;
      //return;
      try
      {
        switch (gridState)
        {
          case BaseGridState.Selecting:
            SetGridTimer(false, 0);
            break;
          case BaseGridState.RowSizing:
          case BaseGridState.ColSizing:
            DrawSizingLine();
            break;
          case BaseGridState.ColMoving:
          case BaseGridState.RowMoving:
            HideMove();
            SetGridTimer(false, 0);
            break;
        }
      }
      finally
      {
        if (GridState != BaseGridState.Normal)
        {
          GridState = BaseGridState.Normal;
          if (MoveNScrollService.Active)
            MoveNScrollService.Release();
          InvalidateGrid();
        }
        Cursor = null;
      }

      if (MouseDownCellCoord.X >= 0 && MouseDownCellCoord.Y >= 0 &&
          MouseDownCellCoord.X < FullColCount && MouseDownCellCoord.Y < FullRowCount)
      {
        CellCancelMode(MouseDownCellCoord.X, MouseDownCellCoord.Y);

        InvalidateCell(MouseDownCellCoord.X, MouseDownCellCoord.Y);
      }
      MouseDownCellCoord = new GridCoord(-1, -1);
      MouseDownButton = MouseButtons.None;
      MouseDownCellCoordPressed = false;
    }

    protected virtual void CellCancelMode(int colIndex, int rowIndex)
    {
      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex);
      if (cell != null)
        cell.CancelMode();
    }

    protected virtual void TestSetCursor(MouseEventArgs e, ref Cursor newCursor)
    {
      BaseGridState state;
      int index;
      int pos, ofs;

      if (GridMouseSpecialStateActive()) return;

      newCursor = null;

      if (gridState == BaseGridState.Normal)
        CalcSizingState(e.X, e.Y, out state, out index, out pos, out ofs);
      else
        state = gridState;

      if (state == BaseGridState.RowSizing)
        newCursor = Cursors.HSplit;
      else if (state == BaseGridState.ColSizing)
        newCursor = Cursors.VSplit;
    }

    internal int ResizeLine(GridAxisData axis)
    {
      int i;
      int result;

      if (SizingIndex >= axis.CellCount)
      {
        result = axis.ContraStart;
        for (i = axis.CellCount; i <= SizingIndex; i++)
          result = result + axis.CellLens[i];
        result = result - SizingPos;
      }
      else
      {
        if (SizingIndex < axis.FixedCellCount)
        {
          result = 0;
          for (i = 0; i <= SizingIndex - 1; i++)
            result = result + axis.CellLens[i];
        }
        else
        {
          result = axis.FixedBoundary - axis.RollStartVisCellOffset;
          for (i = axis.StartVisCell; i <= SizingIndex - 1; i++)
            result = result + axis.CellLens[i];
        }
        result = SizingPos - result;
      }
      return result;
    }

    protected virtual void InteractiveMoveColumn(int fromIndex, int toIndex)
    {
      MoveColumn(fromIndex, toIndex);
    }

    protected internal virtual void MoveColumn(int fromIndex, int toIndex)
    {
      HorzAxis.MoveCell(fromIndex, toIndex);
    }

    protected virtual void MoveRow(int fromIndex, int toIndex)
    {
      VertAxis.MoveCell(fromIndex, toIndex);
    }

    protected virtual void UpdateHotTackInfo(int p, int p2)
    {
      //      throw new NotImplementedException();
    }

    public virtual bool IsDrawHotState()
    {
      return GridState == BaseGridState.Normal;
    }

    public void MoveAndScroll(int mouseAxisPos, int cellHit, GridAxisData axis, Orientation orientation, Point mousePos)
    {
      int oldMvePos = MoveToIndex;
      //bool oldMovePosLeftSite = moveToPosLeftSite;

      if (mouseAxisPos < axis.FixedBoundary)
      {
        if (axis.RollStartVisPos > 0)
        {
          ScrollBarMessage(orientation, new ScrollEventArgs(ScrollEventType.SmallDecrement, 0), true);
          Update();
        }
        mouseAxisPos = axis.FixedBoundary;
        //cellHit = axis.StartVisCell;
      }
      else if ((mouseAxisPos >= axis.RollInClientBoundary))
      {
        ScrollBarMessage(orientation, new ScrollEventArgs(ScrollEventType.SmallIncrement, 0), true);
        Update();
        mouseAxisPos = axis.RollInClientBoundary - 1;
      }

      int cellAxisIndex;
      int inCellAxisPos;
      int cellAxisPos;
      int cellAxisSize;

      if (axis == HorzAxis)
        ClientHorzPosToCellHorzPos(mouseAxisPos, out cellAxisIndex, out inCellAxisPos, out cellAxisPos, out cellAxisSize);
      else
        ClientVertPosToCellVertPos(mouseAxisPos, out cellAxisIndex, out inCellAxisPos, out cellAxisPos, out cellAxisSize);

      if (cellAxisIndex >= axis.FixedCellCount && cellAxisIndex < axis.CellCount)
      {
        int fromColIndex = MoveFromIndex;
        int toColIndex;

        if (inCellAxisPos < cellAxisSize / 2)
          toColIndex = cellAxisIndex;
        else
          toColIndex = cellAxisIndex + 1;

        if (CheckColumnDrag(ref fromColIndex, ref toColIndex, mousePos))
        {
          MoveFromIndex = fromColIndex;
          MoveToIndex = toColIndex;
        }
        //this.moveToPosLeftSite = true;
        //if (MoveToIndex == axis.CellCount)
        //{
        //  MoveToIndex = MoveToIndex - 1;
        //  this.moveToPosLeftSite = false;
        //}
      }

      if (oldMvePos != MoveToIndex)
        DrawMove();
    }

    public void SafeScrollData(int dx, int dy)
    {
      if (dx != 0)
        HorzAxis.RollStartVisPos =
          HorzAxis.CheckRollStartVisPos(HorzAxis.RollStartVisPos + dx);
      if (dy != 0)
        VertAxis.RollStartVisPos =
          VertAxis.CheckRollStartVisPos(VertAxis.RollStartVisPos + dy);
    }

    public void SetGridTimer(bool enabled, int interval)
    {
      if (enabled == false)
      {
        gridTimer.Enabled = false;
      }
      else
      {
        if (interval == 0)
          gridTimer.Interval = 1;
        else
          gridTimer.Interval = interval;
        gridTimer.Enabled = true;
      }
    }

    public int SkipHiddenCells(int index)
    {
      int i;

      int result = 0;
      for (i = index; i <= ColCount - 1; i++)
      {
        if (ColWidths[i] > 0)
          return result;
        result++;
      }
      return result;
    }

    public virtual void StartColMoving(int colIndex, int moveToIndex, int x, int y)
    {
      Rectangle noScrollRect = Rectangle.Empty;

      Rectangle cellRect = CellRect(colIndex, 0);

      MoveFromIndex = colIndex;
      MoveToIndex = moveToIndex;
      MoveFromCellOriginDistance = x - cellRect.Left;

      gridState = BaseGridState.ColMoving;
      Update();
      DrawMove();

      noScrollRect.X = HorzAxis.FixedBoundary;
      noScrollRect.Width = HorzAxis.RollClientLen;
      noScrollRect.Y = VertAxis.GridClientStart;
      noScrollRect.Height = VertAxis.GridClientStop - VertAxis.GridClientStart;

      MoveNScrollService.Capture(this, noScrollRect, MoveAndScrollHelpServiceEventHandler, true, false);
    }

    public virtual void StartColSizing(int colIndex, int x, int y, int sizingPos, int sizingOffset)
    {
      SizingIndex = colIndex;
      SizingPos = sizingPos;
      SizingOffset = sizingOffset;

      GridState = BaseGridState.ColSizing;
      SizingPosChanged = false;
      InitSizingLines();
      DrawSizingLine();
    }

    public virtual void StartRowSizing(int colIndex, int x, int y, int sizingPos, int sizingOffset)
    {
      SizingIndex = colIndex;
      SizingPos = sizingPos;
      SizingOffset = sizingOffset;

      GridState = BaseGridState.RowSizing;
      SizingPosChanged = false;
      InitSizingLines();
      DrawSizingLine();
    }

    public Rectangle CellRect(int col, int row, bool excludeLines = true)
    {
      Rectangle result = BoxRect(col, row, col, row);

      if (excludeLines == true)
      {
        if (CheckCellLine(col, row, GridCellBorderType.Right) &&
             (result.Left + ColWidths[col] <= result.Right))
        {
          if (RightToLeft == RightToLeft.Yes)
            result.X = result.Left + GridLineWidth;
          else
            result.Width = result.Width - GridLineWidth;
        }

        if (CheckCellLine(col, row, GridCellBorderType.Bottom) == true)
          result.Height = result.Height - GridLineWidth;
      }

      return result;
    }

    public Rectangle BoxRect(int left, int top, int right, int bottom)
    {
      Rectangle result;
      GridRect gridRect;

      gridRect.Left = left;
      gridRect.Right = right;
      gridRect.Top = top;
      gridRect.Bottom = bottom;
      GridRectToScreenRect(gridRect, out result);
      return result;
    }

    public void GridRectToScreenRect(GridRect gridRect, out Rectangle screenRect, bool cutOutbounds = true)
    {
      int locCol;
      int locRow;

      screenRect = new Rectangle();
      if ((gridRect.Left > gridRect.Right) || (gridRect.Top > gridRect.Bottom))
        return;

      // Left
      if (gridRect.Left < FixedColCount)
        screenRect.X = (int)(HorzAxis.GridClientStart + CalcColRangeWidth(0, gridRect.Left));
      else if (gridRect.Left < ColCount)
      {
        locCol = gridRect.Left - FixedColCount;
        screenRect.X = (int)(HorzAxis.RollLocCellPosArr[locCol] - RollStartVisPosX);
        if (cutOutbounds && (screenRect.Left < 0))
          screenRect.X = HorzAxis.FixedBoundary;
        else if (cutOutbounds & (screenRect.Left > HorzAxis.ContraStart))
          screenRect.X = HorzAxis.ContraStart;
        else
          screenRect.X = screenRect.Left + HorzAxis.FixedBoundary;
      }
      else
        screenRect.X = (int)(HorzAxis.ContraStart + CalcColRangeWidth(ColCount, gridRect.Left - ColCount));

      // Top
      if (gridRect.Top < FixedRowCount)
        screenRect.Y = (int)(VertAxis.GridClientStart + CalcRowRangeHeight(0, gridRect.Top));
      else if (gridRect.Top < RowCount)
      {
        locRow = gridRect.Top - FixedRowCount;
        screenRect.Y = (int)(VertAxis.RollLocCellPosArr[locRow] - RollStartVisPosY);
        if (cutOutbounds & (screenRect.Top < 0))
          screenRect.Y = VertAxis.FixedBoundary;
        else
          screenRect.Y = screenRect.Top + VertAxis.FixedBoundary;
      }
      else
        screenRect.Y = (int)(VertAxis.ContraStart + CalcRowRangeHeight(RowCount, gridRect.Top - RowCount));

      // Right
      if (gridRect.Right < FixedColCount)
      {
        screenRect.Width = (int)(HorzAxis.GridClientStart + CalcColRangeWidth(0, gridRect.Right + 1)) - screenRect.Left;
        if (screenRect.Right > HorzAxis.ContraStart)
          screenRect.Width = HorzAxis.ContraStart - screenRect.Left;
      }
      else if (gridRect.Right < ColCount)
      {
        locCol = gridRect.Right - FixedColCount;
        screenRect.Width = (int)(HorzAxis.RollLocCellPosArr[locCol] + HorzAxis.RollCellLens[locCol] - RollStartVisPosX) - screenRect.Left;
        if (cutOutbounds & (screenRect.Right < 0))
          //screenRect.Width = HorzAxis.FixedBoundary - 1 - screenRect.Left;
          screenRect.Width = 0;
        else
          screenRect.Width = screenRect.Right + HorzAxis.FixedBoundary - screenRect.Left;
        if (cutOutbounds & (screenRect.Right > HorzAxis.ContraStart))
        {
          if (HorzAxis.ContraStart > screenRect.Left)
            screenRect.Width = HorzAxis.ContraStart - screenRect.Left;
          else
            screenRect.Width = 0;
        }
      }
      else
        screenRect.Width = (int)(HorzAxis.ContraStart + CalcColRangeWidth(ColCount, gridRect.Right - ColCount + 1)) - screenRect.Left;

      // Bottom
      if (gridRect.Bottom < FixedRowCount)
      {
        screenRect.Height = (int)(VertAxis.GridClientStart + CalcRowRangeHeight(0, gridRect.Bottom + 1) - screenRect.Top);
        if (screenRect.Bottom > VertAxis.ContraStart)
          screenRect.Height = VertAxis.ContraStart - screenRect.Top;
      }
      else if (gridRect.Bottom < RowCount)
      {
        locRow = gridRect.Bottom - FixedRowCount;
        screenRect.Height = (int)(VertAxis.RollLocCellPosArr[locRow] + VertAxis.RollCellLens[locRow] - RollStartVisPosY) - screenRect.Top;
        if (cutOutbounds & (screenRect.Bottom < 0))
          screenRect.Height = VertAxis.FixedBoundary - 1 - screenRect.Top;
        else
          screenRect.Height = screenRect.Bottom + VertAxis.FixedBoundary - screenRect.Top;
        if (cutOutbounds & (screenRect.Bottom > VertAxis.ContraStart))
          screenRect.Height = VertAxis.ContraStart - screenRect.Top;
      }
      else
        screenRect.Height = (int)(VertAxis.ContraStart + CalcRowRangeHeight(RowCount, gridRect.Bottom - RowCount + 1) - screenRect.Top);

      if ((screenRect.Left > screenRect.Right) | (screenRect.Top > screenRect.Bottom))
        screenRect = new Rectangle();
    }

    public long CalcColRangeWidth(int fromCol, int rangeColCount)
    {
      int i;
      int inFixedToCol, inRolToCol, inContraFormCol;
      int inRolStart;

      long result = 0;
      if (rangeColCount <= 0)
        return result;
      if (fromCol < FixedColCount)
      {
        if (fromCol + rangeColCount <= FixedColCount)
          inFixedToCol = fromCol + rangeColCount;
        else
          inFixedToCol = FixedColCount;
        for (i = fromCol; i <= inFixedToCol - 1; i++)
          result = result + ColWidths[i];
      }

      if ((fromCol < ColCount) & (fromCol + rangeColCount > FixedColCount))
      {
        if ((fromCol > FixedColCount - 1))
          inRolStart = HorzAxis.RollLocCellPosArr[fromCol];
        else
          inRolStart = 0;
        if (fromCol + rangeColCount <= ColCount)
          inRolToCol = fromCol + rangeColCount - 1;
        else
          inRolToCol = ColCount - FixedColCount - 1;
        result = result + (HorzAxis.RollLocCellPosArr[inRolToCol] - inRolStart);
      }

      if (fromCol + rangeColCount > ColCount)
      {
        if (fromCol > ColCount)
          inContraFormCol = fromCol;
        else
          inContraFormCol = ColCount;
        for (i = inContraFormCol; i <= fromCol + rangeColCount - 1; i++)
          result = result + ColWidths[i];
      }

      return result;
    }

    public long CalcRowRangeHeight(int fromRow, int rangeRowCount)
    {
      int i;
      int inFixedToRow, inRolToRow, inContraFormRow;
      int inRolStart;

      long result = 0;
      if (rangeRowCount == 0) return result;

      if (fromRow < FixedRowCount)
      {
        if (fromRow + rangeRowCount <= FixedRowCount) inFixedToRow = fromRow + rangeRowCount; else inFixedToRow = FixedRowCount;
        for (i = fromRow; i <= inFixedToRow - 1; i++)
          result = result + RowHeights[i];
      }

      if ((fromRow < RowCount) & (fromRow + rangeRowCount > FixedRowCount))
      {
        if ((fromRow > FixedRowCount - 1)) inRolStart = VertAxis.RollLocCellPosArr[fromRow]; else inRolStart = 0;
        if (fromRow + rangeRowCount <= RowCount) inRolToRow = fromRow + rangeRowCount - 1; else inRolToRow = RowCount - FixedRowCount - 1;
        result = result + VertAxis.RollLocCellPosArr[inRolToRow] - inRolStart;
      }

      if (fromRow + rangeRowCount > RowCount)
      {
        if (fromRow > RowCount) inContraFormRow = fromRow; else inContraFormRow = RowCount;
        for (i = inContraFormRow; i <= fromRow + rangeRowCount - 1; i++)
          result = result + RowHeights[i];
      }

      return result;
    }

    public int CalcColFromPos(int x)
    {
      int result;
      int inCellHorzPos, cellHorzPos, cellWidth;
      ClientHorzPosToCellHorzPos(x, out result, out inCellHorzPos, out cellHorzPos, out cellWidth);
      return result;
    }

    public void ClientHorzPosToCellHorzPos(int clientHorzPos, 
      out int cellHorzIndex, out int inCellHorzPos, out int cellHorzPos, out int cellWidth)
    {
      int i;
      int pos;

      cellHorzIndex = -1;
      inCellHorzPos = -1;
      cellHorzPos = -1;
      cellWidth = -1;

      if (clientHorzPos < HorzAxis.GridClientStart)
      {
        EhLibUtils.DoNothing();
      }
      else if (clientHorzPos < HorzAxis.FixedBoundary)
      {
        pos = HorzAxis.GridClientStart;
        for (i = 0; i <= FixedColCount - 1; i++)
        {
          if (pos + ColWidths[i] > clientHorzPos)
          {
            cellHorzIndex = i;
            inCellHorzPos = clientHorzPos - pos;
            cellHorzPos = pos;
            cellWidth = ColWidths[i];
            return;
          }
          else
            pos = pos + ColWidths[i];
        }
      }
      else if (clientHorzPos <= HorzAxis.ContraStart)
      {
        pos = HorzAxis.FixedBoundary - HorzAxis.RollStartVisCellOffset;
        for (i = HorzAxis.RollStartVisCell + FixedColCount; i <= ColCount - 1; i++)
        {
          if (pos + ColWidths[i] > clientHorzPos)
          {
            cellHorzIndex = i;
            inCellHorzPos = clientHorzPos - pos;
            cellHorzPos = pos;
            cellWidth = ColWidths[i];
            return;
          }
          else
            pos = pos + ColWidths[i];
        }
      }
      else if (clientHorzPos < HorzAxis.GridClientStop)
      {
        pos = HorzAxis.ContraStart;
        for (i = ColCount; i <= FullColCount - 1; i++)
        {
          if (pos + ColWidths[i] > clientHorzPos)
          {
            cellHorzIndex = i;
            inCellHorzPos = clientHorzPos - pos;
            cellHorzPos = pos;
            cellWidth = ColWidths[i];
            return;
          }
          else
            pos = pos + ColWidths[i];
        }
      }
    }

    public int CalcRowFromPos(int y)
    {
      int result;
      int inCellVertPos, cellVertPos, cellHeight;
      ClientVertPosToCellVertPos(y, out result, out inCellVertPos, out cellVertPos, out cellHeight);
      return result;
    }

    public void ClientVertPosToCellVertPos(int clientVertPos,
      out int cellVertIndex, out int inCellVertPos, out int cellVertPos, out int cellHeight)
    {
      int i;
      int pos;

      cellVertIndex = -1;
      inCellVertPos = -1;
      cellVertPos = -1;
      cellHeight = -1;

      if (clientVertPos < VertAxis.GridClientStart)
        EhLibUtils.DoNothing();
      else if (clientVertPos < VertAxis.FixedBoundary)
      {
        pos = VertAxis.GridClientStart;
        for (i = 0; i <= FixedRowCount - 1; i++)
        {
          if (pos + RowHeights[i] > clientVertPos)
          {
            cellVertIndex = i;
            inCellVertPos = clientVertPos - pos;
            cellVertPos = pos;
            cellHeight = RowHeights[i];
            return;
          }
          else
            pos = pos + RowHeights[i];
        }
      }
      else if (clientVertPos < VertAxis.ContraStart)
      {
        pos = VertAxis.FixedBoundary - VertAxis.RollStartVisCellOffset;
        for (i = VertAxis.RollStartVisCell + FixedRowCount; i <= RowCount - 1; i++)
        {
          if (pos + RowHeights[i] > clientVertPos)
          {
            cellVertIndex = i;
            inCellVertPos = clientVertPos - pos;
            cellVertPos = pos;
            cellHeight = RowHeights[i];
            return;
          }
          else
            pos = pos + RowHeights[i];
        }
      }
      else if (clientVertPos < VertAxis.GridClientStop)
      {
        pos = VertAxis.ContraStart;
        for (i = RowCount; i <= FullRowCount - 1; i++)
        {
          if (pos + RowHeights[i] > clientVertPos)
          {
            cellVertIndex = i;
            inCellVertPos = clientVertPos - pos;
            cellVertPos = pos;
            cellHeight = RowHeights[i];
            return;
          }
          else
            pos = pos + RowHeights[i];
        }
      }
    }

    public void ClientPointToCell(Point clientPoint, out Point cellPos, out Point inCellMousePos, out Rectangle cellRect)
    {
      int cellHorzIndex;
      int inCellHorzPos;
      int cellHorzPos;
      int cellWidth;
      ClientHorzPosToCellHorzPos(clientPoint.X, out cellHorzIndex, out inCellHorzPos, out cellHorzPos, out cellWidth);

      int cellVertIndex;
      int inCellVertPos;
      int cellVertPos;
      int cellHeight;
      ClientVertPosToCellVertPos(clientPoint.Y, out cellVertIndex, out inCellVertPos, out cellVertPos, out cellHeight);

      cellPos = new Point(cellHorzIndex, cellVertIndex);
      inCellMousePos = new Point(inCellHorzPos, inCellVertPos);
      cellRect = new Rectangle(cellHorzPos, cellVertPos, cellWidth, cellHeight);
    }

    public GridCoord CalcCellCoordFromPoint(int x, int y)
    {
      GridCoord result;

      result.X = CalcColFromPos(x);
      result.Y = CalcRowFromPos(y);

      return result;
    }

    public GridCoord MouseCoord(int x, int y)
    {
      GridCoord result = CalcCellCoordFromPoint(x, y);

      if ((result.X < 0) || (result.X >= FullColCount))
        result.X = -1;
      if ((result.Y < 0) || (result.Y >= FullRowCount))
        result.Y = -1;

      return result;
    }

    public GridCoord MouseCoord(int x, int y, bool ExcludeCellBorders)
    {
      GridCoord result = MouseCoord(x, y);
      if (result.X >= 0 && result.Y >= 0 && ExcludeCellBorders)
      {
        Rectangle cellRect = CellRect(result.X, result.Y, true);
        if (!cellRect.Contains(x, y))
          return new GridCoord(-1, -1);
      }
      return result;
    }

    public virtual bool CheckBeginRowDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      return true;
    }

    public virtual bool CheckBeginColumnDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      return true;
    }

    public virtual bool EndColumnDrag(ref int origin, ref int destination, Point mousePos)
    {
      //if ((destination > origin) && !moveToPosLeftSite)
      //  destination--;
      return true;
    }

    public virtual bool EndRowDrag(ref int origin, ref int destination, Point mousePos)
    {
      return true;
    }

    public virtual bool CheckColumnDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      return true;
    }

    public virtual bool CheckRowDrag(ref int origin, ref int destination, Point mousePos)
    {
      return true;
    }

    protected internal virtual void HideMove()
    {
      GridMoveLine.GetMoveLine().Hide();
    }

    protected internal virtual void DrawMove()
    {
      int moveSize;
      int pos;
      Rectangle r;

      GridMoveLine line = GridMoveLine.GetMoveLine();
      if (gridState == BaseGridState.RowMoving)
      {

        r = CellRect(0, MoveToIndex);
        if (MoveToIndex > MoveFromIndex)
          pos = r.Bottom;
        else
          pos = r.Top;
        moveSize = HorzAxis.GridClientLen;

        if (line.Visible)
          line.MoveToFor(this, new Point(HorzAxis.GridClientStart, pos));
        else
          line.StartShow(this, new Point(HorzAxis.GridClientStart, pos), false, moveSize, this);
      }
      else
      {
        //BaseGridState.ColMoving
        Point listPos;
        int lineSize;

        GetColMovingLineBounds(out listPos, out lineSize);

        if (line.Visible)
          line.MoveToFor(this, listPos);
        else
          line.StartShow(this, listPos, true, lineSize, this);
      }
    }

    protected virtual void GetColMovingLineBounds(out Point linePos, out int lineSize)
    {
      int pos;
      int moveToIndex;
      Rectangle cellRect;

      if (MoveToIndex > HorzAxis.RollLastVisCell + HorzAxis.FixedCellCount)
      {
        pos = HorzAxis.RollInClientBoundary;
      }
      else
      {
        if (MoveToIndex == ColCount)
          moveToIndex = MoveToIndex - 1;
        else
          moveToIndex = MoveToIndex;
        cellRect = CellRect(moveToIndex, 0);
        if (MoveToIndex == ColCount)
          pos = cellRect.Right;
        else
          pos = cellRect.Left;
      }

      if ((GridOptions.ExtendVertLines & Options) != 0)
        lineSize = VertAxis.RollInClientBoundary - VertAxis.GridClientStart;
      else
        lineSize = VertAxis.GridClientLen;

      linePos = new Point(pos, VertAxis.GridClientStart);
    }

    private void DrawSizingLine()
    {
      UpdateSizingLines();
    }

    public virtual void GetDrawSizingLineBound(out int startPos, out int finishPos, int lineIndex)
    {
      if (gridState == BaseGridState.RowSizing)
      {
        //if (UseRightToLeft)
        //{
        //  StartPos = HorzAxis.GridClientStop;
        //  FinishPos = HorzAxis.GridClientStop - HorzAxis.GridClientStop;
        //}
        //else
        //{
          startPos = HorzAxis.GridClientStart;
          finishPos = HorzAxis.GridClientStop;
        //}
      }
      else
      {
        startPos = VertAxis.GridClientStart;
        if ((GridOptions.ExtendVertLines & Options) != 0)
          finishPos = VertAxis.GridClientStop;
        else
          finishPos = VertAxis.GridClientStop;
      }
    }

    public void PaintSizingLines(Graphics g)
    {
      int startPos;
      int finishPos;

      GetDrawSizingLineBound(out startPos, out finishPos, SizingIndex);

      if (gridState == BaseGridState.ColSizing)
        PaintingDrawLine(g, SystemColors.ControlDarkDark, DashStyle.Solid, Color.Empty, new Point(SizingPos - 1, startPos), new Point(SizingPos - 1, finishPos));
      else
        PaintingDrawLine(g, SystemColors.ControlDarkDark, DashStyle.Solid, Color.Empty, new Point(startPos, SizingPos - 1), new Point(finishPos, SizingPos - 1));

      if (DrawnSizingPos1 >= 0)
      {
        GetDrawSizingLineBound(out startPos, out finishPos, SizingIndex - 1);
        if (gridState == BaseGridState.ColSizing)
          PaintingDrawLine(g, SystemColors.ControlDarkDark, DashStyle.Solid, Color.Empty, new Point(DrawnSizingPos1 - 1, startPos), new Point(DrawnSizingPos1 - 1, finishPos));
        else
          PaintingDrawLine(g, SystemColors.ControlDarkDark, DashStyle.Solid, Color.Empty, new Point(startPos, DrawnSizingPos1 - 1), new Point(finishPos, DrawnSizingPos1 - 1));
      }
    }

    public void UpdateSizingLines()
    {
      Rectangle invalidRect;

      if (!IsHandleCreated) return;

      if (gridState == BaseGridState.ColSizing)
      {
        invalidRect = new Rectangle(DrawnSizingPos2 - 1, 0, 1, ClientHeight);
        Invalidate(invalidRect);

        invalidRect = new Rectangle(SizingPos - 1, 0, 1, ClientHeight);
        Invalidate(invalidRect);
      }
      else
      {
        invalidRect = new Rectangle(0, DrawnSizingPos2 - 1, ClientWidth, 1);
        Invalidate(invalidRect);

        invalidRect = new Rectangle(0, SizingPos - 1, ClientWidth, 1);
        Invalidate(invalidRect);
      }
      Update();
      DrawnSizingPos2 = SizingPos;
    }

    public void InitSizingLines()
    {
      int celStartPos;

      DrawnSizingPos2 = SizingPos;

      if (gridState == BaseGridState.ColSizing)
      {
        if (SizingIndex >= ColCount)
        {
          celStartPos = HorzAxis.ContraStart;
          for(int i = ColCount; i <= SizingIndex; i++)
            celStartPos = celStartPos + HorzAxis.CellLens[i];
          DrawnSizingPos1 = celStartPos;
        }
        else if (SizingIndex - FixedColCount >= 0)
          DrawnSizingPos1 = (int)(HorzAxis.FixedBoundary + HorzAxis.RollLocCellPosArr[SizingIndex - FixedColCount] - HorzAxis.RollStartVisPos);
        else
          DrawnSizingPos1 = -1;

        if (DrawnSizingPos1 < HorzAxis.FixedBoundary)
          DrawnSizingPos1 = -1;
      }
      else
      {
        if (SizingIndex - FixedRowCount >= 0)
          DrawnSizingPos1 = (int)(VertAxis.FixedBoundary + VertAxis.RollLocCellPosArr[SizingIndex - FixedRowCount] - VertAxis.RollStartVisPos);
        else
          DrawnSizingPos1 = -1;

        if (DrawnSizingPos1 < VertAxis.FixedBoundary)
          DrawnSizingPos1 = -1;
      }
      InvalidateGrid();
    }

    protected virtual bool CanResizeCol(int colIndex, int rowIndex, int xPos, int yPos, int inCellXPos, int inCellYPos)
    {
      if (rowIndex < 0 || rowIndex >= FixedRowCount - FrozenRowCount)
        return FixedColsSizingAllowed();
      else
        return true;
    }

    protected virtual bool CanResizeRow(int colIndex, int rowIndex, int xPos, int yPos, int inCellXPos, int inCellYPos)
    {
      return ((GridOptions.RowSizing & Options) != 0);
    }

    private bool CanAxisResizeCell(BaseGridState state, int axisCellIndex, int crossCellIndex, int axisPos, int crossPos, int axisInCellPos, int crossInCellPos)
    {
      if (state == BaseGridState.ColSizing)
        return CanResizeCol(axisCellIndex, crossCellIndex, axisPos, crossPos, axisInCellPos, crossInCellPos);
      else
        return CanResizeRow(crossCellIndex, axisCellIndex, crossPos, axisPos, crossInCellPos, axisInCellPos);
    }

    protected virtual void CalcAxisState(GridAxisData axis, int xPos, int yPos,
       BaseGridState newState, int sizingAreaSize, bool fixedCellSizingAllowed,
       out BaseGridState state, out int index, out int sizingPos, out int sizingOfs)
    {
      int i;
      int leftSizingBound;
      int leftSizingCell;
      int axisPos;
      int crossPos;
      //int axisCellIndex;
      int crossCellIndex;
      int axisInCellPos;
      int crossInCellPos;
      int crossInCellStartPos;
      int crossInCellWidth;

      if (newState == BaseGridState.ColSizing)
      {
        axisPos = xPos;
        crossPos = yPos;
        ClientVertPosToCellVertPos(yPos, out crossCellIndex, out crossInCellPos, out crossInCellStartPos, out crossInCellWidth);
      }
      else
      {
        axisPos = yPos;
        crossPos = xPos;
        ClientHorzPosToCellHorzPos(xPos, out crossCellIndex, out crossInCellPos, out crossInCellStartPos, out crossInCellWidth);
      }

      int range = 0;
      int back = 0;
      state = BaseGridState.Normal;
      index = -1;
      sizingPos = 1;
      sizingOfs = -1;

      if (range < sizingAreaSize)
      {
        range = sizingAreaSize;
        back = range / 2;
      }

      if (fixedCellSizingAllowed)
      {
        leftSizingBound = axis.GridClientStart;
        leftSizingCell = 0;
      }
      else
      {
        leftSizingBound = axis.FixedBoundary - axis.FrozenLen;
        leftSizingCell = axis.FixedCellCount - axis.FrozenCellCount;
      }

      int line = leftSizingBound;
      for (i = leftSizingCell; i <= axis.FixedCellCount - 1; i++)
      {
        axisInCellPos = axisPos - line;
        line = line + axis.CellLens[i];
        if (line >= axis.GridClientStop) break;
        if ((axisPos >= line - back) &&
            (axisPos <= line - back + range) &&
            CanAxisResizeCell(newState, i, crossCellIndex, axisPos, crossPos, axisInCellPos, crossInCellPos))
        {
          state = newState;
          sizingPos = line;
          sizingOfs = line - axisPos;
          index = i;
          return;
        }
      }

      line = axis.FixedBoundary - axis.RollStartVisCellOffset;
      for (i = axis.RollStartVisCell + axis.FixedCellCount; i <= axis.CellCount - 1; i++)
      {
        axisInCellPos = axisPos - line;
        line = line + axis.CellLens[i];
        if (line >= axis.ContraStart) break;
        if ((axisPos >= line - back) &&
            (axisPos <= line - back + range) &&
            CanAxisResizeCell(newState, i, crossCellIndex, axisPos, crossPos, axisInCellPos, crossInCellPos))
        {
          state = newState;
          sizingPos = line;
          sizingOfs = line - axisPos;
          index = i;
          return;
        }
      }

      i = axis.RollLastVisCell + axis.FixedCellCount;
      axisInCellPos = axisPos - axis.RollInClientBoundary;
      if ((axis.ContraStart == axis.RollInClientBoundary) &&
          (axisPos >= axis.RollInClientBoundary - back) &&
          (axisPos <= axis.RollInClientBoundary) &&
          CanAxisResizeCell(newState, i, crossCellIndex, axisPos, crossPos, axisInCellPos, crossInCellPos))
      {
        state = newState;
        sizingPos = axis.RollInClientBoundary;
        sizingOfs = axis.RollInClientBoundary - axisPos;
        if (axis.FixedBoundary > axis.ContraStart)
          index = axis.RollLastVisCell + axis.FixedCellCount;
        else
          index = axis.RollLastVisCell + axis.FixedCellCount;
        return;
      }

      i = axis.RollLastVisCell + axis.FixedCellCount;
      axisInCellPos = axisPos - axis.RollInClientBoundary;
      if ((axis.ContraCellCount > 0) &&
          (axisPos >= axis.ContraStart) &&
          (axisPos <= axis.ContraStart + back) &&
          CanAxisResizeCell(newState, i, crossCellIndex, axisPos, crossPos, axisInCellPos, crossInCellPos))
      {
        state = newState;
        sizingPos = axis.ContraStart;
        sizingOfs = axis.ContraStart - axisPos;
        index = axis.CellCount;
        return;
      }

      line = axis.ContraStart;
      for (i = axis.CellCount; i <= axis.CellCount + axis.ContraCellCount - 2; i++)
      {
        line = line + axis.CellLens[i];
        if (line >= axis.GridClientStop) break;
        axisInCellPos = axisPos - line;
        if ((axisPos >= line - back) &&
            (axisPos <= line - back + range) &&
            CanAxisResizeCell(newState, i, crossCellIndex, axisPos, crossPos, axisInCellPos, crossInCellPos))
        {
          state = newState;
          sizingPos = line;
          sizingOfs = line - axisPos;
          index = i + 1;
          return;
        }
      }
    }

    public bool XOutsideHorzFixedBoundary(int x)
    {
      bool result;
      int leftSizingBound;

      if (FixedColsSizingAllowed())
        leftSizingBound = HorzAxis.GridClientStart;
      else
        leftSizingBound = HorzAxis.FixedBoundary - HorzAxis.FrozenLen;
      if (!UseRightToLeft)
        result = x > leftSizingBound;
      else
        result = x < ClientWidth - leftSizingBound;
      return result;
    }

    public bool XOutsideOrEqualHorzFixedBoundary(int x)
    {
      bool result;

      if (!UseRightToLeft)
        result = x >= HorzAxis.FixedBoundary - HorzAxis.FrozenLen; // FixedBoundary
      else
        result = x <= ClientWidth - (HorzAxis.FixedBoundary - HorzAxis.FrozenLen);
      return result;
    }

    public void CalcSizingState(int x, int y, out BaseGridState state, out int index, out int sizingPos, out int sizingOfs)
    {
      state = BaseGridState.Normal;
      index = -1;
      sizingPos = -1;
      sizingOfs = -1;

      GridOptions effectiveOptions = Options;
      if (DesignMode)
        effectiveOptions = effectiveOptions | DesignOptionsBoost;
      if (((GridOptions.ColSizing | GridOptions.RowSizing) & effectiveOptions) != 0)
      {

        if ((XOutsideHorzFixedBoundary(x)) && ((GridOptions.ColSizing & effectiveOptions) != 0))
        {
          //if ((y >= VertAxis.FixedBoundary - VertAxis.FrozenLen) || (y < VertAxis.GridClientStart)) return;
          CalcAxisState(HorzAxis, x, y, BaseGridState.ColSizing, 7, FixedColsSizingAllowed(), out state, out index, out sizingPos, out sizingOfs);
        }
        else if ((y > VertAxis.FixedBoundary - VertAxis.FrozenLen) && ((GridOptions.RowSizing & effectiveOptions) != 0))
        {
          if (XOutsideOrEqualHorzFixedBoundary(x)) return;
          CalcAxisState(VertAxis, x, y, BaseGridState.RowSizing, 5, FixedRowsSizingAllowed(), out state, out index, out sizingPos, out sizingOfs);
        }
      }
    }

    public BaseGridState CheckSizingState(int x, int y)
    {
      int sizingIndex;
      int sizingPos;
      int sizingOffset;
      BaseGridState result;
      CalcSizingState(x, y, out result, out sizingIndex, out sizingPos, out sizingOffset);
      return result;
    }

    protected internal virtual bool FixedColsSizingAllowed()
    {
      return false;
    }

    public bool FixedRowsSizingAllowed()
    {
      return false;
    }

    protected internal virtual void ShowEditor(bool selectAll)
    {
      //      throw new NotImplementedException();
    }

    protected internal virtual bool HideEditor(bool acceptValue)
    {
      return true;
    }

    protected internal virtual void UpdateEdit()
    {
      //      throw new NotImplementedException();
    }

    internal void MoveAnchorCell(int col, int row, bool show)
    {
      //GridRect oldSel;
      if ((anchorCell.X == col) && (anchorCell.Y == row)) return;
      if ((col < 0) || (row < 0) || (col >= FullColCount) || (row >= FullRowCount))
        throw (new InvalidOperationException(@"MoveAnchorCell: Grid index out of range"));
      //oldSel = Selection;
      anchorCell.X = col;
      anchorCell.Y = row;
      ClampInView(anchorCell, true, true);
      //OnSelectionChanged(oldSel);
    }

    protected virtual void OnSelectionChanged(GridRect oldSel)
    {
      InvalidateGrid();
    }

    public void InvalidateGrid()
    {
      Invalidate(true);
    }

    public new void Invalidate(Rectangle rect)
    {
      if (UseRightToLeft)
        rect = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, rect);
      base.Invalidate(rect);
    }

    public void InvalidateCell(int col, int row)
    {
      GridRect grRect = new GridRect
      {
        Top = row,
        Left = col,
        Bottom = row,
        Right = col
      };

      InvalidateRect(grRect);
    }

    public void InvalidateRow(int row)
    {
      GridRect grRect;
      Rectangle scRect;
      if (!IsHandleCreated) return;
      grRect.Top = row;
      grRect.Left = 0;
      grRect.Bottom = row;
      grRect.Right = HorzAxis.FixedCellCount + HorzAxis.RollLastVisCell;
      GridRectToScreenRect(grRect, out scRect);
      scRect.X = 0;
      scRect.Width = ClientWidth;
      Invalidate(scRect);
    }

    public void InvalidateCol(int col)
    {
      GridRect grRect;
      Rectangle scRect;
      if (!IsHandleCreated) return;
      grRect.Top = 0;
      grRect.Left = col;
      grRect.Bottom = VertAxis.FixedCellCount + VertAxis.RollLastVisCell;
      grRect.Right = col;
      GridRectToScreenRect(grRect, out scRect);
      scRect.X = 0;
      scRect.Width = ClientWidth;
      Invalidate(scRect);
    }

    protected internal void InvalidateRect(GridRect rect)
    {
      Rectangle invalidRect;
      if (!IsHandleCreated) return;
      GridRectToScreenRect(rect, out invalidRect);
      if (invalidRect != Rectangle.Empty)
      {
        Invalidate(invalidRect);
      }
    }

    internal void CalcPageExtents(out int nextPageRow, out int prevPageRow)
    {
      int newCel, newCelOff, i;

      long newPos = (VertAxis.RollStartVisPos + VertAxis.RollClientLen);
      nextPageRow = RollRowCount - 1;
      if (newPos < VertAxis.RollLen)
      {
        VertAxis.BinarySearch(VertAxis.RollLocCellPosArr.Array, newPos, out newCel, out newCelOff);
        if (newCel < RollRowCount)
        {
          for (i = newCel; i <= RollRowCount - 1; i++)
          {
            nextPageRow = i - 1;
            if (VertAxis.RollLocCellPosArr[i] + VertAxis.RollCellLens[i] > newPos + VertAxis.RollClientLen)
              break;
          }
        }
      }
      nextPageRow = nextPageRow + FixedRowCount;
      if ((nextPageRow <= Row) && (nextPageRow < RowCount))
        nextPageRow = Row + 1;

      newPos = VertAxis.RollStartVisPos - VertAxis.RollClientLen;
      VertAxis.BinarySearch(VertAxis.RollLocCellPosArr.Array, newPos, out newCel, out newCelOff);
      if (newCelOff > 0)
        newCel++;
      prevPageRow = newCel + FixedRowCount;
      if ((prevPageRow >= Row) && (prevPageRow > 0))
        prevPageRow = Row - 1;
    }

    internal GridCoord NextSelectableCellFor(GridCoord nextCell)
    {
      int i;
      GridCoord result = nextCell;

      if (nextCell.X > Col)
        for (i = nextCell.X; i <= ColCount - 1; i++)
        {
          if (SelectCell(i, nextCell.Y))
          {
            result.X = i;
            break;
          }
        }
      else if (nextCell.X < Col)
        for (i = nextCell.X; i >= 0; i--)
        {
          if (SelectCell(i, nextCell.Y))
          {
            result.X = i;
            break;
          }
        }

      if (nextCell.Y > Row)
        for (i = nextCell.Y; i <= RowCount - 1; i++)
        {
          if (SelectCell(nextCell.X, i))
          {
            result.Y = i;
            break;
          }
        }
      else if (nextCell.Y < Row)
        for (i = nextCell.Y; i >= 0; i--)
        {
          if (SelectCell(nextCell.X, i))
          {
            result.Y = i;
            break;
          }
        }
      return result;
    }

    internal void Restrict(ref GridCoord coord, int minX, int minY, int maxX, int maxY)
    {
      if (coord.X > maxX)
        coord.X = maxX;
      else if (coord.X < minX)
        coord.X = minX;

      if (coord.Y > maxY)
        coord.Y = maxY;
      else if (coord.Y < minY)
        coord.Y = minY;
    }

    internal void CellCountChanged()
    {
      InvalidateGrid();
      if (curCell.X >= ColCount)
        curCell.X = ColCount - 1;

      if (curCell.X < FixedColCount - FrozenColCount)
        curCell.X = FixedColCount - FrozenColCount;

      if (curCell.Y >= RowCount)
        curCell.Y = RowCount - 1;

      if (curCell.Y < FixedRowCount - FrozenRowCount)
        curCell.Y = FixedRowCount - FrozenRowCount;

      anchorCell = curCell;
    }

    internal void RolPosAxisChanged(GridAxisData axis, long oldRowPos)
    {
      if (axis == HorzAxis)
      {
        RollPosChanged(oldRowPos, VertAxis.RollStartVisPos);
        HorzScrollBar.OnScrollPosChanged();
      }
      else
      {
        RollPosChanged(HorzAxis.RollStartVisPos, oldRowPos);
        VertScrollBar.OnScrollPosChanged();
      }
    }

    protected virtual void RollPosChanged(long oldRowPosX, long oldRowPosY)
    {
      Rectangle scrollArea;

      UpdateScrollBars();
      if (!IsHandleCreated)
        return;

      if (FullRedrawOnScroll)
      {
        InvalidateGrid();
        return;
      }

      //ScrollFlags = SW_INVALIDATE;

      int dx = (int)(oldRowPosX - HorzAxis.RollStartVisPos);
      int dy = (int)(oldRowPosY - VertAxis.RollStartVisPos);

      if (dy == 0)
      {
        scrollArea = new Rectangle(HorzAxis.FixedBoundary,
                                   VertAxis.GridClientStart,
                                   HorzAxis.RollInClientBoundary - HorzAxis.FixedBoundary,
                                   VertAxis.GridClientStop - VertAxis.GridClientStart);
        if (UseRightToLeft)
        {
          scrollArea = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, scrollArea);
          dx = -dx;
        }

        EhLibUtils.ScrollControlWindow(this, dx, 0, scrollArea);
      }
      else if (dx == 0)
      {
        scrollArea = new Rectangle(HorzAxis.GridClientStart,
                                   VertAxis.FixedBoundary,
                                   HorzAxis.GridClientStop - HorzAxis.GridClientStart,
                                   VertAxis.ContraStart - VertAxis.FixedBoundary);
        if (UseRightToLeft)
        {
          scrollArea = EhLibUtils.RightToLeftFlipRectangle(ClientRectangle, scrollArea);
        }

        EhLibUtils.ScrollControlWindow(this, 0, dy, scrollArea);
      }
      else
      {
        InvalidateGrid();
        Update();
      }
    }

    internal void RolSizeUpdated()
    {
      UpdateBoundaries();
    }

    //private GridRect GetSelection()
    //{
    //  return GridRect(curCell, AnchorCell);
    //}

    //private void SetSelection(GridRect value)
    //{
    //  //throw new NotImplementedException();
    //}

    public static GridRect GridRect(GridCoord coord1, GridCoord coord2)
    {
      GridRect result = new GridRect();

      if (coord1.X < coord2.X)
      {
        result.Left = coord1.X;
        result.Right = coord2.X;
      }
      else
      {
        result.Left = coord2.X;
        result.Right = coord1.X;
      }

      if (coord1.Y < coord2.Y)
      {
        result.Top = coord1.Y;
        result.Bottom = coord2.Y;
      }
      else
      {
        result.Top = coord2.Y;
        result.Bottom = coord1.Y;
      }
      return result;
    }

    private void SetCol(int value)
    {
      if (Col != value)
        FocusCell(value, Row, true);
    }

    private void SetRow(int value)
    {
      if (Row != value)
      {
        if (Options.HasFlag(GridOptions.RowSelect))
          MoveCurrent(Col, value, false, true);
        else
          FocusCell(Col, value, true);
      }
    }

    private void SetFixedRowCount(int value)
    {
      VertAxis.FixedCellCount = value;
    }

    public void SetScrollBarSize(int value)
    {
      if (scrollBarSize != value)
      {
        scrollBarSize = value;
        UpdateBoundaries();
      }
    }

    public void SetSizeGripAlwaysShow(bool value)
    {
      if (sizeGripAlwaysShow != value)
      {
        sizeGripAlwaysShow = value;
        UpdateScrollBarPanels();
      }
    }

    public void SetSizeGripPosition(SizeGripPosition value)
    {
      if (sizeGripPosition != value)
      {
        sizeGripPosition = value;
        UpdateScrollBarPanels();
      }
    }

    public void SetGridLineWidth(int value)
    {
      gridLineWidth = value;
    }

    public virtual void InteractiveFocusCell(int col, int row, InteractiveActionSource actionSource)
    {
      FocusCell(col, row, false);
    }

    public virtual void FocusCell(int col, int row, bool moveAnchor)
    {
      MoveCurrent(col, row, true, true);
      //      UpdateEdit;
      //      Click;
    }

    public void MoveCurrent(int col, int row, bool showX, bool showY)
    {
      GridCoord oldCurCell;
      //      bool OldMultiselected;
      //      GridRect OldSel;

      if (Options.HasFlag(GridOptions.RowSelect))
        //Debug.Assert(col != Col, "ColIndex can't be changed in RowSelect mode");
        col = FixedColCount - FrozenColCount;
      if ((col < 0) || (row < 0) || (col >= ColCount) || (row >= RowCount))
        throw (new InvalidOperationException("Grid index out of range"));

      if (SelectCell(col, row))
      {
        //        OldSel = Selection; 
        oldCurCell = curCell;
        //        OldMultiselected = IsMultiSelected; 
        curCell.X = col;
        curCell.Y = row;
        //        if (!(goAlwaysShowEditorEh in Options)) 
        //          HideEditor;
        anchorCell = curCell;
        if (showX || showY)
          ClampInView(curCell, showX, showY);

        //if (OldMultiselected != IsMultiSelected)
        //{
        //  InvalidateGrid;
        //}
        //else
        //{
        //  InvalidateCell(OldCurCell.X, OldCurCell.Y);
        //  InvalidateCell(ACol, ARow);
        //}
        //SelectionChanged(OldSel);
        CurrentCellMoved(oldCurCell);
        InvalidateCell(oldCurCell.X, oldCurCell.Y);
        InvalidateCell(curCell.X, curCell.Y);
      }
    }

    protected virtual void CurrentCellMoved(GridCoord oldCurCell)
    {
    }

    public virtual bool SelectCell(int col, int row)
    {
      return true;
    }

    public bool IsMultiSelected()
    {
      return false;
      //Result = (FAnchorCell.X != FCurCell.X) | (FAnchorCell.Y != FCurCell.Y); 
    }

    public void ClampInView(GridCoord coord, bool checkX, bool checkY)
    {

      int locCol, locRow;
      int rolBoundWidth, rolBoundHeight;
      int newCel, newPosInCell;

      PointL newRolStartPos = new PointL() { X = RollStartVisPosX, Y = RollStartVisPosY };

      if (checkX && (coord.X >= FixedColCount) && (coord.X < ColCount))
      {
        locCol = coord.X - FixedColCount;
        rolBoundWidth = HorzAxis.ContraStart - HorzAxis.FixedBoundary;
        if (HorzAxis.RollLocCellPosArr[locCol] < RollStartVisPosX)
          newRolStartPos.X = HorzAxis.RollLocCellPosArr[locCol];
        else if (HorzAxis.RollLocCellPosArr[locCol] + HorzAxis.RollCellLens[locCol] > RollStartVisPosX + rolBoundWidth)
        {
          newRolStartPos.X = (HorzAxis.RollLocCellPosArr[locCol] + HorzAxis.RollCellLens[locCol]) - rolBoundWidth;
          if (HorzAxis.RollLocCellPosArr[locCol] < newRolStartPos.X)
            newRolStartPos.X = HorzAxis.RollLocCellPosArr[locCol];
        }
      }

      if (checkY && (coord.Y >= FixedRowCount) && (coord.Y < RowCount))
      {
        locRow = coord.Y - FixedRowCount;
        rolBoundHeight = VertAxis.ContraStart - VertAxis.FixedBoundary;
        if (VertAxis.RollLocCellPosArr[locRow] < RollStartVisPosY)
          newRolStartPos.Y = VertAxis.RollLocCellPosArr[locRow];
        else if (VertAxis.RollLocCellPosArr[locRow] + VertAxis.RollCellLens[locRow] > RollStartVisPosY + rolBoundHeight)
        {
          newRolStartPos.Y = (VertAxis.RollLocCellPosArr[locRow] + VertAxis.RollCellLens[locRow]) - rolBoundHeight;
          if (VertAxis.RollLocCellPosArr[locRow] < newRolStartPos.Y)
            newRolStartPos.Y = VertAxis.RollLocCellPosArr[locRow];
        }
      }

      if (IsSmoothHorzScroll())
        RollStartVisPosX = newRolStartPos.X;
      else
      {
        HorzAxis.RollCellAtPos(newRolStartPos.X, out newCel, out newPosInCell);
        RollStartVisPosX = newRolStartPos.X - newPosInCell;
      }

      if (IsSmoothVertScroll())
        RollStartVisPosY = newRolStartPos.Y;
      else
      {
        VertAxis.RollCellAtPos(newRolStartPos.Y, out newCel, out newPosInCell);
        if (newPosInCell == 0)
          RollStartVisPosY = newRolStartPos.Y;
        else
          RollStartVisPosY = newRolStartPos.Y - newPosInCell + VertAxis.RollCellLens[newCel];
      }

    }

    protected virtual bool IsSmoothVertScroll()
    {
      return true;
    }

    protected virtual bool IsSmoothHorzScroll()
    {
      return true;
    }

    internal void CheckUpdateAxises()
    {
      HorzAxis.CheckUpdateRollCellPosArray();
      VertAxis.CheckUpdateRollCellPosArray();
    }

    public void AdjustMaxTopLeft(bool adjustLeft, bool adjustTop, bool leftBindToCell, bool topBindToCell)
    {

      long maxLeftPos = HorzAxis.RollLen;
      long maxTopPos = VertAxis.RollLen;

      CalcMaxRollTopLeft(ref maxLeftPos, ref maxTopPos, leftBindToCell, topBindToCell);

      if (maxLeftPos < HorzAxis.RollStartVisPos)
        RollStartVisPosX = maxLeftPos;
      if (maxTopPos < RollStartVisPosY)
        RollStartVisPosY = maxTopPos;
    }

    public void CalcMaxRollTopLeft(ref long maxLeftPos, ref long maxTopPos, bool leftBindToCell, bool topBindToCell)
    {
      int cel, celOffset;

      maxLeftPos = maxLeftPos - HorzAxis.RollClientLen;
      if (maxLeftPos < 0)
        maxLeftPos = 0;

      if (leftBindToCell)
      {
        HorzAxis.RollCellAtPos(maxLeftPos, out cel, out celOffset);
        if ((celOffset > 0) && (cel < HorzAxis.RollCellCount - 1))
          cel++;
        maxLeftPos = HorzAxis.RollLocCellPosArr[cel];
      }

      maxTopPos = maxTopPos - VertAxis.RollClientLen;
      if (maxTopPos < 0)
        maxTopPos = 0;

      if (topBindToCell)
      {
        VertAxis.RollCellAtPos(maxTopPos, out cel, out celOffset);
        if ((celOffset > 0) && (cel < VertAxis.RollCellCount - 1))
          cel++;
        maxTopPos = VertAxis.RollLocCellPosArr[cel];
      }

    }

    public void UpdateScrollBars()
    {
      int position, min, max, pageSize;

      if (ScrollBarInternalUpdating) return;
      GetDataForHorzScrollBar(out position, out min, out max, out pageSize);
      HorzScrollBar.SetParams(position, min, max, pageSize);

      GetDataForVertScrollBar(out position, out min, out max, out pageSize);
      VertScrollBar.SetParams(position, min, max, pageSize);

      UpdateScrollBarPanels();
    }

    public void UpdateScrollBarPanels()
    {
      int sHeight, sWidth, sizeGripWidth, sizeGripHeight;
      Rectangle clientBounds = ClientBounds;

      if (!IsHandleCreated) return;

      if (VertScrollBar.IsScrollBarShowing())
        sWidth = VertScrollBar.ActualSize();
      else
        sWidth = 0;

      if (HorzScrollBar.IsScrollBarShowing())
        sHeight = HorzScrollBar.ActualSize();
      else
        sHeight = 0;

      int sbLeftStartOffset = clientBounds.Left;
      int sbTopStartOffset = clientBounds.Top;
      if (SizeGripPosition == SizeGripPosition.BottomRight)
      {
        extraSizeGripControl.Visible = false;
        cornerScrollBarPanelControl.GripActiveStatus = CornerSizeGripActiveStatus(cornerScrollBarPanelControl);
        if (!UseRightToLeft &&
            (((sHeight > 0) && (sWidth > 0)) || SizeGripAlwaysShow)
           )
        {
          sizeGripWidth = VertScrollBar.ActualSize();
          sizeGripHeight = HorzScrollBar.ActualScrollBarBoxSize();
        }
        else
        {
          sizeGripWidth = 0;
          sizeGripHeight = 0;
        }
      }
      else
      {
        sizeGripWidth = 0;
        sizeGripHeight = 0;
        cornerScrollBarPanelControl.GripActiveStatus = GripActiveStatus.Never;
        if (SizeGripPosition == SizeGripPosition.TopLeft)
        {
          extraSizeGripControl.SetBounds(0, 0, HorzScrollBar.ActualSize(), VertScrollBar.ActualSize());
          extraSizeGripControl.TriangleWindow = true;
        }
        else if (SizeGripPosition == SizeGripPosition.TopRight)
        {
          sbTopStartOffset = VertScrollBar.ActualSize();
          extraSizeGripControl.SetBounds(clientBounds.Right - HorzScrollBar.ActualSize(), clientBounds.Top,
                                         HorzScrollBar.ActualSize(), VertScrollBar.ActualSize());
          extraSizeGripControl.TriangleWindow = (sWidth == 0);
        }
        else //sgpBottomLeft
        {
          sbLeftStartOffset = VertScrollBar.ActualSize();
          extraSizeGripControl.SetBounds(sbLeftStartOffset, clientBounds.Height - VertScrollBar.ActualSize(), 
                                         HorzScrollBar.ActualSize(), VertScrollBar.ActualSize());
          extraSizeGripControl.TriangleWindow = (sHeight == 0);
          if (UseRightToLeft &&
              (((sHeight > 0) && (sWidth > 0)) || SizeGripAlwaysShow) 
             ) 
          {
            sizeGripWidth = VertScrollBar.ActualSize();
            sizeGripHeight = HorzScrollBar.ActualScrollBarBoxSize();
            extraSizeGripControl.TriangleWindow = (sWidth == 0);
          }
        }
        extraSizeGripControl.GripActiveStatus = GripActiveStatus.Always;
        extraSizeGripControl.Position = SizeGripPosition;
        extraSizeGripControl.Visible = true;
      }

      if (UseRightToLeft)
      {
        vertScrollBarPanelControl.SetBounds(sbLeftStartOffset, sbTopStartOffset, sWidth, clientBounds.Height - sizeGripHeight - sHeight);
        horzScrollBarPanelControl.SetBounds(sWidth, clientBounds.Bottom - sHeight, clientBounds.Width - sWidth, sHeight);
        cornerScrollBarPanelControl.SetBounds(sbLeftStartOffset, clientBounds.Height - sHeight, sWidth, sHeight);
      }
      else
      {
        vertScrollBarPanelControl.ResetBounds(clientBounds.Right - sWidth, sbTopStartOffset, sWidth,
                                            clientBounds.Bottom - sizeGripHeight - sbTopStartOffset);
        horzScrollBarPanelControl.ResetBounds(sbLeftStartOffset, clientBounds.Bottom - sHeight,
                                            clientBounds.Right - sizeGripWidth - sbTopStartOffset, sHeight);
        cornerScrollBarPanelControl.SetBounds(clientBounds.Right - sizeGripWidth, clientBounds.Bottom - sizeGripHeight,
                                              sizeGripWidth, sizeGripHeight);
      }

      vertScrollBarPanelControl.Visible = true;
      vertScrollBarPanelControl.KeepMaxSizeInDefault = VertScrollBar.IsKeepMaxSizeInDefault();

      horzScrollBarPanelControl.Visible = true;
      horzScrollBarPanelControl.KeepMaxSizeInDefault = HorzScrollBar.IsKeepMaxSizeInDefault();

      cornerScrollBarPanelControl.Visible = true;
      cornerScrollBarPanelControl.TriangleWindow = ((sHeight == 0) && (sWidth == 0) && SizeGripAlwaysShow);

      bool scrollBarShowingChanged = false;
      if (vertScrollBarIsShowing != VertScrollBar.IsScrollBarShowing())
      {
        vertScrollBarIsShowing = VertScrollBar.IsScrollBarShowing();
        scrollBarShowingChanged = true;
      }

      if (horzScrollBarIsShowing != HorzScrollBar.IsScrollBarShowing())
      {
        horzScrollBarIsShowing = HorzScrollBar.IsScrollBarShowing();
        scrollBarShowingChanged = true;
      }
      if (scrollBarShowingChanged)
        ScrollBarShowingChanged();
    }

    protected virtual GripActiveStatus CornerSizeGripActiveStatus(SizeGripControl sizeGrip)
    {
      if (SizeGripAlwaysShow)
        return GripActiveStatus.Always;
      else
        return GripActiveStatus.Auto;
    }

    public void ScrollBarShowingChanged()
    {
    }

    public void GetDataForHorzScrollBar(out int position, out int min, out int max, out int pageSize)
    {
      position = (int)HorzAxis.RollStartVisPos;
      min = 0;
      if (HorzAxis.RollLen > 0)
        max = (int)HorzAxis.RollLen - 1;// - APageSize;
      else
        max = 0;
      pageSize = HorzAxis.RollClientLen;
    }

    public void GetDataForVertScrollBar(out int position, out int min, out int max, out int pageSize)
    {
      position = (int)VertAxis.RollStartVisPos;
      min = 0;
      max = (int)VertAxis.RollLen - 1;
      pageSize = VertAxis.RollClientLen;
    }

    internal void ScrollBarMessage(Orientation kind, ScrollEventArgs e, bool modifyScrollBar)
    {
      if (kind == Orientation.Horizontal)
        HorzScrollBarMessage(e, modifyScrollBar);
      else
        VertScrollBarMessage(e, modifyScrollBar);
    }

    protected virtual void VertScrollBarMessage(ScrollEventArgs e, bool modifyScrollBar)
    {
      if (HorzScrollBar.SmoothStep)
        ModifySmoothScrollBar(e, VertAxis, VertScrollBar, modifyScrollBar);
      else
        ModifyDiscreteScrollBar(e, VertAxis, VertScrollBar);
    }

    protected virtual void HorzScrollBarMessage(ScrollEventArgs e, bool modifyScrollBar)
    {
      if (HorzScrollBar.SmoothStep)
        ModifySmoothScrollBar(e, HorzAxis, HorzScrollBar, modifyScrollBar);
      else
        ModifyDiscreteScrollBar(e, HorzAxis, HorzScrollBar);
    }

    public void ScrollMessage(Orientation kind, ScrollEventType type)
    {
      ScrollOrientation scOr;
      if (kind == Orientation.Horizontal)
        scOr = ScrollOrientation.HorizontalScroll;
      else
        scOr = ScrollOrientation.VerticalScroll;

      ScrollEventArgs e = new ScrollEventArgs(type, -1, -1, scOr);
      ScrollBarMessage(kind, e, true);
    }

    private void ModifyDiscreteScrollBar(ScrollEventArgs e, GridAxisData axis, 
      BaseGridScrollBar scrollBar)
      //, bool modifyScrollBar
    {
      int newCelOffset, newValue;

      int newCell = -1;
      switch (e.Type)
      {
        case ScrollEventType.SmallDecrement:
          if (axis.RollStartVisCellOffset > 0)
            newCell = axis.RollStartVisCell;
          else
            newCell = axis.RollStartVisCell - 1;
          break;

        case ScrollEventType.SmallIncrement:
          newCell = axis.RollStartVisCell + 1;
          break;

        case ScrollEventType.LargeDecrement:
          axis.RollCellAtPos(e.OldValue - axis.RollClientLen, out newCell, out newCelOffset);
          if (newCelOffset > 0)
            newCell++;
          break;

        case ScrollEventType.LargeIncrement:
          if (axis.RollLastFullVisCell == axis.RollLastVisCell)
            newCell = axis.RollLastVisCell + 1;
          else
            newCell = axis.RollLastVisCell;
          break;

        case ScrollEventType.ThumbTrack:
          //        case ScrollEventType.ThumbPosition:
          if ((scrollBar.Tracking) || (e.Type == ScrollEventType.ThumbPosition))
          {
            if (e.OldValue == axis.RollLen - axis.RollClientLen)
              newCell = axis.RollCellCount - 1;
            else
            {
              axis.RollCellAtPos(e.OldValue, out newCell, out newCelOffset);
              if (newCelOffset > axis.RollCellLens[newCell] / 2)
                newCell++;
            }
          }
          break;

        case ScrollEventType.Last:
          newCell = axis.RollCellCount;
          break;

        case ScrollEventType.First:
          newCell = 0;
          break;

      }
      if (newCell != -1)
      {
        ScrollBarInternalUpdating = true;
        try
        {
          newValue = (int)axis.SafeSetRollStartVisCell(newCell);
        }
        finally
        {
          ScrollBarInternalUpdating = false;
        }

        if ((newValue != e.OldValue) && (e.Type != ScrollEventType.ThumbTrack))
          e.NewValue = newValue;
      }
    }

    private void ModifySmoothScrollBar(ScrollEventArgs e, GridAxisData axis, 
      BaseGridScrollBar scrollBar, bool modifyScrollBar)
    {
      int newValue;

      int newOffset = 0;
      switch (e.Type)
      {
        case ScrollEventType.SmallDecrement:
          newOffset = -axis.GetScrollStep();
          break;
        case ScrollEventType.SmallIncrement:
          newOffset = axis.GetScrollStep();
          break;
        case ScrollEventType.LargeDecrement:
          newOffset = -axis.RollClientLen;
          break;
        case ScrollEventType.LargeIncrement:
          newOffset = axis.RollClientLen;
          break;
        case ScrollEventType.ThumbTrack:
          //        case ScrollEventType.ThumbPosition:
          if ((scrollBar.Tracking) || (e.Type == ScrollEventType.ThumbPosition))
          {
            newOffset = e.NewValue - (int)axis.RollStartVisPos;
          }
          break;
        case ScrollEventType.Last:
          newOffset = (int)(axis.RollStopVisPos - axis.RollStartVisPos);
          break;
        case ScrollEventType.First:
          newOffset = (int)-axis.RollStartVisPos;
          break;
      }

      if (!modifyScrollBar)
        ScrollBarInternalUpdating = true;
      try
      {
        newValue = (int)axis.RollStartVisPos + newOffset;
        //        Debug.WriteLine("OldValue=" + e.OldValue.ToString() + " NewValue=" + e.NewValue.ToString());
        if ((newValue != e.OldValue) || (e.Type == ScrollEventType.ThumbTrack))
        {
          axis.RollStartVisPos = axis.CheckRollStartVisPos(newValue);
          if (e.Type != ScrollEventType.ThumbTrack)
            e.NewValue = (int)axis.RollStartVisPos;
        }
      }
      finally
      {
        ScrollBarInternalUpdating = false;
      }

    }

    internal bool CanFillSelectionByTheme()
    {
      return false;
    }

    internal GridCoord GridCoord(int x, int y)
    {
      GridCoord result;
      result.X = x;
      result.Y = y;
      return result;
    }

    public void AxisMoved(GridAxisData axis, int fromIndex, int toIndex)
    {
      InvalidateGrid();
      if (axis == HorzAxis)
        ColumnMoved(fromIndex, toIndex);
      else
        RowMoved(fromIndex, toIndex);
    }

    public void ColumnMoved(int fromIndex, int toIndex)
    {
      GridCoord oldCell = curCell;

      if (curCell.X == fromIndex)
        curCell.X = toIndex;
      else if ((fromIndex < curCell.X) && (toIndex >= curCell.X))
        curCell.X = curCell.X - 1;
      else if ((fromIndex > curCell.X) && (toIndex <= curCell.X))
        curCell.X = curCell.X + 1;
      if ((oldCell.X == anchorCell.X) && (oldCell.Y == anchorCell.Y))
        anchorCell = curCell;
    }

    public void RowMoved(int fromIndex, int toIndex)
    {
      GridCoord oldCell = curCell;

      if (curCell.X == fromIndex)
        curCell.X = toIndex;
      else if ((fromIndex < curCell.X) && (toIndex >= curCell.X))
        curCell.X = curCell.X - 1;
      else if ((fromIndex > curCell.X) && (toIndex <= curCell.X))
        curCell.X = curCell.X + 1;
      if ((oldCell.X == anchorCell.X) && (oldCell.Y == anchorCell.Y))
        anchorCell = curCell;
    }

    protected internal virtual void CellLenChanged(GridAxisData axis, int index, int oldLen)
    {
      if ((index < axis.FixedCellCount) || (index >= axis.CellCount))
        UpdateBoundaries();
      if (axis == HorzAxis)
        ColWidthsChanged();
      else
        RowHeightsChanged();
    }

    protected virtual void ColWidthsChanged()
    {
      if (RollSizeValid())
        UpdateEdit();
    }

    protected virtual void RowHeightsChanged()
    {
      if (RollSizeValid())
        UpdateEdit();
    }

    public bool RollSizeValid()
    {
      return !HorzAxis.RollLocCellPosArrObsolete && !VertAxis.RollLocCellPosArrObsolete;
    }

    protected void DeleteColumn(int col)
    {
      HorzAxis.DeleteRollCells(col - HorzAxis.FixedCellCount, 1);
    }

    protected void DeleteRow(int row)
    {
      VertAxis.DeleteRollCells(row - VertAxis.FixedCellCount, 1);
    }

    internal virtual void ScrollBarSizeChanged(BaseGridScrollBar baseGridScrollBar)
    {
      UpdateBoundaries();
    }

    protected override void WndProc(ref Message m)
    {
      int result = 0;
      switch (m.Msg)
      {
        case NativeMethods.WM_NCHITTEST:
          WmNCHitTest(ref m);
          break;
        case NativeMethods.WM_MOUSEACTIVATE:
          WmNCHitTest(ref m);
          break;
        case NativeMethods.WM_CONTEXTMENU:
          result = WmContextMenu(ref m);
          break;
      }
      if (result == 0)
        base.WndProc(ref m);
    }

    // ReSharper disable once InconsistentNaming
    private void WmNCHitTest(ref Message m)
    {
      //Debug.WriteLine(MouseButtons);
      if (MouseButtons == MouseButtons.Left)
        HitTestPoint = new Point(m.LParam.ToInt32());
    }

    private int WmContextMenu(ref Message m)
    {

      int x, y;
      ContextMenuStrip menu = null;
      GridCoord cellCoord = new EhLib.GridCoord(-1, -1);
      Point menuPos = Point.Empty;

      EhLibUtils.SplitIntPtr(m.LParam, out x, out y);


      if (x == -1 && y == -1)
      {
        cellCoord = CalcCellCoordFromPoint(Col, Row);
        Rectangle cellRect = CellRect(Col, Row);
        menuPos = new Point(cellRect.Left + cellRect.Width / 2, cellRect.Top + cellRect.Height / 2);
        if ((cellCoord.X >= 0) && (cellCoord.Y >= 0))
          menu = GetCellContextMenuStrip(menuPos, cellCoord.X, cellCoord.Y);
      }
      else
      {
        menuPos = PointToClient(new Point(x, y));
        cellCoord = CalcCellCoordFromPoint(menuPos.X, menuPos.Y);
        if ((cellCoord.X >= 0) && (cellCoord.Y >= 0))
          menu = GetCellContextMenuStrip(menuPos, cellCoord.X, cellCoord.Y);
      }

      if (menu == null)
        menu = ContextMenuStrip;

      if (menu != null)
      {
        ShowContextMenuStrip(menu, menuPos, cellCoord.X, cellCoord.Y);
        return 1;
      }
      else
      {
        return 0;
        //DefWndProc(ref m);
      }
    }

    protected internal virtual void FocusGrid()
    {
      Focus();
    }

    public virtual bool GridMouseSpecialStateActive()
    {
      if (gridState != BaseGridState.Normal)
        return true;
      else
        return false;
    }

    protected internal void UpdateCursor(MouseEventArgs e)
    {
      Cursor newCursor = Cursor;
      TestSetCursor(e, ref newCursor);
      Cursor = newCursor;
    }

    protected internal virtual bool CanShowScrollBar(Orientation kind)
    {
      return true;
    }

    private void Border_BorderStateChanged(object sender, EventArgs e)
    {
      ControlBorderChanged();
    }

    protected virtual void ControlBorderChanged()
    {
      UpdateBoundaries();
    }

    protected internal virtual void FixedFillOptionsChanged()
    {

    }

    protected internal virtual void GridBackgroundChanged()
    {
      Invalidate();
    }

    void ICellBackFillerOwner.BackFillerChanged(CellBackFiller backFiller)
    {
      BackFillerChanged(backFiller);
    }

    protected virtual void BackFillerChanged(CellBackFiller backFiller)
    {
      Invalidate();
    }

    Color ICellBackFillerOwner.BackFillerDefaultColor(CellBackFiller backFiller)
    {
      return BackFillerDefaultColor(backFiller);
    }

    protected virtual Color BackFillerDefaultColor(CellBackFiller backFiller)
    {
      return SystemColors.ButtonFace;
    }

    Color ICellBackFillerOwner.BackFillerDefaultSecondColor(CellBackFiller backFiller)
    {
      return BackFillerDefaultSecondColor(backFiller);
    }

    protected virtual Color BackFillerDefaultSecondColor(CellBackFiller backFiller)
    {
      return BackColor;
    }

    CellFillStyle ICellBackFillerOwner.BackFillerDefaultFillStyle(CellBackFiller backFiller)
    {
      return BackFillerDefaultFillStyle(backFiller);
    }

    protected virtual CellFillStyle BackFillerDefaultFillStyle(CellBackFiller backFiller)
    {
      return CellFillStyle.VisualStyles;
    }

    CellInnerBorderStyle ICellBackFillerOwner.BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    {
      return BackFillerDefaultInnerBorder(backFiller);
    }

    protected virtual CellInnerBorderStyle BackFillerDefaultInnerBorder(CellBackFiller backFiller)
    {
      return CellInnerBorderStyle.RaisedTopLeft;
    }

    public virtual BaseGridCellManager CellByColRow(int colIndex, int rowIndex)
    {
      return CellMan;
    }

    public BaseGridCellManager CellByColRow(int colIndex, int rowIndex, out int localColIndex, out int localRowIndex)
    {
      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex);
      cell.GridCellPosToAreaCellPos(colIndex, rowIndex, out localColIndex, out localRowIndex);
      return cell;
    }

    #endregion

  }

}