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

unit NxCustomGrid6;

interface

uses
  { Standard }
  Classes, Types, Messages, Windows, Graphics, Clipbrd, StdCtrls,
  {$IFDEF UI_TYPES}UITypes,{$ENDIF}
  { Additional }
  Controls, ExtCtrls, Forms, IniFiles, Registry,
  { Next Standard 6 }
  NxIntf6, NxClasses6, NxTypes6, NxConsts6, NxControls6, NxEdit6,
  { NextGrid 6 }
  NxColumns6, NxGridView6, NxGridStylePaint6, NxCells6, NxGridSerialization6;

const
  { Exceptions }
  exCellNotExists = 'Cell (%d, %d) out of bounds.';
  exViewNotExists = 'View out of list.';

const
  { Intervals }
  inSearchTimer = 600;

type
  TNxGridOptions = set of (goArrowEndEditing, goAutoHideScrollBars,
    goExitEndEditing, goResponsiveViews, goTabLeaveControl);

  TNxGridState = set of (gtEditingEnd, gtMultiSelected);

  TNxSelectionDirection = (sdNone, sdUp, sdDown, sdLeft, sdRight);

  TNxBeforeSelectEvent = procedure (Sender: TObject; var ACol, ARow: Integer;
    Key: Word; Shift: TShiftState) of object;

  TNxCalculateOptions = set of (roExcludeInvisible);

  TNxCellNotifyEvent = procedure (Sender: TObject; ACol, ARow: Integer) of object;
  TNxCellQueryEvent = procedure (Sender: TObject; ACol, ARow: Integer; var Accept: Boolean) of object;

  TNxCellClickEvent = procedure (Sender: TObject; ACol, ARow: Integer; Button: TMouseButton) of object;
  TNxCellDrawEvent = procedure (Sender: TObject; ACol, ARow: Integer;
    CellRect: TRect; State: TNxCellPaintingState; var DefaultDrawing: Boolean) of object;

  TNxAcceptEditEvent = procedure (Sender: TObject; ACol, ARow: Integer; var Text: WideString; var Accept: Boolean; var CanLeave: Boolean) of object;

  TNxAfterEditEvent = procedure (Sender: TObject; ACol, ARow: Integer; Text: WideString) of object;
  TNxBeforeEditEvent = procedure (Sender: TObject; ACol, ARow: Integer; var Accept: Boolean; var Text: WideString) of object;

  TNxSortQueryEvent = procedure (Sender: TObject; Index: Integer; SortKind: TNxSortKind; var Accept: Boolean) of object;

  TNxInsertRowQueryEvent = procedure (Sender: TObject; var Accept: Boolean) of object;

  TNxGetCellInplaceEditEvent = procedure (Sender: TObject; ACol, ARow: Integer;
    var InplaceEdit: INxInplaceEdit) of object;
  TNxInplaceEditInsertEvent = procedure (Sender: TObject; ACol, ARow: Integer;
    Component: TComponent) of object;
  TNxInplaceEditBounds = procedure (Sender: TObject; ACol, ARow: Integer;
    Component: TComponent; var EditRect: TRect) of object;

  TNxMeasureRowHeightEvent = procedure (Sender: TObject; Index: Integer; var RowHeight: Integer) of object;

  TNxFooterCalculatedEvent = procedure (Sender: TObject; ACol: Integer; var Value: Double) of object;

  TNxCustomGrid6 = class;

  { TNxCustomGrid6 }

  TNxCustomGrid6 = class(TNxScrollControl6, INxGridViewControl,
    INxVersionControl, INxDesignControl,
    INxPersistentDesignResponder, INxCellOwner, INxRowsControl)
  private
    { Property Fields }
    FActiveView: TNxGridView6;
    FAlternatingRowColor: TColor;
    FAlternatingRowColorOptions: TNxAlternatingRowColorsOptions;
    FAppearanceOptions: TNxAppearanceOptions;
    FAutoScroll: Boolean;
    FAutoSelect: Boolean;
    FCalculateOptions: TNxCalculateOptions;
    FCanLeaveEdit: Boolean;
    FColumns: TNxColumns6;
    FDesignerDelegate: INxDesignNotificationRecipient;
    FDesignerSelected: TPersistent;
    FEditing: Boolean;
    FEditingCell: TPoint;
    FFiltered: Boolean;
    FFindCols: array of Integer;
    FFindEndRow: Integer;
    FFindMatchingOptions: TNxSearchMatchingOptions;
    FFindOptions: TNxSearchOptions;
    FFindText: WideString;
    FFromSelected: Integer;
    FHideFocus: Boolean;
    FHideSelection: Boolean;
    FHoverResponder: INxDesignNotificationRecipient;
    FIgnoreEditing: Boolean;
    FInactiveSelectionColor: TColor;
    FInplaceEdit: INxInplaceEdit;
    FInserting: Boolean;
    FInsertSelected: Boolean;
    FInvertSelected: Boolean;
    FLastFoundRow: Integer;
    FMultiSelect: Boolean;
    FMultiSort: Boolean;
    FOnAcceptEdit: TNxAcceptEditEvent;
    FOnAfterEdit: TNxAfterEditEvent;
    FOnAfterSort: TNotifyEvent;
    FOnBeforeEdit: TNxBeforeEditEvent;
    FOnBeforeSelect: TNxBeforeSelectEvent;
    FOnCellClick: TNxCellClickEvent;
    FOnCellDblClick: TNxCellNotifyEvent;
    FOnCustomDrawCell: TNxCellDrawEvent;
    FOnDeselect: TNxCellNotifyEvent;
    FOnEditEnter: TNxCellNotifyEvent;
    FOnEditExit: TNxCellNotifyEvent;
    FOnFooterCalculated: TNxFooterCalculatedEvent;
    FOnGetInplaceEdit: TNxGetCellInplaceEditEvent;
    FOnInplaceEditChange: TNotifyEvent;
    FOnInplaceEditInsert: TNxInplaceEditInsertEvent;
    FOnInsertRowAdd: TNotifyEvent;
    FOnInsertRowQuery: TNxInsertRowQueryEvent;
    FOnMeasureRowHeight: TNxMeasureRowHeightEvent;
    FOnSelect: TNxCellNotifyEvent;
    FOnSelectionChanged: TNxCellNotifyEvent;
    FOnSelectQuery: TNxCellQueryEvent;
    FOnSortQuery: TNxSortQueryEvent;
    FOnViewChange: TNotifyEvent;
    FOptions: TNxGridOptions;
    FPrevHeight: Integer;
    FPrevWidth: Integer;
    FReadOnly: Boolean;
    FRightClickDeselect: Boolean;
    FRightClickSelect: Boolean;
    FRowHeight: Integer;
    FSearchBuffer: WideString;
    FSearchBufferTimer: TTimer;
    FSecondClickEditing: Boolean;
    FSelectFullRow: Boolean;
    FSelectionColor: TColor;
    FSelectionDirection: TNxSelectionDirection;
    FSelectionKey: Word;
    FSelectionTextColor: TColor;
    FSerialize: TNxGridSerialization;
    FStyle: TNxAppearanceStyle;
    FStylePaint: INxGridStylePaint;
    FUpdateCount: Integer;
    FViews: TNxGridViews6;
    FWantReturns: Boolean;
    FWantTabs: Boolean;
    FOnInplaceEditBounds: TNxInplaceEditBounds;
    { Property Accessors }
    function GetActiveViewIndex: Integer;
    function GetAlternatingRowColor: TColor;
    function GetAlternatingRowColorOptions: TNxAlternatingRowColorsOptions;
    function GetAppearanceOptions: TNxAppearanceOptions;
    function GetCaption: TCaption;
    function GetColCount: Integer;
    function GetColor: TColor;
    function GetContentIndent: TSize;
    function GetControlName: string;
    function GetEditingCell: TPoint;
    function GetHideFocus: Boolean;
    function GetHideSelection: Boolean;
    function GetInactiveSelectionColor: TColor;
    function GetInplaceEdit: INxInplaceEdit;
    function GetInsertSelected: Boolean;
    function GetInvertSelected: Boolean;
    function GetLastAddedColumn: TNxColumn6;
    function GetMultiSelect: Boolean;
    function GetMultiSort: Boolean;
    function GetRightClickSelect: Boolean;
    function GetSecondClickEditing: Boolean;
    function GetSelectedLocation: TPoint;
    function GetSelectFullRow: Boolean;
    function GetSelectionColor: TColor;
    function GetSelectionKey: Word;
    function GetSelectionTextColor: TColor;
    function GetStylePaint: INxGridStylePaint;
    function GetVersion: string;
    procedure SetActiveView(const Value: TNxGridView6);
    procedure SetActiveViewIndex(const Value: Integer);
    procedure SetAlternatingRowColor(const Value: TColor);
    procedure SetAppearanceOptions(const Value: TNxAppearanceOptions);
    procedure SetEditing(const Value: Boolean);
    procedure SetHideFocus(const Value: Boolean);
    procedure SetHideSelection(const Value: Boolean);
    procedure SetHoverResponder(const Value: INxDesignNotificationRecipient);
    procedure SetInactiveSelectionColor(const Value: TColor);
    procedure SetInsertSelected(const Value: Boolean);
    procedure SetInvertSelcted(const Value: Boolean);
    procedure SetMultiSelect(const Value: Boolean);
    procedure SetMultiSort(const Value: Boolean);
    procedure SetOptions(const Value: TNxGridOptions);
    procedure SetRightClickSelect(const Value: Boolean);
    procedure SetRowHeight(const Value: Integer);
    procedure SetSelectedLocation(const Value: TPoint);
    procedure SetSelectFullRow(const Value: Boolean);
    procedure SetSelectionColor(const Value: TColor);
    procedure SetSelectionKey(const Value: Word);
    procedure SetSelectionTextColor(const Value: TColor);
    procedure SetStyle(const Value: TNxAppearanceStyle);
  protected
    procedure SetResponsiveActiveView; virtual;
  protected
    { INxRowIndices }
    function GetFirstVisibleRow: Integer; virtual; abstract;
    function GetLastVisibleRow: Integer; virtual; abstract;
    function GetSelectedCount: Integer; virtual;
    function GetShowingCount: Integer; virtual; abstract;
  protected
    FSelectedCol: Integer;
    FSelectedRow: Integer;
    FUpdateOptions: TNxUpdateOptions;
    { INxObject }
    function ToObject: TObject;
    { INxGridViewControl }
    function GetColumns: TNxColumns6;
    function GetFont: TFont;
    procedure SetActiveCell(const Point: TPoint); virtual; abstract;
  protected
    function InternalEditCell(ACol, ARow: Integer; EditText: WideString;
      ForceEditing, SelectText: Boolean): Boolean;
    procedure SetName(const NewName: TComponentName); override;
  protected
    FSelectDelta: TPoint;
    FState: TNxGridState;
    function CanAutoScroll: Boolean; virtual;
    { TControl }
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateWnd; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure ReadState(Reader: TReader); override;
    { INxCellOwner }
    procedure LocateCell(ACol, ARow: Integer); virtual;
    { INxDesignControl }
    procedure DesignNotification(Sender: INxDesignNotificationRecipient;
      Operation: TNxDesignOperation);
    function GetInstance: TPersistent;
    function GetResponderAtPos(Location: TPoint): INxDesignNotificationRecipient;
    function GetResponderRect(AResponder: INxDesignNotificationRecipient): TRect;
    procedure SelectComponent(Instance: TPersistent);
    procedure SetDesignerDelegate(const Value: INxDesignNotificationRecipient);
    { Designing }
    procedure DesignMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    { Calc. Methods }
    function CanCalculate(const Index: Integer): Boolean;
    function GetAutoCalculate: Boolean; virtual;
    function GetFetchedRowCount: Integer; virtual;
    function GetFirstFetchedRow: Integer; virtual;
    procedure RowsChanged; virtual; abstract;
    { Filter Methods }
    procedure Filter; virtual;
    { Protected Methods }
    procedure AssignStylePaint; virtual;
    procedure CreateStylePaint; virtual;
    procedure DeselectSelected; virtual;
    procedure StyleChanged; override;
    function GetCell(ACol, ARow: Integer): INxCell; virtual; abstract;
    function GetCellLocation(ACol, ARow: Variant): TPoint;
    function GetCells(ACol, ARow: Integer): WideString; virtual;
    function GetCellSource: INxCells; virtual; abstract;
    function GetChildRow(const Index: Integer): INxRow; virtual; abstract;
    function GetChildRowCount: Integer; virtual; abstract;
    function GetOwnerRow: INxRow;
    function GetRow(const Index: Integer): INxRow; virtual; abstract;
    function GetRowCount: Integer; virtual; abstract;
    function GetRowHeight: Integer;
    function GetRowsBetween(FromPos, ToPos: Integer): Integer; virtual; abstract;
    function GetRowSize(Index: Integer): Integer;
    function GetScrollBars: TScrollStyle; override;
    function GetShowing(const Index: Integer): Boolean; virtual; abstract;
    function GetVisibleRowCount: Integer; virtual; abstract;
    procedure Recount; virtual;
    procedure SetActiveRow(const Index: Integer); virtual;
    procedure SetCells(ACol, ARow: Integer; const Value: WideString); virtual; abstract;
    procedure SetFiltered(const Value: Boolean); virtual;
    procedure SetRowCount(const Value: Integer); virtual; abstract;
    { Selection Methods }
    function GetHighlighted(ACol, ARow: Integer): Boolean; virtual;
    function GetSelected(Index: Integer): Boolean; virtual;
    function GetSelectedCol: Integer; virtual;
    function GetSelectedRow: Integer; virtual;
    procedure SetHighlighted(ACol, ARow: Integer; const Value: Boolean); virtual;
    procedure SetSelected(Index: Integer; const Value: Boolean); virtual;
    procedure SetSelectedCol(const Value: Integer); virtual;
    procedure SetSelectedRow(const Value: Integer); virtual;
    { Event Handlers }
    procedure DoAcceptEdit(ACol, ARow: Integer; var Text: WideString; var Accept: Boolean; var CanLeave: Boolean); dynamic;
    procedure DoAfterEdit(ACol, ARow: Integer; Text: WideString); dynamic;
    procedure DoAfterSort; dynamic;
    procedure DoAlternatingRowColorOptionsChange(Sender: TObject); dynamic;
    procedure DoBeforePostEdit(Cell: INxCell); virtual;
    procedure DoBeforeSelect(var ACol, ARow: Integer; Key: Word;
      Shift: TShiftState); dynamic;
    procedure DoBeforeEdit(ACol, ARow: Integer; var Accept: Boolean;
      var Text: WideString); dynamic;
    procedure DoBeginEditing; virtual;
    procedure DoCellClick(ACol, ARow: Integer; Button: TMouseButton); dynamic;
    procedure DoCellDblClick(ACol, ARow: Integer); dynamic;
    procedure DoCustomDrawCell(ACol, ARow: Integer; CellRect: TRect;
      State: TNxCellPaintingState; var DefaultDrawing: Boolean); dynamic;
    procedure DoDeselect(ACol, ARow: Integer); dynamic;
    procedure DoEditEnter(ACol, ARow: Integer); dynamic;
    procedure DoEditExit(ACol, ARow: Integer); dynamic;
    procedure DoFooterCalculated(const ACol: Integer; var Value: Double); dynamic;
    procedure DoGetInplaceEdit(ACol, ARow: Integer; var InplaceEdit: INxInplaceEdit); dynamic;
    procedure DoInplaceEditBounds(ACol, ARow: Integer; Component: TComponent; var EditRect: TRect); dynamic;
    procedure DoInplaceEditChange(Sender: TObject); dynamic;
    procedure DoInplaceEditInsert(ACol, ARow: Integer; Component: TComponent); dynamic;
    procedure DoInsertRowAdd; dynamic;
    procedure DoInsertRowQuery(var Accept: Boolean); dynamic;
    procedure DoMeasureRowHeight(Index: Integer; var RowHeight: Integer); dynamic;
    procedure DoSelect(ACol, ARow: Integer); dynamic;
    procedure DoSelectionChanged(ACol, ARow: Integer); dynamic;
    procedure DoSelectQuery(ACol, ARow: Integer; var Accept: Boolean); dynamic;
    procedure DoSortQuery(Index: Integer; SortKind: TNxSortKind; var Accept: Boolean); dynamic;
    procedure DoViewChange; dynamic;
    { External Event Handlers }
    procedure DoColumnAdd(Sender: TNxColumns6; Index: Integer = -1); virtual;
    procedure DoColumnChanged(Sender: TNxColumn6; Area: TNxGridArea); virtual;
    procedure DoColumnFilter(Sender: TObject); virtual;
    procedure DoColumnRemove(Sender: TNxColumn6); virtual;
    procedure DoColumnResized(Sender: TNxColumn6; Delta: Integer); virtual;
    procedure DoColumnSort(Sender: TNxColumn6); virtual;
    procedure DoClumnsUpdate(Sender: TObject);
    procedure DoSearchTimer(Sender: TObject);
    { Keyboard & Mouse Methods }
    function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure KeyUp(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;
    { Streaming Methods }
    function GetChildOwner: TComponent; override;
    procedure SetChildOrder(Child: TComponent; Order: Integer); override;
    { Painting Methods }
    procedure Paint; override;
    procedure PaintDebug;
    procedure PaintDesign; virtual;
    function IsIntegralHeight: Boolean; virtual;
    function IsVirtual: Boolean; virtual;
    { Delphi Messages }
    procedure CMChildKey(var AMsg: TCMChildKey); message CM_CHILDKEY;
    procedure CMDesignHitTest(var Message: TCMDesignHitTest); message CM_DESIGNHITTEST;
    procedure CMFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
    { Windows Messages }
    procedure WMActivateApp(var Message: TWMActivateApp); message WM_ACTIVATEAPP;
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
    procedure WMKillFocus(var Message: TWMSetFocus); message WM_KILLFOCUS;
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
    procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
    { InplaceEdit Methods }
    procedure UpdateInplaceEditor; virtual;
    { ScrollBar Methods }
    procedure UpdateHorzScrollBar; virtual;
    procedure UpdateScrollBars;
    procedure UpdateVertScrollBar; virtual;
    { Properties }
    property DesignerDelegate: INxDesignNotificationRecipient read FDesignerDelegate;
    property HoverResponder: INxDesignNotificationRecipient read FHoverResponder write SetHoverResponder;
  public
    function AddInsertRow: Boolean; virtual;
    procedure BeginUpdate(Options: TNxUpdateOptions = [uoScrollBar]);
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ChangeRowHeight(const Value: Integer); virtual;
    procedure DataChanged(Options: TNxUpdateOptions = [uoRecount, uoRepaint, uoScrollBar]); virtual;
    procedure EndUpdate(Update: Boolean = True; Immediate: Boolean = False);
    { Public Event Handlers }
    procedure DoAddRow(Sender: TObject); virtual; abstract;
    procedure DoCSVGetValue(Sender: TObject; X, Y: Integer; var Value: WideString);
    procedure DoCSVSetValue(Sender: TObject; X, Y: Integer; Value: WideString);
    { Streaming Methods }
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    { INxDesignControl }
    { INxViewControl }
    function BestFitCol(const Index: Integer): Integer; virtual;
    function BestFitColumn(const Column: TNxColumn6; Mode: TNxBestFitMode = [bfCells]): Integer; virtual;
    function BestFitRow(const RowIndex: Integer; const ColIndex: Integer = -1): Integer; virtual;
    function CellExists(const ACell: TPoint): Boolean; overload;
    function CellExists(const ACol, ARow: Integer): Boolean; overload;
    function CanEdit(const ACol, ARow: Integer): Boolean; virtual;
    function CanKeyLeaveEdit(Key: Word): Boolean;
    function CanSelect(const ACol, ARow: Integer): Boolean; virtual;
    function CanUpdate(Options: TNxUpdateOptions): Boolean;
    function CheckCell(const ACol, ARow: Integer): Boolean;
    function GetCanvas: TCanvas;
    function RowExists(const Index: Integer): Boolean;
    function RowPersist(const Index: Integer): Boolean; virtual;
//    procedure InvalidateRect(InvalidationRect: TRect);
    { Virtual Methods }
    function MeasureCellSize(const ACol, ARow: Integer): TSize; virtual;
    procedure ScrollRect(DeltaX, DeltaY: Integer; Rect, ClipRect: TRect); override;
    { Methods }
    function AssignEditing: Boolean;
    function EditCell(ACol, ARow: Integer; EditText: WideString = '';
      ForceEditing: Boolean = False): Boolean; overload; virtual;
    function EditCell(ACol, ARow: Integer; Key: WideChar): Boolean; overload; virtual;
    function EditCell(Location: TPoint; Value: WideString = ''): Boolean; overload;
    function EditSelected: Boolean;
    function EndEditing(AssignEditing: Boolean = True): Boolean; virtual;
    function GetAnchorCell(const ACol, ARow: Integer): TPoint;
    function GetDisplayText(Cell: INxCell): WideString; virtual;
    function GetItemRect(Index: Integer): TRect;
    function GetNextChild(const Index: Integer; VisibleOnly: Boolean = True): Integer; virtual; abstract;
    procedure IgnoreEditing;
    function InsertCell(Index: Integer; InsertText: WideString = ''): Boolean; overload; virtual;
    function InsertCell(Index: Integer; Key: WideChar): Boolean; overload; virtual;
    procedure Recalculate; virtual;
    procedure RepeatValue;
    procedure ScrollToBottom;
    procedure ScrollToCell(ACol, ARow: Integer); virtual;
    procedure ScrollToSelected;
    procedure ScrollToTop;
    function HasCols: Boolean;
    function HasRows: Boolean;
    function InplaceEditFocused: Boolean;
    function IsUnique(const Index: Integer; Cell: INxCell): Boolean; virtual; abstract;
    function IsUpdating: Boolean;
    function IsSelectionValid: Boolean;
    { Refresh Methods }
    procedure RefreshCell(const ACol, ARow: Integer);
    procedure RefreshRow(const Index: Integer);
    procedure RefreshSelectedCell;
    { Selection Methods }
    procedure MoveByColumn(Distance: Integer; Shift: TShiftState = []); virtual;
    procedure MoveByPage(MoveUp: Boolean; Shift: TShiftState = []);
    procedure MoveByRow(Distance: Integer; Shift: TShiftState = []); virtual;
    procedure SelectAll; virtual;
    procedure SelectCell(ACol, ARow: Integer; Shift: TShiftState = []); virtual;
    procedure SelectFirst(Shift: TShiftState = []); virtual;
    procedure SelectLast(Shift: TShiftState = []); virtual;
    procedure SelectNone(DelayedRefresh: Boolean = True); virtual;
    procedure SelectRange(FromPos, ToPos: Integer; Value: Boolean); virtual;
    procedure TabByColumn(Shift: TShiftState; LeaveControl: Boolean);
    { Searching }
    function FindText(Cols: array of Integer; Text: WideString; StartRow, EndRow: Integer;
      Options: TNxSearchOptions; MatchingOptions: TNxSearchMatchingOptions = moContain): Integer;
    function FindNext: Integer;
    { TWinControl }
    function Focused: Boolean; override;
    {$IFDEF DEBUGING}
    procedure Test;
    {$ENDIF}
    { Properties }
    property Canvas;
    property Cell[ACol, ARow: Integer]: INxCell read GetCell;
    property Cells[ACol, ARow: Integer]: WideString read GetCells write SetCells;
    property ChildRow[const Index: Integer]: INxRow read GetChildRow;
    property ChildRowCount: Integer read GetChildRowCount;
    property ColCount: Integer read GetColCount;
    property ContentIndent: TSize read GetContentIndent;
    property Editing: Boolean read FEditing write SetEditing;
    property EditingCell: TPoint read GetEditingCell;
    property FetchedRowCount: Integer read GetFetchedRowCount;
    property FirstFetchedRow: Integer read GetFirstFetchedRow;
    property FirstVisibleRow: Integer read GetFirstVisibleRow;
    property Highlighted[ACol, ARow: Integer]: Boolean read GetHighlighted write SetHighlighted;
    property InplaceEdit: INxInplaceEdit read GetInplaceEdit;
    property Inserting: Boolean read FInserting;
    property LastAddedColumn: TNxColumn6 read GetLastAddedColumn;
    property LastFoundRow: Integer read FLastFoundRow;
    property LastVisibleRow: Integer read GetLastVisibleRow;
    property Row[const Index: Integer]: INxRow read GetRow;
    property RowCount: Integer read GetRowCount write SetRowCount default 0;
    property Selected[Index: Integer]: Boolean read GetSelected write SetSelected;
    property SelectedCol: Integer read GetSelectedCol write SetSelectedCol;
    property SelectedCount: Integer read GetSelectedCount;
    property SelectedLocation: TPoint read GetSelectedLocation write SetSelectedLocation;
    property SelectedRow: Integer read GetSelectedRow write SetSelectedRow;
    property SelectionKey: Word read GetSelectionKey write SetSelectionKey;
    property Serialize: TNxGridSerialization read FSerialize;
    property Showing[const Index: Integer]: Boolean read GetShowing;
    property ShowingCount: Integer read GetShowingCount;
    property StylePaint: INxGridStylePaint read GetStylePaint write FStylePaint;
    property UpdateCount: Integer read FUpdateCount;
  published
    { Properties }
    property ActiveView: TNxGridView6 read FActiveView write SetActiveView;
    property ActiveViewIndex: Integer read GetActiveViewIndex write SetActiveViewIndex default -1;
    property Align;
    property AlternatingRowColor: TColor read GetAlternatingRowColor write SetAlternatingRowColor default clMoneyGreen;
    property AlternatingRowColorOptions: TNxAlternatingRowColorsOptions read GetAlternatingRowColorOptions;
    property Anchors;
    property AppearanceOptions: TNxAppearanceOptions read FAppearanceOptions write SetAppearanceOptions default [aoHintIndicators, aoStyleColors];
    property AutoScroll: Boolean read FAutoScroll write FAutoScroll default True;
    property AutoSelect: Boolean read FAutoSelect write FAutoSelect default False;
    property BiDiMode;
    property BorderSize default 1;
    property CalculateOptions: TNxCalculateOptions read FCalculateOptions write FCalculateOptions default [];
    property Caption;
    property Color;
    property Columns: TNxColumns6 read GetColumns;
    property Constraints;
    property Ctl3D;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property Filtered: Boolean read FFiltered write SetFiltered default False;
    property Font;
    property Height default 180;
    property HideFocus: Boolean read GetHideFocus write SetHideFocus default False;
    property HideSelection: Boolean read GetHideSelection write SetHideSelection default True;
    property Hint;
    property InactiveSelectionColor: TColor read GetInactiveSelectionColor write SetInactiveSelectionColor default clBtnFace;
    property InsertSelected: Boolean read GetInsertSelected write SetInsertSelected default False;
    property InvertSelected: Boolean read GetInvertSelected write SetInvertSelcted default False;
    property MultiSelect: Boolean read GetMultiSelect write SetMultiSelect default False;
    property MultiSort: Boolean read FMultiSort write SetMultiSort default False;
    property Options: TNxGridOptions read FOptions write SetOptions default [goArrowEndEditing, goExitEndEditing, goTabLeaveControl];
    property ParentBiDiMode;
    property ParentColor;
    property ParentFont;
    property PopupMenu;
    property ReadOnly: Boolean read FReadOnly write FReadOnly default False;
    property RightClickDeselect: Boolean read FRightClickDeselect write FRightClickDeselect default True;
    property RightClickSelect: Boolean read GetRightClickSelect write SetRightClickSelect default True;
    property RowHeight: Integer read GetRowHeight write SetRowHeight default szDefaultRowHeight;
    property ScrollBars;
    property SecondClickEditing: Boolean read GetSecondClickEditing write FSecondClickEditing default False;
    property SelectFullRow: Boolean read GetSelectFullRow write SetSelectFullRow default False;
    property SelectionColor: TColor read GetSelectionColor write SetSelectionColor default clHighlight;
    property SelectionDirection: TNxSelectionDirection read FSelectionDirection write FSelectionDirection default sdDown;
    property SelectionTextColor: TColor read GetSelectionTextColor write SetSelectionTextColor default clHighlightText;
    property ShowHint;
    property Style: TNxAppearanceStyle read FStyle write SetStyle default stNative;
    property TabOrder;
    property TabStop;
    property Version: string read GetVersion stored False;
    property Views: TNxGridViews6 read FViews write FViews;
    property Visible;
    property WantReturns: Boolean read FWantReturns write FWantReturns default False;
    property WantTabs: Boolean read FWantTabs write FWantTabs default False;
    property Width default 320;
    { Events }
    property OnAcceptEdit: TNxAcceptEditEvent read FOnAcceptEdit write FOnAcceptEdit;
    property OnAfterEdit: TNxAfterEditEvent read FOnAfterEdit write FOnAfterEdit;
    property OnAfterSort: TNotifyEvent read FOnAfterSort write FOnAfterSort;
    property OnBeforeEdit: TNxBeforeEditEvent read FOnBeforeEdit write FOnBeforeEdit;
    property OnBeforeSelect: TNxBeforeSelectEvent read FOnBeforeSelect write FOnBeforeSelect;
    property OnCellClick: TNxCellClickEvent read FOnCellClick write FOnCellClick;
    property OnCellDblClick: TNxCellNotifyEvent read FOnCellDblClick write FOnCellDblClick;
    property OnClick;
    property OnContextPopup;
    property OnCustomDrawCell: TNxCellDrawEvent read FOnCustomDrawCell write FOnCustomDrawCell;
    property OnDblClick;
    property OnDeselect: TNxCellNotifyEvent read FOnDeselect write FOnDeselect;
    property OnDragDrop;
    property OnDragOver;
    property OnEditEnter: TNxCellNotifyEvent read FOnEditEnter write FOnEditEnter;
    property OnEditExit: TNxCellNotifyEvent read FOnEditExit write FOnEditExit;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnFooterCalculated: TNxFooterCalculatedEvent read FOnFooterCalculated write FOnFooterCalculated;
    property OnGetInplaceEdit: TNxGetCellInplaceEditEvent read FOnGetInplaceEdit write FOnGetInplaceEdit;
    property OnInplaceEditBounds: TNxInplaceEditBounds read FOnInplaceEditBounds write FOnInplaceEditBounds;
    property OnInplaceEditChange: TNotifyEvent read FOnInplaceEditChange write FOnInplaceEditChange;
    property OnInplaceEditInsert: TNxInplaceEditInsertEvent read FOnInplaceEditInsert write FOnInplaceEditInsert;
    property OnInsertRowAdd: TNotifyEvent read FOnInsertRowAdd write FOnInsertRowAdd;
    property OnInsertRowQuery: TNxInsertRowQueryEvent read FOnInsertRowQuery write FOnInsertRowQuery;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMeasureRowHeight: TNxMeasureRowHeightEvent read FOnMeasureRowHeight write FOnMeasureRowHeight;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
    property OnResize;
    property OnSelect: TNxCellNotifyEvent read FOnSelect write FOnSelect;
    property OnSelectionChanged: TNxCellNotifyEvent read FOnSelectionChanged write FOnSelectionChanged;
    property OnSelectQuery: TNxCellQueryEvent read FOnSelectQuery write FOnSelectQuery;
    property OnSortQuery: TNxSortQueryEvent read FOnSortQuery write FOnSortQuery;
    property OnStartDrag;
    property OnViewChange: TNotifyEvent read FOnViewChange write FOnViewChange;
  end;

implementation

uses
  { Standard }
  SysUtils, StrUtils, Math, Dialogs, Variants,
  { Next Standard 6 }
  NxGraphics6, NxTheme6,
  { Next Grid 6 }
  NxColumnViewClasses6;

{ TNxCustomGrid6 }

function TNxCustomGrid6.AddInsertRow: Boolean;
var
  i: Integer;
begin
  { Default }
  Result := False;

  { Should Add? }
  for i := 0 to Pred(Columns.Count) do
    if Columns[i].InsertValue.IsSet then
    begin
      Result := True;

      { Found one with Value (!) }
      Break;
    end;

  { Trigger event }
  DoInsertRowQuery(Result);
end;

function TNxCustomGrid6.AssignEditing: Boolean;
var
  Text: WideString;
  EditCell: INxCell;
  PropertyIntf: INxProperty;
begin
  { Yes, Assign }
  Result := True;

  if Assigned(FInplaceEdit) then
  begin

    if FInserting then
    begin
      { Note: Give Edit a last chance to change Value }
      FInplaceEdit.EndEdit;

      { Trigger Event }
      if Supports(InplaceEdit, INxProperty, PropertyIntf) then
      begin
        Text := PropertyIntf.AsString;
      end else Text := FInplaceEdit.Text;
      DoAcceptEdit(FEditingCell.X, -1, Text, FCanLeaveEdit, Result);

      if Result then
      begin
        Columns[FEditingCell.X].AssignEditValue(Columns[FEditingCell.X].InsertValue, FInplaceEdit);

        { Trigger Event }
        DoAfterEdit(FEditingCell.X, -1, Text);
      end;

      if not FCanLeaveEdit then
      begin
        FInplaceEdit.Text := Text;
        FInplaceEdit.SelectAll;
      end;

    end;

    if FEditing then
    begin
      { Note: Give Edit a last chance to change Value }
      FInplaceEdit.EndEdit;

      { Trigger Event }
      if Supports(InplaceEdit, INxProperty, PropertyIntf) then
      begin
        Text := PropertyIntf.AsString;
      end else Text := FInplaceEdit.Text;
      DoAcceptEdit(FEditingCell.X, FEditingCell.Y, Text, FCanLeaveEdit, Result);

      if Result then
      begin
        EditCell := Cell[FEditingCell.X, FEditingCell.Y];

        { Descendants (e.g. NextDBGrid) override this }
        DoBeforePostEdit(EditCell);

        { Assign Value to Cell }
        Columns[FEditingCell.X].AssignEditValue(EditCell, FInplaceEdit);

        { Trigger Event }
        DoAfterEdit(FEditingCell.X, FEditingCell.Y, Text);
      end;

      if not FCanLeaveEdit then
      begin
        FInplaceEdit.Text := Text;
        FInplaceEdit.SelectAll;
      end;
    end;

  end;

end;

procedure TNxCustomGrid6.AssignStylePaint;
begin
  if Assigned(FStylePaint) then
  begin
    { Associate Prop. }
    FStylePaint.Canvas := Canvas;
  end;
end;

procedure TNxCustomGrid6.BeginUpdate(Options: TNxUpdateOptions);
begin
  FUpdateOptions := Options;

  { Don't Update ScrollBar }
  if not (uoScrollBar in FUpdateOptions) then
  begin
    { Set Position Field, but not Update }
    VertScrollBar.Lock;
  end;

  { Increase }
  Inc(FUpdateCount);
end;

function TNxCustomGrid6.BestFitCol(const Index: Integer): Integer;
begin
  Result := BestFitColumn(Columns[Index]);
end;

function TNxCustomGrid6.BestFitColumn(const Column: TNxColumn6;
  Mode: TNxBestFitMode): Integer;
var
  i, Largest: Integer;
  BestSize: TSize;
  RowView: INxRowView;
begin
  if Assigned(ActiveView) then
  begin
    { Default }
    Largest := Column.MinWidth;

    if (bfFooter in Mode) or (bfHeader in Mode) then
    begin
      StylePaint.SetColumn(Column);
      StylePaint.Canvas := Canvas;
    end;

    if bfFooter in Mode then
    begin
      { Incl. padding }
      Largest := StylePaint.GetFooterSize.cx;
    end;

    if bfHeader in Mode then
    begin
      { Incl. padding }
      Largest := Max(Largest, StylePaint.GetHeaderSize.cx);
    end;

    if bfCells in Mode then
    begin
      for i := FirstFetchedRow to Pred(FetchedRowCount) do
      begin
        if Showing[i] then
        begin
          { Set Prop. }
          with Column.View do
          begin
            Canvas := Self.Canvas;
            Cell := Self.Cell[Column.Index, i];
          end;

          { Support INxRowView interface? }
          if Supports(Column.View, INxRowView, RowView) then
          begin
            RowView.Row := Row[i];
          end;

          BestSize := Column.View.BestSize;

          { Inc. Padding & Grid }
          ActiveView.AdjustCellSize(BestSize, Column.Index);

          if BestSize.cx > Largest
            then Largest := BestSize.cx;
        end;
      end;
    end;

    { Final }
    Column.Width := Largest;

  end; { ActiveView assigned }

  { Return value }
  Result := Column.Width;
end;

function TNxCustomGrid6.BestFitRow(const RowIndex, ColIndex: Integer): Integer;
var
  BestSize: TSize;
  i: Integer;
begin
  { Default }
  Result := RowHeight;

  if Assigned(ActiveView) then
  begin
    for i := 0 to Pred(Columns.Count) do
      if Columns[i].Visible then
      begin
        { Set Prop. }
        with Columns[i].View do
        begin
          Canvas := Self.Canvas;
          Cell := Self.Cell[i, RowIndex];
        end;

        BestSize := Columns[i].View.BestSize;

        { Inc. Padding & Grid }
        ActiveView.AdjustCellSize(BestSize, i);

        if BestSize.cy > Result
          then Result := BestSize.cy;

      end;
  end;

  Row[RowIndex].Height := Result;
end;

function TNxCustomGrid6.CanAutoScroll: Boolean;
begin
  Result := True;
end;

function TNxCustomGrid6.CanCalculate(const Index: Integer): Boolean;
begin
  //TODO: Add Method
  Result := True;
end;

function TNxCustomGrid6.CanEdit(const ACol, ARow: Integer): Boolean;
begin
  Result := not FReadOnly;
end;

function TNxCustomGrid6.CanKeyLeaveEdit(Key: Word): Boolean;
begin
  Result := not Editing
    or (goArrowEndEditing in Options)
    or not (Key in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT]);
end;

function TNxCustomGrid6.CanSelect(const ACol, ARow: Integer): Boolean;
begin
  { Default }
  Result := False;

  { Valid Col and Row including InsertRow (-1) }
  if InRange(ACol, 0, Pred(ColCount))
    and InRange(ARow, -1, Pred(RowCount)) then
  begin
    Result := Columns[ACol].CanSelect;

    if ARow > -1 then
    begin
      Result := Result
        and Showing[ARow]
        and Cell[ACol, ARow].Enabled
        and Cell[ACol, ARow].Visible;

      if Assigned(ActiveView) then
      begin
        Result := Result and ActiveView.CanSelect(ACol, ARow);
      end;

    end;
  end;

  DoSelectQuery(ACol, ARow, Result);
end;

function TNxCustomGrid6.CanUpdate(Options: TNxUpdateOptions): Boolean;
begin
  Result := (FUpdateCount = 0) or (Options * FUpdateOptions <> []);
end;

function TNxCustomGrid6.CellExists(const ACol, ARow: Integer): Boolean;
begin
  Result := Columns.Exist(ACol) and HasRows and InRange(ARow, 0, Pred(RowCount));
end;

function TNxCustomGrid6.CellExists(const ACell: TPoint): Boolean;
begin
  Result := CellExists(ACell.X, ACell.Y);
end;

procedure TNxCustomGrid6.ChangeRowHeight(const Value: Integer);
begin
  FRowHeight := Value;
end;

function TNxCustomGrid6.CheckCell(const ACol, ARow: Integer): Boolean;
begin
  Result := CellExists(ACol, ARow);

  { Raise Exception if Cell is out of bounds }
  if not Result then
    raise EAccessViolation.CreateFmt(exCellNotExists, [ACol, ARow]);
end;

procedure TNxCustomGrid6.CMChildKey(var AMsg: TCMChildKey);
var
  Ref: IInterfaceComponentReference;
  DispatchKey: Boolean;
begin
  inherited;

  if Supports(FInplaceEdit, IInterfaceComponentReference, Ref) then
  begin
    { 10/23/11: If Child is FInplaceEdit then send KeyDown and
                stop further processing if FInplaceEdit is released
                within KeyDown (!) }
    if Ref.GetComponent = AMsg.Sender then
    begin
      case AMsg.CharCode of
        VK_TAB: DispatchKey := WantTabs;
        else DispatchKey := True;
      end;

      { Ask InplaceEdit first (!) }
      if DispatchKey and FInplaceEdit.CanDispatchKey(AMsg.CharCode)
        then KeyDown(AMsg.CharCode, []);

      if AMsg.CharCode = VK_F6 then RepeatValue;

      { 2/18/12: Potential problem with Tab key
                 and Button InplaceEdit's  }
      if AMsg.CharCode = VK_TAB then AMsg.Result := 1;

      { 10/22/11: Must be set in order to stop processing
                  if FInplaceEdit is nil (!) }
      if FInplaceEdit = nil then AMsg.Result := 1;
    end;
  end;
end;

procedure TNxCustomGrid6.CMDesignHitTest(var Message: TCMDesignHitTest);
begin
  { Click on Design Obj. }
  if Assigned(GetResponderAtPos(Point(Message.XPos, Message.YPos)))
    then Message.Result := 1
      else Message.Result := 0;
end;

procedure TNxCustomGrid6.CMFocusChanged(var Message: TCMFocusChanged);
begin
  inherited;
  if not Focused and not InplaceEditFocused then
    if goExitEndEditing in Options then EndEditing;
end;

procedure TNxCustomGrid6.CMFontChanged(var Message: TMessage);
var
  i: Integer;
begin
  inherited;
  for i := 0 to Pred(ColCount) do
  begin
    if Columns[i].ParentFont then Columns[i].Font := Font;
    if Columns[i].Header.ParentFont then Columns[i].Header.Font := Font;
    if Columns[i].Footer.ParentFont then Columns[i].Footer.Font := Font;
  end;
end;

procedure TNxCustomGrid6.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  if Assigned(ActiveView) and ActiveView.Enabled then
  begin
    ActiveView.MouseLeave;
  end;
end;

procedure TNxCustomGrid6.CMTextChanged(var Message: TMessage);
begin
  inherited;
  if Assigned(ActiveView) then
  begin
    if Caption <> '' then ActiveView.InvalidateCaption;
  end;
end;

constructor TNxCustomGrid6.Create(AOwner: TComponent);
begin
  inherited;
  FColumns := TNxColumns6.Create(Self);
  FColumns.OnAdd := DoColumnAdd;
  FColumns.OnChanged := DoColumnChanged;
  FColumns.OnFilter := DoColumnFilter;
  FColumns.OnRemove := DoColumnRemove;
  FColumns.OnResized := DoColumnResized;
  FColumns.OnSort := DoColumnSort;
  FColumns.OnUpdate := DoClumnsUpdate;

  { Set Fields }
  FActiveView := nil;
  FAlternatingRowColor := clMoneyGreen;
  FAlternatingRowColorOptions := TNxAlternatingRowColorsOptions.Create;
  FAlternatingRowColorOptions.OnChange := DoAlternatingRowColorOptionsChange;
  FAppearanceOptions := [aoHintIndicators, aoStyleColors];
  FAutoScroll := True;
  FAutoSelect := False;
  FCalculateOptions := [];
  FDesignerDelegate := nil;
  FEditing := False;
  FEditingCell := EmptyPoint;
  FFiltered := False;
  FFindMatchingOptions := moContain;
  FFindEndRow := 0;
  FFindOptions := [];
  FFindText := '';
  FFromSelected := -1;
  FHideFocus := False;
  FHideSelection := True;
  FHoverResponder := nil;
  FIgnoreEditing := False;
  FInactiveSelectionColor := clBtnFace;
  FInserting := False;
  FInsertSelected := False;
  FInvertSelected := False;
  FLastFoundRow := -1;
  FMultiSelect := False;
  FMultiSort := False;
  FOptions := [goArrowEndEditing, goExitEndEditing, goTabLeaveControl];
  FPrevHeight := 0;
  FPrevWidth := 0;
  FReadOnly := False;
  FRightClickSelect := True;
  FRightClickDeselect := True;
  FRowHeight := szDefaultRowHeight;
  FSearchBuffer := EmptyStr;
  FSearchBufferTimer := TTimer.Create(nil);
  FSearchBufferTimer.Enabled := False;
  FSearchBufferTimer.Interval := inSearchTimer;
  FSearchBufferTimer.OnTimer := DoSearchTimer;
  FSecondClickEditing := False;
  FSelectedCol := 0;
  FDesignerSelected := nil;
  FSelectedRow := -1;
  FSelectFullRow := False;
  FSelectionColor := clHighlight;
  FSelectionDirection := sdDown;
  FSelectionTextColor := clHighlightText;
  FSerialize := TNxGridSerialization.Create(Self);
  FState := [];
  FStyle := stNative;
  FUpdateCount := 0;
  FWantReturns := False;
  FWantTabs := False;
  FViews := TNxGridViews6.Create(Self);

  { Set Prop. }
  ParentColor := False;
  Color := clWindow;
  BorderSize := 1;

  Width := 320;
  Height := 180;

  { Initializations }
  CreateStylePaint;
end;

procedure TNxCustomGrid6.CreateParams(var Params: TCreateParams);
begin
  inherited;

  with Params do
  begin
    { Don't redraw on Resize }
		with WindowClass do Style := Style and not (CS_HREDRAW or CS_VREDRAW);
  end;
end;

procedure TNxCustomGrid6.CreateStylePaint;
begin
  { Destroy old Style (if RefCount allows ;) }
  FStylePaint := nil;

  { Create Obj. }
  case FStyle of
    stUserDefined: FStylePaint := TNxUserDefinedStylePaint.Create(Self);
    stNative: FStylePaint := TNxNativeGridPartStylePaint.Create(Self);
    stModern: FStylePaint := TNxModernGridPartStylePaint.Create(Self);
  end;

  AssignStylePaint;
end;

procedure TNxCustomGrid6.CreateWnd;
begin
  VertScrollBar.Max := 0;
  VertScrollBar.PageSize := 0;
  VertScrollBar.AutoHide := goAutoHideScrollBars in Options;
  inherited CreateWnd;
end;

procedure TNxCustomGrid6.DataChanged;
begin
  if uoRecount in Options then
  begin
    if Assigned(ActiveView) then
    begin
      ActiveView.Reset;

      RowsChanged;

      { Silent reset ScrollBar }
      VertScrollBar.Clear(False);
    end;
  end;
  if uoScrollBar in Options then UpdateScrollBars;
  if uoRepaint in Options then Invalidate;
end;

procedure TNxCustomGrid6.DeselectSelected;
var
  i: Integer;
begin
  if gtMultiSelected in FState then
  begin
    for i := 0 to Pred(RowCount) do Selected[i] := False;
    Exclude(FState, gtMultiSelected);
  end;
end;

procedure TNxCustomGrid6.DesignMouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Sender: INxDesignNotificationRecipient;
begin
  if Assigned(DesignerDelegate) then
  begin
    Sender := GetResponderAtPos(Point(X, Y));
    if Assigned(Sender) then
    begin
      DesignerDelegate.DesignNotification(Sender, NxTypes6.doSelect);
    end;
  end;
end;

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

end;

destructor TNxCustomGrid6.Destroy;
begin
  if Editing or Inserting then
  begin
    Columns[FEditingCell.X].InplaceEdit := nil;
  end;

  FInplaceEdit := nil;

  FActiveView := nil;

  { Auto-released }
//  FreeAndNil(FStylePaint);
  FStylePaint := nil;

  { Destroy Obj. }
  FreeAndNil(FAlternatingRowColorOptions);
  FreeAndNil(FColumns);
  FreeAndNil(FSerialize);
  FreeAndNil(FViews);

  FSearchBufferTimer.Free;

  inherited Destroy;
end;

procedure TNxCustomGrid6.DoAcceptEdit(ACol, ARow: Integer; var Text: WideString; var Accept,
  CanLeave: Boolean);
begin
  if Assigned(FOnAcceptEdit) then FOnAcceptEdit(Self, ACol, ARow, Text, Accept, CanLeave);
end;

procedure TNxCustomGrid6.DoAfterEdit(ACol, ARow: Integer; Text: WideString);
begin
  if Assigned(FOnAfterEdit) then FOnAfterEdit(Self, ACol, ARow, Text);
end;

procedure TNxCustomGrid6.DoAfterSort;
begin
  if Assigned(FOnAfterSort) then FOnAfterSort(Self);
end;

procedure TNxCustomGrid6.DoAlternatingRowColorOptionsChange(Sender: TObject);
begin
  Invalidate;
end;

procedure TNxCustomGrid6.DoBeforeEdit(ACol, ARow: Integer; var Accept: Boolean;
  var Text: WideString);
begin
  if Assigned(FOnBeforeEdit) then FOnBeforeEdit(Self, ACol, ARow, Accept, Text);
end;

procedure TNxCustomGrid6.DoBeforePostEdit(Cell: INxCell);
begin

end;

procedure TNxCustomGrid6.DoBeforeSelect(var ACol, ARow: Integer; Key: Word;
  Shift: TShiftState);
begin
  if Assigned(FOnBeforeSelect) then FOnBeforeSelect(Self, ACol, ARow, Key, Shift);
end;

procedure TNxCustomGrid6.DoBeginEditing;
begin

end;

procedure TNxCustomGrid6.DoCellClick(ACol, ARow: Integer; Button: TMouseButton);
begin
  if Assigned(FOnCellClick) then FOnCellClick(Self, ACol, ARow, Button);
end;

procedure TNxCustomGrid6.DoCellDblClick(ACol, ARow: Integer);
begin
  if Assigned(FOnCellDblClick) then FOnCellDblClick(Self, ACol, ARow);
end;

procedure TNxCustomGrid6.DoClumnsUpdate(Sender: TObject);
begin
  Invalidate;
end;

procedure TNxCustomGrid6.DoColumnAdd(Sender: TNxColumns6; Index: Integer);
begin
  if ActiveView <> nil then
  begin
    ActiveView.DoAddColumn;

    UpdateHorzScrollBar;
  end;
end;

procedure TNxCustomGrid6.DoColumnChanged(Sender: TNxColumn6; Area: TNxGridArea);
begin
  if Assigned(ActiveView) then
  begin
    ActiveView.RefreshColumn(Sender, Area);
  end;
end;

procedure TNxCustomGrid6.DoColumnRemove(Sender: TNxColumn6);
begin
  if Assigned(ActiveView) then
  begin
    ActiveView.Invalidate;

    UpdateScrollBars;
    UpdateInplaceEditor;
  end;
end;

procedure TNxCustomGrid6.DoColumnFilter(Sender: TObject);
begin
  Filter;
end;

procedure TNxCustomGrid6.DoColumnResized(Sender: TNxColumn6; Delta: Integer);
begin
  if Assigned(ActiveView) then
  begin
    ActiveView.Invalidate;

    UpdateScrollBars;
    UpdateInplaceEditor;
  end;
end;

procedure TNxCustomGrid6.DoColumnSort(Sender: TNxColumn6);
begin
  DoAfterSort;
end;

procedure TNxCustomGrid6.DoCSVGetValue(Sender: TObject; X, Y: Integer;
  var Value: WideString);
begin
  Value := Cells[X, Y];
end;

procedure TNxCustomGrid6.DoCSVSetValue(Sender: TObject; X, Y: Integer;
  Value: WideString);
begin
  Cells[X, Y] := Value;
end;

procedure TNxCustomGrid6.DoCustomDrawCell(ACol, ARow: Integer; CellRect: TRect;
  State: TNxCellPaintingState; var DefaultDrawing: Boolean);
begin
  if Assigned(FOnCustomDrawCell) then FOnCustomDrawCell(Self, ACol, ARow, CellRect, State, DefaultDrawing);
end;

procedure TNxCustomGrid6.DoDeselect(ACol, ARow: Integer);
begin
  if Assigned(FOnDeselect) then FOnDeselect(Self, ACol, ARow);
end;

procedure TNxCustomGrid6.DoEditEnter(ACol, ARow: Integer);
begin
  if Assigned(FOnEditEnter) then FOnEditEnter(Self, ACol, ARow);
end;

procedure TNxCustomGrid6.DoEditExit(ACol, ARow: Integer);
begin
  if Assigned(FOnEditExit) then FOnEditExit(Self, ACol, ARow);
end;

procedure TNxCustomGrid6.DoFooterCalculated(const ACol: Integer; var Value: Double);
begin
  if Assigned(FOnFooterCalculated) then FOnFooterCalculated(Self, ACol, Value);
end;

procedure TNxCustomGrid6.DoGetInplaceEdit(ACol, ARow: Integer; var InplaceEdit: INxInplaceEdit);
begin
  if Assigned(FOnGetInplaceEdit) then FOnGetInplaceEdit(Self, ACol, ARow, InplaceEdit);
end;

procedure TNxCustomGrid6.DoInplaceEditBounds(ACol, ARow: Integer; Component: TComponent; var EditRect: TRect);
begin
  if Assigned(FOnInplaceEditBounds) then FOnInplaceEditBounds(Self, ACol, ARow, Component, EditRect);
end;

procedure TNxCustomGrid6.DoInplaceEditChange(Sender: TObject);
begin
  if Assigned(FOnInplaceEditChange) then FOnInplaceEditChange(Self);
end;

procedure TNxCustomGrid6.DoInplaceEditInsert(ACol, ARow: Integer; Component: TComponent);
begin
  if Assigned(FOnInplaceEditInsert) then FOnInplaceEditInsert(Self, ACol, ARow, Component);
end;

procedure TNxCustomGrid6.DoMeasureRowHeight(Index: Integer; var RowHeight: Integer);
begin
  if Assigned(FOnMeasureRowHeight) then FOnMeasureRowHeight(Self, Index, RowHeight);
end;

function TNxCustomGrid6.DoMouseWheelDown(Shift: TShiftState;
  MousePos: TPoint): Boolean;
var
  ScrollBar: INxScrollBar;
begin
  Result := inherited DoMouseWheelDown(Shift, MousePos);

  if Result
    and not Editing then
  begin
    { Default }
    ScrollBar := nil;

    if VertScrollBar.Showing
      then ScrollBar := VertScrollBar
        else if HorzScrollBar.Showing
              then ScrollBar := HorzScrollBar;

    { Do Scroll }
    if Assigned(ScrollBar) then
      if ssCtrl in Shift
        then ScrollBar.PageDown
          else ScrollBar.Next;
  end;

end;

function TNxCustomGrid6.DoMouseWheelUp(Shift: TShiftState;
  MousePos: TPoint): Boolean;
var
  ScrollBar: INxScrollBar;
begin
  Result := inherited DoMouseWheelDown(Shift, MousePos);

  if Result
    and not Editing then
  begin
    { Default }
    ScrollBar := nil;

    if VertScrollBar.Showing
      then ScrollBar := VertScrollBar
        else if HorzScrollBar.Showing
              then ScrollBar := HorzScrollBar;

    { Do Scroll }
    if Assigned(ScrollBar) then
      if ssCtrl in Shift
        then ScrollBar.PageUp
          else ScrollBar.Prior;
  end;

end;

procedure TNxCustomGrid6.DoSearchTimer(Sender: TObject);
begin
  FSearchBufferTimer.Enabled := False;
  FSearchBuffer := EmptyStr;
end;

procedure TNxCustomGrid6.DoSelect(ACol, ARow: Integer);
begin
  if Assigned(FOnSelect) then FOnSelect(Self, ACol, ARow);
end;

procedure TNxCustomGrid6.DoSelectionChanged(ACol, ARow: Integer);
begin
  if Assigned(FOnSelectionChanged) then FOnSelectionChanged(Self, ACol, ARow);
end;

procedure TNxCustomGrid6.DoSelectQuery(ACol, ARow: Integer;
  var Accept: Boolean);
begin
  if Assigned(FOnSelectQuery) then FOnSelectQuery(Self, ACol, ARow, Accept);
end;

procedure TNxCustomGrid6.DoSortQuery(Index: Integer; SortKind: TNxSortKind;
  var Accept: Boolean);
begin
  if Assigned(FOnSortQuery) then FOnSortQuery(Self, Index, SortKind, Accept);
end;

procedure TNxCustomGrid6.DoViewChange;
begin
  if Assigned(FOnViewChange) then FOnViewChange(Self);
end;

function TNxCustomGrid6.EditCell(ACol, ARow: Integer;
  EditText: WideString; ForceEditing: Boolean): Boolean;
begin
  Result := InternalEditCell(ACol, ARow, EditText, ForceEditing, True);
end;

function TNxCustomGrid6.EditCell(ACol, ARow: Integer; Key: WideChar): Boolean;
begin
  Result := InternalEditCell(ACol, ARow, Key, False, False);
end;

function TNxCustomGrid6.EditCell(Location: TPoint; Value: WideString): Boolean;
begin
  Result := EditCell(Location.X, Location.Y, Value);
end;

function TNxCustomGrid6.EditSelected: Boolean;
begin
  Result := EditCell(SelectedCol, SelectedRow);
end;

function TNxCustomGrid6.EndEditing(AssignEditing: Boolean): Boolean;
var
  FocusBack: Boolean;
begin
  { Default result }
  Result := False;

  { CanLeave is true }
  FCanLeaveEdit := True;

  { Already ending? }
  if gtEditingEnd in FState
    then Exit;

  try
    Include(FState, gtEditingEnd);

    if Assigned(FInplaceEdit) then
    begin

      FocusBack := FInplaceEdit.Focused;

      if FInserting then
      begin

        { Try to assign }
        if AssignEditing then Result := Self.AssignEditing;

        { Can leave? }
        if FCanLeaveEdit then
        begin
          Columns[FEditingCell.X].EndEditing;

          { Already destroyed in EndEditing }
          FInplaceEdit := nil;

          FInserting := False;
          FEditingCell := EmptyPoint;

          { Set Focus back }
          if FocusBack and CanFocus and CanFocusParent
            then SetFocus;
        end;
      end;

      if FEditing then
      begin
        { Cell is deleted? }
        if not CellExists(FEditingCell)
          then Exit;

        { Try to assign }
        if AssignEditing then Self.AssignEditing;

        { Can leave? }
        if FCanLeaveEdit then
        begin
          FColumns[FEditingCell.X].EndEditing;

          { Already destroyed in EndEditing }
          FInplaceEdit := nil;

          FEditing := False;

          { Set Focus back }
          if FocusBack and CanFocus and CanFocusParent
            then SetFocus;

          { Trigger event }
          DoEditExit(FEditingCell.X, FEditingCell.Y);

          FEditingCell := EmptyPoint;
        end;
      end;

    end; { Assigned }

  finally
    Exclude(FState, gtEditingEnd);
  end;

  Result := FCanLeaveEdit;
end;

procedure TNxCustomGrid6.EndUpdate(Update: Boolean = True;
  Immediate: Boolean = False);
begin
  Dec(FUpdateCount);

  { Finished Updating? }
  if (Update and (FUpdateCount = 0)) or Immediate then
  begin

    if not (uoRecalculate in FUpdateOptions) and GetAutoCalculate
      then Recalculate;

    if Assigned(ActiveView) then
    begin
      if not (uoRecount in FUpdateOptions) then
      begin
        { Recount FirstVisible & LastVisible }
        Recount;

        { Recount LastFixedRow }
        ActiveView.Recount;
      end;

      { Refresh }
      ActiveView.Invalidate;
    end;

    if not (uoScrollBar in FUpdateOptions) then
    begin
      VertScrollBar.Unlock;
      UpdateScrollBars;
    end;
  end;
end;

procedure TNxCustomGrid6.Filter;
begin

  if Assigned(ActiveView) then
  begin
    { Refresh Data only }
    ActiveView.Invalidate;

    { Scroll to top, release Captured view etc. }
    ActiveView.Reset; { ToDo: Maybe to call it Clear? }

    { Scroll to Top, quietly }
    VertScrollBar.Clear;

    UpdateScrollBars;
  end;

end;

function TNxCustomGrid6.FindNext: Integer;
begin
  Result := FindText(FFindCols, FFindText, Succ(FLastFoundRow), FFindEndRow,
    FFindOptions, FFindMatchingOptions);
end;

function TNxCustomGrid6.FindText(Cols: array of Integer; Text: WideString;
  StartRow, EndRow: Integer; Options: TNxSearchOptions;
  MatchingOptions: TNxSearchMatchingOptions): Integer;
var
  a: Integer;

  function HasMatch(Content: WideString): Boolean;
  begin
    if soCaseSensitive in Options then
    begin

      case MatchingOptions of
        moBeginWith: Result := WideCompareStr(LeftStr(Content, Length(Text)), Text) = 0;
        moExactMatch: Result := WideCompareStr(Content, Text) = 0;
        else Result := Pos(Text, Content) > 0;
      end;

    end else
    begin

      case MatchingOptions of
        moBeginWith: Result := WideCompareText(LeftStr(Content, Length(Text)), Text) = 0;
        moExactMatch: Result := WideCompareText(Content, Text) = 0
        else Result := Pos(WideLowerCase(Text), WideLowerCase(Content)) > 0;
      end;

    end;

  end;

  function LocateText(StartIndex, EndIndex: Integer): Boolean;
  var
    i, j: Integer;
  begin
    Result := False;

    for i := StartIndex to EndIndex do
    begin

      if Row[i].Visible or (soIncludeInvisible in Options) then
      begin

        for j := Low(Cols) to High(Cols) do
        begin

          if HasMatch(Cell[Cols[j], i].AsString) then
          begin
            Result := True;
            FLastFoundRow := i;
            Exit;
          end;

        end;

      end;

    end;

  end;

begin
  { Default, not found }
  FLastFoundRow := -1;

  if not LocateText(StartRow, EndRow)
    and (soRestartAfterEnd in Options)
      then LocateText(0, Pred(StartRow));

  { Save for FindNext }
  SetLength(FFindCols, Length(Cols));
  for a := Low(Cols) to High(Cols) do
  begin
    FFindCols[a] := Cols[a];
  end;

  FFindEndRow := EndRow;
  FFindMatchingOptions := MatchingOptions;
  FFindOptions := Options;
  FFindText := Text;

  Result := FLastFoundRow;
end;

function TNxCustomGrid6.Focused: Boolean;
begin
  Result := inherited Focused
    or ((Assigned(FInplaceEdit) and FInplaceEdit.Focused));
end;

function TNxCustomGrid6.GetActiveViewIndex: Integer;
begin
  Result := -1;
  if Assigned(ActiveView) then Result := ActiveView.Index;
end;

function TNxCustomGrid6.GetAlternatingRowColor: TColor;
begin
  Result := FAlternatingRowColor;
end;

function TNxCustomGrid6.GetAlternatingRowColorOptions: TNxAlternatingRowColorsOptions;
begin
  Result := FAlternatingRowColorOptions;
end;

function TNxCustomGrid6.GetAnchorCell(const ACol, ARow: Integer): TPoint;
begin
  if Cell[ACol, ARow].Visible then Result := Point(ACol, ARow) else
  begin

  end;
end;

function TNxCustomGrid6.GetAppearanceOptions: TNxAppearanceOptions;
begin
  Result := FAppearanceOptions;
end;

function TNxCustomGrid6.GetAutoCalculate: Boolean;
begin
  Result := False;
end;

function TNxCustomGrid6.GetCanvas: TCanvas;
begin
  Result := Canvas;
end;

function TNxCustomGrid6.GetCaption: TCaption;
begin
  Result := Caption;
end;

function TNxCustomGrid6.GetCellLocation(ACol, ARow: Variant): TPoint;
begin

  if CompareText(ARow, 'First') = 0 then Result.Y := 0
  else if CompareText(ARow, 'Last') = 0 then Result.Y := Pred(RowCount)
  else if CompareText(ARow, 'Selected') = 0 then Result.Y := SelectedRow
  else try
    Result.Y := ARow;
  except
    raise Exception.CreateFmt('Invalid Rowname '#39'%s'#39' for '#39'%s:%s'#39'.', [VarToStr(ARow), Self.ClassName, Self.Name]);
  end;

  if CompareText(ACol, 'First') = 0 then Result.X := 0
  else if CompareText(ACol, 'Last') = 0 then Result.X := Pred(Columns.Count)
  else if CompareText(ACol, 'Selected') = 0 then Result.X := SelectedCol
  else if Columns.ItemBy[ACol] <> nil then Result.X := Columns.ItemBy[ACol].Index
  else try
    Result.X := ACol;
  except
    raise Exception.CreateFmt('Invalid Columnname '#39'%s'#39' for '#39'%s:%s'#39'.', [VarToStr(ACol), Self.ClassName, Self.Name]);
  end;

end;

function TNxCustomGrid6.GetCells(ACol, ARow: Integer): WideString;
begin
  { If Cell not exist, AV occur }
  Result := Cell[ACol, ARow].AsString;
end;

function TNxCustomGrid6.GetChildOwner: TComponent;
begin
  Result := nil; { Streaming: Very Important }
end;

procedure TNxCustomGrid6.GetChildren(Proc: TGetChildProc; Root: TComponent);
var
  i: Integer;
  Ref: IInterfaceComponentReference;
begin
	{ Save Views as Childrens into DFM }
  for i := 0 to Pred(Views.Count) do
  begin
    if Supports(Views[i], IInterfaceComponentReference, Ref) then
    begin
      Proc(Ref.GetComponent);
    end;
  end;

	{ Save Columns as Childrens into DFM }
  for i := 0 to Pred(Columns.Count) do
  begin
    if Supports(Columns[i], IInterfaceComponentReference, Ref) then
    begin
      Proc(Ref.GetComponent);
    end;
  end;
end;

function TNxCustomGrid6.GetColCount: Integer;
begin
  Result := Columns.Count;
end;

function TNxCustomGrid6.GetColor: TColor;
begin
  Result := inherited Color;
end;

function TNxCustomGrid6.GetColumns: TNxColumns6;
begin
  Result := FColumns;
end;

function TNxCustomGrid6.GetContentIndent: TSize;
begin
  Result.cx := 0;
  Result.cy := 0;
end;

function TNxCustomGrid6.GetControlName: string;
begin
  Result := 'NextGrid';
end;

function TNxCustomGrid6.GetDisplayText(Cell: INxCell): WideString;
begin
  Result := Columns[Cell.ColIndex].GetDisplayText(Cell, Cell.ColIndex, Cell.RowIndex);
end;

function TNxCustomGrid6.GetEditingCell: TPoint;
begin
  Result := FEditingCell;
end;

function TNxCustomGrid6.GetFetchedRowCount: Integer;
begin
  Result := RowCount;
end;

function TNxCustomGrid6.GetFirstFetchedRow: Integer;
begin
  Result := FirstVisibleRow;
end;

function TNxCustomGrid6.GetFont: TFont;
begin
  Result := Font;
end;

function TNxCustomGrid6.GetInactiveSelectionColor: TColor;
begin
  Result := FInactiveSelectionColor;
end;

function TNxCustomGrid6.GetInplaceEdit: INxInplaceEdit;
begin
  Result := FInplaceEdit;
end;

function TNxCustomGrid6.GetInsertSelected: Boolean;
begin
  Result := FInsertSelected;
end;

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

function TNxCustomGrid6.GetInvertSelected: Boolean;
begin
  Result := FInvertSelected;
end;

function TNxCustomGrid6.GetItemRect(Index: Integer): TRect;
begin
  if Assigned(ActiveView) then Result := ActiveView.GetItemRect(Index);
end;

function TNxCustomGrid6.GetLastAddedColumn: TNxColumn6;
begin
  Result := FColumns.LastAdded;
end;

function TNxCustomGrid6.GetMultiSelect: Boolean;
begin
  Result := FMultiSelect;
end;

function TNxCustomGrid6.GetMultiSort: Boolean;
begin
  Result := FMultiSort;
end;

function TNxCustomGrid6.GetOwnerRow: INxRow;
begin
  Result := nil;
end;

function TNxCustomGrid6.GetResponderAtPos(Location: TPoint): INxDesignNotificationRecipient;
var
  Pos: TPoint;
  FontHeight, i: Integer;
  TextSize, BoxSize: TSize;
  HitRect: TRect;
  S: TComponentName;
  Responder: INxDesignNotificationRecipient;
begin
  { Nothing to click }
  Result := nil;

  { Start }
  Pos := Point(0, 0);

  { Assign Font }
  Canvas.Font.Assign(Font);

  FontHeight := GetTextMetric(Canvas).tmAscent + pdStandard;

  TextSize := GetTextSize(Canvas, Name, True);

  with Canvas do
  begin
    { Shift inside View }
    if Assigned(ActiveView)
      then OffsetPoint(Pos, ActiveView.DataRect.TopLeft);

    OffsetPoint(Pos, spGrid, spGrid);

    { Control }
    HitRect := Bounds(Pos.X, Pos.Y, TextSize.cx + 8 * 2, FontHeight + 6 * 2);
    BoxSize.cy := RectHeight(HitRect);

    if PtInRect(HitRect, Location) then
    begin
      Result := INxDesignControl(Self);

      { Done }
      Exit;
    end;

    { Shift beyond Arrow }
    Pos.X := HitRect.Right;

    if Views.Count > 0 then
    begin
      Inc(Pos.X, 23);

      BoxSize.cx := 0;

      { Calc. Widest }
      for i := 0 to Pred(Views.Count) do
      begin
        S := IfThen(Views[i].Name = EmptyStr, stUnnamed, Views[i].Name);

        TextSize := GetTextSize(Canvas, S, True);

        if TextSize.cx > BoxSize.cx
          then BoxSize.cx := TextSize.cx;
      end;

      HitRect := Bounds(Pos.X, Pos.Y, BoxSize.cx + 8 * 2 + 16 + pdDouble, BoxSize.cy);

      for i := 0 to Pred(Views.Count) do
      begin
        S := IfThen(Views[i].Name = EmptyStr, stUnnamed, Views[i].Name);

        if PtInRect(HitRect, Location) then
        begin
          if Supports(Views[i], INxDesignNotificationRecipient, Responder) then
          begin
            Result := Responder;

            Exit;
          end;
        end;

        OffsetRect(HitRect, 0, BoxSize.cy + 4)
      end;
    end;

    { Editor button }
    Pos.X := HitRect.Right + pdDouble;

    HitRect := Bounds(Pos.X, Pos.Y, BoxSize.cy, BoxSize.cy);

    if PtInRect(HitRect, Location) then
    begin
      Result := INxEntityDesignRespoder(TNxEntityDesignResponder.Create);
      INxEntityDesignRespoder(Result).Index := 1;
    end;

  end;

end;

function TNxCustomGrid6.GetResponderRect(AResponder: INxDesignNotificationRecipient): TRect;
var
  Pos: TPoint;
  FontHeight, i: Integer;
  TextSize, BoxSize: TSize;
  HitRect: TRect;
  ViewName: TComponentName;
  Intf: INxDesignNotificationRecipient;
begin
  { Empty Rect }
  Result := Bounds(0, 0, 0, 0);

  { Start }
  Pos := Point(0, 0);

  { Assign Font }
  Canvas.Font.Assign(Font);

  FontHeight := GetTextMetric(Canvas).tmAscent + pdStandard;

  TextSize := GetTextSize(Canvas, Name, True);

  with Canvas do
  begin
    { Shift inside View }
    if Assigned(ActiveView)
      then OffsetPoint(Pos, ActiveView.DataRect.TopLeft);

    OffsetPoint(Pos, spGrid, spGrid);

    { Control }
    HitRect := Bounds(Pos.X, Pos.Y, TextSize.cx + 8 * 2, FontHeight + 6 * 2);

    Supports(Self, INxPersistentDesignResponder, Intf);

    if AResponder = Intf then
    begin
      Result := HitRect;

      { Done }
      Exit;
    end;

    { Shift beyond Arrow }
    Pos.X := HitRect.Right;
    Inc(Pos.X, 23);

    BoxSize.cx := 0;

    { Calc. Widest }
    for i := 0 to Pred(Views.Count) do
    begin
      ViewName := IfThen(Views[i].Name = EmptyStr, stUnnamed, Views[i].Name);

      TextSize := GetTextSize(Canvas, ViewName, True);

      if TextSize.cx > BoxSize.cx
        then BoxSize.cx := TextSize.cx;
    end;

    BoxSize.cy := HitRect.Bottom - HitRect.Top;

    HitRect := Bounds(Pos.X, Pos.Y, BoxSize.cx + 8 * 2 + 16 + pdDouble, BoxSize.cy);

    for i := 0 to Pred(Views.Count) do
    begin
      ViewName := IfThen(Views[i].Name = EmptyStr, stUnnamed, Views[i].Name);

      Supports(Views[i], INxPersistentDesignResponder, Intf);

      if AResponder = Intf then
      begin
        Result := HitRect;

        Exit;
      end;

      OffsetRect(HitRect, 0, BoxSize.cy + 4)
    end;

  end;

end;

function TNxCustomGrid6.GetRightClickSelect: Boolean;
begin
  Result := FRightClickSelect;
end;

function TNxCustomGrid6.GetRowHeight: Integer;
begin
  Result := FRowHeight;
end;

function TNxCustomGrid6.GetRowSize(Index: Integer): Integer;
begin
  Result := Row[Index].Height;
  DoMeasureRowHeight(Index, Result);
end;

function TNxCustomGrid6.GetScrollBars: TScrollStyle;
begin
  Result := inherited GetScrollBars;
end;

function TNxCustomGrid6.GetHideFocus: Boolean;
begin
  Result := FHideFocus;
end;

function TNxCustomGrid6.GetHideSelection: Boolean;
begin
  Result := FHideSelection;
end;

function TNxCustomGrid6.GetHighlighted(ACol, ARow: Integer): Boolean;
begin
  case SelectFullRow of
    False: Result := (ACol = SelectedCol) and (ARow = SelectedRow);
    else
    begin
      Result := ARow = SelectedRow;

      if MultiSelect
        and RowExists(ARow) then
          Result := Selected[ARow];

      if InvertSelected then
        Result := Result and not (ACol = SelectedCol);
    end;
  end;
end;

function TNxCustomGrid6.GetSecondClickEditing: Boolean;
begin
  Result := FSecondClickEditing;
end;

function TNxCustomGrid6.GetSelected(Index: Integer): Boolean;
begin
  Result := False;
end;

function TNxCustomGrid6.GetSelectedLocation: TPoint;
begin
  Result := Point(SelectedCol, SelectedRow);
end;

function TNxCustomGrid6.GetSelectedCol: Integer;
begin
  Result := FSelectedCol;
end;

function TNxCustomGrid6.GetSelectedCount: Integer;
var
  i: Integer;
begin
  Result := 0;
	for i := 0 to Pred(RowCount) do if Selected[i] then Inc(Result);
end;

function TNxCustomGrid6.GetSelectedRow: Integer;
begin
  Result := FSelectedRow;
end;

function TNxCustomGrid6.GetSelectFullRow: Boolean;
begin
  Result := FSelectFullRow;
end;

function TNxCustomGrid6.GetSelectionColor: TColor;
begin
  Result := FSelectionColor;
end;

function TNxCustomGrid6.GetSelectionKey: Word;
begin
  Result := FSelectionKey;
end;

function TNxCustomGrid6.GetSelectionTextColor: TColor;
begin
  Result := FSelectionTextColor;
end;

function TNxCustomGrid6.GetStylePaint: INxGridStylePaint;
begin
  Result := FStylePaint;
end;

function TNxCustomGrid6.GetVersion: string;
begin
  Result := vrNextGrid;
end;

function TNxCustomGrid6.InsertCell(Index: Integer;
  InsertText: WideString): Boolean;
var
  CanInsert: Boolean;
  EditRect: TRect;
begin
  { Default Val. }
  Result := False;

  EndEditing;

  if Columns.Check(Index) and Assigned(ActiveView) then
  begin
    CanInsert := True;

    { Event Trigger }
//    DoBeforeEdit(ACol, ARow, CanInsert);

    if CanInsert and Columns[Index].CanInsert then
    begin

      FInplaceEdit := nil;

      { Event }
      DoGetInplaceEdit(Index, -1, FInplaceEdit);

      if Assigned(FInplaceEdit) then Columns[Index].InplaceEdit := FInplaceEdit else
      begin
        { Create InplaceEdit & Set Prop. }
        Columns[Index].BeginEditing;

        FInplaceEdit := Columns[Index].InplaceEdit;
      end;

      { Note: Even Columns without InplaceEdit may have
              one attached }
      if Assigned(FInplaceEdit) then
      begin
        if InsertText = EmptyStr then InsertText := Columns[Index].GetEditText(Columns[Index].InsertValue, Index, -1);

        FEditingCell := Point(Index, -1);

        // TODO: Add GetEditRect()
        EditRect := ActiveView.GetCellRect(Index);

        { Shrink EditRect }
        Columns[Index].AdjustEditRect(EditRect);

        try
          FInplaceEdit.Hide;
          FInplaceEdit.Parent := Self;

          FInplaceEdit.Text := InsertText;

          { Set BorderStyle, AutoSize etc. }
          FInplaceEdit.BeginEdit;

          { Note: Turn off AutoSize first }
          FInplaceEdit.SetBounds(EditRect.Left, EditRect.Top, EditRect.Right - EditRect.Left, EditRect.Bottom - EditRect.Top);

          FInplaceEdit.Show;
          FInplaceEdit.SetFocus;

          FInserting := True;

          InsertSelected := True;
        except
          { Failed }
          Exit;
        end;

        { Editing Start }
        Result := True;
      end;
    end;
  end;
end;

procedure TNxCustomGrid6.IgnoreEditing;
begin
  FIgnoreEditing := True;
end;

function TNxCustomGrid6.InplaceEditFocused: Boolean;
begin
  Result := Assigned(FInplaceEdit) and FInplaceEdit.Focused;
end;

function TNxCustomGrid6.InsertCell(Index: Integer; Key: WideChar): Boolean;
var
  CanInsert: Boolean;
  EditRect: TRect;
  InsertText: WideString;
begin
  { Default Val. }
  Result := False;

  EndEditing;

  if Columns.Check(Index) and Assigned(ActiveView) then
  begin
    CanInsert := True;

    InsertText := Key;

    { Event Trigger }
    DoBeforeEdit(Index, -1, CanInsert, InsertText);

    if CanInsert and Columns[Index].CanInsert then
    begin
      { Create InplaceEdit & Set Prop. }
      Columns[Index].BeginEditing;

      FInplaceEdit := Columns[Index].InplaceEdit;

      { Note: Even Columns without InplaceEdit may have
              one attached }
      if Assigned(FInplaceEdit) then
      begin
        FEditingCell := Point(Index, -1);

        EditRect := ActiveView.GetCellRect(Index);

        { Shrink EditRect }
        Columns[Index].AdjustEditRect(EditRect);

        try
          FInplaceEdit.Hide;
          FInplaceEdit.Parent := Self;

          FInplaceEdit.Text := InsertText;

          { Set BorderStyle, AutoSize etc. }
          FInplaceEdit.BeginEdit(Key);

          { Note: Turn off AutoSize first }
          FInplaceEdit.SetBounds(EditRect.Left, EditRect.Top, EditRect.Right - EditRect.Left, EditRect.Bottom - EditRect.Top);

          FInplaceEdit.Show;
          FInplaceEdit.SetFocus;

          FInserting := True;

          InsertSelected := True;
        except
          { Failed }
          Exit;
        end;

        { Editing Start }
        Result := True;
      end;
    end;
  end;
end;

function TNxCustomGrid6.InternalEditCell(ACol, ARow: Integer; EditText: WideString;
  ForceEditing, SelectText: Boolean): Boolean;
var
  CanEdit: Boolean;
  ACell: INxBaseCell;
  EditRect: TRect;
  Component: TComponent;
  ComponentReference: IInterfaceComponentReference;
begin
  { Default Val. }
  Result := False;

  { May be set inside KeyDown or MouseDown
    via IgnoreEditing }
  if FIgnoreEditing then
  begin
    FIgnoreEditing := False;

    Exit;
  end;

  if IsEqual(Point(ACol, ARow), FEditingCell)
    then Exit;

  EndEditing;

  if CheckCell(ACol, ARow) and Assigned(ActiveView) then
  begin
    ACell := Cell[ACol, ARow];

    Columns[ACol].DoSetCell(ACol, ARow, ACell);

    CanEdit := Self.CanEdit(ACol, ARow);

    { If EditText is not set, take Cell's value }
    if EditText = '' then EditText := Columns[ACol].GetEditText(ACell, ACol, ARow);

    { Event Trigger }
    DoBeforeEdit(ACol, ARow, CanEdit, EditText);

    if (CanEdit and Columns[ACol].CanEdit) or ForceEditing then
    begin
      FInplaceEdit := nil;

      { Trigger event }
      DoGetInplaceEdit(ACol, ARow, FInplaceEdit);

      if Assigned(FInplaceEdit) then Columns[ACol].InplaceEdit := FInplaceEdit else
      begin
        { Create InplaceEdit & Set Properties (Font, etc. ) }
        Columns[ACol].BeginEditing;

        FInplaceEdit := Columns[ACol].InplaceEdit;
      end;

      { Note: Even Col without own InplaceEdit
              can have one attached by property,
              or event }
      if Assigned(FInplaceEdit) then
      begin
        FEditingCell := Point(ACol, ARow);

        { Editing & Selected cell need to be equal }
        if not PointsEqual(FEditingCell, SelectedLocation)
          then SelectedLocation := FEditingCell;

        EditRect := ActiveView.GetCellRect(ACol, ARow);

        { Update Col's View }
        ActiveView.UpdateCellView(ACol, ARow, EditRect);

        { Shrink EditRect }
        Columns[ACol].AdjustEditRect(EditRect);

        try
          FInplaceEdit.Hide;
          FInplaceEdit.Parent := Self;

          Component := nil;
          if Supports(InplaceEdit, IInterfaceComponentReference, ComponentReference) then
          begin
            Component := ComponentReference.GetComponent;
          end;

          { Trigger event }
          DoInplaceEditInsert(ACol, ARow, Component);

          { Set BorderStyle, AutoSize etc. }

          if SelectText then
          begin
            FInplaceEdit.Text := EditText;
            FInplaceEdit.BeginEdit;
          end
          else FInplaceEdit.BeginEdit(EditText[1]);

          FInplaceEdit.SetEditPadding(1, 1);

          { Trigger event }
          DoInplaceEditBounds(ACol, ARow, Component, EditRect);

          { Note: Turn off AutoSize first }
          FInplaceEdit.SetBounds(EditRect.Left, EditRect.Top, EditRect.Right - EditRect.Left, EditRect.Bottom - EditRect.Top);

          FInplaceEdit.Show;
          FInplaceEdit.SetFocus;

          FInplaceEdit.OnChange := DoInplaceEditChange;

          FEditing := True;

          { Trigger event }
          DoEditEnter(FEditingCell.X, FEditingCell.Y);

          DoBeginEditing;
        except
          { Failed }
          Exit;
        end;

        { Editing Start }
        Result := True;

      end; { Assigned }

    end;
  end;
end;

function TNxCustomGrid6.IsIntegralHeight: Boolean;
begin
  Result := False;
end;

function TNxCustomGrid6.IsSelectionValid: Boolean;
begin
  Result := RowExists(SelectedRow) and Columns.Exist(SelectedCol);
end;

function TNxCustomGrid6.IsUpdating: Boolean;
begin
  Result := FUpdateCount > 0;
end;

function TNxCustomGrid6.IsVirtual: Boolean;
begin
  Result := True;
end;

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

  case Key of
    VK_PRIOR..VK_DOWN, VK_RETURN, VK_TAB: FSelectionKey := Key;
  end;

  if Assigned(ActiveView)
    and ActiveView.Enabled then
  case Key of
    VK_F2:
      if InsertSelected then InsertCell(SelectedCol)
      else if HasRows then EditCell(SelectedCol, SelectedRow);
    VK_TAB: TabByColumn(Shift, True);
    VK_RETURN:
    begin
      if Inserting then
      begin
        { AddInsertRow call EndEditing }
        if InsertSelected then AddInsertRow;
      end
      else if Editing then
      begin
        if EndEditing then
          if InsertSelected then AddInsertRow else
            case SelectionDirection of
              sdUp: MoveByRow(-1, Shift);
              sdDown: MoveByRow(1, Shift);
              sdLeft: TabByColumn([ssShift], goTabLeaveControl in Options);
              sdRight: TabByColumn([], goTabLeaveControl in Options);
            end;
      end
      else if SelectionDirection = sdNone then EditCell(SelectedCol, SelectedRow);
    end;
    VK_ESCAPE: EndEditing(False);
    else
    begin
      (ActiveView as INxInteract).KeyDown(Key, Shift);
    end;
  end;
end;

procedure TNxCustomGrid6.KeyPress(var Key: Char);

  function FindStr(St: string; FromPos, ToPos: Integer): Boolean;
  var
    i: Integer;
    S: WideString;
  begin
    { Not found }
    Result := False;

    for i := FromPos to ToPos do
    begin
      S := Cells[Columns.SearchingColumn.Index, i];

      if St <> EmptyStr then
        if LeftStr(WideUpperCase(S), Length(St)) = WideUpperCase(St) then
        begin
          SelectedRow := i;

          { Found, stop }
          Result := True;

          Exit;
        end;

    end;

  end;

var
  sto: WideString;
begin
  inherited;
  if Key = #9 then Exit;
  if Key = #13 then Exit;

  if Assigned(ActiveView) and ActiveView.Enabled then
    if InsertSelected and ActiveView.ShowInsertRow
      then InsertCell(SelectedCol, Key)
      else
        if CellExists(SelectedLocation)
          then if not EditCell(SelectedCol, SelectedRow, Key) and Assigned(Columns.SearchingColumn) then
          begin
            { Add into Buffer }
            FSearchBuffer := FSearchBuffer + Key;

            FSearchBufferTimer.Enabled := False;
            FSearchBufferTimer.Enabled := True;

            Sto := FSearchBuffer;

            if not FindStr(Sto, SelectedRow, Pred(RowCount)) then
              if not FindStr(Sto, 0, Pred(SelectedRow)) then
              begin
                FSearchBuffer := EmptyStr;
                FindStr(Key, 0, Pred(RowCount))
              end;

          end;

end;

procedure TNxCustomGrid6.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited;
  FSelectionKey := 0;

  if Assigned(ActiveView)
    and ActiveView.Enabled
    and not FEditing then
  begin
    (ActiveView as INxInteract).KeyUp(Key, Shift);
  end;
end;

function TNxCustomGrid6.HasCols: Boolean;
begin
  Result := Columns.Count > 0;
end;

function TNxCustomGrid6.HasRows: Boolean;
begin
  Result := RowCount > 0;
end;

function TNxCustomGrid6.MeasureCellSize(const ACol, ARow: Integer): TSize;
begin

end;

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

  if csDesigning in ComponentState then
  begin

    { Design hit-test }
    DesignMouseDown(Button, Shift, X, Y);

  end else
  begin

    { Running hit-test }
    if not Focused then SetFocus;

    if Assigned(ActiveView) and ActiveView.Enabled then
    begin
      { Send to ActiveView }
      ActiveView.MouseDown(Button, Shift, X, Y);
    end;
  end;
end;

procedure TNxCustomGrid6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if Assigned(ActiveView) and ActiveView.Enabled then
  begin
    { Send to ActiveView }
    ActiveView.MouseMove(Shift, X, Y);
  end;
end;

procedure TNxCustomGrid6.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if Assigned(ActiveView) and ActiveView.Enabled then
  begin
    { Send to ActiveView }
    ActiveView.MouseUp(Button, Shift, X, Y);
  end;
end;

///<summary>Move selection by number of columns</summary>
procedure TNxCustomGrid6.MoveByColumn(Distance: Integer; Shift: TShiftState);
var
  Col, Count, Pos: Integer;
begin
  Count := 0;

  { Default }
  Col := SelectedCol;

  { Current }
  Pos := Columns[SelectedCol].Position;

  if Distance > 0 then
  begin

    while (Count < Distance) and (Pos < Pred(Columns.Count)) do
    begin
      Inc(Pos);

      Col := Columns.PositionItem[Pos].Index;

      if CanSelect(Col, SelectedRow)
        then Inc(Count);
    end;

  end else if Distance < 0 then
  begin

    while (Count < Abs(Distance)) and (Pos > 0) do
    begin
      Dec(Pos);

      Col := Columns.PositionItem[Pos].Index;

      if CanSelect(Col, SelectedRow)
        then Inc(Count);
    end;

  end
  else Exit;

  SelectedCol := Col;
end;

///<summary>Move selection by <c>page</c></summary>
///<param name="MoveUp">Specifies if PageUp is pressed</param>
///<param name="Shift">State of Ctrl, Alt, Shift keys</param>
///<author>Eduard</author>
procedure TNxCustomGrid6.MoveByPage(MoveUp: Boolean; Shift: TShiftState);
var
  SelectDelta, SaveRow, Index: Integer;

  { Added }
  function FindNextVisible(ASelectDelta: Integer; Row: Integer): Integer;
  begin
    Index := 0;
    Result := Row;
    while (Index < ASelectDelta) do
    begin
      Inc(Result);
      if (RowCount > Result) then
      begin
        if Showing[Result] then
        begin
          Inc(Index);
        end;
      end else
      begin
        SelectLast(Shift);
        Result := SelectedRow;
        Break;
      end;
    end;
  end;

  { Added }
  function FindPreviousVisible(ASelectDelta: Integer; Row: Integer): Integer;
  begin
    Index := 0;
    Result := Row;
    while (Index < ASelectDelta) do
    begin
      Dec(Result);
      if Showing[Result] then
      begin
        Inc(Index);
      end;
    end;
  end;

begin
  SaveRow := SelectedRow;

  if MoveUp then
  begin

    if (SelectedRow > ActiveView.FirstRowInPage) then
    begin
      SelectedRow := (ActiveView.FirstRowInPage);
    end else
    begin
      { Default }
      SelectDelta := ActiveView.GetRowCountInPrevPage;

      { if SelectedRow - SelectDelta < FirstVisibleRow then }
      if SelectedRow - SelectDelta < 0 then // Faster!
      begin
        SelectFirst(Shift);

        Exit;
      end else begin
        SelectedRow := FindPreviousVisible(SelectDelta, SelectedRow);
        { SelectedRow := SelectedRow - SelectDelta; Removed! }
      end;

    end;
  end else
  begin

    if (SelectedRow < ActiveView.LastRowInPage)
      then SelectedRow := ActiveView.LastRowInPage else
    begin
      SelectDelta := ActiveView.GetRowCountInPage(SelectedRow);

      if SelectedRow + SelectDelta >= LastVisibleRow then
      begin
        SelectLast(Shift);

        Exit;
      end
      else SelectedRow := FindNextVisible(SelectDelta, SelectedRow);
    end;

  end;

  { Virtual }
  if (SelectedRow <> SaveRow) and IsVirtual then
  begin
    Update;
  end;
end;

///<summary>Move selection by <c>Distance</c> rows</summary>
///<param name="Distance">Distance of rows to move</param>
///<param name="Shift">State of Ctrl/Alt/Shift while selection</param>
///<author>Eduard</author>
procedure TNxCustomGrid6.MoveByRow(Distance: Integer; Shift: TShiftState);
var
  SaveRow, Row, i: Integer;
  FirstVisible, LastVisible: Integer;
begin
  i := 0;
  Row := SelectedRow;

  { Added }
  SaveRow := Row;

  if Distance > 0 then
  begin
    LastVisible := LastVisibleRow;
    while (i < Distance) and (Row < LastVisible) do
    begin
      Inc(Row);
      if CanSelect(SelectedCol, Row) then Inc(i);
    end;
  end
  else if Distance < 0 then
  begin
    FirstVisible := FirstVisibleRow;

    if Row <= FirstVisible then
    begin
      if Assigned(ActiveView) and ActiveView.ShowInsertRow
        then InsertSelected := True;

      Exit;
    end else
      while (i < Abs(Distance)) and (Row > FirstVisible) do
      begin
        Dec(Row);

        if CanSelect(SelectedCol, Row) then Inc(i);
      end;
  end
  else Exit;

  SelectCell(SelectedCol, Row, Shift);

  if (Row <> SaveRow) and IsVirtual
    then Update;
end;

procedure TNxCustomGrid6.LocateCell(ACol, ARow: Integer);
begin

end;

procedure TNxCustomGrid6.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  case Operation of
    opInsert: ;
    opRemove:
      begin
        if Assigned(ActiveView) and (AComponent = ActiveView)
          then ActiveView := nil;
      end;
  end;
end;

procedure TNxCustomGrid6.DoInsertRowAdd;
begin
  if Assigned(FOnInsertRowAdd) then FOnInsertRowAdd(Self);
end;

procedure TNxCustomGrid6.DoInsertRowQuery(var Accept: Boolean);
begin
  if Assigned(FOnInsertRowQuery) then FOnInsertRowQuery(Self, Accept);
end;

procedure TNxCustomGrid6.Paint;
begin
  try
    Include(FPaintingState, ptPainting);

    inherited;

    if Assigned(ActiveView) then
    begin
      { Reset Font }
      Canvas.Font.Assign(Font);

      ActiveView.Paint;
    end else
      with Canvas do
      begin
        Brush.Color := Color;

        { Empty Fill }
        FillRect(ClientRect);
      end;

    { Paint Design Controls }
    if csDesigning in ComponentState
      then PaintDesign;

{$IFDEF EXPERIMENTAL}

{$ENDIF}

{$IFDEF DEBUGING}
    PaintDebug;
{$ENDIF}

  finally
    Exclude(FPaintingState, ptPainting);
  end;

end;

procedure TNxCustomGrid6.PaintDebug;
begin
  with Canvas do
  begin
    Brush.Color := clLime;
//    TextRect(Bounds(10, 10, 100, 20), 10, 10, 'VisibleCount: ' + IntToStr(VisibleRowCount));
//    TextRect(Bounds(10, 30, 100, 20), 10, 30, 'PageSize: ' + IntToStr(VertScrollBar.PAgeSize));
    Brush.Color := clYellow;
    TextRect(Bounds(ClientWidth - 110, 50, 100, 20), ClientWidth - 120, 50, 'FirstVisible: ' + IntToStr(FirstVisibleRow));
//    TextRect(Bounds(10, 50, 100, 20), 10, 50, 'Position: ' + IntToStr(VertScrollBar.Position));
//    TextRect(Bounds(10, 70, 100, 20), 10, 70, 'Showing: ' + BoolToStr(VertScrollBar.Showing, True));
  end;
end;

procedure TNxCustomGrid6.PaintDesign;
var
  i, FontHeight: Integer;
  State: TNxButtonState;
  TextSize, ButtonSize: TSize;
  Location, ButtonLocation, IndicatorLocation, EditorLocation: TPoint;
  ControlRect, IndicatorRect, ButtonRect, EditorRect, ArrowRect: TRect;
  S: TComponentName;
  PersistentRef: INxPersistentDesignResponder;
begin
  with Canvas do
  begin
    Font.Assign(Self.Font);

    { Turn off ClearType }
    SetFontQuality(Font, NONANTIALIASED_QUALITY);
    TextSize := GetTextSize(Canvas, Name, True);
    FontHeight := GetTextMetric(Canvas).tmAscent + pdStandard;

    { Default Pos }
    Location := Point(0, 0);

    if Assigned(ActiveView) then
    begin
      OffsetPoint(Location, ActiveView.DataRect.TopLeft);
    end;

    OffsetPoint(Location, 8, 8);

    ButtonSize.cy := FontHeight + 6 * 2;
    ButtonLocation.Y := Location.Y;

    { Control Responder }
    ControlRect := Bounds(Location.X, Location.Y, TextSize.cx + 8 * 2, ButtonSize.cy);

    State := [];
    if TPersistent(Self) = FDesignerSelected then State := [bsSelected];

    DrawModernButton(Canvas, Name, ControlRect, State);

    EditorLocation := Point(ControlRect.Right, ControlRect.Top);

    IndicatorLocation := Point(ControlRect.Right, ControlRect.Top);

    ButtonLocation.X := IndicatorLocation.X + 23;

    { View Responder(s) }
    ButtonSize.cx := 0;

    { Calc. largest button }
    for i := 0 to Pred(Views.Count) do
    begin
      S := IfThen(Views[i].Name = EmptyStr, stUnnamed, Views[i].Name);

      TextSize := GetTextSize(Canvas, S, True);

      if TextSize.cx > ButtonSize.cx
        then ButtonSize.cx := TextSize.cx;
    end;

    ButtonRect := Bounds(ButtonLocation.X, ButtonLocation.Y,
      ButtonSize.cx + 8 * 2 + 16 + pdDouble, ButtonSize.cy);

    { Paint Buttons }
    for i := 0 to Pred(Views.Count) do
    begin
      { Active Indicator }
      IndicatorRect := Bounds(IndicatorLocation.X, ButtonRect.Top, 23, ButtonSize.cy);

      if Views[i] = ActiveView then
      begin
        ArrowRect := Bounds(0, 0, 7, 7);
        ArrowRect := CenteredRect(IndicatorRect, ArrowRect);
        DrawIndicatorArrow(Canvas, ArrowRect, clGrayText);
      end;

      Font.Color := clBtnText;

      State := [];
      if Supports(Views[i], INxPersistentDesignResponder, PersistentRef) then
      begin
        if PersistentRef.Instance = FDesignerSelected
          then State := [bsSelected];
      end;

      S := IfThen(Views[i].Name = EmptyStr, stUnnamed, Views[i].Name);

      DrawModernButton(Canvas, S, ButtonRect, State);

      OffsetRect(ButtonRect, 0, RectHeight(ButtonRect) + pdDouble);
      EditorLocation.X := ButtonRect.Right;
    end;

    { Editor Button }
    Inc(EditorLocation.X, pdDouble);
    EditorRect := Bounds(EditorLocation.X, EditorLocation.Y, ButtonSize.cy, ButtonSize.cy);
    Brush.Color := clModernBtnFace;
    FillRect(EditorRect);
    DrawEllipsis(Canvas, EditorRect, clModernGray);
  end;
end;

procedure TNxCustomGrid6.ReadState(Reader: TReader);
begin
  { Read children first inside inherited }
  inherited;
  Columns.UpdateStoredPositions;
end;

procedure TNxCustomGrid6.Recalculate;
var
  Count, i: Integer;
  CaltulatedValue: Double;

  function SumCol(Index: Integer): Extended;
  var
    i: Integer;
  begin
    Result := 0;
    for i := 0 to Pred(RowCount) do
    begin
      if (roExcludeInvisible in FCalculateOptions)
        or Row[i].Visible then Result := Result + Cell[Index, i].AsFloat;
    end;
  end;

  function CalcCol(Index: Integer; Kind: TNxFormulaKind): Extended;
  var
    i: Integer;
    Value: Double;
    s: WideString;
    sl: TStringList;
  begin
    Value := 0;

    case Kind of
      fkAverage: Value := SumCol(Index) / Count;
      fkCount: Value := Count;
      fkCustom: // Loop trough all and call OnCalculate;

        for i := 1 to Pred(RowCount) do
          if (not (roExcludeInvisible in FCalculateOptions) or Row[i].Visible)
            and CanCalculate(i) then
            begin
              Columns[Index].DoCellCalculate(Index, i, Value);
            end;

      fkDistinct:
      begin
        sl := TStringList.Create;
        for i := 0 to RowCount - 1 do
          if (not (roExcludeInvisible in FCalculateOptions) or Row[i].Visible) { visible only }
            and CanCalculate(i) then
          begin
            s := Cells[Index, i];
            if sl.IndexOf(s) = -1 then
            sl.Add(s);
          end;
        Value := sl.Count;
        FreeAndNil(sl);
      end;
      fkMaximum:
      for i := 1 to Pred(RowCount) do
        if (not (roExcludeInvisible in FCalculateOptions) or Row[i].Visible)
          and CanCalculate(i)
            and (Cell[Index, i].AsFloat > Value)
              then Value := Cell[Index, i].AsFloat;
      fkMinimum:  for i := 1 to Pred(RowCount) do
        if (not (roExcludeInvisible in FCalculateOptions) or Row[i].Visible)
                      and CanCalculate(i)
                        and (Cell[Index, i].AsFloat < Value)
                          then Value := Cell[Index, i].AsFloat;
      fkSum: Value := SumCol(Index);
    end;

    { Done }
    Result := Value;
  end;

begin
  if roExcludeInvisible in FCalculateOptions
    then Count := RowCount// FCells.ShownCount
    else Count := RowCount;

  for i := 0 to Pred(Columns.Count) do
    with Columns[i].Footer do
    begin
      CaltulatedValue := CalcCol(i, FormulaKind);

      { Trigger event }
      Columns[i].DoCalculated(i, CaltulatedValue);

      { Trigger event of the Grid }
      DoFooterCalculated(i, CaltulatedValue);

      Value := CaltulatedValue;
    end;

  WritelnDebug('Recalculate');
end;

procedure TNxCustomGrid6.Recount;
begin

end;

procedure TNxCustomGrid6.RefreshCell(const ACol, ARow: Integer);
begin
  if Assigned(ActiveView) and CellExists(ACol, ARow) then
  begin
    ActiveView.RefreshCell(ACol, ARow);
  end;
end;

procedure TNxCustomGrid6.RefreshRow(const Index: Integer);
begin
  if Assigned(ActiveView) and RowExists(Index) then
  begin
    ActiveView.RefreshRow(Index);
    ActiveView.RefreshIndicator(Index);
  end;
end;

procedure TNxCustomGrid6.RefreshSelectedCell;
begin
  RefreshCell(SelectedCol, SelectedRow);
end;

procedure TNxCustomGrid6.RepeatValue;
var
  Source: INxBase;
  PropertyRef: INxProperty;
begin
  if Assigned(FInplaceEdit) then
    if FEditingCell.Y > 0 then
    begin
      { Cell above target (editing) }
      Source := Cell[FEditingCell.X, FEditingCell.Y - 1];

      if Supports(FInplaceEdit, INxProperty, PropertyRef) then
        case Columns[FEditingCell.X].DataType of
          dtFloat:    PropertyRef.AsFloat := Source.AsFloat;
          dtInteger:  PropertyRef.AsInteger := Source.AsInteger;
          else PropertyRef.AsString := Source.AsString;
        end;

    end;
end;

function TNxCustomGrid6.RowExists(const Index: Integer): Boolean;
begin
  Result := InRange(Index, 0, Pred(RowCount));
end;

function TNxCustomGrid6.RowPersist(const Index: Integer): Boolean;
begin
  Result := True;
end;

procedure TNxCustomGrid6.ScrollRect(DeltaX, DeltaY: Integer; Rect,
  ClipRect: TRect);
begin
  inherited;

  if Assigned(ActiveView) then
  begin
    { Scroll View }
    ActiveView.ScrollContentBy(DeltaX, DeltaY);
  end;
end;

procedure TNxCustomGrid6.ScrollToBottom;
begin
  HorzScrollBar.First;
  VertScrollBar.Last;
end;

procedure TNxCustomGrid6.ScrollToCell(ACol, ARow: Integer);
begin
  if Assigned(ActiveView) then
  begin
    if Columns.Exist(ACol) then ActiveView.ScrollToCol(ACol);
    ActiveView.ScrollToRow(ARow);
  end;
end;

procedure TNxCustomGrid6.ScrollToSelected;
begin
  if CellExists(SelectedLocation) then
  begin
    ScrollToCell(SelectedCol, SelectedRow);
  end;
end;

procedure TNxCustomGrid6.ScrollToTop;
begin
  HorzScrollBar.First;
  VertScrollBar.First;
end;

procedure TNxCustomGrid6.SelectAll;
var
	i: Integer;
begin
  if SelectFullRow and MultiSelect then
    try
      BeginUpdate;

    	for i := 0 to Pred(RowCount)
        do Selected[i] := True;

      { for SelectNone }
      Include(FState, gtMultiSelected);
    finally
      { Update }
      EndUpdate;
    end;
end;

procedure TNxCustomGrid6.SelectCell(ACol, ARow: Integer; Shift: TShiftState);
var
  CanSelect, CanDeselect, Highlighted: Boolean;
  PrevSelected: TPoint;
begin
  if not EndEditing then Exit;

  { 12/5/12:  Don't block if value is the equal
              as current cell. But, be carefull about
              not refreshing cell again if not needed! }

  Highlighted := False;

  { Prev. Selected }
  PrevSelected := SelectedLocation;

  if CellExists(PrevSelected) then
  begin
    Highlighted := Self.Highlighted[FSelectedCol, FSelectedRow];
  end;

  try
    DoBeforeSelect(ACol, ARow, SelectionKey, Shift);
  finally
    SelectionKey := 0;
  end;

  { Default }
  CanSelect := Self.CanSelect(ACol, ARow);

  if CanSelect then
  begin
    { Note: Property instead of Field here
            for Descendants }
    FSelectDelta := Point(ACol - SelectedCol, ARow - SelectedRow);

    FSelectedCol := ACol;
    FSelectedRow := ARow;

    { If cell is changed? }
    if not IsEqual(PrevSelected, Point(FSelectedCol, FSelectedRow)) then
    begin
      DoDeselect(PrevSelected.X, PrevSelected.Y);

      DoSelectionChanged(FSelectedCol, FSelectedRow);
    end;

    { Every time }
    DoSelect(FSelectedCol, FSelectedRow);
  end
  else Exit;

  { InsertRow deselect }
  if ARow > Undefined then
  begin
    InsertSelected := False;
  end;

  if Assigned(ActiveView) then
  begin

    if InsertSelected then
    begin
      if PrevSelected.X <> SelectedLocation.X then
      begin
        ActiveView.RefreshCell(PrevSelected.X);
        ActiveView.RefreshCell(SelectedLocation.X);
      end;

    end;

    case SelectFullRow of
      True:
      begin

        if MultiSelect and (ARow > -1) then
        begin

          if (ssCtrl in Shift) and not (ssShift in Shift) then
          begin
            FFromSelected := ARow;

            Include(FState, gtMultiSelected);

            Selected[FSelectedRow] := not Selected[FSelectedRow];

            RefreshRow(FSelectedRow);

             { first set selected then DoSelectEvent! }
//            if OldRow <> ARow then
//            begin
//              if FGridStyle = gsSlides then RefreshSlide(OldRow, True);
//              RefreshRow(OldRow);
//            end;
//            DoSelectCell(ACol, ARow);

            Exit;
          end;

          if ssShift in Shift then
          begin
            Include(FState, gtMultiSelected);

            if FFromSelected < ARow then { up -> down }
            begin
              if not (ssCtrl in Shift) then { don't clear if Ctrl is pressed }
              begin
                SelectRange(0, Pred(FFromSelected), False);
                SelectRange(Succ(ARow), Pred(RowCount), False);
              end;

              SelectRange(FFromSelected, ARow, True);
            end else
            begin
              if not (ssCtrl in Shift) then { don't clear if Ctrl is pressed }
              begin
                SelectRange(0, Pred(ARow), False);
                SelectRange(Succ(FFromSelected), Pred(RowCount), False);
              end;

              SelectRange(ARow, FFromSelected, True);
            end;

            Exit;
          end;

          FFromSelected := ARow;

          { Deselect all }
          CanDeselect := True;

          if (ssRight in Shift) and not RightClickDeselect then
            CanDeselect := False;

          if CanDeselect then
          begin
            DeselectSelected;

            if RowExists(PrevSelected.Y) then
              Selected[PrevSelected.Y] := False;
          end;

          Selected[FSelectedRow] := True;

        end; { Multi select }

        if FSelectedRow <> PrevSelected.Y then
        begin
          RefreshRow(PrevSelected.Y);
          RefreshRow(FSelectedRow);
        end;

        if InvertSelected then
        begin
          RefreshCell(PrevSelected.X, PrevSelected.Y);
          RefreshCell(FSelectedCol, FSelectedRow);
        end;

      end;

      False:
      begin

        if not IsEqual(PrevSelected, SelectedLocation) then
        begin
          if CellExists(PrevSelected)
            then RefreshCell(PrevSelected.X, PrevSelected.Y);


          RefreshCell(SelectedLocation.X, SelectedLocation.Y);

        end;

      end
    end;

    if Highlighted <> Self.Highlighted[FSelectedCol, FSelectedRow] then
    begin

    end;

    if FSelectedRow <> PrevSelected.Y then
    begin
      if RowExists(PrevSelected.Y) then
        ActiveView.RefreshIndicator(PrevSelected.Y);
      ActiveView.RefreshIndicator(FSelectedRow);
    end;

    if CanAutoScroll and AutoScroll then ScrollToSelected;

    if FColumns[ACol].AutoEditing
      then EditCell(SelectedCol, SelectedRow);
  end;
end;

procedure TNxCustomGrid6.SelectComponent(Instance: TPersistent);
var
  FPrevSelected: TPersistent;
  Intf: INxPersistentDesignResponder;
begin
  if Instance <> FDesignerSelected then
  begin
    FPrevSelected := FDesignerSelected;

    FDesignerSelected := Instance;

    if Assigned(FPrevSelected) then
    begin
      if Supports(FPrevSelected, INxPersistentDesignResponder, Intf) then
        InvalidateRect(GetResponderRect(Intf));
    end;

    if Assigned(FDesignerSelected) then
    begin
      if Supports(FDesignerSelected, INxPersistentDesignResponder, Intf) then
        InvalidateRect(GetResponderRect(Intf));
    end;
  end;
end;

procedure TNxCustomGrid6.SelectFirst(Shift: TShiftState = []);
begin
  SelectCell(SelectedCol, FirstVisibleRow, Shift);
end;

procedure TNxCustomGrid6.SelectLast(Shift: TShiftState = []);
begin
  SelectCell(SelectedCol, LastVisibleRow, Shift);
end;

procedure TNxCustomGrid6.SelectNone(DelayedRefresh: Boolean);
var
  i: Integer;
begin
  if gtMultiSelected in FState then
  begin
    try
      if DelayedRefresh then BeginUpdate([]);
    	for i := 0 to Pred(RowCount)
        do Selected[i] := False;
      Exclude(FState, gtMultiSelected);
    finally
      if DelayedRefresh then EndUpdate;
    end;
  end
  else if RowExists(FSelectedRow) then Selected[FSelectedRow] := False;

  FSelectedCol := -1;
  FSelectedRow := -1;
end;

procedure TNxCustomGrid6.SelectRange(FromPos, ToPos: Integer; Value: Boolean);
var
  i: Integer;
begin
  if RowExists(FromPos) and RowExists(ToPos) then
  begin
    try
      { Don't Lock ScrollBar }
      BeginUpdate;

      for i := FromPos to ToPos do
        Selected[i] := Value;

      if Assigned(ActiveView)
        then ActiveView.RefreshRow(FromPos, ToPos);

    finally
      EndUpdate(False);
    end;
  end;
end;

procedure TNxCustomGrid6.SetActiveRow(const Index: Integer);
begin
  // nothing
end;

procedure TNxCustomGrid6.SetActiveView(const Value: TNxGridView6);
begin
  FActiveView := Value;

  if Assigned(FActiveView) then
  begin
    FActiveView.Reset;

    FActiveView.Activate;
  end;

  { Required }
  UpdateScrollBars;

  Invalidate;
end;

procedure TNxCustomGrid6.SetActiveViewIndex(const Value: Integer);
begin
  if InRange(Value, 0, Pred(Views.Count)) then ActiveView := Views[Value];
end;

procedure TNxCustomGrid6.SetAlternatingRowColor(const Value: TColor);
begin
  if Value <> FAlternatingRowColor then
  begin
    FAlternatingRowColor := Value;
    Invalidate;
  end;
end;

procedure TNxCustomGrid6.SetAppearanceOptions(
  const Value: TNxAppearanceOptions);
begin
  if Value <> FAppearanceOptions then
  begin
    FAppearanceOptions := Value;

    { Update paint }
    AssignStylePaint;

    Invalidate;
  end;
end;

procedure TNxCustomGrid6.SetChildOrder(Child: TComponent; Order: Integer);
begin
  inherited SetChildOrder(Child, Order);

end;

procedure TNxCustomGrid6.SetDesignerDelegate(const Value: INxDesignNotificationRecipient);
begin
  FDesignerDelegate := Value;
end;

procedure TNxCustomGrid6.SetEditing(const Value: Boolean);
begin
  if FEditing <> Value then
  begin
    if FEditing
      then EditCell(SelectedCol, SelectedRow)
      else EndEditing(True);
  end;
end;

procedure TNxCustomGrid6.SetFiltered(const Value: Boolean);
begin
  FFiltered := Value;
end;

procedure TNxCustomGrid6.SetHoverResponder(const Value: INxDesignNotificationRecipient);
begin
  if Value <> FHoverResponder then
  begin
    FHoverResponder := Value;
  end;
end;

procedure TNxCustomGrid6.SetInactiveSelectionColor(const Value: TColor);
begin
  if Value <> FInactiveSelectionColor then
  begin
    FInactiveSelectionColor := Value;
    if Assigned(ActiveView) then ActiveView.RefreshData;
  end;
end;

procedure TNxCustomGrid6.SetInsertSelected(const Value: Boolean);
begin
  if Value <> FInsertSelected then
  begin
    FInsertSelected := Value;

    if Assigned(ActiveView) then
    begin
      ActiveView.RefreshInsertRow;
    end;

    if FInsertSelected
      then SelectedRow := Undefined;
  end;
end;

procedure TNxCustomGrid6.SetInvertSelcted(const Value: Boolean);
begin
  FInvertSelected := Value;

  if Assigned(ActiveView) then
  begin
    ActiveView.Invalidate(ActiveView.DataRect);
  end;
end;

procedure TNxCustomGrid6.SetMultiSelect(const Value: Boolean);
begin
  if Value <> FMultiSelect then
  begin
    FMultiSelect := Value;
    if not FMultiSelect and (gtMultiSelected in FState) then
    begin
      SelectNone(True);
    end;
    if Assigned(ActiveView) then
    begin
      ActiveView.Invalidate(ActiveView.DataRect);
    end;
  end;
end;

procedure TNxCustomGrid6.SetMultiSort(const Value: Boolean);
begin
  if Value <> FMultiSort then
  begin
    FMultiSort := Value;
    if not FMultiSort then Columns.UnsortAll;
  end;
end;

procedure TNxCustomGrid6.SetName(const NewName: TComponentName);
begin
  inherited;
  Invalidate;
end;

procedure TNxCustomGrid6.SetOptions(const Value: TNxGridOptions);
begin
  if Value <> FOptions then
  begin
    FOptions := Value;

    { Disabled, not Hide }
    VertScrollBar.AutoHide := goAutoHideScrollBars in FOptions;

    UpdateScrollBars;
  end;
end;

procedure TNxCustomGrid6.SetResponsiveActiveView;
var
  View: TNxGridView6;
  i, NewIndex, OldIndex: Integer;
begin
  OldIndex := ActiveViewIndex;
  NewIndex := 0;
  for i := 0 to Pred(Views.Count) do
  begin
    View := Views[i];
    if (View.ResponsiveWidth > 0)
      and (Width <= View.ResponsiveWidth) then
    begin
      NewIndex := i;
    end;
  end;
  if OldIndex <> NewIndex then ActiveViewIndex := NewIndex;
end;

procedure TNxCustomGrid6.SetRightClickSelect(const Value: Boolean);
begin
  FRightClickSelect := Value;
end;

procedure TNxCustomGrid6.SetRowHeight(const Value: Integer);
begin
  if InRange(Value, 0, MaxInt) then
  begin
    FRowHeight := Value;
    Invalidate;
  end;
end;

procedure TNxCustomGrid6.SetHideFocus(const Value: Boolean);
begin
  if Value <> FHideFocus then
  begin
    FHideFocus := Value;

    if Assigned(ActiveView)
      then ActiveView.RefreshSelection;
  end;
end;

procedure TNxCustomGrid6.SetHideSelection(const Value: Boolean);
begin
  if Value <> FHideSelection then
  begin
    FHideSelection := Value;

    if Assigned(ActiveView)
      then ActiveView.RefreshSelection;
  end;
end;

procedure TNxCustomGrid6.SetHighlighted(ACol, ARow: Integer; const Value: Boolean);
begin
  SelectedCol := ACol;
  SelectedRow := ARow;
end;

procedure TNxCustomGrid6.SetSelected(Index: Integer; const Value: Boolean);
begin

end;

procedure TNxCustomGrid6.SetSelectedLocation(const Value: TPoint);
begin
  SelectCell(Value.X, Value.Y);
end;

procedure TNxCustomGrid6.SetSelectedCol(const Value: Integer);
begin
  { -1 is fine too }
  if InRange(Value, -1, Pred(Columns.Count))
    then SelectCell(Value, SelectedRow);
end;

procedure TNxCustomGrid6.SetSelectedRow(const Value: Integer);
begin
  { -1 is fine too }
  if InRange(Value, -1, Pred(RowCount))
    then SelectCell(SelectedCol, Value);
end;

procedure TNxCustomGrid6.SetSelectFullRow(const Value: Boolean);
begin
  FSelectFullRow := Value;

  Invalidate;
end;

procedure TNxCustomGrid6.SetSelectionColor(const Value: TColor);
begin
  if Value <> FSelectionColor then
  begin
    FSelectionColor := Value;

    if Assigned(ActiveView) then
      ActiveView.RefreshSelection;
  end;
end;

procedure TNxCustomGrid6.SetSelectionKey(const Value: Word);
begin
  FSelectionKey := Value;
end;

procedure TNxCustomGrid6.SetSelectionTextColor(const Value: TColor);
begin
  if Value <> FSelectionTextColor then
  begin
    FSelectionTextColor := Value;

    if Assigned(ActiveView)
      then ActiveView.RefreshSelection;
  end;
end;

procedure TNxCustomGrid6.SetStyle(const Value: TNxAppearanceStyle);
begin
  if Value <> FStyle then
  begin
    FStyle := Value;

    { Create INxStylePaint Obj. }
    CreateStylePaint;

    Invalidate;
  end;
end;

procedure TNxCustomGrid6.StyleChanged;
begin
  AssignStylePaint;
  inherited;
end;

procedure TNxCustomGrid6.TabByColumn(Shift: TShiftState; LeaveControl: Boolean);
var
  r, p, c: Integer;
begin
  if ssShift in Shift then
  begin
    { Tab backward }

    { Start from next }
    p := Pred(Columns[SelectedCol].Position);

    if InsertSelected then
    begin

      while not (p = Columns[SelectedCol].Position) do
      begin

        while p > -1 do
        begin

          if Columns.PositionItem[p].Visible then
          begin
            { Index of Pos. }
            c := Columns.PositionItem[p].Index;

            { Enabled & etc. }
            SelectedCol := c;

            { Done }
            Exit;
          end;

          Dec(p);
        end;

        { Start over }
        p := Pred(Columns.Count);
      end;

    end else
    begin
      for r := SelectedRow downto 0 do
      begin

        while p > -1 do
        begin
          { Index of Pos. }
          c := Columns.PositionItem[p].Index;

          { Enabled & etc. }
          if CanSelect(c, r) then
          begin
            SelectCell(c, r);

            { Done }
            Exit;
          end;

          Dec(p);
        end;

        { Start over }
        p := Pred(Columns.Count);
      end;

      { Not found }
      if goTabLeaveControl in Options
        then SelectPrevControl;
    end;

  end else
  begin
    { Tab forward }

    { Start from next }
    p := Succ(Columns[SelectedCol].Position);

    if InsertSelected then
    begin

      while not (p = Columns[SelectedCol].Position) do
      begin

        while p < Columns.Count do
        begin

          if Columns.PositionItem[p].Visible then
          begin
            { Index of Pos. }
            c := Columns.PositionItem[p].Index;

            { Enabled & etc. }
            SelectedCol := c;

            { Done }
            Exit;
          end;

          Inc(p);
        end;

        { Start over }
        p := 0;
      end;

    end else
    begin

      for r := SelectedRow to Pred(RowCount) do
      begin

        while p < Columns.Count do
        begin
          { Index of Pos. }
          c := Columns.PositionItem[p].Index;

          { Enabled & etc. }
          if CanSelect(c, r) then
          begin
            SelectCell(c, r);

            { Done }
            Exit;
          end;

          Inc(p);
        end;

        { Start over }
        p := 0;
      end;

      { Not found }
      if goTabLeaveControl in Options
        then SelectNextControl;
    end;

  end;

end;

{$IFDEF DEBUGING}
procedure TNxCustomGrid6.Test;
begin
  VertScrollBar.Update;
end;
{$ENDIF}

function TNxCustomGrid6.ToObject: TObject;
begin
  Result := Self;
end;

procedure TNxCustomGrid6.UpdateHorzScrollBar;
var
  Max: Integer;
begin
  if not HorzScrollBar.IsUpdating then
  begin
    { Unlock first }
    HorzScrollBar.Unlock;

    if Assigned(ActiveView) then
    begin
      Max := ActiveView.HorzMax - 1;
      HorzScrollBar.SetValues(Max, ActiveView.DataRect.Right - ActiveView.DataRect.Left);
    end else HorzScrollBar.SetValues(0, 0);
  end;
end;

procedure TNxCustomGrid6.UpdateInplaceEditor;
var
  EditRect: TRect;
begin
  if Assigned(ActiveView) then
  begin

    if Editing then
    begin
      EditRect := ActiveView.GetCellRect(FEditingCell);

      { Shrink EditRect }
      Columns[FEditingCell.X].AdjustEditRect(EditRect);

      { ToDo: Intensive testings here }
      if RectInRect(ActiveView.DataRect, EditRect) then
      begin
        FInplaceEdit.Show;
        FInplaceEdit.SetBounds(EditRect.Left, EditRect.Top, EditRect.Right - EditRect.Left, EditRect.Bottom - EditRect.Top);
        FInplaceEdit.SetFocus;
      end
      else FInplaceEdit.Hide;

    end;

  end;

end;

procedure TNxCustomGrid6.UpdateScrollBars;
begin
  if not (csDestroying in ComponentState) then
  begin
    UpdateHorzScrollBar;
    UpdateVertScrollBar;
  end;
end;

procedure TNxCustomGrid6.UpdateVertScrollBar;
var
  Max: Integer;
begin
  if Assigned(ActiveView) then
  begin
    Max := Pred(ShowingCount);

    Dec(Max, ActiveView.FixedRowCount);

    VertScrollBar.SetValues(Max, ActiveView.VertPageSize);
  end
  else VertScrollBar.SetValues(0, 0);
end;

procedure TNxCustomGrid6.WMActivateApp(var Message: TWMActivateApp);
begin
	inherited;
	if not Message.Active then
    if Assigned(ActiveView) then
    begin
      ActiveView.Deactivate;
    end;
end;

procedure TNxCustomGrid6.WMGetDlgCode(var Message: TWMGetDlgCode);
var
  SkipTab: Boolean;
begin
  inherited;
  Message.Result := Message.Result or DLGC_WANTCHARS or DLGC_WANTARROWS;
  SkipTab := (Columns.VisibleCount = 0) or ((RowCount = 0) and not InsertSelected);
  if WantTabs and not SkipTab then Message.Result := Message.Result or DLGC_WANTTAB
  else Message.Result := Message.Result and not DLGC_WANTTAB;
end;

procedure TNxCustomGrid6.WMHScroll(var Message: TWMHScroll);
begin
  inherited;
  if Assigned(ActiveView)
    and ActiveView.Enabled then
  begin
    // TODO: Border should be refreshed (erased)
    UpdateInplaceEditor;
  end;
end;

procedure TNxCustomGrid6.WMKillFocus(var Message: TWMSetFocus);
begin
  inherited;
  if Assigned(ActiveView) then
  begin
    ActiveView.RefreshSelection;
  end;
end;

procedure TNxCustomGrid6.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  if Assigned(ActiveView) then ActiveView.RefreshSelection;
end;

procedure TNxCustomGrid6.WMSize(var Message: TWMSize);
var
  DeltaX, DeltaY: Integer;
  InvalidationSize: TSize;
  InvalidationRect: TRect;
begin

  if Assigned(ActiveView)
    and not (csLoading in ComponentState) then
  begin

    InvalidationSize.cx := ClientWidth - FPrevWidth;

    { Horizontal }

    if InvalidationSize.cx <> 0 then
    begin
      DeltaX := InvalidationSize.cx;

      ActiveView.ResizeBy(DeltaX, 0);

      if CanUpdate([uoRepaint]) then
      begin
        InvalidationRect := Rect(ClientWidth - InvalidationSize.cx - 20, 0, ClientWidth, ClientHeight);
        InvalidateRect(InvalidationRect);
      end;

      if Caption <> '' then ActiveView.InvalidateCaption;

      if goResponsiveViews in Options
        then SetResponsiveActiveView;
    end;

    { Vertical }

    InvalidationSize.cy := ClientHeight - FPrevHeight;

    if InvalidationSize.cy <> 0 then
    begin

      DeltaY := ActiveView.DataRect.Bottom - ActiveView.DataBottom;

      ActiveView.ResizeBy(0, DeltaY);

      if CanUpdate([uoRepaint]) then
      begin
        InvalidationRect := Rect(0, ActiveView.DataRect.Bottom, ClientWidth, ClientHeight);

        if InvalidationSize.cy > 0
          then Dec(InvalidationRect.Top, InvalidationSize.cy);

        InvalidateRect(InvalidationRect);
      end;

    end;

  end;

  { Calc. Delta }
  FPrevHeight := ClientHeight;
  FPrevWidth := ClientWidth;

  inherited;

  { Update }

  if IsSet(InvalidationSize) then
  begin

    if CanUpdate([uoRepaint])
      then UpdateInplaceEditor;

    if CanUpdate([uoScrollBar])
      then UpdateScrollBars;

  end;

end;

procedure TNxCustomGrid6.WMVScroll(var Message: TWMVScroll);
begin
  inherited;

  if Assigned(ActiveView)
    and ActiveView.Enabled then
  begin
    UpdateInplaceEditor;

    { Required for different size of Rows. It
      is not much time consuming }
    if CanUpdate([uoScrollBar])
      then UpdateScrollBars;
  end;

end;

procedure TNxCustomGrid6.WMWindowPosChanged(var Message: TWMWindowPosChanged);
begin
  inherited;

  { 11/4/2013: Prevent AV while destroying! }
  if not (csDestroying in ComponentState) then
  begin
   // HorzScrollBar.Update;
   // VertScrollBar.Update;
  end;
end;

end.




