{ ------------------------------------------------------------- }
{ Purpose : NextGrid 6                                          }
{ By      : Bojan Nikolic                                       }
{ For     : BergSoft                                            }
{ ------------------------------------------------------------- }
{ Copyright (C) BergSoft.net 2021. All Rights Reserved.         }
{ ------------------------------------------------------------- }
{$I '..\NxSuite6.inc'}

unit NxGridView6;

interface

uses
  { Standard }
  Classes, Types, Windows, Graphics, ExtCtrls, Messages, Controls,
  { Next Standard 6 }
  NxClasses6, NxTypes6, NxIntf6, NxConsts6, NxControls6, NxEdit6, NxPopupCtrls6,
  { NextGrid 6 }
  NxColumns6, NxGridStylePaint6, NxCells6;

const
  szFooterHeight = 18;
  szFooterSplitterHeight = 4;
  szHeaderHeight = 18;
  szIndicatorWidth = 16;
  szInsertRowHeight = 16;
  szInsertRowSplitterHeight = 4;
  szMoveRowThreshold = 0.33;

const
  crHeaderNoDrop = -13;

type
  TNxBorderEdgeLocation = (beRight, beBottom, beLeft, beTop);

  TNxBorderEdge6 = record
    Color: TColor;
    Style: TPenStyle;
  end;

  TNxBorderEdges = array[TNxBorderEdgeLocation] of TNxBorderEdge6;

  TNxGridViewOptions = set of (voLockFixedColumns);

  TNxGridLinesStyle = (glActiveOnly, glBoth, glHorizontalOnly, glVerticalOnly);
  TNxCellHintLocation = (hlBottom, hlBottomRight);

  TNxTextLocation = (tlLeft, tlTop);
  TNxSlideDrawState = set of (ssSelected, ssFocused);
  TNxBestFitMode = set of (bfCells, bfFooter, bfHeader);
  TNxHomeEndBehaviour = (heTopBottom, heLeftRight);

  TNxGetCellColorEvent = procedure (Sender: TObject; ACol, ARow: Integer; var CellColor: TColor; State: TNxCellPaintingState) of object;
  TNxGetCellGridEvent = procedure (Sender: TObject; ACol, ARow: Integer; var Edges: TNxBorderEdges; State: TNxCellPaintingState) of object;
  TNxGetSlideColorEvent = procedure (Sender: TObject; Index: Integer; var SlideColor: TColor; State: TNxSlideDrawState) of object;

  TNxGridView6 = class;
  TNxGridViews6 = class;
  TNxGridViewClass = class of TNxGridView6;

  { TNxAlternatingRowColorsOptions }

  TNxAlternatingRowColorsOptions = class(TPersistent)
  private
    FIncludeInactiveRows: Boolean;
    FOnChange: TNotifyEvent;
    procedure SetIncludeInactiveRows(const Value: Boolean);
  protected
    procedure DoChange; dynamic;
  public
    constructor Create;
  published
    property IncludeInactiveRows: Boolean read FIncludeInactiveRows write SetIncludeInactiveRows default True;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  { INxGridViewControl }

  INxGridViewControl = interface(INxViewControl)
    ['{9A550941-C4F1-47BB-A2E6-ABC0E5E0B0B5}']
    { Property Accessors }
    function GetAlternatingRowColor: TColor;
    function GetAlternatingRowColorOptions: TNxAlternatingRowColorsOptions;
    function GetAppearanceOptions: TNxAppearanceOptions;
    function GetCaption: TCaption;
    function GetCell(ACol, ARow: Integer): INxCell;
    function GetCellHintLocation: TNxCellHintLocation;
    function GetCellSource: INxCells;
    function GetColor: TColor;
    function GetColumns: TNxColumns6;
    function GetContentIndent: TSize;
    function GetEditingCell: TPoint;
    function GetFont: TFont;
    function GetHandle: HWND;
    function GetHideFocus: Boolean;
    function GetHideSelection: Boolean;
    function GetHighlighted(ACol, ARow: Integer): Boolean;
    function GetHorzScrollBar: TNxScrollBar;
    function GetInactiveSelectionColor: TColor;
    function GetInplaceEdit: INxInplaceEdit;
    function GetInsertSelected: Boolean;
    function GetInvertSelected: Boolean;
    function GetMultiSelect: Boolean;
    function GetMultiSort: Boolean;
    function GetRightClickSelect: Boolean;
    function GetRowHeight: Integer;
    function GetRowSize(Index: Integer): Integer;
    function GetSecondClickEditing: Boolean;
    function GetSelected(Index: Integer): Boolean;
    function GetSelectedCol: Integer;
    function GetSelectedLocation: TPoint;
    function GetSelectedRow: Integer;
    function GetSelectFullRow: Boolean;
    function GetSelectionColor: TColor;
    function GetSelectionKey: Word;
    function GetSelectionTextColor: TColor;
    function GetStylePaint: INxGridStylePaint;
    function GetVertScrollBar: TNxScrollBar;
    procedure SetHighlighted(ACol, ARow: Integer; const Value: Boolean);
    procedure SetInsertSelected(const Value: Boolean);
    procedure SetRightClickSelect(const Value: Boolean);
    procedure SetRowHeight(const Value: Integer);
    procedure SetSelected(Index: Integer; const Value: Boolean);
    procedure SetSelectedCol(const Value: Integer);
    procedure SetSelectedRow(const Value: Integer);
    procedure SetSelectionKey(const Value: Word);
    { Methods }
    function AddInsertRow: Boolean;
    function BestFitColumn(const Column: TNxColumn6; Mode: TNxBestFitMode = [bfCells]): Integer;
    function BestFitRow(const RowIndex: Integer; const ColIndex: Integer = -1): Integer;
    function CanKeyLeaveEdit(Key: Word): Boolean;
    function CanUpdate(Options: TNxUpdateOptions): Boolean;
    function CellExists(const ACell: TPoint): Boolean; overload;
    function CellExists(const ACol, ARow: Integer): Boolean; overload;
    function CheckCell(const ACol, ARow: Integer): Boolean;
    function ClientToScreen(const Point: TPoint): TPoint;
    procedure ChangeRowHeight(const Value: Integer);
    function EditCell(ACol, ARow: Integer; Value: WideString = '';
      ForceEdit: Boolean = False): Boolean; overload;
    function EditCell(Location: TPoint; Value: WideString = ''): Boolean; overload;
    function EndEditing(AssignEditing: Boolean = True): Boolean;
    function GetNextChild(const Index: Integer; VisibleOnly: Boolean = True): Integer;
    function GetRowsBetween(FromPos, ToPos: Integer): Integer;
    function InsertCell(Index: Integer; InsertText: WideString = ''): Boolean; overload;
    function RowExists(const Index: Integer): Boolean;
    function RowPersist(const Index: Integer): Boolean;
    function ScreenToClient(const Point: TPoint): TPoint;
    procedure SetActiveCell(const Point: TPoint);
    function Focused: Boolean;
    procedure InvalidateRect(const Source: TRect);
    function IsIntegralHeight: Boolean;
    function IsSelectionValid: Boolean;
    function IsVirtual: Boolean;
    { Event Handlers }
    procedure DoBeforeSelect(var ACol, ARow: Integer; Key: Word; Shift: TShiftState);
    procedure DoCellClick(ACol, ARow: Integer; Button: TMouseButton);
    procedure DoCellDblClick(ACol, ARow: Integer);
    procedure DoCellMouseDown(ACol, ARow: Integer; Button: TMouseButton; Shift: TShiftState);
    procedure DoCellMouseEnter(ACol, ARow: Integer);
    procedure DoCellMouseLeave(ACol, ARow: Integer);
    procedure DoCustomDrawCell(ACol, ARow: Integer; CellRect: TRect;
      State: TNxCellPaintingState; var DefaultDrawing: Boolean);
    procedure DoCustomDrawFooter(Index: Integer; FooterRect: TRect);
    procedure DoCustomDrawHeader(Index: Integer; HeaderRect: TRect; HeaderState: TNxButtonState);
    procedure DoSortQuery(Index: Integer; SortKind: TNxSortKind; var Accept: Boolean);
    { Selection Methods }
    function CanSelect(const ACol, ARow: Integer): Boolean;
    procedure MoveByColumn(Distance: Integer; Shift: TShiftState = []);
    procedure MoveByPage(MoveUp: Boolean; Shift: TShiftState = []);
    procedure MoveByRow(Distance: Integer; Shift: TShiftState = []);
    procedure SelectCell(ACol, ARow: Integer; Shift: TShiftState = []);
    procedure SelectFirst(Shift: TShiftState = []);
    procedure SelectLast(Shift: TShiftState = []);
    procedure TabByColumn(Shift: TShiftState; LeaveControl: Boolean);
    procedure UpdateInplaceEditor;
    procedure UpdateScrollBars;
    procedure Update;
    { Properties }
    property AlternatingRowColor: TColor read GetAlternatingRowColor;
    property AlternatingRowColorOptions: TNxAlternatingRowColorsOptions read GetAlternatingRowColorOptions;
    property AppearanceOptions: TNxAppearanceOptions read GetAppearanceOptions;
    property Caption: TCaption read GetCaption;
    property Cell[ACol, ARow: Integer]: INxCell read GetCell;
    property CellHintLocation: TNxCellHintLocation read GetCellHintLocation;
    property Color: TColor read GetColor;
    property Columns: TNxColumns6 read GetColumns;
    property ContentIndent: TSize read GetContentIndent;
    property EditingCell: TPoint read GetEditingCell;
    property Font: TFont read GetFont;
    property Handle: HWND read GetHandle;
    property HideFocus: Boolean read GetHideFocus;
    property HideSelection: Boolean read GetHideSelection;
    property Highlighted[ACol, ARow: Integer]: Boolean read GetHighlighted write SetHighlighted;
    property HorzScrollBar: TNxScrollBar read GetHorzScrollBar;
    property InactiveSelectionColor: TColor read GetInactiveSelectionColor;
    property InplaceEdit: INxInplaceEdit read GetInplaceEdit;
    property InsertSelected: Boolean read GetInsertSelected write SetInsertSelected;
    property InvertSelected: Boolean read GetInvertSelected;
    property MultiSelect: Boolean read GetMultiSelect;
    property MultiSort: Boolean read GetMultiSort;
    property RightClickSelect: Boolean read GetRightClickSelect write SetRightClickSelect;
    property RowHeight: Integer read GetRowHeight write SetRowHeight;
    property SecondClickEditing: Boolean read GetSecondClickEditing;
    property Selected[Index: Integer]: Boolean read GetSelected write SetSelected;
    property SelectedLocation: TPoint read GetSelectedLocation;
    property SelectedCol: Integer read GetSelectedCol write SetSelectedCol;
    property SelectedRow: Integer read GetSelectedRow write SetSelectedRow;
    property SelectFullRow: Boolean read GetSelectFullRow;
    property SelectionColor: TColor read GetSelectionColor;
    property SelectionKey: Word read GetSelectionKey write SetSelectionKey;
    property SelectionTextColor: TColor read GetSelectionTextColor;
    property StylePaint: INxGridStylePaint read GetStylePaint;
    property VertScrollBar: TNxScrollBar read GetVertScrollBar;
  end;

  { TNxGridViews6 }

  TNxGridViews6 = class
  private
    FList: TList;
    FViewControl: INxGridViewControl;
    { Property Accessors }
    function GetItem(Index: Integer): TNxGridView6;
    function GetCount: Integer;
  public
    constructor Create(AControl: INxGridViewControl);
    destructor Destroy; override;
    { Methods }
    function Add(ViewClass: TNxGridViewClass): TNxGridView6; overload;
    procedure Add(View: TNxGridView6); overload;
    procedure Clear;
    procedure Delete(const Index: Integer);
    function IndexOf(const View: TNxGridView6): Integer;
    function Remove(const View: TNxGridView6): Integer;
    { Properties }
    property Control: INxGridViewControl read FViewControl write FViewControl;
    property Count: Integer read GetCount;
    property Item[Index: Integer]: TNxGridView6 read GetItem; default;
  end;

  { TNxHeaderControlArrow }

  TNxArrowKind = (akNone, akUp, akDown);

  TNxHeaderControlArrow = class(TNxFlyoverControl6)
  private
    FArrowKind: TNxArrowKind;
    procedure SetArrowKind(const Value: TNxArrowKind);
  protected
    procedure Paint; override;
    procedure SetWindowShape; virtual;
  public
    constructor Create(AOwner: TComponent); override;
    property ArrowKind: TNxArrowKind read FArrowKind write SetArrowKind;
  end;

  { TNxColumnHeaderControl }

  TNxLocationEvent = procedure (Sender: TObject; X, Y: Integer) of object;

  TNxColumnHeaderControl = class(TNxFlyoverControl6)
  private
    FColumn: TNxColumn6;
    FOnDrop: TNxLocationEvent;
    FOnMove: TNxLocationEvent;
    FStylePaint: INxGridStylePaint;
  protected
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure Paint; override;
  public
    procedure MoveToPoint(Location: TPoint);
    { Properties }
    property Column: TNxColumn6 read FColumn write FColumn;
    property StylePaint: INxGridStylePaint read FStylePaint write FStylePaint;
    property OnDrop: TNxLocationEvent read FOnDrop write FOnDrop;
    property OnMove: TNxLocationEvent read FOnMove write FOnMove;
  end;

  { TNxGridView }

  TNxGridViewState = set of (taHintCreating);

  TNxHeaderMouseDownEvent = procedure (Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; Col, X, Y: Integer) of object;

  TNxColumnMoveOverEvent = procedure (Sender: TObject; CurrentPosition, NewPosition: Integer;
    var Accept: Boolean) of object;

  TNxColumnMoveDropEvent = procedure (Sender: TObject; ACol, OldPosition, NewPosition: Integer) of object;

  TNxGridView6 = class(TComponent, INxParentColumnView, INxInteract,
    INxDropDown,
    INxDesignNotificationRecipient,
    INxPersistentDesignResponder)
  private
    { Property Fields }
    FCapturedView: INxColumnView;
    FCellHint: THintWindow;
    FCellTextFitHint: THintWindow;
    FClickOnSelected: Boolean;
    FColumnMoving: Boolean;
    FEnabled: Boolean;
    FFilterPopup: TNxFilterPopupControl6;
    FFixedColCount: Integer;
    FFixedRowCount: Integer;
    FFooterGridLinesColor: TColor;
    FFooterHeight: Integer;
    FGridLines: Boolean;
    FGridLinesColor: TColor;
    FGridLinesStyle: TNxGridLinesStyle;
    FHeaderArrows: array[0..1] of TNxHeaderControlArrow;
    FHeaderControl: TNxColumnHeaderControl;
    FHeaderHeight: Integer;
    FHeaderHint: THintWindow;
    FHeaderHintDelayTimer: TTimer;
    FHomeEndBehaviour: TNxHomeEndBehaviour;
    FHotCell: TPoint;
    FHoverButton: TNxColumn6;
    FHoverFooter: TNxColumn6;
    FHoverHeader: TNxColumn6;
    FIndicatorWidth: Integer;
    FInsertRowHeight: Integer;
    FLastFixedRow: Integer;
    FMouseDown: Boolean;
    FMouseDownLocation: TPoint;
    FOnActivate: TNotifyEvent;
    FOnColumnMoveOver: TNxColumnMoveOverEvent;
    FOnColumnMoveDrop: TNxColumnMoveDropEvent;
    FOnFooterMouseDown: TNxHeaderMouseDownEvent;
    FOnGetCellColor: TNxGetCellColorEvent;
    FOnGetCellGrid: TNxGetCellGridEvent;
    FOnHeaderMouseDown: TNxHeaderMouseDownEvent;
    FOptions: TNxGridViewOptions;
    FPressedCell: TPoint;
    FPressedHeader: TNxColumn6;
    FPressedHeaderButton: TNxColumn6;
    FPressedInsertColumn: TNxColumn6;
    FResizeReadyColumn: TNxColumn6;
    FResizingColumn: TNxColumn6;
    FResizingPos: TPoint;
    FResponsiveWidth: Integer;
    FSelectionStyle: TNxSelectionStyle;
    FShowFooter: Boolean;
    FShowHeader: Boolean;
    FShowIndicator: Boolean;
    FShowInsertRow: Boolean;
    FState: TNxGridViewState;
    FViews: TNxGridViews6;
    { Property Accessors }
    function GetCanvas: TCanvas;
    function GetCaptionRect: TRect;
    function GetCell(const ACol, ARow: Integer): INxCell;
    function GetCells: INxCells;
    function GetCellVisible(const ACol, ARow: Integer): Boolean;
    function GetClientHeight: Integer;
    function GetClientRect: TRect;
    function GetColor: TColor;
    function GetColumns: TNxColumns6;
    function GetControl: INxGridViewControl;
    function GetFixedHeight: Integer;
    function GetFixedWidth: Integer;
    function GetGridSize(Location: TNxLocation): Integer;
    function GetHorzScrollBar: INxScrollBar;
    function GetHoverCell: TPoint;
    function GetIndex: Integer;
    function GetIndicatorRect: TRect;
    function GetOffset: TSize;
    function GetRow(Index: Integer): INxRow;
    function GetRowCount: Integer;
    function GetRowHeight(Index: Integer): Integer;
    function GetRowsControl: INxRowsControl;
    function GetSelectedCol: Integer;
    function GetSelectionStyle: TNxSelectionStyle;
    function GetShowing(const Index: Integer): Boolean;
    function GetShowingCount: Integer;
    function GetStylePaint: INxGridStylePaint;
    function GetVertScrollBar: INxScrollBar;
    function GetViews: TNxGridViews6;
    function GetVirtualMode: Boolean;
    procedure SetCanvas(const Value: TCanvas);
    procedure SetClientRect(const Value: TRect);
    procedure SetEnabled(const Value: Boolean);
    procedure SetFixedColCount(const Value: Integer);
    procedure SetFixedRowCount(const Value: Integer);
    procedure SetFooterGridLinesColor(const Value: TColor);
    procedure SetFooterHeight(const Value: Integer);
    procedure SetGridLines(const Value: Boolean);
    procedure SetGridLinesColor(const Value: TColor);
    procedure SetGridLinesStyle(const Value: TNxGridLinesStyle);
    procedure SetHeaderHeight(const Value: Integer);
    procedure SetHoverButton(const Value: TNxColumn6);
    procedure SetHoverCell(const Value: TPoint);
    procedure SetHoverFooter(const Value: TNxColumn6);
    procedure SetHoverHeader(const Value: TNxColumn6);
    procedure SetIndex(const Value: Integer);
    procedure SetIndicatorWidth(const Value: Integer);
    procedure SetInsertRowHeight(const Value: Integer);
    procedure SetOptions(const Value: TNxGridViewOptions);
    procedure SetPressedCell(const Value: TPoint);
    procedure SetPressedHeader(const Value: TNxColumn6);
    procedure SetPressedHeaderButton(const Value: TNxColumn6);
    procedure SetResizeReadyColumn(const Value: TNxColumn6);
    procedure SetResizingColumn(const Value: TNxColumn6);
    procedure SetResizingPos(const Value: TPoint);
    procedure SetResponsiveWidth(const Value: Integer);
    procedure SetSelectionStyle(const Value: TNxSelectionStyle);
    procedure SetShowFooter(const Value: Boolean);
    procedure SetShowHeader(const Value: Boolean);
    procedure SetShowIndicator(const Value: Boolean);
    procedure SetShowInsertRow(const Value: Boolean);
    function GetSelectedRow: Integer;
  protected
    { INxObject }
    function ToObject: TObject;
    procedure CaptureView(const Location: TPoint); overload;
    procedure ViewChanged(View: INxColumnView);
    { INxDesignResponder }
    function GetInstance: TPersistent;
    procedure DesignNotification(Sender: INxDesignNotificationRecipient; Operation: TNxDesignOperation);
    { Event Handlers }
    procedure DoColumnMoveOver(CurrentPosition, NewPosition: Integer; var Accept: Boolean); dynamic;
    procedure DoColumnMoveDrop(ACol, OldPosition, NewPosition: Integer); dynamic;
    procedure DoFooterMouseDown(Button: TMouseButton; Shift: TShiftState; Col, X, Y: Integer); dynamic;
    procedure DoGetCellColor(ACol, ARow: Integer; var CellColor: TColor;
      State: TNxCellPaintingState); dynamic;
    procedure DoGetCellGrid(Sender: TObject; ACol, ARow: Integer; var Edges: TNxBorderEdges;
      State: TNxCellPaintingState); dynamic;
    procedure DoHeaderControlDrop(Sender: TObject; X, Y: Integer);
    procedure DoHeaderControlMove(Sender: TObject; X, Y: Integer);
    procedure DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; Col, X, Y: Integer); dynamic;
    { Timer Handlers }
    procedure DoFooterHintDelayTimer(Sender: TObject);
    procedure DoHeaderHintDelayTimer(Sender: TObject);
    { INxDropDown }
    procedure DoCloseUp; dynamic;
    procedure DoSelect; dynamic;
    function GetAutoClose: Boolean;
    function GetDroppedDown: Boolean;
    procedure SetDroppedDown(const Value: Boolean);
    { Methods }
    function GetClientDataRect: TRect; virtual;
    function GetDataBottom: Integer; virtual;
    function GetDataRect: TRect; virtual;
    function GetFirstRowInPage: Integer; virtual; abstract;
    function GetFirstSelectableCol: Integer; virtual;
    function GetFixedRect: TRect; virtual;
    function GetFooterRect: TRect; virtual;
    function GetFullRowHeight(Index: Integer): Integer; virtual;
    function GetHeaderDropRect: TRect; virtual;
    function GetHeaderRect: TRect; virtual;
    function GetHorzMax: Integer; virtual;
    function GetInsertRowRect: TRect; virtual;
    function GetItemHeight(Index: Integer): Integer; virtual; abstract;
    function GetLastRowInPage: Integer; virtual; abstract;
    function GetLastSelectableCol: Integer; virtual;
    function GetVertPageSize: Integer; virtual;
    { Virtual Methods }
    procedure DataMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
    procedure DataMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
    procedure IndicatorMouseLeave; virtual;
    procedure IndicatorMouseMove(Shift: TShiftState; X, Y: Integer); virtual;
    procedure InsertRowMouseMove(Shift: TShiftState; X, Y: Integer); virtual;
    procedure InsertRowMouseLeave; virtual;
    procedure InsertRowMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
    procedure InsertRowMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
    function GetHorzClipRect: TRect; virtual; abstract;
    function GetVertClipRect: TRect; virtual; abstract;
    { Methods }
    procedure SetScreenCursor(ACursor: TCursor);
    function GetArrowsLocation(CurrentPosition, Position: Integer): TPoint;
    procedure SetViews(const Value: TNxGridViews6); virtual;
    procedure StartHeaderDrag(X, Y: Integer);
    procedure HideArrows;
    procedure ShowArrows(Location: TPoint);
    procedure ShowCellHint(Location: TPoint; Hint: WideString);
    procedure ShowCellTextFitHint(Location: TPoint; Hint: WideString);
    { Properties }
    property PressedHeader: TNxColumn6 read FPressedHeader write SetPressedHeader;
    property PressedHeaderButton: TNxColumn6 read FPressedHeaderButton write SetPressedHeaderButton;
    property HoverButton: TNxColumn6 read FHoverButton write SetHoverButton;
    property HoverCell: TPoint read GetHoverCell write SetHoverCell;
    property HoverFooter: TNxColumn6 read FHoverFooter write SetHoverFooter;
    property HoverHeader: TNxColumn6 read FHoverHeader write SetHoverHeader;
    property Offset: TSize read GetOffset;
    property ResizeReadyColumn: TNxColumn6 read FResizeReadyColumn write SetResizeReadyColumn;
    property VirtualMode: Boolean read GetVirtualMode;
  protected
    procedure MoveByColumn(Distance: Integer; Shift: TShiftState = []); virtual;
    { Properties }
    property RowsOwner: INxRowsControl read GetRowsControl;
    property RowCount: Integer read GetRowCount;
    property Showing[const Index: Integer]: Boolean read GetShowing;
    property ShowingCount: Integer read GetShowingCount;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Changed; virtual;
    destructor Destroy; override;
    function CanSelect(const ACol, ARow: Integer): Boolean; virtual;
    { INxInteract Methods }
    procedure KeyDown(var Key: Word; Shift: TShiftState); virtual;
    procedure KeyUp; overload; virtual;
    procedure KeyUp(var Key: Word; Shift: TShiftState); overload; virtual;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
    procedure MouseLeave; virtual;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); virtual;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
    { Event Handlers }
    procedure DoAddColumn; virtual;
    procedure DoAddRow(const Count: Integer); virtual; abstract;

    procedure AfterSort; virtual; abstract;
    procedure ExpandRow(Row: INxRow; Expand: Boolean); virtual; abstract;
    procedure DoRowAppear(Index, Height: Integer; Show, Permanent: Boolean); virtual; abstract;

    { Methods }
    procedure Activate; virtual;
    procedure DataKeyDown(var Key: Word; Shift: TShiftState); virtual;
    procedure Deactivate; virtual;
    function FindFirstRowInPage: Integer;
    function GetRowCountInPage(FromPos: Integer): Integer; virtual; abstract;
    function GetRowCountInPrevPage: Integer; virtual; abstract;
    procedure Paint; virtual;
    procedure PopupFilter(Column: TNxColumn6);
    procedure PaintFocus;
    procedure Remove;
    procedure Reset; virtual;
    procedure ResizeBy(DeltaX, DeltaY: Integer); virtual; abstract;
    { Painting Methods }
    procedure InitCellView(const AView: INxColumnView; const ACol, ARow: Integer); virtual;
    procedure PaintCaption;
    procedure PaintCell(const ACol, ARow, AVisibleRowIndex: Integer; CellRect: TRect); overload; virtual;
    procedure PaintCells; virtual;
    procedure PaintCellSelection(const ACol, ARow: Integer; CellRect: TRect); virtual;
    procedure PaintFooters; virtual;
    procedure PaintGrid(const ACol, ARow: Integer; CellRect: TRect; Edges: TNxBorderEdges; State: TNxCellPaintingState); virtual;
    procedure PaintHeaders; virtual;
    procedure PaintIndicators; virtual;
    procedure PaintInsertRow; virtual;
    procedure PaintRows; virtual;
    function Pixels(Points: Integer): Integer;
    { Refresh Methods }
    procedure Invalidate; overload;
    procedure Invalidate(InvalidationRect: TRect); overload;
    procedure InvalidateCaption;
    function IsOnScreen(Index: Integer): Boolean; virtual;
    procedure RefreshCell(ACol, ARow: Integer); overload;
    procedure RefreshCell(Location: TPoint; ContentOnly: Boolean = False); overload;
    procedure RefreshCell(ACol: Integer); overload;
    procedure RefreshColumn(Column: TNxColumn6; Area: TNxGridArea); virtual;
    procedure RefreshData;
    procedure RefreshHeader(const Index: Integer);
    procedure RefreshHeaderButton(Column: TNxColumn6);
    procedure RefreshIndicator(Index: Integer); virtual; abstract;
    procedure RefreshInsertRow;
    procedure RefreshRow(Index: Integer); overload; virtual; abstract;
    procedure RefreshRow(FromPos, ToPos: Integer); overload; virtual; abstract;
    procedure RefreshSelection; virtual;
    { }
    procedure ReleaseCellHint;
    procedure ReleaseHeaderHint;
    procedure ReleaseTextFitHint;
    { Scroll Methods }
    procedure ScrollContentBy(DeltaX, DeltaY: Integer); virtual;
    procedure ScrollRect(DeltaX, DeltaY: Integer; Rect, ClipRect: TRect); virtual;
    procedure ScrollToCol(Index: Integer); virtual; abstract;
    procedure ScrollToRow(Index: Integer); virtual; abstract;
    procedure ShiftContentBy(DeltaX, DeltaY: Integer; Index: Integer); virtual; abstract;
    { Stream Methods }
    procedure SetParentComponent(Value: TComponent); override;
    function GetParentComponent: TComponent; override;
    function HasParent: Boolean; override;
    { Virtual Methods }
    procedure AdjustCellSize(var Size: TSize; Col: Integer);
    function GetCellAtCursor: TPoint;
    function GetCellAtPos(Location: TPoint): TPoint; virtual; abstract;
    function GetCellHint(ACol, ARow: Integer; Cell: INxBaseCell): WideString;
    function GetCellRect(ACol, ARow: Integer): TRect; overload; virtual; abstract;
    function GetCellRect(ACol: Integer): TRect; overload; virtual;
    function GetCellRect(Location: TPoint): TRect; overload;
//    function GetCellView(Cell: INxCell): INxColumnView;

    function GetColumnAt(X, Y: Integer; Area: TNxGridArea): TNxColumn6; virtual;
    function GetColumnRect(Column: TNxColumn6; Area: TNxGridArea = gaAll): TRect; virtual;
    function GetColumnSizeGripAtPos(X, Y: Integer): TNxColumn6;

    function GetFocusRect(Index: Integer): TRect; virtual; abstract;

    function GetHeaderButttonAtPos(X, Y: Integer): TNxColumn6;
    function GetHeaderButttonRect(Column: TNxColumn6): TRect;

    function GetItemAtPos(X, Y: Integer): Integer; virtual; abstract;
    function GetItemRect(Index: Integer): TRect; virtual; abstract;
    function GetNearestPosition(Column: TNxColumn6; Point: TPoint): Integer;

    procedure Recount; virtual;
    procedure Update;
    function UpdateCellView(ACol, ARow: Integer; CellRect: TRect): INxColumnView;
    { Properties }
    property Canvas: TCanvas read GetCanvas write SetCanvas;
    property CaptionRect: TRect read GetCaptionRect;
    property Cell[const ACol, ARow: Integer]: INxCell read GetCell;
    property Cells: INxCells read GetCells;
    property CellVisible[const ACol, ARow: Integer]: Boolean read GetCellVisible;
    property ClientDataRect: TRect read GetClientDataRect;
    property ClientHeight: Integer read GetClientHeight;
    property ClientRect: TRect read GetClientRect write SetClientRect;
    property Color: TColor read GetColor;
    property Columns: TNxColumns6 read GetColumns;
    property Control: INxGridViewControl read GetControl;
    property DataBottom: Integer read GetDataBottom;
    property DataRect: TRect read GetDataRect;
    property FirstRowInPage: Integer read GetFirstRowInPage;
    property FirstSelectableCol: Integer read GetFirstSelectableCol;
    property FixedHeight: Integer read GetFixedHeight;
    property FixedRect: TRect read GetFixedRect;
    property FixedWidth: Integer read GetFixedWidth;
    property FooterRect: TRect read GetFooterRect;
    property FullRowHeight[Index: Integer]: Integer read GetFullRowHeight;
    property GridSize[Location: TNxLocation]: Integer read GetGridSize;
    property HeaderRect: TRect read GetHeaderRect;
    property HorzMax: Integer read GetHorzMax;
    property HorzScrollBar: INxScrollBar read GetHorzScrollBar;
    property IndicatorRect: TRect read GetIndicatorRect;
    property InsertRowRect: TRect read GetInsertRowRect;
    /// <summary>
    /// Gets height of an Item (i.e. Row or Slide) adjusted with current scaling.
    /// </summary>
    property ItemHeight[Index: Integer]: Integer read GetItemHeight;
    property LastFixedRow: Integer read FLastFixedRow;
    property LastRowInPage: Integer read GetLastRowInPage;
    property LastSelectableCol: Integer read GetLastSelectableCol;
    property PressedCell: TPoint read FPressedCell write SetPressedCell;
    property ResizingColumn: TNxColumn6 read FResizingColumn write SetResizingColumn;
    property ResizingPos: TPoint read FResizingPos write SetResizingPos;
    property Row[Index: Integer]: INxRow read GetRow;
    property RowHeight[Index: Integer]: Integer read GetRowHeight;
    property SelectedCol: Integer read GetSelectedCol;
    property SelectedRow: Integer read GetSelectedRow;
    property StylePaint: INxGridStylePaint read GetStylePaint;
    property VertPageSize: Integer read GetVertPageSize;
    property VertScrollBar: INxScrollBar read GetVertScrollBar;
    property Views: TNxGridViews6 read GetViews write SetViews;
  published
    { Properties }
    property ColumnMoving: Boolean read FColumnMoving write FColumnMoving default True;
    property Enabled: Boolean read FEnabled write SetEnabled default True;
    property FixedColCount: Integer read FFixedColCount write SetFixedColCount default 0;
    property FixedRowCount: Integer read FFixedRowCount write SetFixedRowCount default 0;
    property FooterGridLinesColor: TColor read FFooterGridLinesColor write SetFooterGridLinesColor default clBtnFace;
    property FooterHeight: Integer read FFooterHeight write SetFooterHeight default szFooterHeight;
    property GridLines: Boolean read FGridLines write SetGridLines default False;
    property GridLinesColor: TColor read FGridLinesColor write SetGridLinesColor default clBtnFace;
    property GridLinesStyle: TNxGridLinesStyle read FGridLinesStyle write SetGridLinesStyle default glBoth;
    property HeaderHeight: Integer read FHeaderHeight write SetHeaderHeight default szHeaderHeight;
    property HomeEndBehaviour: TNxHomeEndBehaviour read FHomeEndBehaviour write FHomeEndBehaviour default heTopBottom;
    property Index: Integer read GetIndex write SetIndex default 0;
    property IndicatorWidth: Integer read FIndicatorWidth write SetIndicatorWidth default szIndicatorWidth;
    property InsertRowHeight: Integer read FInsertRowHeight write SetInsertRowHeight default szInsertRowHeight;
    property Options: TNxGridViewOptions read FOptions write SetOptions default [];
    property ResponsiveWidth: Integer read FResponsiveWidth write SetResponsiveWidth default 0;
    property SelectionStyle: TNxSelectionStyle read FSelectionStyle write SetSelectionStyle default stSolid;
    property ShowFooter: Boolean read FShowFooter write SetShowFooter default False;
    property ShowHeader: Boolean read FShowHeader write SetShowHeader default True;
    property ShowIndicator: Boolean read FShowIndicator write SetShowIndicator default False;
    property ShowInsertRow: Boolean read FShowInsertRow write SetShowInsertRow default False;
    { Events }
    property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
    property OnColumnMoveDrop: TNxColumnMoveDropEvent read FOnColumnMoveDrop write FOnColumnMoveDrop;
    property OnColumnMoveOver: TNxColumnMoveOverEvent read FOnColumnMoveOver write FOnColumnMoveOver;
    property OnGetCellColor: TNxGetCellColorEvent read FOnGetCellColor write FOnGetCellColor;
    property OnGetCellGrid: TNxGetCellGridEvent read FOnGetCellGrid write FOnGetCellGrid;
    property OnFooterMouseDown: TNxHeaderMouseDownEvent read FOnFooterMouseDown write FOnFooterMouseDown;
    property OnHeaderMouseDown: TNxHeaderMouseDownEvent read FOnHeaderMouseDown write FOnHeaderMouseDown;
  end;

  { TNxListGridView }

  TNxRowMoveLocation = (lcNone, lcBefore, lcAfter, lcInside);

  TNxRowMoveOptions = set of (moPosition, moInsert);
  TNxRowResizingOptions = (roResizeAllRows, roResizeSingleRow);

  TNxRowMoveDropEvent = procedure (Sender: TObject; Row, ParentRow: INxRow;
    CurIndex, NewIndex: Integer) of object;

  TNxListGridView6 = class(TNxGridView6)
  private
    FFirstIndex: Integer;
    FIngrealBottom: Integer;
    FMovingIndex: Integer;
    FMovingLocation: TNxRowMoveLocation;
    FMovingRect: TRect;
    FMovingRow: INxRow;
    FMovingTargetRow: INxRow;
    FMovingTimer: TTimer;
    FOldMovingLocation: TNxRowMoveLocation;
    FOldMovingRect: TRect;
    FOnRowMoveDrop: TNxRowMoveDropEvent;
    FResizeReadyRow: INxRow;
    FResizingRange: TRange;
    FResizingRow: INxRow;
    FRowMoving: Boolean;
    FRowMovingOptions: TNxRowMoveOptions;
    FRowResizing: Boolean;
    FRowResizingOptions: TNxRowResizingOptions;
    { Property Accessors }
    function GetFirstIndex: Integer;
    function GetFixedShowingCount: Integer;
    function GetLastFixedRow: Integer;
    function GetLastRowInView: Integer;
    procedure SetMovingRow(const Value: INxRow);
    procedure SetMovingTargetRow(const Value: INxRow);
    procedure SetResizeReadyRow(const Value: INxRow);
    procedure SetResizingRange(const Value: TRange);
    procedure SetResizingRow(const Value: INxRow);
  protected
    { INxGridView }
    procedure DoMovingTimer(Sender: TObject);
    function GetDataBottom: Integer; override;
    function GetFirstRowInPage: Integer; override;
    function GetFixedRect: TRect; override;
    function GetLastRowInPage: Integer; override;
    function GetVertPageSize: Integer; override;
    { Abstract Methods }
    function GetItemDefaultHeight: Integer; virtual; abstract;
    function GetItemGridSize(Location: TNxLocation): Integer; virtual; abstract;
    { Overrided Methods }
    procedure IndicatorMouseLeave; override;
    procedure IndicatorMouseMove(Shift: TShiftState; X, Y: Integer); override;
    { Properties }
    property ItemDefaultHeight: Integer read GetItemDefaultHeight;
    property ItemGridSize[Location: TNxLocation]: Integer read GetItemGridSize;
    /// <summary>
    /// Gets height of a Item (i.e. Row or Slide) adjusted with current scaling.
    /// </summary>
    property ItemHeight[Index: Integer]: Integer read GetItemHeight;
  public
    { Public Event Handlers }
    procedure DoAddRow(const Count: Integer); override;
    procedure DoMoveDrop(Row, ParentRow: INxRow; CurIndex, NewIndex: Integer); dynamic;
    procedure DoRowAppear(Index, Height: Integer; Appear, Delete: Boolean); override;
    procedure ExpandRow(Row: INxRow; Expand: Boolean); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Overrided Methods }
    procedure Activate; override;
    procedure Deactivate; override;
    procedure AfterSort; override;
    function GetRowCountInPage(FromPos: Integer): Integer; override;
    function GetRowCountInPrevPage: Integer; override;
    function GetHorzClipRect: TRect; override;
    function GetVertClipRect: TRect; override;
    function IsOnScreen(Index: Integer): Boolean; override;
    { Keyboard & Mouse Methods }
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseLeave; override;
    { Paint }
    procedure Paint; override;
    procedure PaintIndicators; override;
    procedure PaintMovingGuides;
    procedure Reset; override;
    procedure ResizeBy(DeltaX, DeltaY: Integer); override;
    procedure RefreshIndicator(Index: Integer); override;
    { Scroll Methods }
    procedure ScrollContentBy(DeltaX, DeltaY: Integer); override;
    procedure ScrollToRow(Index: Integer); override;
    procedure ShiftContentBy(DeltaX, DeltaY: Integer; Index: Integer); override;
    { Methods }
    function GetFocusRect(Index: Integer): TRect; override;
    function GetItemAtPos(X, Y: Integer): Integer; override;
    function GetItemRect(Index: Integer): TRect; override;
    function GetItemTop(Index: Integer): Integer; virtual;
    function GetNearestRowAtPos(X, Y: Integer; ARow: INxRow; Options: TNxRowMoveOptions;
      var Location: TNxRowMoveLocation): INxRow;
    function GetRowSizeGripAtPos(X, Y: Integer): INxRow;
    { Properties }
    property FirstIndex: Integer read GetFirstIndex;
    property FixedShowingCount: Integer read GetFixedShowingCount;
    property LastFixedRow: Integer read GetLastFixedRow;
    property LastRowInPage: Integer read GetLastRowInPage;
    property LastRowInView: Integer read GetLastRowInView;
    property MovingRow: INxRow read FMovingRow write SetMovingRow;
    property MovingTargetRow: INxRow read FMovingTargetRow write SetMovingTargetRow;
    property ResizeReadyRow: INxRow read FResizeReadyRow write SetResizeReadyRow;
    property ResizingRange: TRange read FResizingRange write SetResizingRange;
    property ResizingRow: INxRow read FResizingRow write SetResizingRow;
  published
    { Properties }
    property RowMoving: Boolean read FRowMoving write FRowMoving default False;
    property RowMovingOptions: TNxRowMoveOptions read FRowMovingOptions write FRowMovingOptions default [moPosition, moInsert];
    property RowResizing: Boolean read FRowResizing write FRowResizing default False;
    property RowResizingOptions: TNxRowResizingOptions read FRowResizingOptions
      write FRowResizingOptions default roResizeSingleRow;
    { Events }
    property OnRowMoveDrop: TNxRowMoveDropEvent read FOnRowMoveDrop write FOnRowMoveDrop;
  end;

  { TNxReportGridView6 }

  TNxDetailsRowStyle = (dsHidden, dsAlwaysShown);//, dsSelectedShown);

  TNxReportGridView6 = class(TNxListGridView6)
  private
    FColorOverflowInactiveCells: Boolean;
    FDetailsColumn: TNxColumn6;
    FDetailsRowStyle: TNxDetailsRowStyle;
    FDetailsRowHeight: Integer;
    procedure SetColorOverflowInactiveCells(const Value: Boolean);
    procedure SetDetailsColumn(const Value: TNxColumn6);
    procedure SetDetailsRowStyle(const Value: TNxDetailsRowStyle);
    procedure SetDetailsRowHeight(const Value: Integer);
  protected
    { Overrided Methods }
    function GetClientDataRect: TRect; override;
    function GetFirstColInView: Integer; virtual;
    function GetFullRowHeight(Index: Integer): Integer; override;
    function GetHorzMax: Integer; override;
    function GetVertPageSize: Integer; override;
    function GetItemDefaultHeight: Integer; override;
    function GetItemGridSize(Location: TNxLocation): Integer; override;
    function GetItemHeight(Index: Integer): Integer; override;
  public
    constructor Create(AOwner: TComponent); override;
    { Methods }
    function GetCellAtPos(Location: TPoint): TPoint; override;
    function GetCellLeft(const ACol, ARow: Integer): Integer;
    function GetCellRect(ACol, ARow: Integer): TRect; override;
    function GetCellWidth(const ACol, ARow: Integer): Integer;
    function GetGridIncludedRect(CellRect: TRect): TRect;
    function GetVertClipRect: TRect; override;
    function HasDetailsRow(const ARow: Integer): Boolean;
    procedure Paint; override;
    procedure PaintCells; override;
    procedure PreparePaintCell(ACol, ARow, AColVisibleIndex, ARowVisibleIndex: Integer;
      ACellRect: TRect);
    procedure RefreshColumn(Column: TNxColumn6; Area: TNxGridArea); override;
    procedure RefreshRow(Index: Integer); overload; override;
    procedure RefreshRow(FromPos, ToPos: Integer); overload; override;
    procedure ScrollToCol(Index: Integer); override;
    { Properties }
    property FirstColInView: Integer read GetFirstColInView;
  published
    property DetailsColumn: TNxColumn6 read FDetailsColumn write SetDetailsColumn default nil;
    property DetailsRowStyle: TNxDetailsRowStyle read FDetailsRowStyle write SetDetailsRowStyle default dsHidden;
    property DetailsRowHeight: Integer read FDetailsRowHeight write SetDetailsRowHeight default 16;
    property ColorOverflowInactiveCells: Boolean read FColorOverflowInactiveCells
      write SetColorOverflowInactiveCells default True;
  end;

  { TNxSlideGridView6 }

  TNxSlidesGridView6 = class;

  TNxSlideBound6 = class(TCollectionItem)
  private
    FCaption: WideString;
    FCaptionFont: TFont;
    FCaptionLocation: TNxTextLocation;
    FColumn: TNxColumn6;
    FHeight: Integer;
    FLeft: Integer;
    FParentCaptionFont: Boolean;
    FTop: Integer;
    FVisible: Boolean;
    FWidth: Integer;
    { Property Acessors }
    function GetBottom: Integer;
    function GetCellRect: TRect;
    function GetRight: Integer;
    function GetSlidesGridView: TNxSlidesGridView6;
    procedure SetCaption(const Value: WideString);
    procedure SetCaptionFont(const Value: TFont);
    procedure SetCaptionLocation(const Value: TNxTextLocation);
    procedure SetColumn(const Value: TNxColumn6);
    procedure SetHeight(const Value: Integer);
    procedure SetLeft(const Value: Integer);
    procedure SetParentCaptionFont(const Value: Boolean);
    procedure SetTop(const Value: Integer);
    procedure SetVisible(const Value: Boolean);
    procedure SetWidth(const Value: Integer);
  protected
    procedure Changed; virtual;
    procedure DoCaptionFontChange(Sender: TObject);
  public
    { Overrided Methods }
    procedure Assign(Source: TPersistent); override;
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    { Properties }
    property CellRect: TRect read GetCellRect;
    property SlidesGridView: TNxSlidesGridView6 read GetSlidesGridView;
  published
    { Properties }
    property Bottom: Integer read GetBottom;
    property Caption: WideString read FCaption write SetCaption;
    property CaptionFont: TFont read FCaptionFont write SetCaptionFont;
    property CaptionLocation: TNxTextLocation read FCaptionLocation write SetCaptionLocation default tlTop;
    property Column: TNxColumn6 read FColumn write SetColumn;
    property Height: Integer read FHeight write SetHeight default 16;
    property Left: Integer read FLeft write SetLeft default 0;
    property ParentCaptionFont: Boolean read FParentCaptionFont write SetParentCaptionFont default True;
    property Right: Integer read GetRight;
    property Top: Integer read FTop write SetTop default 0;
    property Visible: Boolean read FVisible write SetVisible default True;
    property Width: Integer read FWidth write SetWidth default 80;
  end;

  TNxSlideBounds6 = class(TCollection)
  private
    FOwner: TNxSlidesGridView6;
    function GetItem(Index: Integer): TNxSlideBound6;
    procedure SetItem(Index: Integer; const Value: TNxSlideBound6);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TNxSlidesGridView6);
    function Add: TNxSlideBound6;
    function GetBoundRect(Column: TNxColumn6): TRect;
    function IndexOf(Column: TNxColumn6): Integer;
    property Items[Index: Integer]: TNxSlideBound6 read GetItem write SetItem; default;
  end;

  { TNxSlidesGridView6 }

  TNxMeasureSlideHeightEvent = procedure (Sender: TObject; Index: Integer;
    var SlideHeight: Integer) of object;

  TNxSlidesGridView6 = class(TNxListGridView6)
  private
    FBounds: TNxSlideBounds6;
    FCaptionFont: TFont;
    FOnGetSlideColor: TNxGetSlideColorEvent;
    FOnMeasureSlideHeight: TNxMeasureSlideHeightEvent;
    FSlideGridLines: Boolean;
    FSlideHeight: Integer;
    FSlideSelectionStyle: TNxSlideSelectionStyle;
    FSlideSelectionFrameWidth: Integer;
    function GetSlideGridSize: Integer;
    procedure SetBounds(const Value: TNxSlideBounds6);
    procedure SetCaptionFont(const Value: TFont);
    procedure SetSlideGridLines(const Value: Boolean);
    procedure SetSlideHeight(const Value: Integer);
    procedure SetSlideSelectionFrameWidth(const Value: Integer);
    procedure SetSlideSelectionStyle(const Value: TNxSlideSelectionStyle);
  protected
    { Event Handlers }
    procedure DoCaptionFontChange(Sender: TObject);
    procedure DoGetSlideColor(Index: Integer; var SlideColor: TColor;
      State: TNxSlideDrawState); dynamic;
    procedure DoMeasureSlideHeight(Index: Integer; var SlideHeight: Integer); dynamic;
    { Overriden Methods }
    procedure DataMouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    function GetItemDefaultHeight: Integer; override;
    function GetItemGridSize(Location: TNxLocation): Integer; override;
    function GetItemHeight(Index: Integer): Integer; override;
    function GetLastRowInPage: Integer; override;
    function GetVertPageSize: Integer; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    property SlideGridSize: Integer read GetSlideGridSize;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Methods }
    function GetCellAtPos(Location: TPoint): TPoint; override;
    function GetCellRect(ACol, ARow: Integer): TRect; override;
    function GetItemRect(Index: Integer): TRect; override;
    function GetItemTop(Index: Integer): Integer; override;
    function GetRowCountInPage(FromPos: Integer): Integer; override;
    procedure PaintCells; override;
    procedure RefreshColumn(Column: TNxColumn6; Area: TNxGridArea); override;
    procedure RefreshIndicator(Index: Integer); override;
    procedure RefreshRow(Index: Integer); overload; override;
    procedure RefreshRow(FromPos, ToPos: Integer); overload; override;
    procedure RefreshSelection; override;
    { Painting }
    class procedure PaintSlideBoundCaption(Canvas: TCanvas;
      const SlideBound: TNxSlideBound6; CaptionRect: TRect); virtual;
    { Public Methods }
    class function GetCaptionRect(Canvas: TCanvas; const SlideBound: TNxSlideBound6; SlideRect: TRect): TRect;
    function GetSlideHeight(const Index: Integer): Integer;
    { Scroll Methods }
    procedure ScrollContentBy(DeltaX, DeltaY: Integer); override;
    procedure ScrollToCol(Index: Integer); override;
  published
    { Properties }
    property Bounds: TNxSlideBounds6 read FBounds write SetBounds;
    property CaptionFont: TFont read FCaptionFont write SetCaptionFont;
    property ShowHeader default False;
    property SlideGridLines: Boolean read FSlideGridLines write SetSlideGridLines default True;
    property SlideHeight: Integer read FSlideHeight write SetSlideHeight default 60;
    property SlideSelectionStyle: TNxSlideSelectionStyle read FSlideSelectionStyle write
      SetSlideSelectionStyle default slSolid;
    property SlideSelectionFrameWidth: Integer read FSlideSelectionFrameWidth write
      SetSlideSelectionFrameWidth default 2;
    { Events }
    property OnGetSlideColor: TNxGetSlideColorEvent read FOnGetSlideColor write FOnGetSlideColor;
    property OnMeasureSlideHeight: TNxMeasureSlideHeightEvent read FOnMeasureSlideHeight write FOnMeasureSlideHeight;
  end;

implementation

uses
  { Standard }
  SysUtils, Forms, Dialogs, Math,
  { Next Common 6 }
  NxGraphics6,
  { NextGrid 6 }
  NxCustomGrid6, NxColumnViewClasses6
  { GExperts }
{$IFDEF DEBUG_INTF}
  ,DbugIntf
{$ENDIF}
  ;

function ColorEdges(Color: TColor): TNxBorderEdges;
begin
  Result[beRight].Color := Color;
  Result[beRight].Style := psSolid;
  Result[beBottom].Color := Color;
  Result[beBottom].Style := psSolid;
  Result[beLeft].Color := Color;
  Result[beLeft].Style := psSolid;
  Result[beTop].Color := Color;
  Result[beTop].Style := psSolid;
end;

{ TNxAlternatingRowColorsOptions }

constructor TNxAlternatingRowColorsOptions.Create;
begin
  FIncludeInactiveRows := True;
end;

procedure TNxAlternatingRowColorsOptions.DoChange;
begin
  if Assigned(FOnChange) then FOnChange(Self);
end;

procedure TNxAlternatingRowColorsOptions.SetIncludeInactiveRows(const Value: Boolean);
begin
  if Value <> FIncludeInactiveRows then
  begin
    FIncludeInactiveRows := Value;
    DoChange;
  end;
end;

{ TNxGridViews6 }

procedure TNxGridViews6.Add(View: TNxGridView6);
begin
  if Assigned(View) then
  begin

    { Associate }
    View.Views := Self;

  end else
    raise EInvalidInsert.Create(exNilParameter);
end;

function TNxGridViews6.Add(ViewClass: TNxGridViewClass): TNxGridView6;
begin
  Result := ViewClass.Create(Control.ToObject as TComponent);
  Add(Result);
end;

procedure TNxGridViews6.Clear;
var
  i: Integer;
begin
  for i := Pred(Count) downto 0 do Delete(i);
  FList.Clear;
end;

constructor TNxGridViews6.Create(AControl: INxGridViewControl);
begin
  FViewControl := AControl;

  { List }
  FList := TList.Create;
end;

procedure TNxGridViews6.Delete(const Index: Integer);
begin
  Item[Index].Free;
end;

destructor TNxGridViews6.Destroy;
begin
  Clear;
  { Destroy Objects }
  FreeAndNil(FList);
  inherited;
end;

function TNxGridViews6.GetCount: Integer;
begin
  Result := FList.Count;
end;

function TNxGridViews6.GetItem(Index: Integer): TNxGridView6;
begin
  Result := TNxGridView6(FList[Index]);
end;

function TNxGridViews6.IndexOf(const View: TNxGridView6): Integer;
begin
  Result := FList.IndexOf(View);
end;

function TNxGridViews6.Remove(const View: TNxGridView6): Integer;
begin
  { ToDo: Add AV}
  if FList <> nil then Result := FList.Remove(View)
    else raise EAccessViolation.Create(exViewNotExists);
end;

{ TNxHeaderControlArrow }

constructor TNxHeaderControlArrow.Create(AOwner: TComponent);
begin
  inherited;
  FArrowKind := akNone;
  Height := 9;
  Width := 9;
end;

procedure TNxHeaderControlArrow.Paint;
begin
  inherited;
  with Canvas do
  begin
    Brush.Color := clRed;
    FillRect(ClientRect);
  end;
end;

procedure TNxHeaderControlArrow.SetArrowKind(const Value: TNxArrowKind);
begin
  FArrowKind := Value;
  SetWindowShape;
end;

procedure TNxHeaderControlArrow.SetWindowShape;
var
  APoints: array[1..8] of TPoint;
  R: HRGN;
begin
  inherited;
  case FArrowKind of
    akDown:
    begin
      APoints[1] := Point(5, 0);
      APoints[2] := Point(3, 0);
      APoints[3] := Point(3, 4);
      APoints[4] := Point(0, 4);
      APoints[5] := Point(4, 9);
      APoints[6] := Point(9, 4);
      APoints[7] := Point(6, 4);
      APoints[8] := Point(6, 0);
    end;
    akUp:
    begin
      APoints[1] := Point(-1, 5);
      APoints[2] := Point(4, -1);
      APoints[3] := Point(9, 5);
      APoints[4] := Point(6, 5);
      APoints[5] := Point(6, 9);
      APoints[6] := Point(3, 9);
      APoints[7] := Point(3, 4);
      APoints[8] := Point(0, 5);
    end;
  end;
  R := CreatePolygonRgn(APoints, 8, WINDING);
  SetWindowRgn(Handle, R, True);
end;

{ TNxColumnHeaderControl }

procedure TNxColumnHeaderControl.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  ScreenPoint: TPoint;
begin
  inherited;
  ScreenPoint := ClientToScreen(Point(X, Y));

  MoveToPoint(ScreenPoint);

  { Trigger event }
  if Assigned(FOnMove)
    then FOnMove(Self, ScreenPoint.X, ScreenPoint.Y);
end;

procedure TNxColumnHeaderControl.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  ScreenPoint: TPoint;
begin
  inherited;
  ScreenPoint := ClientToScreen(Point(X, Y));

  { Trigger event }
  if Assigned(FOnDrop) then
    FOnDrop(Self, ScreenPoint.X, ScreenPoint.Y);
end;

procedure TNxColumnHeaderControl.MoveToPoint(Location: TPoint);
begin
  SetBounds(Location.X - Width div 2, Location.Y - Height + 5, Width, Height);
end;

procedure TNxColumnHeaderControl.Paint;
var
  ACanvas: TCanvas;
begin
  inherited;
  StylePaint.SetColumn(Column);
  ACanvas := StylePaint.Canvas;
  try
    StylePaint.Canvas := Canvas;
    StylePaint.Color := Color;
    StylePaint.SetLocation(clAlone);
    StylePaint.PaintHeader(ClientRect, []);
  finally
    StylePaint.Canvas := ACanvas;
  end;
end;

{ TNxGridView }

procedure TNxGridView6.Activate;
begin
  if Assigned(OnActivate) then OnActivate(Self);
end;

procedure TNxGridView6.AdjustCellSize(var Size: TSize; Col: Integer);
begin
  with Size do
  begin
    Inc(cx, Columns[Col].Padding.Left);
    Inc(cx, Columns[Col].Padding.Right);
    Inc(cx, GridSize[loRight]);

    Inc(cy, Columns[Col].Padding.Top);
    Inc(cy, Columns[Col].Padding.Bottom);
    Inc(cx, GridSize[loBottom]);
  end;
end;

function TNxGridView6.CanSelect(const ACol, ARow: Integer): Boolean;
begin
  Result := True;
end;

/// <summary>
/// Capture View of location
/// </summary>
procedure TNxGridView6.CaptureView(const Location: TPoint);
var
  View: INxColumnView;
  RowView: INxRowView;
begin
  if not Columns.Exist(Location.X)
    or not Columns[Location.X].Enabled
      then Exit;

  { Access Orig. View }
  View := Columns[Location.X].View;

  { Important }
  if not View.IsResponsive then Exit;

  View.Control := TWinControl(GetComponent(Control));
  View.Location := Location;
  View.Parent := Self;

  if Location.Y = -1 then
  begin
    View.Cell := Columns[Location.X].InsertValue;
    View.ClientRect := GetCellRect(Location.X);
    View.Selected := False;
    View.Pressed := IsEqual(Location, PressedCell);
  end else
  begin
    View.Cell := Control.Cell[Location.X, Location.Y];
    View.Selected := Control.Highlighted[Location.X, Location.Y];
    View.ClientRect := GetCellRect(Location);
    View.Pressed := IsEqual(Location, PressedCell);
  end;

  //TODO: InitCellView

  InitCellView(View, Location.X, Location.Y);

  if Supports(View, INxRowView, RowView) then
  begin
    if Location.Y > -1 then
      RowView.Row := Row[Location.Y];
  end;

  { Clone Obj. }
  FCapturedView := View.Clone;

  { Can Hover & Press }
  FCapturedView.Active := True;
end;

procedure TNxGridView6.SetScreenCursor(ACursor: TCursor);
begin
  if ACursor <> Screen.Cursor then
    Screen.Cursor := ACursor;
end;

procedure TNxGridView6.Changed;
var
  CursorPos: TPoint;
begin
  if Control.CanUpdate([uoRepaint]) then
    if Assigned(FCapturedView)
      and (FCapturedView.Location.Y = Index) then
    begin
      GetCursorPos(CursorPos);
      CursorPos := Control.ScreenToClient(CursorPos);

      { Set CapturedView }
      HoverCell := GetCellAtPos(CursorPos);

      MouseMove([], CursorPos.X, CursorPos.Y);
    end;
end;

constructor TNxGridView6.Create(AOwner: TComponent);
begin
  { 8/11/12: Stream require inherited }
  inherited;
  FCapturedView := nil;
  FCellHint := nil;
  FClickOnSelected := False;
  FColumnMoving := True;
  FPressedCell := EmptyPoint;
  FEnabled := True;
  FFixedColCount := 0;
  FFixedRowCount := 0;
  FFooterGridLinesColor := clBtnFace;
  FFooterHeight := szFooterHeight;
  FGridLines := False;
  FGridLinesColor := clBtnFace;
  FGridLinesStyle := glBoth;
  FHeaderArrows[0] := nil;
  FHeaderArrows[1] := nil;
  FHeaderControl := nil;
  FHeaderHeight := szHeaderHeight;
  FHomeEndBehaviour := heTopBottom;
  FHotCell := EmptyPoint;
  FHoverFooter := nil;
  FHoverHeader := nil;
  FIndicatorWidth := szIndicatorWidth;
  FInsertRowHeight := szInsertRowHeight;
  FLastFixedRow := -1;
  FResponsiveWidth := 0;
  FMouseDown := False;
  FOptions := [];
  FResizeReadyColumn := nil;
  FResizingColumn := nil;
  FResizingPos := EmptyPoint;
  FShowFooter := False;
  FShowHeader := True;
  FShowIndicator := False;
  FShowInsertRow := False;
  FState := [];
  FViews := nil;
end;

procedure TNxGridView6.DataKeyDown(var Key: Word; Shift: TShiftState);
begin
  if Assigned(FCapturedView)
    and not IsEqual(FCapturedView.Location, Control.SelectedLocation)
  then
  begin
    FCapturedView := nil;
  end;

  { Enabled & IsResponsive etc. ? }
  CaptureView(Control.SelectedLocation);

  if Assigned(FCapturedView)
    and FCapturedView.IsResponsive
    and FCapturedView.Column.Interactive
    and FCapturedView.CanDispatchKey(Key) then
  begin

    if FCapturedView.Cell.Enabled
      then FCapturedView.KeyDown(Key, Shift);

  end;
end;

procedure TNxGridView6.DataMouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  CellAtPos: TPoint;

  function CanChangeSelection(Column: TNxColumn6): Boolean;
  var
    Intf: INxMoveSelection;
    InteractiveHitTest: Boolean;
  begin
    InteractiveHitTest := Assigned(FCapturedView)
      and FCapturedView.InteractiveHitTest(X, Y);

    Result := not Supports(Column, INxMoveSelection, Intf)
      or Intf.GetInteractionMoveSelection or not InteractiveHitTest;
  end;

begin
  CellAtPos := GetCellAtPos(Point(X, Y));
  Control.DoCellMouseDown(CellAtPos.X, CellAtPos.Y, Button, Shift);

  FClickOnSelected := IsEqual(Control.SelectedLocation, CellAtPos);

  { CaptureView }
  PressedCell := CellAtPos;

  { Select Cell }
  if Control.CellExists(CellAtPos)
    and Columns[CellAtPos.X].Enabled
    and ((Button = mbLeft) or Control.RightClickSelect)
    and CanChangeSelection(Columns[CellAtPos.X]) then
  begin
    Control.SelectCell(CellAtPos.X, CellAtPos.Y, Shift);
  end
  else Control.EndEditing;


  { Trigger event }
  if IsSet(PressedCell)
    and (ssDouble in Shift)
      then Control.DoCellDblClick(FPressedCell.X, FPressedCell.Y);
end;

procedure TNxGridView6.DataMouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  UpCell: TPoint;
begin
  UpCell := GetCellAtPos(Point(X, Y));

  if IsEqual(UpCell, FPressedCell) then
  begin

    { Trigger event }
    if Control.CellExists(UpCell)
      then Control.DoCellClick(UpCell.X, UpCell.Y, Button);

    { Is deleted in OnCellClick ? }
    if Control.CellExists(UpCell) then
    begin

      { Start edit }
      if (Button = mbLeft)
        and IsEqual(Control.SelectedLocation, UpCell) then
      begin

        { Don't edit if in interactive TRect }
        if Assigned(FCapturedView)
          and FCapturedView.IsResponsive
          and PtInRect(FCapturedView.InteractiveRect, Point(X, Y))
            then Exit;

        if not Control.SecondClickEditing
          or FClickOnSelected then
        begin
          ReleaseTextFitHint;
          Control.EditCell(UpCell);
        end;
      end;

    end;
  end;

end;

procedure TNxGridView6.Deactivate;
begin
  HoverCell := EmptyPoint;
  FCapturedView := nil;

  { Hint(s) }
  ReleaseCellHint;
  ReleaseHeaderHint;
  ReleaseTextFitHint;

  RefreshSelection;
end;

procedure TNxGridView6.DesignNotification(Sender: INxDesignNotificationRecipient;
  Operation: TNxDesignOperation);
begin

end;

destructor TNxGridView6.Destroy;
begin
  { Remove Itself from Views }
  if Assigned(Owner) and Assigned(Views) then Views.Remove(Self);

  { Destroy Hints }
  ReleaseCellHint;
  ReleaseTextFitHint;
  ReleaseHeaderHint;

  { Destroy Objects }
  FreeAndNil(FHeaderHintDelayTimer);

  FPressedInsertColumn := nil;

  {TODO: destroy hint too! }

  { Destroy Interf. Obj. }
  FCapturedView := nil;

  HideArrows;

  ReleaseTextFitHint;

  inherited;
end;

procedure TNxGridView6.DoHeaderControlDrop(Sender: TObject; X, Y: Integer);
var
  ClientPoint: TPoint;
  OldPos, Position: Integer;
  Accept: Boolean;

begin
  Accept := True;

  ClientPoint := Control.ScreenToClient(Point(X, Y));

  if PtInRect(GetHeaderDropRect, ClientPoint) then
  begin
    OldPos := FPressedHeader.Position;
    Position := GetNearestPosition(FPressedHeader, ClientPoint);

    DoColumnMoveOver(OldPos, Position, Accept);

    if Accept and not ((voLockFixedColumns in Options)
      and (Position < FixedColCount) or (OldPos < FixedColCount)) then
    begin
      PressedHeader.Position := Position;

      { Event }
      DoColumnMoveDrop(PressedHeader.Index, OldPos, Position);

      { Refresh all }
      Invalidate;
    end;
  end;

  SetScreenCursor(crDefault);
  PressedHeader := nil;
  HideArrows;
end;

procedure TNxGridView6.DoHeaderControlMove(Sender: TObject; X, Y: Integer);
var
  MovePoint: TPoint;
  OldPos, Position: Integer;
  Accept: Boolean;
begin
  Accept := True;

  MovePoint := Control.ScreenToClient(Point(X, Y));

  if PtInRect(GetHeaderDropRect, MovePoint) then
  begin
    OldPos := FPressedHeader.Position;
    Position := GetNearestPosition(FPressedHeader, MovePoint);

    if OldPos = Position then
    begin
      SetScreenCursor(crDefault);
      HideArrows;
      Exit;
    end;

    { Event }
    DoColumnMoveOver(OldPos, Position, Accept);

    if (voLockFixedColumns in Options)
      and ((Position < FixedColCount) or (OldPos < FixedColCount))
      or not Accept then
    begin
      HideArrows;
      SetScreenCursor(crHeaderNoDrop);

      Exit;
    end
    else SetScreenCursor(crDefault);

    if Columns.PositionItem[Position].Visible
      then ShowArrows(GetArrowsLocation(OldPos, Position));

  end else
  begin
    HideArrows;
    SetScreenCursor(crHeaderNoDrop);
  end;
end;

procedure TNxGridView6.DoHeaderHintDelayTimer(Sender: TObject);
var
  Shift, PosX: Integer;
  HintRect: TRect;
begin
  { Stop & Destroy }
  FreeAndNil(FHeaderHintDelayTimer);

  if Assigned(HoverHeader) and
    not (FHoverHeader = FPressedHeader) then
  begin
    { Create Hint Window }
    FHeaderHint := HintWindowClass.Create(nil);
    FHeaderHint.Color := clInfoBk;

    { Set Position & Activate }

    { Calculate Rect }
    HintRect := FHeaderHint.CalcHintRect(Screen.Width, HoverHeader.Header.Hint, nil);

    Shift := DataRect.Left;

    { Horz ScrollBar Shift }
    Dec(Shift, Offset.cx);

    PosX := HoverHeader.Left + Shift;
    if PosX < DataRect.Left then PosX := DataRect.Left;

    { Cordinates must be "Screen" }
    HintRect.TopLeft := Views.Control.ClientToScreen(Point(PosX, HeaderHeight));

    HintRect.Bottom := HintRect.Top + HintRect.Bottom;
    HintRect.Right := HintRect.Left + HintRect.Right;

    { Show Hint }
    FHeaderHint.ActivateHint(HintRect, HoverHeader.Header.Hint);
  end;
end;

procedure TNxGridView6.DoHeaderMouseDown(Button: TMouseButton;
  Shift: TShiftState; Col, X, Y: Integer);
begin
  if Assigned(FOnHeaderMouseDown) then FOnHeaderMouseDown(Self, Button, Shift, Col, X, Y);
end;

procedure TNxGridView6.DoSelect;
begin

end;

///<summary></summary>
///<returns>Index of first row in Page</returns>
///<author>Eduard</author>
function TNxGridView6.FindFirstRowInPage: Integer;
var
  Count: Integer;
begin
  { 8/28/16: Changed 0 to -1 }
  Result := -1;

  Count := 0;
  while Result < RowCount do
  begin
    Inc(Result);
    if Showing[Result] then
    begin
      Inc(Count);
      if Count > VertScrollBar.Position then Break;
    end;
  end;
end;

procedure TNxGridView6.DoAddColumn;
begin
  Columns.LastAdded.Changed(gaAll);
end;

procedure TNxGridView6.DoCloseUp;
begin

end;

procedure TNxGridView6.DoColumnMoveDrop(ACol, OldPosition,
  NewPosition: Integer);
begin
  if Assigned(FOnColumnMoveDrop) then FOnColumnMoveDrop(Self, ACol, OldPosition, NewPosition);
end;

procedure TNxGridView6.DoColumnMoveOver(CurrentPosition, NewPosition: Integer; var Accept: Boolean);
begin
  if Assigned(FOnColumnMoveOver) then FOnColumnMoveOver(Self, CurrentPosition, NewPosition, Accept);
end;

procedure TNxGridView6.DoFooterHintDelayTimer(Sender: TObject);
var
  Shift, PosX: Integer;
  HintRect: TRect;
begin
  { Stop & Destroy }
  FreeAndNil(FHeaderHintDelayTimer);

  if Assigned(FHoverFooter) and
    not (FHoverFooter = FPressedHeader) then
  begin
    { Create Hint Window }
    FHeaderHint := HintWindowClass.Create(nil);
    FHeaderHint.Color := clInfoBk;

    { Set Position & Activate }

    { Calculate Rect }
    HintRect := FHeaderHint.CalcHintRect(Screen.Width, FHoverFooter.Footer.Hint, nil);

    Shift := DataRect.Left;

    { Horz ScrollBar Shift }
    Dec(Shift, Offset.cx);

    PosX := HoverFooter.Left + Shift;
    if PosX < DataRect.Left then PosX := DataRect.Left;

    { Cordinates must be "Screen" }
    HintRect.TopLeft := Views.Control.ClientToScreen(Point(PosX, ClientHeight));

    HintRect.Bottom := HintRect.Top + HintRect.Bottom;
    HintRect.Right := HintRect.Left + HintRect.Right;

    { Show Hint }
    FHeaderHint.ActivateHint(HintRect, FHoverFooter.Footer.Hint);
  end;
end;

procedure TNxGridView6.DoFooterMouseDown(Button: TMouseButton; Shift: TShiftState; Col, X, Y: Integer);
begin
  if Assigned(FOnFooterMouseDown) then FOnFooterMouseDown(Self, Button, Shift, Col, X, Y);
end;

procedure TNxGridView6.DoGetCellColor(ACol, ARow: Integer; var CellColor: TColor;
  State: TNxCellPaintingState);
begin
  if Assigned(FOnGetCellColor) then FOnGetCellColor(Self, ACol, ARow, CellColor, State);
end;

procedure TNxGridView6.DoGetCellGrid(Sender: TObject; ACol, ARow: Integer; var Edges: TNxBorderEdges;
      State: TNxCellPaintingState);
begin
  if Assigned(FOnGetCellGrid) then FOnGetCellGrid(Sender, ACol, ARow, Edges, State);
end;

function TNxGridView6.GetArrowsLocation(CurrentPosition, Position: Integer): TPoint;
var
  DragColumn, TargetColumn: TNxColumn6;
  X: Integer;
begin
  if csDesigning in ComponentState then Exit;
  TargetColumn := Columns.PositionItem[Position];
  DragColumn := Columns.PositionItem[CurrentPosition];

  if CurrentPosition <> Position then
  begin
    if DragColumn.Visible then
    begin
      case CurrentPosition < Position of
        True: case TargetColumn.Location of
                clAlone, clLeftSide: X := TargetColumn.Left;
                else X := TargetColumn.Left + TargetColumn.Width;
              end;
        else X := TargetColumn.Left;
      end;
    end else
    begin
      if Position > CurrentPosition then
      begin
        case TargetColumn.Location of
          clAlone, clLeftSide: X := TargetColumn.Left + TargetColumn.Width;
          else X := TargetColumn.Left + TargetColumn.Width;
        end;
      end else
      begin
        X := TargetColumn.Left;
      end;
    end;
  end else
  begin
//    if UseSelf then
//    begin
//      X := TargetColumn.Left;
//    end else
    begin
      Exit;
    end;
  end;

  Result := Point(X, 0);

  { Shift for indicators }
  Inc(Result.X, DataRect.Left);

  { Shift for fixed cols }
  if Position >= FixedColCount
    then Dec(Result.X, HorzScrollBar.Position);
end;

function TNxGridView6.GetAutoClose: Boolean;
begin
  Result := True;
end;

function TNxGridView6.GetCanvas: TCanvas;
begin
  if Assigned(Control) then Result := Control.Canvas else Result := nil;
end;

function TNxGridView6.GetCaptionRect: TRect;
begin
  Result := DataRect;
  OffsetRect(Result, 0, pdDouble);
  Result.Bottom := Result.Top + DotToPixel(HeaderHeight);
end;

function TNxGridView6.GetCellRect(ACol: Integer): TRect;
begin
  Result := Bounds(InsertRowRect.Left + Columns[ACol].Left - HorzScrollBar.Position, InsertRowRect.Top,
    MulDiv(Columns[ACol].Width, Screen.PixelsPerInch, 96) - GridSize[loRight], FInsertRowHeight);
end;

function TNxGridView6.GetCell(const ACol, ARow: Integer): INxCell;
begin
  Result := Control.Cell[ACol, ARow];
end;

function TNxGridView6.GetCellAtCursor: TPoint;
begin
  GetCursorPos(Result);

  { Make local }
  Result := Control.ScreenToClient(Result);
end;

function TNxGridView6.GetCellHint(ACol, ARow: Integer; Cell: INxBaseCell): WideString;
var
  GridCell: INxCell;
begin
  Result := '';
  if Supports(Cell, INxCell, GridCell) then
  begin
    Result := GridCell.Hint;
  end;
  Control.Columns[ACol].DoGetHint(ACol, ARow, Result);
end;

function TNxGridView6.GetCellRect(Location: TPoint): TRect;
begin
  Result := GetCellRect(Location.X, Location.Y);
end;

function TNxGridView6.GetCells: INxCells;
begin
  Result := Control.GetCellSource;
end;

///<param name="ACol">Index of the column</param>
///<param name="ARow">Index of the row</param>
///<returns>True if cell is for sure visible</returns>
function TNxGridView6.GetCellVisible(const ACol, ARow: Integer): Boolean;
begin
  Result := Columns[ACol].Visible and Cell[ACol, ARow].Visible;
end;

function TNxGridView6.GetClientDataRect: TRect;
begin
  Result := DataRect;
end;

function TNxGridView6.GetClientHeight: Integer;
begin
  Result := ClientRect.Bottom - ClientRect.Top;
end;

function TNxGridView6.GetClientRect: TRect;
begin
  if Assigned(Views)
    then Result := Views.Control.ClientRect;
end;

function TNxGridView6.GetColor: TColor;
begin
  if Assigned(Control) then Result := Control.Color else Result := clNone;
end;

function TNxGridView6.GetColumnAt(X, Y: Integer; Area: TNxGridArea): TNxColumn6;
var
  Offset: Integer;
begin
  { No offset }
  Offset := HeaderRect.Left;

  { Not fixed? }
  if X >= FixedRect.Left then Dec(Offset, Self.Offset.cx);

  Result := Columns.GetAtPos(X - Offset, Y);
end;

function TNxGridView6.GetColumnRect(Column: TNxColumn6; Area: TNxGridArea): TRect;
var
  Shift: Integer;
begin
  Shift := DataRect.Left;

  { ScrollBar Shift }
  if Column.VisibleIndex >= FFixedColCount then
    Dec(Shift, HorzScrollBar.Position);

  case Area of
    gaFooter: Result := Bounds(Column.Left + Shift, FooterRect.Top, Column.Width, MulDiv(FFooterHeight, Screen.PixelsPerInch, 96));
    gaHeader: Result := Bounds(Column.Left + Shift, 0, MulDiv(Column.Width, Screen.PixelsPerInch, 96), MulDiv(HeaderHeight, Screen.PixelsPerInch, 96));
    gaHeaderDropButton: Result := Bounds(Column.Right + Shift - szFilterDropButtonWidth, 0, szFilterDropButtonWidth, HeaderHeight);
    gaInsertRow: Result := Bounds(Column.Left + Shift, InsertRowRect.Top, Column.Width, FInsertRowHeight);
  end;
end;

function TNxGridView6.GetColumns: TNxColumns6;
begin
  Result := nil;

  if Assigned(FViews)
    then Result := FViews.Control.Columns;
end;

function TNxGridView6.GetColumnSizeGripAtPos(X, Y: Integer): TNxColumn6;
var
  i, Pos, Treshold: Integer;
  Item: TNxColumn6;
begin
  { Default }
  Result := nil;

  Pos := HeaderRect.Left;

  if ShowHeader then
  begin

    for i := 0 to Pred(Columns.Count) do
    begin
      Item := Columns.PositionItem[i];

      if Item.Visible then
      begin

        if i = FFixedColCount
          then Dec(Pos, Offset.cx);

        { Shift }
        Inc(Pos, MulDiv(Item.Width, Screen.PixelsPerInch, 96));

        Treshold := MulDiv(spSizingTreshold, Screen.PixelsPerInch, 96);

        if Item.Resizeable and InRange(X, Pos - Treshold, Pos + Treshold) then
        begin
          Result := Item;

          { Done }
          Exit;
        end;
      end;
    end;
  end;
end;

function TNxGridView6.GetControl: INxGridViewControl;
begin
  Result := Views.Control;
end;

function TNxGridView6.GetDataBottom: Integer;
begin
  Result := GetDataRect.Bottom;
end;

function TNxGridView6.GetDataRect: TRect;
begin
  { Client Area }
  Result := ClientRect;

  { Adjust }
  with Result do
  begin
    if ShowHeader then Inc(Top, DotToPixel(FHeaderHeight));
    if ShowInsertRow then Inc(Top, FInsertRowHeight + szInsertRowSplitterHeight);
    if ShowIndicator then Inc(Left, DotToPixel(FIndicatorWidth));
    if ShowFooter then Dec(Bottom, DotToPixel(FFooterHeight + szFooterSplitterHeight));
  end;
end;

function TNxGridView6.GetDroppedDown: Boolean;
begin
  Result := False;
end;

function TNxGridView6.GetFirstSelectableCol: Integer;
var
  i: Integer;
begin
  Result := -1;
  for i := 0 to Pred(Columns.Count) do
    if Control.CanSelect(i, SelectedRow) then
    begin
      Result := i;
      Exit;
    end;
end;

function TNxGridView6.GetFixedHeight: Integer;
var
  i, Count: Integer;
begin
  { Default }
  Result := 0;
  Count := 0;

  for i := 0 to Pred(RowsOwner.RowCount) do
  begin
    { Stop? }
    if Count = FFixedRowCount
      then Break;

    if Row[i].Showing then
    begin
      Inc(Result, RowHeight[i] + GridSize[loBottom]);
      Inc(Count);
    end;
  end;
end;

function TNxGridView6.GetFixedRect: TRect;
begin
  Result := DataRect;
  Inc(Result.Left, FixedWidth);
end;

function TNxGridView6.GetFixedWidth: Integer;
var
  C, i: Integer;
begin
  { Default }
  Result := 0;

  C := 1;

  for i := 0 to Pred(Columns.Count) do
    if Columns.PositionItem[i].Visible then
    begin

      { Done }
      if C > FFixedColCount
        then Break;

      Inc(Result, Columns.PositionItem[i].Width);

      Inc(C);

    end;

end;

function TNxGridView6.GetFooterRect: TRect;
begin
  Result := Bounds(0, ClientRect.Bottom - FFooterHeight - szFooterSplitterHeight, Columns.VisibleWidth, FFooterHeight + szFooterSplitterHeight);

  { Shift to Right }
  if ShowIndicator then OffsetRect(Result, DotToPixel(FIndicatorWidth), 0);
end;

function TNxGridView6.GetFullRowHeight(Index: Integer): Integer;
begin
  Result := RowHeight[Index];
end;

function TNxGridView6.GetGridSize(Location: TNxLocation): Integer;
begin
  Result := 0;
  case Location of
    loBottom: Result := IfThen(GridLines and not (GridLinesStyle = glVerticalOnly), 1, 0);
    loLeft: ;
    loRight: Result := IfThen(GridLines and not (GridLinesStyle = glHorizontalOnly), 1, 0);
    loTop: ;
  end;
end;

function TNxGridView6.GetHeaderButttonAtPos(X, Y: Integer): TNxColumn6;
var
  Column: TNxColumn6;
begin
  Result := nil;

  Column := GetColumnAt(X, Y, gaHeader);

  if Assigned(Column) then
    if Column.Header.ShowButton and PtInRect(GetHeaderButttonRect(Column), Point(X, Y))
      then Result := Column;
end;

function TNxGridView6.GetHeaderButttonRect(Column: TNxColumn6): TRect;
begin
  Result := GetColumnRect(Column, gaHeader);

  Result := Bounds(Result.Right - szFilterDropButtonWidth - 2, 2, szFilterDropButtonWidth, FHeaderHeight - 4);
end;

function TNxGridView6.GetHeaderDropRect: TRect;
var
	Right: Integer;
begin
	Right := HeaderRect.Right;
  if Right > ClientRect.Right then Right := ClientRect.Right;
  Result := Rect(0, 0, Right, DataRect.Top);
end;

function TNxGridView6.GetHeaderRect: TRect;
begin
  Result := Bounds(0, 0, MulDiv(Columns.VisibleWidth, Screen.PixelsPerInch, 96),
    MulDiv(HeaderHeight, Screen.PixelsPerInch, 96));

  { Shift to Right }
  if ShowIndicator then OffsetRect(Result, DotToPixel(FIndicatorWidth), 0);
end;

function TNxGridView6.GetHorzMax: Integer;
begin
  { Default - Hide }
  Result := 0;
end;

function TNxGridView6.GetHorzScrollBar: INxScrollBar;
begin
  Result := Control.HorzScrollBar;
end;

function TNxGridView6.GetHoverCell: TPoint;
begin
  Result := FHotCell;
end;

function TNxGridView6.GetIndex: Integer;
begin
  { Default }
  Result := -1;

  if Assigned(FViews)
    then Result := FViews.IndexOf(Self);
end;

function TNxGridView6.GetIndicatorRect: TRect;
begin
  Result := Bounds(0, 0, DotToPixel(FIndicatorWidth), ClientRect.Bottom - ClientRect.Top);
end;

function TNxGridView6.GetInsertRowRect: TRect;
begin
  Result := Bounds(0, 0, Columns.VisibleWidth, HeaderHeight);

  { Shift Left & Top }
  if ShowHeader then OffsetRect(Result, 0, DotToPixel(FHeaderHeight));
  if ShowIndicator then OffsetRect(Result, DotToPixel(FIndicatorWidth), 0);
end;

function TNxGridView6.GetInstance: TPersistent;
begin
  Result := TPersistent(Self);
end;

function TNxGridView6.GetLastSelectableCol: Integer;
var
  i: Integer;
begin
  Result := -1;
  for i := Pred(Columns.Count) downto 0 do
    if Control.CanSelect(i, SelectedRow) then
    begin
      Result := i;
      Exit;
    end;
end;

function TNxGridView6.GetNearestPosition(Column: TNxColumn6;
  Point: TPoint): Integer;
var
  i, Indent, Pos, Middle: Integer;
  Clipped: Boolean;
  CurColumn, PrevColumn: TNxColumn6;
begin
  Result := Column.Position;
  PrevColumn := nil;

  Dec(Point.X, DataRect.Left);

  for i := 0 to Pred(Columns.Count) do
  begin
    CurColumn := Columns.PositionItem[i];

    if CurColumn.Visible or (CurColumn = Column) then
    begin
      if PrevColumn = nil then PrevColumn := CurColumn;
      if i >= FixedColCount then Indent := HorzScrollBar.Position else Indent := 0;
      Pos := CurColumn.Left + CurColumn.Width - Indent;

      if (Point.X >= CurColumn.Left - Indent) and (Point.X <= Pos) then
      begin
        Middle := Pos - CurColumn.Width div 2;

        if Column <> CurColumn then
        begin
          if Point.X > Middle then
          begin
            if CurColumn.Position > Column.Position then Result := CurColumn.Position
              else Result := CurColumn.Position + 1;
          end else
          begin
            if CurColumn.Position < Column.Position then Result := CurColumn.Position
              else Result := PrevColumn.Position;
          end;
        end;

        Clipped := (Result >= FixedColCount) and (Pos - CurColumn.Width < GetFixedWidth);

        if Clipped then Result := Column.Position;

        Break;
      end; { hit a spot }

      PrevColumn := CurColumn;

    end; { if visible }

  end;

end;

function TNxGridView6.GetOffset: TSize;
begin
  with Result do
  begin
    cx := HorzScrollBar.Position;
    cy := VertScrollBar.Position;
  end;
end;

function TNxGridView6.GetParentComponent: TComponent;
begin
  Result := GetComponent(FViews.FViewControl);
end;

function TNxGridView6.GetRow(Index: Integer): INxRow;
begin
  Result := RowsOwner.Row[Index];
end;

function TNxGridView6.GetRowCount: Integer;
begin
  Result := RowsOwner.RowCount;
end;

function TNxGridView6.GetRowHeight(Index: Integer): Integer;
begin
  Result := Control.GetRowSize(Index);
end;

function TNxGridView6.GetRowsControl: INxRowsControl;
begin
  Supports(Views.Control, INxRowsControl, Result);
end;

function TNxGridView6.GetSelectedCol: Integer;
begin
  Result := Control.SelectedLocation.X;
end;

function TNxGridView6.GetSelectedRow: Integer;
begin
  Result := Control.SelectedRow;
end;

function TNxGridView6.GetSelectionStyle: TNxSelectionStyle;
begin
  Result := FSelectionStyle;
end;

function TNxGridView6.GetShowing(const Index: Integer): Boolean;
begin
  Result := RowsOwner.Showing[Index];
end;

function TNxGridView6.GetShowingCount: Integer;
begin
  Result := RowsOwner.ShowingCount;
end;

function TNxGridView6.GetStylePaint: INxGridStylePaint;
begin
  Result := nil;
  if Assigned(Views) then Result := Views.Control.StylePaint;
end;

function TNxGridView6.GetVertPageSize: Integer;
begin
  Result := 0;
end;

function TNxGridView6.GetVertScrollBar: INxScrollBar;
begin
  Result := Control.VertScrollBar;
end;

function TNxGridView6.GetViews: TNxGridViews6;
begin
  Result := FViews;
end;

function TNxGridView6.GetVirtualMode: Boolean;
begin
  Result := Control.IsVirtual;
end;

function TNxGridView6.HasParent: Boolean;
begin
  Result := True;
end;

procedure TNxGridView6.HideArrows;
begin
  { Release arrows }
  FreeAndNil(FHeaderArrows[0]);
  FreeAndNil(FHeaderArrows[1]);
end;

procedure TNxGridView6.Invalidate;
begin
  Invalidate(ClientRect);
end;

procedure TNxGridView6.IndicatorMouseLeave;
begin

end;

procedure TNxGridView6.IndicatorMouseMove(Shift: TShiftState; X, Y: Integer);
begin

end;

/// <summary>
/// Prepare Cell's View before calling Paint
/// </summary>
/// <param name="AView">View to be prepared</param>
procedure TNxGridView6.InitCellView(const AView: INxColumnView; const ACol, ARow: Integer);
begin
  AView.Active := False;
  AView.Canvas := Canvas;
  AView.Parent := Self;

  AView.Style := Control.StylePaint;
  AView.Style.Canvas := Canvas; { TODO: Style.Reset() ? }

  AView.HideSelection := Control.HideSelection;

  AView.Alternated := False;
  AView.AlternatingRowColor := Control.AlternatingRowColor;

  AView.InactiveSelectionColor := Control.InactiveSelectionColor;
  AView.SelectionColor := Control.SelectionColor;
  AView.SelectionTextColor := Control.SelectionTextColor;

  AView.BoldSelectedText := aoBoldSelectedText in Control.AppearanceOptions;
  AView.DrawingOptions := Columns[ACol].DrawingOptions;
  AView.EmptyCaption := Columns[ACol].EmptyCaption;
  AView.HideWhenEmpty := Columns[ACol].HideWhenEmpty;
  AView.HintIndicators := aoHintIndicators in Control.AppearanceOptions;
end;

procedure TNxGridView6.InsertRowMouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FPressedInsertColumn := Columns.GetAtPos(X - InsertRowRect.Left, Y);

  { Select InsertRow }
  Control.InsertSelected := True;

  if FPressedInsertColumn.Enabled then
  begin
    Control.SelectCell(FPressedInsertColumn.Index, -1);
  end;
end;

procedure TNxGridView6.InsertRowMouseLeave;
begin

end;

procedure TNxGridView6.InsertRowMouseMove(Shift: TShiftState; X, Y: Integer);
begin

end;

procedure TNxGridView6.InsertRowMouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  { Don't edit if in interactive TRect }
  if Assigned(FCapturedView)
    and PtInRect(FCapturedView.InteractiveRect, Point(X, Y))
      then Exit;

  if Assigned(FPressedInsertColumn) then
    Control.InsertCell(FPressedInsertColumn.Index);
end;

procedure TNxGridView6.Invalidate(InvalidationRect: TRect);
begin
  Views.Control.InvalidateRect(InvalidationRect);
end;

procedure TNxGridView6.InvalidateCaption;
begin
  Invalidate(CaptionRect);
end;

function TNxGridView6.IsOnScreen(Index: Integer): Boolean;
begin
  Result := True;
end;

procedure TNxGridView6.KeyDown(var Key: Word; Shift: TShiftState);
begin

end;

procedure TNxGridView6.KeyUp(var Key: Word; Shift: TShiftState);
begin
  if Assigned(FCapturedView) then
  begin
    FCapturedView.KeyUp(Key, Shift);

    { Release Intf. }
    FCapturedView := nil;
  end;
end;

procedure TNxGridView6.KeyUp;
begin
  if Assigned(FCapturedView) then FCapturedView.KeyUp;
end;

procedure TNxGridView6.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  ColumnAtPos: TNxColumn6;
  BestFitMode: TNxBestFitMode;
begin
  FMouseDownLocation := Point(X, Y);
  FMouseDown := True;

  { Header }
  if ShowHeader and PtInRect(HeaderRect, Point(X, Y)) then
  begin

    { Size-grip behind }
    if Assigned(FResizeReadyColumn) then
    begin
      BestFitMode := [bfCells];
      if ssDouble in Shift then
      begin
        if RowsOwner.GetShowingCount = 0 then BestFitMode := [bfHeader];
        Control.BestFitColumn(FResizeReadyColumn, BestFitMode);

        { Event }
        FResizeReadyColumn.DoResize;
      end
      else ResizingColumn := FResizeReadyColumn;
    end else
    begin
      ColumnAtPos := GetColumnAt(X, Y, gaHeader);

      if Button = mbLeft then
      begin
        PressedHeaderButton := GetHeaderButttonAtPos(X, Y);

        if not Assigned(PressedHeaderButton)
          then PressedHeader := ColumnAtPos;

        PressedHeaderButton := nil;
      end;

      { Trigger event }
      if Assigned(ColumnAtPos)
        then DoHeaderMouseDown(Button, Shift, ColumnAtPos.Index, X, Y);

    end;

  end
  else PressedHeader := nil;

  if ShowFooter and PtInRect(FooterRect, Point(X, Y)) then
  begin
    ColumnAtPos := GetColumnAt(X, Y, gaFooter);
    DoFooterMouseDown(Button, Shift, ColumnAtPos.Index, X, Y);
  end;

  { InsertRow }
  if ShowInsertRow and PtInRect(InsertRowRect, Point(X, Y)) then
  begin
    InsertRowMouseDown(Button, Shift, X, Y);
  end;

  { Data }
  if PtInRect(DataRect, Point(X, Y)) then
  begin
    { Add from Insert R. }
    if Control.InsertSelected then
    begin
      { Also, call OnInsertRowAdd }
      Control.AddInsertRow;
    end;

    DataMouseDown(Button, Shift, X, Y);
  end
  else Control.EndEditing;

  { Process captured view last }
  if Assigned(FCapturedView) then
  begin

    FCapturedView.Selected := Control.Highlighted[FCapturedView.Location.X, FCapturedView.Location.Y];

    if FCapturedView.Column.Interactive then
      if PtInRect(FCapturedView.InteractiveRect, Point(X, Y)) then
      begin

        { TODO: Testing required! }
        if FCapturedView.Cell.Enabled and not FCapturedView.Cell.IsNull
          then FCapturedView.MouseDown(Button, Shift, X, Y);

      end;
  end;
end;

procedure TNxGridView6.MouseLeave;
var
  CursorPos: TPoint;
begin
  GetCursorPos(CursorPos);
  CursorPos := Control.ScreenToClient(CursorPos);

  { 12/24/2020: Toolbar hint is not hidden after control is hidden. (5434) }
//  if not PtInRect(ClientRect, CursorPos) then
//  begin
  HoverButton := nil;
  HoverFooter := nil;
  HoverHeader := nil;
  ReleaseCellHint;

  { Note: Hint can trigger CM_MOUSELEAVE &
          destroy self! }

  ReleaseTextFitHint;
  HoverCell := EmptyPoint;
//  end;

  ResizeReadyColumn := nil;
end;

procedure TNxGridView6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  { Boki: When view capture a mouse (Captured = True),
          he become only object reacting on MouseMove }

  { View captured a mouse ! }
  if (not Assigned(FCapturedView) or not FCapturedView.Captured)
    and not Assigned(FPressedHeader)
    and not Assigned(FPressedHeaderButton) then
  begin

    { Stop everytging else while resizing }
    if Assigned(ResizingColumn) then
    begin
      ResizingPos := Point(X, Y);

      Exit;
    end;

    if ShowFooter and PtInRect(FooterRect, Point(X, Y)) then
    begin
      HoverFooter := GetColumnAt(X, Y, gaFooter);
    end else
    begin
      HoverFooter := nil;
    end;

    { Header }
    if ShowHeader and PtInRect(HeaderRect, Point(X, Y)) then
    begin
      HoverButton := GetHeaderButttonAtPos(X, Y);

      if not Assigned(HoverButton) then
      begin
        { Area is set inside }
        HoverHeader := GetColumnAt(X, Y, gaHeader);

        if not Assigned(PressedHeader)
          then ResizeReadyColumn := GetColumnSizeGripAtPos(X, Y);
      end;

    end else
    begin
      HoverHeader := nil;
      HoverButton := nil;
      ResizeReadyColumn := nil;
    end;

    { InsertRow }
    if ShowInsertRow and PtInRect(InsertRowRect, Point(X, Y)) then
    begin
      InsertRowMouseMove(Shift, X, Y);
    end
    else InsertRowMouseLeave;

    { Indicator }
    if ShowIndicator and PtInRect(IndicatorRect, Point(X, Y)) then
    begin
      IndicatorMouseMove(Shift, X, Y);
    end
    else IndicatorMouseLeave;

    HoverCell := GetCellAtPos(Point(X, Y));
  end;

  if Assigned(FCapturedView) then
  begin

    if FCapturedView.Cell.Enabled
      then FCapturedView.MouseMove(Shift, X, Y);

  end;

  if ColumnMoving then
    if Assigned(FPressedHeader) and not Assigned(FHeaderControl) then
      if (X < FMouseDownLocation.X - 4) or (X > FMouseDownLocation.X + 4)
        or (Y < FMouseDownLocation.Y - 4) or (Y > FMouseDownLocation.Y + 4) then
    begin
      StartHeaderDrag(X, Y);
    end;
end;

procedure TNxGridView6.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  ColumnAt: TNxColumn6;
  Accept: Boolean;
  SortKind: TNxSortKind;
begin
  try

    { Process CapturedView first! }
    if Assigned(FCapturedView) then
    begin
      { Update Location again }
      Control.SetActiveCell(FCapturedView.Location);

      FCapturedView.MouseUp(Button, Shift, X, Y);
    end;

    { Stop Resizing }
    ResizingColumn := nil;

    { Release Header Button }
    PressedHeaderButton := nil;

    if ShowHeader and
      PtInRect(HeaderRect, Point(X, Y)) then
    begin
      ColumnAt := GetColumnAt(X, Y, gaHeader);

      { Sort Col. }
      if Assigned(PressedHeader)
        and (ColumnAt = PressedHeader) then
      begin

        { Trigger `OnHeaderClick` }
        ColumnAt.DoHeaderClick;

        if not ColumnAt.Sortable
          then Exit;

        { SortKind }
        SortKind := ColumnAt.SortKind;

        if ColumnAt.Sorted then
          if ColumnAt.SortKind = skAscending
            then SortKind := skDescending
            else SortKind := skAscending;

        { Event, can Sort? }
        Accept := True;
        Control.DoSortQuery(ColumnAt.Index, SortKind, Accept);

        if Accept then
          if ColumnAt.Sorted then
          begin
            if Control.MultiSort and (ColumnAt.SortKind = skDescending) then
            begin
              ColumnAt.DeleteMultiSorted;
            end
            else ColumnAt.ReverseSort;
          end
          else ColumnAt.SetMultiSorted(True, (ssCtrl in Shift) and Control.MultiSort);
      end;

    end;

    { Release Header }
    PressedHeader := nil;

    if ShowInsertRow
      and PtInRect(InsertRowRect, Point(X, Y)) then
    begin
      InsertRowMouseUp(Button, Shift, X, Y);
    end;

    if PtInRect(DataRect, Point(X, Y)) then
    begin
      DataMouseUp(Button, Shift, X, Y);
    end;

  finally
    Unset(FPressedCell);

    { Owner will release object again if not nil }
    FPressedInsertColumn := nil;

    { Captured View, once again }
    HoverCell := GetCellAtPos(Point(X, Y));

    { Don't forget ! }
    FMouseDown := False;
    Unset(FMouseDownLocation);
  end;

end;

procedure TNxGridView6.MoveByColumn(Distance: Integer; Shift: TShiftState);
begin
  Control.MoveByColumn(Distance, Shift);
end;

procedure TNxGridView6.Paint;
begin
  if ShowIndicator then
    try
      SetClipRect(Canvas, IndicatorRect);

      PaintIndicators;
    finally
      { Set Back Prev. ClipRect }
      SetClipRect(Canvas, ClientRect);
    end;

  if ShowHeader then PaintHeaders;
  if ShowInsertRow then PaintInsertRow;

  try
    SetClipRect(Canvas, DataRect);

    { Paint Data }
    PaintCells;

    { Paint FocusRect, depending on selection }
    if Control.Focused and not Control.HideFocus
      then PaintFocus;

    if ShowingCount = 0 then PaintCaption;
  finally
    { Set Back Prev. ClipRect }
    SetClipRect(Canvas, ClientRect);
  end;

  if ShowFooter then PaintFooters;

  WritelnDebug('Owned count:' + IntToStr(ComponentCount));
end;

procedure TNxGridView6.PaintCaption;
begin
  if Control.Caption <> '' then
  begin
    Canvas.Font.Assign(Control.Font);
    DrawTextRect(Canvas, CaptionRect, Classes.taCenter, taAlignTop, Control.Caption, wkNone);
  end;
end;

procedure TNxGridView6.PaintCell(const ACol, ARow, AVisibleRowIndex: Integer; CellRect: TRect);
var
  View: INxColumnView;
  RowView: INxRowView;
  RowsControl: INxRowsViewControl;
  TreeNodeView: INxTreeNodeView;
  Cell: INxCell;
begin
  with Canvas do
  begin
    Font.Assign(Control.Font);

    { Hover & Press }
    if Assigned(FCapturedView)
      and (IsEqual(FCapturedView.Location, Point(ACol, ARow))) then
    begin
      View := FCapturedView;
    end else
    begin
      Cell := Control.Cell[ACol, ARow];

      if not Cell.Visible then Exit;

      { ToDo: Move Columns[ACol] as with }
      View := Columns[ACol].View;
      View.Control := TWinControl(Control.ToObject);
      View.Owner := Control as INxCellOwner;
      View.ClientRect := CellRect;
      View.Cell := Cell;

      { Set BoldSelectedText, AlternatingRowColor etc. }
      InitCellView(View, ACol, ARow);

      if View.Cell.Empty then
      begin
//        View.DrawingOptions := doBackgroundOnly;
      end;

      View.Location := Point(ACol, ARow);
      View.Editing := IsEqual(Control.EditingCell, View.Location);
      View.Selected := Control.Highlighted[ACol, ARow];
      View.Pressed := IsEqual(View.Location, PressedCell);

      View.Alternated := False;
      if aoAlternatingRowColors in Control.AppearanceOptions then
      begin
        View.Alternated := (AVisibleRowIndex mod 2) = 0;
      end;

    end;

    if Supports(View, INxRowView, RowView) then
    begin
      RowView.Row := Row[ARow];
    end;

    if Supports(View, INxTreeNodeView, TreeNodeView) then
    begin
      TreeNodeView.IsFirst := ARow = 0;
      if Supports(Control, INxRowsViewControl, RowsControl) then
      begin
        TreeNodeView.IsFirst := RowsControl.GetFirstVisibleRow = ARow;
      end;
      TreeNodeView.IsLast := Row[ARow].NextSibling = nil;
    end;

    { Paint View }
    View.Paint;
  end;
end;

procedure TNxGridView6.PaintCells;
begin

end;

procedure TNxGridView6.PaintCellSelection(const ACol, ARow: Integer;
  CellRect: TRect);
begin

end;

procedure TNxGridView6.PaintFocus;
var
	CellRect, ClipRect: TRect;
begin
  if Control.IsSelectionValid
    and IsOnScreen(Control.SelectedRow) then
  begin

    if Control.SelectFullRow then
    begin

      CellRect := GetFocusRect(Control.SelectedRow);
      ClipRect := ClientDataRect;

    end else
    begin
      CellRect := GetCellRect(Control.SelectedLocation);
      ClipRect := CellRect;

      Inc(CellRect.Left, GridSize[loLeft]);

      if Columns[SelectedCol].VisibleIndex >= FixedColCount then
      begin
        if ClipRect.Left < GetHorzClipRect.Left then ClipRect.Left := GetHorzClipRect.Left;
      end;
    end;

    { Draw Focus }
    if (not Control.InsertSelected)
      and (RowsOwner.RowCount > 0) then
    begin

      try
        SetClipRect(Canvas, ClipRect);

        DrawFocusRect(Canvas, CellRect);
      finally
        SetClipRect(Canvas, ClientRect);
      end;

    end;
  end;
end;

procedure TNxGridView6.PaintFooters;
var
  i: Integer;
  PaintPos: TPoint;
  Item: TNxColumn6;
  SplitterRect, FooterRect, ClipSrc, ClipDst: TRect;
begin
  { Start }
  PaintPos := Self.FooterRect.TopLeft;

  { Splitter }
  with Canvas do
  begin
    SplitterRect := Bounds(PaintPos.X, PaintPos.Y, Columns.VisibleWidth, szFooterSplitterHeight);

    Brush.Color := FooterGridLinesColor;
    FillRect(SplitterRect);
  end;

  Inc(PaintPos.Y, szFooterSplitterHeight);

  for i := 0 to Pred(Columns.Count) do
  begin

    Item := Columns.PositionItem[i];

    { ScrollBar Shift }
    if Item.VisibleIndex = FFixedColCount then Dec(PaintPos.X, Offset.cx);

    if Item.Visible then
    begin
      FooterRect := Bounds(PaintPos.X, PaintPos.Y, Item.Width, FFooterHeight);

      Dec(FooterRect.Right, GridSize[loRight]);

      { Header is completely out of View }
      if FooterRect.Left > ClientRect.Right then Exit;

      ClipDst := Self.FooterRect;
      if i >= FixedColCount then ClipDst.Left := FixedRect.Left;

      { Clip Content inside Rect }
      ClipSrc := FooterRect;

      IntersectRect(ClipSrc, ClipSrc, ClipDst);

      try
        SetClipRect(Canvas, ClipSrc);

        StylePaint.SetColumn(Item);
        StylePaint.Font := Control.Font;

        if doCustom in Item.Footer.DrawingOptions then
          Control.DoCustomDrawFooter(i, FooterRect);

        //TODO: Control for disabling content or background.

        { Paint }
        StylePaint.PaintFooter(FooterRect);
      finally
        StylePaint.SetColumn(nil);
        SetClipRect(Canvas, ClientRect);
      end;

      { Paint Grid }
      if GridLines then
      begin
        { ToDo: CellColoring event }
        PaintGrid(i, -1, FooterRect, ColorEdges(FooterGridLinesColor), []);
      end;

      Inc(PaintPos.X, Item.Width);

    end;

  end;

  { Inactive. Space }
  with Canvas do
  begin
    Brush.Color := clWindow;
    FillRect(Rect(PaintPos.X, Self.FooterRect.Top, ClientRect.Right + pdStandard, ClientRect.Bottom));
  end;
end;

procedure TNxGridView6.PaintGrid(const ACol, ARow: Integer; CellRect: TRect;
  Edges: TNxBorderEdges; State: TNxCellPaintingState);
var
  HorzEdge, VertEdge: TNxBorderEdge6;
  LeftOverlap, HorzOverlap, VertOverlap: Integer;

  function BorderEdge(const X, Y: Integer; Edge: TNxBorderEdgeLocation): TNxBorderEdge6;
  var
    AllBorders: TNxBorderEdges;
  begin
    AllBorders := ColorEdges(GridLinesColor);
    DoGetCellGrid(Self, X, Y, AllBorders, State);
    Result := AllBorders[Edge];
  end;

begin
  with Canvas do
  begin
    { Notice: Reset and fix for
              StyleServices bug }
    Pen.Color := 0;
    Pen.Style := psSolid;

    { Event for Cell being painted }
    DoGetCellGrid(Self, ACol, ARow, Edges, State);

    { Right Borded of cell }
    LeftOverlap := 0;

    HorzEdge := Edges[beRight];

    { Check if next Cell need beLeft (beRight for this cell)
      for herself. }
    if HorzEdge.Color = GridLinesColor then
    begin
      HorzEdge := BorderEdge(ACol + 1, ARow, beLeft);
    end;

    VertEdge := Edges[beBottom];

    if ARow <> -1 then
      if VertEdge.Color = GridLinesColor then
      begin
        VertEdge := BorderEdge(ACol, ARow + 1, beTop);
      end;

    HorzOverlap := 1;
    VertOverlap := 0;

    if (HorzEdge.Color <> FGridLinesColor) then
    begin
      HorzOverlap := 0;
      VertOverlap := 1;
      LeftOverlap := 1;
    end;

    { Horizontal Line }
    if GridSize[loRight] > 0 then
    begin
      { Clean background }
      if HorzEdge.Style <> psSolid then
      begin
        Pen.Color := Control.Color;
        Polyline([
          Point(CellRect.Right, CellRect.Top - LeftOverlap),
          Point(CellRect.Right, CellRect.Bottom + VertOverlap)
        ]);
      end;

      Pen.Color := HorzEdge.Color;
      Pen.Style := HorzEdge.Style;
      Polyline([
        Point(CellRect.Right, CellRect.Top - LeftOverlap),
        Point(CellRect.Right, CellRect.Bottom + VertOverlap)
      ]);
    end;

    { Vertical Line }
    if GridSize[loBottom] > 0 then
    begin

      { Clean background }
      if VertEdge.Style <> psSolid then
      begin
        Pen.Color := Control.Color;
        Polyline([
          Point(CellRect.Left, CellRect.Bottom),
          Point(CellRect.Right + HorzOverlap, CellRect.Bottom)
        ]);
      end;

      Pen.Color := VertEdge.Color;
      Pen.Style := VertEdge.Style;
      Polyline([
        Point(CellRect.Left, CellRect.Bottom),
        Point(CellRect.Right + HorzOverlap, CellRect.Bottom)
      ]);
    end;
  end;
end;

procedure TNxGridView6.PaintHeaders;
var
  Shift, i, Right: Integer;
  Item: TNxColumn6;
  HeaderRect, DropDownRect, ClipSrc, ClipDest: TRect;
  HeaderState, ButtonState: TNxButtonState;
  ScaledHeaderHeight: Integer;
begin
  { Start }
  Right := DataRect.Left;

  StylePaint.Font := Control.Font;
  StylePaint.Color := Control.Color;
  StylePaint.Canvas := Canvas;

  ScaledHeaderHeight := MulDiv(HeaderHeight, Screen.PixelsPerInch, 96);

  for i := 0 to Pred(Columns.Count) do
  begin
    Shift := DataRect.Left;

    { ScrollBar Shift }
    if i >= FixedColCount
      then Dec(Shift, Offset.cx);

    Item := Columns.PositionItem[i];

    if Item.Visible then
    begin
      HeaderRect := Bounds(Item.Left + Shift, 0, MulDiv(Item.Width, Screen.PixelsPerInch, 96), ScaledHeaderHeight);

      Right := HeaderRect.Right;

      { Header is completely out of View }
      if HeaderRect.Left > ClientRect.Right then Exit;

      { Clip Content inside Rect }
      ClipSrc := HeaderRect;

      ClipDest := Self.HeaderRect;

      if i >= FixedColCount
        then ClipDest.Left := FixedRect.Left;

      IntersectRect(ClipSrc, ClipSrc, ClipDest);

      try
        SetClipRect(Canvas, ClipSrc);

        StylePaint.SetLocation(Item.Location);

        try
          StylePaint.SetColumn(Item);
        except

        end;

        { Default State }
        HeaderState := [];

        { Check Hover }
        if HoverHeader = Item then
        begin
          HeaderState := [bsHover];
        end;

        { Check Pressed }
        if PressedHeader = Item then
        begin
          HeaderState := HeaderState + [bsPressed];
        end;

        { Event }
        if doCustom in Item.Header.DrawingOptions then
          Control.DoCustomDrawHeader(i, HeaderRect, HeaderState);

        { Paint }
        StylePaint.PaintHeader(HeaderRect, HeaderState);
      finally
        StylePaint.SetColumn(nil);
        SetClipRect(Canvas, ClientRect);
      end;

      { Button }
      if Item.Header.ShowButton then
        try
          ButtonState := [];

          if FHoverButton = Columns[i] then
          begin
            Include(ButtonState, bsHover);
          end;

          if FPressedHeaderButton = Columns[i] then
          begin
            Include(ButtonState, bsPressed);
          end;

          DropDownRect := Bounds(HeaderRect.Right - szFilterDropButtonWidth - 2, 2, szFilterDropButtonWidth, HeaderHeight - 4);

          StylePaint.PaintHeaderButton(DropDownRect, ButtonState);
        finally
          SetClipRect(Canvas, ClientRect);
        end;

    end; { Visible }

  end; { for }

  { Inactive. Space }
  StylePaint.PaintInactiveHeader(Rect(Right, 0, ClientRect.Right + pdStandard, ScaledHeaderHeight));
end;

procedure TNxGridView6.PaintIndicators;
begin
  if ShowHeader then
  begin
    StylePaint.PaintIndicator(Bounds(0, 0, RectWidth(IndicatorRect), DotToPixel(HeaderHeight)), ilHeader, False, False);
  end;
  if ShowInsertRow then
  begin
    StylePaint.PaintIndicator(Bounds(0, InsertRowRect.Top, RectWidth(IndicatorRect),
      DotToPixel(InsertRowHeight + szInsertRowSplitterHeight)), ilInsertRow, False, False);
  end;
  if ShowFooter then
  begin
    StylePaint.PaintIndicator(Bounds(0, FooterRect.Top, RectWidth(IndicatorRect), FFooterHeight + szFooterSplitterHeight), ilHeader, False, False);
  end;
end;

procedure TNxGridView6.PaintInsertRow;
var
  i: Integer;
  CellRect, SplitterRect, ClipSrc, ClipDest: TRect;
  DrawPos: TPoint;
  View: INxColumnView;
  Item: TNxColumn6;
begin
  SetClipRect(Canvas, ClientRect);

  DrawPos := InsertRowRect.TopLeft;

  { Splitter }
  with Canvas do
  begin
    SplitterRect := Bounds(DrawPos.X, DrawPos.Y + FInsertRowHeight, Columns.VisibleWidth, szInsertRowSplitterHeight);

    Brush.Color := clBtnFace;
    FillRect(SplitterRect);
  end;

  for i := 0 to Pred(Columns.Count) do
  begin

    { ScrollBar Shift }
    if i = FixedColCount
      then Dec(DrawPos.X, Offset.cx);

    Item := Columns.PositionItem[i];

    if Item.Visible then
    begin
      CellRect := Bounds(DrawPos.X, DrawPos.Y, Item.Width, FInsertRowHeight);

      { Exclude Grid from Rect }
      Dec(CellRect.Right, GridSize[loRight]);

      ClipSrc := CellRect;

      ClipDest := Self.InsertRowRect;

      if i >= FixedColCount
        then ClipDest.Left := FixedRect.Left;

      IntersectRect(ClipSrc, ClipSrc, ClipDest);

      { Paint Cell }
      try
        SetClipRect(Canvas, ClipSrc);

        if Assigned(FCapturedView)
          and (FCapturedView.Cell = Item.InsertValue) then
        begin
          View := FCapturedView;
        end else
        begin
          View := Item.View;

          View.Style := Control.StylePaint;
          View.Style.Canvas := Canvas;

          View.ClientRect := CellRect;
          View.Cell := Item.InsertValue;
          View.DrawingOptions := [doBackground, doContent, doCustom];
          View.Parent := Self;
          View.Location := Point(i, -1);
          View.HideSelection := Control.HideSelection;
          View.InactiveSelectionColor := Control.InactiveSelectionColor;
          View.SelectionColor := Control.SelectionColor;
          View.SelectionTextColor := Control.SelectionTextColor;
          View.HintIndicators := aoHintIndicators in Control.AppearanceOptions;

          View.EmptyCaption := Item.InsertCaption;
          View.HideWhenEmpty := Item.InsertCaption <> EmptyStr;

          { Note: Some columns (e.g. AutoInc) don't paint themself
                  inside Insert row. }
          if not (csPaintInsert in Item.Style)
            then View.DrawingOptions := [doBackground];

          View.Selected := Control.InsertSelected and not (Control.SelectedLocation.X = Item.Index);
          View.Selected := View.Selected;// or EqualPoint(Control.SelectedCell, Control.EditingCell);

          View.Editing := IsEqual(Control.EditingCell, View.Location);

          View.Canvas := Canvas;
          View.Control := TWinControl(GetComponent(Self.Control));
          View.Owner := Control as INxCellOwner;

        end;

        View.Paint;
      finally
        SetClipRect(Canvas, ClientRect);
      end;

      { Paint Grid }
      if GridLines then
      begin
        { ToDo: CellColoring event }
        PaintGrid(i, -1, CellRect, ColorEdges(GridLinesColor), []);
      end;

      Inc(DrawPos.X, Item.Width);

      { Right edge }
      if DrawPos.X > InsertRowRect.Right
        then Exit;
    end;
  end;

  with Canvas do
  begin
    Brush.Color := clWindow;
    FillRect(Rect(DrawPos.X, DrawPos.Y, ClientRect.Right, DrawPos.Y + FInsertRowHeight +  szInsertRowSplitterHeight));
  end;

end;

procedure TNxGridView6.PaintRows;
begin

end;

function TNxGridView6.Pixels(Points: Integer): Integer;
begin
  Result := 0;
end;

procedure TNxGridView6.PopupFilter(Column: TNxColumn6);
var
  Location: TPoint;
  Accept: Boolean;
begin
  { Destroy Old one }
  FreeAndNil(FFilterPopup);

  { Default behaviour }
  Accept := True;

  Location := GetHeaderButttonRect(Column).BottomRight;
  Location := Control.ClientToScreen(Location);

  { Trigger event }
  Column.DoHeaderButtonClick(Location.X, Location.Y, Accept);

  if Accept then
  begin
    try
      FFilterPopup := TNxFilterPopupControl6.Create(Self);
      FFilterPopup.Parent := TWinControl(Control);
      FFilterPopup.Popup(Location, paRight);
    except
      FreeAndNil(FFilterPopup);
    end;
  end;
end;

procedure TNxGridView6.RefreshCell(ACol, ARow: Integer);
begin
  if Control.CellExists(ACol, ARow) then
  begin
    Invalidate(GetCellRect(ACol, ARow));
  end;
end;

procedure TNxGridView6.Recount;
begin
end;

procedure TNxGridView6.RefreshCell(ACol: Integer);
begin
  Invalidate(GetCellRect(ACol));
end;

procedure TNxGridView6.RefreshCell(Location: TPoint; ContentOnly: Boolean);
var
  View: INxColumnView;
  RowView: INxRowView;
begin
  if ContentOnly then
  begin
    if Assigned(FCapturedView) then
    begin
      View := FCapturedView;
    end else
    begin
      View := Columns[Location.X].View;
      View.Cell := Control.Cell[Location.X, Location.Y];
      View.ClientRect := GetCellRect(Location);
      View.Canvas := Self.Canvas;
      View.Control := TWinControl(Control.ToObject);
      View.Location := Location;
      View.Style := Control.StylePaint;

      View.DrawingOptions := [doBackground, doContent, doCustom];
      View.Parent := Self;
      View.HideSelection := Control.HideSelection;
      View.InactiveSelectionColor := Control.InactiveSelectionColor;
      View.SelectionColor := Control.SelectionColor;
      View.SelectionTextColor := Control.SelectionTextColor;

      if Supports(View, INxRowView, RowView) then
      begin
        RowView.Row := Row[Location.Y];
      end;
    end;

    { NOTE: Changed only update portion
            of cell, if set }
    View.Changed;
  end
  else RefreshCell(Location.X, Location.Y); { overloaded }
end;

procedure TNxGridView6.RefreshColumn(Column: TNxColumn6; Area: TNxGridArea);
var
  InvalidationRect: TRect;
begin
  case Area of
    gaFooter,
    gaHeader,
    gaInsertRow:
    begin
      InvalidationRect := GetColumnRect(Column, Area);

      Invalidate(InvalidationRect);
    end;
  end;
end;

procedure TNxGridView6.RefreshData;
var
  InvalidationRect: TRect;
begin
  InvalidationRect := DataRect;
  InvalidationRect.Left := 0;

  { Refresh }
  Invalidate(InvalidationRect);
end;

procedure TNxGridView6.RefreshHeader(const Index: Integer);
begin
  Invalidate(GetColumnRect(Columns[Index], gaHeader));
end;

procedure TNxGridView6.RefreshHeaderButton(Column: TNxColumn6);
begin
  Invalidate(GetHeaderButttonRect(Column));
end;

procedure TNxGridView6.RefreshInsertRow;
begin
  Invalidate(InsertRowRect);
end;

procedure TNxGridView6.RefreshSelection;
var
  i: Integer;
begin
  with Control do
    if InsertSelected and ShowInsertRow
      then RefreshInsertRow else
    begin

      if SelectFullRow then
      begin

        if MultiSelect then
        begin
          for i := 0 to Pred(RowCount) do
            if Selected[i] then RefreshRow(i);
        end else
          for i := 0 to Pred(Columns.Count) do
            if Highlighted[i, SelectedLocation.Y] then
              RefreshCell(i, SelectedLocation.Y);

      end else
      begin
        if Highlighted[SelectedLocation.X, SelectedLocation.Y]
          then RefreshCell(SelectedLocation.X, SelectedLocation.Y);
      end;

    end;
end;

procedure TNxGridView6.ReleaseCellHint;
begin
  if Assigned(FCellHint) then
  begin
    FCellHint.ReleaseHandle;
    FreeAndNil(FCellHint);
  end;
end;

procedure TNxGridView6.ReleaseHeaderHint;
begin
  if Assigned(FHeaderHint) then
  begin
    FHeaderHint.ReleaseHandle;
    FreeAndNil(FHeaderHint);
  end;
end;

procedure TNxGridView6.ReleaseTextFitHint;
begin
  if Assigned(FCellTextFitHint) then
  begin
    FCellTextFitHint.ReleaseHandle;
    FreeAndNil(FCellTextFitHint);
  end;
end;

procedure TNxGridView6.Remove;
begin
  if Assigned(Owner) then Owner.RemoveComponent(Self);
end;

procedure TNxGridView6.Reset;
begin
  { Interf. }
  FCapturedView := nil;
end;

procedure TNxGridView6.ScrollContentBy(DeltaX, DeltaY: Integer);
var
  CursorPos: TPoint;
begin
  GetCursorPos(CursorPos);
  CursorPos := Control.ScreenToClient(CursorPos);

  { Set ClientRect of View }
  ViewChanged(FCapturedView);

  MouseMove([], CursorPos.X, CursorPos.Y);
end;

procedure TNxGridView6.ScrollRect(DeltaX, DeltaY: Integer; Rect,
  ClipRect: TRect);
begin
{$IFDEF UNSAFE}
  ScrollWindowEx(Control.Handle, DeltaX, DeltaY, @Rect, @ClipRect, 0, nil, SW_INVALIDATE);
{$ELSE}
  ScrollWindowEx(Control.Handle, DeltaX, DeltaY, Rect, ClipRect, 0, nil, SW_INVALIDATE);
{$ENDIF}
end;

procedure TNxGridView6.SetCanvas(const Value: TCanvas);
begin
end;

procedure TNxGridView6.SetClientRect(const Value: TRect);
begin
end;

procedure TNxGridView6.SetPressedCell(const Value: TPoint);
var
  View: INxColumnView;
begin
  { Init. }
  View := nil;

  if not IsEqual(FPressedCell, Value) then
  begin

    { Set Value }
    FPressedCell := Value;

    { 10/15/13: Don't compare with FHover cell, since
                Popup controls cause problems. }

    if IsSet(FPressedCell)
      and Columns[FPressedCell.X].Enabled then
    begin

      { Capture View }
      if not Assigned(FCapturedView) then
      begin
        View := Columns[FPressedCell.X].View;

        { Can respond to Mouse & Keys? }
        if View.IsResponsive then
        begin
          { Set & Clone }
          CaptureView(FPressedCell);
        end;

      end;

    end
    else Unset(FPressedCell);

  end;

end;

procedure TNxGridView6.SetPressedHeader(const Value: TNxColumn6);
var
  PrevDownHeader: TNxColumn6;
begin
  if Assigned(FHeaderControl) then
  begin
    FreeAndNil(FHeaderControl);
  end;

  if Assigned(Value) and (not Value.Enabled or not Value.Header.Clickable)
    then Exit;

  if Value <> FPressedHeader then
  begin
    PrevDownHeader := FPressedHeader;
    FPressedHeader := Value;

    { Refresh Prev. }
    if Assigned(PrevDownHeader) then
      RefreshHeader(PrevDownHeader.Index);

    { Refresh New }
    if Assigned(FPressedHeader) then
      RefreshHeader(FPressedHeader.Index);
  end;
end;

procedure TNxGridView6.SetPressedHeaderButton(const Value: TNxColumn6);
var
  T: TNxColumn6;
begin
  if Value <> FPressedHeaderButton then
  begin
    T := FPressedHeaderButton;
    FPressedHeaderButton := Value;

    if Assigned(T) then RefreshHeaderButton(T);
    if Assigned(FPressedHeaderButton) then
    begin
      RefreshHeaderButton(FPressedHeaderButton);

      Control.Update;

      PopupFilter(FPressedHeaderButton);
    end;
  end;
end;

procedure TNxGridView6.SetDroppedDown(const Value: Boolean);
begin
  if not Value then
  begin
    PressedHeaderButton := nil;

    FreeAndNil(FFilterPopup);
  end;
end;

procedure TNxGridView6.SetEnabled(const Value: Boolean);
begin
  FEnabled := Value;
end;

procedure TNxGridView6.SetFixedColCount(const Value: Integer);
begin
  if (Value <> FFixedColCount)
    and (Columns.Exist(Value) or (csLoading in ComponentState)) then
  begin
    FFixedColCount := Value;
    Invalidate;
  end;
end;

procedure TNxGridView6.SetFixedRowCount(const Value: Integer);
begin
  if (Value <> FFixedRowCount) and (Value > -1) then
  begin
    FFixedRowCount := Value;

    Control.UpdateScrollBars;
    Invalidate;
  end;
end;

procedure TNxGridView6.SetFooterGridLinesColor(const Value: TColor);
begin
  if Value <> FFooterGridLinesColor then
  begin
    FFooterGridLinesColor := Value;
    Invalidate;
  end;
end;

procedure TNxGridView6.SetFooterHeight(const Value: Integer);
begin
  FFooterHeight := Value;

  Control.UpdateScrollBars;

  { Refresh }
  Invalidate;
end;

procedure TNxGridView6.SetGridLines(const Value: Boolean);
begin
  FGridLines := Value;

  Control.UpdateScrollBars;
  Control.UpdateInplaceEditor;

  { Refresh }
  Invalidate;
end;

procedure TNxGridView6.SetGridLinesColor(const Value: TColor);
begin
  if Value <> FGridLinesColor then
  begin
    FGridLinesColor := Value;

    { Refresh }
    Invalidate;
  end;
end;

procedure TNxGridView6.SetGridLinesStyle(const Value: TNxGridLinesStyle);
begin
  if Value <> FGridLinesStyle then
  begin
    FGridLinesStyle := Value;

    Control.UpdateScrollBars;
    Control.UpdateInplaceEditor;

    { Refresh }
    Invalidate;
  end;
end;

procedure TNxGridView6.SetHeaderHeight(const Value: Integer);
begin
  FHeaderHeight := Value;

  Control.UpdateScrollBars;

  { Refresh }
  Invalidate;
end;

procedure TNxGridView6.SetHoverButton(const Value: TNxColumn6);
var
  T: TNxColumn6;
begin
  if Value <> FHoverButton then
  begin
    HoverHeader := nil;
    ResizeReadyColumn := nil;

    T := FHoverButton;
    FHoverButton := Value;

    if Assigned(T) then RefreshHeaderButton(T);
    if Assigned(FHoverButton) then RefreshHeaderButton(FHoverButton);
  end;
end;

procedure TNxGridView6.SetHoverCell(const Value: TPoint);
var
  Cell: INxBaseCell;
  CellHint: WideString;
  CellRect: TRect;
  Location: TPoint;
  TextContent: INxTextContent;
  View: INxColumnView;
begin
  if not IsEqual(FHotCell, Value) then
  begin
    ReleaseCellHint;
    ReleaseTextFitHint;

    if Assigned(FCapturedView) then
    begin
      { Can't capture! }
      if FCapturedView.Captured
        then Exit;

      { Unset Hover }
      FCapturedView.MouseLeave;

      { Release }
      FCapturedView := nil;
    end;

    { Event }
    if IsSet(FHotCell)
      then Control.DoCellMouseLeave(FHotCell.X, FHotCell.Y);

    { Set Value }

    FHotCell := Value;

    if IsSet(FHotCell)
      and Columns[FHotCell.X].Enabled then
    begin
      { Event }
      Control.DoCellMouseEnter(FHotCell.X, FHotCell.Y);

      SetScreenCursor(Columns[FHotCell.X].Cursor);

      { IsResponsive Checked inside
        Set & Clone }
      CaptureView(FHotCell);

      if FHotCell.Y = -1 then
      begin
        Cell := Columns[FHotCell.X].InsertValue;
        CellRect := GetCellRect(FHotCell.X);
      end else
      begin
        Cell := Cells[FHotCell.X, FHotCell.Y];
        CellRect := GetCellRect(FHotCell);
      end;

      if Supports(Columns[FHotCell.X], INxTextContent, TextContent) then
        if TextContent.ShowTextFitHint then
        begin
          if not Cell.Visible then Exit;

          View := UpdateCellView(FHotCell.X, FHotCell.Y, CellRect);

          if not View.CanFitText then
          begin
            Location := CellRect.TopLeft;

            ShowCellTextFitHint(Location, Columns[FHotCell.X].GetDisplayText(Cell, FHotCell.X, FHotCell.Y));
          end;

        end;

      { Cell's Hint }
      CellHint := GetCellHint(FHotCell.X, FHotCell.Y, Cell);
      if CellHint <> '' then
      begin
        Location := CellRect.TopLeft;

        case Control.CellHintLocation of
          hlBottom: OffsetPoint(Location, 0, RectHeight(CellRect));
          hlBottomRight: OffsetPoint(Location, RectWidth(CellRect), -RectHeight(CellRect));
        end;

        if Assigned(Columns[FHotCell.X].OnGetHint) then
          Columns[FHotCell.X].OnGetHint(Columns[FHotCell.X], FHotCell.X, FHotCell.Y, CellHint);

        ShowCellHint(Location, CellHint);
      end;

    end else
    begin
      Unset(FHotCell);
      SetScreenCursor(crDefault);
    end;

  end;
end;

procedure TNxGridView6.SetHoverFooter(const Value: TNxColumn6);
begin
  if Value <> FHoverFooter then
  begin
    if Assigned(Value) and Value.Enabled
      then FHoverFooter := Value
        else FHoverFooter := nil;

    { Destroy old Hint, if exists }
    ReleaseHeaderHint;

    FreeAndNil(FHeaderHintDelayTimer);

    if Assigned(FHoverFooter) then
    begin
      { Trigger Event for Hint }
      if (FHoverFooter.Footer.Hint <> EmptyStr)
        and not Assigned(ResizeReadyColumn) then
      begin
        FHeaderHintDelayTimer := TTimer.Create(Self);
        FHeaderHintDelayTimer.Interval := Application.HintPause;
        FHeaderHintDelayTimer.OnTimer := DoFooterHintDelayTimer;
      end;
    end;
  end;
end;

procedure TNxGridView6.SetHoverHeader(const Value: TNxColumn6);
var
  PrevHoverHeader: TNxColumn6;
begin
  if Value <> FHoverHeader then
  begin
    PrevHoverHeader := FHoverHeader;

    if Assigned(Value) and Value.Enabled
      then FHoverHeader := Value
        else FHoverHeader := nil;

    { Destroy old Hint, if exists }
    ReleaseHeaderHint;

    FreeAndNil(FHeaderHintDelayTimer);

    if Assigned(PrevHoverHeader) then
    begin
      { Refresh Prev. "Hover" Header }
      if StylePaint.HotTrackHeaders
        then RefreshHeader(PrevHoverHeader.Index);
    end;

    if Assigned(FHoverHeader) then
    begin
      { Refresh Header }
      if StylePaint.HotTrackHeaders
        then RefreshHeader(FHoverHeader.Index);

      { Trigger Event for Hint }
      if (HoverHeader.Header.Hint <> EmptyStr)
        and not Assigned(ResizeReadyColumn) then
      begin
        FHeaderHintDelayTimer := TTimer.Create(Self);
        FHeaderHintDelayTimer.Interval := Application.HintPause;
        FHeaderHintDelayTimer.OnTimer := DoHeaderHintDelayTimer;
      end;
    end;
  end;
end;

procedure TNxGridView6.SetIndex(const Value: Integer);
begin
  
end;

procedure TNxGridView6.SetIndicatorWidth(const Value: Integer);
begin
  if Value <> FIndicatorWidth then
  begin
    FIndicatorWidth := Value;
    Invalidate;
  end;
end;

procedure TNxGridView6.SetInsertRowHeight(const Value: Integer);
begin
  if Value <> FInsertRowHeight then
  begin
    FInsertRowHeight := Value;
    Invalidate;
  end;
end;

procedure TNxGridView6.SetResponsiveWidth(const Value: Integer);
begin
  if Value <> FResponsiveWidth then
  begin
    FResponsiveWidth := Value;
    Changed;
  end;
end;

procedure TNxGridView6.SetOptions(const Value: TNxGridViewOptions);
begin
  FOptions := Value;
end;

procedure TNxGridView6.SetParentComponent(Value: TComponent);
begin
  if Value is TNxCustomGrid6 then
  begin
    Views := TNxCustomGrid6(Value).Views;
  end;
end;

procedure TNxGridView6.SetResizeReadyColumn(const Value: TNxColumn6);
begin
  if Value <> FResizeReadyColumn then
  begin
    FResizeReadyColumn := Value;

    FreeAndNil(FHeaderHintDelayTimer);

    if Assigned(FResizeReadyColumn) then
    begin
      SetScreenCursor(crSizeWE);
    end
    else SetScreenCursor(crDefault);
  end;
end;

procedure TNxGridView6.SetResizingColumn(const Value: TNxColumn6);
var
  X, Delta: Integer;
begin
  X := 0;
  if Value <> FResizingColumn then
  begin

    if Assigned(FResizingColumn) then
    begin
      X := FResizingColumn.Left + DataRect.Left - HorzScrollBar.Position;
    end;

//    if Assigned(FResizingColumn) then
//      with Canvas do
//        try
//          X := FResizingColumn.Left + DataRect.Left - Control.HorzScrollBar.Position;
//          Pen.Mode := pmNot;
//          Polyline([
//            Point(X, 0),
//            Point(X, ClientRect.Bottom)
//          ]);
//        finally
//          Pen.Mode := pmCopy;
//        end;

    if not Assigned(Value) then
    begin
      Delta := FResizingPos.X - X;
      Delta := Delta div (Screen.PixelsPerInch div 96);
      FResizingColumn.Width := Delta;

      { Event }
      FResizingColumn.DoResize;
    end;

    FResizingColumn := Value;

    if Assigned(FResizingColumn) then
      with Canvas do
        try
          X := FResizingColumn.Left + DataRect.Left - HorzScrollBar.Position;
          Pen.Mode := pmNot;
          Polyline([
            Point(X, 0),
            Point(X, ClientRect.Bottom)
          ]);
        finally
          Pen.Mode := pmCopy;
        end;

    if Assigned(FResizingColumn) then
    begin
      ResizingPos := Point(X + MulDiv(FResizingColumn.Width, Screen.PixelsPerInch, 96), 0);
    end else
    begin
      ResizingPos := EmptyPoint;
    end;
  end;
end;

procedure TNxGridView6.SetResizingPos(const Value: TPoint);
var
  FPrevPos: TPoint;
begin
  if not IsEqual(Value, FResizingPos) then
  begin

    { Erase first }
    with Canvas do
      try
        Pen.Mode := pmNot;
        Polyline([
          Point(FResizingPos.X, 0),
          Point(FResizingPos.X, ClientRect.Bottom)
        ]);
      finally
        Pen.Mode := pmCopy;
      end;

    { Assign value }
    FResizingPos := Value;

    if Assigned(FResizingColumn) then
    begin
      FPrevPos.X := FResizingColumn.Left + DataRect.Left - HorzScrollBar.Position;

      if FResizingPos.X < FPrevPos.X + FResizingColumn.MinWidth then
      begin
        FResizingPos.X := FPrevPos.X + FResizingColumn.MinWidth;
      end;
    end;

    with Canvas do
      try
        Pen.Mode := pmNot;
        Polyline([
          Point(FResizingPos.X, 0),
          Point(FResizingPos.X, ClientRect.Bottom)
        ]);
      finally
        Pen.Mode := pmCopy;
      end;
  end;
end;

procedure TNxGridView6.SetSelectionStyle(const Value: TNxSelectionStyle);
begin
  if Value <> FSelectionStyle then
  begin
    FSelectionStyle := Value;
    Invalidate;
  end;
end;

procedure TNxGridView6.SetShowFooter(const Value: Boolean);
begin
  if Value <> FShowFooter then
  begin
    FShowFooter := Value;

    Update;
  end;
end;

procedure TNxGridView6.SetShowHeader(const Value: Boolean);
begin
  if Value <> FShowHeader then
  begin
    FShowHeader := Value;

    Update;
  end;
end;

procedure TNxGridView6.SetShowIndicator(const Value: Boolean);
begin
  if Value <> FShowIndicator then
  begin
    FShowIndicator := Value;

    Update;
  end;
end;

procedure TNxGridView6.SetShowInsertRow(const Value: Boolean);
begin
  if Value <> FShowInsertRow then
  begin
    FShowInsertRow := Value;

    Update;
  end;
end;

procedure TNxGridView6.SetViews(const Value: TNxGridViews6);
var
  Ref: IInterfaceComponentReference;
begin
  if Value <> Views then
  begin
    { Remove from old View }
    if Assigned(FViews) then
    begin
      FViews.FList.Remove(Self);
    end;

    FViews := Value;
    { Add into new View }
    { 8/22/12: Must use typecast for Interface (!)
               Otherwise Address will be different }
    if Assigned(FViews) then
    begin
      FViews.FList.Add(Self);

      if Supports(Control, IInterfaceComponentReference, Ref) then
      begin
        FreeNotification(Ref.GetComponent);
      end;
    end;

  end;
end;

procedure TNxGridView6.ShowArrows(Location: TPoint);
var
  ScreenPoint: TPoint;
begin
  { Align with header line }
  Dec(Location.X);

  { Top arrow }
  if not Assigned(FHeaderArrows[0]) then
  begin
    FHeaderArrows[0] := TNxHeaderControlArrow.Create(Self);
    FHeaderArrows[0].Parent := TWinControl(Control.ToObject);
    FHeaderArrows[0].ArrowKind := akDown;
    FHeaderArrows[0].Show;
  end;

  Location.Y := -FHeaderArrows[0].Height;
  Dec(Location.X, FHeaderArrows[0].Width div 2);
  ScreenPoint := Control.ClientToScreen(Location);

  FHeaderArrows[0].SetBounds(ScreenPoint.X, ScreenPoint.Y, FHeaderArrows[0].Width, FHeaderArrows[0].Height);

  { Bottom arrow }
  if not Assigned(FHeaderArrows[1]) then
  begin
    FHeaderArrows[1] := TNxHeaderControlArrow.Create(Self);
    FHeaderArrows[1].Parent := TWinControl(Control.ToObject);
    FHeaderArrows[1].ArrowKind := akUp;
    FHeaderArrows[1].Show;

  end;

  Location.Y := HeaderRect.Bottom;

  ScreenPoint := Control.ClientToScreen(Location);
  FHeaderArrows[1].SetBounds(ScreenPoint.X, ScreenPoint.Y, FHeaderArrows[1].Width, FHeaderArrows[1].Height);

  FHeaderControl.BringToFront;
end;

procedure TNxGridView6.ShowCellHint(Location: TPoint; Hint: WideString);
var
  HintRect: TRect;
begin
  { Create Hint Window }
  FCellHint := HintWindowClass.Create(nil);

  { Set Position & Activate }

  { Calculate Rect }
  HintRect := FCellHint.CalcHintRect(Screen.Width, Hint, nil);

  { Convert to Screen }
  HintRect.TopLeft := Views.Control.ClientToScreen(Location);

  HintRect.Bottom := HintRect.Top + HintRect.Bottom;
  HintRect.Right := HintRect.Left + HintRect.Right;

  { Show Hint }
  FCellHint.ActivateHint(HintRect, Hint);
end;

procedure TNxGridView6.ShowCellTextFitHint(Location: TPoint; Hint: WideString);
var
  HintRect: TRect;
begin
  if Hint <> '' then
  begin
    Include(FState, taHintCreating);

    { Create Hint Window }
    FCellTextFitHint := TNxTextFitHintWindow.Create(Self);
    FCellTextFitHint.Color := clWindow;

    { Set Position & Activate }

    { Calculate Rect }
    HintRect := FCellTextFitHint.CalcHintRect(Screen.Width, Hint, nil);

    { Convert to Screen }
    HintRect.TopLeft := Views.Control.ClientToScreen(Location);

    HintRect.Bottom := HintRect.Top + HintRect.Bottom;
    HintRect.Right := HintRect.Left + HintRect.Right;

    { Show Hint }
    FCellTextFitHint.ActivateHint(HintRect, Hint);

    Exclude(FState, taHintCreating);
  end;
end;

procedure TNxGridView6.StartHeaderDrag(X, Y: Integer);
var
  ScreenPoint: TPoint;
begin
  ScreenPoint := Control.ClientToScreen(Point(X, Y));

  FHeaderControl := TNxColumnHeaderControl.Create(Self);
  FHeaderControl.Visible := False;

  FHeaderControl.Column := FPressedHeader;
  FHeaderControl.Width := FPressedHeader.Width;
  FHeaderControl.Height := FHeaderHeight;
  FHeaderControl.Parent := TWinControl(Control.ToObject);
  FHeaderControl.StylePaint := StylePaint;
  FHeaderControl.OnDrop := DoHeaderControlDrop;
  FHeaderControl.OnMove := DoHeaderControlMove;

  FHeaderControl.Visible := True;

  FHeaderControl.MoveToPoint(ScreenPoint);
  Windows.SendMessage(FHeaderControl.Handle, WM_LBUTTONDOWN, 0, 0);
end;

procedure TNxGridView6.Update;
begin
  if Assigned(Views) then
  begin
    Control.UpdateScrollBars;
    Invalidate;
  end;
end;

function TNxGridView6.UpdateCellView(ACol, ARow: Integer; CellRect: TRect): INxColumnView;
var
  View: INxColumnView;
  RowView: INxRowView;
  Cell: INxBaseCell;
begin
  with Canvas do
  begin
    Font.Assign(Control.Font);

    if ARow < 0 then
      Cell := Control.Columns[ACol].InsertValue
    else
      Cell := Control.Cell[ACol, ARow];

    { ToDo: Move Columns[ACol] as with }
    View := Columns[ACol].View;

    View.Style := Control.StylePaint;
    View.Active := False;
    View.Canvas := Canvas;
    View.Parent := Self;
    View.HideSelection := Control.HideSelection;

    View.InactiveSelectionColor := Control.InactiveSelectionColor;
    View.SelectionColor := Control.SelectionColor;
    View.SelectionTextColor := Control.SelectionTextColor;

    View.Control := TWinControl(Control.ToObject);

    View.ClientRect := CellRect;
    View.Cell := Cell;
    View.EmptyCaption := Columns[ACol].EmptyCaption;
    View.HideWhenEmpty := Columns[ACol].HideWhenEmpty;

    View.DrawingOptions := Columns[ACol].DrawingOptions;

    if View.Cell.Empty then
    begin
//        View.DrawingOptions := doBackgroundOnly;
    end;

    View.Location := Point(ACol, ARow);
    View.Editing := IsEqual(Control.EditingCell, View.Location);
    View.Selected := Control.Highlighted[ACol, ARow];
    View.Pressed := IsEqual(View.Location, PressedCell);
  end;

  if Supports(View, INxRowView, RowView) then
  begin
    if ARow >= 0 then
    begin
      RowView.Row := Row[ARow];
    end else
      RowView.Row := nil;
  end;

  Result := View;
end;

procedure TNxGridView6.ViewChanged(View: INxColumnView);
begin
  if Assigned(View) then
    with View do
    begin
      ClientRect := GetCellRect(Location);
    end;
end;

{ TNxListGridView }

procedure TNxListGridView6.Activate;
begin
  inherited;
  Columns.ClientWidth := DataRect.Right - DataRect.Left;
  Columns.UpdateAutoSizes;
end;

procedure TNxListGridView6.AfterSort;
var
  i, Position: Integer;
begin
  { Reset FirstIndex, CapturedView... }
  Reset;

  i := 0;
  Position := VertScrollBar.Position;

  while i < Position do
  begin
    if RowsOwner.Showing[FFirstIndex]
      then Inc(i);

    Inc(FFirstIndex);
  end;
end;

constructor TNxListGridView6.Create(AOwner: TComponent);
begin
  inherited;
  FFirstIndex := 0;
  FIngrealBottom := 0;
  FRowMovingOptions := [moPosition, moInsert];
  FMovingRow := nil;
  FMovingTargetRow := nil;
  FMovingTimer := nil;
  FOldMovingLocation := lcNone;
  FResizeReadyRow := nil;
  FRowResizing := False;
  FRowResizingOptions := roResizeSingleRow;
  FResizingRow := nil;
end;

procedure TNxListGridView6.Deactivate;
begin
  MovingTargetRow := nil;
  inherited;
end;

destructor TNxListGridView6.Destroy;
begin
  FreeAndNil(FMovingTimer);
  inherited;
end;

procedure TNxListGridView6.DoAddRow(const Count: Integer);
begin
  FFirstIndex := RowsOwner.RowCount - Count;
end;

procedure TNxListGridView6.DoMoveDrop(Row, ParentRow: INxRow;
  CurIndex, NewIndex: Integer);
begin
  if Assigned(FOnRowMoveDrop) then FOnRowMoveDrop(Self, MovingRow, ParentRow, CurIndex, NewIndex);
end;

procedure TNxListGridView6.DoMovingTimer(Sender: TObject);
begin
  if Assigned(FMovingTargetRow) then ScrollToRow(FMovingTargetRow.AbsoluteIndex);
  FreeAndNil(FMovingTimer);
end;

{$HINTS OFF}
procedure TNxListGridView6.ExpandRow(Row: INxRow; Expand: Boolean);
var
  AbsoluteIndex, ContentHeight: Integer;
  Index, Top, Bottom, Delta: Integer;
  R: TRect;
  Sibling: INxRow;

  function GetRowContentHeight(const Index: Integer; Rows: INxRows): Integer;
  var
    i: Integer;
  begin
    Result := 0;

    for i := Index to Pred(Rows.ChildRowCount) do
    begin
      Inc(ContentHeight, ItemHeight[AbsoluteIndex]);

      Inc(ContentHeight, GetGridSize(loBottom));

      Inc(AbsoluteIndex);

      if Rows.ChildRow[i].HasChildren then
      begin

        if Rows.ChildRow[i].Expanded then
        begin
          GetRowContentHeight(0, Rows[i] as INxRows);
        end else
        begin
          Inc(AbsoluteIndex, (Rows.ChildRow[i] as INxBranches).BranchRowCount);
        end;
      end;

    end;

  end;

begin
  Index := Row.AbsoluteIndex;

  ContentHeight := 0;

  AbsoluteIndex := Row.AbsoluteIndex;

  if Index >= FirstIndex then
  begin

    Top := GetItemTop(Index) + ItemHeight[Index];

    Sibling := Row.NextSibling;

    Bottom := ClientHeight;
    if Assigned(Sibling) then
    begin
      Bottom := GetItemTop(Sibling.AbsoluteIndex);
    end;

//    Delta := GetRowContentHeight(0, Row as INxRows);
    Delta := ContentHeight;

    R := Rect(0, Top, ClientRect.Right - ClientRect.Left, ClientRect.Bottom);

    with Canvas do
    begin
//      Brush.Color := clRed;
//      FillRect(R);
//      exit;
    end;

    if not Expand then
      Delta := 0 - Delta;

    ScrollRect(0, Delta, r, r);
  end;
//  for i := Index to Control. do

end;
{$HINTS ON}

function TNxListGridView6.GetDataBottom: Integer;
var
  i: Integer;
begin
  { Default }
  Result := FixedRect.Top;

  for i := FirstIndex to Pred(RowsOwner.RowCount) do
    if RowsOwner.Showing[i] then
    begin

      { Shift Pos (& Grid) }
      Inc(Result, ItemHeight[i] + ItemGridSize[loBottom]);

      { Note: Not Include Grid }
      if Result + ItemHeight[i] > DataRect.Bottom then
      begin

        Exit; { Done }
      end;
    end;
end;

function TNxListGridView6.GetFirstIndex: Integer;
begin
  Result := FFirstIndex + LastFixedRow + 1;
end;

function TNxListGridView6.GetFirstRowInPage: Integer;
begin
  Result := FFirstIndex;
  { TODO: Solve better FindFirstRowInPage for VirtualMode }
//  if VirtualMode then Result := FindFirstRowInPage else Result := FFirstIndex;
end;

function TNxListGridView6.GetFixedRect: TRect;
begin
  Result := inherited GetFixedRect;
  Inc(Result.Top, FixedHeight);
end;

function TNxListGridView6.GetFixedShowingCount: Integer;
var
  Index: Integer;
begin
  Result := 0;
  Index := 0;
  while Index < RowsOwner.RowCount do
  begin
    if Result >= FFixedRowCount then Exit;
    if RowsOwner.Showing[Index] then Inc(Result);
    Inc(Index);
  end;
end;

///<summary>
///Get client Row rectangle.
///</summary>
function TNxListGridView6.GetFocusRect(Index: Integer): TRect;
begin
  Result := Bounds(DataRect.Left, GetItemTop(Index), ClientDataRect.Right, GetItemHeight(Index));
end;

function TNxListGridView6.GetHorzClipRect: TRect;
begin
  Result := Bounds(FixedRect.Left, 0, DotToPixel(Columns.VisibleWidth), ClientRect.Bottom);
end;

function TNxListGridView6.GetItemAtPos(X, Y: Integer): Integer;
var
  RowIndex, ShowingCount: Integer;
  ItemY: Integer;
  ItemRect: TRect;
begin
  { Default, not found }
  Result := -1;

  { Top-left Corner }
  ItemY := DataRect.Top;

  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FirstIndex;
  end;

  ShowingCount := 0;

  while RowIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[RowIndex] then
    begin

      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FirstIndex + RowIndex;
      end;

      ItemRect := Types.Bounds(DataRect.Left, ItemY, DataRect.Right - DataRect.Left, ItemHeight[RowIndex]);

      if PtInRect(ItemRect, Point(X, Y)) then
      begin
        Result := RowIndex;

        { Done }
        Exit;
      end;

      { Shift Yt (& Grid) }
      Inc(ItemY, ItemHeight[RowIndex] + ItemGridSize[loBottom]);

      Inc(ShowingCount);
    end;

    { Go to next }
    Inc(RowIndex);
  end;
end;

function TNxListGridView6.GetItemRect(Index: Integer): TRect;
begin
  Result := Bounds(DataRect.Left, GetItemTop(Index), DataRect.Right - DataRect.Left, ItemHeight[Index]);
end;

function TNxListGridView6.GetItemTop(Index: Integer): Integer;
var
  RowIndex, ShownCount: Integer;
begin
  { Top-left Corner }
  Result := DataRect.Top;

  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FirstIndex;
  end;

  ShownCount := 0;

  while RowIndex < Index do
  begin
    if RowsOwner.Showing[RowIndex] then
    begin
      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShownCount = FFixedRowCount then RowIndex := FirstIndex + RowIndex;
      end;

      { Shift Y (& Grid) }
      Inc(Result, ItemHeight[RowIndex] + ItemGridSize[loBottom]);

      Inc(ShownCount);
    end;

    { Go to next }
    Inc(RowIndex);
  end;
end;

function TNxListGridView6.GetLastFixedRow: Integer;
var
  c: Integer;
begin
  Result := -1;
  if RowCount = 0 then Exit;
  c := 0;
  while (Result < RowCount - 1) and (c < FixedRowCount) do
  begin
    Inc(Result);
    if Showing[Result] then Inc(c);
  end;
end;

function TNxListGridView6.GetLastRowInPage: Integer;
var
  Pos, i: Integer;
begin
  { Default }
  Result := 0;

  Pos := FixedRect.Top;

  for i := FirstIndex to Pred(RowsOwner.RowCount) do
    if RowsOwner.Showing[i] then
    begin
      { Assign }
      Result := i;

      { Shift Pos (& Grid) }
      Inc(Pos, RowHeight[i] + GridSize[loBottom]);

//      if Control.IsIntegralHeight then
//      begin
//
//        if Pos > DataRect.Bottom then
//        begin
//
//          Exit; { Done }
//        end;
//
//      end else

      { Note: Not Include Grid }
      if Pos + RowHeight[i] > DataRect.Bottom then
      begin

        Exit; { Done }
      end;


    end;
end;

function TNxListGridView6.GetLastRowInView: Integer;
var
  Pos, RowIndex: Integer;
begin
  { Set Default }
  Result := FirstIndex;

  Pos := FixedRect.Top;

  for RowIndex := FirstIndex to Pred(RowsOwner.RowCount) do
    if RowsOwner.Showing[RowIndex] then
    begin
      Result := RowIndex;

      Inc(Pos, RowHeight[RowIndex]);

      { Inc. Grid }
      Inc(Pos, GridSize[loBottom]);

      { Reach Edge }
      if Pos > DataRect.Bottom
        then Exit;
    end;
end;

function TNxListGridView6.GetNearestRowAtPos(X, Y: Integer;
  ARow: INxRow; Options: TNxRowMoveOptions; var Location: TNxRowMoveLocation): INxRow;
var
  RowIndex, ShowingCount, Middle, Treshold: Integer;
  CurrentRow: INxRow;
  Pos: TPoint;
  RowRect: TRect;
begin
  Result := nil;
  CurrentRow := nil;

  { Top-left Corner }
  Pos := DataRect.TopLeft;

  { Start fixed, if exist }
  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FirstIndex;
  end;

  ShowingCount := 0;

  while RowIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[RowIndex] then
    begin
      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FirstIndex + RowIndex;
      end;

      CurrentRow := RowsOwner.Row[RowIndex];

      { Reset X Position }
      Pos.X := DataRect.Left;

      RowRect := Bounds(Pos.X, Pos.Y, Columns.VisibleWidth, ItemHeight[RowIndex]);

      { Incl. Bottom Grid, it is also clickable }
      Inc(RowRect.Bottom, GridSize[loBottom]);

      if PtInRect(RowRect, Point(X, Y)) then
      begin
        Location := lcNone;

        Middle := (RowRect.Bottom - RowRect.Top) div 2;

        if moPosition in Options then
        begin
          if (moInsert in Options) and (CurrentRow.HasChildren) then Treshold := Floor(ItemHeight[RowIndex] * szMoveRowThreshold)
            else Treshold := Middle;

          if Y <= RowRect.Top + Treshold then
          begin
            Location := lcBefore;
          end
          else if Y >= RowRect.Bottom - Treshold then
          begin
            Location := lcAfter;
          end;

        end;

        if (moInsert in Options) and (Location = lcNone) then
        begin
          Location := lcInside;
        end;

        Result := CurrentRow;

        Exit; { Done }
      end;

      { Shift Y Drawing Pos. (& Grid) }
      Inc(Pos.Y, RowHeight[RowIndex] + GridSize[loBottom]);

      if Pos.Y > DataRect.Bottom
        then Exit;

      Inc(ShowingCount);

    end; { Shown }

    { Go to next }
    Inc(RowIndex);
  end;

end;

function TNxListGridView6.GetRowCountInPage(FromPos: Integer): Integer;
var
  Pos, i: Integer;
begin
  { Default }
  Result := 0;

  Pos := FixedRect.Top;

  for i := FromPos to Pred(RowsOwner.RowCount) do
    if RowsOwner.Showing[i] then
    begin
      Inc(Pos, RowHeight[i]);

      { Inc. Grid }
      Inc(Pos, GridSize[loBottom]);

      { Reach Limit }
      if Pos > DataRect.Bottom
        then Exit;

      Inc(Result);
    end;
end;

function TNxListGridView6.GetRowCountInPrevPage: Integer;
var
  Pos, i: Integer;
begin
  { Default }
  Result := 0;

  Pos := FixedRect.Top;

  for i := Pred(FirstIndex) downto 0 do
    if RowsOwner.Showing[i] then
    begin
      Inc(Pos, RowHeight[i]);

      { Inc. Grid }
      Inc(Pos, GridSize[loBottom]);

      { Reach Limit }
      if Pos > DataRect.Bottom
        then Exit;

      Inc(Result);
    end;
end;

function TNxListGridView6.GetRowSizeGripAtPos(X, Y: Integer): INxRow;
var
  Pos: TPoint;
  RowIndex, ShowingCount, RowHeight: Integer;
  CurrentRow: INxRow;
begin
  Result := nil;

  Pos := DataRect.TopLeft;

  { Start fixed, if exist }
  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FirstIndex;
  end;

  ShowingCount := 0;

  while RowIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[RowIndex] then
    begin
      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FirstIndex + RowIndex;
      end;

      CurrentRow := RowsOwner.Row[RowIndex];
      RowHeight := ItemHeight[RowIndex];

      { Shift Y Drawing Pos. (& Grid) }
      Inc(Pos.Y, RowHeight + GridSize[loBottom]);

      if InRange(Y, Pos.Y - spSizingTreshold, Pos.Y + spSizingTreshold) then
      begin
        Result := CurrentRow;

        { Done }
        Exit;
      end;

      if Pos.Y > DataRect.Bottom
        then Exit;

      Inc(ShowingCount);

    end; { Shown }

    { Go to next }
    Inc(RowIndex);
  end;

end;

function TNxListGridView6.GetVertClipRect: TRect;
begin
  Result := DataRect;

  if Control.IsIntegralHeight then
  begin
    Result.Bottom := FIngrealBottom;
  end;

  { Include Indicator }
  Result.Left := 0;
end;

function TNxListGridView6.GetVertPageSize: Integer;
var
  i, RowHeight: Integer;
begin
  { Default }
  Result := 0;

  FIngrealBottom := FixedRect.Top;

  for i := FirstIndex to Pred(RowCount) do
  begin
    RowHeight := ItemHeight[i];

    if FIngrealBottom + DotToPixel(RowHeight) + GridSize[loBottom] > FixedRect.Bottom
      then Exit;

    { Filtered, Collapsed, Hidden }
    if Showing[i] then
    begin
      Inc(Result);

      { Shift for Height & Grid }
      Inc(FIngrealBottom, DotToPixel(RowHeight) + GridSize[loBottom]);
    end;
  end;
end;

procedure TNxListGridView6.IndicatorMouseLeave;
begin
  { Block if already resizing }
  if not Assigned(ResizingRow)
    then ResizeReadyRow := nil;
end;

procedure TNxListGridView6.IndicatorMouseMove(Shift: TShiftState; X, Y: Integer);
begin
  if FRowResizing and not Assigned(FResizingRow) then
  begin
    ResizeReadyRow := GetRowSizeGripAtPos(X, Y);
  end;
end;

function TNxListGridView6.IsOnScreen(Index: Integer): Boolean;
begin
  Result := InRange(Index, FirstIndex, LastRowInView);
end;

procedure TNxListGridView6.KeyDown(var Key: Word; Shift: TShiftState);
{Per}
var
  HEBehaviour : TNxHomeEndBehaviour;
begin
  inherited;
  { Maybe key is pressed }
  if Assigned(FCapturedView) then
  begin
    FCapturedView := nil;
  end;

  HEBehaviour := HomeEndBehaviour;
  if ssCtrl in Shift then
  begin
    if HomeEndBehaviour = heTopBottom then
      HEBehaviour := heLeftRight
    else
      HEBehaviour := heTopBottom;
  end;

  if Control.CanKeyLeaveEdit(Key) then
    case Key of
      VK_LEFT: MoveByColumn(-1, Shift);
      VK_RIGHT: MoveByColumn(1, Shift);
      VK_UP: Control.MoveByRow(-1, Shift);
      VK_DOWN: Control.MoveByRow(1, Shift);
      VK_PRIOR: Control.MoveByPage(True, Shift);
      VK_NEXT: Control.MoveByPage(False, Shift);
      VK_HOME:
        case HEBehaviour of
          heTopBottom: Control.SelectFirst(Shift);
          heLeftRight: Control.SelectCell(FirstSelectableCol, SelectedRow, Shift);
        end;
      VK_END:
        case HEBehaviour of
          heTopBottom: Control.SelectLast(Shift);
          heLeftRight: Control.SelectCell(LastSelectableCol, SelectedRow, Shift);
        end;
      VK_TAB: Control.TabByColumn(Shift, True);
      else if not Assigned(Control.InplaceEdit) then DataKeyDown(Key, Shift);
    end;
end;

procedure TNxListGridView6.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;

  if (ssDouble in Shift) and Assigned(ResizeReadyRow) then
  begin
    Control.BestFitRow(ResizeReadyRow.Index);
  end else
  begin

    { Resizing row }
    if RowResizing then
    begin
      ResizingRow := ResizeReadyRow;
    end;

    { Moving row }
    if not Assigned(ResizingRow)
      and RowMoving then
    begin
      FMovingIndex := GetItemAtPos(X, Y);
    end;

  end;
end;

procedure TNxListGridView6.MouseLeave;
begin
  inherited;
  ResizeReadyRow := nil;
end;

procedure TNxListGridView6.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  NearestRow: INxRow;
  Index: Integer;
begin
  try
    if Assigned(MovingRow) then
    begin
      NearestRow := GetNearestRowAtPos(X, Y, MovingRow, RowMovingOptions, FMovingLocation);

      MovingTargetRow := NearestRow;

      if Assigned(MovingTargetRow) then
      begin
        if MovingRow.IsParentOf(MovingTargetRow)
          then SetScreenCursor(crNoDrop)
        else
          SetScreenCursor(crDefault);

      end;

      { Stop anything else }
      Exit;
    end;
  except
    FMovingRow := nil;
  end;

  if Assigned(ResizingRow) then
  begin
    ResizingRange := Range(ResizingRange.Min, Y);

    { Stop anything else }
    Exit;
  end;

  { User can move rows? }
  try
    if RowMoving and FMouseDown then
    begin
      Index := FMovingIndex;

      if (X < FMouseDownLocation.X - 6) or (X > FMouseDownLocation.X + 6)
        or (Y < FMouseDownLocation.Y - 6) or (Y > FMouseDownLocation.Y + 6) then
      begin
        if Index <> -1 then
        begin
          MovingRow := Row[Index];
        end;
      end;
    end;
  except
    FMovingRow := nil;
  end;

  inherited;
end;

procedure TNxListGridView6.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  NewIndex, CurIndex: Integer;
  TargetRow: INxRow;
begin
  ResizingRow := nil;

  TargetRow := MovingTargetRow;

  { Hide arrows }
  MovingTargetRow := nil;

  if Assigned(MovingRow)
    and Assigned(TargetRow)
    and (MovingRow <> TargetRow)
    and not MovingRow.IsParentOf(TargetRow) then
  begin
    CurIndex := MovingRow.Index;

    NewIndex := -1;

    if FMovingLocation <> lcInside then
    begin
      NewIndex := TargetRow.Index;

      if FMovingIndex < TargetRow.AbsoluteIndex then
      begin
        case FMovingLocation of
          lcBefore: Dec(NewIndex);
        end;
      end
      else if FMovingIndex > NewIndex then
      begin
        case FMovingLocation of
          lcAfter: Inc(NewIndex);
        end;
      end;
    end;

    if NewIndex < 0 then NewIndex := 0;

    case FMovingLocation of
      lcInside: MovingRow.ParentRow := TargetRow;
      lcAfter, lcBefore:
      begin
        MovingRow.MoveTo(TargetRow.ParentRow, NewIndex);
        RefreshData;
      end;
    end;

    { Make it selected it again }
    Control.SelectedRow := MovingRow.AbsoluteIndex;

    { Event }
    DoMoveDrop(MovingRow, TargetRow.ParentRow, CurIndex, NewIndex);
  end;

  MovingRow := nil;
  MovingTargetRow := nil;

  inherited;
end;

procedure TNxListGridView6.Paint;
begin
  inherited Paint;

  if Assigned(FMovingTargetRow) then
  begin
    PaintMovingGuides;
  end;

{$IFDEF DEBUG_INTF}
  SendDebugClear;
  SendDebugEx('FirstIndex: ' + IntToStr(FFirstIndex), mtInformation);
{$ENDIF}
end;

procedure TNxListGridView6.PaintIndicators;
var
  RowIndex, Pos, RowHeight, ShowingCount: Integer;
  IndicatorRect, ClipRect, RowsRect: TRect;
begin
  { Paint Header, InsertRow }
  inherited;

  { Default Pos }
  Pos := DataRect.Top;

  { Start from }
  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FirstIndex;
  end;

  ShowingCount := 0;

  RowsRect := Rect(0, DataRect.Top, RectWidth(Self.IndicatorRect), DataRect.Bottom);

  while RowIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[RowIndex] then
    begin
      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FirstIndex + RowIndex;
      end;

      RowHeight := ItemHeight[RowIndex];

      IndicatorRect := Bounds(0, Pos, RectWidth(Self.IndicatorRect), RowHeight + ItemGridSize[loBottom]);

      ClipRect := IndicatorRect;

      IntersectRect(ClipRect, ClipRect, RowsRect);

      SetClipRect(Canvas, ClipRect);

      { Paint Elem. }
      StylePaint.PaintIndicator(IndicatorRect, ilRow, RowIndex = Control.SelectedLocation.Y, Control.Selected[RowIndex]);

      { Shift Pos (& Grid) }
      Inc(Pos, RectHeight(IndicatorRect));

      { Done }
      if Pos > DataRect.Bottom
        then Break;

      { One more visible }
      Inc(ShowingCount);
    end;

    { Go to next }
    Inc(RowIndex);
  end;

  { Non-active Rows }
  while Pos < DataRect.Bottom do
  begin
    IndicatorRect := Bounds(0, Pos, RectWidth(Self.IndicatorRect), DotToPixel(ItemDefaultHeight) + ItemGridSize[loBottom]);

    ClipRect := IndicatorRect;

    IntersectRect(ClipRect, ClipRect, RowsRect);

    SetClipRect(Canvas, ClipRect);

    { Paint Elem. }
    StylePaint.PaintIndicator(IndicatorRect, ilRow, False, False);

    { Shift Pos (& Grid) }
    Inc(Pos, RectHeight(IndicatorRect));

    SetClipRect(Canvas, ClientRect);
  end;

end;

procedure TNxListGridView6.PaintMovingGuides;
var
  InsideRect: TRect;
  X, Y: Integer;
begin
  if Assigned(FMovingTargetRow) then
  begin

    Y := 0;
    if FMovingLocation = lcBefore then Y := FMovingRect.Top - GridSize[loBottom];
    if FMovingLocation = lcAfter then Y := FMovingRect.Bottom;

    if FMovingLocation = lcNone then ShowMessage('Error moving rows');

    if FMovingLocation = lcInside then
    begin

      with Canvas do
      begin
        Pen.Color := clRed;
        Brush.Color := clRed;

        InsideRect := FMovingRect;
        FrameRect(InsideRect);
        InflateRect(InsideRect, -1, -1);
        FrameRect(InsideRect);
      end;

    end else
    begin
      with Canvas do
      begin
        Pen.Color := clRed;
        Brush.Color := clRed;
        X := DataRect.Left;
        Polygon([
          Point(X, Y - 2),
          Point(X + 2, Y - 2),
          Point(X + 2, Y - 5),
          Point(X + 7, Y),
          Point(X + 2, Y + 5),
          Point(X + 2, Y + 2),
          Point(X, Y + 2),
          Point(X, Y - 2)]);
        X := FMovingRect.Right - 1;
        Polygon([
          Point(X, Y - 2),
          Point(X - 2, Y - 2),
          Point(X - 2, Y - 5),
          Point(X - 7, Y),
          Point(X - 2, Y + 5),
          Point(X - 2, Y + 2),
          Point(X, Y + 2),
          Point(X, Y - 2)]);
        Polyline([Point(DataRect.Left + 8, Y), Point(X - 7, Y)]);
      end;

    end;
  end;

end;

procedure TNxListGridView6.RefreshIndicator(Index: Integer);
var
  InvalidationRect: TRect;
begin
  if Control.RowExists(Index) then
  begin
    InvalidationRect := Bounds(0, GetItemTop(Index), RectWidth(IndicatorRect), ItemHeight[Index]);

    { Refresh }
    Invalidate(InvalidationRect);
  end;
end;

procedure TNxListGridView6.Reset;
begin
  inherited Reset;

  { ToDo: Should be first visible, not 0 }
  FFirstIndex := 0;

  Columns.ClientWidth := DataRect.Right - DataRect.Left;
end;

procedure TNxListGridView6.ResizeBy(DeltaX, DeltaY: Integer);
var
  i: Integer;
begin
  if DeltaY > 0 then
    for i := Pred(FirstIndex) downto 0 do
      if RowsOwner.Showing[i] then
        if DeltaY > ItemHeight[i] then
        begin
          VertScrollBar.Prior;

          Dec(DeltaY, ItemHeight[i] + ItemGridSize[loBottom]);
        end
        else Break;

  if DeltaX > 0 then
  begin
    HorzScrollBar.MoveBy(-DeltaX);
  end;

  Columns.ClientWidth := DataRect.Right - DataRect.Left;

  if Columns.FlexibleWidth <> 0 then
  begin
    Columns.UpdateAutoSizes;
    Invalidate;
  end;
end;

procedure TNxListGridView6.ScrollContentBy(DeltaX, DeltaY: Integer);
var
  PixelDeltaX, PixelDeltaY: Integer;
begin
  PixelDeltaY := 0;

  while DeltaY <> 0 do
    if DeltaY > 0 then { Scroll Down }
    begin

      if RowsOwner.Showing[FirstIndex] then
      begin
        Dec(PixelDeltaY, MulDiv(FullRowHeight[FFirstIndex], Screen.PixelsPerInch, 96));

        { Inc. Grid }
        Dec(PixelDeltaY, GridSize[loBottom]);

        Dec(DeltaY);
      end;

      Inc(FFirstIndex);

    end else if DeltaY < 0 then { Scroll Up }
    begin
      Dec(FFirstIndex);

      if FFirstIndex < 0 then
      begin
        ShowMessage('Error: ' + IntToStr(FFirstIndex));
      end;

      if RowsOwner.Showing[FirstIndex] then
      begin
        Inc(PixelDeltaY, MulDiv(FullRowHeight[FirstIndex], Screen.PixelsPerInch, 96));

        { Inc. Grid }
        Inc(PixelDeltaY, GridSize[loBottom]);

        Inc(DeltaY);
      end;
    end;

  PixelDeltaX := -DeltaX;

  if PixelDeltaX <> 0 then
  begin
    ScrollRect(PixelDeltaX, 0, GetHorzClipRect, GetHorzClipRect);
  end;

  if PixelDeltaY <> 0 then
  begin
    ScrollRect(0, PixelDeltaY, GetVertClipRect, GetVertClipRect);
  end;

  { Update CapturedView }
  inherited;
end;

procedure TNxListGridView6.ScrollToRow(Index: Integer);
var
  Delta,Pos, i: Integer;
begin
  Delta := 0; { Default }

  { ToDo: Check invisible fixed rows }

  if (Index >= FixedRowCount) and (Index < RowsOwner.RowCount) then
  begin

    if Index > LastRowInPage then
    begin
      Pos := GetItemRect(Index).Bottom;

      for i := FirstIndex + FixedRowCount to Pred(Index) do
        if RowsOwner.Showing[i] then
        begin
          Dec(Pos, ItemHeight[i]);

          { Inc. Grid }
          Dec(Pos, ItemGridSize[loBottom]);

          Inc(Delta);
          if Pos < DataRect.Bottom then Break;
        end;

      Control.VertScrollBar.MoveBy(Delta);

    end else if Index < FirstIndex + FixedRowCount then
    begin
      Delta := Control.GetRowsBetween(Index, FirstIndex);
      Control.VertScrollBar.MoveBy(-Delta);
    end;
  end;
end;

procedure TNxListGridView6.SetMovingRow(const Value: INxRow);
begin
  FMovingRow := Value;
end;

procedure TNxListGridView6.SetMovingTargetRow(const Value: INxRow);
var
  Right: Integer;
begin
  if (Value <> FMovingTargetRow) or
    (FMovingLocation <> FOldMovingLocation) then
  begin
    FMovingTargetRow := Value;

    Invalidate(FOldMovingRect);

    if Assigned(FMovingTargetRow) then
    begin
      Right := DataRect.Left + Columns.VisibleWidth;

      FMovingRect := GetItemRect(FMovingTargetRow.AbsoluteIndex);
      FMovingRect.Right := Right;

      case FMovingLocation of
        lcBefore: FOldMovingRect := Bounds(0, FMovingRect.Top - 6, Right, 11);
        lcAfter:  FOldMovingRect := Bounds(0, FMovingRect.Bottom - 5, Right, 11);
        lcInside: FOldMovingRect := FMovingRect;
      end;

      Invalidate(FOldMovingRect);
    end;

    FOldMovingLocation := FMovingLocation;
  end;
end;

procedure TNxListGridView6.SetResizeReadyRow(const Value: INxRow);
begin
  if Value <> FResizeReadyRow then
  begin
    FResizeReadyRow := Value;

    if Assigned(FResizeReadyRow) then
    begin
      SetScreenCursor(crSizeNS);
    end
    else SetScreenCursor(crDefault);
  end;
end;

procedure TNxListGridView6.SetResizingRange(const Value: TRange);
var
  AMax: Integer;
begin
  AMax := Value.Max;

  if Value.Max - Value.Min < 8 then
  begin
    AMax := Value.Min + 8;
  end;

  { Earase first }
  with Canvas do
    try
      Pen.Mode := pmNot;
      Polyline([
        Point(0, FResizingRange.Max),
        Point(ClientRect.Right, FResizingRange.Max)
      ]);
    finally
      Pen.Mode := pmCopy;
    end;

  { Assign }
  FResizingRange := Value;
  FResizingRange.Max := AMax;

  { Paint }
  with Canvas do
    try
      Pen.Mode := pmNot;
      Polyline([
        Point(0, FResizingRange.Max),
        Point(ClientRect.Right, FResizingRange.Max)
      ]);
    finally
      Pen.Mode := pmCopy;
    end;

end;

procedure TNxListGridView6.SetResizingRow(const Value: INxRow);
var
  r: TRect;
  Delta: Integer;
begin
  if Value <> FResizingRow then
  begin

    { Button released? }
    if not Assigned(Value) then
    begin
      { Delta need to be converted back to logical Points }
      Delta := (ResizingRange.Max - ResizingRange.Min) div (Screen.PixelsPerInch div 96);

      case RowResizingOptions of
        roResizeSingleRow: FResizingRow.Height := Delta;
        roResizeAllRows: Control.ChangeRowHeight(Delta);
      end;

      { Hide }
      with Canvas do
        try
          Pen.Mode := pmNot;
          Polyline([
            Point(0, FResizingRange.Min),
            Point(ClientRect.Right, FResizingRange.Min)
          ]);
          Polyline([
            Point(0, FResizingRange.Max),
            Point(ClientRect.Right, FResizingRange.Max)
          ]);
        finally
          Pen.Mode := pmCopy;
        end;
    end;

    { Assign value }
    FResizingRow := Value;

    if Assigned(FResizingRow) then
    begin
      r := GetItemRect(FResizingRow.Index);

      with Canvas do
        try
          Pen.Mode := pmNot;
          Polyline([
            Point(0, r.Top),
            Point(ClientRect.Right, r.Top)
          ]);
          Polyline([
            Point(0, r.Bottom),
            Point(ClientRect.Right, r.Bottom)
          ]);
        finally
          Pen.Mode := pmCopy;
        end;

      FResizingRange := Range(r.Top, r.Bottom);
    end
    else
      FResizingRange := EmptyRange;

  end;
end;

procedure TNxListGridView6.ShiftContentBy(DeltaX, DeltaY: Integer;
  Index: Integer);
var
  ClipRect, InvalidationRect: TRect;
begin
  ClipRect := DataRect;

  { Include indicator }
  ClipRect.Left := 0;

  InvalidationRect := DataRect;
  InvalidationRect.Top := GetItemTop(Index);

  ScrollRect(DeltaX, DeltaY, InvalidationRect, ClipRect);
end;

procedure TNxListGridView6.DoRowAppear(Index, Height: Integer; Appear,
  Delete: Boolean);
var
  InvalidationRect: TRect;
  Delta: Integer;

  function GetLastFixedRow: Integer;
  var
    i: Integer;
  begin
    Result := -1;

    for i := 0 to RowsOwner.RowCount - 1 do
      if RowsOwner.Showing[i] then
      begin
        Inc(Result);
        if Result = FFixedRowCount then Exit;
      end;
  end;

begin
  InvalidationRect := FixedRect;

  { Include Indicator }
  InvalidationRect.Left := 0;

  { Row is fixed }
  if Index < FixedRowCount then
  begin

    { Scroll is Repaint too }
    if Control.CanUpdate([uoRepaint]) then
    begin
      InvalidationRect.Top := GetItemTop(Index);

      { Within fixed area }
      InvalidationRect.Bottom := FixedRect.Top;

      Delta := 0 - Height - ItemGridSize[loBottom];

      if Appear then Delta := Abs(Delta);

      { Do Scroll }
      ScrollRect(0, Delta, InvalidationRect, InvalidationRect);
    end;

    { Scroll non-fixed area }
    if VertScrollBar.IsFirst and (RowsOwner.GetShowingCount > 0) then
    begin

      Height := ItemHeight[FFirstIndex];

      Delta := -(Height + ItemGridSize[loBottom]);

      { Scroll is Repaint too }
      if Control.CanUpdate([uoRepaint]) then
      begin
        InvalidationRect := FixedRect;
        ScrollRect(0, Delta, InvalidationRect, InvalidationRect);
      end;

    end;

  end else
  begin
    { No visible Rows }
    if RowsOwner.GetShowingCount = 0 then
    begin
      FFirstIndex := 0;

      { Scroll is Repaint too }
      if Control.CanUpdate([uoRepaint]) then
      begin
        InvalidationRect.Top := GetItemTop(Index);
        Delta := 0 - Height - ItemGridSize[loBottom];

        { Do Scroll }
        ScrollRect(0, Delta, InvalidationRect, InvalidationRect);
      end;
    end;

    { It is first }
    if Index = FirstIndex then
    begin

      if Appear then Delta := Height + GridSize[loBottom] else
      begin

        if not VertScrollBar.IsLast then
        begin
          if RowCount > 0 then
            while (FirstIndex < Pred(RowCount)) and not Showing[FirstIndex]
              do Inc(FFirstIndex);
          { Bn: If row is last, Pos will be larger than Max,
                and pos will be moved and scrolled back }
        end;

        if Control.CanUpdate([uoScrollBar])
          and VertScrollBar.IsLast
            then VertScrollBar.MoveBy(-1);

        Delta := -(Height + ItemGridSize[loBottom]);
      end;

      { Scroll is Repaint too }
      if Control.CanUpdate([uoRepaint]) then
      begin
        ScrollRect(0, Delta, InvalidationRect, InvalidationRect);
      end;

    end

    { After first }
    else if Index > FirstIndex then
    begin

      if Control.CanUpdate([uoRepaint]) then
      begin
        InvalidationRect.Top := GetItemTop(Index);

        Delta := Height + ItemGridSize[loBottom];
        if not Appear then Delta := -Delta;

        ScrollRect(0, Delta, InvalidationRect, InvalidationRect);
      end;

      if Control.CanUpdate([uoScrollBar])
        and VertScrollBar.IsLast then VertScrollBar.MoveBy(-1);

    end

    { Before first }
    else if Index < FirstIndex then
    begin

      { Insert or Delete? }
      if Delete then
        case Appear of
          True: Inc(FFirstIndex);
          False: Dec(FFirstIndex);
        end;

      { ScrollBar at Top? }
      if VertScrollBar.IsFirst then
      begin

        { Scroll is Repaint too }
        if Control.CanUpdate([uoRepaint])
          and Appear then
        begin
          FFirstIndex := Index;
          Delta := Height + ItemGridSize[loBottom];

          ScrollRect(0, Delta, InvalidationRect, InvalidationRect);
        end;

      end else
      begin

        if Control.CanUpdate([uoScrollBar]) then
          try
            { Update bar (silently), but don't scroll }
            VertScrollBar.Lock;

            if Appear then VertScrollBar.MoveBy(1) else
            begin

              { Hide }
              if VertScrollBar.IsLast
                then VertScrollBar.MoveBy(1)
                else VertScrollBar.MoveBy(-1);

            end;

          finally
            VertScrollBar.Unlock(False);
          end;

      end; { if IsFirst }

    end;

  end; { Fixed }

  VertScrollBar.SetValues(Pred(RowsOwner.GetShowingCount), GetVertPageSize);

  { No more same View }
  Changed;
end;

{ TNxReportGridView6 }

constructor TNxReportGridView6.Create(AOwner: TComponent);
begin
  inherited;
  FDetailsColumn := nil;
  FDetailsRowHeight := 16;
  FDetailsRowStyle := dsHidden;
  FColorOverflowInactiveCells := True;
end;

function TNxReportGridView6.GetCellAtPos(Location: TPoint): TPoint;
var
  ColIndex, RowIndex, i, ShowingCount, RowHeightScaled, CellLeft: Integer;
  CurrentRow: INxRow;
  CurrentColumn: TNxColumn6;
  CellTopLeft: TPoint;
  CellRect: TRect;
begin
  Result := EmptyPoint;

  if ShowInsertRow and PtInRect(InsertRowRect, Location) then
  begin
    Result := Point(GetColumnAt(Location.X, Location.Y, gaHeader).Index, -1);

    Exit;
  end;

  { Top-left Corner }
  CellTopLeft := DataRect.TopLeft;

  { Start fixed, if exist }
  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FFirstIndex;
  end;

  ShowingCount := 0;

  while RowIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[RowIndex] then
    begin

      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FFirstIndex + RowIndex;
      end;

      CurrentRow := RowsOwner.Row[RowIndex];

      RowHeightScaled := MulDiv(Self.RowHeight[RowIndex], Screen.PixelsPerInch, 96);

      { Reset X Position }
      CellTopLeft.X := DataRect.Left;

      for i := 0 to Pred(Columns.Count) do
      begin
        if i = FFixedColCount
          then Dec(CellTopLeft.X, Offset.cx);

        CurrentColumn := Columns.PositionItem[i];

        if CurrentColumn.Visible then
        begin

          ColIndex := CurrentColumn.Index;

          if Cell[ColIndex, RowIndex].Visible then
          begin

            CellLeft := CellTopLeft.X;
            Dec(CellLeft, GetCellLeft(ColIndex, RowIndex));

            CellRect := Bounds(CellLeft, CellTopLeft.Y, GetCellWidth(ColIndex, RowIndex), RowHeightScaled);

            { Incl. Bottom Grid, it is also clickable }
            Inc(CellRect.Bottom, GridSize[loBottom]);

            if PtInRect(CellRect, Location) then
            begin
              Result := Point(ColIndex, RowIndex);

              Exit; { Done }
            end;
          end;

          { Shift X Pos. }
          Inc(CellTopLeft.X, MulDiv(CurrentColumn.Width, Screen.PixelsPerInch, 96));
        end;

      end;

      if Control.IsIntegralHeight
        and (CellTopLeft.Y + RowHeightScaled + GridSize[loBottom] > DataRect.Bottom)
          then Break;

      { Shift Y Drawing Pos. (& Grid) }
      Inc(CellTopLeft.Y, RowHeightScaled + GridSize[loBottom]);

      { Details }
      if HasDetailsRow(RowIndex)
        then Inc(CellTopLeft.Y, DetailsRowHeight + GridSize[loBottom]);

      if CellTopLeft.Y > DataRect.Bottom
        then Exit;

      Inc(ShowingCount);
    end; { Shown }

    Inc(RowIndex);

    if not Control.RowPersist(RowIndex)
      then Exit;
  end;
end;

function TNxReportGridView6.GetCellLeft(const ACol, ARow: Integer): Integer;
var
  i, Index: Integer;
begin
  Result := 0;
  for i := Pred(Columns[ACol].Position) downto 0 do
  begin
    Index := Columns.PositionItem[i].Index;
    if Columns.PositionItem[i].Visible then
    begin
      if CellVisible[Index, ARow] then
      begin
        //FIXME:
        Result := 0;
        Exit;
      end;
      Inc(Result, MulDiv(Columns.PositionItem[i].Width, Screen.PixelsPerInch, 96));
    end;
  end;
end;

function TNxReportGridView6.GetCellRect(ACol, ARow: Integer): TRect;
var
  RowIndex, ShowingCount, RowHeight, CellWidth, CellLeft: Integer;
  CurrentRow: INxRow;
  DrawPos: TPoint;


begin
  { ToDo: Big optimization !!}

  { Top-left Corner }
  DrawPos := DataRect.TopLeft;

  { Start fixed, if exist }
  RowIndex := 0;
  if FixedRowCount = 0 then
  begin
    RowIndex := FFirstIndex;
  end;

  ShowingCount := 0;

  while RowIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[RowIndex] then
    begin

      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FFirstIndex + RowIndex;
      end;

      CurrentRow := RowsOwner.Row[RowIndex];

      RowHeight := MulDiv(Self.RowHeight[RowIndex], Screen.PixelsPerInch, 96);

      if RowIndex = ARow then
      begin

        with Columns[ACol] do
        begin
          DrawPos.X := Left + DataRect.Left;

          CellLeft := GetCellLeft(ACol, RowIndex);
          Dec(DrawPos.X, CellLeft);

          { ScrollBar Shift }
          if VisibleIndex >= FFixedColCount
            then Dec(DrawPos.X, Offset.cx);

          CellWidth := GetCellWidth(ACol, RowIndex);

          Result := Bounds(DrawPos.X, DrawPos.Y, CellWidth - GridSize[loRight], RowHeight);

          { Done }
          Exit;
        end;
      end;

      if Control.IsIntegralHeight
        and (DrawPos.Y + RowHeight + GridSize[loBottom] > DataRect.Bottom)
          then Break;

      { Shift Y Drawing Pos. }
      Inc(DrawPos.Y, RowHeight + GridSize[loBottom]);

      { Also Shift Y for Details Row }
      if HasDetailsRow(RowIndex) then
        Inc(DrawPos.Y, DetailsRowHeight + GridSize[loBottom]);

      if DrawPos.Y > DataRect.Bottom
        then Exit;

      Inc(ShowingCount);

    end; { if Showing }

    Inc(RowIndex);
  end;
end;

/// <summary>
///  Gets width of a cell in pixels.
/// </summary>
function TNxReportGridView6.GetCellWidth(const ACol, ARow: Integer): Integer;
var
  i, Index: Integer;
  Column: TNxColumn6;
begin
  Result := Columns[ACol].Width;
  for i := Succ(Columns[ACol].Position) to Pred(Columns.Count) do
  begin
    Column := Columns.PositionItem[i];
    if Column.Visible then
    begin
      Index := Column.Index;
      if Cell[Index, ARow].Visible then Break;
      Inc(Result, Column.Width);
    end;
  end;
  Inc(Result, GetCellLeft(ACol, ARow));
  Result := MulDiv(Result, Screen.PixelsPerInch, 96);
end;

/// <summary>
///  Gets DataRect without unused space on the right.
/// </summary>
function TNxReportGridView6.GetClientDataRect: TRect;
begin
  Result := inherited GetClientDataRect;

  { Exclude unusable spece on the right }
  Result.Right := DataRect.Left + MulDiv(Columns.VisibleWidth, Screen.PixelsPerInch, 96) - Control.HorzScrollBar.Position;
end;

function TNxReportGridView6.GetFirstColInView: Integer;
var
  Shift, i, X: Integer;
  Column: TNxColumn6;
begin
  Result := 0;

  { Start }
  //Shift := DataRect.Left;

  for i := 0 to Pred(Columns.Count) do
  begin
    Shift := DataRect.Left;

    { ScrollBar Shift }
    if i >= FixedColCount
      then Dec(Shift, Offset.cx);

    Column := Columns.PositionItem[i];

    if Column.Visible then
    begin
      X := Column.Left + Shift;

      if X + Column.Width >= DataRect.Left then
      begin
        Result := i;
        Exit;
      end;

      if X > ClientRect.Right
        then Exit;
    end;
  end;
end;

function TNxReportGridView6.GetFullRowHeight(Index: Integer): Integer;
begin
  Result := inherited GetFullRowHeight(Index);
  if HasDetailsRow(Index)
    then Inc(Result, DetailsRowHeight + GridSize[loBottom]);
end;

function TNxReportGridView6.GetGridIncludedRect(CellRect: TRect): TRect;
begin
  Result := CellRect;
  with Result do
  begin
    Inc(Right, GridSize[loRight]);
    Inc(Bottom, GridSize[loBottom]);
  end;
end;

function TNxReportGridView6.GetHorzMax: Integer;
begin
  Result := DotToPixel(Columns.VisibleWidth);
end;

function TNxReportGridView6.GetItemDefaultHeight: Integer;
begin
  Result := Control.RowHeight;
end;

function TNxReportGridView6.GetItemGridSize(Location: TNxLocation): Integer;
begin
  Result := GridSize[Location];
end;

function TNxReportGridView6.GetItemHeight(Index: Integer): Integer;
begin
  Result := MulDiv(RowHeight[Index], Screen.PixelsPerInch, 96);
end;

function TNxReportGridView6.GetVertClipRect: TRect;
begin
  Result := inherited GetVertClipRect;

  Inc(Result.Top, FixedHeight);
end;

function TNxReportGridView6.GetVertPageSize: Integer;
var
  i, RowHeight: Integer;
  CurrRow: INxRow;
begin
  { Default }
  Result := 0;

  FIngrealBottom := FixedRect.Top;

  for i := FirstIndex to Pred(RowCount) do
  begin
    CurrRow := Row[i];

    RowHeight := ItemHeight[i];

    if HasDetailsRow(i) then
      Inc(RowHeight, DetailsRowHeight + GridSize[loBottom]);

    if FIngrealBottom + RowHeight + GridSize[loBottom] > FixedRect.Bottom
      then Exit;

    { Filtered, Collapsed, Hidden }
    if Showing[i] then
    begin
      Inc(Result);

      { Shift for Height & Grid }
      Inc(FIngrealBottom, RowHeight + GridSize[loBottom]);
    end;
  end;
end;

function TNxReportGridView6.HasDetailsRow(const ARow: Integer): Boolean;
begin
  Result := (DetailsRowStyle = dsAlwaysShown) and Assigned(DetailsColumn);
end;

procedure TNxReportGridView6.Paint;
begin
  inherited Paint;
end;

procedure TNxReportGridView6.PaintCells;
var
  CellPoint: TPoint;
  CellSize: TSize;

  i, RowIndex, ColIndex, ShowingCount, VisibleRowIndex: Integer;

  CurrentRow: INxRow;
  CurrentColumn, MeasuringColumn: TNxColumn6;

  CellRect, ClipSrc, ClipDst: TRect;
  CellColor: TColor;
  CellState: TNxCellPaintingState;
begin
  inherited;
  CellPoint := DataRect.TopLeft;

  { Start fixed, if > 0 }
  if FixedRowCount > 0
    then RowIndex := 0
    else RowIndex := FFirstIndex;

  ShowingCount := 0;
  VisibleRowIndex := RowIndex;

  while RowIndex < RowsOwner.RowCount do
  begin
    { NextDBGrid6 locate record }
//    RowsOwner.SetActiveRow(RowIndex);

    if RowsOwner.Showing[RowIndex] then
    begin
      Inc(VisibleRowIndex);

      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShowingCount = FFixedRowCount then RowIndex := FFirstIndex + RowIndex;
      end;

      { Reset for each Row }
      CurrentRow := RowsOwner.Row[RowIndex];

      CellPoint.X := DataRect.Left;

      CellSize.cx := 0;
      CellSize.cy := MulDiv(Self.RowHeight[RowIndex], Screen.PixelsPerInch, 96);

      MeasuringColumn := nil;

      for i := 0 to Pred(Columns.Count) do
      begin
        CurrentColumn := Columns.PositionItem[i];

        //Shift was here before

        if CurrentColumn.Visible then
        begin
          ColIndex := CurrentColumn.Index;

          if CellVisible[ColIndex, RowIndex] then
          begin

            if not Assigned(MeasuringColumn) then
            begin
              MeasuringColumn := CurrentColumn;

              Inc(CellSize.cx, MulDiv(CurrentColumn.Width, Screen.PixelsPerInch, 96));
            end else
            begin
              { Paint Previous }
              CellRect := Bounds(CellPoint.X, CellPoint.Y, CellSize.cx, CellSize.cy);

              PreparePaintCell(MeasuringColumn.Index, RowIndex, MeasuringColumn.VisibleIndex, VisibleRowIndex, CellRect);

              MeasuringColumn := CurrentColumn;

              { Shift X drawing position }
              Inc(CellPoint.X, CellSize.cx);

              CellSize.cx := MulDiv(CurrentColumn.Width, Screen.PixelsPerInch, 96);
            end;

          end else
          begin
            Inc(CellSize.cx, MulDiv(CurrentColumn.Width, Screen.PixelsPerInch, 96));
          end; { if CellVisible }

        end; { if CurrentCol.Visible }

        { Start ScrollBar offset }
        if CurrentColumn.VisibleIndex = FixedColCount
          then Dec(CellPoint.X, Offset.cx);

      end; { for i }

      { Last one visible }
      if Assigned(MeasuringColumn) then
      begin
        CellRect := Bounds(CellPoint.X, CellPoint.Y, CellSize.cx, CellSize.cy);

        PreparePaintCell(MeasuringColumn.Index, RowIndex, MeasuringColumn.VisibleIndex, VisibleRowIndex, CellRect);
      end;

      if Control.IsIntegralHeight
        and (CellPoint.Y + CellSize.cy + GridSize[loBottom] > DataRect.Bottom)
          then Break;

      { Shift Y for next row }
      Inc(CellPoint.Y, CellSize.cy + GridSize[loBottom]);

      { Details Row }
      if HasDetailsRow(RowIndex) then
      begin
        CellRect := Bounds(DataRect.Left - Offset.cx, CellPoint.Y, Columns.VisibleWidth, DetailsRowHeight);
        Canvas.Brush.Color := clYellow;
        Canvas.FillRect(CellRect);
        PreparePaintCell(DetailsColumn.Index, RowIndex, 0, 0, CellRect);
        Inc(CellPoint.Y, DetailsRowHeight + GridSize[loBottom]);
      end;

      { Note: Calling Exit instead of Break
              will skip fill right space part. }
      if CellPoint.Y > DataRect.Bottom
        then Break;

      Inc(ShowingCount);

    end; { if Showing }

    Inc(RowIndex);

    { Used for DbGrid and BufferCount }
    if not Control.RowPersist(RowIndex)
      then Break;
  end;

  { Paint out-of-scope cells }
  while CellPoint.Y < DataRect.Bottom do
  begin
    Inc(VisibleRowIndex);

    CellPoint.X := DataRect.Left;

    for ColIndex := 0 to Pred(Columns.Count) do
    begin

      CurrentColumn := Columns.PositionItem[ColIndex];

      { Start ScrollBar offset }
      if CurrentColumn.VisibleIndex = FixedColCount
        then Dec(CellPoint.X, Offset.cx);

      if CurrentColumn.Visible then
      begin
        CellRect := Bounds(CellPoint.X, CellPoint.Y,
          MulDiv(CurrentColumn.Width, Screen.PixelsPerInch, 96),
          MulDiv(Control.RowHeight, Screen.PixelsPerInch, 96));

        { Exclude Grid from Rect }
        Dec(CellRect.Right, IfThen(GridLinesStyle = glActiveOnly, 0, GridSize[loRight]));

        { Inside Invalidation rect ? }
        if RectVisible(Canvas.Handle, CellRect) then
        begin
          ClipSrc := CellRect;
          ClipDst := Self.DataRect;

          if CurrentColumn.VisibleIndex >= FFixedColCount then
          begin
            ClipDst.Left := FixedRect.Left;
          end;

          { Intersection of ClipSrc & ClipDsy -> ClipSrc }
          IntersectRect(ClipSrc, ClipSrc, ClipDst);

          try
            SetClipRect(Canvas, ClipSrc);

            CellColor := Control.Color;
            if ColorOverflowInactiveCells then
            begin
              CellColor := CurrentColumn.Color;
            end;

            if (aoAlternatingRowColors in Control.AppearanceOptions)
              and (Control.GetAlternatingRowColorOptions.IncludeInactiveRows) then
            begin
              if VisibleRowIndex mod 2 = 0 then
                CellColor := Control.AlternatingRowColor;
            end;

            CellState := [];

            { Trigger event }
            DoGetCellColor(ColIndex, RowIndex, CellColor, CellState);

            { Paint Cell }
            with Canvas do
            begin
              Brush.Color := CellColor;
              FillRect(CellRect);
            end;

          finally
            SetClipRect(Canvas, ClientRect);
          end;

          { Paint Grid }
          if GridLines
            and not (GridLinesStyle = glActiveOnly) then
          begin
            { ToDo: CellColoring event }
            PaintGrid(ColIndex, RowIndex, CellRect, ColorEdges(GridLinesColor), CellState);
          end;

        end;

        { Shift X Drawing Pos. }
        Inc(CellPoint.X, MulDiv(CurrentColumn.Width, Screen.PixelsPerInch, 96));
      end;

    end; { for }

    { Shift Y Drawing Pos. }
    Inc(CellPoint.Y, MulDiv(Control.RowHeight, Screen.PixelsPerInch, 96));

    if GridLinesStyle <> glActiveOnly
      then Inc(CellPoint.Y, GridSize[loBottom]);

    { Go to next }
    Inc(RowIndex);
  end;

  { Fill space left horizontaly }
  with Canvas do
  begin
    Brush.Color := Control.Color;
    FillRect(Rect(ClientDataRect.Right, DataRect.Top, ClientRect.Right, ClientRect.Bottom));
  end;
end;

procedure TNxReportGridView6.PreparePaintCell(ACol, ARow, AColVisibleIndex, ARowVisibleIndex: Integer;
  ACellRect: TRect);
var
  CellState: TNxCellPaintingState;
  ClipSrc, ClipDst: TRect;
begin
  { Exclude Grid from Rect }
  Dec(ACellRect.Right, GridSize[loRight]);

  { Inside Invalidation rect ? }
  if RectVisible(Canvas.Handle, ACellRect) then
  begin
    ClipSrc := ACellRect;
    ClipDst := Self.DataRect;

    if AColVisibleIndex >= FFixedColCount then
    begin
      ClipDst.Left := FixedRect.Left;
    end;

    { Intersection of ClipSrc & ClipDsy -> ClipSrc }
    IntersectRect(ClipSrc, ClipSrc, ClipDst);

    try
      SetClipRect(Canvas, ClipSrc);

      { Paint Cell }
      PaintCell(ACol, ARow, ARowVisibleIndex, ACellRect);

      if GridLines then
      begin
        SetClipRect(Canvas, GetGridIncludedRect(ClipSrc));

        PaintGrid(ACol, ARow, ACellRect, ColorEdges(GridLinesColor), CellState);
      end;

    finally
      SetClipRect(Canvas, ClientRect);
    end;

  end; { if RectVisible }
end;

procedure TNxReportGridView6.RefreshRow(Index: Integer);
var
  InvalidationRect: TRect;
begin
  { Should repaint? }
  if IsOnScreen(Index) then
  begin
    InvalidationRect := GetItemRect(Index);

    if RectIntersect(InvalidationRect, DataRect) then
    begin
      { Invalidate Rect }
      Invalidate(InvalidationRect);
    end;
  end;
end;

procedure TNxReportGridView6.RefreshColumn(Column: TNxColumn6; Area: TNxGridArea);
var
  InvalidationRect: TRect;
  Shift, ScaledWidth: Integer;
begin
  Shift := DataRect.Left;

  { ScrollBar Shift }
  if Column.VisibleIndex >= FFixedColCount then
    Dec(Shift, HorzScrollBar.Position);

  ScaledWidth := MulDiv(Column.Width, Screen.PixelsPerInch, 96);

  InvalidationRect := Bounds(Column.Left + Shift, 0, ScaledWidth, ClientHeight);

  Invalidate(InvalidationRect);

  case Area of
    gaAll: ;
    gaBody:
    begin
      InvalidationRect.Top := DataRect.Top;
      InvalidationRect.Bottom := DataRect.Bottom;
    end
    else inherited;
  end;
end;

procedure TNxReportGridView6.RefreshRow(FromPos, ToPos: Integer);
var
  InvalidationRect: TRect;
  i: Integer;
begin
  InvalidationRect := GetItemRect(FromPos);

  if ShowIndicator then
  begin
    { Note: Right is anchored }
    InvalidationRect.Left := 0;
  end;

  for i := FromPos to ToPos do
    if RowsOwner.Showing[i] then
    begin
      Inc(InvalidationRect.Bottom, RowHeight[i] + GridSize[loBottom]);

      { Stop Process. }
      if InvalidationRect.Bottom > DataRect.Bottom
        then Break;
    end;

  if RectIntersect(InvalidationRect, DataRect) then
  begin
    { Invalidate Rect }
    Invalidate(InvalidationRect);
  end;
end;

procedure TNxReportGridView6.ScrollToCol(Index: Integer);
var
  Column: TNxColumn6;
  Left, Delta: Integer;
begin
  Column := Columns[Index];

  { Should scroll? }
  { ToDo: VisibleIndex property }
  if Column.Position >= FFixedColCount then
  begin
    Left := DataRect.Left + Column.Left;

    { ScrollBar offset }
    Dec(Left, Offset.cx);

    if (Left < FixedRect.Left)
      or (Column.Width > FixedRect.Right - FixedRect.Left) then
    begin
      Delta := Left - FixedRect.Left;
      HorzScrollBar.MoveBy(Delta);
    end
    else if Left + Column.Width > FixedRect.Right then
    begin
      Delta := (Left + Column.Width) - FixedRect.Right;
      HorzScrollBar.MoveBy(Delta);
    end;

  end;
end;

procedure TNxReportGridView6.SetColorOverflowInactiveCells(const Value: Boolean);
begin
  if Value <> FColorOverflowInactiveCells then
  begin
    FColorOverflowInactiveCells := Value;
    Invalidate;
  end;
end;

procedure TNxReportGridView6.SetDetailsColumn(const Value: TNxColumn6);
begin
  if Value <> FDetailsColumn then
  begin
    FDetailsColumn := Value;
    Control.UpdateScrollBars;
    Invalidate;
  end;
end;

procedure TNxReportGridView6.SetDetailsRowHeight(const Value: Integer);
begin
  if Value <> FDetailsRowHeight then
  begin
    FDetailsRowHeight := Value;
    Control.UpdateScrollBars;
    Invalidate;
  end;
end;

procedure TNxReportGridView6.SetDetailsRowStyle(
  const Value: TNxDetailsRowStyle);
begin
  if Value <> FDetailsRowStyle then
  begin
    FDetailsRowStyle := Value;
    Control.UpdateScrollBars;
    Invalidate;
  end;
end;

{ TNxSlideBound6 }

procedure TNxSlideBound6.Assign(Source: TPersistent);
begin
  inherited;
  if Source is TNxSlideBound6 then
  begin
    Caption := TNxSlideBound6(Source).Caption;
    CaptionFont.Assign(TNxSlideBound6(Source).CaptionFont);
    CaptionLocation := TNxSlideBound6(Source).CaptionLocation;
    Column := TNxSlideBound6(Source).Column;
    Height := TNxSlideBound6(Source).Height;
    Left := TNxSlideBound6(Source).Left;
    ParentCaptionFont := TNxSlideBound6(Source).ParentCaptionFont;
    Top := TNxSlideBound6(Source).Top;
    Visible := TNxSlideBound6(Source).Visible;
    Width := TNxSlideBound6(Source).Width;
  end;
end;

procedure TNxSlideBound6.Changed;
begin
  SlidesGridView.Invalidate;
end;

constructor TNxSlideBound6.Create(Collection: TCollection);
begin
  inherited;
  FCaption := EmptyStr;
  FCaptionFont := TFont.Create;
  FCaptionFont.OnChange := DoCaptionFontChange;
  FCaptionLocation := tlTop;
  FColumn := nil;
  FHeight := 16;
  FLeft := 0;
  FParentCaptionFont := True;
  FTop := 0;
  FVisible := True;
  FWidth := 80;
end;

destructor TNxSlideBound6.Destroy;
begin
  FCaptionFont.Free;
  inherited;
end;

procedure TNxSlideBound6.DoCaptionFontChange(Sender: TObject);
begin
  ParentCaptionFont := False;
end;

function TNxSlideBound6.GetBottom: Integer;
begin
  Result := Top + Height;
end;

function TNxSlideBound6.GetCellRect: TRect;
begin
  Result := Bounds(Left, Top, Width, Height);
end;

function TNxSlideBound6.GetRight: Integer;
begin
  Result := Left + Width;
end;

function TNxSlideBound6.GetSlidesGridView: TNxSlidesGridView6;
begin
  Result := TNxSlideBounds6(Collection).FOwner;
end;

procedure TNxSlideBound6.SetCaption(const Value: WideString);
begin
  if Value <> FCaption then
  begin
    FCaption := Value;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetCaptionFont(const Value: TFont);
begin
  FCaptionFont.Assign(Value);
  Changed;
end;

procedure TNxSlideBound6.SetCaptionLocation(const Value: TNxTextLocation);
begin
  if Value <> FCaptionLocation then
  begin
    FCaptionLocation := Value;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetColumn(const Value: TNxColumn6);
begin
  if Value <> FColumn then
  begin
    if Assigned(Value) then Value.FreeNotification(SlidesGridView);
    FColumn := Value;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetHeight(const Value: Integer);
var
  NewValue: Integer;
begin
  NewValue := Value;
  if NewValue < 8 then NewValue := 8;
  if NewValue <> FHeight then
  begin
    FHeight := NewValue;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetLeft(const Value: Integer);
begin
  if Value <> FLeft then
  begin
    FLeft := Value;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetParentCaptionFont(const Value: Boolean);
begin
  FParentCaptionFont := Value;
  if FParentCaptionFont then
  begin
    FCaptionFont.OnChange := nil;
    FCaptionFont.Assign(SlidesGridView.CaptionFont);
    FCaptionFont.OnChange := DoCaptionFontChange;
  end;
end;

procedure TNxSlideBound6.SetTop(const Value: Integer);
begin
  if Value <> FTop then
  begin
    FTop := Value;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetVisible(const Value: Boolean);
begin
  if Value <> FVisible then
  begin
    FVisible := Value;
    Changed;
  end;
end;

procedure TNxSlideBound6.SetWidth(const Value: Integer);
var
  NewValue: Integer;
begin
  NewValue := Value;
  if NewValue < 8 then NewValue := 8;
  if NewValue <> FWidth then
  begin
    FWidth := NewValue;
    Changed;
  end;
end;

{ TNxSlideBounds6 }

function TNxSlideBounds6.Add: TNxSlideBound6;
begin
  Result := TNxSlideBound6(inherited Add);
end;

constructor TNxSlideBounds6.Create(AOwner: TNxSlidesGridView6);
begin
  inherited Create(TNxSlideBound6);
  Assert(AOwner <> nil);
  FOwner := AOwner;
end;

function TNxSlideBounds6.GetBoundRect(Column: TNxColumn6): TRect;
var
  Index: Integer;
begin
  Index := IndexOf(Column);
  if Index <> -1 then Result := Items[Index].CellRect;
end;

function TNxSlideBounds6.GetItem(Index: Integer): TNxSlideBound6;
begin
  Result := TNxSlideBound6(inherited GetItem(Index));
end;

function TNxSlideBounds6.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TNxSlideBounds6.IndexOf(Column: TNxColumn6): Integer;
var
  i: Integer;
begin
  for i := 0 to Pred(Count) do
  begin
    if Items[i].Column = Column then
    begin
      Result := i;
      Exit;
    end;
  end;
  Result := -1;
end;

procedure TNxSlideBounds6.SetItem(Index: Integer; const Value: TNxSlideBound6);
begin
  inherited SetItem(Index, Value);
end;

{ TNxSlidesGridView }

constructor TNxSlidesGridView6.Create(AOwner: TComponent);
begin
  inherited;
  FBounds := TNxSlideBounds6.Create(Self);
  FCaptionFont := TFont.Create;
  FCaptionFont.Color := clGrayText;
  FCaptionFont.OnChange := DoCaptionFontChange;
  FSlideGridLines := True;
  FSlideHeight := 80;
  FSlideSelectionFrameWidth := 2;
  FSlideSelectionStyle := slSolid;

  { Set Prop. }
  ShowHeader := False;
end;

procedure TNxSlidesGridView6.DataMouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  RowAtPos: Integer;
begin
  inherited;

  if not IsSet(FPressedCell) then
  begin
    RowAtPos := GetItemAtPos(X, Y);

    { Must exists }
    if Control.RowExists(RowAtPos) then
      Control.SelectedRow := RowAtPos;
  end;
end;

destructor TNxSlidesGridView6.Destroy;
begin
  FreeAndNil(FBounds);
  FreeAndNil(FCaptionFont);
  inherited;
end;

procedure TNxSlidesGridView6.DoCaptionFontChange(Sender: TObject);
var
  I: Integer;
begin
  for i := 0 to Pred(Bounds.Count) do
    if Bounds[i].ParentCaptionFont then Bounds[i].ParentCaptionFont := True;
  Invalidate;
end;

procedure TNxSlidesGridView6.DoGetSlideColor(Index: Integer; var SlideColor: TColor;
  State: TNxSlideDrawState);
begin
  if Assigned(FOnGetSlideColor) then FOnGetSlideColor(Self, Index, SlideColor, State);
end;

procedure TNxSlidesGridView6.DoMeasureSlideHeight(Index: Integer;
  var SlideHeight: Integer);
begin
  if Assigned(FOnMeasureSlideHeight) then FOnMeasureSlideHeight(Self, Index, SlideHeight);  
end;

class function TNxSlidesGridView6.GetCaptionRect(Canvas: TCanvas;
  const SlideBound: TNxSlideBound6; SlideRect: TRect): TRect;
var
  CaptionSize: TSize;
  CellRect: TRect;
begin
  CellRect := Types.Bounds(
    SlideRect.Left + SlideBound.Left,
    SlideRect.Top + SlideBound.Top,
    SlideBound.Width,
    SlideBound.Height);

  CaptionSize := GetTextSize(Canvas, SlideBound.Caption, True);

  with CellRect, CaptionSize do
    case SlideBound.CaptionLocation of
      tlLeft: Result := Types.Bounds(Left - cx - pdStandard, Top, cx, cy);
      tlTop: Result := Types.Bounds(Left, Top - cy - pdStandard, cx, cy);
    end;
end;

function TNxSlidesGridView6.GetCellAtPos(Location: TPoint): TPoint;
var
  Pos: TPoint;
  SlideIndex, BoundIndex: Integer;
  Bound: TNxSlideBound6;
  SlideRect, CellRect: TRect;
begin
  { Default }
  Result := EmptyPoint;

  if FFirstIndex < 0
    then Exit;

  { Start }
  Pos := DataRect.TopLeft;

  SlideIndex := FFirstIndex;

  while SlideIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[SlideIndex] then
    begin

      SlideRect := Types.Bounds(DataRect.Left, Pos.Y, DataRect.Right - DataRect.Left, GetSlideHeight(SlideIndex));

      if PtInRect(SlideRect, Location) then

        for BoundIndex := 0 to Pred(Bounds.Count) do
        begin
          Bound := Bounds[BoundIndex];

          if Assigned(Bound.Column) and Bound.Visible then
          begin
            CellRect := Types.Bounds(DataRect.Left + Bound.Left, Pos.Y + Bound.Top, Bound.Width, Bound.Height);

            if PtInRect(CellRect, Location) then
            begin
              Result := Point(Bound.Column.Index, SlideIndex);

              Exit;
            end;
          end;

        end;

      Inc(Pos.Y, GetSlideHeight(SlideIndex));

      { SlideGrid }
      Inc(Pos.Y, SlideGridSize);

      if Pos.Y > DataRect.Bottom
        then Break;
    end;

    { Next slide }
    Inc(SlideIndex);

  end; { Slide (row) }

end;

function TNxSlidesGridView6.GetCellRect(ACol, ARow: Integer): TRect;
var
  Pos: TPoint;
  SlideIndex, BoundIndex: Integer;
  Bound: TNxSlideBound6;
  CellRect: TRect;
begin
  { Default }
  Result := Types.Bounds(0, 0, 0, 0);

  { Start }
  Pos := DataRect.TopLeft;

  SlideIndex := FFirstIndex;

  while SlideIndex < RowsOwner.RowCount do
  begin

    if RowsOwner.Showing[SlideIndex] then
    begin

      for BoundIndex := 0 to Pred(Bounds.Count) do
      begin
        Bound := Bounds[BoundIndex];

        if Assigned(Bound.Column) then
        begin
          CellRect := Types.Bounds(DataRect.Left + Bound.Left, Pos.Y + Bound.Top, Bound.Width, Bound.Height);

          if (SlideIndex = ARow) and (Bound.Column.Index = ACol) then
          begin
            Result := CellRect;

            Exit;
          end;
        end;

      end;

      Inc(Pos.Y, GetSlideHeight(SlideIndex));

      { SlideGrid }
      Inc(Pos.Y, SlideGridSize);

      if Pos.Y > DataRect.Bottom
        then Break;

    end;

    { Next slide }
    Inc(SlideIndex);
  end;

end;

function TNxSlidesGridView6.GetItemDefaultHeight: Integer;
begin
  Result := SlideHeight;
end;

function TNxSlidesGridView6.GetItemGridSize(Location: TNxLocation): Integer;
begin
  Result := SlideGridSize;
end;

function TNxSlidesGridView6.GetItemHeight(Index: Integer): Integer;
begin
  Result := SlideHeight;
end;

function TNxSlidesGridView6.GetItemRect(Index: Integer): TRect;
begin
  Result := Types.Bounds(DataRect.Left, GetItemTop(Index), DataRect.Right - DataRect.Left, GetSlideHeight(Index));
end;

function TNxSlidesGridView6.GetItemTop(Index: Integer): Integer;
var
  SlideIndex, ShownCount: Integer;
begin
  { Top-left Corner }
  Result := DataRect.Top;

  SlideIndex := 0;

  if FixedRowCount = 0 then
  begin
    SlideIndex := FFirstIndex;
  end;

  ShownCount := 0;

  while SlideIndex < Index do
  begin
    if RowsOwner.Showing[SlideIndex] then
    begin
      { Has Fixed }
      if FFixedRowCount > 0 then
      begin
        if ShownCount = FFixedRowCount then SlideIndex := FirstIndex + SlideIndex;
      end;

      { Shift Y (& Grid) }
      Inc(Result, GetSlideHeight(SlideIndex) + SlideGridSize);

      Inc(ShownCount);
    end;

    { Go to next }
    Inc(SlideIndex);
  end;
end;

function TNxSlidesGridView6.GetLastRowInPage: Integer;
var
  Pos, i: Integer;
begin
  { Default }
  Result := 0;

  Pos := FixedRect.Top;

  for i := FirstIndex to Pred(RowsOwner.RowCount) do
    if RowsOwner.Showing[i] then
    begin
      { Assign }
      Result := i;

      { Shift Pos (& Grid) }
      Inc(Pos, GetSlideHeight(i) + SlideGridSize);

      { Note: Not Include Grid }
      if Pos + GetSlideHeight(i) > DataRect.Bottom then
      begin

        Exit; { Done }
      end;
    end;
end;

function TNxSlidesGridView6.GetRowCountInPage(FromPos: Integer): Integer;
var
  Pos, i: Integer;
begin
  { Default }
  Result := 0;

  Pos := FixedRect.Top;

  for i := FromPos to Pred(RowsOwner.RowCount) do
    if RowsOwner.Showing[i] then
    begin
      Inc(Pos, GetSlideHeight(i));

      { Inc. Grid }
      Inc(Pos, SlideGridSize);

      { Reach Limit }
      if Pos > DataRect.Bottom
        then Exit;

      Inc(Result);
    end;
end;

function TNxSlidesGridView6.GetSlideGridSize: Integer;
begin
  Result := IfThen(FSlideGridLines, 1, 0);
end;

function TNxSlidesGridView6.GetSlideHeight(const Index: Integer): Integer;
begin
  Result := SlideHeight;
  DoMeasureSlideHeight(Index, Result);
end;

function TNxSlidesGridView6.GetVertPageSize: Integer;
var
  Pos, i: Integer;
begin
  { Default }
  Result := 0;

  Pos := FixedRect.Top;

  for i := FFirstIndex to Pred(RowsOwner.RowCount) do
  begin

    if Pos + GetSlideHeight(i) + SlideGridSize > FixedRect.Bottom
      then Exit;

    { Filtered, Collapsed, Hidden }
    if RowsOwner.Showing[i] then
    begin
      Inc(Result);

      { Shift for Height & Grid }
      Inc(Pos, GetSlideHeight(i) + SlideGridSize);
    end;

  end;

end;

procedure TNxSlidesGridView6.Notification(AComponent: TComponent;
  Operation: TOperation);
var
  i: Integer;
begin
  inherited;
  if csDestroying in ComponentState then Exit;

  { Deleted col. }
  if (Operation = opRemove) and Assigned(FBounds) then
    for i := 0 to Pred(Bounds.Count) do
    begin
      if TComponent(Bounds[i].Column) = AComponent then
      begin
        Bounds[i].Column := nil;
      end;
    end;

end;

procedure TNxSlidesGridView6.PaintCells;
var
  SlideIndex, b, VisibleRowIndex, i: Integer;
  Pos: TPoint;
  UpdatingRect, ClipSrc, ClipDst, SlideRect, CellRect, CaptionRect: TRect;
  Bound: TNxSlideBound6;
  SlideState: TNxSlideDrawState;
  SlideColor, SlideSelectionColor: TColor;
  CaptionSize: TSize;
begin
  { Start }
  Pos := DataRect.TopLeft;

  { Updating Area }
  GetClipBox(Canvas.Handle, UpdatingRect);

  SlideSelectionColor := Control.SelectionColor;
  if not Control.Focused then
  begin
    SlideSelectionColor := Control.InactiveSelectionColor;
  end;

  SlideIndex := FFirstIndex;
  VisibleRowIndex := SlideIndex;

  while SlideIndex < RowsOwner.RowCount do
  begin

    { Showing }
    if RowsOwner.Showing[SlideIndex] then
    begin
      Inc(VisibleRowIndex);

      SlideRect := Types.Bounds(DataRect.Left, Pos.Y, DataRect.Right - DataRect.Left, GetSlideHeight(SlideIndex));

      SlideState := [];
      SlideColor := Control.Color;

      if Control.Selected[SlideIndex] then
      begin
        Include(SlideState, ssSelected);
        case SlideSelectionStyle of
          slNone: SlideColor := SlideColor;
          slSolid: SlideColor := SlideSelectionColor;
          slAlphaBlended: SlideColor := BlendColor(SlideSelectionColor, Control.Color, 64);
        end;
      end;

      { Trigger event }
      DoGetSlideColor(SlideIndex, SlideColor, SlideState);

      with Canvas do
      begin
        Brush.Color := SlideColor;
        FillRect(SlideRect);

        if (ssSelected in SlideState)
          and (SlideSelectionStyle = slFramed) then
        begin
          Brush.Color := SlideSelectionColor;
          for i := 1 to SlideSelectionFrameWidth do
          begin
            InflateRect(SlideRect, -1, -1);
            FrameRect(SlideRect);
          end;
        end;
      end;

      for b := 0 to Pred(Bounds.Count) do
      begin
        Bound := Bounds[b];

        if Assigned(Bound.Column) and Bound.Visible then
        begin
          CellRect := Types.Bounds(DataRect.Left + Bound.Left, Pos.Y + Bound.Top, Bound.Width, Bound.Height);

          { Caption }
          if Bound.Caption <> EmptyStr then
          begin

            { CaptionFont }
            Canvas.Font.Assign(Bound.CaptionFont);

            CaptionSize := GetTextSize(Canvas, Bound.Caption, True);

            with CellRect, CaptionSize do
              case Bound.CaptionLocation of
                tlLeft: CaptionRect := Types.Bounds(Left - cx - pdStandard, Top, cx, cy);
                tlTop: CaptionRect := Types.Bounds(Left, Top - cy - pdStandard, cx, cy);
              end;

            if RectIntersect(CaptionRect, UpdatingRect) then
            begin
              DrawTextRect(Canvas, CaptionRect, taLeftJustify, taVerticalCenter, Bound.Caption, wkNone);
            end;
          end;

          { Inside Invalidation rect ? }
          if RectIntersect(CellRect, UpdatingRect) then
          begin
            ClipSrc := CellRect;
            ClipDst := Self.DataRect;

            { Intersection of ClipSrc & ClipDsy -> ClipSrc }
            IntersectRect(ClipSrc, ClipSrc, ClipDst);

            try
              SetClipRect(Canvas, ClipSrc);

              { Paint Cell }
              PaintCell(Bound.Column.Index, SlideIndex, VisibleRowIndex, CellRect);

            finally
              SetClipRect(Canvas, ClientRect);
            end;

          end; { inside }

        end; { Column <> nil }

      end;

      Inc(Pos.Y, GetSlideHeight(SlideIndex));

      { SlideGrid }
      if SlideGridLines then
      begin
        with Canvas do
        begin
          Pen.Color := GridLinesColor;
          Polyline([
            Point(DataRect.Left, Pos.Y),
            Point(DataRect.Right, Pos.Y)
          ]);
        end;

        Inc(Pos.Y, SlideGridSize);
      end;

      if Pos.Y > DataRect.Bottom
        then Exit;

    end; { Shown }

    { Next slide }
    Inc(SlideIndex);
  end;

  with Canvas do
  begin
    Brush.Color := Control.Color;
    FillRect(Rect(DataRect.Left, Pos.Y, DataRect.Right, DataRect.Bottom));
  end;
end;

class procedure TNxSlidesGridView6.PaintSlideBoundCaption(Canvas: TCanvas;
  const SlideBound: TNxSlideBound6; CaptionRect: TRect);
begin
  DrawTextRect(Canvas, CaptionRect, taLeftJustify, taVerticalCenter,
    SlideBound.Caption, wkNone);
end;

procedure TNxSlidesGridView6.RefreshColumn(Column: TNxColumn6;
  Area: TNxGridArea);
var
  BoundsRect: TRect;
  i: Integer;
begin
  if Bounds.IndexOf(Column) <> -1 then
  begin
    BoundsRect := Bounds.GetBoundRect(Column);

    if ShowIndicator then OffsetRect(BoundsRect, IndicatorWidth, 0);

    if RowsOwner.RowCount > 0 then
      for i := FirstIndex to LastRowInView do
        if RowsOwner.Showing[i] then
        begin
          { Invalidate if on screen }
          if RectIntersect(BoundsRect, DataRect) then Invalidate(BoundsRect);

          OffsetRect(BoundsRect, 0, GetSlideHeight(i) + SlideGridSize);
        end;
  end;
end;

procedure TNxSlidesGridView6.RefreshIndicator(Index: Integer);
var
  SlideRgn, InRgn: HRGN;
  Indent: Integer;
begin
  inherited;
  case SlideSelectionStyle of
    slFramed:
    begin
      Indent := Succ(SlideSelectionFrameWidth);
      with GetItemRect(Index) do
      begin
        SlideRgn := CreateRectRgn(Left + 1, Top + 1, Right - 1, Bottom - 1);
        InRgn := CreateRectRgn(Left + Indent, Top + Indent, Right - Indent, Bottom - Indent);
        CombineRgn(SlideRgn, SlideRgn, InRgn, RGN_XOR);
      end;
      InvalidateRgn(Control.Handle, SlideRgn, False);
    end;
    slSolid,
    slAlphaBlended: Invalidate(GetItemRect(Index));
  end;
end;

procedure TNxSlidesGridView6.RefreshRow(Index: Integer);
begin
  Invalidate(GetItemRect(Index));
end;

procedure TNxSlidesGridView6.RefreshRow(FromPos, ToPos: Integer);
var
  InvalidationRect: TRect;
  i: Integer;
begin
  InvalidationRect := GetItemRect(FromPos);

  if ShowIndicator then
  begin
    { Note: Right is anchored }
    InvalidationRect.Left := 0;
  end;

  for i := FromPos to ToPos do
    if RowsOwner.Showing[i] then
    begin
      Inc(InvalidationRect.Bottom, GetSlideHeight(i) + SlideGridSize);

      { Stop Process. }
      if InvalidationRect.Bottom > DataRect.Bottom
        then Break;
    end;

  if RectIntersect(InvalidationRect, DataRect) then
  begin
    { Invalidate Rect }
    Invalidate(InvalidationRect);
  end;
end;

procedure TNxSlidesGridView6.RefreshSelection;
begin
  if SlideSelectionStyle in [slSolid, slAlphaBlended] then
  begin
    RefreshRow(Control.SelectedLocation.Y);
  end
  else inherited;
end;

procedure TNxSlidesGridView6.ScrollContentBy(DeltaX, DeltaY: Integer);
var
  PixelDeltaY: Integer;
begin
  PixelDeltaY := 0;

  while DeltaY <> 0 do
    if DeltaY > 0 then { Scroll Down }
    begin

      if RowsOwner.Showing[FFirstIndex] then
      begin
        Dec(PixelDeltaY, GetSlideHeight(FFirstIndex));

        { Inc. Grid }
        Dec(PixelDeltaY, SlideGridSize);

        Dec(DeltaY);
      end;

      Inc(FFirstIndex);

    end else if DeltaY < 0 then { Scroll Up }
    begin
      Dec(FFirstIndex);

      if FFirstIndex < 0 then
      begin
        ShowMessage('Error: ' + IntToStr(FFirstIndex));
      end;

      if RowsOwner.Showing[FFirstIndex] then
      begin
        Inc(PixelDeltaY, GetSlideHeight(FFirstIndex));

        { Inc. Grid }
        Inc(PixelDeltaY, SlideGridSize);

        Inc(DeltaY);
      end;
    end;

  if PixelDeltaY <> 0 then
  begin
    ScrollRect(0, PixelDeltaY, GetVertClipRect, GetVertClipRect);
  end;

  { Update CapturedView }
  inherited;
end;

procedure TNxSlidesGridView6.ScrollToCol(Index: Integer);
begin

end;

procedure TNxSlidesGridView6.SetBounds(const Value: TNxSlideBounds6);
begin
  FBounds.Assign(Value);
end;

procedure TNxSlidesGridView6.SetCaptionFont(const Value: TFont);
begin
  FCaptionFont.Assign(Value);
  FCaptionFont.OnChange := DoCaptionFontChange;
end;

procedure TNxSlidesGridView6.SetSlideGridLines(const Value: Boolean);
begin
  if Value <> FSlideGridLines then
  begin
    FSlideGridLines := Value;
    Invalidate;
  end;
end;

procedure TNxSlidesGridView6.SetSlideHeight(const Value: Integer);
begin
  if Value <> FSlideHeight then
  begin
    FSlideHeight := Value;
    Invalidate;
  end;
end;

procedure TNxSlidesGridView6.SetSlideSelectionFrameWidth(const Value: Integer);
begin
  if Value <> FSlideSelectionFrameWidth then
  begin
    FSlideSelectionFrameWidth := Value;
    Invalidate;
  end;
end;

procedure TNxSlidesGridView6.SetSlideSelectionStyle(const Value: TNxSlideSelectionStyle);
begin
  if Value <> FSlideSelectionStyle then
  begin
    FSlideSelectionStyle := Value;
    Invalidate;
  end;
end;

function TNxGridView6.ToObject: TObject;
begin
  Result := Self;
end;

end.
