{***************************************************************************}
{ TAdvStringGrid component                                                  }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 1996 - 2015                                        }
{            Email : info@tmssoftware.com                                   }
{            Web : http://www.tmssoftware.com                               }
{                                                                           }
{ The source code is given as is. The author is not responsible             }
{ for any possible damage done due to the use of this code.                 }
{ The component can be freely used in any application. The complete         }
{ source code remains property of the author and may not be distributed,    }
{ published, given or sold in any form as such. No parts of the source      }
{ code can be included in any other component or application without        }
{ written authorization of the author.                                      }
{***************************************************************************}

// version history
// 6.0.0.0 : New : Metro style
//         : New : Tristate checkbox support added
//         : New : TAdvHeaderList / TAdvHeaderListPopup column chooser components
//         : New : OnEditChange support added for fixed cell editing
//         : New : Added option to control export of images with TAdvGridExcelIO
//         : New : OnGetCellCursor event added
//         : New : FilterNormalCellsOnly property added to skip filter on node/summary rows
//         : New : Group checkboxes
//         : New : edNumericUnitEditBtn, edFloatUnitEditBtn inplace editor types
//         : New : Groups grand total automatically displayed in floating footer line
//         : New : Public properties SaveFixedCols, SaveFixedRows added
//         : New : Grid.ControlLook.DropDownCount property added
//         : New : FilterDropDownCheck to have multiselect dropdown filter
//         : New : Combo edit & combo list fixed cell editor
//         : New : Inplace editor alignment will automatically match display alignment
//         : New : DISTINCT, STDDEV column & group calculation function added
//         : New : Cell control to expand/collaps rows
//         : New : Method grid.EditCell(Col,Row) added
//         : New : grid.SortSettings.ToggleDirection method added
//         : New : Event OnComboDropDown added
//         : New : Support for XY scatter charts added in TAdvChartLink
//         : New : OnColumnCalc event added
//         : New : DragDropSettings.OleColumnsOnly property added
//         : Improved : Flat node appearance
//         : Improved : Various code optimizations
//         : Improved : Behavior with cell scroll
//         : Improved : TAdvGridImport selection between delimited & fixed column with files
//         : Improved : Column OLE drag & drop
//         : Improved : 64bit compatibility
//         : Fixed : Issue with OnCheckBoxClick when hidden rows are used
//         : Fixed : Issue with find & replace dialog for replacement within selected cells
//         : Fixed : Strange searchpanel alignment issue under specific conditions
//         : Fixed : Issue with progress pie for value = 0
//         : Fixed : Issue to work in XE2 styled app
//         : Fixed : Issue with OLE drag & drop of rich text

// 6.0.0.1 : Fixed : Issue with HTML formatted text and & prefix.
//         : Improved : Coverage of special characters to convert to HTML
//         : Fixed : Issue with horiz. Metro scroller
//         : Fixed : Issue with default filter logical operation initialization
//         : Fixed : Repaint issue on header cell for HotmailRowSelect and DisjunctRowSelect
//         : Fixed : Issue with FixedFooter > 0 and QSortIndexed

// 6.0.1.0 : New : Property Grid.ComboIndex[ACol,ARow]: integer added
//         : New : Property SelectionColorMixerFactor added

// 6.0.1.1 : Fixed : Issue with printing
//         : Fixed : Issue with ColumnSize.SynchWithGrid in combination with grid.SizeWhileTyping
// 6.0.2.0 : New : Method LoadFromCSVStream() added
// 6.0.3.0 : New : DragDropSettings.OleAppendRows: boolean property added
//         : New : Design helper column numbers
// 6.0.3.1 : Fixed : Issue with HideSelectedRows
//         : Fixed : Issue with ACol parameter in OnEditCellDone
//         : Fixed : Issue with CheckAllCheck = true
// 6.0.4.0 : New : Event OnPrintGetPageNum event added
//         : New : Exposed public method UpdateFooter
//         : Improved : Auto insert & delete row possible in filtered grid
// 6.0.4.1 : Fixed : Issue with append rows via OLE drag & drop
//         : Fixed : Issue with page nr. in OnPrintPage event
// 6.0.4.2 : Fixed : Issue with row selection from fixed row header with goRangeSelect = false
// 6.0.4.3 : Fixed : Issue with disjunct cell selection & keyboard selection
//         : Improved : Tristate checkbox drawing in non themed Win apps
//         : Improved : Metro scroller switching
// 6.0.4.4 : Fixed : Issue with SearchFooter.AlwaysHighlight option
//         : Fixed : Printing with variable row sizes & grid.PrintSettings.NoAutoSizeRows = true
// 6.0.5.0 : New : Event OnFilterCheck event added
//         : New : Property FilterDropDownColumns added
//         : Fixed : Issue with sort indicator drawing when merged column header cells are used
//         : Fixed : Issue in HTML rendering engine with image hyperlinks & width/height tags
//         : Fixed : Issue with mouse wheel events when MouseActions.WheelIncrement = 1
//         : Fixed : Issue with auto insert rows and FixedRowAlways = true
//         : Fixed : Issue with MouseActions.CheckAllCheck and hidden columns
//         : Fixed : Issue with painting progress pie for specific values
//         : Fixed : Issue with disjunct cell selection and clicking on fixed cells
// 6.0.5.1 : Fixed : Issue with mousewheel scroll in app with VCL Styles in XE2
//         : Improved : Drawing of glyph on ctBitButton control type in grid
// 6.0.5.2 : Fixed : Issue with ColumnSize.Stretch & scrollbars
//         : Fixed : Issue with handling disjunct row selection when mouseup happens outside grid
//         : Fixed : Issue with anchor handling in HTML formatted cells
// 6.1.0.0 : New : Added edMaskEditBtn inplace editor type
//         : New : Added adLeftRightInRow, adTopBottomInCol navigation modes
//         : New : Added AdvanceSkipReadOnlyCells property in navigation
//         : New : Added Method MoveRows() added to perform block moving of rows
//         : New : Added CursorMoveRows property in navigation
//         : New : Added basic support for XE2 VCL Styles
//         : Improved : Printing of HTML formatted text, rotated text
// 6.1.0.1 : Fixed : Rare issue with combination of custom inplace editors & checkboxes
//         : Fixed : Issue with calling RemoveDataImage() and text remaining in cell
//         : Fixed : Issue with OnRowChanging & goRowSelect
//         : Fixed : Rare issue with cell validation for edDateEdit
//         : Fixed : Rare issue for edEditBtn & AdvanceOnEnter
// 6.1.1.0 : Improved : CursorWalkEditor behavior also applied for csComboEdit inplace editor
//         : Fixed : Allow form shortcuts from custom inplace editors in the grid
// 6.1.1.1 : Fixed : Rare issue with ActiveRowShow & Shift-Tab
//         : Fixed : Rare issue with OnCanEdit & scrolling
//         : Improved : Home / Ctrl-Home behavior in combination with OnSelectCell
//         : Fixed : Rare issue with edAdvGridDropDown and ItemIndex initialization
//         : Fixed : Issue with RowIndicator use and FixedRowAlways = true and RowCount = FixdRows
// 6.1.2.0 : New : HintShowLargeTextPos property added to control positioning of large text hints in cells
//         : Fixed : Issue with loading specific XML files with empty nodes
//         : Improved : Hints on HTML anchors in cells
// 6.1.3.0 : New : Title, Footer added in TAdvGridRTFIO
//         : Improved : Border export for Word 2007, 2010 in TAdvGridRTFIO
// 6.1.3.1 : Fixed : Issue with TAdvGridCSVPager with page calculation when CSV has only one line
//         : Improved : Font size handling for HTML formatted text during printing
//         : Fixed : Issue with inplace combobox editor & BiDiMode = bdRightToLeft
//         : Fixed : Issue with CheckAllCheck / HotMailRowSelect under specific circumstances
//         : Fixed : Issue with merged cell printing
// 6.1.3.2 : Fixed : Issue with sync grid / SelectionRow & mouse wheel
// 6.1.3.3 : Fixed : Issue with AllowClipboardColGrow
//         : Improved : Title height when printing with HTML formatted title
// 6.1.4.0 : New : Added property grid.ControlLook.HintMaxWidth
//         : Fixed : Issue with custom inplace editors & Navigation.TabToNextAtEnd=true
//         : Improved : Auto column sizing when ActiveCellShow = true in specific circumstances
// 6.1.4.1 : Fixed : Issue with loading from empty file in LoadFromCSV
//         : Fixed : Issue with import from CSV when there are spaces between columns
//         : Fixed : Issue with disjunct row selection on focus leave under specific circumstances
//         : Fixed : Issue with filtered grid & HotmailRowSelect = true
// 6.2.0.0 : New : HoverRowCells property added
//         : New : Methods GetSelectionAsText/SetSeledctionAsText added
//         : Improved : Performance to export to file when exporting grids with hidden rows
//         : Fixed : Rare stack overflow issue when assigning Objects in OnGetCellColor
//         : Fixed : Issue with disjunct row selection & fixed footers & selection row count
//         : Fixed : Rare issue with SelectOnRightClick & popup menus
//         : Fixed : Issue with search highlight & special chars
// 6.2.0.1 : Fixed : Issue with AdvanceAutoEdit and spin inplace editor
//         : Fixed : Issue with AdvanceDirection = adLeftRightInRow and AdvanceOnEnterLoop = False
//         : Fixed : Issue with focus & shift-tab
// 6.2.1.0 : New : fmLiteral,fmExpression methods added for filtering
//         : New : Support for imagelist images & PictureContainer images in HTML hints
//         : Improved : Performance with AutoSizeColumns()
//         : Fixed : Rare issue with SelectOnRightClick & code in OnRightClickCell
//         : Fixed : Issue with balloon & cell comments on merged cells
//         : Fixed : Rare issue with tabbing & checkboxes
// 6.2.1.1 : Fixed : Issue with tab keys and rich text inplace editor
//         : Fixed : Issue with drag & drop in combination with hidden columns
//         : Fixed : Issue with Search footer / floating footer & default row height
//         : Fixed : Issue with access of AllObjects under specific circumstances
// 6.2.1.2 : Fixed : Issue with SelectionTextColor and grid.Enabled = false
// 6.2.1.3 : Improved : Autosizing of rows
//         : Improved : Printing with merged cells
// 6.2.1.4 : Improved : Handling of balloons & recreate window
//         : Fixed : Issue with OnAnchorHint event
//         : Fixed : Erratic triggering of OnDisjunctRowSelected
// 6.2.2.0 : New : Function DistinctValues() added
// 6.2.2.1 : Fixed : Issue with UnCheckAll() and tristate checkboxes
// 6.2.2.2 : Improved : Min/max handling with spin inplace editor
// 6.2.3.0 : New : Function HasShape() added
//         : New : FilterDropDownMultiCol property added to enable/disable multicolumn filtering
//         : Improved : Filter dropdown checklist handling
//         : Improved : MultiLine cell drawing
// 6.2.3.1 : Fixed : Issue with inplace grid dropdown editor OnDropUp event when ESC pressed
//         : Improved : XHTML output
//         : Improved : Use of Filter.GlyphActive with checklist dropdown filter mode
//         : Fixed : Issue with grouping and CheckAllCheck setting
// 6.2.4.0 : New : Events OnFilterShow / OnFilterClose added
//         : Improved : Performance for printing
//         : Improved : Printing with merged cells
//         : Fixed : Issue in rare condition for fpAlways printing mode
// 6.2.5.0 : New : Functions SelectionMin,SelectionMax,SelectionAvg,SelectionSum
//         : New : Functions RectMin, RectMax, RectAvg, RectSum
//         : Improved : OnComboChange event triggered when fixed cell combobox editor is used
//         : Improved : AutoSizeRows() when WordWrap = false
//         : Fixed : Rare issue with handling disjunct row selection
// 6.2.6.0 : New : VirtualEdit public property added
//         : Fixed : Small issue with call to grid.RepaintCell
//         : Fixed : Rare condition for cell scrollbars & mousewheel scrolling
//         : Fixed : Issue with using gradient backgrounds on grid with no cell borders
// 6.2.6.1 : Fixed : Issue with horiz. prop. scroll
//         : Improved : Copy to clipboard as HTML with unicode
//         : Fixed : Issue with highlight + hidden columns & search from footer
// 6.2.6.2 : Fixed : Issue with VCL Styles & ShowSelection = false
//         : Fixed : Issue with indexed sort indicator display & BidiMode = bdRightToLeft
// 6.2.7.0 : New : RemoveRowList method added
//         : Improved : Using grid.Ints[] now returns the rounded value when the cell contains a float
//         : Improved : Printing of graphics type ctPicture
//         : Improved : Performance in rich text painting
//         : Improved : Significant performance improvement for RemoveDuplicates()
//         : Fixed : Issue with multiline vertical text alignment
//         : Fixed : Fixed-cell paint issue in glListView style when goFixedVertLine,goFixedHorzLine = false
//         : Fixed : Issue with autosize rows & multiline = true
//         : Fixed : Issue with cell merging & hidden columns
//         : Fixed : Issue with InvalidEntry balloons and custom inplace editors
// 6.2.7.1 : Improved : Printing of semi transparent cell images
//         : Fixed : Issue with cell merging & hiding columns
//         : Fixed : Issue with showing labels on range indicators
// 6.2.7.2 : Fixed : Issue with printing cell images
// 6.2.8.0 : New : OnFilterCheckClick event added
// 6.2.8.1 : Fixed : Issue with DisjunctRowSelect & RemoveRows()
// 6.2.8.2 : Fixed : Issue with extremely long single line text drawing
// 7.0.0.0 : New : Windows 8 / Office 2013 color styles
//         : New : FilterEdit capability
//         : New : Configurable width preview in printsettings dialog
//         : New : Always visible edEditBtn inplace editor button
//         : New : SaveToJSON method added
//         : New : AutoColor added for automatic coloring of positive & negative numbers
//         : New : TouchScroll functionality added
//         : New : Extended design-time style gallery
//         : New : OnClipboardPasteDone event added
//         : New : Equidistant column stretching (via ColumnSize.StretchAll = true)
//         : New : MouseActions.AutoFocus added
//         : New : MouseActions.WheelActive added
//         : New : AddRadioButtonGroup, HasRadioButtonGroup, AddRadioButtonGroupColumn methods added
//         : New : Methods AutoGrowCol/AutoGrowColumns added
//         : Improved : Persistence of checked dropdown filter
//         : Improved : Printing of shapes
//         : Improved : Use of nodes in TAdvGridDropDown
//         : Improved : OnCellValidate for use with edColorPickerDropDown editor type
//         : Improved : Extended PDF developers guide
// 7.0.0.1 : Fixed : Issue with use of BeginUpdate/EndUpdate and searchfooter
//         : Fixed : Issue with wheel scroll action = waScroll
//         : Fixed : Issue with retrieving RowSelectCount when row selection is not used
// 7.0.0.2 : Fixed : Issue with gallery at design time for specific styles
//         : Fixed : Issue with gradient background display and selection
//         : Fixed : Issue with printing password cells
//         : Fixed : Issue with autogoto and find in selection in TAdvGridFindDialog
// 7.0.1.0 : New : Overload from LoadFromCSV() with TEncoding parameter
//         : Improved : Grid will no longer handle Ctrl-Tab, can be externally handled
// 7.0.2.0 : New : AutoHideSelection property added, automatically hide selection when control loses focus
//         : Fixed : Issue with OnEllipsClick and DropDownAlwaysVisible = true
// 7.0.2.1 : Fixed : Issue with Combobox inplace editor & grid OnKeyDown event
// 7.0.2.2 : Fixed : Issue with OnKeyDown event handler when Ctrl-Enter is pressed and AllowCtrlEnter = false
// 7.0.3.0 : New : Extra parameter added for grid.ScrollInView to define scroll position better
//         : Improved : Handling of VCL styles
// 7.0.3.1 : Fixed : Rare issue with combination of DropDownAlwaysVisible = true and EditOnDblClickOnly = true
// 7.0.3.2 : Fixed : Issue with handling radio button clicks
//         : Fixed : Issue with VCL styles & using colors for fixed cells
// 7.0.4.0 : New : AdvGridImportDialog.FirstRowHeaders property added
// 7.0.4.1 : Fixed : Made OnButtonClick handling consistent for keyboard & mouse when combined with hidden columns
// 7.0.4.2 : Fixed : Issue with printing stretched / not stretched cell images
// 7.0.4.3 : Fixed : Issue with RowEnabled[] and sorting
// 7.1.0.0 : New : ssNatural sort format added
//         : New : grid.SortSettings.DefaultFormat property added
// 7.1.0.1 : Fixed : Issue with CursorWalkEditor := true and cell validation
// 7.1.0.2 : Fixed : Issue with handling cell validation & tab key
// 7.1.0.3 : Improved : Dealing with HTML formatted text in filter conditions
//         : Fixed : Issue with OLE drag & drop when mouse buttons are swapped
// 7.1.0.4 : Fixed : Issue with VCL styles & ShowSelection = false
// 7.1.0.5 : Improved : Handling date entry with use of MinDate/MaxDate
//         : Improved : Inplace editing with edMemoDropDown
//         : Fixed : Issue with VCL styles and cell color properties
// 7.2.0.0 : New : edControlDropDown inplace editor
//         : New : RemoveAccented option in Filter & NarrowDown() operation
//         : New : FindMulti/FindMultiNext functions added
//         : Improved : Selection drawing with VCL styles
//         : Improved : SelectionRectangle drawing
//         : Fixed : Issue with AdvanceOnEnter and fixed cells
//         : Fixed : Issue with DropDownAlwaysVisible and default EditBtn inplace editor at design time
//         : Fixed : Issue with disjunct row selection & row select via fixed row header
//         : Fixed : Issue with restoring orig. value for esPopup style custom inplace editors when pressing ESC
//         : Fixed : Access of cells created after hiding rows
// 7.2.0.1 : Fixed : Issue with auto sized pictures and column hiding
//         : Fixed : Issue with OLE drag & drop with goRowSelect = true setting
//         : Fixed : Issue with NarrowDown in combination with RemoveRows
// 7.2.0.2 : Fixed : Issue with printing HTML controls
// 7.2.1.0 : New : added public properties grid.HTMLSettings.HeaderText:string,grid.HTMLSettings.FooterText:string to
//                 to set a HTML header text or footer text via code.
// 7.2.1.1 : Fixed : Left/Right custom border drawing issue
// 7.2.1.2 : Fixed : Issue with tab & checkboxes & hidden columns
//         : Improved : AdvanceInsert behavior when AdvanceDirection = adTopBottomInCol
//         : Fixed : Issue with printing very large cells that exceed a page size
// 7.2.1.3 : Fixed : Issue with AdvanceOnEnter and edEditBtn,edDateEdit editor type
//         : Improved : Handling of ScrollProportional when only horz. or only vert. scrollbar is needed
//         : Fixed: Persisting of Auto size rows in print settings
//         : Fixed: Rare issue with printing and large margins
// 7.2.2.0 : New : Support for input from CSV files with multiline cells
//         : Fixed: Issues with combination of RangeSelectAndEdit = true and AdvanceAutoEdit = true
//         : Improved : Handling of combination of column sizing and filter dropdown
//         : Fixed : Issue with Undo & clipboard in combination with hidden columns
//         : Improved : For CursorWalkEditor = true, the AdvanceDirection adLeftRightInRow is respected
// 7.2.3.0 : New : FilterDropDownCheckUnCheckAll option added
//         : Fixed : Issue with HotmailRowselect and row filtering
// 7.2.3.1 : Fixed : Issue with filtering & quotes
// 7.2.3.2 : Fixed : Issue with AllowSmartClipboard and hidden columns
// 7.2.3.3 : Fixed : Issue with IsSelSuperScript for inplace rich text editor
//         : Improved : Performance with handling cell properties
//         : Fixed : Rare issues with read only cells and advance on enter
// 7.2.3.4 : Fixed : Issue with cell object assignment in hidden rows
// 7.2.3.5 : Fixed : Issue with grid.Navigation.AlwaysEdit = true and scrolling
// 7.2.3.6 : Fixed : Issue with smart clipboard & hidden columns
//         : Fixed : Issue with Windows 2000 compatibility
// 7.2.3.6 : Fixed : Issue with column size in OnColumnSizing event
// 7.2.4.0 : New : Delphi XE5 & C++Builder XE5 support
// 7.2.5.0 : New : FooterPanel exposed via public property
//         : New : CreateFooter protected virtual function added for creating custom footer panels
//         : Fixed : Rare issue with disjunct row selection in grid without fixed columns
// 7.2.6.0 : New : Property grid.Navigation.AutoComboSelect added
//         : New : Support for multiline rotated text for 90° rotated text
//         : New : OnCanAddCol event added
//         : Fixed : Issue with grid.Navigation.KeepHorizScroll = true and checkboxes
//         : Fixed : Issue with column moving / column hiding and use of OnIsFixedCell
//         : Improved : Handled rare exception in auto data detection during sorting
//         : Fixed : Issue with grouping, merged summary rows and floatingfooter use
//         : Fixed : Persisting of selected checkboxes for filter dropdown with use of friendly names
// 7.2.7.0 : New : Horiz. alignment applied to 90 degree multiline rotated text
//         : Fixed : Issue with filter dropdown check & use of spaces in friendly name
//         : New : Public property Encoding: TEncoding added to specify encoding when saving to unicode text files
// 7.2.7.1 : Fixed : Issue with OnDblClickCell and cells with buttons
// 7.2.8.0 : New : Event OnIntelliZoom added
// 7.2.8.1 : Fixed : Rare issue with setting focus to other control from OnKeyDown
//         : Fixed : Issue with readonly cells and DropDownAlwaysVisible
// 7.2.8.2 : Fixed : Issue with incorrect font size mapping during intellizoom
// 7.2.8.3 : Fixed : Issue with column stretch & floating footer
//         : Fixed : Issue with NarrowDown() and GetCheckBoxState
// 7.2.9.0 : Improved : Performance of working with grid with hidden rows
// 7.2.9.1 : Fixed : Issue with grid with just one row hidden
// 7.2.10.0: New : Support for multiline 90° degrees rotated text printing
//         : Fixed : Issue with RemoveRows() call
// 7.2.10.1: Fixed : Issue with SelectionMirrorColor & styles
//         : Fixed : Issue with SelectedText & disjunct row selection
//         : Fixed : Issue with CellRect reported in OnClipboardPasteDone
//         : Fixed : Issue with multiline cell printing vertical offset
// 7.3.0.0 : New : Hilight cells calls with option to highlight only cells with full matching text
//         : New : Searchfooter with highlight text only for cells with full matching text
//         : New : grid.MouseActions.NoScrollOnPartialCol added
//         : Fixed : Issue with ShowInplaceEdit call when RangeSelectAndEdit = true
// 7.3.0.1 : Fixed : Made intellizoom function work consistent with behavior in Excel 2013
//         : Fixed : 1 pixel offset when text on cell with filter dropdown is displayed
//         : Improved : Filter dropdown list autosize
//         : Improved : Filter dropdown list close up
//         : Fixed : Issue with AllowSmartClipboard = true & clipboard paste
//         : Improved : Performance of auto filter dropdown display
// 7.3.0.2 : Fixed : Issue with real row index calculation in combination with filtering
// 7.3.0.3 : Improved : Use of inplace editor when GridLineWidth > 1.
// 7.3.0.4 : Improved : Find in grid indication with disjunct cell selection
// 7.3.1.0 : Fixed : Rare issue with auto advance edit and AdvanceEnterLoop = false
//         : Fixed : Rare issue with sort on grid with 3 rows
//         : Fixed : Issue with hilight & special characters in cells
// 7.4.0.0 : New : Excel cell value formatting capability
//         : New : Method NextVisitableCell added
//         : New : Row HoverButtons added
//         : New : OnClipboardCutDone, OnClipboardCopyDone event added
//         : New : Property grid.Navigation.ClipboardCutAction added
//         : Fixed : Issue with FilterDropDownAuto & FilterDropDownCheck styles
//         : Fixed : Small repaint issue when using show modified rows in combination with filtering
//         : Fixed : Issue with node drawing in specific circumstances
// 7.4.0.1 : Fixed : Issue with generated C++ HPP file
// 7.4.0.2 : Improved : Auto sizing for grid with nodes
//         : Improved : Sorting on virtual cells in ssRaw mode
// 7.4.1.0 : New : Width property added to set width for hover buttons
// 7.4.1.1 : Fixed : Rare issue with cell node tree drawing
//         : Fixed : Regression with sort
//         : Improved : TouchScroll behavior with checkboxes & buttons in cells
// 7.4.1.2 : Fixed : Issue with OLE drag & drop and data checkbox cells
//         : Fixed : Issue with grouping, sorting and collapsing/expanding nodes
// 7.4.1.3 : Improved : TouchScroll behavior
// 7.4.1.4 : Fixed : Issue with disjunct row selection, sorting & move row on sort
//         : Fixed : Issue with cell controls on fixed cells during column or row resizing
//         : Fixed : Issue with mousewheel scrolling and fixed cells in middle of grid
//         : Improved : Faster highlighting from search footer
// 7.4.2.0 : New : Added capability to add comment to cells that contain other graphic elements
//         : New : Hilighting of text in HTML formatted cells
// 7.4.2.1 : Fixed : Issue with setting cell color for cells with checkboxes
//         : Fixed : Issue with formatted cells values in rotated cells
//         : Improved : Displaying filter dropdown
//         : Fixed : Rare issue when sorting & column sizing is enabled on non first fixed row
// 7.4.3.0 : New : Delphi XE6 & C++Builder XE6 support
// 7.4.3.1 : Fixed : Issue with wheel increment & VCL styles
// 7.4.3.2 : Improved : Invisible comments can be added with the color clNone
// 7.4.3.3 : Fixed : Tabbing in merged cells paint issue
// 7.4.3.4 : Fixed : Issue with call validation & cursorwalkeditor
// 7.4.3.5 : Improved : Handling cells with file pictures when file does not exist
//         : Fixed : Issue with using OnPrintStart event
//         : Fixed : Issue with auto filtering of complex values
//         : Fixed : Issue with filter dropdown & mousewheel
//         : Fixed : Issue with ShowSelection & disjunct row selection
// 7.4.3.6 : Fixed : Highlighting & special chars
// 7.4.3.7 : Improved : Filtering for empty cells
// 7.4.3.8 : Fixed : Issue with SizeWhileTyping.Width = true
//         : Improved : Auto filtering in grouped grids
//         : Fixed : Issue with SetRowColor and comment cells
//         : Improved : Nr. of events triggered for OnGetEditorType when DropDownAlwaysVisible = true
//         : Fixed : Issue with grid.MouseActions.AllRowSize = true and reloading grid
// 7.4.4.0 : New : public property OwnsObjects added
// 7.4.4.1 : Fixed : Issue with ShowFocusHelper.Enabled = true and closing form
//         : Fixed : Issue with ClearRowSelect & disjunct row selection
//         : Fixed : Issue with filter condition with & and spaces
//         : Fixed : Issue with hoverbuttons & imagelist images
// 7.4.4.2 : Fixed : Rare issue with row selection & select on right-click
//         : Fixed : Issue with FocusHelper & DirectEdit mode
//         : Fixed : Rare issue with AdvanceOnEnter & AllowDeleteRow in grid without rows
//         : Fixed : Issue with adding checkbox column in grid with floating footer
//         : Fixed : Issue with cell index in OnClickCell event in combination with merged cells & hidden columns
//         : Fixed : Rare issue with auto combo dropdown & tabbing in grid
//         : Fixed : Control down paint handling in cells with multiple HTML controls
//         : Improved : Compatibility with incorrect generated CSV files
//         : Fixed : Issue with triggering OnMouseWheel* events
//         : Fixed : Design-time issue with focus helper
//         : Fixed : Issue with FormControlEditLink and hiding inplace editor after editing
//         : Fixed : Issue with tab handling when goTabs = true for inplace datetime picker
//         : Fixed : Issue with setting grid.RowColor[] = clNone & objects in cells
//         : Fixed : Issue with EditSelectAll = false and edEditBtn inplace editor type
// 7.4.4.3 : Fixed : Issue with focushelper & scrolling in grid
// 7.4.4.4 : Fixed : Issue with loading CSV files with multiline cells
// 7.4.4.5 : Fixed : Rare C++ only issue with tab editing
// 7.4.4.6 : Fixed : Issue with ShowModified & row moving
//         : Fixed : Issue with AdvanceOnEnter & cell controls
// 7.4.5.0 : New : Delphi XE7 & C++Builder XE7 support added
// 7.4.5.1 : Fixed : Issue with RemoveAllNodes under specific circumstances
// 7.4.5.2 : Fixed : Issue with wheel scroll & resizing grid
//         : Fixed : Issue when pressing Ctrl-Enter when WordWrap = false
//         : Fixed : Issue with ACol,ARow parameters for OnComboChange for fixed cell combobox editing
// 7.4.5.3 : Fixed : Issue with incorrect column index in OnCanEditCell when EditOnDblClickOnly = true
// 7.4.5.4 : Fixed : Issue with OnSelectionChanged & Home key
// 7.4.6.0 : New : Access to grid.FixedCombobox, grid.FixedEdit
//         : New : Dropdown width of fixed cell combobox can be set with grid.FixedComboBox.DropWidth
//         : Fixed : Issue with column drag & drop and controls in grid
//         : Fixed : Issue with OnCheckBoxClick event parameters under specific conditions
// 7.4.6.1 : Fixed : Issue with grid.ClearAll in rare corner case
//         : Fixed : Issue with clipboard support for edNumeric, edFloat, edValidChars editor type
// 7.4.6.2 : Fixed : Issue with empty cells & auto dropdown filter
//         : Fixed : Tab editing with hidden & readonly cells
//         : Fixed : Rare issue with hiding standard inplace editor
//         : Fixed : Rare issue with shift key & searchfooter
// 7.4.6.3 : Fixed : Rare issue with entering keys fast during advance on return
// 7.4.6.4 : Improved : Format control of values in cell progressbar
//         : Fixed : Regresssion with AutoColumnSize()
// 7.4.6.5 : Fixed : Regression with mousewheel handling
// 7.4.7.0 : New : FilterEdit.CaseSensitive property added
//         : Fixed : Always visible combobox handling in merged cells
//         : Fixed : Rare issue with advance on enter & hidden columns
// 7.4.7.1 : Fixed : Issue with using filtering in combination with check-all checkbox
//         : Fixed : Issue with cell balloons & radiobuttons
// 7.4.7.2 : Improved : Key lookup in ColorPickerDropDown
//         : Improved : Printing with page range selection
// 7.4.7.3 : Fixed : Issue with atypical use of using controls in tree node column
// 7.4.7.4 : Fixed : Regression with mouse wheel handling
//         : Fixed : Issue with cell validation & form closing
// 7.5.0.0 : New : Property HoverButtons.MoveActiveRow added
//         : New : Larger than / Smaller than conditions added in FilterEdit
//         : New : Grid.ControlLook.DropDownCount now also applies on fixed cell combobox editors
//         : New : Function ColumnType added
//         : New : Grid.Navigation.AutoComboDropSize now also applies on fixed cell combobox editors
//         : Fixed : Issue with auto row sizing & hidden columns
//         : Fixed : Issue with edColorPickerDropdown & hidden columns
// 7.5.0.1 : Fixed : Issue with disjunct row selection & removing rows
//         : Fixed : Rare issue with using grid.Navigation.AdvanceAutoEdit = false
//         : Fixed : Issue with SaveToBinStream & graphic cell objects
//         : Fixed : Rare issue with NoScrollOnPartialRow = true
// 7.5.1.0 : New : Navigation.AllowEditButtonCells property added
// 7.5.1.1 : Fixed : Issue with hidden columns and auto sizing columns
//         : Fixed : Issue with focus helper
//         : Fixed : Rare painting issue with frames in 64bit
// 7.5.2.0 : New: TouchScroll support for horiz. direction added
//         : Improved: Unicode char support for export to RTF
// 7.5.3.0 : New : FilterDropDown.CaseSensitive property added
//         : New : FilterDropDown.Sorted property added
//         : New : HTMLKeepLineBreak: boolean property added
//         : Fixed : Issue with OLE drag & drop + removing rows
//         : Fixed : Printing issue with fpShrink option
//         : Fixed : Issue with editing and Touchscroll enabled
// 7.5.4.0 : New : grid.Navigation.HomeEndKey = heDefault option added
//         : New : Improved handling of printing graphics
//         : Fixed : Issue with triggering OnCellsChanged on read-only cells
// 7.6.0.0 : New : PDF export
//         : Fixed : Rare issue with hidden columns and grid.Navigation.AdvanceAutoEdit = true
//         : Fixed : Issue with import from CSV files with multiple linebreaks in cells
//         : Fixed : Handling of filter conditions with parenthesis
//         : Fixed : Regression with print preview handling
//         : Fixed : Rare issue with using RemoveCols() to remove all columns
//         : Fixed : Issue with combination of row selection & touch scroll
//         : Improved : Export to CSV for grid with multiline cells
// 7.6.0.1 : Fixed : Glyph display in search footer buttons with empty captions
// 7.6.1.0 : Improved : Handling filtering of columns with images
// 7.6.1.1 : Fixed : Rare issue with custom key event handling and AlwaysEdit = true
// 7.6.2.0 : Improved : Auto-filtering with HTML formatted cells supported
//         : Improved : Testing for HTML in cells
//         : New : OnCheckBoxCanToggle event added
//         : Fixed : Issue with hidden columns & search
// 7.7.0.0 : New : Integration capabilities with TAdvRichEditor as inplace editor (Supported in TMS Component Pack only)
//         : New : Support for ordered list rendering in HTML formatted text
//         : New : Support for ToolBarPopup (Supported in TMS Component Pack only)
// 7.7.1.0 : New : Public property SearchCell exposed
//         : Fixed : Issue with fixed cell handling & hidden columns
//         : Improved : HTML rendering compatibility with TAdvRichEditor HTML output
//         : Improved : Inplace TAdvRichEditor control behavior
//         : Improved : Printing of HTML header with grid
// 7.7.1.1 : Fixed : HTML cell rendering issue
// 7.7.2.0 : New : Delphi XE8 & C++Builder XE8 support
// 7.7.3.0 : New : Support to set IME mode per cell for inplace editor
//         : Improved : Code to deal with not limited columns during XLSX import
//         : Fixed : Issue with disjunct selection and no scroll on partial row setting
//         : Fixed : Issue with VCL styles for runtime created controls
// 7.7.3.1 : Fixed : Rare issue with auto filtering of grid that contains empty cells
//         : Fixed : Issue with ExpandAll
// 7.7.4.0 : New : grid.SaveFilter/grid.LoadFilter methods added
//         : Fixed : Issue with radiobutton row group & keyboard handling
//         : Fixed : OnSpinClick event triggering in combination with SpinButtonAlwaysVisible = true
// 7.7.4.1 : Improved : Printing with NoAutoSizeRows = true and rotated text
//         : Fixed : Issue with OnRowChanging event from fixed column row selection
//         : Fixed : Issue with removing rows from filtered grids
//         : Fixed : Header printing when PrintSettings.FitToPage = fpAlways
// 7.7.4.2 : Fixed : Issue with paint update for ssMetro scroll type
//         : Fixed : Issue with touchscroll & disjunct row selection
//         : Fixed : Issue with AutoSizeRows, WordWrap false and hidden columns
//         : Improved : Behavior on page control with tab key when goTabs = true in Options
// 7.7.4.3 : Improved : Printing with fit to page and no auto column sizing
// 7.7.5.0 : New: grid.IgnoreColumns can be used in combination with NarrowDown()
//         : Fixed : Rare case with use of nodes & expand/collaps
//         : Fixed : Issue with OnSelectionChanged event and disjunct cell selection
// 7.7.5.1 : Fixed : Issue with ClearRowSelect
//         : Fixed : Issue with inserting child rows in subnodes
//         : Fixed : Issue with caret in inplace editor
//         : Fixed : Issue with print header size calculation
//         : Improved : Issue with EditWithTags = false for specific entered text
// 7.7.6.0 : New : Property grid.MouseActions.PartialScrollDelta added
// 7.7.6.1 : Improved : Behavior of OnSearchFooterAction to protect against making grid invisible from this event
// 7.7.6.2 : Improved : Integration with TAdvGridFilterPanel for date & time handling
//         : Fixed : Issue with drawing pictures in grid with goVertLine = false in Options
// 7.8.0.0 : New : Windows 10, Office 2016 styles added
//         : New : ControlLook.ButtonPrefix property added
//         : New : Set of grid actions for cell property control
//         : New : Grid classic docking & ribbon toolbars
//         : New : Additional settings for HTML image export control
//         : Fixed : Issue with disjunct row selection & tab edit
//         : Fixed : Issue with regular inplace editor properties
// 7.8.0.1 : Fixed : Issue with automatic float format handling
//         : Fixed : Issue with goRowSelect = true and gradient background
//         : Fixed : Issue with hex formatting using OnGetFloatFormat
//         : Fixed : Issue with virtual cell auto filtering
//         : Fixed : Rare issue with cell validation and EditOnDblClick only
// 7.8.0.2 : Fixed : Issue with HintShowLargeText and hidden columns
// 7.8.0.3 : Fixed : Issue with FilterEdit and hidden columns
//         : Fixed : Issue with OnFixedDropDownClick when fixed dropdown is dynamically hidden
// 7.8.1.0 : New : Public property grid.PrintSettings.PrintComments added
//         : New : Event OnSearchFooterSearchEnd event added
//         : Improved : Handling of selectionresizer when always visible comboboxes are used
//         : Fixed : Issue with HotmailRowSelect and FixedCols = 0
//         : Fixed : Issue with search footer when maximizing form with client aligned grid
//         : Fixed : Issue with auto sizing radiobutton groups in cells
//         : Fixed : Issue with edFloat editor type when ThousandSeparator is different from '.', ','.
//         : Fixed : Rare issue with using edColorpickerDropDown inplace editor
//         : Fixed : Issue with incorrect OnComboChange event when DirectComboClose = true
//         : Fixed : Issue with removing cell graphics from the form destructor
// 7.8.1.1 : Fixed : Issue with OLE drag & drop and hidden columns
//         : Improved : Search functionality for search footer
// 7.8.2.0 : New : Support for Office 2016 for auto theme adaption
// 7.8.2.1 : Fixed : Issue with mousewheel at design-time in XE8
// 7.8.2.2 : Fixed : Issue with handling disjunct row selection
//         : Fixed : Workaround for bug introduced with column width persistence in Delphi 10
//         : Fixed : Rare issue with AdvanceDirection = adTopBottom and AdvanceEnterLoop = false
//         : Fixed : Issue with ClearRect and hidden columns
// 7.8.3.0 : New : RAD Studio 10 Seattle support
//         : Improved : Fixed cell color export to XLS file via TAdvGridExcelIO
// 7.8.3.1 : Fixed : Issue with column moving & grouping with merged group headers or summary
//         : Fixed : Issue with specific HideColumn/UnHideColumn sequence
// 7.8.4.0 : Improved : Support for handling vertically merged cells within node range
//         : Fixed : Rare issue with drawing fixed rows in grid with nodes
//         : Fixed : Rare issue with ClearRowSelect and disjunct row selection
//         : Fixed : Issue with shift-select and HotmailRowSelect mode
// 7.8.4.1 : Fixed : Rare issue with setting specific ColCount value
// 7.8.4.2 : Fixed : Issue with disjunct row selection & changing rowcount
// 7.8.5.0 : New : Properties LastRow, LastCol added
//         : New : TAdvGridColumnPicker component
//         : Improved : PDF export
// 7.8.5.1 : Fixed : Issue with SearchFixedCells option for search footer
// 7.8.6.0 : Improved : Vertical alignment control of default inplace editor
//         : Improved : Use of StyleElements for VCL style use
//         : Fixed : Rare issue with column hiding & disjunct row selection
//         : Fixed : Issue with cell merging & nodes
//         : Fixed : Issue with disjunct row selection in grid with no fixed rows
//         : Fixed : Rare issue with OnExit event handling for edTimeEdit
// 7.8.6.1 : Fixed : Issue with row suppress & BidiMode right to left
//         : Improved : Drawing when seClient = false in StyleElements
// 7.8.7.0 : New : Public property SaveMergedCells: boolean to control export of non base cells
//         : Fixed : Issue with nodes ExpandAll
// 7.8.7.1 : Improved : Combobox height handling
//         : Fixed : Issue with disjunct row selection & sorting
//         : Fixed : Issue with PrintSelectedCols & column hiding
// 7.8.8.0 : New : grid.Navigation.ToggleTriStateCheck property added
//         : Fixed : Rare issue with inplace editor font & VCL styles
//         : Fixed : Rare issue with editing date in grid
// 7.8.8.1 : Fixed : Regression with improvement for combobox height when DirectComboDrop = true
// 7.8.8.2 : Fixed : Issue with OnSelectionChanged & disjunct row selection
//         : Fixed : Rare issue with custom inplace editors & F2 handling
// 7.8.8.3 : Fixed : Rare issue with custom WheelIncrement & VCL styles
//         : Fixed : Rare issue with selecting after ClearRowSelect()
// 7.9.0.0 : New : Public functions FirstCellInRow, LastCellInRow to retrieve first & last editable column cell
//         : New : Property CellImageIdx[col,row] added
//         : New : ControlLook.DropDownButtonWidth property added
//         : New : Support for use of SaveHiddenCells with SaveToXML()
//         : Improved : Handling of filtering & column moving
//         : Improved : Performance of node handling
//         : Improved : High DPI handling
//         : Fixed : Issue with merged cell printing
// 7.9.0.1 : Fixed : Workaround for rare issue with use from DLL form in specific circumstances
//         : Improved : DropDownButtonWidth handling & High DPI compatibility
//         : Fixed : Issue with custom inplace editors in Delphi XE5 or newer versions
//         : Fixed : Regression with virtual cell use & raw sort style
// 7.9.0.2 : Fixed : Issue with TAdvGridColumnPicker and editable grid
// 7.9.0.3 : Improved : Faster disjunct row removal
//         : Fixed : Rare issue with HideSelectedRows
//         : Fixed : Memoryleak with TAdvGridImportDialog
//         : Fixed : Issue with vertical scrollbar and search footer in special circumstances
//         : Improved : SaveHiddenCells now also applies to SaveToBinFile()

{$I TMSDEFS.INC}

unit AdvGrid;

{$R ADVGRID.RES}
{$R ASGRES.RES}
{$R ADVMETRO.RES}
{$R ASGFLTR.RES}

{$H+}
{$J+}
{$Y+}
{$T-}

{$IFNDEF DELPHI_UNICODE}
  {$DEFINE TMSUNICODE}
{$ENDIF}

interface

uses
  Windows, Graphics, SysUtils, Messages, Classes, Controls, Grids, ClipBrd,
  Dialogs, Printers, Forms, StdCtrls, Buttons, AdvUtil, ExtCtrls, IniFiles,
  AsgSpin, AsgEdit, ComCtrls, AsgCombo, RichEdit, CommCtrl, Registry, Menus,
  ShellApi, PictureContainer, AsgCheck, AsgHTMLE, AsgDateTimePicker, BaseGrid,
  Mask, AdvStyleIF, CheckLst, AdvXPVS, JPeg, ComObj, Winspool, ActiveX, ImgList,
  AsgDD, Variants, AdvObj, AdvDateTimePicker,
  AdvDropDown, AdvTrackBarDropDown, AdvMemoDropDown, AdvCalculatorDropDown,
  AdvTimePickerDropDown, AdvDetailDropDown, AdvMultiColumnDropDown,
  AdvColorPickerDropDown, AdvImagePickerDropDown, AdvCustomGridDropDown,
  AdvControlDropDown
  {$IFDEF DELPHIXE_LVL} , AsgXlsFmt {$ENDIF}
  {$IFDEF TMSUNICODE} , AsgUni {$ENDIF}
  {$IFDEF TMSDEBUG} , TMSUtil {$ENDIF}
  {$IFDEF TMSGDIPLUS}
  , AdvHintInfo
  {$ENDIF}
  {$IFDEF DELPHIXE3_LVL}
  , System.UITypes, System.Types
  {$ENDIF}
  ;

const
  {$IFDEF FREEWARE}
  trialversion = ' trial version ';
  {$ENDIF}

  RTF_TWIPS = 1440;

  MAJ_VER = 7; // Major version nr.
  MIN_VER = 9; // Minor version nr.
  REL_VER = 0; // Release nr.
  BLD_VER = 3; // Build nr.
  DATE_VER = 'Jan, 2016'; // Month version

var
  CF_GRIDCELLS: Word;
  WM_GRIDEDITDONE: Word;
  WM_GRIDEDITSHOW: Word;
  WM_EDITPROP: Word;
  WM_DTPSHIFTFOCUS: Word;

type
  {$IFDEF ISDELPHI}
  {$IFDEF DELPHI_UNICODE}
  THintInfo = Controls.THintInfo;
  PHintInfo = Controls.PHintInfo;
  {$ENDIF}
  {$ENDIF}

  {$IFDEF DELPHIXE2_LVL}
  [ComponentPlatformsAttribute(pidWin32 or pidWin64)]
  {$ENDIF}
  TAdvStringGrid = class;
  TEditLink = class;


  ICellGraphic = Interface
  ['{0712BE3F-5C9A-4771-BF71-4C987CDC39B3}']
    procedure Draw(Canvas: TCanvas;R: TRect; Col,Row: integer; Selected: boolean; Grid: TAdvStringGrid);
    function CellWidth: integer;
    function CellHeight: integer;
    function IsBackground: boolean;
  end;

  TWinCtrl = class(TWinControl);

  TBoolArray = array of Boolean;
  TWidthArray = array of SmallInt;

  TAdvGridStyle = (gsOffice2003Blue, gsOffice2003Silver, gsOffice2003Olive, gsOffice2003Classic, gsOffice2007Luna, gsOffice2007Obsidian, gsWindowsXP, gsWhidbey,
                   gsCustom, gsOffice2007Silver, gsWindowsVista, gsWindows7, gsTerminal, gsOffice2010Blue, gsOffice2010Silver, gsOffice2010Black,
                   gsWindows8, gsOffice2013white, gsOffice2013LightGray, gsOffice2013Gray,
                   gsWindows10, gsOffice2016white, gsOffice2016Gray, gsOffice2016Black);

  TFilterType = (ftStartsWith, ftEndsWith, ftContains, ftNotContains, ftEqual, ftNotEqual, ftLargerThan, ftSmallerThan, ftClear,ftNone);

  TSearchType = (stStartsWith, stEndsWith, stContains, stEqual, stNotEqual, stNotContains);

  EAdvGridError = class(Exception);

  {$IFDEF TMSUNICODE}
  TWideEllipsClickEvent = procedure(Sender:TObject;ACol,ARow: Integer;
    var S:widestring) of object;
  {$ENDIF}

  TUnitChangedEvent = procedure(Sender:TObject;ACol,ARow: Integer; NewUnit: string) of object;

  TDropDownButtonClickEvent = procedure(Sender: TObject; ACol, ARow, ButtonIndex: integer) of object;

  TRatingChangeEvent = procedure(Sender:TObject;ACol,ARow: integer; var NewRate: Double; var Allow: Boolean) of object;

  TRadioClickEvent = procedure(Sender:TObject;ACol,ARow,AIdx: Integer) of object;

  TRadioButtonClickEvent = procedure(Sender: TObject; ACol, ARow: Integer) of object;

  TComboChangeEvent = procedure(Sender: TObject; ACol,ARow,AItemIndex: Integer;
    ASelection: string) of object;

  TComboObjectChangeEvent = procedure(Sender:TObject;ACol,ARow,AItemIndex: Integer;
    ASelection: string; AObject: TObject) of object;


  TFloatSpinClickEvent = procedure(Sender:TObject;ACol,ARow: Integer;
    AValue:Double; UpDown: Boolean) of object;

  TDateTimeSpinClickEvent = procedure(Sender:TObject;ACol,ARow: Integer;
    AValue:TDateTime;UpDown: Boolean) of object;


  TSearchAction = (saFindFirst, saFindPrevious, saFindNext);

  TSearchFooterActionEvent = procedure(Sender: TObject; Value: string; ACol, ARow: integer; SearchAction: TSearchAction) of object;

  TSearchFooterSearchEndEvent = procedure(Sender: TObject; var ContinueFromStart: boolean) of object;

  TCellSaveLoadEvent = procedure(Sender: TObject; ACol,ARow: integer; var Value: string) of object;

  {$IFDEF TMSUNICODE}
  TGetEditWideTextEvent = procedure(Sender: TObject; ACol,ARow: integer; var Value: widestring) of object;

  TSetEditWideTextEvent = procedure(Sender: TObject; ACol,ARow: integer; const Value: widestring) of object;
  {$ENDIF}

  TScrollHintType = (shNone,shVertical,shHorizontal,shBoth);

  TFilterOperation = (foSHORT, foNONE, foAND, foXOR, foOR);

  TCustomFilterEvent = procedure(Sender: TObject; ARow: integer; var AcceptRow: boolean) of object;

  THasFilterEditEvent = procedure(Sender: TObject; ACol: integer; var HasFilter: boolean) of object;

  TFilterEditUpdateEvent = procedure(Sender: TObject; ACol: integer; Condition: string; FilterType: TFilterType) of object;

  TPrintPosition = (ppNone,ppTopLeft,ppTopRight,ppTopCenter,ppBottomLeft,
    ppBottomRight,ppBottomCenter);

  TPrintBorders = (pbNoborder,pbSingle,pbDouble,pbVertical,pbHorizontal,pbAround,
    pbAroundVertical,pbAroundHorizontal,pbCustom);


  TPrintMethod = (prPreview,prPrint,prCalcPrint,prCalcPreview);

  TSortDirection = (sdAscending,sdDescending);

  TIntelliPan = (ipVertical,ipHorizontal,ipBoth,ipNone);

  TScrollType = (ssNormal,ssFlat,ssEncarta,ssMetro);

  TXPColorScheme = (xpNone, xpBlue, xpGreen, xpGray, vistaAero);

  TGridLook = (glStandard,glSoft,glClassic,glTMS,glXP,glListView,glVista,glWin7,glOffice2007,glCustom);

  TGridProgressEvent = procedure(Sender:TObject;progress: smallint) of object;

  TClipboardPasteDoneEvent = procedure(Sender: TObject; CellRect: TGridRect) of object;

  TClipboardEvent = procedure(Sender:TObject; var Allow: Boolean) of object;

  TNodeClickEvent = procedure(Sender:TObject; ARow,ARowreal: Integer) of object;

  TNodeAllowEvent = procedure(Sender:TObject; ARow,ARowReal: Integer; var Allow: Boolean) of object;

  TSelectionResizeEvent = procedure(Sender: TObject; OrigSelection, NewSelection: TGridRect) of object;
            

  TGridWideHintEvent = procedure (Sender:TObject; ARow, ACol: Integer;
    var hintstr:widestring) of object;

  TOleDragDropEvent = procedure (Sender:TObject; ARow, ACol: Integer; data:string;
    var Allow: Boolean) of object;

  TOleDropFileEvent = procedure(Sender: TObject; ARow, ACol: Integer; FileName: string;
    var Allow: Boolean) of object;

  TOleDropURLEvent = procedure(Sender: TObject; ARow, ACol: Integer; URL: string;
    var Allow: Boolean) of object;

  TOleDragOverEvent = procedure (Sender:TObject; ARow, ACol: Integer;
    var Allow: Boolean) of object;

  TOleDragStartEvent = procedure (Sender:TObject; ARow, ACol: Integer) of object;
  TOleDragStopEvent =  procedure (Sender:TObject; OLEEffect: Integer) of object;

  TOleDropColEvent = procedure (Sender:TObject; ARow, ACol, DropCol: Integer) of object;

  TOleDroppedEvent = procedure (Sender:TObject; ARect: TGridRect) of object;

  TRowChangingEvent = procedure(Sender:TObject; OldRow, NewRow: Integer;
    var Allow: Boolean) of object;

  TRowChangedEvent = procedure(Sender:TObject; OldRow, NewRow: Integer) of object;

  TColChangingEvent = procedure(Sender:TObject; OldCol, NewCol: Integer;
    var Allow: Boolean) of object;

  TCellChangingEvent = procedure(Sender:TObject; OldRow,OldCol,NewRow,NewCol: Integer;
    var Allow: Boolean) of object;

  TAutoAdvanceEvent = procedure(Sender:TObject; OldRow,OldCol: Integer; var NewRow,NewCol: Integer;
    var Allow: Boolean) of object;

  TGridPrintPageEvent = procedure(Sender:TObject; Canvas: TCanvas; PageNr,PageXSize,PageYSize: Integer) of object;

  TGridPrintPageNumEvent = procedure(Sender: TObject; PageNum,PageColNum: integer; var PageNumString: string) of object;

  TGridPrintStartEvent = procedure (Sender:TObject; NrOfPages: Integer;var FromPage,ToPage: Integer) of object;

  TGridPrintPageDoneEvent = procedure (Sender:TObject; Canvas: TCanvas; LastRow, LastRowOffset, LastPage, PageXSize,PageYSize: Integer) of object;

  TGridPrintCancelEvent = procedure(Sender: TObject; PageNr: Integer; var Cancel: Boolean) of object;

  TGridPrintNewPageEvent = procedure (Sender:TObject; ARow: Integer; var NewPage: Boolean) of object;

  TGridPrintColumnWidthEvent = procedure (Sender:TObject; ACol: Integer; var Width: Integer) of object;
  TGridPrintRowHeightEvent = procedure (Sender:TObject; ARow: Integer; var Height: Integer) of object;
  
  TCustomStrToDateEvent = procedure(Sender: TObject; Value: string;var ADate: TDateTime) of object;


  TCanClickCellEvent = procedure (Sender:TObject;ARow,ACol: Integer;var Allow: Boolean) of object;

  TColorSelectedEvent = procedure(Sender:TObject;ACol,ARow: Integer; var Color: TColor; var Value: string) of object;

  TColorSelectEvent = procedure(Sender:TObject;ACol,ARow: Integer; Color: TColor; Value: string) of object;

  TImageSelectedEvent = procedure(Sender:TObject;ACol,ARow: Integer; var Index: integer) of object;

  TImageSelectEvent = procedure(Sender:TObject;ACol,ARow: Integer; Index: integer) of object;

  TIsFixedCellEvent = procedure (Sender:TObject;ARow,ACol: Integer;var IsFixed: Boolean) of object;
  TIsPasswordCellEvent = procedure (Sender:TObject;ARow,ACol: Integer;var IsPassword: Boolean) of object;

  TFixedEditEvent = procedure(Sender: TObject; ACol,ARow: integer; var AEditor: TGridFixedCellEditor; Values: TStrings) of object;

  TCellControlEvent = procedure(Sender: TObject; ARow,ACol: Integer; CtrlID,CtrlType,CtrlVal: string) of object;

  TCellComboControlEvent = procedure(Sender: TObject; ARow,ACol: Integer; CtrlID,CtrlType,CtrlVal: string;
    Values: TStringList; var Edit: Boolean; var DropCount: Integer) of object;

  TCellComboControlSelectEvent = procedure(Sender: TObject; ARow,ACol, ItemIndex: Integer; CtrlID, CtrlValue: string) of object;

  TCellValidateEvent = procedure(Sender: TObject; ACol, ARow: Integer;
                       var Value: String; var Valid: Boolean) of object;

  TCellValidateWideEvent = procedure(Sender: TObject; ACol, ARow: Integer;
                       var Value: WideString; var Valid: Boolean) of object;

  TEditChangeEvent = procedure(Sender: TObject; ACol, ARow: Integer; Value: string) of object;

  TEditCellDoneEvent = procedure(Sender: TObject; ACol, ARow: Integer) of object;

  TDateTimeChangeEvent = procedure(Sender: TObject; ACol,ARow: Integer; ADateTime: TDateTime) of object;

  TCellsChangedEvent = procedure(Sender: TObject; R: TRect) of object;

  TGetCheckEvent = procedure(Sender: TObject; ACol,ARow: Integer; var Value: string) of object;

  TGetEditorPropEvent = procedure(Sender:TObject;ACol,ARow: Integer; AEditLink: TEditLink) of object;

  TCustomCellSizeEvent = procedure(Sender: TObject; Canvas: TCanvas; ACol,ARow: Integer;
    var ASize: TPoint; Printing: Boolean) of object;

  TDoFitToPageEvent = procedure(Sender:TObject;var ScaleFactor:Double;
    var Allow: Boolean) of object;

  TBeforeCellPasteEvent = procedure(Sender: TObject; ACol,ARow: Integer;
    var Value: string; var Allow: Boolean) of object;

  TAfterCellPasteEvent = procedure(Sender: TObject; ACol,ARow: Integer; Value: string) of object;

  TBeforeCellPasteWideEvent = procedure(Sender: TObject; ACol,ARow: Integer;
    var Value: widestring; var Allow: Boolean) of object;

  TAfterCellPasteWideEvent = procedure(Sender: TObject; ACol,ARow: Integer;
    Value: widestring) of object;

  TSelectionChanged = procedure(Sender: TObject; ALeft, ATop, ARight, ABottom: integer) of object;

  TRowDisjunctSelectEvent = procedure(Sender: TObject; ARow: Integer; AState: boolean; var Allow: boolean) of object;

  TFilterShowEvent = procedure(Sender: TObject; ACol: integer; var Allow: boolean) of object;
  TFilterCloseEvent = procedure(Sender: TObject; ACol: integer) of object;

  TFindParameters = (fnMatchCase,fnMatchFull,fnMatchRegular,fnDirectionLeftRight,
    fnMatchStart,fnFindInCurrentRow,fnFindInCurrentCol,fnIncludeFixed,fnAutoGoto,
    fnIgnoreHTMLTags,fnBackward,fnIncludeHiddenColumns,fnFindInPresetCol,fnFindInPresetRow,fnSelectedCells,fnIncludeHiddenRows);

  TCellHAlign = (haLeft,haRight,haCenter,haBeforeText,haAfterText,haFull);

  TCellVAlign = (vaTop,vaBottom,vaCenter,vaUnderText,vaAboveText,vaFull);

  TCellType = (ctBitmap,ctIcon,ctNone,ctImageList,ctCheckBox,ctDataCheckBox,
    ctRotated,ctDataImage,ctNode,ctRadio,ctEmpty,ctImages,ctPicture,ctFilePicture,
    ctValue,ctProgress,ctComment,ctButton,ctBitButton,ctVirtCheckBox,ctRowCheckBox,
    ctProgressPie,ctSummary,ctRangeIndicator,ctXPProgress,ctInterface,ctScrollbar,
    ctRadioButton,ctBalloon,ctShape,ctRating,ctTriStateCheckBox,ctExpand);

  TCellTypeSet = set of TCellType;

  TFitToPage = (fpNever,fpGrow,fpShrink,fpAlways,fpCustom);

  TFindParams = set of TFindParameters;

  TStretchMode = (noStretch,Stretch,StretchWithAspectRatio,Shrink,ShrinkWithAspectRatio);

  TSortBlankPosition = (blFirst,blLast);

  TScrollBarAlways = (saNone, saVert, saHorz, saBoth);

  TFilterDropDownColumns = (fdNormal, fdAll);

  TRadioButtonGroup = (rgNone, rgCol, rgRow);

  TScrollCellEvent = procedure(Sender: TObject; ACol,ARow: Integer; ScrollPosition, ScrollMin,ScrollMax: integer) of object;

  THasComboEvent = procedure(Sender: TObject; ACol,ARow: Integer; var HasComboBox: Boolean) of object;

  THasEditBtnEvent = procedure(Sender: TObject; ACol,ARow: Integer; var HasEditBtn: Boolean) of object;

  THasSpinEditEvent = procedure(Sender: TObject; ACol,ARow: Integer; var HasSpinEdit: Boolean) of object;

  TCellCursorEvent = procedure(Sender: TObject; ACol, ARow, X, Y: Integer; var ACursor: TCursor) of object;

  TGridExportState = (esExportStart, esExportNewRow, esExportDone, esExportSelRow, esExportFail, esExportNextRow);
  TGridImportState = (isImportStart, isImportNewRow, isImportDone, isImportSelRow);

  TCalcFooterEvent = procedure(Sender: TObject; ACol, ARow: Integer; var Value: String) of object;

  TWordWrapEvent = procedure(Sender: TObject; ACol,ARow: Integer; var WordWrap: boolean) of object;

  TGroupCalcEvent = procedure(Sender: TObject; ACol, FromRow, ToRow: integer; var Res: double) of object;

  TFixedDropDownEvent = procedure(Sender: TObject; ACol,ARow: integer; var AMenu: TPopupMenu; var KeepFixedCellHighlighted: boolean) of object;

  TCanShowFixedDropDownEvent = procedure(Sender: TObject; ACol: integer; var CanShow:boolean) of object;


  //For Drag-Scrolling
  TDragScrollDelays = class(TPersistent)
  private
    FInitialDelay: Integer;
    FRepeatDelay: Integer;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property InitialDelay: Integer read FInitialDelay write FInitialDelay default 1000;
    property RepeatDelay: Integer read FRepeatDelay write FRepeatDelay default 250;
  end;

  TDragScrollMargins = class(TPersistent)
  private
    FTopMargin: Integer;
    FBottomMargin: Integer;
    FLeftMargin: Integer;
    FRightMargin: Integer;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property TopMargin: Integer read FTopMargin write FTopMargin default 50;
    property BottomMargin:Integer read FBottomMargin write FBottomMargin default 50;
    property LeftMargin: Integer read FLeftMargin write FLeftMargin default 50;
    property RightMargin: Integer read FRightMargin write FRightMargin default 50;
  end;

  TDragScrollOptions = class(TPersistent)
  private
    FActive: Boolean;
    FDelays: TDragScrollDelays;
    FMargins: TDragScrollMargins;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Active: boolean read FActive write FActive default False;
    property Delays: TDragScrollDelays read FDelays write FDelays;
    property Margins: TDragScrollMargins read FMargins write FMargins;
  end;

  TDragScrollDirections = (dsdUp,dsdDown,dsdLeft,dsdRight);
  TDragScrollDirection = set of TDragScrollDirections;
  TDragScrollEvent = procedure(Sender: TObject;TopRow,LeftCol:LongInt;var DragScrollDir:TDragScrollDirection;var CanScroll:boolean) of object;

  TDropSelectEvent = procedure(Sender: TObject; ItemIndex: Integer) of object;

  TFilterSelectEvent = procedure(Sender: TObject; Column, ItemIndex: Integer;
    FriendlyName: string; var FilterCondition: string) of object;

  TGetColumnFilterEvent = procedure(Sender: TObject; Column: integer; Filter: TStrings) of object;

  TFilterCheckEvent = procedure(Sender: TObject; Column, ItemIndex: Integer;
    FriendlyName: string; var FilterCondition: string; CheckList: TCheckListBox) of object;

  TFilterCheckClickEvent = procedure(Sender: TObject; Column, ItemIndex: Integer; State: boolean;
    CheckList: TCheckListBox) of object;

  {TDropList}

  TDropList = class(TListBox)
  private
    FOnSelect: TDropSelectEvent;
  protected
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure KeyPress(var Key: Char); override;
    procedure WndProc(var Msg: TMessage); override;
  public
  published
    property OnSelect: TDropSelectEvent read FOnSelect write FOnSelect;
  end;

  {TDropCheckList}

  TDropCheckList = class(TCheckListBox)
  private
    FOnSelect: TDropSelectEvent;
  protected
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure KeyPress(var Key: Char); override;
    procedure WndProc(var Msg: TMessage); override;
    procedure ClickCheck; override;
  public
  published
    property OnSelect: TDropSelectEvent read FOnSelect write FOnSelect;
  end;

  {TFilterEdit}

  TFilterEdit = class(TPersistent)
  private
    FOwner: TAdvStringGrid;
    FEnabled: boolean;
    FRow: integer;
    FColor: TColor;
    FColumns: TFilterDropDownColumns;
    FTypeNames: TStringList;
    FCaseSensitive: boolean;
    procedure SetEnabled(const Value: boolean);
    procedure SetRow(const Value: integer);
    procedure SetColor(const Value: TColor);
    procedure SetColumns(const Value: TFilterDropDownColumns);
    procedure SetTypeNames(const Value: TStringList);
  protected
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property CaseSensitive: boolean read FCaseSensitive write FCaseSensitive default true;
    property Color: TColor read FColor write SetColor default clWhite;
    property Columns: TFilterDropDownColumns read FColumns write SetColumns default fdNormal;
    property Enabled: boolean read FEnabled write SetEnabled default false;
    property Row: integer read FRow write SetRow default 0;
    property TypeNames: TStringList read FTypeNames write SetTypeNames;
  end;


  {TFilterDropDown}

  TFilterDropDown = class(TPersistent)
  private
    FAutoSize: Boolean;
    FHeight: Integer;
    FWidth: Integer;
    FColor: TColor;
    FFont: TFont;
    FGlyph: TBitmap;
    FGlyphActive: TBitmap;
    FColumnWidth: Boolean;
    FOnChange: TNotifyEvent;
    FTextChecked: string;
    FTextUnChecked: string;
    FCaseSensitive: boolean;
    FSorted: boolean;
    procedure SetFont(const Value: TFont);
    procedure SetGlyph(const Value: TBitmap);
    procedure SetGlyphActive(const Value: TBitmap);
  protected
    procedure GlyphChanged(Sender: TObject);
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property AutoSize: boolean read FAutoSize write FAutoSize default false;
    property CaseSensitive: boolean read FCaseSensitive write FCaseSensitive default false;
    property Color: TColor read FColor write FColor default clWindow;
    property ColumnWidth: Boolean read FColumnWidth write FColumnWidth default false;
    property Font: TFont read FFont write SetFont;
    property Glyph: TBitmap read FGlyph write SetGlyph;
    property GlyphActive: TBitmap read FGlyphActive write SetGlyphActive;
    property Height: Integer read FHeight write FHeight default 150;
    property Sorted: boolean read FSorted write FSorted default True;
    property TextChecked: string read FTextChecked write FTextChecked;
    property TextUnChecked: string read FTextUnChecked write FTextUnChecked;
    property Width: Integer read FWidth write FWidth default 150;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  {TCellGraphic}

  TBaseCellGraphic = class(TPersistent)
  private
    FCellType: TCellType;
    FCellBitmap: TBitmap;
    FCellIcon: TIcon;
    FCellVAlign: TCellVAlign;
    FCellHAlign: TCellHAlign;
    FCellIndex: Integer;
    FCellTransparent: Boolean;
    FCellCreated: Boolean;
    FCellBoolean: Boolean;
    FCellAngle: Integer;
    FCellValue: Double;
    FCellErrFrom: Integer;
    FCellErrLen: Integer;
    FCellText: string;
    FCellVar: variant;
    FCellCheckBoxState: TCheckBoxState;
 public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure SetInterfacedCell(AObject: TInterfacedPersistent);
    procedure SetBitmap(ABmp:TBitmap;Transparent: Boolean;hal:TCellHAlign;val:TCellVAlign);
    procedure SetPicture(APicture:TPicture;Transparent: Boolean;StretchMode:TStretchMode;padding: Integer;hal:TCellHAlign;val:TCellVAlign);
    procedure SetFilePicture(APicture:TFilePicture;Transparent: Boolean;stretchmode:TStretchMode;padding: Integer;hal:TCellHAlign;val:TCellVAlign);
    procedure SetImageIdx(idx: Integer;hal:TCellHAlign;val:TCellVAlign);
    procedure SetDataImage(idx: Integer;hal:TCellHAlign;val:TCellVAlign);
    procedure SetMultiImage(Col,Row,dir: Integer;hal:TCellHAlign;val:TCellVAlign;Notifier:TImageChangeEvent);
    procedure SetIcon(aicon:ticon;hal:TCellHAlign;val:TCellVAlign);
    procedure SetCheckBox(Value,Data,Flat: Boolean;hal:TCellHAlign;val:TCellVAlign); overload;
    procedure SetCheckBox(Value: TCheckBoxState; Flat: Boolean; hal: TCellHAlign; val: TCellVAlign); overload;
    procedure SetRadioButton(Value, Flat: boolean;hal:TCellHAlign;val:TCellVAlign; Group: TRadioButtonGroup);
    procedure SetAngle(AAngle:smallint);
    procedure SetButton(bw,bh: Integer;caption:string;hal:TCellHAlign;val:TCellVAlign);
    procedure SetBitButton(bw,bh: Integer;caption:string;Glyph: TBitmap;hal:TCellHAlign;val:TCellVAlign);
    function GetPictureSize(cw,rh: Integer;hastext: Boolean):TPoint;
    property CellIcon: TIcon read FCellIcon write FCellIcon;
    property CellBitmap: TBitmap read FCellBitmap write FCellBitmap;
    property CellVar: Variant read FCellVar write FCellVar;
  published
    property CellType: TCellType read FCellType write FCellType;
    property CellVAlign: TCellVAlign read FCellVAlign write FCellVAlign;
    property CellHAlign: TCellHAlign read FCellHAlign write FCellHAlign;
    property CellIndex: Integer read FCellIndex write FCellIndex;
    property CellTransparent: Boolean read FCellTransparent write FCellTransparent;
    property CellCreated: Boolean read FCellCreated write FCellCreated;
    property CellBoolean: Boolean read FCellBoolean write FCellBoolean;
    property CellCheckBoxState: TCheckBoxState read FCellCheckBoxState write FCellCheckBoxState;
    property CellAngle: Integer read FCellAngle write FCellAngle;
    property CellValue: Double read FCellValue write FCellValue;
    property CellErrFrom: Integer read FCellErrFrom write FCellErrFrom;
    property CellErrLen: Integer read FCellErrLen write FCellErrLen;
    property CellText: string read FCellText write FCellText;
  end;

  TCellGraphic = class(TBaseCellGraphic)
  private
    FCellComment: string;
    FCommentColor: TColor;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property CellComment: string read FCellComment write FCellComment;
    property CommentColor: TColor read FCommentColor write FCommentColor;
  end;

  TNodeType = (cnFlat,cn3D,cnGlyph,cnLeaf,cnXP);

  {TCellNode}

  TCellNode = class(TPersistent)
  private
    FColor: TColor;
    FNodeType: TNodeType;
    FNodeColor: TColor;
    FExpandGlyph: TBitmap;
    FExpandOne: Boolean;
    FContractGlyph: TBitmap;
    FOwner: TAdvStringGrid;
    FShowTree: Boolean;
    FShowTreeFull: Boolean;
    FNodeIndent: Integer;
    FTreeColor: TColor;
    procedure SetExpandGlyph(Value: TBitmap);
    procedure SetContractGlyph(Value: TBitmap);
    procedure SetNodeType(Value: TNodeType);
    procedure SetShowTree(const Value: Boolean);
    procedure SetShowTreeFull(const Value: Boolean);
    procedure SetNodeIndent(const Value: Integer);
    procedure SetTreeColor(const Value: TColor);
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Color: TColor read FColor write FColor default clSilver;
    property ExpandOne: Boolean read FExpandOne write FExpandOne default False;
    property NodeType: TNodeType read FNodeType write SetNodeType default cnXP;
    property NodeColor: TColor read FNodeColor write FNodeColor default clBlack;
    property NodeIndent: Integer read FNodeIndent write SetNodeIndent default 12;
    property ExpandGlyph: TBitmap read FExpandGlyph write SetExpandGlyph;
    property ContractGlyph: TBitmap read FContractGlyph write SetContractGlyph;
    property ShowTree: Boolean read FShowTree write SetShowTree default True;
    property ShowTreeFull: Boolean read FShowTreeFull write SetShowTreeFull default True;
    property TreeColor: TColor read FTreeColor write SetTreeColor default clGray;
  end;

  TControlStyle = (csClassic,csFlat,csWinXP,csBorland,csTMS,csGlyph,csTheme);

  TControlLook = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    FCheckBoxSize: Integer;
    FUnCheckedGlyph: TBitmap;
    FCheckedGlyph: TBitmap;
    FControlStyle: TControlStyle;
    FColor: TColor;
    FRadioSize: Integer;
    FRadioOffGlyph: TBitmap;
    FRadioOnGlyph: TBitmap;
    FFlatButton: Boolean;
    FProgressMarginY: Integer;
    FProgressMarginX: Integer;
    FProgressXP: Boolean;
    FDropDownAlwaysVisible: Boolean;
    FSpinButtonsAlwaysVisible: Boolean;
    FNoDisabledCheckRadioLook: Boolean;
    FNoDisabledButtonLook: Boolean;
    FCommentColor: TColor;
    FProgressBorderColor: TColor;
    FFixedGradientFrom: TColor;
    FFixedGradientTo: TColor;
    FFixedGradientMirrorFrom: TColor;
    FFixedGradientMirrorTo: TColor;
    FFixedGradientHoverFrom: TColor;
    FFixedGradientHoverTo: TColor;
    FFixedGradientHoverMirrorFrom: TColor;
    FFixedGradientHoverMirrorTo: TColor;
    FFixedGradientHoverBorder: TColor;
    FFixedGradientDownFrom: TColor;
    FFixedGradientDownTo: TColor;
    FFixedGradientDownMirrorFrom: TColor;
    FFixedGradientDownMirrorTo: TColor;
    FFixedGradientDownBorder: TColor;
    FFixedDropdownButton: boolean;
    FCheckAlwaysActive: Boolean;
    FRadioAlwaysActive: Boolean;
    FDropDownCount: Integer;
    FDropDownHeader: THeaderAppearance;
    FDropDownFooter: TFooterAppearance;
    FHintMaxWidth: integer;
    FButtonPrefix: boolean;
    FDropDownButtonWidth: integer;
    procedure SetCheckBoxSize(const Value: Integer);
    procedure SetControlStyle(const Value: TControlStyle);
    procedure SetCheckedGlyph(const Value: TBitmap);
    procedure SetUnCheckedGlyph(const Value: TBitmap);
    procedure SetColor(const Value: TColor);
    procedure SetRadioOffGlyph(const Value: TBitmap);
    procedure SetRadioOnGlyph(const Value: TBitmap);
    procedure SetRadioSize(const Value: Integer);
    procedure SetFlatButton(const Value: Boolean);
    procedure SetProgressMarginX(const Value: Integer);
    procedure SetProgressMarginY(const Value: Integer);
    procedure SetProgressXP(const Value: Boolean);
    procedure SetDropDownAlwaysVisible(const Value: Boolean);
    procedure SetSpinButtonsAlwaysVisible(const Value: Boolean);    
    procedure SetNoDisabledCheckRadioLook(const Value: Boolean);
    procedure SetNoDisabledButtonLook(const Value: Boolean);
    procedure SetCommentColor(const Value: TColor);
    procedure SetFixedGradientFrom(const Value: TColor);
    procedure SetFixedGradientTo(const Value: TColor);
    procedure SetFixedGradientMirrorFrom(const Value: TColor);
    procedure SetFixedGradientMirrorTo(const Value: TColor);
    procedure SetFixedGradientHoverFrom(const Value: TColor);
    procedure SetFixedGradientHoverTo(const Value: TColor);
    procedure SetFixedGradientHoverMirrorFrom(const Value: TColor);
    procedure SetFixedGradientHoverMirrorTo(const Value: TColor);
    procedure SetFixedGradientHoverBorder(const Value: TColor);
    procedure SetFixedGradientDownFrom(const Value: TColor);
    procedure SetFixedGradientDownTo(const Value: TColor);
    procedure SetFixedGradientDownMirrorFrom(const Value: TColor);
    procedure SetFixedGradientDownMirrorTo(const Value: TColor);
    procedure SetFixedGradientDownBorder(const Value: TColor);
    procedure SetDropDownFooter(const Value: TFooterAppearance);
    procedure SetDropDownHeader(const Value: THeaderAppearance);
    procedure SetDropDownButtonWidth(const Value: integer);
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Init;
    procedure Assign(Source: TPersistent); override;
  published
    property ButtonPrefix: boolean read FButtonPrefix write FButtonPrefix default false;
    property Color: TColor read FColor write SetColor default clBlack;
    property CommentColor: TColor read FCommentColor write SetCommentColor default clRed;
    property CheckedGlyph: TBitmap read FCheckedGlyph write SetCheckedGlyph;
    property FixedGradientFrom: TColor read FFixedGradientTo write SetFixedGradientTo default clNone;
    property FixedGradientTo: TColor read FFixedGradientFrom write SetFixedGradientFrom default clNone;
    property FixedGradientMirrorFrom: TColor read FFixedGradientMirrorTo write SetFixedGradientMirrorTo default clNone;
    property FixedGradientMirrorTo: TColor read FFixedGradientMirrorFrom write SetFixedGradientMirrorFrom default clNone;

    property FixedGradientHoverFrom: TColor read FFixedGradientHoverTo write SetFixedGradientHoverTo default clWhite;
    property FixedGradientHoverTo: TColor read FFixedGradientHoverFrom write SetFixedGradientHoverFrom default clGray;
    property FixedGradientHoverMirrorFrom: TColor read FFixedGradientHoverMirrorTo write SetFixedGradientHoverMirrorTo default clNone;
    property FixedGradientHoverMirrorTo: TColor read FFixedGradientHoverMirrorFrom write SetFixedGradientHoverMirrorFrom default clNone;
    property FixedGradientHoverBorder: TColor read FFixedGradientHoverBorder write SetFixedGradientHoverBorder default clSilver;

    property FixedGradientDownFrom: TColor read FFixedGradientDownTo write SetFixedGradientDownTo default clSilver;
    property FixedGradientDownTo: TColor read FFixedGradientDownFrom write SetFixedGradientDownFrom default clGray;
    property FixedGradientDownMirrorFrom: TColor read FFixedGradientDownMirrorTo write SetFixedGradientDownMirrorTo default clNone;
    property FixedGradientDownMirrorTo: TColor read FFixedGradientDownMirrorFrom write SetFixedGradientDownMirrorFrom default clNone;
    property FixedGradientDownBorder: TColor read FFixedGradientDownBorder write SetFixedGradientDownBorder default clGray;

    property FixedDropDownButton: Boolean read FFixedDropDownButton write FFixedDropDownButton default False;
    property HintMaxWidth: integer read FHintMaxWidth write FHintMaxWidth default 0;
    property UnCheckedGlyph: TBitmap read FUnCheckedGlyph write SetUnCheckedGlyph;
    property RadioOnGlyph: TBitmap read FRadioOnGlyph write SetRadioOnGlyph;
    property RadioOffGlyph: TBitmap read FRadioOffGlyph write SetRadioOffGlyph;
    property CheckSize: Integer read FCheckBoxSize write SetCheckBoxSize default 15;
    property CheckAlwaysActive: Boolean read FCheckAlwaysActive write FCheckAlwaysActive default False;
    property RadioSize: Integer read FRadioSize write SetRadioSize default 10;
    property RadioAlwaysActive: Boolean read FRadioAlwaysActive write FRadioAlwaysActive default False;
    property ControlStyle: TControlStyle read FControlStyle write SetControlStyle default csTheme;
    property DropDownAlwaysVisible: Boolean read FDropDownAlwaysVisible write SetDropDownAlwaysVisible default False;
    property DropDownButtonWidth: integer read FDropDownButtonWidth write SetDropDownButtonWidth default 16;
    property DropDownCount: Integer read FDropDownCount write FDropDownCount default 8;
    property DropDownHeader: THeaderAppearance read FDropDownHeader write SetDropDownHeader;
    property DropDownFooter: TFooterAppearance read FDropDownFooter write SetDropDownFooter;
    property SpinButtonsAlwaysVisible: Boolean read FSpinButtonsAlwaysVisible write SetSpinButtonsAlwaysVisible default False;
    property FlatButton: Boolean read FFlatButton write SetFlatButton default False;
    property NoDisabledCheckRadioLook: Boolean read FNoDisabledCheckRadioLook write SetNoDisabledCheckRadioLook default False;
    property NoDisabledButtonLook: Boolean read FNoDisabledButtonLook write SetNoDisabledButtonLook default False;
    property ProgressBorderColor: TColor read FProgressBorderColor write FProgressBorderColor default clGray;
    property ProgressMarginX: Integer read FProgressMarginX write SetProgressMarginX default 2;
    property ProgressMarginY: Integer read FProgressMarginY write SetProgressMarginY default 2;
    property ProgressXP: Boolean read FProgressXP write SetProgressXP default False;
  end;

  TShowModified = class(TPersistent)
  private
    FEnabled: Boolean;
    FColor: TColor;
    FOnChange: TNotifyEvent;
    procedure SetColor(const Value: TColor);
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
  published
    property Enabled: Boolean read FEnabled write FEnabled default false;
    property Color: TColor read FColor write SetColor default clYellow;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  {TSizeWhileTyping}

  TSizeWhileTyping = class(TPersistent)
  private
    FHeight: Boolean;
    FWidth: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property Height: Boolean read FHeight write FHeight default False;
    property Width: Boolean read FWidth write FWidth default False;
  end;



  TColumnSizeLocation = (clRegistry,clIniFile);

  TAutoSizeRows = (arAll, arNormal, arFixed);

  {TColumnSize}

  TColumnSize = class(TPersistent)
  private
    Owner: TComponent;
    FSave: Boolean;
    FKey : string;
    FSection : string;
    FStretch: Boolean;
    FStretchColumn: Integer;
    FStretchAll: Boolean;
    FSynchWithGrid: Boolean;
    FSynchNormalCellsOnly: Boolean;
    FLocation: TColumnSizeLocation;
    FRows: TAutoSizeRows;
    procedure SetStretch(Value: Boolean);
    procedure SetStretchAll(const Value: Boolean);
  public
    constructor Create(AOwner:TComponent);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Rows: TAutoSizeRows read FRows write FRows default arAll;
    property Save: Boolean read FSave write FSave default False;
    property Key: string read FKey write FKey;
    property Section: string read FSection write FSection;
    property Stretch: Boolean read FStretch write SetStretch default False;
    property StretchAll: Boolean read FStretchAll write SetStretchAll default False;
    property StretchColumn: Integer read FStretchColumn write FStretchColumn default -1;
    property SynchWithGrid: Boolean read FSynchWithGrid write FSynchWithGrid default False;
    property SynchNormalCellsOnly: Boolean read FSynchNormalCellsOnly write FSynchNormalCellsOnly default False;
    property Location: TColumnSizeLocation read FLocation write FLocation default clRegistry;
  end;

  { Hover buttons }

  THoverButtonPosition = (hbLeftFromColumnLeft, hbRightFromColumnLeft, hbLeftFromColumnRight, hbRightFromColumnRight);

  THoverButtonsCollectionItem = class(TCollectionItem)
  private
    FEnabled: boolean;
    FHint: string;
    FPicture: TPicture;
    FCaption: string;
    FTag: integer;
    FImageIndex: integer;
    FFlat: boolean;
    FWidth: integer;
    procedure SetPicture(const Value: TPicture);
  public
    constructor Create(Collection: TCollection); override;
    procedure Assign(Source: TPersistent); override;
    destructor Destroy; override;
  published
    property Caption: string read FCaption write FCaption;
    property Enabled: boolean read FEnabled write FEnabled default true;
    property Flat: boolean read FFlat write FFlat default false;
    property Hint: string read FHint write FHint;
    property ImageIndex: integer read FImageIndex write FImageIndex default -1;
    property Picture: TPicture read FPicture write SetPicture;
    property Tag: integer read FTag write FTag default 0;
    property Width: integer read FWidth write FWidth default 0;
  end;

  THoverButtonsCollection = class(TOwnedCollection)
  private
    function GetItems(Index: integer): THoverButtonsCollectionItem;
    procedure SetItems(Index: integer;
      const Value: THoverButtonsCollectionItem);
  published
  public
    constructor Create(AOwner: TPersistent);
    function Add: THoverButtonsCollectionItem;
    function Insert(Index: integer): THoverButtonsCollectionItem;
    property Items[Index: integer]: THoverButtonsCollectionItem read GetItems write SetItems; default;
  end;

  THoverRows = (hrAll, hrNormal);

  THoverButtons = class(TPersistent)
  private
    FOwner: TPersistent;
    FEnabled: boolean;
    FColumn: integer;
    FPosition: THoverButtonPosition;
    FButtons: THoverButtonsCollection;
    FRows: THoverRows;
    FMoveActiveRow: boolean;
    procedure SetButtons(const Value: THoverButtonsCollection);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TPersistent);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Enabled: boolean read FEnabled write FEnabled default false;
    property Buttons: THoverButtonsCollection read FButtons write SetButtons;
    property Column: integer read FColumn write FColumn default 0;
    property MoveActiveRow: boolean read FMoveActiveRow write FMoveActiveRow default true;
    property Position: THoverButtonPosition read FPosition write FPosition default hbRightFromColumnRight;
    property Rows: THoverRows read FRows write FRows default hrNormal;
  end;

  { Grouping visual properties }

  TGrouping = class(TPersistent)
  private
    FMergeHeader: Boolean;
    FMergeSummary: Boolean;
    FHeaderColor: TColor;
    FSummaryColor: TColor;
    FHeaderColorTo: TColor;
    FHeaderTextColor: TColor;
    FSummary: Boolean;
    FSummaryTextColor: TColor;
    FSummaryColorTo: TColor;
    FHeaderUnderline: Boolean;
    FSummaryLine: boolean;
    FSummaryLineWidth: Integer;
    FHeaderLineWidth: Integer;
    FSummaryLineColor: TColor;
    FHeaderLineColor: TColor;
    FShowGroupCount: boolean;
    FGroupCountFormat: string;
    FAutoSelectGroup: boolean;
    FAutoCheckGroup: boolean;
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
  published
    property AutoSelectGroup: boolean read FAutoSelectGroup write FAutoSelectGroup default False;
    property AutoCheckGroup: boolean read FAutoCheckGroup write FAutoCheckGroup default False;
    property GroupCountFormat: string read FGroupCountFormat write FGroupCountFormat;
    property HeaderColor: TColor read FHeaderColor write FHeaderColor default clNone;
    property HeaderColorTo: TColor read FHeaderColorTo write FHeaderColorTo default clNone;
    property HeaderTextColor: TColor read FHeaderTextColor write FHeaderTextColor default clNone;
    property HeaderUnderline: Boolean read FHeaderUnderline write FHeaderUnderline default false;
    property HeaderLineColor: TColor read FHeaderLineColor write FHeaderLineColor default clBlue;
    property HeaderLineWidth: Integer read FHeaderLineWidth write FHeaderLineWidth default 2;
    property MergeHeader: Boolean read FMergeHeader write FMergeHeader default false;
    property MergeSummary: Boolean read FMergeSummary write FMergeSummary default false;
    property ShowGroupCount: Boolean read FShowGroupCount write FShowGroupCount default false;
    property Summary: Boolean read FSummary write FSummary default false;
    property SummaryColor: TColor read FSummaryColor write FSummaryColor default clNone;
    property SummaryColorTo: TColor read FSummaryColorTo write FSummaryColorTo default clNone;
    property SummaryTextColor: TColor read FSummaryTextColor write FSummaryTextColor default clNone;
    property SummaryLine: boolean read FSummaryLine write FSummaryLine default false;
    property SummaryLineColor: TColor read FSummaryLineColor write FSummaryLineColor default clBlue;
    property SummaryLineWidth: Integer read FSummaryLineWidth write FSummaryLineWidth default 2;
  end;


  {THTMLSettings}

  THTMLSettings = class(TPersistent)
  private
    FAutoPreview: Boolean;
    FConvertSpecialChars: Boolean;
    FNonBreakingText: Boolean;
    FSaveColor: Boolean;
    FSaveFonts: Boolean;
    FFooterFile: string;
    FHeaderFile: string;
    FBorderSize: Integer;
    FCellSpacing: Integer;
    FCellPadding: Integer;
    FTableStyle: string;
    FPrefixTag: string;
    FSuffixTag: string;
    FSummary: string;
    FHeaderText: string;
    FFooterText: string;
    FWidth: Integer;
    FColWidths: TIntList;
    FXHTML: Boolean;
    FExportImages: Boolean;
    FImageBaseName: string;
    FImageFolder: string;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property ColWidths: TIntList read FColWidths;
  published
    property AutoPreview: boolean read FAutoPreview write FAutoPreview default False;
    property BorderSize: Integer read FBorderSize write FBorderSize default 1;
    property CellSpacing: Integer read FCellSpacing write FCellSpacing default 0;
    property CellPadding: Integer read FCellPadding write FCellPadding default 0;
    property ConvertSpecialChars: Boolean read FConvertSpecialChars write FConvertSpecialChars default False;
    property ExportImages: boolean read FExportImages write FExportImages default True;
    property FooterFile: string read FFooterFile write FFooterFile;
    property FooterText: string read FFooterText write FFooterText;
    property HeaderFile: string read FHeaderFile write FHeaderFile;
    property HeaderText: string read FHeaderText write FHeaderText;
    property ImageFolder: string read FImageFolder write FImageFolder;
    property ImageBaseName: string read FImageBaseName write FImageBaseName;
    property NonBreakingText: Boolean read FNonBreakingText write FNonBreakingText default False;
    property PrefixTag: string read FPrefixTag write FPrefixTag;
    property SaveColor: Boolean read FSaveColor write FSaveColor default True;
    property SaveFonts: Boolean read FSaveFonts write FSaveFonts default True;
    property SuffixTag: string read FSuffixTag write FSuffixTag;
    property Summary: string read FSummary write FSummary;
    property TableStyle: string read FTableStyle write FTableStyle;
    property Width: Integer read FWidth write FWidth default 100;
    property XHTML: Boolean read FXHTML write FXHTML default False;
  end;

  { TBalloonSettings }

  TBalloonSettings = class(TPersistent)
  private
    FInit: Boolean;
    FBackgroundColor: TColor;
    FTextColor: TColor;
    FReshowDelay: Integer;
    FInitialDelay: Integer;
    FAutoHideDelay: Integer;
    FTransparency: Byte;
    FEnable: Boolean;
    FOnEnableChange: TNotifyEvent;
    procedure SetEnable(const Value: Boolean);
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
  published
    property AutoHideDelay: Integer read FAutoHideDelay write FAutoHideDelay default -1;
    property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor default clNone;
    property Enable: Boolean read FEnable write SetEnable default False;
    property InitialDelay: Integer read FInitialDelay write FInitialDelay default -1;
    property ReshowDelay: Integer read FReshowDelay write FReshowDelay default -1;
    property TextColor: TColor read FTextColor write FTextColor default clNone;
    property Transparency: Byte read FTransparency write FTransparency default 0;
    property OnEnableChange: TNotifyEvent read FOnEnableChange write FOnEnableChange;
  end;



  {TPrintSettings}

  TPrintSettings = class(TPersistent)
  private
    FTime: TPrintPosition;
    FDate: TPrintPosition;
    FPageNr: TPrintPosition;
    FPageNumSep: string;
    FDateFormat: string;
    FTitle: TPrintPosition;
    FFont: TFont;
    FHeaderFont: TFont;
    FFooterFont: TFont;
    FBorders: TPrintBorders;
    FBorderStyle: TPenStyle;
    FTitleText: string;
    FTitleLines: TStringList;
    FCentered: Boolean;
    FRepeatFixedRows: Boolean;
    FRepeatFixedCols: Boolean;
    FFooterSize: Integer;
    FHeaderSize: Integer;
    FLeftSize: Integer;
    FRightSize: Integer;
    FColumnSpacing: Integer;
    FRowSpacing: Integer;
    FTitleSpacing: Integer;
    FOrientation: TPrinterOrientation;
    FPagePrefix: string;
    FPageSuffix: string;
    FFixedHeight: Integer;
    FUseFixedHeight: Boolean;
    FFixedWidth: Integer;
    FUseFixedWidth: Boolean;
    FFitToPage: TFitToPage;
    FNoAutoSize: Boolean;
    FPrintGraphics: Boolean;
    FJobName: string;
    FNoAutoSizeRow: Boolean;
    FPageNumberOffset: Integer;
    FMaxPagesOffset: Integer;
    FFixedFont: TFont;
    FUseDisplayFont: Boolean;
    FUseDefaultOrientation: Boolean;
    FFixedCellsAlways: Boolean;
    FBorderColor: TColor;
    FPrintComments: boolean;
    procedure SetPrintFont(Value: TFont);
    procedure SetPrintHeaderFont(Value: TFont);
    procedure SetPrintFooterFont(Value: TFont);
    procedure SetTitleLines(Value: TStringList);
    procedure SetFixedFont(const Value: TFont);
  protected
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property FixedCellsAlways: boolean read FFixedCellsAlways write FFixedCellsAlways;
    property PrintComments: boolean read FPrintComments write FPrintComments;
  published
    property FooterSize: Integer read FFooterSize write FFooterSize default 0;
    property HeaderSize: Integer read FHeaderSize write FHeaderSize default 0;
    property Time: TPrintPosition read FTime write FTime default ppNone;
    property Date: TPrintPosition read FDate write FDate default ppNone;
    property DateFormat: string read FDateFormat write FDateFormat;
    property PageNr: TPrintPosition read FPageNr write FPageNr default ppNone;
    property Title: TPrintPosition read FTitle write FTitle default ppNone;
    property TitleText : string read FTitleText write FTitleText;
    property TitleLines: TStringList read FTitleLines write SetTitleLines;
    property Font: TFont read FFont write SetPrintFont;
    property FixedFont: TFont read FFixedFont write SetFixedFont;
    property HeaderFont: TFont read FHeaderFont write SetPrintHeaderFont;
    property FooterFont: TFont read FFooterFont write SetPrintFooterFont;
    property Borders : TPrintBorders read FBorders write FBorders default pbSingle;
    property BorderStyle : TPenStyle read FBorderStyle write FBorderStyle default psSolid;
    property BorderColor: TColor read FBorderColor write FBorderColor default clBlack;
    property Centered : Boolean read FCentered write FCentered default True;
    property RepeatFixedRows : Boolean read FRepeatFixedRows write FRepeatFixedRows default false;
    property RepeatFixedCols : Boolean read FRepeatFixedCols write FRepeatFixedCols default false;
    property LeftSize: Integer read FLeftSize write FLeftSize default 0;
    property RightSize: Integer read FRightSize write FRightSize default 0;
    property ColumnSpacing: Integer read FColumnSpacing write FColumnSpacing default 0;
    property RowSpacing: Integer read FRowSpacing write FRowSpacing default 0;
    property TitleSpacing: Integer read FTitleSpacing write FTitleSpacing default 0;
    property Orientation: TPrinterOrientation read FOrientation write FOrientation default poPortrait;
    property PagePrefix: string read FPagePrefix write FPagePrefix stored True;
    property PageSuffix: string read FPageSuffix write FPageSuffix;
    property PageNumberOffset: Integer read FPageNumberOffset write FPageNumberOffset default 0;
    property MaxPagesOffset: Integer read FMaxPagesOffset write FMaxPagesOffset default 0;
    property FixedWidth: Integer read FFixedWidth write FFixedWidth default 0;
    property FixedHeight: Integer read FFixedHeight write FFixedHeight default 0;
    property UseFixedHeight: Boolean read FUseFixedHeight write FUseFixedHeight default False;
    property UseFixedWidth: Boolean read FUseFixedWidth write FUseFixedWidth default False;
    property FitToPage: TFitToPage read FFitToPage write FFitToPage default fpNever;
    property JobName: string read FJobName write FJobName;
    property PageNumSep: string read FPageNumSep write FPageNumSep;
    property NoAutoSize: Boolean read FNoAutoSize write FNoAutoSize default False;
    property NoAutoSizeRow: Boolean read FNoAutoSizeRow write FNoAutoSizeRow default False;
    property PrintGraphics: Boolean read FPrintGraphics write FPrintGraphics default False;
    property UseDisplayFont: Boolean read FUseDisplayFont write FUseDisplayFont default True;
    property UseDefaultOrientation: Boolean read FUseDefaultOrientation write FUseDefaultOrientation default False;
  end;

  TBackGroundDisplay = (bdTile, bdFixed, bdGradientHorz, bdGradientVert);
  TBackGroundCells = (bcNormal, bcFixed, bcAll);
  TIndexSortKey = (ikShift, ikCtrl);

  { TSortSettings }

  TSortSettings = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    FSortShow : Boolean;
    FSortIndexShow: Boolean;
    FSortFull : Boolean;
    FSortSingleColumn: Boolean;
    FSortIgnoreBlanks: Boolean;
    FSortBlankPos: TSortBlankPosition;
    FSortAutoFormat : Boolean;
    FSortDirection : TSortDirection;
    FSortUpGlyph: TBitmap;
    FSortDownGlyph: TBitmap;
    FIndexUpGlyph: TBitmap;
    FIndexDownGlyph: TBitmap;
    FSortNormalCellsOnly: Boolean;
    FSortFixedCols: Boolean;
    FSortColumn: Integer;
    FSortRow: Integer;
    FAutoColumnMerge: Boolean;
    FSortIndexColor: TColor;
    FInitSortDirection: TSortDirection;
    FUndoSort: Boolean;
    FAutoSortForGrouping: Boolean;
    FVirtualCells: Boolean;
    FIgnoreCase: Boolean;
    FHeaderColor: TColor;
    FHeaderColorTo: TColor;
    FHeaderMirrorColor: TColor;
    FHeaderMirrorColorTo: TColor;
    FIndexSortKey: TIndexSortKey;
    FDefaultFormat: TSortStyle;
    function GetDownGlyph: TBitmap;
    function GetUpGlyph: TBitmap;
    procedure SetDownGlyph(const Value: TBitmap);
    procedure SetUpGlyph(const Value: TBitmap);
    procedure SetSortRow(const Value: Integer);
    procedure SetIndexDownGlyph(const Value: TBitmap);
    procedure SetIndexUpGlyph(const Value: TBitmap);
    procedure SetShow(const Value: Boolean);
    procedure SetHeaderColor(const Value: TColor);
    procedure SetHeaderColorTo(const Value: TColor);
    procedure SetHeaderMirrorColor(const Value: TColor);
    procedure SetHeaderMirrorColorTo(const Value: TColor);
  protected
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure Remove;
    function SaveToString: string;
    procedure LoadFromString(const Value: string);
    procedure ToggleDirection;
  published
    property AutoSortForGrouping: Boolean read FAutoSortForGrouping write FAutoSortForGrouping default True;
    property AutoColumnMerge: Boolean read FAutoColumnMerge write FAutoColumnMerge default False;
    property DefaultFormat: TSortStyle read FDefaultFormat write FDefaultFormat default ssAlphabetic;
    property Column: Integer read FSortColumn write FSortColumn default -1;
    property Show: Boolean read FSortShow write SetShow default False;
    property IndexShow: Boolean read FSortIndexShow write FSortIndexShow default False;
    property IndexColor: TColor read FSortIndexColor write FSortIndexColor default clYellow;
    property IndexSortKey: TIndexSortKey read FIndexSortKey write FIndexSortKey default ikShift;
    property Full: Boolean read FSortFull write FSortFull default True;
    property SingleColumn: Boolean read FSortSingleColumn write FSortSingleColumn default False;
    property IgnoreBlanks: Boolean read FSortIgnoreBlanks write FSortIgnoreBlanks default False;
    property BlankPos: TSortBlankPosition read FSortBlankPos write FSortBlankPos default blFirst;
    property AutoFormat: Boolean read FSortAutoFormat write FSortAutoFormat default True;
    property Direction: TSortDirection read FSortDirection write FSortDirection default sdAscending;
    property UpGlyph: TBitmap read GetUpGlyph write SetUpGlyph;
    property DownGlyph: TBitmap read GetDownGlyph write SetDownGlyph;
    property IgnoreCase: boolean read FIgnoreCase write FIgnoreCase default False;
    property IndexUpGlyph: TBitmap read FIndexUpGlyph write SetIndexUpGlyph;
    property IndexDownGlyph: TBitmap read FIndexDownGlyph write SetIndexDownGlyph;
    property InitSortDirection: TSortDirection read FInitSortDirection write FInitSortDirection default sdAscending;
    property FixedCols: Boolean read FSortFixedCols write FSortFixedCols default False;
    property NormalCellsOnly: Boolean read FSortNormalCellsOnly write FSortNormalCellsOnly default False;
    property Row: Integer read FSortRow write SetSortRow default 0;
    property UndoSort: Boolean read FUndoSort write FUndoSort default False;
    property SortOnVirtualCells: Boolean read FVirtualCells write FVirtualCells default True;
    property HeaderColor: TColor read FHeaderColor write SetHeaderColor default clNone;
    property HeaderColorTo: TColor read FHeaderColorTo write SetHeaderColorTo default clNone;
    property HeaderMirrorColor: TColor read FHeaderMirrorColor write SetHeaderMirrorColor default clNone;
    property HeaderMirrorColorTo: TColor read FHeaderMirrorColorTo write SetHeaderMirrorColorTo default clNone;
  end;

  TProgressStyle = (psXP, psClassic);

  TGridProgressAppearance = class(TPersistent)
  private
    FUnCompleteFontColor: TColor;
    FCompleteColor: TColor;
    FUnCompleteColor: TColor;
    FCompleteFontColor: TColor;
    FOnChange: TNotifyEvent;
    FStacked: Boolean;
    FShowPercentage: Boolean;
    FShowBorder: Boolean;
    FCompletionSmooth: Boolean;
    FShowGradient: Boolean;
    FLevel2Perc: Integer;
    FLevel1Perc: Integer;
    FSteps: Integer;
    FLevel3Color: TColor;
    FLevel1Color: TColor;
    FLevel0Color: TColor;
    FLevel3ColorTo: TColor;
    FLevel2ColorTo: TColor;
    FLevel0ColorTo: TColor;
    FLevel1ColorTo: TColor;
    FBorderColor: TColor;
    FLevel2Color: TColor;
    FStyle: TProgressStyle;
    procedure SetCompleteColor(const Value: TColor);
    procedure SetCompleteFontColor(const Value: TColor);
    procedure SetUnCompleteColor(const Value: TColor);
    procedure SetUnCompleteFontColor(const Value: TColor);
    procedure SetBorderColor(const Value: TColor);
    procedure SetCompletionSmooth(const Value: Boolean);
    procedure SetLevel0Color(const Value: TColor);
    procedure SetLevel0ColorTo(const Value: TColor);
    procedure SetLevel1Color(const Value: TColor);
    procedure SetLevel1ColorTo(const Value: TColor);
    procedure SetLevel1Perc(const Value: Integer);
    procedure SetLevel2Color(const Value: TColor);
    procedure SetLevel2ColorTo(const Value: TColor);
    procedure SetLevel2Perc(const Value: Integer);
    procedure SetLevel3Color(const Value: TColor);
    procedure SetLevel3ColorTo(const Value: TColor);
    procedure SetShowBorder(const Value: Boolean);
    procedure SetShowGradient(const Value: Boolean);
    procedure SetShowPercentage(const Value: Boolean);
    procedure SetStacked(const Value: Boolean);
    procedure SetSteps(const Value: Integer);
    procedure SetStyle(const Value: TProgressStyle);
  protected
    procedure Changed;
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
    property Style: TProgressStyle read FStyle write SetStyle default psXP;
  published
    property CompleteColor: TColor read FCompleteColor write SetCompleteColor default clRed;
    property CompleteFontColor: TColor read FCompleteFontColor write SetCompleteFontColor default clBlue;
    property UnCompleteColor: TColor read FUnCompleteColor write SetUnCompleteColor default clNone;
    property UnCompleteFontColor: TColor read FUnCompleteFontColor write SetUnCompleteFontColor default clWindowText;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property Level0Color: TColor read FLevel0Color write SetLevel0Color default clLime;
    property Level0ColorTo: TColor read FLevel0ColorTo write SetLevel0ColorTo default $00E1FFE1;
    property Level1Color: TColor read FLevel1Color write SetLevel1Color default clYellow;
    property Level1ColorTo: TColor read FLevel1ColorTo write SetLevel1ColorTo default $00CAFFFF;
    property Level2Color: TColor read FLevel2Color write SetLevel2Color default $0053A9FF;
    property Level2ColorTo: TColor read FLevel2ColorTo write SetLevel2ColorTo default $00A8D3FF;
    property Level3Color: TColor read FLevel3Color write SetLevel3Color default clRed;
    property Level3ColorTo: TColor read FLevel3ColorTo write SetLevel3ColorTo default $00CACAFF;
    property Level1Perc: Integer read FLevel1Perc write SetLevel1Perc default 70;
    property Level2Perc: Integer read FLevel2Perc write SetLevel2Perc default 90;
    property BorderColor: TColor read FBorderColor write SetBorderColor default clBlack;
    property ShowBorder: Boolean read FShowBorder write SetShowBorder default False;
    property Stacked: Boolean read FStacked write SetStacked default False;
    property ShowPercentage: Boolean read FShowPercentage write SetShowPercentage default true;
    property CompletionSmooth: Boolean read FCompletionSmooth write SetCompletionSmooth default true;
    property ShowGradient: Boolean read FShowGradient write SetShowGradient default true;
    property Steps: Integer read FSteps write SetSteps default 11;
  end;

  {TBackGround}

  TBackGround = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    FTop: Integer;
    FLeft: Integer;
    FDisplay: TBackGroundDisplay;
    FBackgroundCells: TBackgroundCells;
    FColorTo: TColor;
    FColor: TColor;
    procedure SetBitmap(Value: TBitmap);
    procedure SetTop(Value: Integer);
    procedure SetLeft(Value: Integer);
    procedure SetDisplay(Value: TBackgroundDisplay);
    procedure SetBackGroundCells(const Value: TBackgroundCells);
    procedure SetColor(const Value: TColor);
    procedure SetColorTo(const Value: TColor);
  private
    FBitmap: TBitmap;
  public
    constructor Create(AGrid: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Top: Integer read FTop write SetTop default 0;
    property Left: Integer read FLeft write SetLeft default 0;
    property Display: TBackgroundDisplay read FDisplay write SetDisplay default bdTile;
    property Bitmap: TBitmap read FBitmap write SetBitmap;
    property Cells: TBackgroundCells read FBackgroundCells write SetBackGroundCells default bcNormal;
    property Color: TColor read FColor write SetColor default clWindow;
    property ColorTo: TColor read FColorTo write SetColorTo default clBtnFace;
  end;

  TEditStyle = (esInplace,esPopup);

  {TEditLink}

  TEditLink = class(TComponent)
  private
    FOwner: TAdvStringGrid;
    FWantKeyLeftRight: Boolean;
    FWantKeyUpDown: Boolean;
    FWantKeyHomeEnd: Boolean;
    FWantKeyPriorNext: Boolean;
    FWantKeyReturn: Boolean;
    FWantKeyEscape: Boolean;
    FEditStyle: TEditStyle;
    FPopupForm: TForm;
    FPopupWidth: Integer;
    FPopupHeight: Integer;
    FForcedExit: Boolean;
    FEditCell: TPoint;
    FTag: Integer;
    FAutoPopupWidth: Boolean;
    FPopupLeft: Integer;
    FPopupTop: Integer;
    FSubClassed: boolean;
    FWantReturns: boolean;
    FWantTabs: boolean;
    FWantHTML: boolean;
    FKeepFocus: boolean;
  protected
    property ForcedExit: Boolean read FForcedExit write FForcedExit;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); virtual;
    procedure EditExit(Sender: TObject);
    procedure FormExit(Sender: TObject);
    function GetParent: TWinControl;
    function GetEditControl:TWinControl; virtual;
    function GetCellValue: string;
    procedure SetCellValue(s: string);
    procedure CreateEditor(AParent: TWinControl); virtual;
    procedure DestroyEditor; virtual;
    procedure HideEditor;
    procedure RestoreWinProc;
    procedure SetFocus(Value: Boolean); virtual;
    procedure SetRect(r:TRect); virtual;
    procedure SetVisible(Value: Boolean); virtual;
    procedure SetProperties; virtual;
    procedure SetCellProps(AColor: TColor; AFont: TFont); virtual;
    function GetEditorValue:string; virtual;
    procedure SetEditorValue(s:string); virtual;
    property Grid: TAdvStringGrid read FOwner;
    property KeepFocus: Boolean read FKeepFocus write FKeepFocus;
    property EditCell:TPoint read FEditCell;
    property WantReturns: Boolean read FWantReturns write FWantReturns;
    property WantTabs: Boolean  read FWantTabs write FWantTabs;
    property WantHTML: boolean read FWantHTML write FWantHTML;
  published
    property AutoPopupWidth: Boolean read FAutoPopupWidth write FAutoPopupWidth default false;
    property EditStyle: TEditStyle read FEditStyle write FEditStyle default esInplace;
    property PopupLeft: Integer read FPopupLeft write FPopupLeft default -1;
    property PopupTop: Integer read FPopupTop write FPopupTop default -1;
    property PopupWidth: Integer read FPopupWidth write FPopupWidth default 0;
    property PopupHeight: Integer read FPopupHeight write FPopupHeight default 0;
    property WantKeyLeftRight: Boolean read FWantKeyLeftRight write FWantKeyLeftRight;
    property WantKeyUpDown: Boolean read FWantKeyUpDown write FWantKeyUpDown;
    property WantKeyHomeEnd: Boolean read FWantKeyHomeEnd write FWantKeyHomeEnd;
    property WantKeyPriorNext: Boolean read FWantKeyPriorNext write FWantKeyPriorNext;
    property WantKeyReturn: Boolean read FWantKeyReturn write FWantKeyReturn default false;
    property WantKeyEscape: Boolean read FWantKeyEscape write FWantKeyEscape default false;
    property Tag: Integer read FTag write FTag;
  end;


  {TControlCombo}

  TControlCombo = class(TASGCombobox)
  private
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
  protected
    procedure KeyPress(var Key: Char); override;
  end;

  {TControlEdit}

  TControlEdit = class(TMaskEdit)
  private
    procedure WMKeyDown(var Msg:TWMKeydown); message WM_KEYDOWN;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
  protected
    procedure KeyPress(var Key: Char); override;
  end;

  {TGridCombo}

  TGridCombo = class(TASGCombobox)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    ItemIdx: Integer;
    FAdvance: boolean;
    FOnReturnKey: TNotifyEvent;
    ItemChange: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure WndProc(var Message: TMessage); override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    procedure DoChange;
    constructor Create(AOwner: TComponent); override;
    procedure SizeDropDownWidth;
  published
    property OnReturnKey: TNotifyEvent read FOnReturnKey write FOnReturnKey;
  end;

  {TGridSpin}

  TGridSpin = class(TAsgSpinEdit)
  private
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
  protected
    procedure DoClick(UpDown: Boolean);
    procedure UpClick (Sender: TObject); override;
    procedure DownClick (Sender: TObject); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
    procedure Change; override;
    procedure CheckMinMax;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
  end;

  TGridTransEdit = class(TCustomEdit)
  private
    FRow: Integer;
    FCol: Integer;
    FFilterEdit: boolean;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    function StopEdit: Boolean;
    property BorderStyle;
    property FilterEdit: boolean read FFilterEdit write FFilterEdit;
  published
    property Col: Integer read FCol write FCol;
    property Row: Integer read FRow write FRow;
  end;

  TGridTransCombo = class(TCustomComboBox)
  private
    FRow: Integer;
    FCol: Integer;
    function GetDropWidth: integer;
    procedure SetDropWidth(const Value: integer);
  protected
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    function StopEdit: Boolean;
    procedure SizeDropDownWidth;
    property DropWidth: integer read GetDropWidth write SetDropWidth;
  published
    property Col: Integer read FCol write FCol;
    property Row: Integer read FRow write FRow;
  end;


  ///EDITORINTEGRATION
  ///

  TGridTrackbarDropDown = class(TAdvTrackBarDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure WndProc(var Message: TMessage); override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    procedure DoChange;
    constructor Create(AOwner: TComponent); override;
  end;
  
  TGridMemoDropDown = class(TAdvMemoDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridCalculatorDropDown = class(TAdvCalculatorDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridTimepickerDropDown = class(TAdvTimePickerDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridDetailPickerDropDown = class(TAdvDetailDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridGridDropDown = class(TAdvMultiColumnDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridAdvGridDropDown = class(TCustomAdvGridDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
    function GetAdvGrid: TAdvStringGrid;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    property Grid: TAdvStringGrid read GetAdvGrid;
  end;

  TGridColorDropDown = class(TAdvColorPickerDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridImageDropDown = class(TAdvImagePickerDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;

  TGridControlDropDown = class(TAdvControlDropDown)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  end;


  ///EDITORINTEGRATION


  {$IFDEF TMSUNICODE}

  {TGridUniEdit}

  TGridUniEdit = class(TAsgUniEdit)
  private
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
  published
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  end;

  { TGridUniEdit }

  TGridUniEditBtn = class(TAsgUniEditBtn)
  private
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
  published
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  end;

  { TGridUniCombo }

  TGridUniCombo = class(TASGUniCombobox)
  private
    Forced: Boolean;
    WorkMode: Boolean;
    ItemIdx: Integer;
    FOnReturnKey: TNotifyEvent;
    ItemChange: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure WndProc(var Message: TMessage); override;
  public
    FGrid: TAdvStringGrid;
    procedure DoChange;
    constructor Create(AOwner: TComponent); override;
    procedure SizeDropDownWidth;
  published
    property OnReturnKey: TNotifyEvent read FOnReturnKey write FOnReturnKey;
  end;

  TGridUniMemo = class(TAsgUniMemo)
  private
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
  published
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  end;

  {$ENDIF}

  { TGridDateTimePicker }

  TGridDatePicker = class(TAsgDateTimePicker)
  private
    Fy, Fm, Fd: word;
    Fth, Ftm, Fts, Ftms: Word;
    FOldDropped: Boolean;
    FWeekNumbers: Boolean;
    FShowToday: Boolean;
    FShowTodayCircle: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
    procedure WMNCPaint (var Message: TMessage); message WM_NCPAINT;
  protected
    procedure WndProc(var Message: TMessage); override;
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure ShiftFocus; virtual;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
    {$IFDEF DELPHI2006_LVL}
    property Text;
    {$ENDIF}
    property Weeknumbers: boolean read FWeekNumbers write FWeekNumbers default false;
    property ShowToday: boolean read FShowToday write FShowToday default true;
    property ShowTodayCircle: boolean read FShowTodayCircle write FShowTodayCircle default true;
  end;

  TGridDateTimePicker = class(TAdvDateTimePicker)
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
  published
  end;

  {TGridCheckBox}

  TGridCheckBox = class(TCheckBox)
  private
    procedure WMLButtonDown(var Msg:TWMLButtonDown); message WM_LBUTTONDOWN;
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner:tComponent); override;
    procedure ReCreate;
  end;

  {TGridEditBtn}

  TGridEditBtn = class(TAsgEditBtn)
  private
    WorkMode: boolean;
    FSelKeyDown: integer;
    FGrid: TAdvStringGrid;
    FStopEditAfterClick: boolean;
    procedure WMSetFocus(var Msg: TMessage); message WM_SETFOCUS;
    procedure WMKillFocus(var Msg: TMessage); message WM_KILLFOCUS;
    procedure WMChar(var Msg:TWMChar); message WM_CHAR;
    procedure WMPaste(var Msg:TMessage); message WM_PASTE;
    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
  protected
    procedure ExtClick(Sender: TObject);
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
    procedure Change; override;
    procedure DoChange;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
    property StopEditAfterClick: boolean read FStopEditAfterClick write FStopEditAfterClick default false;
  end;

  {TGridUnitEditBtn}

  TGridUnitEditBtn = class(TAsgUnitEditBtn)
  private
    FGrid: TAdvStringGrid;
    procedure WMChar(var Msg:TWMChar); message WM_CHAR;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
  protected
    procedure ExtClick(Sender: TObject);
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
  end;

  {TGridButton}

  TGridButton = class(TButton)
  private
    FGrid:TAdvStringGrid;
  protected
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure WMLButtonUp(var Msg:TWMLButtonDown); message WM_LBUTTONUP;
//    procedure WMKeyDown(var Msg:TWMKeydown); message WM_KEYDOWN;
//    procedure WMKeyUp(var Msg:TWMKeydown); message WM_KEYUP;

    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;

    procedure DoExit; override;
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
    {$IFDEF DELPHI2006_LVL}
    property Text;
    {$ENDIF}
  end;

  {TAdvInplaceEdit}

  TAdvInplaceEdit = class(TInplaceEdit)
  private
    FSelKeyDown: Integer;
    FOldSelStart: integer;
    FLengthLimit: SmallInt;
    FValign: Boolean;
    FWordWrap: Boolean;
    GotKey: Boolean;
    FGotFocus: Boolean;
    Workmode: Boolean;
    FGrid: TAdvStringGrid;
    FColE,FRowE: integer;
    FAltBack: boolean;
    procedure SetVAlign(Value: Boolean);
    procedure SetWordWrap(Value: Boolean);
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
    procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
    procedure WMKeyDown(var Msg:TWMKeydown); message WM_KEYDOWN;
    procedure WMKeyUp(var Msg:TWMKeydown); message WM_KEYUP;
    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
    procedure WMChar(var Msg:TWMKey); message WM_CHAR;
    procedure WMPaste(var Msg:TMessage); message WM_PASTE;
    procedure WMCopy(var Msg:TMessage); message WM_COPY;
    procedure WMCut(var Msg:TMessage); message WM_CUT;
    procedure CMWantSpecialKey(var Msg:TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure UpdateSize;
  protected
    procedure CreateParams(var Params:TCreateParams); override;
    procedure CreateWnd; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure UpdateContents; override;
    procedure BoundsChanged; override;
    procedure Change; override;
    procedure WndProc(var Msg: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DoChange;
    {$IFDEF DELPHIXE_LVL}
    property ImeMode;
    property ImeName;
    {$ENDIF}
  published
    property VAlign: Boolean read FVAlign write SetVAlign;
    property WordWrap: Boolean read FWordwrap write SetWordWrap;
    property LengthLimit: smallint read FLengthLimit write FLengthLimit;
    property PopupMenu;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseMove;
    property OnMouseDown;
    property OnMouseUp;
    property OnChange;
  end;

  TNoActiveForm = class(TForm)
  private
    FEnabled: boolean;
    procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
    procedure WMMouseActivate(var Msg: TWMMouseActivate); message WM_MOUSEACTIVATE;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    property Enabled: boolean read FEnabled write FEnabled;
  end;

  TFilterCells = (fcVirtual, fcNormal, fcStripHTML, fcCalculated, fcRow);

  TFilterMethod = (fmExpression, fmLiteral);

  {TFilterData}

  TFilterData = class(TCollectionItem)
  private
    FColumn: SmallInt;
    FCondition: string;
    FCaseSensitive: Boolean;
    FSuffix: string;
    FPrefix: string;
    FFriendlyName: string;
    FOperation: TFilterOperation;
    FData: TFilterCells;
    FMethod: TFilterMethod;
    FFilterType: TFilterType;
    FEnabled: boolean;
    FRemoveAccented: boolean;
  protected
  public
    constructor Create(ACollection: TCollection); override;
    procedure Assign(Source: TPersistent); override;
    procedure BuildCondition(s: string);
    property FilterType: TFilterType read FFilterType write FFilterType;
    property FriendlyName: string read FFriendlyName write FFriendlyName;
  published
    property Column: smallint read FColumn write FColumn;
    property Condition:string read FCondition write FCondition;
    property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive default True;
    property Data: TFilterCells read FData write FData default fcVirtual;
    property Enabled: boolean read FEnabled write FEnabled default true;
    property Prefix: string read FPrefix write FPrefix;
    property Suffix: string read FSuffix write FSuffix;
    property Operation: TFilterOperation read FOperation write FOperation;
    property Method: TFilterMethod read FMethod write FMethod;
    property RemoveAccented: boolean read FRemoveAccented write FRemoveAccented default False;
  end;

  {TFilter}

  TFilter = class(TCollection)
  private
    FOwner: TAdvStringGrid;
    function GetItem(Index: Integer): TFilterData;
    procedure SetItem(Index: Integer; Value: TFilterData);
    function GetColFilter(Col: Integer): TFilterData;
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create(AOwner: TAdvStringGrid);
    function Add: TFilterData;
    function Insert(index: Integer): TFilterData;
    property Items[Index: Integer]: TFilterData read GetItem write SetItem; default;
    property ColumnFilter[Col: Integer]: TFilterData read GetColFilter;
    function HasFilter(Col: integer): Boolean;
    function HasOtherFilter(Col: integer): Boolean;
    function HasFilterType(Col: integer): TFilterType;
    procedure RemoveColumnFilter(Col: integer);
  protected
    function GetOwner: TPersistent; override;
  end;

  {TGridItem}

  TGridItem = class(TCollectionItem)
  private
    FIdx: Integer;
    FHeight: Integer;
    FItems: TStrings;
    FLevel: Integer;
    procedure SetIdx(const Value: Integer);
    procedure SetItems(const Value: TStrings);
    procedure SetHeight(const Value: Integer);
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property Idx: Integer read FIdx write SetIdx;
    property Height: Integer read FHeight write SetHeight;
    property Level: Integer read FLevel write FLevel;
    property Items: TStrings read FItems write SetItems;
  end;

  {TAdvRichEdit}

  TAdvRichEdit = class(TRichEdit)
  private
    FGrid: TAdvStringGrid;
    FReqHeight: Integer;
    FReqWidth: Integer;
    FLocked: Boolean;
    procedure SelFormat(offset: Integer);
    procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure WMKillFocus(var Msg:TMessage); message WM_KILLFOCUS;
    procedure CNNotify(var Msg:TWMNotify); message CN_NOTIFY;
  protected
    procedure Lock;
    procedure Unlock;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
    procedure SelSubscript;
    procedure SelSuperscript;
    procedure SelNormal;
    function IsSelSubscript: Boolean;
    function IsSelSuperscript: Boolean;
    function IsSelNormal: Boolean;
  published
    property ReqWidth: Integer read FReqWidth;
    property ReqHeight: Integer read FReqHeight;
  end;

  TMouseSelectMode = (msNormal,msColumn,msRow,msAll,msURL,msResize);
  TClipOperation = (coCut,coCopy);

  {OLE Drag & Drop helper objects}

  TDragDropSettings = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    FOleDropRTF: Boolean;
    FOleAcceptText: Boolean;
    FOleEntireRows: Boolean;
    FOleDropSource: Boolean;
    FOleRemoveRows: Boolean;
    FOleAcceptFiles: Boolean;
    FOleAcceptURLs: Boolean;
    FOleDropTarget: Boolean;
    FOleInsertRows: Boolean;
    FOleAppendRows: Boolean;
    FOleCopyAlways: Boolean;
    FOleColumnDragDrop: Boolean;
    FOleColumnReorder: Boolean;
    FOleColumnsOnly: Boolean;
    FShowCells: Boolean;
    procedure SetOleDropRTF(const Value: Boolean);
    procedure SetOleDropTarget(const Value: Boolean);
    procedure SetShowCells(const Value: boolean);
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property ShowCells: boolean read FShowCells write SetShowCells default True;
    property OleAcceptFiles: Boolean read FOleAcceptFiles write FOleAcceptFiles default True;
    property OleAcceptText: Boolean read FOleAcceptText write FOleAcceptText default True;
    property OleAcceptURLs: Boolean read FOleAcceptURLs write FOleAcceptURLs default True;
    property OleAppendRows: Boolean read FOleAppendRows write FOleAppendRows default False;
    property OleColumnDragDrop: Boolean read FOleColumnDragDrop write FOleColumnDragDrop default False;
    property OleColumnReorder: Boolean read FOleColumnReorder write FOleColumnReorder default False;
    property OleColumnsOnly: Boolean read FOleColumnsOnly write FOleColumnsOnly default False;
    property OleCopyAlways: Boolean read FOleCopyAlways write FOleCopyAlways default False;
    property OleDropTarget: Boolean read FOleDropTarget write SetOleDropTarget default False;
    property OleDropSource: Boolean read FOleDropSource write FOleDropSource default False;
    property OleEntireRows: Boolean read FOleEntireRows write FOleEntireRows default False;
    property OleInsertRows: Boolean read FOleInsertRows write FOleInsertRows default False;
    property OleRemoveRows: Boolean read FOleRemoveRows write FOleRemoveRows default False;
    property OleDropRTF: Boolean read FOleDropRTF write SetOleDropRTF default False;

  end;

  TGridDropTarget = class(TASGDropTarget)
  private
    FGrid: TAdvStringGrid;
  public
    constructor Create(AGrid:TAdvStringGrid);
    procedure DropText(pt:TPoint;s:string); override;
    procedure DropStream(pt:TPoint; ms: TMemoryStream); override;
    procedure DropCol(pt:TPoint;Col: Integer); override;
    procedure DropRTF(pt:TPoint;s:string); override;
    procedure DropFiles(pt:TPoint;files:tstrings); override;
    procedure DropURL(pt:TPoint;s:string); override;
    procedure DragMouseMove(pt:TPoint;var Allow: Boolean; DropFormats:TDropFormats); override;
    procedure DragMouseLeave; override;
  end;

  TGridDropSource = class(TASGDropSource)
  private
    FGrid:TAdvStringGrid;
    FLastEffect: Integer;
  protected
    procedure DragDropStop; override;
  public
    constructor Create(aGrid:TAdvStringGrid);
    procedure CurrentEffect(dwEffect: Longint); override;
    procedure QueryDrag; override;
    property LastEffect: Integer read FLastEffect;
  end;

  {}

  ITAdvStringGridSelect = interface ['{ED636930-EF86-46AD-80F7-FD29C28525EB}']
    procedure SelectionChange(Col,Row: integer);
  end;

  {TGridChangeNotifier}

  TGridChangeNotifier = class(TComponent)
  protected
    procedure CellsChanged(R:TRect); virtual;
  end;

  {THTMLHintWindow}

  THTMLHintWindow = class(THintWindow)
  private
    FImages: TCustomImageList;
    FPictureContainer: TPictureContainer;
    FTextHeight, FTextWidth: Integer;
    FWideCaption: widestring;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  protected
    procedure Paint; override;
    procedure CreateParams(var Params: TCreateParams); override;
    property WideCaption: widestring read FWideCaption write FWideCaption;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ActivateHint(Rect: TRect; const AHint: string); override;
    {$IFDEF DELPHI_UNICODE}
    procedure ActivateHintData(Rect: TRect; const AHint: string; AData: TCustomData); override;
    {$ENDIF}
    function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect; override;
  published
  end;

  TRetEdit = class(TEdit)
  private
    FOnReturn: TNotifyEvent;
    FOnCtrlReturn: TNotifyEvent;
    procedure WMKeyDown(var Msg:TWMKeydown); message WM_KEYDOWN;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  published
    property OnReturn: TNotifyEvent read FOnReturn write FOnReturn;
    property OnCtrlReturn: TNotifyEvent read FOnCtrlReturn write FOnCtrlReturn;
  end;

  { TSearchPanel }

  TSearchPanel = class(TPanel)
  private
    FGrid: TAdvStringGrid;
    FEdit: TRetEdit;
    FExitButton: TAdvGridButton;
    FForwardButton: TAdvGridButton;
    FBackwardButton: TAdvGridButton;
    FHiliteButton: TAdvGridButton;
    FMatchCase: TAdvCheckBox;
    FOnForwardClick: TNotifyEvent;
    FOnBackwardClick: TNotifyEvent;
    FOnEditChange: TNotifyEvent;
    FOnExitClick: TNotifyEvent;
    FOnHighLightClick: TNotifyEvent;
    FOnMatchCaseClick: TNotifyEvent;
    FColorTo: TColor;
    FFindNextCaption: string;
    FFindPrevCaption: string;
    FMatchCaseCaption: string;
    FHintFindPrev: string;
    FHintClose: string;
    FHintFindNext: string;
    FHintHighlight: string;
    FHighLightCaption: string;
    procedure SetColorTo(const Value: TColor);
  protected
    procedure ForwardClick(Sender: TObject);
    procedure BackwardClick(Sender: TObject);
    procedure ExitClick(Sender: TObject);
    procedure HighlightClick(Sender: TObject);
    procedure MatchCaseClick(Sender: TObject);
    procedure EditChange(Sender: TObject);
    procedure EditKeydown(Sender: TObject; var Key: word; shift: TShiftState);
    procedure EditReturn(Sender: TObject);
    procedure EditCtrlReturn(Sender: TObject);
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure CreateWnd; override;
    property FindNextCaption: string read FFindNextCaption write FFindNextCaption;
    property FindPrevCaption: string read FFindPrevCaption write FFindPrevCaption;
    property MatchCaseCaption: string read FMatchCaseCaption write FMatchCaseCaption;
    property HighLightCaption: string read FHighlightCaption write FHighLightCaption;
    property HintClose: string read FHintClose write FHintClose;
    property HintFindNext: string read FHintFindNext write FHintFindNext;
    property HintFindPrev: string read FHintFindPrev write FHintFindPrev;
    property HintHighlight: string read FHintHighlight write FHintHighlight;
    property EditControl: TRetEdit read FEdit;
    property MatchCase: TAdvCheckBox read FMatchCase;
    property HiliteButton: TAdvGridButton read FHiliteButton;
    property ForwardButton: TAdvGridButton read FForwardButton;
    property BackwardButton: TAdvGridButton read FBackwardButton;
    property ExitButton: TAdvGridButton read FExitButton;
  published
    property ColorTo: TColor read FColorTo write SetColorTo default clNone;
    property OnBackwardClick: TNotifyEvent read FOnBackwardClick write FOnBackwardClick;
    property OnEditChange: TNotifyEvent read FOnEditChange write FOnEditChange;
    property OnForwardClick: TNotifyEvent read FOnForwardClick write FOnForwardClick;
    property OnHighlightClick: TNotifyEvent read FOnHighLightClick write FOnHighLightClick;
    property OnMatchCaseClick: TNotifyEvent read FOnMatchCaseClick write FOnMatchCaseClick;
    property OnExitClick: TNotifyEvent read FOnExitClick write FOnExitClick;
  end;


  TFooterPaintEvent = procedure(Sender: TObject; AColumn: Integer; Canvas: TCanvas; ARect: TRect) of object;

  { TFooterPanel }

  TFooterPanel = class(TCustomPanel)
  private
    FGrid: TAdvStringGrid;
    FLastHintX: integer;
    procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
    procedure CMHintShow(var Msg: TCMHintShow); message CM_HINTSHOW;
  protected
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    function HTMLColReplace(s:string):string;
    function PaintLastRow: integer;
    function PaintColPreview: integer;
    function PaintCustomPreview: integer;
    function PaintCustomPaint: integer;
    procedure Paint; override;
    procedure CreateWnd; override;
    function RTLCoord(rtl: boolean; ARect: TRect): TRect;
    function GridColWidths: integer;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property BorderWidth;
    property OnMouseDown;
    property OnMouseUp;
    {$IFDEF DELPHI_UNICODE}
    property OnMouseLeave;
    property OnMouseEnter;
    {$ENDIF}
    property OnMouseMove;
  end;

  TFooterStyle = (fsFixedLastRow, fsColumnPreview, fsCustomPreview, fsCustomPaint);

  { TFloatingFooter }

  TFloatingFooter = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    FDidInc: boolean;
    FHeight: Integer;
    FVisible: Boolean;
    FColor: TColor;
    FFooterStyle: TFooterStyle;
    FColumn: Integer;
    FOnCalcFooter: TCalcFooterEvent;
    FCustomTemplate: string;
    FCalculateHiddenRows: Boolean;
    FEnableCalculation: Boolean;
    FShowHint: boolean;
    FBorderColor: TColor;
    procedure SetHeight(const Value: Integer);
    procedure SetVisible(const Value: Boolean);
    procedure SetColor(const Value: TColor);
    procedure SetFooterStyle(const Value: TFooterStyle);
    procedure SetColumn(const Value: Integer);
    procedure SetCustomTemplate(const Value: string);
    function GetColumnCalc(c: Integer): TColumnCalcType;
    procedure SetColumnCalc(c: Integer; const Value: TColumnCalcType);
    procedure SetEnableCalculation(const Value: Boolean);
    procedure SetShowHint(const Value: boolean);
    procedure SetBorderColor(const Value: TColor);
  protected
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure Invalidate;
    property Height: Integer read FHeight write SetHeight;
    property ColumnCalc[c: Integer]: TColumnCalcType read GetColumnCalc write SetColumnCalc;
    property EnableCalculation: Boolean read FEnableCalculation write SetEnableCalculation;
  published
    property BorderColor: TColor read FBorderColor write SetBorderColor default clNone;
    property CalculateHiddenRows: Boolean read FCalculateHiddenRows write FCalculateHiddenRows default True;
    property Color: TColor read FColor write SetColor default clBtnFace;
    property Column: Integer read FColumn write SetColumn default 0;
    property CustomTemplate: string read FCustomTemplate write SetCustomTemplate;
    property FooterStyle: TFooterStyle read FFooterStyle write SetFooterStyle default fsFixedLastRow;
    property ShowHint: boolean read FShowHint write SetShowHint default False;
    property Visible: Boolean read FVisible write SetVisible default False;
    property OnCalcFooter: TCalcFooterEvent read FOnCalcFooter write FOnCalcFooter;
  end;

  { TCellAlignment }

  TCellAlignment = record
    Alignment: TAlignment;
    VAlignment: TVAlignment;
  end;

  THoverFixedCells = (hfNone, hfAll, hfFixedRows, hfFixedColumns);

  TScrollProp = record
    PageSize: integer;
    Range: integer;
  end;

  TInvalidEntryIcon = (ieNone, ieInfo, ieWarning, ieError);

  TBalloonIcon = (biNone, biInfo, biWarning, biError);

  TCharSet = set of AnsiChar;

  TScrollDirection = (sdVertical, sdHorizontal);

  THintShowLargeTextPos = (hpCell, hpCursor);

  TScrollControl = class(TCustomControl)
  private
    FColor: TColor;
    FScrollWidth: integer;
    FDownOnScroller: boolean;
    FDownPos: integer;
    FDownRow: integer;
    FDirection: TScrollDirection;
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
    function Grid: TAdvStringGrid;
    procedure SetColor(const AValue: TColor);
    procedure GetScrollPos(var APos,ASize: integer);
    function GetScrollSize: integer;
    function GetScrollOffset: integer;
  protected
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);override;
    procedure MouseUp(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);override;
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Color: TColor read FColor write SetColor default clSilver;
    property ScrollWidth: integer read FScrollWidth write FScrollWidth default 4;
    property Direction: TScrollDirection read FDirection write FDirection default sdVertical;
  end;

  TColorSetting = class(TPersistent)
  private
    FTextColor: TColor;
    FOnChange: TNotifyEvent;
    FBkgColor: TColor;
    procedure SetBkgColor(const Value: TColor);
    procedure SetTextColor(const Value: TColor);
  protected
    procedure Changed; virtual;
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
  published
    property TextColor: TColor read FTextColor write SetTextColor default clNone;
    property BkgColor: TColor read FBkgColor write SetBkgColor default clNone;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  TAutoColor = class(TPersistent)
  private
    FNegativeNumber: TColorSetting;
    FPositiveNumber: TColorSetting;
    FOnChange: TNotifyEvent;
    procedure SetNegativeNumber(const Value: TColorSetting);
    procedure SetPositiveNumber(const Value: TColorSetting);
  protected
    procedure ValueChanged(Sender: TObject);
    procedure Changed; virtual;
    function ColorsDefined: boolean;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property NegativeNumber: TColorSetting read FNegativeNumber write SetNegativeNumber;
    property PositiveNumber: TColorSetting read FPositiveNumber write SetPositiveNumber;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  {THeaderDragButton}

  THeaderDragButton = class(TCustomControl)
  private
    FGrid: TAdvStringGrid;
    FCaption:string;
    FFlat:boolean;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    procedure Paint; override;
    property Grid: TAdvStringGrid read FGrid write FGrid;
  published
    property Caption:string read FCaption write FCaption;
    property Flat: boolean read FFlat write FFlat;
  end;

  TCalcType = (ctSum,ctAvg,ctMin,ctMax);

  TFormatType = (ftVCL, ftExcel);

  TScrollPosition = (spMiddle, spTrailing, spLeading);

  THoverButtonClickEvent = procedure(Sender: TObject; ARow: integer; AButton: THoverButtonsCollectionItem) of object;

  TColumnType = (ctNumeric, ctFloat, ctAlpha, ctDate, ctTime, ctBoolean);

  TAdvGridPopup = class(TComponent)
  private
    FGrid: TAdvStringGrid;
    FGridCell: TGridCoord;
    FVisible: boolean;
  protected
    property Grid: TAdvStringGrid read FGrid write FGrid;
    property GridCell: TGridCoord read FGridCell write FGridCell;
  public
    procedure Show(PT: TPoint); virtual;
    procedure Hide; virtual;
    function MouseInPopup(PT: TPoint): boolean; virtual; abstract;
    property Visible: boolean read FVisible;
  end;

  TPopupToolBarMode = (tbActiveCell, tbHoverCell, tbHoverNormalCell, tbNone);

  ITMSCellValidate = interface
  ['{20335AC0-CD66-42FE-BBD6-BBB1B017CD03}']
    procedure ValidateCell(ACol,ARow:integer; var AValue: string; var Valid: boolean);
  end;

  {TAdvStringGrid}
  {$IFDEF DELPHIXE2_LVL}
  [ComponentPlatformsAttribute(pidWin32 or pidWin64)]
  {$ENDIF}
  TAdvStringGrid = class(TBaseGrid, ITMSStyleEx, ITMSTones)
  private
    {$IFDEF FREEWARE}
    cla:string;
    {$ENDIF}
    ptdown: TPoint;
    FTopDown: integer;
    FLeftRight: integer;
    FScrollVert: boolean;
    vscrlctrl: TScrollControl;
    hscrlctrl: TScrollControl;
    FStyle: TTMSStyle;
    FLastKeyCell: TPoint;
    FFilterLevel: Integer;
    FLastFilter: string;
    FForceSel: Boolean;
    FMoveColInd : Integer;
    FMoveRowInd : Integer;
    FGroupColumn : Integer;
    FGroupCaption : string;
    FGroupFooter: string;
    FGroupWidth : Integer;
    FAutoSize : Boolean;
    FAutoNumAlign : Boolean;
    FEnhTextSize : Boolean;
    FEditWithTags: Boolean;
    FOemConvert : Boolean;
    FLookup : Boolean;
    FLoaded: Boolean;
    FLookupCaseSensitive: Boolean;
    FDeselectState : Boolean;
    FSelectionClick : Boolean;
    FMouseDown : Boolean;
    FSelChange: Boolean;
    FDoOnClick: Boolean;
    FMouseKeepDown: Boolean;
    FCtrlDown: Boolean;
    FCtrlDownId: string;
    FMouseResize: Boolean;
    FMouseDownMove: Boolean;
    FLookupHistory : Boolean;
    FEnhRowColMove : Boolean;
    FSizeWithForm : Boolean;
    FMultilineCells : Boolean;
    FSortRowXRef: TIntList;
    FUnSortRowXRef: TIntList;
    FMergedColumns: TIntList;
    FSelectedCells: TIntList;
    FSelectedRows: TIntList;
    FModifiedRows: TIntList;
    FEnabledRows: TIntList;
    FOnGetCellColor: TGridColorEvent;
    FOnGetCellCursor: TCellCursorEvent;
    FOnGetCellGradient: TGridGradientEvent;
    FOnGetCellPrintColor: TGridColorEvent;
    FOnGetCellBorder: TGridBorderEvent;
    FOnGetCellPrintBorder: TGridBorderEvent;
    FOnGetAlignment: TGridAlignEvent;
    FOnGetFormat: TGridFormatEvent;
    FOnGetFloatFormat: TFloatFormatEvent;
    FOnGetCheckTrue: TGetCheckEvent;
    FOnGetCheckFalse: TGetCheckEvent;
    FOnRowDisjunctSelect: TRowDisjunctSelectEvent;
    FOnRowDisjunctSelected: TAutoInsertRowEvent;
    FOnGridHint: TGridHintEvent;
    FOnGridWideHint: TGridWideHintEvent;
    FOnRowChanging: TRowChangingEvent;
    FOnRowChanged: TRowChangedEvent;
    FOnColChanging: TColChangingEvent;
    FOnCellChanging: TCellChangingEvent;
    FOnAutoAdvance: TAutoAdvanceEvent;
    FOnShowHint: TShowHintEvent;
    FOnCanAddRow: TCanAddRowEvent;
    FOnCanAddCol: TCanAddColEvent;
    FOnAutoAddRow: TAutoAddRowEvent;
    FOnCanInsertRow: TCanInsertRowEvent;
    FOnAutoInsertRow: TAutoInsertRowEvent;
    FOnAutoInsertCol: TAutoInsertColEvent;
    FOnCanDeleteRow: TCanDeleteRowEvent;
    FOnAutoDeleteRow: TAutoDeleteRowEvent;
    FOnOleDrop: TOleDragDropEvent;
    FOnOleDrag: TOleDragDropEvent;
    FOnOleDragOver: TOleDragOverEvent;
    FOnOleDragStart: TOleDragStartEvent;
    FOnOleDragStop: TOleDragStopEvent;
    FOnOleDropCol: TOleDropColEvent;
    FOnOleDropped: TOleDroppedEvent;
    FGridDropTarget: TGridDropTarget;
    FOnOleDropFile: TOleDropFileEvent;
    FOnOleDropURL: TOleDropURLEvent;
    FOnClickSort: TClickSortEvent;
    FOnCanSort: TCanSortEvent;
    FOnExpandNode: TNodeClickEvent;
    FOnContractNode: TNodeClickEvent;
    FOnBeforeExpandNode: TNodeAllowEvent;
    FOnBeforeContractNode: TNodeAllowEvent;
    FCustomCompare: TCustomCompareEvent;
    FRawCompare: TRawCompareEvent;
    FOnSearchEditChange: TSearchEditChangeEvent;
    FOnSearchFooterAction: TSearchFooterActionEvent;
    FOnSearchFooterSearchEnd: TSearchFooterSearchEndEvent;
    FOnSearchFooterClose: TNotifyEvent;
    FOnClipboardPaste: TClipboardEvent;
    FOnClipboardPasteDone: TClipboardPasteDoneEvent;
    FOnClipboardCut: TClipboardEvent;
    FOnClipboardCutDone: TClipboardPasteDoneEvent;
    FOnClipboardCopy: TClipboardEvent;
    FOnClipboardCopyDone:  TClipboardPasteDoneEvent;
    FOnClipboardBeforePasteCell: TBeforeCellPasteEvent;
    FOnClipboardAfterPasteCell: TAfterCellPasteEvent;
    FOnClipboardBeforePasteWideCell: TBeforeCellPasteWideEvent;
    FOnClipboardAfterPasteWideCell: TAfterCellPasteWideEvent;
    FOnResize: TOnResizeEvent;
    FOnPrintStart: TGridPrintStartEvent;
    FOnPrintCancel: TGridPrintCancelEvent;
    FOnPrintPage: TGridPrintPageEvent;
    FOnPrintGetPageNum: TGridPrintPageNumEvent;
    FOnPrintNewPage: TGridPrintNewPageEvent;
    FOnPrintPageDone: TGridPrintPageDoneEvent;
    FOnPrintDone: TNotifyEvent;
    FOnPrintSetColumnWidth: TGridPrintColumnWidthEvent;
    FOnPrintSetRowHeight: TGridPrintRowHeightEvent;
    FDoFitToPage: TDoFitToPageEvent;
    FOnClickCell: TClickCellEvent;
    FOnRightClickCell: TClickCellEvent;
    FOnDblClickCell: TDblClickCellEvent;
    FOnCanEditCell: TCanEditCellEvent;
    FOnCanClickCell: TCanClickCellEvent;
    FOnIsFixedCell: TIsFixedCellEvent;
    FOnFixedEdit: TFixedEditEvent;
    FOnIsPasswordCell: TIsPasswordCellEvent;
    FOnAnchorClick: TAnchorClickEvent;
    FOnAnchorEnter: TAnchorEvent;
    FOnAnchorExit: TAnchorEvent;
    FOnAnchorHint: TAnchorHintEvent;
    FOnControlClick: TCellControlEvent;
    FOnControlEditDone: TCellControlEvent;
    FOnControlComboList: TCellComboControlEvent;
    FOnControlComboSelect: TCellComboControlSelectEvent;
    FOnCellValidate: TCellValidateEvent;
    FOnCellValidateWide: TCellValidateWideEvent;
    FOnCellsChanged: TCellsChangedEvent;
    FOnFileProgress: TGridProgressEvent;
    FOnFilterProgress: TGridProgressEvent;
    FOnFixedDropDownClick: TFixedDropDownEvent;
    FOnCanShowFixedDropDown: TCanShowFixedDropDownEvent;
    FOnRichEditSelectionChange: TNotifyEvent;
    FOnGetColumnFilter: TGetColumnFilterEvent;
    FOnFilterSelect: TFilterSelectEvent;
    FOnFilterCheck: TFilterCheckEvent;
    FOnFilterCheckClick: TFilterCheckClickEvent;
    FOnHasFilterEdit: THasFilterEditEvent;
    FOnFilterEditUpdate: TFilterEditUpdateEvent;
    FOnColorSelected: TColorSelectedEvent;
    FOnColorSelect: TColorSelectEvent;
    FOnImageSelected: TImageSelectedEvent;
    FOnImageSelect: TImageSelectEvent;
    FOnFilterDone: TNotifyEvent;
    FHintColor: TColor;
    FHighlightColor: TColor;
    FHighLightTextColor: TColor;
    FHintShowCells: Boolean;
    FHintShowLargeText: Boolean;
    FHintShowLargeTextPos: THintShowLargeTextPos;
    FHintShowSizing: Boolean;
    FLastHintPos: TPoint;
    FLastBalloonPos: TPoint;
    FRowIndicator: TBitmap;
    FSortIndexes: TSortIndexList;
    FBackGround:TBackGround;
    FDropSelection: TGridRect;
    FOleDropTargetAssigned: Boolean;
    ArwU,ArwD,ArwL,ArwR:TArRowWindow;
    FOnColumnSize:TColumnSizeEvent;
    FOnRowSizing : TRowSizingEvent;
    FOnColumnSizing: TColumnSizingEvent;
    FOnRowSize:TRowSizeEvent;
    FOnColumnMove:TColumnSizeEvent;
    FOnColumnMoving: TColumnSizeEvent;
    FOnRowMove:TRowSizeEvent;
    FOnRowMoving:TRowSizeEvent;
    FOnEndColumnSize: TEndColumnSizeEvent;
    FOnEndRowSize: TEndRowSizeEvent;
    FPrintSettings: TPrintSettings;
    FFastPrint: Boolean;
    FOldOfficeTheme: TOfficeTheme;
    FFocusWindow: TGridFocusWindow;
    //FPrecisePrintMeasure: Boolean;
    FHTMLSettings: THTMLSettings;
    FBands: TBands;
    FBorderColor: TColor;
    FNavigation: TNavigation;
    FColumnSize: TColumnSize;
    FScrollProportional: Boolean;
    FCellNode: TCellNode;
    FSizeWhileTyping: TSizeWhileTyping;
    FMouseActions: TMouseActions;
    FGrouping: TGrouping;
    FVisibleCol: TBoolArray;
    FAllColWidths: TWidthArray;
    FUpdateCount: Integer;
    FLastValidation: Boolean;
    FNumNodes: Integer;
    FNumHidden: Integer;
    FSelectionColor: TColor;
    FSelectionColorTo: TColor;
    FSelectionColorMixer: boolean;
    FSelectionColorMixerFactor: integer;
    FSelectionMirrorColor: TColor;
    FSelectionMirrorColorTo: TColor;
    FSelectionTextColor: TColor;
    FSelectionRectangle: Boolean;
    FSelectionRTFKeep: Boolean;
    FVAlignment: TVAlignment;
    FVAlign: DWORD;
    FURLShow: Boolean;
    FURLShowInText: Boolean;
    FURLUnderlineOnHover: Boolean;
    FURLFull: Boolean;
    FURLColor: TColor;
    FURLEdit: Boolean;
    FGridImages: TCustomImageList;
    FIntelliPan: TIntelliPan;
    FIntelliZoom: Boolean;
    FScrollType: TScrollType;
    FScrollColor: TColor;
    FScrollWidth: Integer;
    FScrollSynch: Boolean;
    FScrollHints: TScrollHintType;
    FIsFlat: Boolean;
    FRichEdit: TAdvRichEdit;
    FInplaceRichEdit: TAdvRichEdit;
    FFixedAsButtons: Boolean;
    FFixedDropDownMenu: TPopupMenu;
    FFixedCellPushed: Boolean;
    FPushedFixedCell: TRect;
    FPushedCellButton: TPoint;
    FHideFocusRect: Boolean;
    FFixedFont: TFont;
    FFixedRowAlways: Boolean;
    FFixedColAlways: Boolean;
    FFixedRowsMin: Integer;
    FFixedColsMin: Integer;
    FFixedColEdit: Integer;
    FFixedRowEdit: Integer;
    FColumnHeaders: TStringList;
    FRowHeaders: TStringList;
    FLookupItems: TStringList;
    FRowSelect: TList;
    FColSelect: TList;
    FFixedFooters: Integer;
    FFixedRightCols: Integer;
    FDelimiter:char;
    FNoDefaultDraw: Boolean;
    FPasswordChar:char;
    FJavaCSV: Boolean;
    FCheckTrue: String;
    FCheckFalse: String;
    FEditMask: string;
    FEnableHTML: Boolean;
    FEnableWheel: Boolean;
    FFlat: Boolean;
    FLastAnchorHint: string;
    FAnchorHint: Boolean;
    FSaveFixedCells: Boolean;
    FSaveFixedCols: Boolean;
    FSaveFixedRows: Boolean;
    FLoadFirstRow: Boolean;
    FSaveHiddenCells: Boolean;
    FSaveMergedCells: Boolean;
    FSaveVirtCells: Boolean;
    FSaveWithHTML: Boolean;
    FSaveWithRTF: Boolean;
    FWordWrapEx: Boolean;
    FModified: Boolean;
    FEditDisable: Boolean;
    FEditChange: Boolean;
    FExcelStyleDecimalSeparator: Boolean;
    FHovering: Boolean;
    FHoverFixedCells: THoverFixedCells;
    FNoMouseLeave: boolean;
    FDropDownDown: boolean;
    FHoverFixedX: integer;
    FHoverFixedY: integer;
    FFloatFormat: string;
    FOldCellText: string;
    FNewCellText: string;
    FOldCellTextWide: WideString;
    FStartEditChar: Char;
    FOldCol,FOldRow,FOldRowSel: Integer;
    FOldModifiedValue: Boolean;
    FOldCursor: Integer;
    FBlockFocus: Boolean;
    FBlockKill: Boolean;
    FDblClk: Boolean;
    FDisSelection: TGridRect;
    FOldSelection: TGridRect;
    FSizeSelection: TGridRect;
    FMoveSelection: TGridRect;
    FRowSelMod: Boolean;
    FEntered: Boolean;
    FEditing: Boolean;
    FSpecialEditor: Boolean;
    FEditActive: Boolean;
    FValidating: Boolean;
    FValidateDblClick: Boolean;
    FFindBusy: Boolean;
    FComboIdx: Integer;
    SortDir: Integer;
    SortRow: Integer;
    FSearchCell: TPoint;
    ResizeAssigned: Boolean;
    FPrintRect: TGridRect;
    FFindParams: TFindParams;
    SearchCache: string;
    SearchCacheWide: widestring;
    SearchInc: string;
    SearchTics: integer;
    FAnchor: string;
    FZoomFactor: Integer;
    FIsColChanging: Boolean;
    ColchgFlg: Boolean;
    ColMoveFlg: Boolean;
    ColSizeFlg: Boolean;
    ColSized: Boolean;
    RowSized: Boolean;
    Colclicked: longint;
    Rowclicked: longint;
    Colclickedsize: Integer;
    Rowclickedsize: Integer;
    Movecell: Integer;
    MoveOfsX: Integer;
    MoveOfsY: Integer;
    Clickposx: Integer;
    Clickposy: Integer;
    Clickposdx: Integer;
    Clickposdy: Integer;
    Invokedchange: Boolean;
    InvokedFocusChange: Boolean;
    wheelmsg: Cardinal;
    wheelscrl: Integer;
    wheelpan: Boolean;
    wheelpanpos: TPoint;
    wheeltimer: THandle;
    cf: TFont;
    prevcurs: HIcon;
    FMouseSelectMode: TMouseSelectMode;
    FMouseSelectStart: Integer;
    FPrinterdriverfix: Boolean;
    PrevRect: TRect;
    Fontscalefactor:double;
    FPrintPageWidth: Integer;
    FPrintPageRect: TRect;
    FPrintColStart: Integer;
    FPrintColEnd: Integer;
    FPrintPageFrom: Integer;
    FPrintPageTo: Integer;
    FPrintPageNum: Integer;
    FExcelClipboardFormat: Boolean;
    FGridTimerID: Integer;
    FGridBlink: Boolean;
    FMaxEditLength: Integer;
    FMaxComboLength: Integer;
    FLook: TGridLook;
    FContainer: TPictureContainer;
    FCellChecker: TAdvStringGridCheck;
    FImageCache: THTMLPictureCache;
    FCtrlXY: TPoint;
    FCtrlID: string;
    FCtrlType: string;
    FCtrlEditing: Boolean;
    FPasteAll: Boolean;
    FSpinUpClick: Boolean;
    FSpinDnClick: Boolean;
    FOrigSelection: TGridRect;
    MaxWidths: array of Integer;
    Indents: array of Integer;
    FOnGetEditorType: TGetEditorTypeEvent;
    FOnHasComboBox: THasComboEvent;
    FOnHasEditBtn: THasEditBtnEvent;
    FOnHasSpinEdit: THasSpinEditEvent;
    FOnGetEditorProp: TGetEditorPropEvent;
    FonGetEditorPropInt: TClickCellEvent;
    FOnEllipsClick: TEllipsClickEvent;
    FOnUnitChanged: TUnitChangedEvent;
    FOnButtonClick: TButtonClickEvent;
    FOnExpandClick: TExpandClickEvent;
    FOnCheckBoxClick: TCheckBoxClickEvent;
    FOnCheckBoxCanToggle: TCheckBoxCanToggleEvent;
    FOnCheckBoxMouseUp: TCheckBoxClickEvent;
    FOnCheckBoxChange: TCheckBoxClickEvent;
    FOnRatingChange: TRatingChangeEvent;
    FOnRadioClick: TRadioClickEvent;
    FOnRadioMouseUp: TRadioClickEvent;
    FOnRadioButtonClick: TRadioButtonClickEvent;
    FOnComboChange: TComboChangeEvent;
    FOnComboCloseUp: TClickCellEvent;
    FOnComboDropDown: TClickCellEvent;
    FOnDatePickerCloseUp: TClickCellEvent;
    FOnDatePickerDropDown: TClickCellEvent;
    FOnComboObjectChange: TComboObjectChangeEvent;
    FOnSpinClick: TSpinClickEvent;
    FOnFloatSpinClick: TFloatSpinClickEvent;
    FOntimeSpinClick: TDateTimeSpinClickEvent;
    FOnDateSpinClick: TDateTimeSpinClickEvent;
    FOnDateTimeChange: TDateTimeChangeEvent;
    FOnScrollHint:TScrollHintEvent;
    FEditLink: TEditLink;
    FEditControl: TControlEdit;
    FComboControl: TControlCombo;
    EditCtrl: TWinControl;
    EditCombo: TGridCombo;
    FEditSpin: TGridSpin;
    EditTrans: TGridTransEdit;
    ComboTrans: TGridTransCombo;
    /// EDITORINTEGRATION
    FEditTrackBar: TGridTrackbarDropDown;
    FEditMemo: TGridMemoDropDown;
    FEditCalculator: TGridCalculatorDropDown;
    FEditTimePicker: TGridTimePickerDropDown;
    FEditDetailPicker: TGridDetailPickerDropDown;
    FEditGridPicker: TGridGridDropDown;
    FEditColorPicker: TGridColorDropDown;
    FEditImagePicker: TGridImageDropDown;
    FEditAdvGridPicker: TGridAdvGridDropDown;
    FEditControlPicker: TGridControlDropDown;
    /// EDITORINTEGRATION
    {$IFDEF TMSUNICODE}
    EditUni: TGridUniEdit;
    MemoUni: TGridUniMemo;
    ComboUni: TGridUniCombo;
    EditBtnUni: TGridUniEditBtn;
    {$ENDIF}
    EditCheck: TGridCheckbox;
    EditBtn: TGridEditBtn;
    UnitEditBtn: TGridUnitEditBtn;
    FEditDate: TGridDatePicker;
    FEditDateTime: TGridDateTimePicker;
    GridButton: TGridButton;
    MoveButton: THeaderDragButton;
    MoveForm: TForm;
    FButtonForm: TNoActiveForm;
    EditControl: TEditorType;
    FGridItems: TCollection;
    FFilter: TFilter;
    FFilterActive: Boolean;
    FFilterNormalCellsOnly: Boolean;
    FFilterCol: Integer;
    FFilterFixedRows: Integer;
    FFilterDropDown: TFilterDropDown;
    FFilterEdit: TFilterEdit;
    FDropList: TDropList;
    FDropCheckList: TDropCheckList;
    FFilterList: TStringList;
    FAutoFilterUpdate: boolean;
    FNotifierList: TList;
    FActiveCellShow: Boolean;
    FActiveCellFont: TFont;
    FXYOffset: TPoint;
    FXYOffsetTopLeftOnly: Boolean;
    FOldSize: Integer;
    FOrigColSizes: TIntList;
    FSuppressColSizes: TIntList;
    FSizeFixed: Boolean;
    FSizingFixedCol: Integer;
    FSizingFixed: Boolean;
    FSizingFixedRow: Integer;
    FSizeFixedR: Boolean;
    FSizingFixedR: Boolean;
    FSizeFixedX: Integer;
    FSizeFixedY: Integer;
    FDisableChange: Boolean;
    FNilObjects: Boolean;
    FQuoteEmptyCells: Boolean;
    FAutoThemeAdapt: Boolean;
    FAlwaysQuotes: Boolean;
    FSortSettings: TSortSettings;
    FSelectionRectangleColor: TColor;
    FDragDropSettings: TDragDropSettings;
    FControlLook: TControlLook;
    FOnGetCellBorderProp: TGridBorderPropEvent;
    FFooterPanel: TFooterPanel;
    FSearchPanel: TSearchPanel;
    FSearchFooter: TSearchFooter;
    FFloatingFooter: TFloatingFooter;
    FIntegralHeight: Boolean;
    FIsWinXP: Boolean;
    FIsWin7: Boolean;
    FIsWinVista: Boolean;
    FIsComCtl6: Boolean;
    FClearTextOnly: Boolean;
    FOnEditingDone: TNotifyEvent;
    FOnEditChange: TEditChangeEvent;
    FOnEditCellDone: TEditCellDoneEvent;
    FOnUpdateColumnSize: TUpdateColumnSizeEvent;
    FHTMLHint: Boolean;
    FHTMLKeepLinebreak: Boolean;
    FAlwaysValidate: Boolean;
    FEnableBlink: Boolean;
    FOnGridResize: TNotifyEvent;
    FSizeGrowOnly: Boolean;
    FActiveCellColor: TColor;
    FActiveCellColorTo: TColor;
    FSelectionResizer: Boolean;
    FMaxColWidth: Integer;
    FMinRowHeight: Integer;
    FMinColWidth: Integer;
    FMaxRowHeight: Integer;
    FOnCustomFilter: TCustomFilterEvent;
    FOnCustomCellDraw: TCustomCellDrawEvent;
    FOnCustomCellBkgDraw: TCustomCellDrawEvent;
    FOnCustomCellSize: TCustomCellSizeEvent;
    FSelectionResizeEvent: TSelectionResizeEvent;
    FSelectionResizedEvent: TSelectionResizeEvent;
    {$IFDEF TMSUNICODE}
    FGetEditWideText: TGetEditWideTextEvent;
    FSetEditWideText: TSetEditWideTextEvent;
    FOnWideEllipsClick: TWideEllipsClickEvent;
    {$ENDIF}
    FOnGetWordWrap: TWordWrapEvent;
    FOnGroupCalc: TGroupCalcEvent;
    FOnColumnCalc: TGroupCalcEvent;
    FTMSGradFrom: TColor;
    FTMSGradTo: TColor;
    FTMSGradMirrorFrom: TColor;
    FTMSGradMirrorTo: TColor;
    FTMSGradHoverFrom: TColor;
    FTMSGradHoverTo: TColor;
    FTMSGradHoverMirrorFrom: TColor;
    FTMSGradHoverMirrorTo: TColor;
    FTMSGradHoverBorder: TColor;
    FTMSGradDownFrom: TColor;
    FTMSGradDownTo: TColor;
    FTMSGradDownMirrorFrom: TColor;
    FTMSGradDownMirrorTo: TColor;
    FTMSGradDownBorder: TColor;
    FUseHTMLHints: Boolean;
    FShowNullDates: Boolean;
    FICursor: THandle;
    FFixedRowHeight: Integer;
    FSelHidden: Boolean;
    FColumnOrder: TIntList;
    FAutoNumberDirection: TSortDirection;
    FAutoNumberOffset: Integer;
    FAutoNumberStart: Integer;
    FOldLeftCol: Integer;
    FOldKeepLeftCol: Integer;
    FOldTopRow: Integer;
    FSelectionChanged: TSelectionChanged;
    FScrollBars: TScrollStyle;
    FOnScrollCell: TScrollCellEvent;
    {$IFDEF TMSUNICODE}
    FUniLocale: LCID;
    FUniCmpFlgs: DWord;
    {$ENDIF}
    {$IFDEF FREEWARE}
    FFreewareCode: Integer;
    {$ENDIF}
    FGridControlWndProc: TWndMethod;
    FNumCellControls: Integer;
    FControlList: TControlList;
    FDisableSize: Boolean;
    FDefaultEditor: TEditorType;
    FDefaultAlignment: TAlignment;
    FDisabledFontColor: TColor;
    FHotFixedCell: TPoint;
    FOnPainted: TNotifyEvent;
    FCellSelectorMode: Boolean;
    FAECol,FAERow: Integer;
    FShowEditProcess: Boolean;
    FEditStart: Boolean;
    FBalloonSettings: TBalloonSettings;
    FHToolTip: THandle;
    FScrollBarAlways: TScrollBarAlways;
    FToolTipBuffer: array[0..4096] of char;
    FOnCellBalloon: TGridBalloonEvent;
    FShowModified: TShowModified;
    FCellGraphic: TCellGraphic;
    FOnPaintFooter: TFooterPaintEvent;
    FOnCalcFooter: TCalcFooterEvent;
    FDragScrollOptions: TDragScrollOptions;
    FTimerTicks: Integer;
    FDragTmr: TTimer;
    FScrollTimer: TTimer;
    FScrollDelta: integer;
    FScrollSteps: integer;
    FScrollStart: boolean;
    FTouchScrollPt: TPoint;
    FScrollEnd: boolean;
    FTimeStart: dword;
    FDragScrollDirection: TDragScrollDirection;
    FOnDragScroll: TDragScrollEvent;
    FFindCol, FFindRow: integer;
    FNoImageAndText: boolean;
    FOnSaveCell: TCellSaveLoadEvent;
    FOnLoadCell: TCellSaveLoadEvent;
    FMaxRowCount: Integer;
    FMaxColCount: Integer;
    FUseEnabledRows: boolean;
    FUseDisabledFont: boolean;
    FLastTabCol,FLastTabRow: integer;
    FProgressAppearance: TGridProgressAppearance;
    FOnCustomStrToDate: TCustomStrToDateEvent;
    FOnCreatedFloatingFooter: TNotifyEvent;
    FOnCreatedSearchFooter: TNotifyEvent;
    FOnDropDownHeaderButtonClick: TDropDownButtonClickEvent;
    FOnDropDownFooterButtonClick: TDropDownButtonClickEvent;
    {$IFDEF TMSGDIPLUS}
    FOnOfficeHint: TOfficeHintEvent;
    FOfficeHint: TAdvHintInfo;
    {$ENDIF}
    FScrollLock: Boolean;
    FPaintCount: integer;
    FEditText: string;
    FEditWideText: widestring;
    FNoEditChange: Boolean;
    FNoAutoAdvance: Boolean;
    FGridModified: Boolean;
    FIgnoreColumns: TIntList;
    FXMLEncoding: string;
    FFilterRow: integer;
    FFilterDropDownAuto: Boolean;
    FFilterDropDownMultiCol: Boolean;
    FFilterDropDownCheck: Boolean;
    FFilterDropDownCheckUnCheckAll: string;
    FFilterDropDownColumns: TFilterDropDownColumns;
    FFilterIncremental: Boolean;
    FFilterDropDownClear: string;
    FOriginalDateTime: TDateTime;
    FScrollBar: TScrollBar;
    FPaintScrollBar: TScrollBar;
    FScrollCol,FScrollRow: integer;
    FInvalidEntryTitle: string;
    FInvalidEntryText: string;
    FInvalidEntryIcon: TInvalidEntryIcon;
    FBlockCellChange: boolean;
    FLastDesignChoice: Integer;
    FShowDesignHelper: Boolean;
    FIsPrintPreview: boolean;
    FValidChars: string;
    FValidCharSet: TCharSet;
    FUseInternalHintClass: Boolean;
    FOnStartBlockFocus: TNotifyEvent;
    FOnEndBlockFocus: TNotifyEvent;
    FSyncGrid: TSyncGrid;
    FFitCellsInGrid: Boolean;
    FShowSelection: Boolean;
    FAutoHideSelection: Boolean;
    FSpreadSheet: boolean;
    FHoverCell: TPoint;
    FHoverButton: TPoint;
    FHoverlink: Integer;
    FOleDragCol: Integer;
    FOleDragIndex: Integer;
    FOleDragList: TCustomListBox;
    FTones: TColorTones;
    FShowColNrs: boolean;
    FFocusHelper: TFocusHelper;
    FISelect: ITAdvStringGridSelect;
    FUseVCLStyles: boolean;
    FOnFilterClose: TFilterCloseEvent;
    FOnFilterShow: TFilterShowEvent;
    FFltrList: TImageList;
    FFltrPopup: TPopupMenu;
    FFltrPopPressCol: integer;
    FAutoColor: TAutoColor;
    FConditions: array of string;
    FColumns: array of integer;
    FCase: array of boolean;
    FInWMSize: boolean;
    FOnIntelliZoom: TNotifyEvent;
    FIsNarrowDown: boolean;
    FHiddenRowLookup: TIntList;
    FFormatType: TFormatType;
    FHoverButtons: THoverButtons;
    FOnHoverButtonClick: THoverButtonClickEvent;
    FOwnsObjects: boolean;
    FForceComboSel: boolean;
    FHoverButtonRow: integer;
    FToolBarPopup: TAdvGridPopup;
    FToolBarPopupCell: TGridCoord;
    FPopupToolBarMode: TPopupToolBarMode;
    FInWorkbook: boolean;
    FSaveFormula: Boolean;
    FICellValidate: ITMSCellValidate;
    FDPIScale: single;
    FLastScrollCode: integer;
    {$IFDEF DELPHI_UNICODE}
    FEncoding: TEncoding;
    {$ENDIF}
    procedure SetDragScrollOptions(Value: TDragScrollOptions);
    procedure NCPaintProc;
    procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
    procedure WMNotify(var Message: TWMNOTIFY); message WM_NOTIFY;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
    procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
    procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
    procedure WMLButtonUp(var Msg:TWMLButtonUp); message WM_LBUTTONUP;
    procedure WMRButtonUp(var Msg:TWMLButtonUp); message WM_RBUTTONUP;
    procedure WMLButtonDown(var Msg:TWMLButtonDown); message WM_LBUTTONDOWN;
    procedure WMRButtonDown(var Msg:TWMLButtonDown); message WM_RBUTTONDOWN;
    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
    procedure WMKeyDown(var Msg: TWMKeydown); message WM_KEYDOWN;
    procedure WMKeyUp(var Msg: TWMKeydown); message WM_KEYUP;
    procedure WMSize(var Msg: TWMSize); message WM_SIZE;
    procedure WMPaint(var Msg: TWMPAINT); message WM_PAINT;
    procedure WMEraseBkGnd(var Message:TMessage); message WM_ERASEBKGND;
    procedure WMTimer(var Msg:TWMTimer); message WM_TIMER;
    procedure WMVScroll(var WMScroll:TWMScroll ); message WM_VSCROLL;
    procedure WMHScroll(var WMScroll:TWMScroll ); message WM_HSCROLL;
    procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CMCursorChanged(var Message: TMessage); message CM_CURSORCHANGED;
    procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
    {$IFDEF DELPHIXE2_LVL}
    procedure CMStyleChanged(var Message: TMessage); message CM_STYLECHANGED;
    {$ENDIF}
    procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
    procedure CMHintShow(var Msg: TMessage); message CM_HINTSHOW;
    procedure CMDialogChar(var Msg: TCMDialogChar); message CM_DIALOGCHAR;
    procedure CMMouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
    procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
    function MouseOverDesignChoice(X, Y: Integer): Integer;
    procedure HideEditControl(ACol,ARow: Integer);
    procedure ShowEditControl(ACol,ARow: Integer);
    procedure ShowFocusHelper(R: TRect);
    procedure HideFocusHelper;
    procedure MoveFocusHelper;
    function IsPassword(ACol,ARow: Integer): Boolean;
    procedure HandleRadioClick(ACol,ARow,Xpos,Ypos: Integer);
    function HasStaticEdit(ACol,ARow: Integer): Boolean;
    function CanVisitCell(ACol,AROw: integer): boolean;

    function NextVisitableCell(ACol,ARow: Integer): TPoint;
    function NextCol(ACol: Integer): Integer;
    function TabEdit(Dir: Boolean): boolean;
    function ToggleRadio(ACol,ARow: Integer; FromEdit: Boolean): Boolean;
    function GetInplaceEditor: TAdvInplaceEdit;
    procedure SetAutoSizeP(AAutoSize: Boolean);
    {$IFDEF TMSGDIPLUS}
    procedure SetOfficeHint(const Value: TAdvHintInfo);
    {$ENDIF}
    procedure SetFlat(const AValue: Boolean);
    procedure SetShowSelection(AValue: Boolean);
    procedure SetMaxEditLength(const AValue: Integer);
    procedure SetGroupColumn(AGroupColumn: Integer);
    procedure QuickSortRows(Col,Left,Right: Integer);
    procedure QuickSortRowsIndexed(Col,Left,Right: Integer);
    procedure QuickSortRowsRef(Col,Left,Right: Integer);
    procedure SetVAlignment(AVAlignment:TVAlignment);
    function BuildPages(ACanvas:TCanvas;PrintMethod:TPrintMethod;MaxPages: Integer;SelRows:Boolean): Integer;
    function Compare(Col,ARow1,ARow2: Integer; sd: TSortDirection): Integer;
    function CompareLine(Col,ARow1,ARow2: Integer): Integer;
    function CompareLineIndexed(Colidx,ARow1,ARow2: Integer): Integer;
    function MatchCell(Col,Row: Integer; IsWide: Boolean): Boolean;
    procedure ShowHintProc(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo);
    procedure DrawSortIndicator(Canvas:TCanvas;Col,x,y: Integer);
    //procedure GridResize(Sender: TObject);
    function FreeCellGraphic(ACol,ARow: Integer): Boolean;
    function RemoveCellGraphic(ACol,ARow: Integer;CellType:TCellType): Boolean;
    function CreateCellGraphic(ACol,ARow: Integer): TCellGraphic;
    function GetCellImages(ACol,ARow: Integer): TIntList;
    function GetCellImageIdx(ACol,ARow: Integer): Integer;
    procedure SetInts(ACol,ARow: Integer;const Value: Integer);
    function GetInts(ACol,ARow: Integer): Integer;
    procedure SetAllInts(ACol,ARow: Integer;const Value: Integer);
    function GetAllInts(ACol,ARow: Integer): Integer;
    procedure SetFloats(ACol,ARow: Integer;const Value:double);
    function GetFloats(ACol,ARow: Integer):Double;
    procedure SetAllFloats(ACol,ARow: Integer;const Value:double);
    function GetAllFloats(ACol,ARow: Integer):Double;
    procedure SetDates(ACol,ARow: Integer;const Value:TDateTime);
    function GetDates(ACol,ARow: Integer):TDateTime;
    procedure SetTimes(ACol,ARow: Integer;const Value:TDateTime);
    function GetTimes(ACol,ARow: Integer):TDateTime;
    function GetRowSelect(ARow: Integer): Boolean;
    procedure SetRowSelect(ARow: Integer; Value: Boolean);
    function GetRowModified(ARow: Integer): Boolean;
    procedure SetRowModified(ARow: Integer; Value: Boolean);
    function GetRowEnabled(ARow: Integer): Boolean;
    procedure SetRowEnabled(ARow: Integer; Value: Boolean);
    function GetRowSelectCount: Integer;
    function GetColSelect(ACol: Integer): Boolean;
    procedure SetColSelect(ACol: Integer;Value: Boolean);
    function GetColSelectCount: Integer;
    procedure SelectToColSelect(IsShift: Boolean);
    function ButtonRect(ACol,ARow: Integer):TRect;
    function ExpandRect(ACol,ARow: Integer):TRect;
    procedure SetFixedFont(Value: TFont);
    procedure FixedFontChanged(Sender: TObject);
    procedure MultiImageChanged(Sender: TObject; ACol,ARow: Integer);
    procedure MergedColumnsChanged(Sender: TObject; ACol,ARow: Integer);
    procedure UndoColumnMerge;
    procedure ApplyColumnMerge;
    procedure RichSelChange(Sender: TObject);
    procedure SetColumnHeaders(Value: TStringList);
    procedure ColHeaderChanged(Sender: TObject);
    procedure SetRowHeaders(Value: TStringList);
    procedure RowHeaderChanged(Sender: TObject);
    function GetPrintColWidth(ACol: Integer): Integer;
    function GetPrintColOffset(ACol: Integer): Integer;
    procedure SetLookupItems(Value: TStringList);
    function PasteFunc(ACol,ARow: Integer;var Cols,Rows: integer): Integer;
    function CopyFuncStr(gd:TGridRect;DoDisjunct: Boolean): string;
    procedure CopyFunc(gd:TGridRect;DoDisjunct: Boolean);
    procedure CopyRTFFunc(ACol,ARow: Integer);
    procedure CopyBinFunc(gd:TGridRect);
    procedure SetPreviewPage(Value: Integer);
    function GetRowIndicator: TBitmap;
    procedure SetRowIndicator(Value: TBitmap);
    procedure SetBackground(Value: TBackground);
    procedure RTFPaint(ACol,ARow: Integer;Canvas:TCanvas;ARect:TRect);
    procedure DrawSizingLine(X: Integer);
    procedure DrawSizingLineR(Y: Integer);
    function YOffsetSize: integer;
    function XOffsetSize: integer;
    procedure InitVCLStyle(init: boolean);
    procedure FlatInit;
    procedure FlatDone;
    procedure FlatUpdate;
    procedure FlatSetScrollProp(index,newValue: Integer;fRedraw:bool);
    procedure FlatSetScrollInfo(code: Integer;var scrollinfo:tscrollinfo;fRedraw:bool);
    { procedure FlatSetScrollPos(code,pos: Integer); }
    procedure FlatShowScrollBar(code: Integer;show:bool);
    procedure UpdateVScrollBar;
    procedure UpdateHScrollBar;
    procedure UpdateScrollBars(Refresh: Boolean);
    procedure UpdateType;
    procedure UpdateColor;
    procedure UpdateWidth;
    procedure SetScrollBarsEx(const Value: TScrollStyle);
    function GetScrollBarsEx: TScrollStyle;
    procedure SetScrollType(const Value: TScrollType);
    procedure SetScrollColor(const Value: TColor);
    procedure SetScrollWidth(const Value: Integer);
    procedure SetScrollProportional(Value: Boolean);
    procedure SetActiveCellShow(const Value: Boolean);
    procedure SetActiveCellFont(const Value: TFont);
    procedure SetAutoThemeAdapt(const Value: Boolean);
    procedure SetXYOffset(const Value: TPoint);
    function GetLockFlag : Boolean;
    procedure SetLockFlag(AValue : Boolean);
    function InSizeZone(x,y: Integer): Boolean;
    function RemapCol(ACol: Integer): Integer;
    function RemapColInv(ACol: Integer): Integer;
    function RemapRow(ARow: Integer): Integer;
    function RemapRowInv(ARow: Integer): Integer;
    procedure SetVisibleCol(i: Integer; AValue: Boolean);
    function GetVisibleCol(i: Integer): Boolean;
    function MaxLinesInGrid: Integer;
    function MaxLinesInRow(ARow: Integer): Integer;
    function MaxCharsInCol(ACol: Integer): Integer;
    procedure SizeToLines(const ARow,Lines,Padding: Integer);
    procedure SizeToWidth(const ACol: Integer;inconly: Boolean);
    procedure SizeToHeight(const ARow: Integer;inconly: Boolean; Padding: integer = 0);
    function GetCellAlignment(ACol,ARow: Integer): TCellAlignment;
    procedure DrawIntelliFocusPoint;
    procedure EraseIntelliFocusPoint;
    procedure SetImages(Value:TCustomImageList);
    procedure SetURLShow(Value: Boolean);
    procedure SetURLShowInText(Value: Boolean);
    procedure SetURLColor(Value: TColor);
    procedure SetURLFull(Value: Boolean);
    procedure SetLook(Value: TGridLook);
    function GetLookAsString(Value: TGridLook): string;
    function GetLookAsFriendlyString(Value: TGridLook): string;
    procedure CalcTextPos(var ARect:TRect;var sz: TSize; AAngle: Integer;ATxt:String;hal: TAlignment;val:TVAlignment);
    procedure SetFixedFooters(Value: Integer);
    procedure SetFixedRightCols(Value: Integer);
    procedure SetFixedColWidth(Value: Integer);
    procedure SetRowCountEx(Value: Integer);
    function GetRowCountEx: Integer;
    procedure SetColCountEx(Value: Integer);
    function GetColCountEx: Integer;
    procedure SetFixedRowsEx(Value: Integer);
    function GetFixedRowsEx: Integer;
    procedure SetFixedColsEx(Value: Integer);
    function GetFixedColsEx: Integer;
    procedure SetHovering(Value: Boolean);
    function GetFixedColWidth: Integer;
    procedure SetFixedRowHeight(Value: Integer);
    function GetFixedRowHeight: Integer;
    procedure SetWordWrapEx(Value: Boolean);
    function GetWordWrapEx: Boolean;
    procedure SetSelectionColor(AColor: TColor);
    procedure SetSelectionColorTo(AColor: TColor);
    procedure SetSelectionMirrorColor(AColor: TColor);
    procedure SetSelectionMirrorColorTo(AColor: TColor);
    procedure SetSelectionTextColor(AColor: TColor);
    procedure SetSelectionRectangle(AValue: Boolean);
    procedure SetFilterActive(const Value: Boolean);
    procedure SetFilterRow(const Value: Integer);
    function GetCursorEx: TCursor;
    procedure SetCursorEx(const Value: TCursor);
    function GetCellsEx(i,j: Integer):string;
    procedure SetCellsEx(i,j: Integer;Value:string);
    function GetGridCellsEx(i,j: Integer):string;
    procedure SetGridCellsEx(i,j: Integer;Value:string);

    function GetWideCellsEx(i,j: Integer):widestring;
    procedure SetWideCellsEx(i,j: Integer;Value:widestring);
    function GetObjectsEx(i,j: Integer):TObject;
    procedure SetObjectsEx(i,j: Integer;aObject:TObject);
    function GetAllColWidths(i: Integer): Integer;
    procedure SetAllColWidths(i: Integer; const Value: Integer);
    function GetColors(i,j: Integer): TColor;
    procedure SetColors(i,j: Integer;AColor: TColor);
    function GetColorsTo(i,j: Integer): TColor;
    procedure SetColorsTo(i,j: Integer;AColor: TColor);

    function GetGradientDir(i,j: Integer): TCellGradientDirection;
    procedure SetGradientDir(i,j: Integer;ADirection: TCellGradientDirection);

    procedure SetRowColor(i: Integer; AColor: TColor);
    procedure SetRowColorTo(i: Integer; AColor: TColor);
    procedure SetRowFontColor(i: Integer; AColor: TColor);
    function GetReadOnly(i,j: Integer): Boolean;
    procedure SetReadOnly(i,j: Integer; AValue: Boolean);
    function GetWordWraps(i,j: Integer): Boolean;
    procedure SetWordWraps(i,j: Integer; AValue: Boolean);
    function GetCellControls(i,j: Integer): TControl;
    procedure SetCellControls(i,j: Integer;AControl: TControl);
    function GetStrippedCell(i,j: Integer): string;
    function HiddenRow(j: Integer): TStrings;
    function PasteText(ACol,ARow: Integer;p:PChar; var Cols,Rows: integer): Integer;
    procedure InputFromCSVStream(AStream: TStream; insertmode: Boolean;MaxRows: integer);
    procedure InputFromCSV(FileName: string;insertmode: Boolean;MaxRows: integer);
    procedure OutputToCSV(FileName: string;appendmode: Boolean; unicode: Boolean);
    procedure OutputToHTML(FileName: string;appendmode: Boolean; Show: boolean = false; Unicode: boolean = true);
    procedure LoadXLS(filename,sheetname: string);
    procedure SaveXLS(filename,sheetname: string; CreateNewSheet: Boolean);
    function GetDateTimePicker:TGridDatePicker;
    procedure SetArrowColor(Value: TColor);
    function GetArrowColor: TColor;
    function PasteSize(p:PChar):TPoint;
    procedure MarkCells(s,tag:string;DoCase: Boolean; FromCol,FromRow,ToCol,ToRow: Integer; FullCell: boolean = false);
    procedure UnMarkCells(tag:string;FromCol,FromRow,ToCol,ToRow: Integer);
    function GetUnSortedCell(i, j: Integer): string;
    procedure SetUnSortedCell(i, j: Integer; const Value: string);
    function GetDefRowHeightEx: Integer;
    procedure SetDefRowHeightEx(const Value: Integer);
    procedure SetIntegralHeight(const Value: Boolean);
    function GetSelectedCells(i, j: Integer): Boolean;
    procedure SetSelectedCells(i, j: Integer; const Value: Boolean);
    function GetSelectedCellsCount: Integer;
    function GetSelectedCell(i: Integer): TGridCoord;
    function GetSelectedRowCount: integer;
    function GetSelectedColCount: integer;
    function GetSelectedRow(i: integer): integer;
    function GetFontColors(i, j: Integer): TColor;
    procedure SetFontColors(i, j: Integer; const Value: TColor);
    function GetAlignments(i, j: Integer): TAlignment;
    procedure SetAlignments(i, j: Integer; const Value: TAlignment);
    function GetLinesInCell(i, j: Integer): integer;
    procedure SetActiveCellColor(const Value: TColor);
    procedure SetActiveCellColorTo(const Value: TColor);
    procedure SetSelectionResizer(const Value: Boolean);
    function GetFontStyles(i, j: Integer): TFontStyles;
    procedure SetFontStyles(i, j: Integer; const Value: TFontStyles);
    function GetFontNames(i, j: Integer): string;
    function GetFontSizes(i, j: Integer): Integer;
    procedure SetFontNames(i, j: Integer; const Value: string);
    procedure SetFontSizes(i, j: Integer; const Value: Integer);
    procedure SetTMSGradFrom(const Value: TColor);
    procedure SetTMSGradTo(const Value: TColor);
    procedure SetTMSGradMirrorFrom(const Value: TColor);
    procedure SetTMSGradMirrorTo(const Value: TColor);
    procedure SetUseHTMLHints(const Value: Boolean);
    procedure ControlExit(Sender: TObject);
    procedure ControlEnter(S, CT,CID,CV:string; CR: TRect; X,RX,Y: Integer);
    function GetCtrlVal(ACol, ARow: Integer; ID: string): string;
    procedure SetCtrlVal(ACol, ARow: Integer; ID: string;
      const Value: string);
    function GetAllColCount: Integer;
    function GetLastCol: Integer;
    function GetAllRowCount: Integer;
    function GetLastRow: Integer;
    function GetWideCells(i, j: Integer): widestring;
    procedure SetWideCells(i, j: Integer; const Value: widestring);
    procedure StartFixedEdit(x,y: Integer; FilterEdit: boolean = false);
    function NumFixedRightVis: Integer;
    function FixedColsVis: Integer;
    function HoverFixedCell(Col,Row: Integer): boolean;
    function GetFooterCanvas: TCanvas;
    function FindInternal(StartCell:TPoint; s:string; sw: widestring; IsWide: boolean; FindParams: TFindParams): TPoint;
    function InNodeRect(ARow,x: integer): Boolean;
    //procedure ComboChange(Sender: TObject);
    procedure SetVersion(const Value: string);
    procedure SaveToDOCInt(FileName, bookmark:string; CreateNewDocument, Append: boolean);
    procedure SaveToASCIIInt(FileName: string; AppendFile: boolean; Unicode: Boolean);
    procedure QSortGroupInt(Indexed: boolean);

    procedure CreateToolTip;
    procedure AddToolTip(IconType: Integer; Text, Title: string);
    procedure DestroyToolTip;

    procedure SetShowModified(const Value: TShowModified);
    procedure SetShowDesignHelper(const Value: Boolean);
    procedure SetBalloonSettings(const Value: TBalloonSettings);

    procedure FixedEditChange(Sender: TObject);
    procedure FixedComboSelect(Sender: TObject);
    procedure SearchEditChange(Sender: TObject);

    procedure SearchBackwardInt(Loop: boolean);
    procedure SearchForwardInt(Loop: boolean);

    procedure SearchBackward(Sender: TObject);
    procedure SearchForward(Sender: TObject);
    procedure SearchExit(Sender: TObject);
    procedure SearchHighLight(Sender: TObject);
    procedure SearchMatchCase(Sender: TObject);
    procedure SetScrollBarAlways(const Value: TScrollBarAlways);
    function GetSelectionEx: TGridRect;
    procedure SetSelectionEx(const Value: TGridRect);
    procedure SetProgressAppearance(const Value: TGridProgressAppearance);
    function GetAllGraphicsObject(i,j: integer): TObject;
    function GetOriginalCells(i, j: Integer): string;
    procedure SetOriginalCells(i, j: Integer; const Value: string);
    procedure SetFilterDropDownAuto(const Value: Boolean);
    procedure FilterDropDownChanged(Sender: TObject);
    procedure SetHighlightColor(const Value: TColor);
    procedure SetHighlightTextColor(const Value: TColor);
    function GetCellFont(i, j: Integer): TFont;
    procedure SetCellFont(i, j: Integer; const Value: TFont);
    procedure SetSortSettings(const Value: TSortSettings);
    procedure SetSyncGrid(const Value: TSyncGrid);
    function GetColEx: Integer;
    procedure SetColEx(const Value: Integer);
    procedure SetSpreadSheet(const Value: boolean);
    procedure SetDefaultAlignment(const Value: TAlignment);
    function GetCurrentEditor: TEditorType;
    procedure SetSelectionColorMixer(const Value: boolean);
    procedure SetBorderColor(const Value: TColor);
    procedure SetFocusHelper(const Value: TFocusHelper);
    function IsCellGraphic(ACol,ARow: integer; CTSet: TCellTypeSet): boolean;
    function GetComboIndex(ACol, ARow: Integer): Integer;
    procedure SetComboIndex(ACol, ARow: Integer; const Value: Integer);
    procedure SetSelectionColorMixerFactor(const Value: integer);
    procedure SetFilterEdit(const Value: TFilterEdit);
    procedure SetAutoColor(const Value: TAutoColor);
    procedure SetSizeWithForm(const Value: Boolean);
    function GetFooterPanel: TFooterPanel;
    procedure SetFormatType(const Value: TFormatType);
    procedure SetHoverButtons(const Value: THoverButtons);
    procedure SetHTMLKeepLineBreak(const Value: Boolean);
    procedure SetCellChecker(const Value: TAdvStringGridCheck);
    function GetReadCell(i, j: Integer): string;
    procedure SetRealCell(i, j: Integer; const Value: string);
  protected
    FClipTopLeft: TPoint;
    FClipLastOp: TClipOperation;
    FScrollHintWnd: THTMLHintWindow;
    FScrollHintShow: Boolean;
    FVirtualCells: Boolean;
    FVirtualEdit: Boolean;
    FCellCache: string;
    FNoRTLOrientation: Boolean;
    FIsGrouping: Boolean;
    FIsDBVersion: Boolean;
    FSyncedMove: Boolean;
    function GetVersion: string;
    function HasColumnsProp: boolean; virtual;
    procedure SubclassProc(var Msg: TMessage);
    procedure DoCalcFooter(ACol: Integer); virtual;
    procedure DoClickSort(ACol: integer); virtual;
    procedure DoClickCell(ARow, ACol: integer); virtual;
    procedure DoF2Edit; virtual;
    function CanTabToNextRow: boolean; virtual;
    procedure UpdateEditingCell(ACol,ARow: Integer; Value: string); virtual;
    procedure UpdateOnSelection(var GR: TGridRect); virtual;
    procedure PasteInCell(ACol,ARow: Integer; Value: string); virtual;
    function CellNameList: TStringList; virtual;
    function GetCurrentCell: string; virtual;
    procedure SetCurrentCell(const AValue: string); virtual;
    function GetCurrentDisplCell: string; virtual;
    function GetEditCell(i,j: integer): string; virtual;
    procedure SetEditCell(const AValue: string); virtual;
    procedure CellTextChange(ACol, ARow: integer); override;
    procedure RestoreCache; virtual;
    function IsDSEdit: boolean; virtual;
    procedure InitHiddenRowLookup;
    procedure DestroyHiddenRowLookup;
    procedure ThemeAdapt;
    procedure ControlComboSelect(Sender: TObject);
    procedure HandleButtonClick(Sender: TObject);
    procedure HoverButtonClick(Sender: TObject); virtual;
    procedure ButtonFormMouseLeave(Sender: TObject); virtual;
    function ToggleCheck(ACol,ARow: Integer; FromEdit: Boolean): Boolean; virtual;
    function ToggleRadioButton(ACol,ARow: Integer; FromEdit: Boolean): Boolean; virtual;
    procedure AdvanceEdit(ACol,ARow: Integer;Advance,Show,Frwrd,Recurs,FromEdit: Boolean);
    procedure AdvanceHTMLEdit(ACol,ARow: Integer; CtrlID: string);
    function GetGraphicDetails(ACol,ARow: Integer; var W,H: Integer; var DisplText: Boolean;
      var HA: TCellHAlign;var VA: TCellVAlign): TCellGraphic;
    function GetFormattedCell(ACol,ARow: Integer): string; virtual;
    function NodeIndent(ARow: Integer): Integer; override;
    function HasNodes: Boolean; override;
    function ShouldDrawSortIndicator(ACol,ARow: Integer): Boolean;
    procedure GetDisplText(c,r: Integer; var Value: string); override;
    function GetCellFloatFormat(ACol,ARow: Integer): string; virtual;
    function GetCellType(ACol,ARow: Integer): TCellType; virtual;
    function GetCellEmpty(ACol,ARow: Integer): boolean; virtual;
    function GetCellGraphic(ACol,ARow: Integer): TCellGraphic; virtual;
    function GetCellGraphicSize(ACol,ARow: Integer): TPoint; virtual;
    function GetCellGraphicSizeEx(ACol,ARow,Padding: Integer): TPoint; overload; virtual;
    function GetCellGraphicSizeEx(ACanvas: TCanvas; ACol,ARow,Padding: Integer; ResFactor: double): TPoint; overload; virtual;
    function GetPrintGraphicSize(ACol,ARow,CW,RH: Integer;ResFactor: Double): TPoint; virtual;
    procedure DrawCell(ACol,ARow:longint;ARect:TRect;AState:TGridDrawState); override;
    procedure DrawGridCell(Canvas:TCanvas; ACol,ARow:longint;ARect:TRect;AState:TGridDrawState); override;
    procedure DrawCheck(R:TRect;State,Enabled,Grayed: Boolean; ControlStyle: TControlStyle; bTriState: Boolean = False; cbState: TCheckBoxState = cbUnchecked);
    procedure DrawWallPaperFixed(crect: TRect);
    procedure DrawWallPaperTile(crect: TRect);
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    function GetEditMask(ACol, ARow: Longint): string; override;
    function CreateEditor: TInplaceEdit; override;
    function CanEditShow: Boolean; override;
    procedure DoClipboardPasteDone(CellRect: TGridRect); virtual;
    procedure DoGetPrintPageNum(PageNum,PageNumCol: integer; var Value: string); virtual;
    procedure DoGetEditorProp(ACol,ARow: integer; EditLink: TEditLink); virtual;
    procedure DoCheckBoxClick(ACol,ARow: integer; AState: boolean); virtual;
    procedure DoFixedCellEdit(ACol,ARow: integer; AEditor: TGridFixedCellEditor; Values: TStrings); virtual;
    function CanShowSelection: Boolean; virtual;
    function ShouldHandleTab: Boolean;
    procedure DoMemoChanged(Sender: TObject);
    procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
    function GetEditText(ACol, ARow: Longint): string; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure ColumnMoved(FromIndex, ToIndex: longint); override;
    procedure RowMoved(FromIndex, ToIndex: longint); override;
    procedure KeyPress(var Key:char); override;
    procedure CreateWnd; override;
    procedure DestroyWnd; override;
    procedure Loaded; override;
    function  SelectCell(ACol, ARow: longint): Boolean; override;
    procedure WndProc(var Message:tMessage); override;
    procedure SizeChanged(OldColCount, OldRowCount: longint); override;
    procedure Notification(AComponent: TComponent; AOperation: TOperation); override;
    procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); override;
    procedure DragTimerProc(Sender:Tobject);
    procedure ScrollTimerProc(Sender:Tobject);
    {$IFDEF TMSUNICODE}
    procedure WideEllipsClick(Sender: TObject);
    {$ENDIF}
    procedure CalcSizingState(X, Y: Integer; var State: TGridState;
      var Index: Integer; var SizingPos, SizingOfs: Integer;
      var FixedInfo: TGridDrawInfo); override;
    procedure SelectionChanged(ALeft, ATop, ARight, ABottom: integer); virtual;
    procedure EditProgress(Value: string; pt: TPoint; SelPos: Integer); virtual;
    procedure DoInsertRow(ARow: Integer); virtual;
    procedure DoDeleteRow(ARow: Integer); virtual;
    procedure DoFilterDone; virtual;
    procedure DoFilterShow(ACol: integer; var Allow: boolean); virtual;
    procedure DoFilterClose(ACol: integer); virtual;
    function CreateFooter: TFooterPanel; virtual;
    procedure Click; override;
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure Paint; override;
    procedure PaintBackground;
    function SelectToRowSelect(IsShift: Boolean): boolean;
    function IsScrolledToLastRow: boolean;
    procedure ScrollToLastRow;
    function GetEditLimit: Integer; override;
    procedure ColWidthsChanged; override;
    procedure RowHeightsChanged; override;
    procedure InvalidateGridRect(r:TGridRect);
    procedure TopLeftChanged; override;
    procedure FloatFooterUpdate; override;
    procedure UpdateColSize(ACol: Integer; var NewWidth: Integer); virtual;
    procedure UpdateAutoColSize(ACol: Integer; var NewWidth: Integer); virtual;
    procedure UpdateColHeaders; virtual;
    function EllipsClick(s:string):string; virtual;
    function MatchFilter(ARow: Integer): Boolean; virtual;
    procedure PasteStart; virtual;
    procedure PasteDone; virtual;
    procedure PasteNotify(orig:TPoint;gr:TGridRect; LastOp:TClipOperation); virtual;
    function CalcCell(ACol,ARow: Integer):string; virtual;
    procedure LoadCell(ACol,ARow: Integer; Value: string); virtual;
    procedure UpdateCell(ACol,ARow: Integer); virtual;
    procedure InitValidate(ACol,ARow: Integer); virtual;
    procedure InitScroll(PageScroll: boolean); virtual;
    procedure DoCanEditCell(ACol,ARow: Integer; var CanEdit: boolean); virtual;
    procedure DoCanSort(ACol: integer; var CanSort: boolean); virtual;
    procedure DoSearchFooterAction(AValue: string; ACol, ARow: integer; ASearchAction: TSearchAction); virtual;
    procedure DoSearchFooterSearchEnd(var ContinueFromStart: boolean); virtual;
    procedure DoButtonClick(ACol,ARow: Integer); virtual;
    procedure DoExpandClick(ACol,ARow: Integer;Expanded: boolean); virtual;
    procedure DoComboCloseUp(ARow, ACol: integer); virtual;
    procedure DoComboDropDown(ARow, ACol: integer); virtual;
    procedure DoSetCellCursor(ACol,ARow,X,Y: Integer); virtual;
    procedure CellsChanged(R:TRect); virtual;
    procedure CellsLoaded; virtual;
    procedure GetCellHint(ACol,ARow: Integer; var AHint: string;var AWideHint: widestring); virtual;
    procedure GetCellColor(ACol,ARow: Integer;AState: TGridDrawState; ABrush: TBrush; AFont: TFont); virtual;
    procedure GetCellPrintColor(ACol,ARow: Integer;AState: TGridDrawState; ABrush: TBrush; AFont: TFont); virtual;
    procedure GetCellBorder(ACol,ARow: Integer; APen:TPen;var Borders: TCellBorders); virtual;
    procedure GetCellPrintBorder(ACol,ARow: Integer; APen:TPen;var Borders: TCellBorders); virtual;
    procedure GetCellAlign(ACol,ARow: Integer;var HAlign: TAlignment;var VAlign: TVAlignment); virtual;
    procedure GetColFormat(ACol: Integer;var AStyle:TSortStyle;var aPrefix,aSuffix:string); virtual;
    procedure GetStaticCellEditor(ACol,ARow: Integer;var AEditor:TEditorType); virtual;
    procedure GetCellEditor(ACol,ARow: Integer;var AEditor:TEditorType); virtual;
    function GetEditorNone(ACol,ARow: Integer): boolean; virtual;
    procedure GetCellFixed(ACol,ARow: Integer;var IsFixed: Boolean); virtual;
    procedure GetCellReadOnly(ACol,ARow: Integer;var IsReadOnly: Boolean); virtual;
    procedure GetCellPassword(ACol,ARow: Integer;var IsPassword: Boolean); virtual;
    procedure GetCellWordWrap(ACol,ARow: Integer;var WordWrap: Boolean); virtual;
    procedure GetDefaultProps(ACol,ARow: Integer; AFont: TFont; ABrush: TBrush; var AColorTo, AMirrorColor, AMirrorColorTo: TColor;
      var HA: TAlignment; var VA: TVAlignment; var WW: boolean; var GD: TCellGradientDirection); override;
    function HasCombo(ACol,ARow: Integer; AEditor: TEditorType = edNone): Boolean; virtual;
    function HasEditBtn(ACol,ARow: Integer; AEditor: TEditorType = edNone): Boolean; virtual;
    function HasSpinEdit(ACol,ARow: Integer; AEditor: TEditorType = edNone): Boolean; virtual;
    function HasFilterEdit(ACol, ARow: integer): Boolean; virtual;
    procedure FilterEditUpdate(ACol: integer; Condition: string; FilterType: TFilterType); virtual;
    function GetCheckTrue(ACol,ARow: Integer): string; virtual;
    function GetCheckFalse(ACol,ARow: Integer): string; virtual;
    function GetFilter(ACol: Integer; Disp: boolean = false): Boolean; virtual;
    function GetUsedCells: TGridRect; virtual;
    function GetSaveStartCol: Integer;
    function GetSaveStartRow: Integer;
    function GetSaveEndCol: Integer;
    function GetSaveEndRow: Integer;
    function GetSaveRowCount: Integer;
    function GetSaveColCount: Integer;
    procedure CreateMetroScrollers;
    procedure DestroyMetroScrollers;
    procedure RemoveRowsInternal(RowIndex, RCount: Integer); virtual;
    procedure StretchColumn(ACol: Integer; NewWidth: integer = -1);
    procedure PrivatePrintRect(Gridrect:TGridRect; SelRows: Boolean);
    procedure PrivatePrintPreviewRect(Canvas:TCanvas; Displayrect:TRect; Gridrect:TGridRect; SelRows: Boolean);
    procedure DoneEditing(ACol,ARow: integer);
    procedure UpdateActiveCells(co,ro,cn,rn: Integer);
    function HasDataCell(ACol,ARow: Integer): Boolean;
    function IsDataCheckCol(ACol: Integer): Boolean;
    function GetColumnCheckTrue(ACol: Integer): string; virtual;
    function GetColumnCheckFalse(ACol: Integer): string; virtual;
    procedure QueryAddRow(var AllowAdd: Boolean); virtual;
    procedure QueryAddCol(var AllowAdd: Boolean); virtual;
    procedure QueryInsertRow(ARow: Integer; var AllowInsert: Boolean); virtual;
    procedure DirectWheelChange(delta: integer; var SuppressMsg: Boolean); virtual;
    function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    procedure DoHeaderButtonClick(Sender: TObject; ButtonIndex: integer);
    procedure DoFooterButtonClick(Sender: TObject; ButtonIndex: integer);
    procedure UpdateVScroller;
    procedure UpdateHScroller;
    procedure DoAppendRow; virtual;
    procedure AddSummary(ARow: Integer);
    procedure IRemoveRows(RowIndex, RCount: Integer; flg: Boolean);
    procedure CorrectSelection; virtual;
    property CellSelectorMode: Boolean read FCellSelectorMode write FCellSelectorMode;
    procedure CellSelect(c,r: Integer); virtual;
    procedure SetCellSelectMode(const Value: Boolean); virtual;
    procedure BalloonChange(Sender: TObject);
    procedure ModifiedChanged(Sender: TObject);
    procedure DatePickerCloseUp(Sender: TObject);
    procedure DatePickerDropDown(Sender: TObject);
    procedure DateTimePickerChange(Sender: TObject);
    procedure DatePickerChange(Sender: TObject);
    procedure SearchChanged(Sender: TObject);
    procedure BandsChanged(Sender: TObject);
    procedure UnitChanged(Sender: TObject; NewUnit:string);
    procedure UpdateSelectionRect(var GR: TGridRect); virtual;
    procedure OnMouseActionsChanged(Sender: TObject); virtual;
    procedure OnMouseActionsIsDesigning(Sender: TObject; var IsDesigning: boolean); virtual;
    procedure OnMouseActionsInvalidate(Sender: TObject); virtual;
    procedure OnMouseActionsDisableEdit(Sender: TObject); virtual;
    procedure EditKeyDown(var Key: Word; Shift: TShiftState); virtual;
    procedure Edit_WMKeyDown(var Msg: TWMKeydown); virtual;
    procedure OnNavigationChanged(Sender: TObject); virtual;
    procedure DrawRadio(Canvas: TCanvas; R:TRect;Num,Idx: Integer;dir,dis: Boolean;sl: TStrings;
      Selected:boolean;ACol,ARow: integer; Style: TControlStyle; ResFactor: real; Print: boolean = false);
    function GetParentForm(Control: TControl): TCustomForm;
    procedure ExpandNodeInt(ARow: Integer);
    procedure TabToNextRowAtEnd; virtual;
    procedure SetComment(ACol,ARow: integer; value: string);
    function GetComment(ACol,ARow: integer): string;
    function DoAllowFmtPaste: boolean; virtual;
    procedure ChangeScale(M, D: Integer); override;
    function ColumnCustomCalcGrp(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    property FilterColumn: integer read FFilterCol write FFilterCol;
    procedure FilterSelect(Sender: TObject; ItemIndex: integer); virtual;
    procedure FilterCheck(Sender: TObject; ItemIndex: integer); virtual;
    function GetCellTextSizeInt(ACol,RCol,ARow: Integer; ColSize: boolean; VS: Boolean = false; SB: Boolean = false): TSize;
    procedure PaintDesigner; virtual;
    procedure HandleDesignChoice(X,Y: integer); virtual;
    function IsOnLastRow: boolean;
    procedure AppendLastRow;
    function HasCustomCellBorder: boolean; override;
    function SetCheckBoxStateInt(ACol,ARow: Integer;state: Boolean): Boolean;
    procedure SetEditorsStyle(AStyle: TTMSStyle);
    procedure DoCheckBoxChange(ACol,ARow: integer; State: boolean); virtual;
    function DoRatingChange(ACol,ARow: integer; var NewRate: double): boolean; virtual;
    procedure DoColorSelect(Sender: TObject); virtual;
    procedure DoImageSelect(Sender: TObject); virtual;
    procedure DoCellChanging(ACol,ARow: integer; var CanChange: boolean); virtual;
    procedure DoCellScroll(ACol,ARow: Integer; ScrollPosition, ScrollMin,ScrollMax: integer); virtual;
    procedure DoFilterType(Sender: TObject);
    procedure DoFilterEditDone(ACol: integer; ft: TFilterType);
    procedure InsertRowsEx(RowIndex, RCount: Integer; UpdateCellControls: boolean = true);
    function  CanShowFixedDropDown(ACol:integer): boolean; virtual;
    procedure DoStartBlockFocus; virtual;
    procedure DoEndBlockFocus; virtual;
    procedure DoIntelliZoom; virtual;
    property OnStartBlockFocus: TNotifyEvent read FOnStartBlockFocus write FOnStartBlockFocus;
    property OnEndBlockFocus: TNotifyEvent read FOnEndBlockFocus write FOnEndBlockFocus;
    property OldCellText: string read FOldCellText write FOldCellText;
    property InWorkbook: boolean read FInWorkbook write FInWorkbook;
    property SaveFormula: Boolean read FSaveFormula write FSaveFormula;
    function GetCellImageList(ACol,ARow: integer): TCustomImageList; virtual;
    function IsEditableInt(ACol,ARow: Integer): Boolean;
    procedure ForceMouseOnCell(Col,Row:integer);
    procedure GotoCellInt(Col,Row: Integer);
    function UseVCLStyles: boolean; override;
    function GetRichEdit: TAdvRichEdit;
    function EditRichEdit: TAdvRichEdit;
    function EditDateTime: TGridDateTimePicker;
    function EditDate: TGridDatePicker;
    function EditSpin: TGridSpin;
    function EditAdvGridPicker: TGridAdvGridDropDown;
    function EditTrackBar: TGridTrackbarDropDown;
    function EditMemo: TGridMemoDropDown;
    function EditCalculator: TGridCalculatorDropDown;
    function EditTimePicker: TGridTimePickerDropDown;
    function EditDetailPicker: TGridDetailPickerDropDown;
    function EditGridPicker: TGridGridDropDown;
    function EditColorPicker: TGridColorDropDown;
    function EditImagePicker: TGridImageDropDown;
    function EditControlPicker: TGridControlDropDown;
    function MatchesMulti(ARow: integer): boolean;
    function GetCellEditorControl: TWinControl;
    procedure ClearRowSelectInt;
    procedure GroupMerge;
    procedure GroupSplit;
    procedure RegisterValidateInterface(AValidate: ITMSCellValidate);
    procedure UnregisterValidateInterface;
    procedure ExpandFast;
  public
    LButFlg: Boolean;
    Compares: Integer;
    Swaps: Integer;
    SortTime: DWord;
    Sortlist: TStringList;
    PrevSizeX,PrevSizeY: Integer;
    EditMode: Boolean;
    ccuCall: Boolean;
    property IsThemed: boolean read FIsComCtl6;
    property IsPrintPreview: boolean read FIsPrintPreview write FIsPrintPreview;
    property FitCellsInGrid: boolean read FFitCellsInGrid write FFitCellsInGrid;
    function GetCellTextSize(ACol,ARow: Integer;VS: Boolean = false; SB: Boolean = false): TSize;
    procedure ExportNotification(AState: TGridExportState; ARow: Integer); virtual;
    procedure ImportNotification(AState: TGridImportState; ARow: Integer); virtual;
    procedure CellControlsUpdate(rebuildlist: boolean = false);
    procedure RegisterNotifier(ANotifier: TGridChangeNotifier);
    procedure UnRegisterNotifier(ANotifier: TGridChangeNotifier);
    procedure RegisterSelListener(AListener: ITAdvStringGridSelect);
    procedure UnRegisterSelListener(AListener: ITAdvStringGridSelect);
    procedure ClearComboString;
    procedure AddComboString(const s: string);
    procedure AddComboStringObject(const s: string; AObject: TObject);
    function RemoveComboString(const s: string): Boolean;
    function SetComboSelectionString(const s: string): Boolean;
    procedure SetComboSelection(idx: Integer);
    function GetComboCount: Integer;
    constructor Create(AOwner:tComponent); override;
    destructor Destroy; override;
    procedure Invalidate; override;
    procedure AssignCells(Source: TPersistent); virtual;
    procedure Assign(Source: TPersistent); override;
    procedure GetFontProperties(ACol,RCol,ARow: Integer; var AState: TGridDrawState; AFont: TFont; ABrush: TBrush; Remap: boolean);
    procedure GetVisualProperties(ACol,ARow: Integer; var AState: TGridDrawState; Print, Select,Remap: Boolean;
      ABrush: TBrush; var AColorTo, AMirrorColor, AMirrorColorTo: TColor; AFont: TFont; var HA: TAlignment; var VA: TVAlignment;
      var WW: Boolean;var GD: TCellGradientDirection); override;
//    procedure PrivatePreviewRect(Preview: TPrintPreview; Gridrect:TGridRect; SelRows: Boolean);
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    procedure OleColumnDragStart(ACol, AIndex: integer; AList: TCustomListbox);
    function GetVersionNr: Integer; virtual;
    function GetVersionString:string; virtual;
    property ZoomFactor: integer read FZoomFactor write FZoomFactor;
    function ValidateCell(const NewValue: string): Boolean; virtual;
    function ValidateCellWide(const NewValue: widestring): Boolean; virtual;

    function FirstCellInRow(ARow: Integer): Integer;
    function LastCellInRow(ARow: Integer): Integer;
    procedure BalloonInit;
    procedure BalloonDone;

    procedure ApplyFilter;
    function RemoveLastFilter: boolean;
    procedure RemoveAllFilters;
    procedure SaveFilter(FileName: string);
    procedure LoadFilter(FileName: string);
    procedure NarrowDown(ACondition: string; AColumn: integer = -1); overload;
    procedure NarrowDown(ACondition: string; DoRemoveAccented: boolean; AColumn: integer = -1); overload;

    procedure InitOrigColSizes;
    function SelectionToForm(ARect: TGridRect): TForm;

    procedure StretchColumns;

    procedure RemoveCheckedRows(CheckBoxColumn: integer; RemoveChecked: boolean=true);
    procedure RemoveRowList(RowList: TIntList);
    procedure RemoveRowsEx(RowIndex, RCount: Integer); virtual;
    procedure RemoveRows(RowIndex, RCount: Integer); virtual;
    procedure InsertRows(RowIndex, RCount: Integer; UpdateCellControls: boolean = true); virtual;
    procedure RemoveCols(ColIndex, CCount: Integer); virtual;
    procedure InsertCols(ColIndex, CCount: Integer); virtual;
    procedure AddColumn;
    procedure AddRow;
    procedure Resize; override;
    procedure FilterRow(ARow: Integer);
    function GetParentRow(ARow: Integer): Integer;
    procedure InsertChildRow(ARow: Integer; InsertAt:integer = 1);
    procedure RemoveChildRow(ARow: Integer);
    procedure InsertNormalRow(ARow: Integer);
    procedure RemoveNormalRow(ARow: Integer);
    procedure RemoveSelectedCols;
    procedure RemoveUnSelectedCols;
    procedure RemoveSelectedRows;
    procedure RemoveUnSelectedRows;
    procedure RemoveDuplicates(ACol: Integer; DoCase: Boolean);
    procedure MergeCols(ColIndex1, ColIndex2 : Integer; Separator : string = ' ');
    procedure MergeColumnCells(ColIndex: Integer; MainMerge: Boolean);
    procedure SplitColumnCells(ColIndex: Integer);
    procedure MergeRowCells(RowIndex: Integer; MainMerge: Boolean);
    procedure SplitRowCells(RowIndex: Integer);
    procedure SplitAllCells;
    function IsSummary(ARow: Integer): Boolean;
    function IsFixed(ACol,ARow: Integer): Boolean; override;
    function IsEditable(ACol,ARow: Integer): Boolean;
    procedure SwapColumns(ACol1,ACol2: Integer);
    procedure HideColumn(ColIndex: Integer);
    procedure UnHideColumn(ColIndex: Integer);
    procedure HideColumns(FromCol,ToCol: Integer);
    procedure UnHideColumns(FromCol,ToCol: Integer);
    procedure UnHideColumnsAll;
    function IsHiddenColumn(Colindex: Integer): Boolean;
    function NumHiddenColumns: Integer;
    function TotalColCount: Integer; override;
    procedure SuppressColumn(ColIndex: Integer);
    procedure UnSuppressColumn(ColIndex: Integer);
    procedure UnSuppressAllColumns;
    procedure RepaintRect(r:TRect);
    procedure RepaintCell(c,r: Integer);
    procedure RepaintRow(ARow: Integer);
    procedure RepaintCol(ACol: Integer);
    procedure GroupCalc(Colindex,method: Integer);
    procedure GroupSum(Colindex: Integer);
    procedure GroupAvg(Colindex: Integer);
    procedure GroupMin(Colindex: Integer);
    procedure GroupMax(Colindex: Integer);
    procedure GroupCustomCalc(Colindex: Integer);
    procedure GroupCount(ColIndex: Integer);
    procedure GroupDistinct(ColIndex: Integer);
    procedure GroupStdDev(ColIndex: Integer);
    procedure SubGroup(Colindex: Integer); virtual;
    procedure SubUnGroup(Colindex: Integer); virtual;
    procedure Group(Colindex: Integer); virtual;
    procedure UnGroup; virtual;
    procedure HideRow(Rowindex: Integer);
    procedure HideRows(FromRow,ToRow: Integer);
    procedure HideRowList(RowList: TIntList);
    procedure HideRowsEx(FromRow,ToRow: Integer);
    procedure UnHideRow(Rowindex: Integer);
    procedure UnHideRows(FromRow,ToRow: Integer);
    procedure UnHideRowList;
    procedure UnHideRowsAll;
    procedure HideSelectedRows;
    procedure HideUnSelectedRows;
    function IsHiddenRow(Rowindex: Integer): Boolean; overload;
    function IsHiddenRow(Rowindex: Integer; var ListHidden: TIntList): Boolean; overload;
    function NumHiddenRows: Integer;
    function TotalRowCount: Integer;
    function RealRowIndex(ARow: Integer): Integer;
    function RealColIndex(ACol: Integer): Integer; override;
    function DisplRowIndex(ARow: Integer): Integer;
    function DisplColIndex(ACol: Integer): Integer; override;
    function IsIgnoredColumn(ACol: Integer): boolean;
    procedure SetColumnOrder;
    procedure ResetColumnOrder;
    function ColumnPosition(ACol: integer): integer;
    function ColumnAtPosition(ACol: integer): integer;
    function ColumnByHeader(AValue: string): integer;
    function UnSortedRowIndex(ARow: Integer): Integer;
    function SortedRowIndex(ARow: Integer): Integer;
    function GetRealCol: Integer;
    function GetRealRow: Integer;
    function GetRowEx: Integer;
    procedure SetRowEx(const Value: Integer); virtual;
    function GetTopRowEx: integer;
    procedure SetTopRowEx(const Value: integer);
    procedure ScreenToCell(pt:TPoint; var ACol,ARow: Integer);
    procedure HideSelection;
    procedure UnHideSelection;
    function IsSelectionHidden: boolean;
    procedure UpdateEditMode;
    procedure UpdateFooter;
    procedure ScrollInView(ColIndex,RowIndex: Integer; Position: TScrollPosition = spMiddle);
    procedure MoveRow(FromIndex, ToIndex: Integer);
    procedure MoveRows(FromIndex, ToIndex, Count: Integer);
    procedure MoveColumn(FromIndex, ToIndex: Integer);
    procedure SwapRows(ARow1,ARow2: Integer);
    procedure SortSwapRows(ARow1,ARow2: Integer); virtual;
    procedure ColorRect(ACol1,ARow1,ACol2,ARow2: Integer; AColor: TColor);
    procedure ClearRect(ACol1,ARow1,ACol2,ARow2: Integer); virtual;
    procedure Clear;
    procedure ClearAll;
    procedure ClearRows(RowIndex, RCount: Integer);
    procedure ClearCols(ColIndex, CCount: Integer);
    procedure ClearNormalRows(RowIndex, RCount: Integer);
    procedure ClearNormalCols(ColIndex, CCount: Integer);
    procedure ClearNormalCells;
    procedure ClearSelection;
    procedure ClearRowSelect;
    procedure ClearColSelect;
    procedure TrimRect(ACol1,ARow1,ACol2,ARow2: Integer); virtual;
    procedure TrimColumn(ACol: Integer);
    procedure TrimRow(ARow: Integer);
    procedure TrimAll;
    procedure EditCell(ACol,ARow: Integer);
    procedure FocusCell(ACol,ARow: Integer);
    procedure GotoCell(ACol,ARow: Integer);
    procedure SwapCells(FromCell,ToCell: TGridCoord);
    procedure SelectRows(RowIndex, RCount: Integer);
    procedure UnSelectRows(RowIndex, RCount: Integer);
    procedure SelectCols(ColIndex, CCount: Integer);
    procedure UnSelectCols(ColIndex, CCount: Integer);
    procedure SelectRange(FromCol,ToCol,FromRow,ToRow: Integer);
    procedure ClearSelectedCells;
    procedure ClearModifiedRows;
    function ModifiedRowCount: integer;
    function DistinctValues(ACol: integer; CaseSensitive: boolean = true): TStrings;
    function IsCell(SubStr: string; var ACol, ARow: Integer): Boolean;
    function IsWideCell(ACol,ARow: Integer): Boolean;
    {$IFDEF DELPHI_UNICODE}
    procedure SaveToFile(FileName: string; Unicode: boolean = true);
    procedure SaveToCSV(FileName: string; Unicode: boolean = true);
    procedure AppendToCSV(FileName: string; Unicode: boolean = true);
    procedure AppendToASCII(FileName: string; Unicode: boolean = true);
    procedure SaveToASCII(FileName: string; Unicode: boolean = true);
    {$ENDIF}
    {$IFNDEF DELPHI_UNICODE}
    procedure SaveToFile(FileName: string);
    procedure SaveToCSV(FileName: string);
    procedure AppendToCSV(FileName: string);
    procedure AppendToASCII(FileName: string);
    procedure SaveToASCII(FileName: string);
    {$ENDIF}
    procedure SaveToBinFile(FileName: string);
    procedure SaveToBinStream(Stream: TStream);
    procedure SaveRectToBinStream(Rect: TRect; Stream: TStream; SaveHidden: boolean = false);
    procedure SaveToHTML(FileName: string; Show:boolean = false; Unicode: boolean = true);
    function SaveToHTMLString(dir: string): string;
    procedure AppendToHTML(FileName: string; Show:boolean = false; Unicode: boolean = true);
    procedure SaveToXML(FileName: string; ListDescr, RecordDescr:string;FieldDescr:TStrings; ExportEmptyCells: boolean=false);
    procedure LoadFromXML(FileName: string; LevelToRow: boolean = false;LoadFieldDescr:boolean = true);
    procedure SaveToJSON(FileName: string; RecordDescr: string; FieldDescr: TStrings);
    procedure SaveToFixed(FileName: string;positions: TIntList);
    procedure SaveToStream(Stream: TStream);
    procedure LoadFromFile(FileName: string);
    procedure LoadFromBinFile(FileName: string);
    procedure LoadFromBinStream(Stream: TStream);
    procedure LoadAtPointFromBinStream(Point: TPoint; Stream: TStream);
    procedure LoadFromCSV(FileName: String; MaxRows: integer = -1); overload;
    {$IFDEF DELPHI_UNICODE}
    procedure LoadFromCSV(FileName: String; AEncoding: TEncoding; MaxRows: integer = -1); overload;
    {$ENDIF}
    procedure LoadFromCSVStream(AStream: TStream; MaxRows: integer = -1);
    procedure LoadFromFixed(FileName:string;positions:TIntList; DoTrim: boolean = true; MaxRows: integer = -1);
    procedure InsertFromCSV(FileName: String; MaxRows: integer = -1);
    procedure LoadFromStream(Stream: TStream);
    procedure SaveColSizes;
    procedure LoadColSizes;
    procedure SaveColPositions; virtual;
    procedure LoadColPositions; virtual;
    function ColumnStatesToString: string;
    procedure StringToColumnStates(Value: string);
    procedure LoadVisualProps(FileName: string);
    procedure SaveVisualProps(FileName: string);
    procedure SavePrintSettings(Key,Section:string);
    procedure LoadPrintSettings(Key,Section:string);
    procedure CutToClipboard;
    procedure CutSelectionToClipboard;
    procedure CopyToClipBoard;
    procedure CopyToClipBoardAsHTML;
    procedure CopySelectionToClipboard;
    procedure PasteFromClipboard;
    procedure PasteSelectionFromClipboard;
    function GetSelectionAsText: string;
    procedure SetSelectionAsText(const Value: string);
    procedure ShowColumnHeaders;
    procedure ClearColumnHeaders;
    procedure ShowRowHeaders;
    procedure ClearRowHeaders;
    procedure HideCellEdit;
    procedure ShowCellEdit;
    procedure UpdateXYOffset(X,Y: integer);
    procedure  Select;
    procedure SetTheme(Scheme: TXPColorScheme);
    procedure SetStyle(AStyle: TAdvGridStyle); virtual;
    procedure SetStyleAndAppColor(AStyle: TAdvGridStyle; AppColor: TColor); virtual;
    procedure SetComponentStyle(AStyle: TTMSStyle);
    procedure SetComponentStyleAndAppColor(AStyle: TTMSStyle; AppColor: TColor);
    procedure SetColorTones(ATones: TColorTones);
    procedure RandomFill(DoFixed: Boolean = false;Rnd: Integer = 100);
    procedure LinearFill(DoFixed: Boolean = false);
    procedure TextFill(DoFixed: Boolean; Txt: string);
    procedure FormatFill(DoFixed: Boolean; Fmt: string);
    function HilightText(DoCase: Boolean; S,Text: string):string;
    function UnHilightText(S:string):string;
    procedure HilightInCell(DoCase: Boolean; Col,Row: Integer; HiText: string; FullText: boolean = false);
    procedure HilightInCol(DoFixed,DoCase: Boolean; Col: Integer; HiText: string; FullText: boolean = false);
    procedure HilightInRow(DoFixed,DoCase: Boolean; Row: Integer; HiText: string; FullText: boolean = false);
    procedure HilightInGrid(DoFixed,DoCase: Boolean; HiText: string; FullText: boolean = false);
    procedure UnHilightInCell(Col,Row: Integer);
    procedure UnHilightInCol(DoFixed: Boolean; Col: Integer);
    procedure UnHilightInRow(DoFixed: Boolean; Row: Integer);
    procedure UnHilightInGrid(DoFixed: Boolean);
    function MarkText(DoCase: Boolean; S,Text: string):string;
    function UnMarkText(S:string):string;
    procedure MarkInCell(DoCase: Boolean; Col,Row: Integer; HiText: string);
    procedure MarkInCol(DoFixed,DoCase: Boolean; Col: Integer; HiText: string);
    procedure MarkInRow(DoFixed,DoCase: Boolean; Row: Integer; HiText: string);
    procedure MarkInGrid(DoFixed,DoCase: Boolean; HiText: string);
    procedure UnMarkInCell(Col,Row: Integer);
    procedure UnMarkInCol(DoFixed: Boolean; Col: Integer);
    procedure UnMarkInRow(DoFixed: Boolean; Row: Integer);
    procedure UnMarkInGrid(DoFixed: Boolean);
    function CheckCells(FromCol,FromRow,ToCol,ToRow: Integer): Boolean;
    function CheckCell(Col,Row: Integer): Boolean;
    function CheckGrid(DoFixed: Boolean): Boolean;
    function CheckCol(DoFixed: Boolean; Col: Integer): Boolean;
    function CheckRow(DoFixed: Boolean; Row: Integer): Boolean;
    procedure Zoom(x: Integer); virtual;
    procedure SaveToXLS(Filename:string; CreateNewSheet: boolean = true);
    procedure SaveToXLSSheet(Filename, SheetName:string);
    function GetXLSSheets(FileName: string): TStringList;
    procedure LoadFromXLS(Filename:string);
    procedure LoadFromXLSSheet(Filename, SheetName:string);
    procedure LoadFromMDBTable(Filename, Table: string);
    procedure LoadFromMDBSQL(Filename, SQL: string);
    procedure AppendToDoc(Filename:string; Bookmark: string);
    procedure SaveToDOC(Filename:string; CreateNewDocument: boolean = true);
    procedure RichToCell(Col,Row: Integer; Richeditor: TRichEdit);
    function RichToString(Richeditor: TRichEdit):string;
    procedure CellToRich(Col,Row: Integer; Richeditor: TRichEdit);
    {$IFDEF ISDELPHI}
    function CellToReal(ACol,ARow: Integer): Real;
    {$ENDIF}
    procedure AutoFitColumns(const DoFixedCells: boolean = true);
    procedure AutoSizeCells(const DoFixedCells: Boolean; const PaddingX,PaddingY: Integer);
    procedure AutoSizeColumns(const DoFixedCols: Boolean; const Padding: Integer = 4);
    procedure AutoSizeCol(const ACol: Integer; const Padding: Integer = 0);
    procedure AutoGrowColumns(const DoFixedCols: Boolean; const Padding: Integer = 4);
    procedure AutoGrowCol(const ACol: Integer; const Padding: Integer = 0);
    procedure AutoSizeRows(const DoFixedRows: Boolean; const Padding: Integer = 0);
    procedure AutoSizeRow(const ARow: Integer; const Padding: Integer = 0);
    procedure StretchRightColumn;
    procedure SizeToCols;
    procedure SizeToRows;
    procedure SizeToCells;
    procedure AutoNumberCol(const ACol: Integer);
    procedure AutoNumberRow(const ARow: Integer);
    function IsSelected(ACol,ARow: Integer): Boolean;
    function SelectedText: string;
    procedure SelectCells(FromCol,FromRow, ToCol, ToRow: integer);
    procedure ShowInplaceEdit;
    procedure HideInplaceEdit;
    procedure DoneInplaceEdit(Key:word; Shift:TShiftState);
    procedure QSort; virtual;
    procedure QSortIndexed; virtual;
    procedure QSortGroup; virtual;
    procedure QSortGroupIndexed; virtual;
    procedure QUnSort; virtual;
    procedure Sort(Column: integer; Direction: TSortDirection = sdAscending);
    procedure InitSortXRef;
    procedure Print;
    procedure PrintRect(Gridrect:TGridRect);
    procedure PrintSelection;
    procedure PrintSelectedRows;
    procedure PrintSelectedCols;
    procedure PrintPreview(Canvas:TCanvas; Displayrect:TRect);
    procedure PrintPreviewRect(Canvas:TCanvas; Displayrect:TRect; Gridrect:TGridRect);
    procedure PrintPreviewSelectedRows(Canvas:TCanvas; Displayrect:TRect);
    procedure PrintPreviewSelectedCols(Canvas:TCanvas; Displayrect:TRect);
    procedure PrintPreviewSelection(Canvas:TCanvas; Displayrect:TRect);    
    procedure PrintDraw(Canvas:TCanvas;DrawRect:TRect);
    procedure PrintDrawRect(Canvas:TCanvas;DrawRect:TRect;Gridrect:TGridRect);
    procedure SortByColumn(Col: Integer);
    procedure QuickSort(Col,Left,Right: Integer);
    procedure QuickSortIndexed(Left,Right: Integer);
    function ColumnType(Col: integer): TColumnType;
    function SortLine(Col,ARow1,ARow2: Integer): Boolean;
    function Search(s:string): Integer;
    function Find(StartCell:TPoint; s:string; FindParams: TFindParams): TPoint;
    function FindWide(StartCell:TPoint; s:widestring; FindParams: TFindParams): TPoint;
    function FindFirst(s:string; FindParams: TFindParams): TPoint;
    function FindNext: TPoint;
    function FindMulti(Conditions: array of string; Columns: array of integer; Searchtypes: array of TSearchType; CaseSensitive: array of boolean; AutoGoto: boolean = false): integer;
    function FindMultiNext: integer;
    function Replace(OrigStr,NewStr: string; FindParams: TFindParams): integer;
    function MapFontHeight(pointsize: Integer): Integer;
    function MapFontSize(Height: Integer): Integer;
    procedure AddInterfacedCell(ACol,ARow: Integer; AObject: TInterfacedPersistent);
    procedure RemoveInterfacedCell(ACol,ARow: Integer);
    function GetInterfacedCell(ACol,ARow: Integer): TInterfacedPersistent;
    function CreateBitmap(ACol,ARow: Integer;transparent: Boolean;hal:TCellHalign;val:TCellValign):TBitmap;
    procedure AddBitmap(ACol,ARow: Integer;ABmp:TBitmap;Transparent: Boolean;hal:TCellHalign;val:TCellValign);
    procedure RemoveBitmap(ACol,ARow: Integer);
    function GetBitmap(ACol,ARow: Integer): TBitmap;
    function HasBitmap(ACol,ARow: Integer): boolean;
    function CreatePicture(ACol,ARow: Integer;transparent: Boolean;stretchmode:TStretchMode;padding: Integer;hal:TCellHalign;val:TCellValign):TPicture;
    procedure AddPicture(ACol,ARow: Integer; APicture:TPicture;transparent: Boolean;stretchmode:TStretchMode;padding: Integer;hal:TCellHalign;val:TCellValign);
    procedure RemovePicture(ACol,ARow: Integer);
    function GetPicture(ACol,ARow: Integer): TPicture;
    function HasPicture(ACol,ARow: Integer): boolean;
    function CreateFilePicture(ACol,ARow: Integer;Transparent: Boolean;StretchMode:TStretchMode;padding: Integer;hal:TCellHalign;val:TCellValign):TFilePicture;
    procedure AddFilePicture(ACol,ARow: Integer;AFilePicture:TFilePicture;Transparent: Boolean;stretchmode:TStretchMode;padding: Integer;hal:TCellHalign;val:TCellValign);
    procedure RemoveFilePicture(ACol,ARow: Integer);
    function GetFilePicture(ACol,ARow: Integer): TFilePicture;
    function HasFilePicture(ACol,ARow: Integer): boolean;
    procedure AddNode(ARow,Span: Integer);
    procedure RemoveNode(ARow: Integer);
    procedure RemoveAllNodes;
    function IsNode(ARow: Integer): Boolean;
    function GetNodeSpanType(ARow: Integer): Integer;
    function GetNodeState(ARow: Integer): Boolean;
    function GetNodeLevel(ARow: Integer): Integer;
    procedure SetNodeState(ARow: Integer;Value: Boolean);
    function GetNodeSpan(ARow: Integer): Integer;
    procedure SetNodeSpan(ARow, Span: Integer);
    function GetSubNodeCount(ARow: Integer): Integer;
    procedure UpdateNodeSpan(ARow, Delta: Integer);
    procedure UpdateSubNodeCount(ARow, Delta: Integer);
    procedure ExpandNode(ARow: Integer);
    procedure ContractNode(ARow: Integer);
    procedure ExpandAll;
    procedure ContractAll;
    procedure AddRadio(ACol,ARow,DirRadio,IdxRadio: Integer; sl:TStrings);
    function CreateRadio(ACol,ARow,DirRadio,IdxRadio: Integer): TStrings;
    procedure RemoveRadio(ACol,ARow: Integer);
    function IsRadio(ACol,ARow: Integer): Boolean;
    function GetRadioIdx(ACol,ARow: Integer;var IdxRadio: Integer): Boolean;
    function SetRadioIdx(ACol,ARow,IdxRadio: Integer): Boolean;
    function GetRadioStrings(ACol,ARow: Integer): TStrings;
    procedure AddImageIdx(ACol,ARow,Aidx: Integer;hal:TCellHalign;val:TCellValign);
    procedure RemoveImageIdx(ACol,ARow: Integer);
    function GetImageIdx(ACol,ARow: Integer;var idx: Integer): Boolean;
    procedure SetImageIdx(ACol,ARow,Idx: Integer);
    procedure AddMultiImage(ACol,ARow,Dir: Integer;hal:TCellHalign;val:TCellValign);
    procedure RemoveMultiImage(ACol,ARow: Integer);
    procedure AddDataImage(ACol,ARow,Aidx: Integer;hal:TCellHalign;val:TCellValign);
    procedure RemoveDataImage(ACol,ARow: Integer);
    function HasDataImage(ACol,ARow: Integer): Boolean;
    procedure AddRotated(ACol,ARow: Integer; AAngle: Smallint; s: string);
    procedure SetRotated(ACol,ARow: Integer; AAngle: SmallInt);
    procedure RemoveRotated(ACol,ARow: Integer);
    function IsRotated(ACol,ARow: Integer;var aAngle: Integer): Boolean;
    function CreateIcon(ACol,ARow: Integer;hal:TCellHalign;val:TCellValign): TIcon;
    procedure AddIcon(ACol,ARow: Integer;AIcon:TIcon;hal:TCellHalign;val:TCellValign);
    procedure RemoveIcon(ACol,ARow: Integer);
    procedure AddButton(ACol,ARow, bw, bh: Integer;Caption:string;hal:TCellHalign;val:TCellValign);
    procedure SetButtonText(ACol,ARow: Integer; Caption: string);
    function GetButtonText(ACol,ARow: Integer): string;
    procedure PushButton(ACol,ARow: Integer;push: Boolean);
    procedure RemoveButton(ACol,ARow: Integer);
    procedure RemoveBitButton(ACol,ARow: Integer);
    procedure RemoveAllButtons;
    function HasButton(ACol,ARow: Integer): Boolean;
    procedure AddBitButton(ACol,ARow, bw, bh: Integer;Caption:string;Glyph: TBitmap;hal:TCellHalign;val:TCellValign);
    function CreateBitButton(ACol,ARow, bw, bh: Integer;Caption:string;hal:TCellHalign;val:TCellValign): TBitmap;
    procedure AddCheckBox(ACol,ARow: Integer; State,Data: Boolean); overload;
    function BoolToCheckBoxState( bChecked: Boolean ): TCheckBoxState;
    procedure AddCheckBox(ACol,ARow: Integer; State: TCheckBoxState ); overload;
    procedure AddTriStateCheckBoxColumn(ACol: integer; state: TCheckBoxState );
    function GetCheckBoxState(ACol,ARow: Integer; var state: TCheckBoxState ): Boolean; overload;
    procedure RemoveCheckBox(ACol,ARow: Integer);
    function HasCheckBox(ACol,ARow: Integer): Boolean;
    function IsInCheckBox(ACol,ARow,XPos,YPos: Integer): Boolean;
    procedure AddCheckBoxColumn(ACol: Integer; DefaultState: boolean = false; DataCheckBox: boolean = false);
    procedure RemoveCheckBoxColumn(ACol: Integer);
    function HasDataCheckBox(ACol,ARow: Integer): Boolean;
    function GetCheckBoxState(ACol,ARow: Integer;var state: Boolean): Boolean; overload;
    function IsChecked(ACol,ARow: Integer): Boolean;
    function SetCheckBoxState(ACol,ARow: Integer; State: Boolean): Boolean; overload;
    function SetCheckBoxState(ACol,ARow: Integer; State: TCheckBoxState): Boolean; overload;
    function ToggleCheckBox(ACol,ARow: Integer): Boolean;
    procedure CheckAll(ACol: Integer);
    procedure UnCheckAll(ACol: Integer);

    procedure AddRadioButton(ACol,ARow: integer; State:boolean = false);
    procedure AddRadioButtonGroup(ACol,ARow: integer; Group: TRadioButtonGroup; State:boolean = false);
    procedure RemoveRadioButton(ACol,ARow: integer);
    function HasRadioButton(ACol,ARow: integer): boolean;
    function HasRadioButtonGroup(ACol,ARow: integer; Group: TRadioButtonGroup): boolean;
    function IsRadioButtonChecked(ACol,ARow: integer): boolean;
    function SetRadioButtonState(ACol, ARow: integer; State: boolean): boolean;
    procedure AddRadioButtonColumn(ACol: integer);
    procedure AddRadioButtonGroupColumn(ACol: integer);
    procedure RemoveRadioButtonColumn(ACol: integer);
    procedure SetRadioButtonColumnIndex(ACol, Index: integer);
    procedure SetRadioButtonRowIndex(ARow, Index: integer);
    function GetRadioButtonColumnIndex(ACol: integer): integer;

    function HasExpand(ACol,ARow: Integer): boolean;
    procedure AddExpand(ACol,ARow, ExpandedHeight: integer);
    procedure RemoveExpand(ACol,ARow: Integer);
    function ToggleExpand(ACol,ARow: Integer): boolean;
    function GetExpandState(ACol,ARow: Integer): boolean;
    function GetExpandHeight(ACol,ARow: Integer; Expanded: boolean): integer;

    function HasProgress(ACol,ARow: Integer): boolean;
    procedure AddProgress(ACol,ARow: Integer;FGColor,BKColor: TColor);
    procedure AddProgressEx(ACol,ARow: Integer;FGColor,FGTextColor,BKColor,BKTextColor: TColor);
    procedure AddProgressFormatted(ACol,ARow: Integer;FGColor,FGTextColor,BKColor,BKTextColor: TColor; Fmt: string; Min, Max: Integer);
    procedure RemoveProgress(ACol,ARow: Integer);

    procedure AddAdvProgress(ACol,ARow: Integer;Min: Integer = 0; Max: Integer=100);
    procedure RemoveAdvProgress(ACol,ARow: Integer);

    procedure AddProgressPie(ACol,ARow: Integer; Color: TColor; Value: Integer);
    procedure SetProgressPie(ACol,ARow: Integer; Value: Integer);
    procedure RemoveProgressPie(ACol,ARow: Integer);

    procedure AddRangeIndicator(ACol, ARow: Integer; Range: Integer = 100; NegColor: TColor = clRed; PosColor: TColor = clBlack; ShowValue: Boolean = false);
    procedure RemoveRangeIndicator(ACol, ARow: Integer);

    procedure AddBalloon(ACol,ARow: Integer; Title, Text:string; Icon: TBalloonIcon);
    procedure RemoveBalloon(ACol, ARow: integer);
    function HasBalloon(ACol, ARow: integer): boolean;
    function IsBalloon(ACol, ARow: integer; var Title, Text: string; var Icon: TBalloonIcon): boolean;

    procedure AddComment(ACol,ARow: Integer; Comment:string);
    procedure AddColorComment(ACol,ARow: Integer; Comment:string; Color: TColor);
    procedure RemoveComment(ACol,ARow: Integer);
    procedure RemoveAllComments;
    procedure AddMarker(ACol,ARow,ErrPos,ErrLen: Integer);
    procedure RemoveMarker(ACol,ARow: Integer);
    procedure RemoveAllMarkers;
    procedure GetMarker(ACol,ARow:Integer;var ErrPos,ErrLen: Integer);
    function IsComment(ACol,ARow: Integer;var comment:string): Boolean;
    property CellComment[ACol,ARow: Integer]: string read GetComment write SetComment;

    procedure AddScrollBar(ACol,ARow: integer; AutoRange: boolean = false);
    procedure RemoveScrollBar(ACol,ARow: integer);
    function HasScrollBar(ACol, ARow: integer): boolean;
    function HasAutoRangeScrollBar(ACol, ARow: integer): boolean;

    procedure AddShape(ACol,ARow: integer; Shape: TCellShape; FillColor,LineColor: TColor;hal:TCellHalign;val:TCellValign);
    function HasShape(ACol,ARow: integer): boolean;
    procedure RemoveShape(ACol,ARow: integer);
    procedure SetShapeColor(ACol,ARow: integer; FillColor: TColor);
    function GetShapeColor(ACol,ARow: integer): TColor;

    procedure AddRating(ACol,ARow,Scale: integer; FillColor, EmptyColor: TColor);
    procedure RemoveRating(ACol,ARow: integer);
    function HasRating(ACol,ARow: integer): boolean;

    function GetScrollPosition(ACol, ARow: integer): integer;
    procedure SetScrollPosition(ACol, ARow, Pos: integer);
    function GetScrollProp(ACol, ARow: integer): TScrollProp;
    procedure SetScrollProp(ACol, ARow: integer; Prop: TScrollProp);

    function ColumnCount(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnSum(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnAvg(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnMin(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnMax(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnDistinct(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnStdDev(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function ColumnCustomCalc(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
    function RowSum(ARow,fromCol,toCol: Integer): Double;
    function RowAvg(ARow,fromCol,toCol: Integer): Double;
    function RowMin(ARow,fromCol,toCol: Integer): Double;
    function RowMax(ARow,fromCol,toCol: Integer): Double;

    function RectCalc(GR: TGridRect; CalcType: TCalcType): double;
    function RectSum(GR: TGridRect): Double;
    function RectAvg(GR: TGridRect): Double;
    function RectMin(GR: TGridRect): Double;
    function RectMax(GR: TGridRect): Double;

    function SelectionSum: Double;
    function SelectionAvg: Double;
    function SelectionMin: Double;
    function SelectionMax: Double;

    procedure SetFontStyle(GridRect: TGridRect; AStyle: TFontStyle; DoSet: boolean);
    function IsFontStyle(GridRect: TGridRect; AStyle: TFontStyle): boolean;
    procedure SetAlignment(GridRect: TGridRect; AAlignment: TAlignment);
    function IsAlignment(GridRect: TGridRect; AAlignment: TAlignment): boolean;
    procedure SetCellColor(GridRect: TGridRect; AColor: TColor);
    procedure SetCellTextColor(GridRect: TGridRect; AColor: TColor);
    procedure SetCellFontName(GridRect: TGridRect; AFontName: string);
    procedure SetCellFontSize(GridRect: TGridRect; AFontSize: integer);

    procedure ResetFixedCellHighlight;
    procedure CalcFooter(ACol: Integer = -1); virtual;
    procedure BeginUpdate;
    procedure EndUpdate;
    procedure StartUpdate;
    procedure ResetUpdate;
    function IsUpdating: boolean;
    {$IFDEF DELPHI_UNICODE}
    property Encoding: TEncoding read FEncoding write FEncoding;
    {$ENDIF}
    property LockUpdate: Boolean read GetLockFlag write SetLockFlag;
    property UsedCells: TGridRect read GetUsedCells;
    property CellTypes[ACol,ARow: Integer]:TCellType read GetCellType;
    property IsEmpty[ACol,ARow: Integer]: boolean read GetCellEmpty;
    property CellGraphics[ACol,ARow: Integer]: TCellGraphic read GetCellGraphic;
    property CellGraphicSize[ACol,ARow: Integer]: TPoint read GetCellGraphicSize;
    property CellImageIdx[ACol,ARow: Integer]: Integer read GetCellImageIdx;
    property CellImages[ACol,ARow: Integer]: TIntList read GetCellImages;
    property Ints[ACol,ARow: Integer]: Integer read GetInts write SetInts;
    property AllInts[ACol,ARow: Integer]: Integer read GetAllInts write SetAllInts;
    property Floats[ACol,ARow: Integer]:double read GetFloats write SetFloats;
    property AllFloats[ACol,ARow: Integer]:double read GetAllFloats write SetAllFloats;
    property Dates[ACol,ARow: Integer]:TDateTime read GetDates write SetDates;
    property Times[ACol,ARow: Integer]:TDateTime read GetTimes write SetTimes;
    property ComboIndex[ACol,ARow: Integer]: Integer read GetComboIndex write SetComboIndex;
    property ControlValues[ACol,ARow: Integer;ID: string]: string read GetCtrlVal write SetCtrlVal;
    property Delimiter:char read FDelimiter write FDelimiter;
    property FilterList: TStringList read FFilterList;
    property NoDefaultDraw: Boolean read FNoDefaultDraw write FNoDefaultDraw;
    property PasswordChar:char read FPasswordChar write FPasswordChar;
    property JavaCSV: Boolean read FJavaCSV write FJavaCSV;
    property FastPrint: Boolean read FFastPrint write FFastPrint;
    property FindCol: Integer read FFindCol write FFindCol;
    property FindRow: Integer read FFindRow write FFindRow;
    //property PrecisePrintMeasure: Boolean read FPrecisePrintMeasure write FPrecisePrintMeasure;
    property CheckTrue: string read FCheckTrue write FCheckTrue;
    property CheckFalse: string read FCheckFalse write FCheckFalse;
    property LoadFirstRow: boolean read FLoadFirstRow write FLoadFirstRow;
    property SaveFixedCells: Boolean read FSaveFixedCells write FSaveFixedCells;
    property SaveFixedCols: Boolean read FSaveFixedCols write FSaveFixedCols;
    property SaveFixedRows: Boolean read FSaveFixedRows write FSaveFixedRows;
    property SaveHiddenCells: Boolean read FSaveHiddenCells write FSaveHiddenCells;
    property SaveVirtCells: Boolean read FSaveVirtCells write FSaveVirtCells;
    property SaveWithHTML: Boolean read FSaveWithHTML write FSaveWithHTML;
    property SaveWithRTF: Boolean read FSaveWithRTF write FSaveWithRTF;
    property SaveMergedCells: Boolean read FSaveMergedCells write FSaveMergedCells;
    property SearchCell: TPoint read FSearchCell write FSearchCell;
    property SortIndexes: TSortIndexList read FSortIndexes;
    property OriginalCellValue: string read FCellCache write FCellCache;
    property EditActive: Boolean read FEditActive;
    property EditMask: string read FEditMask write FEditMask;
    property NoImageAndText: Boolean read FNoImageAndText write FNoImageAndText;
    property DateTimePicker: TGridDatePicker read GetDateTimePicker;
    property DateAndTimePicker: TGridDateTimePicker read EditDateTime;
    property Combobox: TGridCombo read EditCombo;
    property FixedEdit: TGridTransEdit read EditTrans;
    property FixedComboBox: TGridTransCombo read ComboTrans;
    property DropList: TDropList read FDropList;
    property DropCheckList: TDropCheckList read FDropCheckList;
    /// EDITORINTEGRATION
    property TrackbarDropDown: TGridTrackbarDropDown read EditTrackBar;
    property MemoDropDown: TGridMemoDropDown read EditMemo;
    property CalculatorDropDown: TGridCalculatorDropDown read EditCalculator;
    property TimePickerDropDown: TGridTimePickerDropDown read EditTimePicker;
    property DetailPickerDropDown: TGridDetailPickerDropDown read EditDetailPicker;
    property GridDropDown: TGridGridDropDown read EditGridPicker;
    property ColorPickerDropDown: TGridColorDropDown read EditColorPicker;
    property ImagePickerDropDown: TGridImageDropDown read EditImagePicker;
    property AdvGridDropDown: TGridAdvGridDropDown read EditAdvGridPicker;
    property ControlDropDown: TGridControlDropDown read EditControlPicker;
    /// EDITORINTEGRATION
    property ClearTextOnly: Boolean read FClearTextOnly write FClearTextOnly;
    {$IFNDEF TMSUNICODE}
    property UniCombo: TGridCombo read EditCombo;
    {$ENDIF}
    {$IFDEF TMSUNICODE}
    property UniCombo: TGridUniCombo read ComboUni;
    property UniEdit: TGridUniEdit read EditUni;
    property UniMemo: TGridUniMemo read MemoUni;
    property UniEditBtn: TGridUniEditBtn read EditBtnUni;
    {$ENDIF}
    property SpinEdit: TGridSpin read EditSpin;
    property BtnEdit: TGridEditBtn read EditBtn;
    property Btn: TGridButton read GridButton;
    property BtnUnitEdit: TGridUnitEditBtn read UnitEditBtn;
    property RichEdit: TAdvRichEdit read GetRichEdit;
    property FooterCanvas: TCanvas read GetFooterCanvas;
    property FooterPanel: TFooterPanel read GetFooterPanel;
    property InplaceRichEdit: TAdvRichEdit read EditRichEdit;
    property CellEditor: TWinControl read GetCellEditorControl;
    property IncrSearchText: string read SearchInc write SearchInc;
    property NormalEdit: TAdvInplaceEdit read GetInplaceEditor;
    property SearchPanel: TSearchPanel read FSearchPanel;
    property SpreadSheet: boolean read FSpreadSheet write SetSpreadSheet;
    property PrinterDriverFix: Boolean read FPrinterDriverFix write FPrinterDriverFix;
    property RowSelect[ARow: Integer]: Boolean read GetRowSelect write SetRowSelect;
    property ColSelect[ACol: Integer]: Boolean read GetColSelect write SetColSelect;
    property RowSelectCount: Integer read GetRowSelectCount;
    property ColSelectCount: Integer read GetColSelectCount;
    property RowModified[ARow: Integer]: Boolean read GetRowModified write SetRowModified;
    property RowEnabled[ARow: Integer]: Boolean read GetRowEnabled write SetRowEnabled;
    property Modified: boolean read FGridModified write FGridModified;
    property NodeState[ARow: Integer]: Boolean read GetNodeState write SetNodeState;
    property FindBusy: Boolean read FFindBusy;
    property PrintPageRect:TRect read FPrintPageRect;
    property PrintPageWidth: Integer read FPrintPageWidth;
    property PrintColWidth[ACol: Integer]: Integer read GetPrintColWidth;
    property PrintColOffset[ACol: Integer]: Integer read GetPrintColOffset;
    property PrintColStart: Integer read FPrintColStart;
    property PrintColEnd: Integer read FPrintColEnd;
    property PrintNrOfPages: Integer read FPrintPageNum;
    property ExcelClipboardFormat: Boolean read FExcelClipboardFormat write FExcelClipboardFormat;
    property PreviewPage: Integer read FPrintPageFrom write SetPreviewPage;
    property UnSortedCells[i,j: Integer]: string read GetUnSortedCell write SetUnSortedCell;
    function SaveCell(ACol,ARow: Integer): string; virtual;
    function ExportCell(ACol,ARow: Integer): string; virtual;
    property DisplCells[i,j: Integer]: string read GetFormattedCell;
    property RealCells[i,j: Integer]: string read GetReadCell write SetRealCell;
    property AllCells[i,j: Integer]: string read GetCellsEx write SetCellsEx;
    property AllGridCells[i,j: Integer]: string read GetGridCellsEx write SetGridCellsEx;
    property AllWideCells[i,j: Integer]: widestring read GetWideCellsEx write SetWideCellsEx;
    property WideCells[i,j: Integer]: widestring read GetWideCells write SetWideCells;
    property AllObjects[i,j: Integer]: TObject read GetObjectsEx write SetObjectsEx;
    property OriginalCells[i,j: Integer]: string read GetOriginalCells write SetOriginalCells;
    property AllColWidths[i: Integer]: Integer read GetAllColWidths write SetAllColWidths;
    property AllColCount: Integer read GetAllColCount;
    property AllRowCount: Integer read GetAllRowCount;
    property LastCol: Integer read GetLastCol;
    property LastRow: Integer read GetLastRow;
    property Alignments[i,j: Integer]: TAlignment read GetAlignments write SetAlignments;
    property LinesInCell[i,j: Integer]: Integer read GetLinesInCell;
    property Colors[i,j: Integer]: TColor read GetColors write SetColors;
    property ColorsTo[i,j: Integer]: TColor read GetColorsTo write SetColorsTo;
    property Gradients[i,j: Integer]: TCellGradientDirection read GetGradientDir write SetGradientDir;
    property IgnoreColumns: TIntList read FIgnoreColumns;
    property RowColor[i: Integer]: TColor write SetRowColor;
    property RowColorTo[i: Integer]: TColor write SetRowColorTo;
    property RowFontColor[i: Integer]: TColor write SetRowFontColor;
    property Fonts[i,j: Integer]: TFont read GetCellFont write SetCellFont;
    property FontColors[i,j: Integer]: TColor read GetFontColors write SetFontColors;
    property FontStyles[i,j: Integer]: TFontStyles read GetFontStyles write SetFontStyles;
    property FontSizes[i,j: Integer]: Integer read GetFontSizes write SetFontSizes;
    property FontNames[i,j: Integer]: string read GetFontNames write SetFontNames;
    property CellControls[i,j: Integer]: TControl read GetCellControls write SetCellControls;
    property ReadOnly[i,j: Integer]: Boolean read GetReadOnly write SetReadOnly;
    property WordWraps[i,j: Integer]: Boolean read GetWordWraps write SetWordWraps;
    property StrippedCells[i,j: Integer]: string read GetStrippedCell;
    property SelectedCells[i,j: Integer]: Boolean read GetSelectedCells write SetSelectedCells;
    property SelectedCellsCount: Integer read GetSelectedCellsCount;
    property SelectedCell[i: Integer]: TGridCoord read GetSelectedCell;
    property SelectedRow[i: Integer]: Integer read GetSelectedRow;
    property SelectedRowCount: Integer read GetSelectedRowCount;
    property SelectedColCount: Integer read GetSelectedColCount;
    property CurrentCell:string read GetCurrentCell write SetCurrentCell;
    property CurrentEditor: TEditorType read GetCurrentEditor;
    property ArrowColor: TColor read GetArrowColor write SetArrowColor;
    property GroupColumn: Integer read FGroupColumn write SetGroupColumn;
    property QuoteEmptyCells: Boolean read FQuoteEmptyCells write FQuoteEmptyCells;
    property AlwaysQuotes: Boolean read FAlwaysQuotes write FAlwaysQuotes;
    property SelectionRectangleColor: TColor read FSelectionRectangleColor write FSelectionRectangleColor;
    property RealRow: Integer read GetRealRow;
    property RealCol: Integer read GetRealCol;
    property Row: Integer read GetRowEx write SetRowEx;
    property Col: Integer read GetColEx write SetColEx;
    property TopRow: integer read GetTopRowEx write SetTopRowEx;
    property SaveStartCol: Integer read GetSaveStartCol;
    property SaveStartRow: Integer read GetSaveStartRow;
    property SaveEndCol: Integer read GetSaveEndCol;
    property SaveEndRow: Integer read GetSaveEndRow;
    property SaveColCount: Integer read GetSaveColCount;
    property SaveRowCount: Integer read GetSaveRowCount;
    property Selection: TGridRect read GetSelectionEx write SetSelectionEx;
    property ShowNullDates: Boolean read FShowNullDates write FShowNullDates;
    property VersionNr: Integer read GetVersionNr;
    property VersionString: string read GetVersionString;
    property EditLink: TEditLink read FEditLink write FEditLink;
    property XYOffset: TPoint read FXYOffset write SetXYOffset;
    property XYOffsetTopLeftOnly: Boolean read FXYOffsetTopLeftOnly write FXYOffsetTopLeftOnly;
    property ImageCache: THTMLPictureCache read FImageCache;
    property MergedColumns: TIntList read FMergedColumns;
    property AlwaysValidate: Boolean read FAlwaysValidate write FAlwaysValidate;
    property SizeGrowOnly: Boolean read FSizeGrowOnly write FSizeGrowOnly;
    property MaxRowHeight: Integer read FMaxRowHeight write FMaxRowHeight;
    property MinRowHeight: Integer read FMinRowHeight write FMinRowHeight;
    property MaxColWidth: Integer read FMaxColWidth write FMaxColWidth;
    property MinColWidth: Integer read FMinColWidth write FMinColWidth;
    property TMSGradientFrom: TColor read FTMSGradFrom write SetTMSGradFrom;
    property TMSGradientTo: TColor read FTMSGradTo write SetTMSGradTo;
    property TMSGradientMirrorFrom: TColor read FTMSGradMirrorFrom write SetTMSGradMirrorFrom;
    property TMSGradientMirrorTo: TColor read FTMSGradMirrorTo write SetTMSGradMirrorTo;
    property TMSGradientHoverFrom: TColor read FTMSGradHoverFrom write FTMSGradHoverFrom;
    property TMSGradientHoverTo: TColor read FTMSGradHoverTo write FTMSGradHoverTo;
    property TMSGradientHoverMirrorFrom: TColor read FTMSGradHoverMirrorFrom write FTMSGradHoverMirrorFrom;
    property TMSGradientHoverMirrorTo: TColor read FTMSGradHoverMirrorTo write FTMSGradHoverMirrorTo;
    property TMSGradientHoverBorder: TColor read FTMSGradHoverBorder write FTMSGradHoverBorder;
    property TMSGradientDownFrom: TColor read FTMSGradDownFrom write FTMSGradDownFrom;
    property TMSGradientDownTo: TColor read FTMSGradDownTo write FTMSGradDownTo;
    property TMSGradientDownMirrorFrom: TColor read FTMSGradDownMirrorFrom write FTMSGradDownMirrorFrom;
    property TMSGradientDownMirrorTo: TColor read FTMSGradDownMirrorTo write FTMSGradDownMirrorTo;
    property TMSGradientDownBorder: TColor read FTMSGradDownBorder write FTMSGradDownBorder;
    property XMLEncoding: string read FXMLEncoding write FXMLEncoding;
    property VirtualEdit: boolean read FVirtualEdit write FVirtualEdit;
    property UseHTMLHints: Boolean read FUseHTMLHints write SetUseHTMLHints;
    property UseDisabledFont: Boolean read FUseDisabledFont write FUseDisabledFont;
    property OwnsObjects: boolean read FOwnsObjects write FOwnsObjects;
    property AutoNumberDirection: TSortDirection read FAutoNumberDirection write FAutoNumberDirection;
    property AutoNumberOffset: Integer read FAutoNumberOffset write FAutoNumberOffset;
    property AutoNumberStart: Integer read FAutoNumberStart write FAutoNumberStart;
    property OnGetEditorPropInt: TClickCellEvent read FOnGetEditorPropInt write FOnGetEditorPropInt;
    {$IFDEF TMSUNICODE}
    property UniLocale: LCID read FUniLocale write FUniLocale;
    property UniCmpFlgs: DWORD read FUniCmpFlgs write FUniCmpFlgs;
    {$ENDIF}
    {$IFDEF FREEWARE}
    property FreewareCode: Integer read FFreewareCode write FFreewareCode;
    {$ENDIF}
    property ValidCharSet: TCharSet read FValidCharSet write FValidCharSet;
    property FilterIncremental: Boolean read FFilterIncremental write FFilterIncremental default True;
    property ColumnOrder: TIntList read FColumnOrder;
    property VisibleCol: TBoolArray read FVisibleCol;

  published
    property OnAutoAdvance: TAutoAdvanceEvent read FOnAutoAdvance
      write FOnAutoAdvance;
    property OnCustomCellBkgDraw: TCustomCellDrawEvent read FOnCustomCellBkgDraw
      write FOnCustomCellBkgDraw;
    property OnCustomCellDraw: TCustomCellDrawEvent read FOnCustomCellDraw
      write FOnCustomCellDraw;
    property OnCustomCellSize: TCustomCellSizeEvent read FOnCustomCellSize
      write FOnCustomCellSize;
    property OnCustomFilter: TCustomFilterEvent read FOnCustomFilter
      write FOnCustomFilter;  
    property OnGetCellColor: TGridColorEvent read FOnGetCellColor write FOnGetCellColor;
    property OnGetCellCursor: TCellCursorEvent read FOnGetCellCursor write FOnGetCellCursor;
    property OnGetCellGradient: TGridGradientEvent read FOnGetCellGradient write FOnGetCellGradient;
    property OnGetCellPrintColor: TGridColorEvent read FOnGetCellPrintColor
      write FOnGetCellPrintColor;
    property OnGetCellPrintBorder: TGridBorderEvent read FOnGetCellPrintBorder
      write FOnGetCellPrintBorder;
    property OnGetCellBorder: TGridBorderEvent read FOnGetCellBorder
      write FOnGetCellBorder;
    property OnGetCellBorderProp: TGridBorderPropEvent read FOnGetCellBorderProp
      write FOnGetCellBorderProp;
    property OnGetAlignment: TGridAlignEvent read FOnGetAlignment
      write FOnGetAlignment;
    property OnGetWordWrap: TWordWrapEvent read FOnGetWordWrap
      write FOnGetWordWrap;
    property OnGetColumnFilter: TGetColumnFilterEvent read FOnGetColumnFilter
      write FOnGetColumnFilter;
    property OnFilterDone: TNotifyEvent read FOnFilterDone
      write FOnFilterDone;
    property OnFilterSelect: TFilterSelectEvent read FOnFilterSelect
      write FOnFilterSelect;
    property OnFilterCheck: TFilterCheckEvent read FOnFilterCheck
      write FOnFilterCheck;
    property OnFilterCheckClick: TFilterCheckClickEvent read FOnFilterCheckClick
      write FOnFilterCheckClick;
    property OnFilterShow: TFilterShowEvent read FOnFilterShow write FOnFilterShow;
    property OnFilterClose: TFilterCloseEvent read FOnFilterClose write FOnFilterClose;
    property OnGetFormat: TGridFormatEvent read FOnGetFormat
      write FOnGetFormat;
    property OnGetCheckTrue: TGetCheckEvent read FOnGetCheckTrue
      write FOnGetCheckTrue;
    property OnGetCheckFalse: TGetCheckEvent read FOnGetCheckFalse
      write FOnGetCheckFalse;
    property OnGridHint: TGridHintEvent read FOnGridHint
      write FOnGridHint;
    property OnGridWideHint: TGridWideHintEvent read FOnGridWideHint
      write FOnGridWideHint;
    property OnColumnCalc: TGroupCalcEvent read FOnColumnCalc write FOnColumnCalc;
    property OnGroupCalc: TGroupCalcEvent read FOnGroupCalc write FOnGroupCalc;
    {$IFDEF TMSGDIPLUS}
    property OnOfficeHint: TOfficeHintEvent read FOnOfficeHint write FOnOfficeHint;
    {$ENDIF}
    property OnRowUpdate:TRowChangedEvent read FOnRowChanged
      write FOnRowChanged;
    property OnRowChanging:TRowChangingEvent read FOnRowChanging
      write FOnRowChanging;
    property OnColChanging:TColChangingEvent read FOnColChanging
      write FOnColChanging;
    property OnCellChanging:TCellChangingEvent read FOnCellChanging
      write FOnCellChanging;
    property OnCellBalloon: TGridBalloonEvent read FOnCellBalloon
      write FOnCellBalloon;
    property OnCustomStrToDate: TCustomStrToDateEvent read FOnCustomStrToDate
      write FOnCustomStrToDate;
    property OnPrintPage:TGridPrintPageEvent read FOnPrintPage
      write FOnPrintPage;
    property OnPrintGetPageNum: TGridPrintPageNumEvent read FOnPrintGetPageNum
      write FOnPrintGetPageNum;
    property OnPrintPageDone: TGridPrintPageDoneEvent read FOnPrintPageDone
      write FOnPrintPageDone;
    property OnPrintDone: TNotifyEvent read FOnPrintDone
      write FOnPrintDone;
    property OnPrintStart:TGridPrintStartEvent read FOnPrintStart
      write FOnPrintStart;
    property OnPrintCancel: TGridPrintCancelEvent read FOnPrintCancel
      write FOnPrintCancel;
    property OnFitToPage:TDoFitToPageEvent read FDoFitToPage
      write FDoFitToPage;
    property OnPrintNewPage:TGridPrintNewPageEvent read FOnPrintNewPage
      write FOnPrintNewPage;
    property OnPrintSetColumnWidth:TGridPrintColumnWidthEvent read FOnPrintSetColumnWidth
      write FOnPrintSetColumnWidth;
    property OnPrintSetRowHeight:TGridPrintRowHeightEvent read FOnPrintSetRowHeight
      write FOnPrintSetRowHeight;
    property OnCanAddCol: TCanAddColEvent read FOnCanAddCol
      write FOnCanAddCol;
    property OnCanAddRow: TCanAddRowEvent read FOnCanAddRow
      write FOnCanAddRow;
    property OnAutoAddRow:TAutoAddRowEvent read FOnAutoAddRow
      write FOnAutoAddRow;
    property OnCanInsertRow: TCanInsertRowEvent read FOnCanInsertRow
      write FOnCanInsertRow;
    property OnAutoInsertRow:TAutoInsertRowEvent read FOnAutoInsertRow
      write FOnAutoInsertRow;
    property OnAutoInsertCol: TAutoInsertColEvent read FOnAutoInsertCol
      write FOnAutoInsertCol;
    property OnCanDeleteRow: TCanDeleteRowEvent read FOnCanDeleteRow
      write FOnCanDeleteRow;
    property OnAutoDeleteRow: TAutoDeleteRowEvent read FOnAutoDeleteRow
      write FOnAutoDeleteRow;
    property OnClickSort: TClickSortEvent read FOnClickSort
      write FOnClickSort;
    property OnCanSort: TCanSortEvent read FOnCanSort
      write FOnCanSort;
    property OnExpandNode: TNodeClickEvent read FOnExpandNode
      write FOnExpandNode;
    property OnContractNode: TNodeClickEvent read FOnContractNode
      write FOnContractNode;
    property OnDropDownHeaderButtonClick: TDropDownButtonClickEvent read FOnDropDownHeaderButtonClick
      write FOnDropDownHeaderButtonClick;
    property OnDropDownFooterButtonClick: TDropDownButtonClickEvent read FOnDropDownFooterButtonClick
      write FOnDropDownFooterButtonClick;
    property OnBeforeExpandNode: TNodeAllowEvent read FOnBeforeExpandNode
      write FOnBeforeExpandNode;
    property OnBeforeContractNode: TNodeAllowEvent read FOnBeforeContractNode
      write FOnBeforeContractNode;
    property OnCustomCompare: TCustomCompareEvent read FCustomCompare
      write FCustomCompare;
    property OnRawCompare: TRawCompareEvent read FRawCompare
      write FRawCompare;                                                                    
    property OnSearchEditChange: TSearchEditChangeEvent read FOnSearchEditChange
      write FOnSearchEditChange;
    property OnSearchFooterAction: TSearchFooterActionEvent read FOnSearchFooterAction
      write FOnSearchFooterAction;
    property OnSearchFooterClose: TNotifyEvent read FOnSearchFooterClose
      write FOnSearchFooterClose;
    property OnSearchFooterSearchEnd: TSearchFooterSearchEndEvent read FOnSearchFooterSearchEnd
      write FOnSearchFooterSearchEnd;
    property OnCanShowFixedDropDown: TCanShowFixedDropDownEvent read FOnCanShowFixedDropDown
      write FOnCanShowFixedDropDown;
    property OnFixedDropDownClick: TFixedDropDownEvent read FOnFixedDropDownClick
      write FOnFixedDropDownClick;
    property OnClickCell: TClickCellEvent read FOnClickCell
      write FOnClickCell;
    property OnRightClickCell: TClickCellEvent read FOnRightClickCell
      write FOnRightClickCell;
    property OnDblClickCell: TDblClickCellEvent read FOnDblClickCell
      write FOnDblClickCell;
    property OnCanClickCell: TCanClickCellEvent read FOnCanClickCell
      write FOnCanClickCell;
    property OnCanEditCell: TCanEditCellEvent read FOnCanEditCell
      write FOnCanEditCell;
    property OnFixedEdit: TFixedEditEvent read FOnFixedEdit write FOnFixedEdit;
    property OnIsFixedCell: TIsFixedCellEvent read FOnIsFixedCell
      write FOnIsFixedCell;
    property OnIsPasswordCell: TIsPasswordCellEvent read FOnIsPasswordCell
      write FOnIsPasswordCell;
    property OnAnchorClick: TAnchorClickEvent read FOnAnchorClick
      write FOnAnchorClick;
    property OnAnchorEnter: TAnchorEvent read FOnAnchorEnter
      write FOnAnchorEnter;
    property OnAnchorExit: TAnchorEvent read FOnAnchorExit
      write FOnAnchorExit;
    property OnAnchorHint:TAnchorHintEvent read FOnAnchorHint
      write FOnAnchorHint;
    property OnControlClick: TCellControlEvent read FOnControlClick
      write FOnControlClick;
    property OnControlEditDone: TCellControlEvent read FOnControlEditDone
      write FOnControlEditDone;
    property OnControlComboList: TCellComboControlEvent read FOnControlComboList
      write FOnControlComboList;
    property OnControlComboSelect: TCellComboControlSelectEvent read FOnControlComboSelect
      write FOnControlComboSelect;
    property OnClipboardPaste:TClipboardEvent read FOnClipboardPaste
      write FOnClipboardPaste;
    property OnClipboardPasteDone: TClipboardPasteDoneEvent read FOnClipboardPasteDone
      write FOnClipboardPasteDone;
    property OnClipboardCopy: TClipboardEvent read FOnClipboardCopy
      write FOnClipboardCopy;
    property OnClipboardCopyDone: TClipboardPasteDoneEvent read FOnClipboardCopyDone
      write FOnClipboardCopyDone;
    property OnClipboardCut: TClipboardEvent read FOnClipboardCut
      write FOnClipboardCut;
    property OnClipboardCutDone: TClipboardPasteDoneEvent read FOnClipboardCutDone
      write FOnClipboardCutDone;
    property OnClipboardAfterPasteCell: TAfterCellPasteEvent read FOnClipboardAfterPasteCell
      write FOnClipboardAfterPasteCell;
    property OnClipboardAfterPasteWideCell: TAfterCellPasteWideEvent read FOnClipboardAfterPasteWideCell
      write FOnClipboardAfterPasteWideCell;
    property OnClipboardBeforePasteCell: TBeforeCellPasteEvent read FOnClipboardBeforePasteCell
      write FOnClipboardBeforePasteCell;
    property OnClipboardBeforePasteWideCell: TBeforeCellPasteWideEvent read FOnClipboardBeforePasteWideCell
      write FOnClipboardBeforePasteWideCell;
    property OnCellValidate: TCellValidateEvent read FOnCellValidate
      write FOnCellValidate;
    property OnCellValidateWide: TCellValidateWideEvent read FOnCellValidateWide
      write FOnCellValidateWide;
    property OnCellsChanged: TCellsChangedEvent read FOnCellsChanged
      write FOnCellsChanged;
    property OnFileProgress: TGridProgressEvent read FOnFileProgress
      write FOnFileProgress;
    property OnFilterProgress: TGridProgressEvent read FOnFilterProgress
      write FOnFilterProgress;
    property OnFilterEditUpdate: TFilterEditUpdateEvent read FOnFilterEditUpdate write FOnFilterEditUpdate;
    property OnHasComboBox: THasComboEvent read FOnHasComboBox write FOnHasComboBox;
    property OnHasEditBtn: THasEditBtnEvent read FOnHasEditBtn write FOnHasEditBtn;
    property OnHasFilterEdit: THasFilterEditEvent read FOnHasFilterEdit write FOnHasFilterEdit;
    property OnHasSpinEdit: THasSpinEditEvent read FOnHasSpinEdit write FOnHasSpinEdit;
    property OnGetEditorType:TGetEditorTypeEvent read FOnGetEditorType write FOnGetEditorType;
    property OnGetEditorProp:TGetEditorPropEvent read FOnGetEditorProp write FOnGetEditorProp;
    property OnGetFloatFormat: TFloatFormatEvent read FOnGetFloatFormat write FOnGetFloatFormat;
    property OnEllipsClick: TEllipsClickEvent read FOnEllipsClick write FOnEllipsClick;
    property OnIntelliZoom: TNotifyEvent read FOnIntelliZoom write FOnIntelliZoom;
    {$IFDEF TMSUNICODE}
    property OnWideEllipsClick: TWideEllipsClickEvent read FOnWideEllipsClick write FOnWideEllipsClick;
    {$ENDIF}
    property OnButtonClick:TButtonClickEvent read FOnButtonClick write FOnButtonClick;
    property OnCheckBoxCanToggle: TCheckBoxCanToggleEvent read FOnCheckBoxCanToggle write FOnCheckBoxCanToggle;
    property OnCheckBoxChange: TCheckBoxClickEvent read FOnCheckBoxChange write FOnCheckBoxChange;
    property OnCheckBoxClick:TCheckBoxClickEvent read FOnCheckBoxClick write FOnCheckBoxClick;
    property OnCheckBoxMouseUp:TCheckBoxClickEvent read FOnCheckBoxMouseUp write FOnCheckBoxMouseUp;
    property OnColorSelected: TColorSelectedEvent read FOnColorSelected write FOnColorSelected;
    property OnColorSelect: TColorSelectEvent read FOnColorSelect write FOnColorSelect;
    property OnExpandClick: TExpandClickEvent read FOnExpandClick write FOnExpandClick;
    property OnImageSelected: TImageSelectedEvent read FOnImageSelected write FOnImageSelected;
    property OnImageSelect: TImageSelectEvent read FOnImageSelect write FOnImageSelect;
    property OnRadioClick:TRadioClickEvent read FOnRadioClick write FOnRadioClick;
    property OnRadioMouseUp:TRadioClickEvent read FOnRadioMouseUp write FOnRadioMouseUp;
    property OnRadioButtonClick: TRadioButtonClickEvent read FOnRadioButtonClick write FOnRadioButtonClick;
    property OnDatePickerCloseUp: TClickCellEvent read FOnDatePickerCloseUp write FOnDatePickerCloseUp;
    property OnDatePickerDropDown: TClickCellEvent read FOnDatePickerDropDown write FOnDatePickerDropDown;
    property OnComboChange:TComboChangeEvent read FOnComboChange write FOnComboChange;
    property OnComboCloseUp: TClickCellEvent read FOnComboCloseUp write FOnComboCloseUp;
    property OnComboDropDown: TClickCellEvent read FOnComboDropDown write FOnComboDropDown;
    property OnComboObjectChange:TComboObjectChangeEvent read FOnComboObjectChange write FOnComboObjectChange;
    property OnSpinClick:TSpinClickEvent read FOnSpinClick write FOnSpinClick;
    property OnFloatSpinClick:TFloatSpinClickEvent read FOnFloatSpinClick write FOnFloatSpinClick;
    property OnTimeSpinClick:TDateTimeSpinClickEvent read FOnTimeSpinClick write FOnTimeSpinClick;
    property OnDateSpinClick:TDateTimeSpinClickEvent read FOnDateSpinClick write FOnDateSpinClick;
    property OnRichEditSelectionChange: TNotifyEvent read FOnRichEditSelectionChange write FOnRichEditSelectionChange;
    property OnDragScroll: TDragScrollEvent read FOnDragScroll write FOnDragScroll;
    property OnEditingDone: TNotifyEvent read FOnEditingDone write FOnEditingDone;
    property OnEditCellDone: TEditCellDoneEvent read FOnEditCellDone write FOnEditCellDone;
    property OnEditChange: TEditChangeEvent read FOnEditChange write FOnEditChange;
    property OnDateTimeChange: TDateTimeChangeEvent read FOnDateTimeChange write FOnDateTimeChange;
    property OnFooterPaint: TFooterPaintEvent read FOnPaintFooter write FOnPaintFooter;
    property OnFooterCalc: TCalcFooterEvent read FOnCalcFooter write FOnCalcFooter;
    property OnHoverButtonClick: THoverButtonClickEvent read FOnHoverButtonClick write FOnHoverButtonClick;
    property OnResize: TNotifyEvent read FOnGridResize write FOnGridResize;
    property OnRowDisjunctSelect: TRowDisjunctSelectEvent read FOnRowDisjunctSelect write FOnRowDisjunctSelect;
    property OnRowDisjunctSelected: TAutoInsertRowEvent read FOnRowDisjunctSelected write FOnRowDisjunctSelected;
    property OnSelectionChanged: TSelectionChanged read FSelectionChanged write FSelectionChanged;
    property OnUnitChanged: TUnitChangedEvent read FOnUnitChanged write FOnUnitChanged;
    property OnOleDrop: TOleDragDropEvent read FOnOleDrop write FOnOleDrop;
    property OnOleDropped: TOleDroppedEvent read FOnOleDropped write FOnOleDropped;
    property OnOleDrag: TOleDragDropEvent read FOnOleDrag write FOnOleDrag;
    property OnOleDragOver: TOleDragOverEvent read FOnOleDragOver write FOnOleDragOver;
    property OnOleDragStart: TOleDragStartEvent read FOnOleDragStart write FOnOleDragStart;
    property OnOleDragStop: TOleDragStopEvent read FOnOleDragStop write FOnOleDragStop;
    property OnOleDropCol: TOleDropColEvent read FOnOleDropCol write FOnOleDropCol;
    property OnOleDropFile: TOleDropFileEvent read FOnOleDropFile write FOnOleDropFile;
    property OnOleDropURL: TOleDropURLEvent read FOnOleDropURL write FOnOleDropURL;
    property OnPainted: TNotifyEvent read FOnPainted write FOnPainted;
    property OnRatingChange: TRatingChangeEvent read FOnRatingChange write FOnRatingChange;
    property DragDropSettings: TDragDropSettings read FDragDropSettings write FDragDropSettings;
    {$IFDEF TMSGDIPLUS}
    property OfficeHint: TAdvHintInfo read FOfficeHint write SetOfficeHint;
    {$ENDIF}
    property HighlightColor: TColor read FHighlightColor write SetHighlightColor default clHighlight;
    property HighlightTextColor: TColor read FHighlightTextColor write SetHighlightTextColor default clHighlightText;
    property HintColor: TColor read FHintColor write FHintColor default clInfoBk;
    property HintShowCells: Boolean read FHintShowCells write FHintShowCells default False;
    property HintShowLargeText: Boolean read FHintShowLargeText write FHintShowLargeText default False;
    property HintShowLargeTextPos:THintShowLargeTextPos read FHintShowLargeTextPos write FHintShowLargeTextPos default hpCell;
    property HintShowSizing: Boolean read FHintShowSizing write FHintShowSizing default False;
    property HTMLHint: Boolean read FHTMLHint write FHTMLHint default False;
    property HTMLKeepLineBreak: Boolean read FHTMLKeepLineBreak write SetHTMLKeepLineBreak default True;
    property OnScrollHint:TScrollHintEvent read FOnScrollHint write FOnScrollHint;
    property OnColumnSize:TColumnSizeEvent read FOnColumnSize write FOnColumnSize;
    property OnColumnSizing: TColumnSizingEvent read FOnColumnSizing write FOnColumnSizing;
    property OnColumnMove:TColumnSizeEvent read FOnColumnMove write FOnColumnMove;
    property OnColumnMoving:TColumnSizeEvent read FOnColumnMoving write FOnColumnMoving;    
    property OnRowSize:TRowSizeEvent read FOnRowSize write FOnRowSize;
    property OnRowSizing: TRowSizingEvent read FOnRowSizing write FOnRowSizing;
    property OnRowMove:TRowSizeEvent read FOnRowMove write FOnRowMove;
    property OnRowMoving:TRowSizeEvent read FOnRowMoving write FOnRowMoving;
    property OnEndColumnSize:TEndColumnSizeEvent read FOnEndColumnSize write FOnEndColumnSize;
    property OnUpdateColumnSize: TUpdateColumnSizeEvent read FOnUpdateColumnSize write FOnUpdateColumnSize;
    property OnEndRowSize: TEndRowSizeEvent read FOnEndRowSize write FOnEndRowSize;
    property OnScrollCell: TScrollCellEvent read FOnScrollCell write FOnScrollCell;
    property OnSelectionResize: TSelectionResizeEvent read FSelectionResizeEvent write FSelectionResizeEvent;
    property OnSelectionResized: TSelectionResizeEvent read FSelectionResizedEvent write FSelectionResizedEvent;
    property OnCreatedFloatingFooter: TNotifyEvent read FOnCreatedFloatingFooter write FOnCreatedFloatingFooter;
    property OnCreatedSearchFooter: TNotifyEvent read FOnCreatedSearchFooter write FOnCreatedSearchFooter;
    {$IFDEF TMSUNICODE}
    property OnSetEditWideText: TSetEditWideTextEvent read FSetEditWideText write FSetEditWideText;
    property OnGetEditWideText: TGetEditWideTextEvent read FGetEditWideText write FGetEditWideText;
    {$ENDIF}
    property OnSaveCell: TCellSaveLoadEvent read FOnSaveCell write FOnSaveCell;
    property OnLoadCell: TCellSaveLoadEvent read FOnLoadCell write FOnLOadCell;

    property OemConvert: Boolean read FOemConvert write FOemConvert default False;

    property AnchorHint: Boolean read FAnchorHint write FAnchorHint default False;
    property ActiveCellShow: Boolean read FActiveCellShow write SetActiveCellShow default False;
    property ActiveCellFont: TFont read FActiveCellFont write SetActiveCellFont;
    property ActiveCellColor: TColor read FActiveCellColor write SetActiveCellColor default clGray;
    property ActiveCellColorTo: TColor read FActiveCellColorTo write SetActiveCellColorTo default clNone;
    property AutoColor: TAutoColor read FAutoColor write SetAutoColor;
    property AutoHideSelection: Boolean read FAutoHideSelection write FAutoHideSelection default false;
    property AutoNumAlign: Boolean read FAutoNumAlign write FAutoNumAlign default False;
    property AutoSize: Boolean read FAutoSize write SetAutoSizeP default False;
    property AutoThemeAdapt: Boolean read FAutoThemeAdapt write SetAutoThemeAdapt default False;
    property AutoFilterUpdate: Boolean read FAutoFilterUpdate write FAutoFilterUpdate default True;
    property Balloon: TBalloonSettings read FBalloonSettings write SetBalloonSettings;
    property Bands: TBands read FBands write FBands;
    property BackGround: TBackground read FBackground write SetBackground;
    property BorderColor: TColor read FBorderColor write SetBorderColor default $B99D7F;
    property CellNode: TCellNode read fCellNode write fCellNode;
    property CellChecker: TAdvStringGridCheck read FCellChecker write SetCellChecker;
    property ColCount: Integer read GetColCountEx write SetColCountEx default 5;
    property ColumnHeaders: TStringList read FColumnHeaders write SetColumnHeaders;
    property ColumnSize: TColumnSize read FColumnSize write FColumnSize;
    property ControlLook: TControlLook read FControlLook write FControlLook;
    property Cursor: TCursor read GetCursorEx write SetCursorEx;
    property DefaultRowHeight: Integer read GetDefRowHeightEx write SetDefRowHeightEx default 22;
    property DefaultAlignment: TAlignment read FDefaultAlignment write SetDefaultAlignment default taLeftJustify;
    property DefaultEditor: TEditorType read FDefaultEditor write FDefaultEditor default edNormal;
    property DisabledFontColor: TColor read FDisabledFontColor write FDisabledFontColor default clSilver;
    property DragScrollOptions: TDragScrollOptions read FDragScrollOptions write SetDragScrollOptions;
    property EditWithTags: Boolean read FEditWithTags write FEditWithTags default False;
    property EnableBlink: Boolean read FEnableBlink write FEnableBlink default False;
    property EnableHTML: Boolean read FEnableHTML write FEnableHTML default True;
    property EnableWheel: Boolean read FEnableWheel write FEnableWheel default True;
    property EnhTextSize: Boolean read FEnhTextSize write FEnhTextSize default False;
    property EnhRowColMove: Boolean read FEnhRowColMove write FEnhRowColMove default True;
    property ExcelStyleDecimalSeparator: Boolean read FExcelStyleDecimalSeparator write FExcelStyleDecimalSeparator default False;
    property Filter: TFilter read FFilter write FFilter;
    property FilterActive: Boolean read FFilterActive write SetFilterActive default False;
    property FilterDropDown: TFilterDropDown read FFilterDropDown write FFilterDropDown;
    property FilterDropDownAuto: Boolean read FFilterDropDownAuto write SetFilterDropDownAuto default False;
    property FilterDropDownMultiCol: Boolean read FFilterDropDownMultiCol write FFilterDropDownMultiCol default True;
    property FilterDropDownClear: string read FFilterDropDownClear write FFilterDropDownClear;
    property FilterDropDownCheck: Boolean read FFilterDropDownCheck write FFilterDropDownCheck default False;
    property FilterDropDownCheckUnCheckAll: string read FFilterDropDownCheckUnCheckAll write FFilterDropDownCheckUnCheckAll;
    property FilterDropDownColumns: TFilterDropDownColumns read FFilterDropDownColumns write FFilterDropDownColumns default fdNormal;
    property FilterDropDownRow: integer read FFilterRow write SetFilterRow default 0;
    property FilterEdit: TFilterEdit read FFilterEdit write SetFilterEdit;
    property FilterNormalCellsOnly: Boolean read FFilterNormalCellsOnly write FFilterNormalCellsOnly default True;
    property FixedCols: Integer read GetFixedColsEx write SetFixedColsEx default 1;
    property FixedAsButtons: Boolean read FFixedAsButtons write FFixedAsButtons default False;
    property FixedFooters: Integer read FFixedFooters write SetFixedFooters default 0;
    property FixedRightCols: Integer read FFixedRightCols write SetFixedRightCols default 0;
    property FixedColWidth: Integer read GetFixedColWidth write SetFixedColWidth default 64;
    property FixedDropDownMenu: TPopupMenu read FFixedDropDownMenu write FFixedDropDownMenu;
    property FixedRowHeight: Integer read GetFixedRowHeight write SetFixedRowHeight default 21;
    property FixedRowAlways: Boolean read FFixedRowAlways write FFixedRowAlways default False;
    property FixedRows: Integer read GetFixedRowsEx write SetFixedRowsEx default 1;
    property FixedColAlways: Boolean read FFixedColAlways write FFixedColAlways default False;
    property FixedFont: TFont read FFixedFont write SetFixedFont;
    property Flat: Boolean read FFlat write SetFlat default False;
    property FloatFormat:string read FFloatFormat write FFloatFormat;
    property FloatingFooter: TFloatingFooter read FFloatingFooter write FFloatingFooter;
    property FocusHelper: TFocusHelper read FFocusHelper write SetFocusHelper;
    property FormatType: TFormatType read FFormatType write SetFormatType default ftVCL;
    property GridImages: TCustomImageList read FGridImages write SetImages;
    property Grouping: TGrouping read FGrouping write FGrouping;
    property HideFocusRect: Boolean read FHideFocusRect write FHideFocusRect default False;
    property HoverButtons: THoverButtons read FHoverButtons write SetHoverButtons;
    property Hovering: Boolean read FHovering write SetHovering default False;
    property HoverFixedCells: THoverFixedCells read FHoverFixedCells write FHoverFixedCells default hfNone;
    property HTMLSettings: THTMLSettings read FHTMLSettings write FHTMLSettings;
    property IntegralHeight: Boolean read FIntegralHeight write SetIntegralHeight default False;
    property IntelliPan: TIntelliPan read FIntelliPan write FIntelliPan default ipVertical;
    property IntelliZoom: Boolean read FIntelliZoom write FIntelliZoom default True;
    property InvalidEntryTitle: string read FInvalidEntryTitle write FInvalidEntryTitle;
    property InvalidEntryIcon: TInvalidEntryIcon read FInvalidEntryIcon write FInvalidEntryIcon default ieWarning;
    property InvalidEntryText: string read FInvalidEntryText write FInvalidEntryText;
    property Look: TGridLook read FLook write SetLook default glXP;
    property LookupItems: TStringList read FLookupItems write SetLookupItems;
    property Lookup: Boolean read FLookup write FLookup default False;
    property LookupCaseSensitive: Boolean read FLookupCaseSensitive write FLookupCaseSensitive default False;
    property LookupHistory: Boolean read FLookupHistory write FLookupHistory default False;
    property MaxEditLength: Integer read FMaxEditLength write SetMaxEditLength default 0;
    property MaxComboLength: Integer read FMaxComboLength write FMaxComboLength default 0;
    property MouseActions: TMouseActions read FMouseActions write FMouseActions;
    property Multilinecells: Boolean read FMultilinecells write FMultilinecells default False;
    property Navigation: TNavigation read FNavigation write FNavigation;
    property PictureContainer: TPictureContainer read FContainer write FContainer;
    property PopupToolBar: TAdvGridPopup read FToolBarPopup write FToolBarPopup;
    property PopupToolBarMode: TPopupToolBarMode read FPopupToolBarMode write FPopupToolBarMode default tbActiveCell;
    property PrintSettings: TPrintSettings read FPrintSettings write FPrintSettings;
    property ProgressAppearance: TGridProgressAppearance read FProgressAppearance write SetProgressAppearance;
    property RowCount: Integer read GetRowCountEx write SetRowCountEx default 10;
    property RowHeaders: TStringList read FRowHeaders write SetRowHeaders;
    property RowIndicator:TBitmap read GetRowIndicator write SetRowIndicator;
    property ScrollBarAlways: TScrollBarAlways read FScrollBarAlways write SetScrollBarAlways default saNone;
    property ScrollBars: TScrollStyle read GetScrollBarsEx write SetScrollBarsEx;
    property ScrollColor: TColor read FScrollColor write SetScrollColor default clNone;
    property ScrollProportional: Boolean read FScrollProportional write SetScrollProportional default False;
    property ScrollSynch: Boolean read FScrollSynch write FScrollSynch default False;
    property ScrollType:TScrollType read FScrollType write SetScrollType default ssNormal;
    property ScrollWidth: Integer read FScrollWidth write SetScrollWidth default 17;
    property ScrollHints:TScrollHintType read FScrollHints write FScrollHints default shNone;
    property SearchFooter: TSearchFooter read FSearchFooter write FSearchFooter;
    property SelectionColor: TColor read FSelectionColor write SetSelectionColor default $EACAB6;
    property SelectionColorTo: TColor read FSelectionColorTo write SetSelectionColorTo  default clNone;
    property SelectionColorMixer: boolean read FSelectionColorMixer write SetSelectionColorMixer default false;
    property SelectionColorMixerFactor: integer read FSelectionColorMixerFactor write SetSelectionColorMixerFactor default 50;
    property SelectionMirrorColor: TColor read FSelectionMirrorColor write SetSelectionMirrorColor default clNone;
    property SelectionMirrorColorTo: TColor read FSelectionMirrorColorTo write SetSelectionMirrorColorTo  default clNone;
    property SelectionRectangle: Boolean read FSelectionRectangle write SetSelectionRectangle default False;
    property SelectionResizer: Boolean read FSelectionResizer write SetSelectionResizer default False;
    property SelectionRTFKeep: Boolean read FSelectionRTFKeep write FSelectionRTFKeep default False;
    property SelectionTextColor: TColor read FSelectionTextColor write SetSelectionTextColor default clBlack;
    property ShowSelection: Boolean read FShowSelection write SetShowSelection default True;
    property ShowModified: TShowModified read FShowModified write SetShowModified;
    property ShowDesignHelper: Boolean read FShowDesignHelper write SetShowDesignHelper default true;
    property SizeWhileTyping: TSizeWhileTyping read FSizeWhileTyping write FSizeWhileTyping;
    property SizeWithForm: Boolean read FSizeWithForm write SetSizeWithForm default False;
    property SortSettings: TSortSettings read FSortSettings write SetSortSettings;
    property SyncGrid: TSyncGrid read FSyncGrid write SetSyncGrid;
    property URLColor: TColor read FURLColor write SetURLColor default clBlue;
    property URLShow: Boolean read FURLShow write SetURLShow default False;
    property URLShowInText: Boolean read FURLShowInText write SetURLShowInText default False;
    property URLUnderlineOnHover: Boolean read FURLUnderlineOnHover write FURLUnderlineOnHover default False;
    property URLFull: Boolean read FURLFull write SetURLFull default False;
    property URLEdit: Boolean read FURLEdit write FURLEdit default False;
    property UseInternalHintClass: Boolean read FUseInternalHintClass write FUseInternalHintClass default True;
    property ValidChars: string read FValidChars write FValidChars;
    property VAlignment: TVAlignment read FVAlignment write SetVAlignment default vtaTop;
    property Version: string read GetVersion write SetVersion;
    property WordWrap: Boolean read GetWordWrapEx write SetWordWrapEx default true;
  end;

  TGridSLIO = class(TComponent)
  private
    FStrings: TStringList;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Strings: TStringList read FStrings write FStrings;
  end;

  TGridFilePicIO = class(TComponent)
  private
    FPicture: TFilePicture;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Picture: TFilePicture read FPicture write FPicture;
  end;

  TGridPicIO = class(TComponent)
  private
    FPicture: TPicture;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Picture: TPicture read FPicture write FPicture;
  end;

  TGridIconIO = class(TComponent)
  private
    FIcon: TIcon;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Icon: TIcon read FIcon write FIcon;
  end;

  TGridBMPIO = class(TComponent)
  private
    FBitmap: TBitmap;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Bitmap: TBitmap read FBitmap write FBitmap;
  end;

  TGridPropIO = class(TComponent)
  private
    FColCount: Integer;
    FRowCount: Integer;
    FColWidths: string;
    FRowHeights: string;
    FFullGrid: Boolean;
    FID: Integer;
  published
    property ColCount: Integer read FColCount write FColCount;
    property RowCount: Integer read FRowCount write FRowCount;
    property ColWidths: string read FColWidths write FColWidths;
    property RowHeights: string read FRowHeights write FRowHeights;
    property FullGrid: Boolean read FFullGrid write FFullGrid;
    property ID: Integer read FID write FID;
  end;

  TGridGraphicIO = class(TComponent)
  private
    FCellGraphic: TBaseCellGraphic;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property CellGraphic: TBaseCellGraphic read FCellGraphic write FCellGraphic;
  end;

  TGridCellPropIO = class(TComponent)
  private
    FCellProperties: TCellProperties;
    FHasGraphic: Boolean;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property CellProperties: TCellProperties read FCellProperties write FCellProperties;
    property HasGraphic: Boolean read FHasGraphic write FHasGraphic;
  end;

  TGridCellIO = class(TComponent)
  private
    FRow: word;
    FCol: word;
    FCell: string;
    FHasProp: Boolean;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Col: Word read FCol write FCol;
    property Row: Word read FRow write FRow;
    property Cell: string read FCell write FCell;
    property HasProp: Boolean read FHasProp write FHasProp;
  end;



  function GridCoord(x,y: integer): TGridCoord;

implementation

{$IFDEF DELPHIXE2_LVL}
uses
  VCL.Themes;
{$ENDIF}

const
  CELLCONTROLOFFSET = 0;

  s_QuickConfig = 'Quick config';
  s_Edit = 'Allow edit';
  s_Look = 'Set look';
  s_ColNr = 'Column numbers';

  ComCtrl = 'comctl32.dll';

  ComCtrlOk: Boolean = True;

  {$IFNDEF DELPHI7_LVL}
  {$EXTERNALSYM CSTR_LESS_THAN}
  CSTR_LESS_THAN           = 1;             { string 1 less than string 2 }
  {$EXTERNALSYM CSTR_EQUAL}
  CSTR_EQUAL               = 2;             { string 1 equal to string 2 }
  {$EXTERNALSYM CSTR_GREATER_THAN}
  CSTR_GREATER_THAN        = 3;             { string 1 greater than string 2 }
  {$ENDIF}

  TTS_BALLOON  = $40;
  {$EXTERNALSYM TTS_BALLOON}

  {$IFDEF DELPHI_UNICODE}
  TTM_SETTITLE = (WM_USER + 33);
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
  TTM_SETTITLE = (WM_USER + 32);
  {$ENDIF}

  {$EXTERNALSYM TTM_SETTITLE}


  //------------------------------------------------
  //constant definitions for flat/encarta scrollbars
  //------------------------------------------------
  WSB_PROP_CYVSCROLL  = $0000001;
  WSB_PROP_CXHSCROLL  = $0000002;
  WSB_PROP_CYHSCROLL  = $0000004;
  WSB_PROP_CXVSCROLL  = $0000008;
  WSB_PROP_CXHTHUMB   = $0000010;
  WSB_PROP_CYVTHUMB   = $0000020;
  WSB_PROP_VBKGColOR  = $0000040;
  WSB_PROP_HBKGColOR  = $0000080;
  WSB_PROP_VSTYLE     = $0000100;
  WSB_PROP_HSTYLE     = $0000200;
  WSB_PROP_WINSTYLE   = $0000400;
  WSB_PROP_PALETTE    = $0000800;
  WSB_PROP_MASK       = $0000FFF;

  FSB_FLAT_MODE       =    2;
  FSB_ENCARTA_MODE    =    1;
  FSB_REGULAR_MODE    =    0;

  //-------------------------------------------------
  //constant definitions for OLE automation with Word
  //-------------------------------------------------
  wdAlignParagraphLeft = 0;
  wdAlignParagraphCenter = 1;
  wdAlignParagraphRight = 2;
  wdAlignParagraphJustify = 3;

  wdGotoBookmark = -1;
  wdGotoLast = -1;
  wdGotoLine = 3;

  //--------------------------------------------------
  //constant definitions for OLE automation with Excel
  //--------------------------------------------------
  xlAddIn = 18;
  xlCSV = 6;
  xlCSVMac = 22;
  xlCSVMSDOS = 24;
  xlCSVWindows = 23;
  xlDBF2 = 7;
  xlDBF3 = 8;
  xlDBF4 = 11;
  xlDIF = 9;
  xlExcel2 = 16;
  xlExcel2FarEast = 27;
  xlExcel3 = 29;
  xlExcel4 = 33;
  xlExcel5 = 39;
  xlExcel7 = 39;
  xlExcel9795 = 43;
  xlExcel4Workbook = 35;
  xlIntlAddIn = 26;
  xlIntlMacro = 25;
  xlWorkbookNormal = -4143;
  xlSYLK = 2;
  xlTemplate = 17;
  xlCurrentPlatformText = -4158;
  xlTextMac = 19;
  xlTextMSDOS = 21;
  xlTextPrinter = 36;
  xlTextWindows = 20;
  xlWJ2WD1 = 14;
  xlWK1 = 5;
  xlWK1ALL = 31;
  xlWK1FMT = 30;
  xlWK3 = 15;
  xlWK4 = 38;
  xlWK3FM3 = 32;
  xlWKS = 4;
  xlWorks2FarEast = 28;
  xlWQ1 = 34;
  xlWJ3 = 40;
  xlWJ3FJ3 = 41;

  xlA1 = 1;
  xlR1C1 = -4150;

  //---------------------------------------------
  //constant definitions for Intellimouse support
  //---------------------------------------------
  MSH_MOUSEWHEEL = 'MSWHEEL_ROLLMSG';
  MOUSEZ_CLASSNAME = 'MouseZ';               // wheel window class
  MOUSEZ_TITLE     = 'Magellan MSWHEEL';     // wheel window title
  MSH_WHEELSUPPORT = 'MSH_WHEELSUPPORT_MSG'; // name of msg to query for wheel support
  MSH_SCROLL_LINES = 'MSH_SCROLL_LINES_MSG';
  MSH_WHEELMODULE_CLASS = MOUSEZ_CLASSNAME;
  MSH_WHEELMODULE_TITLE = MOUSEZ_TITLE;

  //--------------------------------------
  //constant definitions for extra cursors
  //--------------------------------------
  crURLcursor: Integer = 8009;
  crHorzArr  = 8010;
  crVertArr  = 8011;
  crAsgCross = 8012;
  crAsgSizer = 8013;
  crAsgCell  = 8014;

  Numeric_Characters = [$30..$39,$8,$9,$D,ord('-'),ord(#27)];
  Positive_Numeric_Characters = [$30..$39,$8,$9,$D,ord(#27)];
  Float_Characters = [$30..$39,$8,$9,$D,ord('-'),ord(','),ord('.'),ord(#27)];

  CSVSeparators: array[1..10] of char = (',',';','#',#9,'|','@','*','-','+','&');

{$IFNDEF DELPHI2007_LVL}
const
  {$EXTERNALSYM EM_SHOWBALLOONTIP}
  ECM_FIRST               = $1500;      { Edit control messages }

  EM_SHOWBALLOONTIP          = ECM_FIRST + 3;   // Show a balloon tip associated to the edit control

type
  { $EXTERNALSYM _tagEDITBALLOONTIP}
  _tagEDITBALLOONTIP = record
    cbStruct: DWORD;
    pszTitle: LPCWSTR;
    pszText: LPCWSTR;
    ttiIcon: Integer; // From TTI_*
  end;
  PEditBalloonTip = ^TEditBalloonTip;
  TEditBalloonTip = _tagEDITBALLOONTIP;
{$ENDIF}

{$IFDEF DELPHIXE2_LVL}
type
  TCharFormat = TCharFormatW;
{$ENDIF}

type
  TAdvStringGridEx = class(TAdvStringGrid);

var
  WideHintFontName: string;

{$I DELPHIXE.INC}

var
  MsgHook: HHook;
  FocusGrid: TAdvStringGrid;

function MsgHookProc(Code: Integer; CurrentProcess: Cardinal; HookStruct: PCWPStruct): integer; stdcall;
begin
  case HookStruct.Message of
  WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED:
     begin
       if Assigned(FocusGrid) then
         FocusGrid.MoveFocusHelper;
     end;
  end;

  Result := CallNextHookEx(MsgHook, Code, CurrentProcess, LParam(HookStruct))
end;

function GridCoord(x,y: integer): TGridCoord;
begin
  Result.X := x;
  Result.Y := y;
end;

function LongMulDiv(Mult1, Mult2, Div1: Integer): Integer; stdcall;
  external 'kernel32.dll' name 'MulDiv';

{$IFDEF FREEWARE}
procedure GetFreeStr(cl:string;var s:string);
var
  i: Integer;
  t: string;
begin
  t := 'eµ·®³¹ª©e¼®¹­e©ª²´e»ª·¸®´³e´«e';
  for i := 1 to Length(t) do t[i] := Chr(Ord(t[i])-69);
  s := s + ' ' + t + ' ' + cl;
end;
{$ENDIF}

procedure SetTranspWindow(Hwnd:THandle);
var
  es: Integer;
begin
  es := GetWindowLong(Hwnd,GWL_EXSTYLE);
  es := es OR WS_EX_TRANSPARENT;
  SetWindowLong(Hwnd,GWL_EXSTYLE,es);
end;

function GetFileVersion(FileName:string): Integer;
var
  FileHandle:dword;
  l: Integer;
  pvs: PVSFixedFileInfo;
  lptr: uint;
  querybuf: array[0..255] of char;
  buf: PChar;
begin
  Result := -1;

  StrPCopy(querybuf,FileName);
  l := GetFileVersionInfoSize(querybuf,FileHandle);
  if (l>0) then
  begin
    GetMem(buf,l);
    GetFileVersionInfo(querybuf,FileHandle,l,buf);
    if VerQueryValue(buf,'\',Pointer(pvs),lptr) then
    begin
      if (pvs^.dwSignature=$FEEF04BD) then
      begin
        Result := pvs^.dwFileVersionMS;
      end;
    end;
    FreeMem(buf);
  end;
end;

procedure TColumnSize.SetStretch(Value: Boolean);
begin
  FStretch := Value;
  if Assigned((Owner as TAdvStringGrid).Parent) then
    (Owner as TAdvStringGrid).StretchColumn(FStretchColumn);
end;

procedure TColumnSize.SetStretchAll(const Value: Boolean);
begin
  if (FStretchAll <> Value) then
  begin
    if Value then
      FStretchColumn := -1;

    FStretchAll := Value;
    (Owner as TAdvStringGrid).StretchColumn(-1);
  end;
end;

constructor TGridCheckBox.Create(AOwner:tComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridCheckBox.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridCheckBox.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridCheckBox.WMLButtonDown(var Msg:TWMLButtonDown);
begin
  Toggle;
  inherited;
end;

procedure TGridCheckBox.Keydown(var Key: Word; Shift: TShiftState);
begin
  if Key = VK_SPACE then
    Toggle;

  if (Key in [VK_DOWN,VK_UP,VK_LEFT,VK_RIGHT,VK_PRIOR,VK_NEXT,VK_END,VK_UP,VK_RETURN]) then
  begin
    if Key = VK_ESCAPE then
      self.Text := FGrid.CurrentCell;

    FGrid.HideInplaceEdit;
    FGrid.SetFocus;
    if Key = VK_RETURN then
      FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);

    if Key in [VK_DOWN,VK_UP] then
      FGrid.KeyDown(Key,shift);
  end
  else
    inherited;
end;

constructor TGridSpin.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
  MaxValue := 100;
  MinValue := 0;
  Increment := 1;
end;

procedure TGridSpin.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridSpin.DoClick(UpDown: Boolean);
begin
  case SpinType of
  sptNormal:if Assigned(FGrid.OnSpinClick) then
            FGrid.OnSpinClick(FGrid,FGrid.Col,FGrid.Row,Self.Value,UpDown);
  sptFloat:if Assigned(FGrid.OnFloatSpinClick) then
           FGrid.OnFloatSpinClick(FGrid,FGrid.Col,FGrid.Row,Self.FloatValue,UpDown);
  sptTime:if Assigned(FGrid.OnTimeSpinClick) then
          FGrid.OnTimeSpinClick(FGrid,FGrid.Col,FGrid.Row,Self.TimeValue,UpDown);
  sptDate:if Assigned(FGrid.OnDateSpinClick) then
          FGrid.OnDateSpinClick(FGrid,FGrid.Col,FGrid.Row,Self.DateValue,UpDown);
  end;
end;

procedure TGridSpin.UpClick(Sender:TObject);
begin
  inherited;
  DoClick(True);
end;

procedure TGridSpin.DownClick(Sender:TObject);
begin
  inherited;
  DoClick(False);
end;

procedure TGridSpin.CheckMinMax;
begin
  case SpinType of
  sptNormal:
    begin
      if (MinValue <> MaxValue) then
      begin
        if Value < MinValue then
          Value := MinValue;
        if Value > MaxValue then
          Value := MaxValue;
      end;
    end;
  sptFloat:
    begin
      if (MinFloatValue <> MaxFloatValue) then
      begin
        if FloatValue < MinFloatValue then
          FloatValue := MinFloatValue;
        if FloatValue > MaxFloatValue then
          FloatValue := MaxFloatValue;
      end;
    end;
  end;
end;

procedure TGridSpin.DoExit;
begin
  CheckMinMax;
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridSpin.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited KeyUp(Key,shift);
end;

procedure TGridSpin.Change;
begin
  inherited;
  if Assigned(FGrid) then
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
end;

procedure TGridSpin.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;


procedure TGridSpin.WMChar(var Msg:TWMChar);
begin
  if Msg.CharCode in [Ord(#13),Ord(#9)] then Msg.Result :=0 else
  inherited;
end;

procedure TGridSpin.Keypress(var Key:char);
begin
  if (Key = #27) then
    Key := #0;

  if Key <> #13 then
    inherited Keypress(Key);
end;

procedure TGridSpin.Keydown(var Key: Word; Shift: TShiftState);
var
  i,err: integer;
  r: real;
begin
  case Key of
  VK_NEXT:
    case SpinType of
    sptNormal:if Value - Increment >= MinValue then
                Value := Value - Increment;
    sptFloat:if FloatValue - IncrementFloat >= MinFloatValue then
               FloatValue := FloatValue - IncrementFloat;
    end;
  VK_PRIOR:
    case SpinType of
    sptNormal:if Value - Increment <= MaxValue then
                Value := Value + Increment;
    sptFloat:if FloatValue + IncrementFloat <= MaxFloatValue then
               FloatValue := FloatValue + IncrementFloat;
    end;
  VK_END:
    case SpinType of
    sptNormal: Value := MinValue;
    sptFloat: FloatValue := MinFloatValue;
    end;
  VK_HOME:
    case SpinType of
    sptNormal: Value := MaxValue;
    sptFloat: FloatValue := MaxFloatValue;
    end;
  end;

  if Assigned(FGrid.OnSpinClick) then
  begin
    if (Key in [VK_PRIOR,VK_HOME]) then
      FGrid.OnSpinClick(FGrid,FGrid.Col,FGrid.Row,self.Value,False);
    if (Key in [VK_NEXT,VK_END]) then
      FGrid.OnSpinClick(FGrid,FGrid.Col,FGrid.Row,self.Value,False);
  end;

  if (Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_TAB]) then
  begin
    if Key = VK_ESCAPE then  // restore previous value
    begin
      //self.Text := FGrid.CurrentCell;
      Text := FGrid.OriginalCellValue;

      case SpinType of
      sptNormal:
        begin
          Val(Text, i, err);
          Value := i;
        end;
      sptFloat:
        begin
          val(Text, r, err);
          FloatValue := r;
        end;
      end;
      (*
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Key := 0;
      Exit;
      *)
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
    begin
      CheckMinMax;
      FGrid.CurrentCell := Text;

      if not FGrid.ValidateCell(Text) then
      begin
        Text := FGrid.CurrentCell;
        SelStart := Length(Text);

        Key := 0;
        FGrid.FNoAutoAdvance := true;

        Repaint;
        Exit;
      end;

      self.Text := FGrid.CurrentCell;
    end;


    if (Key = VK_TAB) and (goTabs in FGrid.Options) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;
    {
    if FGrid.Navigation.AdvanceOnEnter and (Key = VK_RETURN) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Key := 0;
      FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);
      Exit;
    end;
    }

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
 else
   inherited;
end;

{$IFDEF TMSUNICODE}
constructor TGridUniEdit.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridUniEdit.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridUniEdit.DoExit;
begin
  FGrid.FEditWideText := self.Text;
  FGrid.HideInplaceEdit;
  self.Text := ' ';
  inherited DoExit;
end;

procedure TGridUniEdit.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

procedure TGridUniEdit.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
  if not FGrid.Navigation.EditSelectAll then
  begin
    SelStart := length(Text);
    SelLength := 1;
  end;
end;


procedure TGridUniEdit.WMChar(var Msg:TWMChar);
begin
  if Msg.CharCode in [Ord(#13),Ord(#9)] then
    Msg.Result :=0
  else
    inherited;
end;

procedure TGridUniEdit.Keypress(var Key:char);
begin
  if Key <> #13 then
    inherited Keypress(Key);
end;

procedure TGridUniEdit.Keydown(var Key: Word; Shift: TShiftState);
var
  RCol: Integer;
begin
  if (Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_TAB]) then
  begin
    RCol := FGrid.RemapCol(FGrid.Col);

    if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
    begin
      //FGrid.WideCells[RCol,FGrid.Row] := Self.Text;

      if not FGrid.ValidateCellWide(Self.Text) then
      begin
        self.Text := FGrid.WideCells[RCol,FGrid.Row];
        self.SelStart := Length(self.Text);
        Repaint;
        Exit;
      end;

      //self.Text := FGrid.WideCells[RCol,FGrid.Row];
    end;

    if (Key = VK_TAB) and (goTabs in FGrid.Options) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;

    if Key = VK_ESCAPE then
    begin
      self.Text := FGrid.WideCells[RCol,FGrid.Row];
    end;

    FGrid.DoneInplaceEdit(Key,Shift);
  end
 else
   inherited;
end;


constructor TGridUniMemo.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridUniMemo.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridUniMemo.DoExit;
begin
  FGrid.FEditWideText := self.Text;
  FGrid.HideInplaceEdit;
  //FGrid.FEditing := true;  //********
  self.Text := ' ';
  inherited DoExit;
end;

procedure TGridUniMemo.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

procedure TGridUniMemo.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
  if not FGrid.Navigation.EditSelectAll then
  begin
    SelStart := length(Text);
    SelLength := 1;
  end;
end;

procedure TGridUniMemo.WMChar(var Msg:TWMChar);
begin
  if Msg.CharCode in [Ord(#9)] then
    Msg.Result :=0
  else
    inherited;
end;

procedure TGridUniMemo.Keypress(var Key:char);
begin
  inherited Keypress(Key);
end;

procedure TGridUniMemo.Keydown(var Key: Word; Shift: TShiftState);
var
  RCol: Integer;
begin
  if (Key in [VK_ESCAPE,VK_TAB]) then
  begin
    RCol := FGrid.RemapCol(FGrid.Col);

    if (Key in [VK_TAB]) then
    begin
      FGrid.WideCells[RCol,FGrid.Row] := Self.Text;

      if not FGrid.ValidateCellWide(Self.Text) then
      begin
        self.Text := FGrid.WideCells[RCol,FGrid.Row];
        self.SelStart := Length(self.Text);
        Repaint;
        Exit;
       end;
       //self.Text := FGrid.WideCells[RCol,FGrid.Row];
    end;

    if (Key = VK_TAB) and (goTabs in FGrid.Options) then
    begin
      FGrid.EditMode := true;
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;

    if Key = VK_ESCAPE then
    begin
      self.Text := FGrid.WideCells[RCol,FGrid.Row];
    end;

    FGrid.DoneInplaceEdit(Key,Shift);
  end
 else
   inherited;
end;


constructor TGridUniEditBtn.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridUniEditBtn.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridUniEditBtn.DoExit;
begin
  FGrid.FEditWideText := self.Text;
  FGrid.HideInplaceEdit;
  self.Text := ' ';
  inherited DoExit;
end;

procedure TGridUniEditBtn.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

procedure TGridUniEditBtn.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;

  if not FGrid.Navigation.EditSelectAll then
  begin
    SelStart := length(text);
    SelLength := 1;
  end;
end;

procedure TGridUniEditBtn.WMChar(var Msg:TWMChar);
begin
  if Msg.CharCode in [Ord(#13),Ord(#9)] then
    Msg.Result := 0
  else
    inherited;
end;

procedure TGridUniEditBtn.Keypress(var Key:char);
begin
  if Key <> #13 then
    inherited Keypress(Key);
end;

procedure TGridUniEditBtn.Keydown(var Key: Word; Shift: TShiftState);
var
  RCol: Integer;
begin
  if (Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_TAB]) then
  begin
    RCol := FGrid.RemapCol(FGrid.Col);

    if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
    begin
      FGrid.WideCells[RCol,FGrid.Row] := Self.Text;

      if not FGrid.ValidateCellWide(Self.Text) then
      begin
        self.Text := FGrid.WideCells[RCol,FGrid.Row];
        self.SelStart := Length(self.Text);
        Repaint;
        Exit;
       end;
       self.Text := FGrid.WideCells[RCol,FGrid.Row];
    end;

    if (Key = VK_TAB) and (goTabs in FGrid.Options) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;

    if Key = VK_ESCAPE then
    begin
      self.Text := FGrid.WideCells[RCol,FGrid.Row];
    end;

    FGrid.DoneInplaceEdit(Key,Shift);
  end
 else
   inherited;
end;


procedure TGridUniCombo.DoExit;
begin
  if FGrid.LookupHistory and (Text <> '') then
  begin
    if (Items.IndexOf(Text) = -1) then
      Items.Add(Text);
  end;
  FGrid.FEditWideText := self.Text;
  FGrid.HideInplaceEdit;
  if Style = csDropDown then
    self.Text := ' '; 
  inherited DoExit;
end;

procedure TGridUniCombo.WndProc(var Message:tMessage);
begin
  if Assigned(FGrid) then
  begin
    if (Message.Msg = FGrid.WheelMsg) then
    begin
      if Message.Wparam < 0 then
        ItemIndex := ItemIndex + 1
      else
        if ItemIndex > 0 then ItemIndex := ItemIndex - 1;

      if Assigned(FGrid.FOnEditChange) then
      begin
        FGrid.FOnEditChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,Items[ItemIndex]);
      end;

      if Assigned(FGrid.FOnComboChange) then
      begin
        FGrid.FOnComboChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex]);
      end;

      if Assigned(FGrid.FOnComboObjectChange) then
      begin
        FGrid.FOnComboObjectChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex],Items.Objects[ItemIndex]);
      end;

      Message.Result := 0;
      Exit;
    end;

    if (Message.Msg = WM_COMMAND) and
       (Message.WParamHi = CBN_SELCHANGE) then
    begin
      if Assigned(FGrid.FOnComboChange) then
      begin
        FGrid.FOnComboChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex]);
      end;

      if Assigned(FGrid.FOnComboObjectChange) then
      begin
        FGrid.FOnComboObjectChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex],Items.Objects[ItemIndex]);
      end;

    end;
  end;

  inherited;
end;

procedure TGridUniCombo.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

constructor TGridUniCombo.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
  ButtonWidth := 16;
  ItemChange := False;
end;

procedure TGridUniCombo.SizeDropDownWidth;
var
  i,tw,nw: Integer;
  HasScroll: Boolean;
  sz: TSize;
  ws: widestring;
begin
  tw := Width;

  HasScroll := Items.Count > DropDownCount;

  for i := 1 to Items.Count do
  begin
    ws := Self.Items[i - 1];
    GetTextExtentPoint32W(FGrid.Canvas.Handle,PWideChar(ws),Length(ws),sz);
    nw := sz.cx;

//    nw := FGrid.Canvas.TextWidth(Self.Items[i - 1]);

    if HasScroll then
    begin
      if nw > tw - 25 then
        tw := nw + 25;
    end
    else
    begin
      if nw > tw - 5 then
        tw := nw + 8;
    end;
  end;

  SendMessage(Handle,CB_SETDROPPEDWIDTH,tw,0);
end;

procedure TGridUniCombo.DoChange;
var
  c,s: string;
  i: Integer;
  UsrStr,AutoAdd:string;

begin
  if not WorkMode then Exit;
  if not FGrid.Lookup then Exit;

  if not FGrid.LookupCaseSensitive then
    c := AnsiUpperCase(Text)
  else
    c := Text;

  c := Copy(c,1,SelStart);

  for i:=1 to Items.Count do
  begin
    if not FGrid.LookupCaseSensitive then
      s := AnsiUpperCase(Items[i - 1])
    else
      s := Items[i - 1];

    if Pos(c,s) = 1 then
    begin
      UsrStr := Copy(Text,1,Length(c));
      AutoAdd := Copy(Items[i - 1],Length(c)+1,255);
      Text := UsrStr + AutoAdd;
      ItemIndex := i - 1;
      SendMessage(Handle,CB_SETEDITSEL,0,MakeLong(Length(c),Length(Text)));
      ItemIdx := i - 1;
      ItemChange := True;
      Exit;
    end;
  end;
end;

procedure TGridUniCombo.WMSetFocus(var Msg: TWMSetFocus);
var
  lpPoint: TPoint;
  i: Integer;
  hwndedit: THandle;
begin
  inherited;

  if not FGrid.LButFlg then
    Exit;

  GetCursorPos(lpPoint);
  lpPoint := ScreenToClient(lpPoint);

  if (lpPoint.x < 0) or (lpPoint.y < 0) or
     (lpPoint.x > Width) or (lpPoint.y > Height) then Exit;

  hwndEdit := FindWindowEx(Handle, 0,nil,nil);

  i := SendMessage(hwndedit,EM_CHARFROMPOS, 0,MakeLong(lpPoint.x,lpPoint.y));
  if i = -1 then
    Exit;

  SelStart := Loword(i);
  SelLength := 0;
  FGrid.LButFlg := False;
end;

procedure TGridUniCombo.Keypress(var Key: char);
var
  idx: integer;
begin
  idx := ItemIndex;

  if (Key = #13) and Assigned(FOnReturnKey) then
    FOnReturnKey(Self);

  if Key in [#13,#9] then
    Key := #0;
    
  inherited Keypress(Key);

  if (idx <> ItemIndex) then
  begin
    if Assigned(FGrid.OnComboChange) then
      FGrid.OnComboChange(Self, FGrid.RealColIndex(FGrid.Col), FGrid.Row, ItemIndex, Text);

   if Assigned(FGrid.FOnComboObjectChange) then
     FGrid.FOnComboObjectChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex],Items.Objects[ItemIndex]);
  end;

end;

procedure TGridUniCombo.KeyUp(var Key: Word; Shift: TShiftState);
begin
  if Key <> VK_RETURN then
    inherited KeyUp(Key,shift);

  Self.DoChange;
end;

procedure TGridUniCombo.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;
  // ComboSelState: Boolean;
  RCol: Integer;

begin
  Forced := False;

  if (Self.Style = csDropDownList) or DroppedDown then
    Condition := Key in [VK_LEFT,VK_RIGHT,VK_ESCAPE,VK_TAB,VK_RETURN]
  else
    Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  // ComboSelState := (Self.Style = csDropDownList) or DroppedDown;

  if Condition then
  begin
    RCol := FGrid.RemapCol(FGrid.Col);

    if Key = VK_ESCAPE then
    begin
      Self.Text := FGrid.WideCells[RCol,FGrid.Row];
      // Self.Text := FGrid.CurrentCell;
//      if Items.IndexOf(self.Text) <> -1 then
//        ItemIndex := Items.IndexOf(self.Text);
      ItemIndex := -1;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
    begin
      FGrid.DoneInplaceEdit(Key,Shift);
      Exit;

      FGrid.WideCells[RCol,FGrid.Row] := Self.Text;

      //  FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCellWide(Self.Text) then
      begin
        Self.Text := FGrid.WideCells[RCol,FGrid.Row];
        // Self.Text := FGrid.CurrentCell;
        Self.SelStart := Length(Self.Text);
        Self.Repaint;
        Exit;
      end;
      Self.Text := FGrid.WideCells[RCol,FGrid.Row];

      // Self.Text := FGrid.CurrentCell;
    end;

    if (Key = VK_TAB) and (goTabs in FGrid.Options) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;

    {
    if ComboSelState then
    begin
      FGrid.HideInplaceEdit;
      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then Key := 0;
    end
    else
    begin
      if Key in [VK_LEFT,VK_RIGHT] then Key := 0;

      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;
    }

    FGrid.DoneInplaceEdit(Key,Shift);

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

{$ENDIF}

{ TGridCombo }

procedure TGridCombo.DoExit;
begin
  if FGrid.LookupHistory and (Text <> '') then
  begin
    if (Items.IndexOf(Text) = -1) then Items.Add(text);
  end;

  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridCombo.WndProc(var Message:tMessage);
begin


  if Assigned(FGrid) then
    if (Message.Msg = FGrid.WheelMsg) then
    begin
      if integer(Message.Wparam) < 0 then
        ItemIndex := ItemIndex + 1
      else
        if ItemIndex > 0 then ItemIndex := ItemIndex - 1;

      if Assigned(FGrid.FOnEditChange) then
      begin
        FGrid.FOnEditChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,Items[ItemIndex]);
      end;

      if Assigned(FGrid.FOnComboChange) then
      begin
        FGrid.FOnComboChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex]);
      end;

      if Assigned(FGrid.FOnComboObjectChange) then
      begin
        FGrid.FOnComboObjectChange(FGrid,FGrid.RealColIndex(FGrid.Col),FGrid.Row,ItemIndex,Items[ItemIndex],Items.Objects[ItemIndex]);
      end;

      Message.Result := 0;
      Exit;
    end;

  inherited;
end;

procedure TGridCombo.Change;
begin
  inherited;
  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;

    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridCombo.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;

  if (Msg.CharCode = VK_RETURN) or (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;

  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridCombo.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
  ButtonWidth := 16;
  ItemChange := False;
end;

procedure TGridCombo.SizeDropDownWidth;
var
  i,tw,nw: Integer;
  HasScroll: Boolean;
begin
  tw := Width;

  HasScroll := Items.Count > DropDownCount;

  for i := 1 to Items.Count do
  begin
    nw := FGrid.Canvas.TextWidth(Self.Items[i - 1]);

    if HasScroll then
    begin
      if nw > tw - 25 then
        tw := nw + 25;
    end
    else
    begin
      if nw > tw - 5 then
        tw := nw + 8;
    end;
  end;

  SendMessage(Handle,CB_SETDROPPEDWIDTH,tw,0);
end;

procedure TGridCombo.DoChange;
var
  c,s: string;
  i: Integer;
  UsrStr,AutoAdd:string;

begin
  if not WorkMode then Exit;
  if not FGrid.Lookup then Exit;

  if not FGrid.LookupCaseSensitive then
    c := AnsiUpperCase(Text)
  else
    c := Text;

  c := Copy(c,1,SelStart);

  for i := 1 to Items.Count do
  begin
    if not FGrid.LookupCaseSensitive then
      s := AnsiUpperCase(Items[i - 1])
    else
      s := Items[i - 1];

    if Pos(c,s) = 1 then
    begin
      UsrStr := Copy(Text,1,Length(c));
      AutoAdd := Copy(Items[i - 1],Length(c)+1,255);
      Text := UsrStr + AutoAdd;
      ItemIndex := i - 1;
      SendMessage(Handle,CB_SETEDITSEL,0,MakeLong(Length(c),Length(Text)));
      ItemIdx := i - 1;
      ItemChange := True;
      Exit;
    end;
  end;

  for i := 1 to FGrid.LookUpItems.Count do
  begin
    if not FGrid.LookupCaseSensitive then
      s := AnsiUpperCase(FGrid.LookupItems[i - 1])
    else
      s := FGrid.LookupItems[i - 1];

    if Pos(c,s) = 1 then
    begin
      UsrStr := Copy(Text,1,Length(c));
      AutoAdd := Copy(FGrid.LookUpItems[i - 1],Length(c)+1,255);
      Text := UsrStr + AutoAdd;
      SendMessage(Handle,CB_SETEDITSEL,0,MakeLong(Length(c),Length(Text)));
      ItemIdx := i - 1;
      ItemChange := True;
      Exit;
    end;
  end;
end;


procedure TGridCombo.WMSetFocus(var Msg: TWMSetFocus);
var
  lpPoint: TPoint;
  i: Integer;
  hwndedit: THandle;
begin
  inherited;

  if not FGrid.Navigation.EditSelectAll and (Style = csDropDown) then
  begin
    SelStart := Length(Text);
    SelLength := 1;
  end;

  if not FGrid.LButFlg then
    Exit;

  GetCursorPos(lpPoint);
  lpPoint := ScreenToClient(lpPoint);

  if (lpPoint.x < 0) or (lpPoint.y < 0) or
     (lpPoint.x > Width) or (lpPoint.y > Height) then Exit;

  hwndEdit := FindWindowEx(Handle, 0,nil,nil);

  i := SendMessage(hwndedit, EM_CHARFROMPOS, 0, MakeLong(lpPoint.x,lpPoint.y));
  if i = -1 then
    Exit;

  SelStart := Loword(i);
  SelLength := 0;
  FGrid.LButFlg := False;
end;

procedure TGridCombo.Keypress(var Key: char);
var
  idx: integer;
  obj: TObject;
begin
  idx := ItemIndex;

  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) and Assigned(FOnReturnKey) then
    FOnReturnKey(Self);

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);

  if (idx <> ItemIndex) then
  begin
    if Assigned(FGrid.OnComboChange) then
      FGrid.OnComboChange(FGrid, FGrid.RealColIndex(FGrid.Col), FGrid.Row, ItemIndex, Text);

    if Assigned(FGrid.OnComboObjectChange) then
    begin
      obj := nil;
      if ItemIndex >= 0 then
        obj := Items.Objects[ItemIndex];
      FGrid.OnComboObjectChange(FGrid, FGrid.RealColIndex(FGrid.Col), FGrid.Row, ItemIndex, Text, obj);
    end;
  end;
end;


procedure TGridCombo.KeyUp(var Key: Word; Shift: TShiftState);
var
  csx: integer;
  am: TAdvanceDirection;
begin
  (*
  if FGrid.Navigation.AdvanceOnEnter and (Key = VK_RETURN) and not FGrid.FNoAutoAdvance then
  begin
    FGrid.HideInplaceEdit;
    FGrid.SetFocus;
    Key := 0;
    FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);
    FGrid.ShowInplaceEdit;
    Exit;
  end;
  *)

  if (Key = VK_LEFT) and (Style = csDropDown) and (FGrid.Navigation.CursorWalkEditor) then
  begin
    if (SelLength = 0) and (SelStart = 0) and (Shift = []) then
    begin
      with FGrid do
      begin
        Key := 0;
        if (Col > FixedCols) and HasStaticEdit(Col - 1,Row) then
        begin
          if ValidateCell(Self.Text) then
          begin
            HideInplaceEdit;
            Col := Col - 1;
          end;
        end
        else
        begin
          FGrid.SetFocus;
          am := Navigation.AdvanceDirection;
          Navigation.AdvanceDirection := adLeftRight;
          AdvanceEdit(Col,Row,True,True,False,False, True);
          Navigation.AdvanceDirection := am;
          if Navigation.CursorWalkAlwaysEdit then
            FGrid.ShowEditor;
        end;
      end;
     end;
  end;

  if (Key = VK_RIGHT) and (Style = csDropDown) and (FGrid.Navigation.CursorWalkEditor) then
  begin
    if (SelLength = 0) and (SelStart = Length(Text)) and (Shift = []) then
    begin
      with FGrid do
      begin
        Key := 0;
        csx := CellSpan(Col,Row).X + 1;

        if (Col < ColCount - 1 - FixedRightCols) and HasStaticEdit(Col + csx, Row) then
        begin
          if ValidateCell(Self.Text) then
          begin
            HideInplaceEdit;
            Col := Col + csx;
          end;
        end
        else
        begin
          FGrid.SetFocus;
          am := Navigation.AdvanceDirection;
          if not (am in [adLeftRight, adLeftRightInRow]) then
            Navigation.AdvanceDirection := adLeftRight;
          AdvanceEdit(Col,Row,True,True,True,False, True);
          Navigation.AdvanceDirection := am;

          if Navigation.CursorWalkAlwaysEdit then
            FGrid.ShowEditor;
        end;
      end;
    end;
  end;

  FGrid.FNoAutoAdvance := false;

  if Key <> VK_RETURN then
    inherited KeyUp(Key,shift);

  DoChange;
end;

procedure TGridCombo.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition,AE: Boolean;
  ComboSelState: Boolean;
  dc: boolean;
  idx: integer;
begin
  if not (Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_PRIOR,VK_NEXT,VK_TAB]) then
    if Assigned(FGrid.OnKeyDown) then
      FGrid.OnKeyDown(FGrid, Key, Shift);

  Forced := False;

  if (Style = csDropDownList) or DroppedDown then
    Condition := Key in [VK_LEFT,VK_RIGHT,VK_ESCAPE,VK_TAB,VK_RETURN]
  else
    Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if ((Key = VK_DOWN) or (Key = VK_UP)) and not FGrid.Navigation.ComboGetUpDown then
  begin
    if not DroppedDown then
    begin
      FGrid.HideInplaceEdit;
      AE := FGrid.Navigation.AlwaysEdit;
      FGrid.Navigation.AlwaysEdit := false;
      FGrid.SetFocus;
      FGrid.Navigation.AlwaysEdit := AE;
      FGrid.KeyDown(Key,Shift);
    end;
  end;

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  ComboSelState := (Style = csDropDownList) or DroppedDown;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Text := FGrid.CurrentCell;
      if Items.IndexOf(FGrid.CurrentCell) <> -1 then
        ItemIndex := Items.IndexOf(FGrid.CurrentCell);

      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Text;
      if not FGrid.ValidateCell(Text) then
      begin
        Text := FGrid.FNewCellText;

        if (Style <> csDropDownList) then
        begin
          SelStart := 0;
          SelLength := Length(Text);
        end;

        Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      if (Style = csDropDownList) then
      begin
        idx := Items.IndexOf(FGrid.CurrentCell);
        if idx <> -1 then
          ItemIndex := idx;
      end
      else
        Text := FGrid.CurrentCell;
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.Text := FGrid.FNewCellText;
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if Style = csDropDownList then
        self.ItemIndex := Items.IndexOf(FGrid.CurrentCell)
      else
        self.Text := FGrid.CurrentCell;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if ComboSelState then
    begin
      dc := FGrid.MouseActions.DirectComboClose;
      FGrid.MouseActions.DirectComboClose := False;

      FGrid.HideInplaceEdit;
      FGrid.MouseActions.DirectComboClose := dc;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key in [VK_LEFT,VK_RIGHT]) and (Style = csDropDownList) then
        Key := 0;

      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FAdvance := true;

    FGrid.DoneInplaceEdit(Key,Shift);

    Key := 0;

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
    begin
      PostMessage(FGrid.Handle, WM_GRIDEDITSHOW, 0,0);
    end;

    inherited;
  end
  else
  begin
    inherited;
  end;
end;

/// EDITORINTEGRATION

{ TGridTrackbarDropDown }

procedure TGridTrackbarDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridTrackbarDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  // wants return, escape, tab
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;

  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;

  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridTrackbarDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridTrackbarDropDown.DoChange;
begin

end;

procedure TGridTrackbarDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridTrackbarDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.Text := FGrid.CurrentCell;
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.Text := FGrid.FNewCellText;

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      self.Text := FGrid.CurrentCell;
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.Text := FGrid.FNewCellText;
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridTrackbarDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridTrackbarDropDown.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited;

end;

procedure TGridTrackbarDropDown.WMSetFocus(var Msg: TWMSetFocus);
var
  lpPoint: TPoint;
  i: Integer;

begin
  inherited;

  if not FGrid.LButFlg then
    Exit;

  GetCursorPos(lpPoint);
  lpPoint := ScreenToClient(lpPoint);

  if (lpPoint.x < 0) or (lpPoint.y < 0) or
     (lpPoint.x > Width) or (lpPoint.y > Height) then Exit;

  i := SendMessage(handle,EM_CHARFROMPOS, 0,MakeLong(lpPoint.x,lpPoint.y));
  if i = -1 then
    Exit;

  SelStart := Loword(i);
  SelLength := 0;
  FGrid.LButFlg := False;
end;

procedure TGridTrackbarDropDown.WndProc(var Message: TMessage);
begin
  inherited;
end;

{ TGridMemoDropDown }

procedure TGridMemoDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridMemoDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridMemoDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridMemoDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridMemoDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;


  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridMemoDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridMemoDropDown.WMSetFocus(var Msg: TWMSetFocus);
var
  lpPoint: TPoint;
  i: Integer;

begin
  inherited;

  if not FGrid.LButFlg then
    Exit;

  GetCursorPos(lpPoint);
  lpPoint := ScreenToClient(lpPoint);

  if (lpPoint.x < 0) or (lpPoint.y < 0) or
     (lpPoint.x > Width) or (lpPoint.y > Height) then Exit;

  i := SendMessage(handle,EM_CHARFROMPOS, 0,MakeLong(lpPoint.x,lpPoint.y));
  if i = -1 then
    Exit;

  SelStart := Loword(i);
  SelLength := 0;
  FGrid.LButFlg := False;
end;

{ TGridCalculatorDropDown }

procedure TGridCalculatorDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridCalculatorDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridCalculatorDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridCalculatorDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridCalculatorDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;


  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      if Key = VK_RETURN then
        CalcResult;
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridCalculatorDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridCalculatorDropDown.WMSetFocus(var Msg: TWMSetFocus);
var
  lpPoint: TPoint;
  i: Integer;

begin
  inherited;

  if not FGrid.LButFlg then
    Exit;

  GetCursorPos(lpPoint);
  lpPoint := ScreenToClient(lpPoint);

  if (lpPoint.x < 0) or (lpPoint.y < 0) or
     (lpPoint.x > Width) or (lpPoint.y > Height) then Exit;

  i := SendMessage(handle,EM_CHARFROMPOS, 0,MakeLong(lpPoint.x,lpPoint.y));
  if i = -1 then
    Exit;

  SelStart := Loword(i);
  SelLength := 0;
  FGrid.LButFlg := False;
end;

{ TGridTimePickerDropDown }

procedure TGridTimePickerDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridTimePickerDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridTimePickerDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
  FocusDraw := false;
end;

procedure TGridTimePickerDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridTimePickerDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridTimePickerDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridTimePickerDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;

{ TGridGridDropDown }

procedure TGridGridDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridGridDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridGridDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridGridDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridGridDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      HideDropDown(true);
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridGridDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridGridDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;


{ TGridAdvGridDropDown }

procedure TGridAdvGridDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridAdvGridDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridAdvGridDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridAdvGridDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

function TGridAdvGridDropDown.GetAdvGrid: TAdvStringGrid;
begin
  Result := GetGrid as TAdvStringGrid;
end;

procedure TGridAdvGridDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;


  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridAdvGridDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridAdvGridDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;


{ TGridDetailPickerDropDown }

procedure TGridDetailPickerDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridDetailPickerDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridDetailPickerDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridDetailPickerDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridDetailPickerDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;


  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridDetailPickerDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridDetailPickerDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;

{ TGridColorDropDown }

procedure TGridColorDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridColorDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;

  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;

  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
  begin
    Msg.Result := 1;
  end;
end;

constructor TGridColorDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridColorDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridColorDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  if DroppedDown then
    Condition := Key in [VK_ESCAPE,VK_TAB,VK_RETURN]
  else
    Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_HOME,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN{,VK_UP,VK_DOWN}]) then
    begin
      FGrid.CurrentCell := Self.SelectedColorText;

      if not FGrid.ValidateCell(Self.SelectedColorText) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.SelectedColorText;
      if not FGrid.ValidateCell(Self.SelectedColorText) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridColorDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridColorDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;

{ TGridImageDropDown }

procedure TGridImageDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridImageDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridImageDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridImageDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridImageDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridImageDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridImageDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;

{ TGridControlDropDown }

procedure TGridControlDropDown.Change;
begin
  inherited;

  if Assigned(FGrid) then
  begin
    FGrid.CanEditModify;
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TGridControlDropDown.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

constructor TGridControlDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  WorkMode := True;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridControlDropDown.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridControlDropDown.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;

begin
  Forced := False;

  Condition := Key in [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT,VK_END,VK_ESCAPE,VK_TAB,VK_RETURN];

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  if (ssAlt in Shift) and (Key = VK_DOWN) then
    Condition := False;

  if Condition then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Self.SetTextDirect(FGrid.CurrentCell);
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);

        Self.SelStart := 0;
        Self.SelLength := Length(Self.Text);
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      Self.SetTextDirect(FGrid.CurrentCell);
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.SetTextDirect(FGrid.FNewCellText);
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if DroppedDown then
    begin
      FGrid.HideInplaceEdit;

      if Key in [VK_LEFT,VK_RIGHT] then
        FGrid.KeyDown(Key,Shift);

      if Key in [VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT] then
        Key := 0;
    end
    else
    begin
      if (Key = VK_END) then
      begin
        inherited;
        Exit;
      end;
      // handle Alt-Dn for combo dropdown opening
      if (Key = VK_DOWN) and (ssAlt in Shift) then
      begin
        inherited;
        Exit;
      end;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

    Key := 0;
    inherited;
  end
  else
    inherited;
end;

procedure TGridControlDropDown.KeyPress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(Self, Key);

  if (Key = #27) then
    Key := #0;

  if (Key = #13) or (Key = #9) then
    Key := #0;

  inherited Keypress(Key);
end;

procedure TGridControlDropDown.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited;
end;

/// EDITORINTEGRATION


{ TGridDatePicker }

procedure TGridDatePicker.CNNotify(var Message: TWMNotify);
begin
  Message.Result := 0;
  case Message.NMHdr^.Code of
    DTN_CLOSEUP:FOldDropped := False;
    DTN_DROPDOWN:FOldDropped := True;
  end;
  inherited;
end;

procedure TGridDatePicker.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

procedure TGridDatePicker.WndProc(var Message: TMessage);
var
  DC: HDC;
  arect: TRect;
  WindowBrush:hBrush;
begin
  inherited;

  if (Message.Msg = WM_DTPSHIFTFOCUS) then
    ShiftFocus;

  if (Message.Msg = WM_NCPAINT) then
  begin
    DC := GetWindowDC(Handle);
    WindowBrush := 0;
    try
      WindowBrush := CreateSolidBrush(ColorToRGB(clwindow));
      GetWindowRect(Handle, ARect);
      OffsetRect(arect,-arect.Left,-arect.Top);

      FrameRect(DC, ARect, WindowBrush);
      InflateRect(arect,-1,-1);
      FrameRect(DC, ARect, WindowBrush);
    finally
      DeleteObject(windowBrush);
      ReleaseDC(Handle,DC);
    end;
  end;
end;

procedure TGridDatePicker.WMNCPaint (var Message: TMessage);
var
  DC: HDC;
  arect: TRect;
  WindowBrush: hBrush;
begin
  inherited;
  DC := GetWindowDC(Handle);
  WindowBrush := 0;
  try
    WindowBrush := CreateSolidBrush(ColorToRGB(clWindow));
    GetWindowRect(Handle, ARect);
    OffsetRect(Arect,-Arect.Left,-Arect.Top);
    FrameRect(DC, ARect, WindowBrush);
    InflateRect(ARect,-1,-1);
    FrameRect(DC, ARect, WindowBrush);
  finally
    DeleteObject(windowBrush);
    ReleaseDC(Handle,DC);
  end;
end;

constructor TGridDatePicker.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
  FWeeknumbers := false;
  FShowToday := true;
  FShowTodayCircle := true;
end;

procedure TGridDatePicker.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridDatePicker.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridDatePicker.ShiftFocus;
var
  y, m, d, h, s, ms: word;
  c: char;
begin
  if Kind = dtkTime then
  begin
    DecodeTime(DateTime, h, m, s, ms);

    if (h <> Fth) or (m <> Ftm) or (s <> Fts) then
      PostMessage(Handle, WM_KEYDOWN, VK_RIGHT, 0);
  end
  else
  begin
    DecodeDate(DateTime, y, m, d);
    if (Format <> '') then
    begin
      c := Format[Length(Format)];

      {$IFDEF DELPHI_UNICODE}
      if ((d <> Fd) and (CharInSet(c,['D','d']))) or ((m <> Fm) and (CharInSet(c,['M','m']))) or ((y <> Fy) and (CharInSet(c,['Y','y']))) then
      {$ENDIF}
      {$IFNDEF DELPHI_UNICODE}
      if ((d <> Fd) and (c in ['D','d'])) or ((m <> Fm) and (c in ['M','m'])) or ((y <> Fy) and (c in ['Y','y'])) then
      {$ENDIF}
      begin
      end
      else
        if (d <> Fd) or (m <> Fm) or (y <> Fy) then
          PostMessage(Handle, WM_KEYDOWN, VK_RIGHT, 0);
    end
    else
    begin
      if (d <> Fd) or (m <> Fm) then
        PostMessage(Handle, WM_KEYDOWN, VK_RIGHT, 0)
      else if (y <> Fy) then
      begin
      end;
    end;
  end;
end;

procedure TGridDatePicker.KeyPress(var Key: Char);
begin
  if (Integer(Key) in [48..57]) {and AutoTab} then
  begin
    DecodeTime(DateTime, Fth, Ftm, Fts, Ftms);
    DecodeDate(DateTime, Fy, Fm, Fd);
    inherited;
    PostMessage(Handle, WM_DTPSHIFTFOCUS, 0, 0);
  end
  else
    inherited;
  if Assigned(FGrid.OnKeypress) then
    FGrid.OnKeyPress(FGrid,Key);
end;


procedure TGridDatePicker.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if (Key in [VK_ESCAPE,VK_PRIOR,VK_NEXT,VK_END,VK_RETURN,VK_TAB]) then
  begin
    if (Key = VK_ESCAPE) then
      try
        if Kind = dtkTime then
          Self.Time := TTime(StrToTime(FGrid.CurrentCell))
        else
          Self.Date := TDate(StrToDate(FGrid.CurrentCell));
      except
        Date := TDate(Now);
      end;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN]) then
    begin
      // workaround for bug in TDateTimePicker
      SendMessage(Handle,WM_KEYDOWN,VK_RIGHT,0);
      SendMessage(Handle,WM_KEYUP,VK_RIGHT,0);
      FGrid.CurrentCell := Text;
      if not FGrid.ValidateCell(Text) then
      begin
        Self.Text := FGrid.FNewCellText;
        Self.Repaint;
        Key := 0;
        FGrid.FNoAutoAdvance := true;
        Exit;
      end;

      self.Text := FGrid.CurrentCell;
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.Text := FGrid.FNewCellText;
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    {
    if FGrid.Navigation.AdvanceOnEnter and (Key = VK_RETURN) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);
      Exit;
    end;
    }

    (*
    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.CurrentCell := self.Text;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;
    *)

    if not DroppedDown then
      FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;

  end
  else
    inherited;
end;

{ TGridDateTimePicker }

constructor TGridDateTimePicker.Create(AOwner: TComponent);
begin
  inherited;
  FGrid := TAdvStringGrid(AOwner);
  GridTabHandling := true;
end;

procedure TGridDateTimePicker.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if (Key in [VK_ESCAPE,VK_PRIOR,VK_NEXT,VK_END,VK_RETURN,VK_TAB]) then
  begin
    if (Key = VK_ESCAPE) then
    begin
      Date := FGrid.FOriginalDateTime;
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Exit;
    end;

    if  (Key = VK_RETURN) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      if FGrid.Navigation.AdvanceOnEnter then
        FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);
      Exit;
    end;

    if (Key = VK_TAB) and FGrid.ShouldHandleTab and (FTimePicker.Focused and (Shift = [])) or (not FTimePicker.Focused and (Shift = [ssShift])) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.CurrentCell := DateToStr(DateTime) + ' ' + TimeToStr(DateTime);
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;
  end;
  inherited;
end;


{TGridEditBtn}

procedure TGridEditBtn.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridEditBtn.ExtClick(Sender:TObject);
begin
  Text := FGrid.EllipsClick(Text);

  SelStart := 0;
  SelLength := Length(Text);
  Invalidate;

  if FStopEditAfterClick then
  begin
    FGrid.HideInplaceEdit;
    FGrid.SetFocus;
  end;
end;

constructor TGridEditBtn.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
  OnClickBtn := ExtClick;
  WorkMode := True;
end;

procedure TGridEditBtn.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridEditBtn.DoChange;
var
  s,c,d:string;
  i: Integer;
  se,ss: Integer;

begin
  SendMessage(Handle,EM_GETSEL,Integer(@se),LParam(@ss));

  if not WorkMode or (ss <> se) then
    Exit;

  if FGrid.LookupCaseSensitive then
    c := Text
  else
    c := AnsiUpperCase(Text);

  c := Copy(c,1,SelStart);

  if not Assigned(FGrid.LookupItems) then
    Exit;

  if (FGrid.LookupItems.Count > 0) and
     FGrid.Lookup then
    for i := 0 to FGrid.LookupItems.Count-1 do
    begin
      if FGrid.LookupCaseSensitive then
        d := FGrid.LookupItems.Strings[i]
      else
        d := AnsiUpperCase(FGrid.LookupItems.Strings[i]);

      if Pos(c,d) = 1  then
      begin
        s := Copy(Text,1,Length(c)) + Copy(FGrid.LookupItems.Strings[i],Length(c)+1,255);
        Text := s;
        SendMessage(Handle,EM_SETSEL,Length(c),Length(s));
        Exit;
      end;
    end;
end;


procedure TGridEditBtn.WMKillFocus(var Msg: TMessage);
begin
  inherited;
end;

procedure TGridEditBtn.WMLButtonDblClk(var Message: TWMLButtonDblClk);
begin
  inherited;
  if Assigned(FGrid.OnDblClickCell) then
    FGrid.OnDblClickCell(FGrid,FGrid.Row,FGrid.Col);
end;

procedure TGridEditBtn.WMPaste(var Msg:TMessage);
var
  {$IFNDEF DELPHI_UNICODE}
  Data: THandle;
  Content: PChar;
  {$ENDIF}
  newstr: string;
  Allow: Boolean;
  Newsl, Newss, Len: integer;

  function InsertString(s:string):string;
  var
    ss: Integer;
  begin
    Result := self.Text;
    ss := SelStart;
    if SelLength = 0 then
    begin
      Insert(s,Result,ss+1);
      Newsl := 0;
      Newss := ss + Length(s);
    end
    else
    begin
      ss := SelStart;
      Delete(Result,ss + 1,selLength);
      Insert(s,Result,ss + 1);
      Newsl := Length(s);
      Newss := ss;
    end;
  end;

begin
  {$IFDEF DELPHI_UNICODE}
  if ClipBoard.HasFormat(CF_TEXT) then
  begin
    Allow := True;
    NewStr := ClipBoard.AsText;
  end;
  {$ENDIF}

  {$IFNDEF DELPHI_UNICODE}
  if not ClipBoard.HasFormat(CF_TEXT) then
    Exit;

  ClipBoard.Open;
  Data := GetClipBoardData(CF_TEXT);
  try
    if Data <> 0 then
      Content := PChar(GlobalLock(Data))
    else
      Content := nil
  finally
    if Data <> 0 then
      GlobalUnlock(Data);
    ClipBoard.Close;
  end;

  if Content = nil then
    Exit;
   Allow := True;
   NewStr := StrPas(Content);

  {$ENDIF}

  if Assigned(FGrid.FOnClipboardPaste) then
    FGrid.FOnClipboardPaste(Self,Allow);

  if not Allow then
    Exit;

  if Assigned(FGrid.OnClipboardBeforePasteCell) then
    FGrid.OnClipboardBeforePasteCell(Self,FGrid.Col,FGrid.Row,NewStr,Allow);

  if not Allow then
    Exit;

  Len := Length(NewStr);

  if (Pos(#13#10,NewStr) = Len - 1) then
  begin
    Delete(NewStr,Len - 1,2);
  end;

  Text := InsertString(NewStr);

  FGrid.SetEditCell(Self.Text);

  SelStart := Newss;
  SelLength := Newsl;
end;

procedure TGridEditBtn.WMSetFocus(var Msg: TMessage);
begin
  inherited;
  if not FGrid.Navigation.EditSelectAll then
  begin
    SelStart := length(Text);
    SelLength := 1;
  end;
end;

procedure TGridEditBtn.WMChar(var Msg:TWMChar);
begin
  if (Msg.CharCode = ord(#13)) or (Msg.CharCode = ord(#9)) then
  begin
    Msg.Result := 1;
    Exit;
  end;

  case FGrid.EditControl of
  edEditBtn, edMaskEditBtn: inherited;
  edNumericEditBtn:if (Msg.CharCode in Numeric_Characters) and
                   not ((Msg.CharCode = Ord('-')) and (Pos('-',Text) > 0)) and
                   not ((Msg.CharCode = Ord('-')) and (SelStart <> 0)) then inherited else MessageBeep(0);
  edFloatEditBtn:
    begin
      if CheckFloatNumNoExp(Chr(Msg.CharCode)) then
//      if Msg.CharCode in Float_Characters then
      begin
        if ((Msg.CharCode = ord(DecimalSeparator)) and
           ( (Pos(DecimalSeparator,self.Text) > 0) and (Pos(DecimalSeparator,self.SelText) = 0) )) then
          Exit;

        if (Msg.CharCode = Ord(ThousandSeparator)) then
          Exit;

        if (Msg.CharCode = Ord('-')) and
           (((SelStart<>0) or (pos('-',self.Text)>0)) and not (pos('-',self.SelText)>0)) then
        begin
          MessageBeep(0);
          Exit;
        end;
        inherited;
      end;

      if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
        inherited;
    end;
  end;
end;

procedure TGridEditBtn.Change;
begin
  inherited;

  if Assigned(FGrid) then
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
end;

procedure TGridEditBtn.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  
  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;
  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

procedure TGridEditBtn.Keypress(var Key: Char);
begin
  if Assigned(FGrid.OnKeyPress) then
    FGrid.OnKeyPress(FGrid, Key);

  if (Key = #9) then
    Exit;

  inherited Keypress(Key);
  //  problem when used with Tab -> move content to new cell!
  //  FGrid.SetEditText(FGrid.Col,FGrid.Row,Text);
end;

procedure TGridEditBtn.KeyUp(var Key: Word; Shift: TShiftState);
var
  am:TAdvanceDirection;
  csx: integer;
begin
  if Assigned(FGrid.OnKeyUp) then
    FGrid.OnKeyUp(FGrid, Key, Shift);

  if (Key = VK_RIGHT) then
  begin
    if (self.SelLength = 0) and (self.SelStart = Length(Text)) and (Shift = []) then
      with FGrid do
      begin
        if Navigation.CursorWalkEditor then
        begin
          Key := 0;
          csx := CellSpan(Col,Row).X + 1;

          if (Col < ColCount - 1 - FixedRightCols) and HasStaticEdit(Col + csx, Row) then
          begin
            if ValidateCell(Self.Text) then
            begin
              HideInplaceEdit;
              Col := Col + csx;
            end;
          end
          else
          begin
            if ValidateCell(Self.Text) then
            begin
              FGrid.SetFocus;
              am := Navigation.AdvanceDirection;
              if not (am in [adLeftRight, adLeftRightInRow]) then
                Navigation.AdvanceDirection := adLeftRight;
              AdvanceEdit(Col,Row,True,True,True,False, True);
              Navigation.AdvanceDirection := am;

              if Navigation.CursorWalkAlwaysEdit then
                FGrid.ShowEditor;
            end;
          end;
        end;
      end;
  end;

  if (Key = VK_LEFT) then
  begin
    if (self.SelLength = 0) and (FSelKeyDown = 0) and (Shift = []) then
    with FGrid do
    begin
      if Navigation.CursorWalkEditor then
      begin
        Key := 0;
        if (Col > FixedCols) and HasStaticEdit(Col - 1,Row) then
        begin
          if ValidateCell(Self.Text) then
          begin
            HideInplaceEdit;
            Col := Col - 1;
          end;
        end
        else
        begin
          FGrid.SetFocus;
          am := Navigation.AdvanceDirection;
          if not (am in [adLeftRight, adLeftRightInRow]) then
            Navigation.AdvanceDirection := adLeftRight;
          AdvanceEdit(Col,Row,True,True,False,False, True);
          Navigation.AdvanceDirection := am;
          if Navigation.CursorWalkAlwaysEdit then
            FGrid.ShowEditor;
        end;
      end;
    end;
  end;

  if (Key <> VK_RETURN) then
    inherited KeyUp(Key, Shift);

  DoChange;  
end;

procedure TGridEditBtn.KeyDown(var Key: Word; Shift: TShiftState);
var
  s:string;
  edc: TEditorType;
begin
  if not (Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_PRIOR,VK_NEXT,VK_TAB]) then
    if Assigned(FGrid.OnKeyDown) then
      FGrid.OnKeyDown(FGrid, Key, Shift);

  WorkMode := not (Key in [VK_BACK,VK_DELETE]);

  FSelKeyDown := SelStart;

  if ssCtrl in Shift then
  begin
    inherited;
    Exit;
  end;

  if Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_PRIOR,VK_NEXT,VK_TAB] then
  begin
    if Assigned(OnKeyDown) then
      OnKeyDown(Self,Key,Shift);

    edc := FGrid.EditControl;

    // grid db issue
    // if (Key = VK_RETURN) or ((Key = VK_TAB) and (goTabs in FGrid.Options)) then
    //   FGrid.HideInplaceEdit;

    if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
    begin
      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.Text := FGrid.FNewCellText;
        SelStart := 0;
        SelLength := Length(Self.Text);
        Repaint;
        Key := 0;
        FGrid.EditControl := edc;
        Exit;
      end;
      Self.Text := FGrid.FNewCellText;

      //Self.Text := FGrid.CurrentCell;
    end;
    {
    if FGrid.Navigation.AdvanceOnEnter and (Key = VK_RETURN) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Key := 0;
      FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);
      Exit;
    end;
    }
    if (Key = VK_TAB) and FGrid.ShouldHandleTab then
    begin
      (*
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
      *)

      FGrid.CurrentCell := Self.Text;
      if not FGrid.ValidateCell(Self.Text) then
      begin
        Self.Text := FGrid.FNewCellText;
        SelStart := Length(Self.Text);
        Repaint;
        Key := 0;
        Exit;
      end;

      if (goTabs in FGrid.Options) then
      begin
        FGrid.HideInplaceEdit;
        FGrid.SetFocus;
        FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
        Exit;
      end
      else
        PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;

    if (Key = VK_F4) and
     (GetKeyState(vk_control) and $8000 = 0) and
     (GetKeyState(vk_lmenu) and $8000 = 0) and
     (GetKeyState(vk_rmenu) and $8000 = 0) then
    begin

      if Assigned(FGrid.OnEllipsClick) then
      begin
        s := Text;
        FGrid.OnEllipsClick(FGrid, FGrid.Col, FGrid.Row, s);
        if (s <> Text) then
          Text := s;
      end;
    end;

    if Key = VK_ESCAPE then
      Self.Text := FGrid.OriginalCellValue;

    FGrid.DoneInplaceEdit(Key,Shift);

    if FGrid.Navigation.AdvanceOnEnter and FGrid.Navigation.AdvanceAutoEdit then
      FGrid.ShowInplaceEdit;
  end
  else
    inherited;
end;

{ TGridUnitEditBtn }

procedure TGridUnitEditBtn.ExtClick(Sender: TObject);
begin
  Text := FGrid.EllipsClick(Text);
  SelStart := 0;
  SelLength := Length(Text);
  Invalidate;
end;

constructor TGridUnitEditBtn.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
  OnClickBtn := ExtClick;
end;

procedure TGridUnitEditBtn.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridUnitEditBtn.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

procedure TGridUnitEditBtn.WMChar(var Msg:TWMChar);
begin
  if Msg.CharCode = Ord(#13) then
  begin
    Msg.Result := 0;
    Exit;
  end;

  case FGrid.EditControl of
  edUnitEditBtn: inherited;
  edNumericUnitEditBtn:if (Msg.CharCode in Numeric_Characters) and
                   not ((Msg.CharCode=ord('-')) and (pos('-',text)>0)) and
                   not ((Msg.CharCode=ord('-')) and (SelStart<>0)) then inherited else MessageBeep(0);
  edFloatUnitEditBtn:
    begin
      if CheckFloatNumNoExp(Chr(Msg.CharCode)) then

      //if Msg.CharCode in Float_Characters then
      begin
        if ((Msg.CharCode = ord(DecimalSeparator)) and
           ( (Pos(DecimalSeparator,self.Text) > 0) and (Pos(DecimalSeparator,self.SelText) = 0) )) then
          Exit;

        if (Msg.CharCode = Ord(ThousandSeparator)) then
          Exit;

        if (Msg.CharCode=ord('-')) and
           (((SelStart<>0) or (pos('-',self.Text)>0)) and not (pos('-',self.SelText)>0)) then
        begin
          MessageBeep(0);
          Exit;
        end;
        inherited;
      end;

      if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
        inherited;
    end;
  end;

end;

procedure TGridUnitEditBtn.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;

  if (Msg.CharCode = VK_RETURN) then
    Msg.Result := 1;

  if (Msg.CharCode = VK_ESCAPE) then
    Msg.Result := 1;

  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

procedure TGridUnitEditBtn.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if (Key in [VK_DOWN,VK_UP,VK_ESCAPE,VK_RETURN,VK_PRIOR,VK_NEXT,VK_TAB]) then
  begin
    if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
    begin
      FGrid.CurrentCell := Self.TextAndUnit;

      if not FGrid.ValidateCell(Self.TextAndUnit) then
      begin
        Self.Text := FGrid.CurrentCell;
        Exit;
      end;

      Self.TextAndUnit := FGrid.CurrentCell;
    end;

    if FGrid.Navigation.AdvanceOnEnter and (Key = VK_RETURN) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      Key := 0;
      FGrid.AdvanceEdit(FGrid.Col,FGrid.Row,False,True,True,False, True);
      Exit;
    end;

    if (Key = VK_TAB) and (goTabs in FGrid.Options) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    end;

    if Key = VK_ESCAPE then
    begin
      self.UnitID := '';
      self.Text := FGrid.CurrentCell;
    end;

    FGrid.DoneInplaceEdit(Key,Shift);
  end
  else
    inherited;
end;

{TGridButton}
procedure TGridButton.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
end;

constructor TGridButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TGridButton.ReCreate;
begin
  ReCreateWnd;
end;

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

procedure TGridButton.WMLButtonUp(var Msg:TWMLButtonUp);
var
  grd: TAdvStringGrid;
begin
  if (Parent is TAdvStringGrid) then
  begin
    grd := (Parent as TAdvStringGrid);
    Caption := grd.EllipsClick(Caption);
    grd.CurrentCell := Caption;
  end;

  inherited;
end;

procedure TGridButton.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  if Msg.CharCode in [VK_LEFT,VK_RIGHT,VK_DOWN,VK_UP,VK_ESCAPE] then
    Msg.Result := 1
  else
    inherited;
end;

procedure TGridButton.Keyup(var Key: Word; Shift: TShiftState);
begin
  {
  if (Key in [VK_LEFT,VK_RIGHT,VK_DOWN,VK_UP]) then
  begin
    SendMessage(FGrid.Handle,WM_KEYDOWN,Key,0);
    Visible := False;
    Enabled := False;
    FGrid.EditMode := False;
    FGrid.SetFocus;
    SendMessage(FGrid.Handle,WM_KEYUP,Key,0);
  end;
  }
  if Key = VK_SPACE then
  begin
    Self.Caption := FGrid.EllipsClick(Self.Caption);
    FGrid.CurrentCell := Self.Caption;
    SetFocus;
    Invalidate;
  end;
end;

procedure TGridButton.Keydown(var Key: Word; Shift: TShiftState);
begin
  if (Key in [VK_LEFT,VK_RIGHT,VK_DOWN,VK_UP]) then
  begin
    SendMessage(FGrid.Handle,WM_KEYDOWN,Key,0);
    Visible := False;
    Enabled := False;
    FGrid.EditMode := False;
    FGrid.SetFocus;
    SendMessage(FGrid.Handle,WM_KEYUP,Key,0);
    Exit;
  end;

  if (Key in [VK_ESCAPE]) then
  begin
    Visible := False;
    Enabled := False;
    FGrid.EditMode:=False;
    FGrid.SetFocus;
    if Key = VK_ESCAPE then
      FGrid.RestoreCache;
    SendMessage(FGrid.Handle,WM_KEYDOWN,Key,0);
  end
  else
    inherited;
end;


constructor TCellNode.Create(AOwner:TAdvStringGrid);
begin
  inherited Create;
  FColor := clSilver;
  FNodeColor := clBlack;
  FNodeType := cnXP;
  FContractGlyph := TBitmap.Create;
  FExpandGlyph := TBitmap.Create;
  FOwner := AOwner;
  FNodeIndent := 12;
  FShowTree := True;
  FShowTreeFull := True;
  FTreeColor := clGray;
end;

destructor TCellNode.Destroy;
begin
  FContractGlyph.Free;
  FExpandGlyph.Free;
  inherited Destroy;
end;

procedure TCellNode.Assign(Source: TPersistent);
begin
  if (Source is TCellNode) then
  begin
    FColor := (Source as TCelLNode).Color;
    FExpandOne := (Source as TCelLNode).ExpandOne;
    FNodeType := (Source as TCelLNode).NodeType;
    FNodeColor := (Source as TCelLNode).NodeColor;
    FNodeIndent := (Source as TCelLNode).NodeIndent;
    FExpandGlyph.Assign((Source as TCelLNode).ExpandGlyph);
    FContractGlyph.Assign((Source as TCelLNode).ContractGlyph);
    FShowTree := (Source as TCelLNode).ShowTree;
    FShowTreeFull := (Source as TCellNode).ShowTreeFull;
    FTreeColor := (Source as TCellNode).TreeColor;
  end;
end;

procedure TCellNode.SetNodeType(Value:TNodeType);
begin
  if Value <> FNodeType then
  begin
    FNodeType := Value;
    FOwner.Repaint;
  end;
end;

procedure TCellNode.SetShowTree(const Value: Boolean);
begin
  if Value <> FShowTree then
  begin
    FShowTree := Value;
    FOwner.Repaint;
  end;
end;

procedure TCellNode.SetShowTreeFull(const Value: Boolean);
begin
  if Value <> FShowTreeFull then
  begin
    FShowTreeFull := Value;
    FOwner.Repaint;
  end;
end;

procedure TCellNode.SetTreeColor(const Value: TColor);
begin
  if Value <> FTreeColor then
  begin
    FTreeColor := Value;
    FOwner.Repaint;
  end;
end;

procedure TCellNode.SetNodeIndent(const Value: Integer);
begin
  if Value <> FNodeIndent then
  begin
    FNodeIndent := Value;
    FOwner.Repaint;
  end;
end;

procedure TCellNode.SetExpandGlyph(Value:TBitmap);
begin
  FExpandGlyph.Assign(Value);
end;

procedure TCellNode.SetContractGlyph(Value:TBitmap);
begin
  FContractGlyph.Assign(Value);
end;

constructor TSizeWhileTyping.Create;
begin
  inherited Create;
end;

destructor TSizeWhileTyping.Destroy;
begin
  inherited Destroy;
end;

constructor TBaseCellGraphic.Create;
begin
  inherited Create;
  CellCreated := False;
  CellType := ctNone;
end;

destructor TBaseCellGraphic.Destroy;
begin
  case CellType of
  ctImages: TIntList(CellBitmap).Free;
  ctPicture: if CellCreated then TPicture(CellBitmap).Free;
  ctFilePicture: if CellCreated then TFilePicture(CellBitmap).Free;
  ctRadio: if CellCreated then TStringList(CellBitmap).Free;

  ctIcon: if CellCreated then CellIcon.Free;
  ctBitmap: if CellCreated then CellBitmap.Free;
  ctBitButton: if CellCreated then CellBitmap.Free;
  ctBalloon: CellBitmap.Free;
  ctCheckBox, ctDataCheckBox, ctRadioButton:
    begin
      if (CellAngle = 1) and Assigned(CellBitmap) then
        CellBitmap.Free;
    end;
  end;
  inherited Destroy;
end;

procedure TBaseCellGraphic.Assign(Source: TPersistent);
begin
  if (Source is TBaseCellGraphic) then
  begin
    FCellType := TBaseCellGraphic(Source).CellType;
    FCellVAlign := TBaseCellGraphic(Source).CellVAlign;
    FCellHAlign := TBaseCellGraphic(Source).CellHAlign;
    FCellIndex := TBaseCellGraphic(Source).CellIndex;
    FCellTransparent := TBaseCellGraphic(Source).CellTransparent;
    FCellValue := TBaseCellGraphic(Source).CellValue;
    FCellAngle := TBaseCellGraphic(Source).CellAngle;
    FCellBoolean := TBaseCellGraphic(Source).CellBoolean;
    FCellErrFrom := TBaseCellGraphic(Source).CellErrFrom;
    FCellErrLen := TBaseCellGraphic(Source).CellErrLen;
    FCellText := TBaseCellGraphic(Source).CellText;
    FCellCreated := TBaseCellGraphic(Source).CellCreated;
  end;

//  FCellBitmap: TBitmap read FCellBitmap write FCellBitmap;
//  FCellIcon: TIcon read FCellIcon write FCellIcon;
//  FCellCreated: Boolean read FCellCreated write FCellCreated;
end;

procedure TBaseCellGraphic.SetInterfacedCell(AObject:TInterfacedPersistent);
begin
  CellBitmap := TBitmap(AObject);
  CellType := ctInterface;
end;

procedure TBaseCellGraphic.SetBitmap(ABmp:TBitmap;Transparent: Boolean;hal:TCellHAlign;val:TCellVAlign);
begin
  CellBitmap := ABmp;
  CellType := ctBitmap;
  CellHAlign := hal;
  CellVAlign := val;
  CellTransparent := Transparent;
end;

procedure TBaseCellGraphic.SetButton(bw,bh: Integer;Caption:string;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctButton;
  CellHAlign := hal;
  CellVAlign := val;
  CellIndex := MakeLong(bw,bh);
  CellBoolean := False;
  CellText := Caption;
end;

procedure TBaseCellGraphic.SetBitButton(bw,bh: Integer;Caption:string;Glyph:TBitmap;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctBitButton;
  CellHAlign := hal;
  CellVAlign := val;
  CellIndex := MakeLong(bw,bh);
  CellBoolean := False;
  CellText := Caption;
  CellBitmap := Glyph;
end;


procedure TBaseCellGraphic.SetPicture(APicture:TPicture; Transparent: Boolean;StretchMode:TStretchMode;padding: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctPicture;
  CellHAlign := hal;
  CellVAlign := val;
  CellBitmap := TBitmap(APicture);
  CellTransparent := Transparent;
  CellAngle := Integer(StretchMode);
  CellIndex := padding;
end;

procedure TBaseCellGraphic.SetFilePicture(APicture: TFilePicture; Transparent: Boolean;stretchmode:TStretchMode;padding: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctFilePicture;
  CellHAlign := hal;
  CellVAlign := val;
  CellBitmap := TBitmap(APicture);
  CellTransparent := Transparent;
  CellAngle := Integer(StretchMode);
  CellIndex := padding;
end;

function TBaseCellGraphic.GetPictureSize(cw,rh: Integer;hastext: Boolean): TPoint;
var
  pw,ph,w,h: Integer;
  hsi,vsi: Double;
begin
  if not (CellType in [ctPicture,ctFilePicture]) then Exit;

  if CellType = ctPicture then
  begin
    ph := TPicture(CellBitmap).Height;
    pw := TPicture(CellBitmap).Width;
  end
  else
  begin
    ph := TFilePicture(CellBitmap).Height;
    pw := TFilePicture(CellBitmap).Width;
  end;

  w := pw;
  h := ph;

  // CellIndex is spacing
  cw := cw - CellIndex;
  rh := rh - CellIndex;

  case TStretchMode(CellAngle) of
  Stretch:
    begin
      w := cw;
      h := rh;
    end;
  Shrink:
    begin
      if (w > cw) or (h > rh) then
      begin
        w := cw;
        h := rh;
      end;
    end;
  StretchWithAspectRatio:
    begin
      if w > 0 then hsi := cw/w else hsi := 1;
      if h > 0 then vsi := rh/h else vsi := 1;

      if (hsi < vsi) then
      begin
        w := cw;
        h := Round(hsi * h);
      end
      else
      begin
        h := rh;
        w := Round(vsi * w);
      end;
    end;
  ShrinkWithAspectRatio:
    begin
      if (w > cw) or (h > rh) then
      begin
        if w > 0 then hsi := cw/w else hsi := 1;
        if h > 0 then vsi := rh/h else vsi := 1;

        // allow shrink only
        if hsi > 1 then hsi := 1;
        if vsi > 1 then vsi := 1;

        if hsi < vsi then
        begin
          w := cw;
          h := Round(hsi * h);
        end
        else
        begin
          h := rh;
          w := Round(vsi * w);
        end;
      end;
    end;
  end;
  Result.x := w;
  Result.y := h;
end;

procedure TBaseCellGraphic.SetCheckBox(Value,Data,Flat: Boolean;hal:TCellHAlign;val:TCellVAlign);
begin
  if Data then
    CellType := ctDataCheckBox
  else
    CellType := ctCheckbox;

  CellAngle := 0;
  CellBoolean := Value;
  CellHAlign := hal;
  CellVAlign := val;
  CellTransparent := Flat;
end;


procedure TBaseCellGraphic.SetCheckBox(Value: TCheckBoxState; Flat: Boolean; hal: TCellHAlign; val: TCellVAlign);
begin
  CellType := ctTriStateCheckBox;
  CellCheckBoxState := Value;
  CellBoolean := False;
  CellHAlign := hal;
  CellVAlign := val;
  CellTransparent := Flat;
end;

procedure TBaseCellGraphic.SetRadioButton(Value,Flat: Boolean;hal:TCellHAlign;val:TCellVAlign; Group: TRadioButtonGroup);
begin
  CellType := ctRadioButton;
  CellAngle := Integer(Group);
  CellBoolean := Value;
  CellHAlign := hal;
  CellVAlign := val;
  CellTransparent := Flat;
end;


procedure TBaseCellGraphic.SetIcon(AIcon: TIcon;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctIcon;
  CellIcon := aicon;
  CellHAlign := hal;
  CellVAlign := val;
end;

procedure TBaseCellGraphic.SetDataImage(idx: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctDataImage;
  CellIndex := idx;
  CellHAlign := hal;
  CellVAlign := val;
end;

procedure TBaseCellGraphic.SetMultiImage(Col,Row,dir: Integer;hal:TCellHAlign;val:TCellVAlign;notifier:TImageChangeEvent);
begin
  CellType := ctImages;
  CellHAlign := hal;
  CellVAlign := val;
  CellBoolean := dir = 0;
  CellBitmap := TBitmap(TIntList.Create(Col,Row));
  TIntList(CellBitmap).OnChange := notifier;
  CellCreated := True;
end;

procedure TBaseCellGraphic.SetImageIdx(idx: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctImageList;
  CellIndex := idx;
  CellHAlign := hal;
  CellVAlign := val;
end;

procedure TBaseCellGraphic.SetAngle(AAngle:smallint);
begin
  CellType := ctRotated;

  while AAngle < 0 do
    AAngle := AAngle + 360;

  while AAngle > 360 do
    AAngle := AAngle - 360;
  CellAngle := AAngle;
end;

constructor TColumnSize.Create(AOwner:TComponent);
begin
  inherited Create;
  Owner := AOwner;
  FStretchColumn := -1;
  Rows := arAll;
end;

destructor TColumnSize.Destroy;
begin
  inherited Destroy;
end;

procedure TColumnSize.Assign(Source: TPersistent);
begin
  if (Source is TColumnSize) then
  begin
    FRows := (Source as TColumnSize).Rows;
    FSave := (Source as TColumnSize).Save;
    FKey := (Source as TColumnSize).Key;
    FSection := (Source as TColumnSize).Section;
    FStretch := (Source as TColumnSize).Stretch;
    FStretchColumn := (Source as TColumnSize).StretchColumn;
    FSynchWithGrid := (Source as TColumnSize).SynchWithGrid;
    FSynchNormalCellsOnly := (Source as TColumnSize).SynchNormalCellsOnly;
    FLocation := (Source as TColumnSize).Location;
  end;
end;


constructor THTMLSettings.Create;
begin
  inherited Create;
  FSaveColor := True;
  FSaveFonts := True;
  FBorderSize := 1;
  FCellSpacing := 0;
  FCellPadding := 0;
  FWidth := 100;
  FExportImages := True;
  FColWidths := TIntList.Create(0,0);
  FImageBaseName := 'img';
  FImageFolder := 'images';
end;

destructor THTMLSettings.Destroy;
begin
  FColWidths.Free;
  inherited Destroy;
end;

procedure THTMLSettings.Assign(Source: TPersistent);
begin
  if (Source is THTMLSettings) then
  begin
    FBorderSize := (Source as THTMLSettings).BorderSize;
    FCellSpacing := (Source as THTMLSettings).CellSpacing;
    FCellPadding := (Source as THTMLSettings).CellPadding;
    FSaveColor := (Source as THTMLSettings).SaveColor;
    FSaveFonts := (Source as THTMLSettings).SaveFonts;
    FFooterFile := (Source as THTMLSettings).FooterFile;
    FFooterText := (Source as THTMLSettings).FooterText;
    FHeaderFile := (Source as THTMLSettings).HeaderFile;
    FHeaderText := (Source as THTMLSettings).HeaderText;
    FTableStyle := (Source as THTMLSettings).TableStyle;
    FPrefixTag := (Source as THTMLSettings).PrefixTag;
    FSuffixTag := (Source as THTMLSettings).SuffixTag;
    FSummary := (Source as THTMLSettings).Summary;
    FWidth := (Source as THTMLSettings).Width;
    FXHTML := (Source as THTMLSettings).XHTML;
    FConvertSpecialChars := (Source as THTMLSettings).ConvertSpecialChars;
    FAutoPreview := (Source as THTMLSettings).AutoPreview;
    FNonBreakingText := (Source as THTMLSettings).NonBreakingText;
    FImageBaseName := (Source as THTMLSettings).ImageBaseName;
    FImageFolder := (Source as THTMLSettings).ImageFolder;
  end;
end;

{ TPrintSettings }

constructor TPrintSettings.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FFont := TFont.Create;
  FHeaderFont := TFont.Create;
  FFooterFont := TFont.Create;
  FFixedFont := TFont.Create;
  FTitleLines := TStringList.Create;
  FPagePrefix := '';
  FPageSuffix := '';
  FPageNumSep := '/';
  FDateFormat := 'dd/mm/yyyy';
  FTitleSpacing := 0;
  FPageNumberOffset := 0;
  FMaxPagesOffset := 0;
  FBorders := pbSingle;
  FCentered := True;
  FUseDisplayFont := True;
  FRepeatFixedRows := False;
  FRepeatFixedCols := False;
  FBorderColor := clBlack;
  FPrintComments := True;
end;

destructor TPrintSettings.Destroy;
begin
  FFont.Free;
  FFixedFont.Free;
  FHeaderFont.Free;
  FFooterFont.Free;
  FTitleLines.Free;
  inherited Destroy;
end;

procedure TPrintSettings.Assign(Source: TPersistent);
begin
  FFooterSize := (Source as TPrintSettings).FooterSize;
  FHeaderSize := (Source as TPrintSettings).HeaderSize;
  FTime := (Source as TPrintSettings).Time;
  FDate := (Source as TPrintSettings).Date;
  FDateFormat := (Source as TPrintSettings).DateFormat;
  FPageNr := (Source as TPrintSettings).PageNr;
  FTitle := (Source as TPrintSettings).Title;
  FTitleText := (Source as TPrintSettings).TitleText;
  FTitleLines.Assign((Source as TPrintSettings).TitleLines);
  FFont.Assign((Source as TPrintSettings).Font);
  FixedFont.Assign((Source as TPrintSettings).FixedFont);
  FHeaderFont.Assign((Source as TPrintSettings).HeaderFont);
  FFooterFont.Assign((Source as TPrintSettings).FooterFont);
  FBorders := (Source as TPrintSettings).Borders;
  FBorderStyle := (Source as TPrintSettings).BorderStyle;
  FCentered := (Source as TPrintSettings).Centered;
  FRepeatFixedRows := (Source as TPrintSettings).RepeatFixedRows;
  FRepeatFixedCols := (Source as TPrintSettings).RepeatFixedCols;
  FLeftSize := (Source as TPrintSettings).LeftSize;
  FRightSize := (Source as TPrintSettings).RightSize;
  FColumnSpacing := (Source as TPrintSettings).ColumnSpacing;
  FRowSpacing := (Source as TPrintSettings).RowSpacing;
  FTitleSpacing := (Source as TPrintSettings).TitleSpacing;
  FOrientation := (Source as TPrintSettings).Orientation;
  FPagePrefix := (Source as TPrintSettings).PagePrefix;
  FPageSuffix := (Source as TPrintSettings).PageSuffix;
  FPageNumberOffset := (Source as TPrintSettings).PageNumberOffset;
  FMaxPagesOffset := (Source as TPrintSettings).MaxPagesOffset;
  FFixedWidth := (Source as TPrintSettings).FixedWidth;
  FFixedHeight := (Source as TPrintSettings).FixedHeight;
  FUseFixedHeight := (Source as TPrintSettings).UseFixedHeight;
  FUseFixedWidth := (Source as TPrintSettings).UseFixedWidth;
  FFitToPage := (Source as TPrintSettings).FitToPage;
  FJobName := (Source as TPrintSettings).JobName;
  FPageNumSep := (Source as TPrintSettings).PageNumSep;
  FNoAutoSize := (Source as TPrintSettings).NoAutoSize;
  FNoAutoSizeRow := (Source as TPrintSettings).NoAutoSizeRow;
  FPrintGraphics := (Source as TPrintSettings).PrintGraphics;
  FUseDisplayFont := (Source as TPrintSettings).UseDisplayFont;
  FUseDefaultOrientation := (Source as TPrintSettings).UseDefaultOrientation;
  FBorderColor := (Source as TPrintSettings).BorderColor;
  FPrintComments := (Source as TPrintSettings).PrintComments;
end;


procedure TPrintSettings.SetFixedFont(const Value: TFont);
begin
  FFixedFont.Assign(Value);
end;

procedure TPrintSettings.SetPrintFont(Value: TFont);
begin
  FFont.Assign(Value);
end;

procedure TPrintSettings.SetPrintHeaderFont(Value: TFont);
begin
  FHeaderFont.Assign(Value);
end;

procedure TPrintSettings.SetPrintFooterFont(Value: TFont);
begin
  FFooterFont.Assign(Value);
end;

procedure TPrintSettings.SetTitleLines(Value: TStringlist);
begin
  FTitleLines.Assign(Value);
end;

procedure TAdvInplaceEdit.WMCopy(var Msg: TMessage);
var
  Allow: Boolean;
begin
  Allow := True;
  if Assigned(FGrid.FOnClipboardCopy) then
     FGrid.FOnClipboardCopy(Self,Allow);
  if not Allow then Exit;
  inherited;
end;

procedure TAdvInplaceEdit.WMCut(var Msg: TMessage);
var
  Allow: Boolean;
begin
  Allow := True;
  if Assigned(FGrid.FOnClipboardCut) then
     FGrid.FOnClipboardCut(Self,Allow);
  if not Allow then Exit;
  inherited;
end;

procedure TAdvInplaceEdit.WMPaste(var Msg: TMessage);
var
  {$IFNDEF DELPHI_UNICODE}
  Data: THandle;
  Content: PChar;
  {$ENDIF}
  newstr: string;
  len: smallint;
  Newsl,Newss,i: Integer;
  Allow: Boolean;

  function InsertString(s:string):string;
  var
    ss: Integer;
  begin
    Result := self.Text;
    ss := SelStart;
    if SelLength = 0 then
    begin
      Insert(s,Result,ss+1);
      Newsl := 0;
      Newss := ss + Length(s);
    end
    else
    begin
      ss := SelStart;
      Delete(Result,ss + 1,selLength);
      Insert(s,Result,ss + 1);
      Newsl := Length(s);
      Newss := ss;
    end;
  end;

begin
  {$IFDEF DELPHI_UNICODE}
  if ClipBoard.HasFormat(CF_TEXT) then
  begin
    Allow := True;
    try
      NewStr := ClipBoard.AsText;
    except
      Exit;
    end;
  end;
  {$ENDIF}

  {$IFNDEF DELPHI_UNICODE}
  if not ClipBoard.HasFormat(CF_TEXT) then
    Exit;

  ClipBoard.Open;
  Data := GetClipBoardData(CF_TEXT);
  try
    if Data <> 0 then
      Content := PChar(GlobalLock(Data))
    else
      Content := nil
  finally
    if Data <> 0 then
      GlobalUnlock(Data);
  ClipBoard.Close;
  end;

  if Content = nil then
    Exit;

   Allow := True;
   NewStr := StrPas(Content);

  {$ENDIF}

  if Assigned(FGrid.FOnClipboardPaste) then
    FGrid.FOnClipboardPaste(Self,Allow);

  if not Allow then
    Exit;

  if Assigned(FGrid.OnClipboardBeforePasteCell) then
    FGrid.OnClipboardBeforePasteCell(Self,FGrid.Col,FGrid.Row,NewStr,Allow);

  if not Allow then
    Exit;

  Len := Length(NewStr);

  if (FLengthLimit > 0) and (Len > FLengthLimit) then
    Exit;

  if (Pos(#13#10,NewStr) = Len - 1) then
  begin
    Delete(NewStr,Len - 1,2);
  end;

  NewStr := InsertString(NewStr);

  if (Length(NewStr) > FLengthLimit) and (FLengthLimit > 0) then
    Exit;

  case FGrid.EditControl of
  edNumeric, edPositiveNumeric:
    begin
      if (IsType(Newstr) = AdvUtil.atNumeric) then
      begin
        if (Pos('-',NewStr) = 0) or (FGrid.EditControl = edNumeric) then
          self.Text := NewStr;
      end;
    end;
  edFloat, edPositiveFloat:
    begin
      if IsType(NewStr) in [AdvUtil.atNumeric,AdvUtil.atFloat] then
      begin
        if (Pos('-',NewStr) = 0) or (FGrid.EditControl = edFloat) then
          self.Text := NewStr;
      end;
    end;
  edValidChars:
    begin
      Allow := true;
      for i := 1 to length(NewStr) do
      begin
        if (pos(NewStr[i], FGrid.ValidChars) = 0) then
          Allow := false;
      end;
      if Allow then
        self.Text := NewStr;
    end;
  edLowerCase:self.Text := AnsiLowerCase(NewStr);
  edUpperCase:self.Text := AnsiUpperCase(NewStr);
  edMixedCase:self.Text := ShiftCase(NewStr);
  else
    self.Text := NewStr;
  end;

  FGrid.SetEditCell(Self.Text);
//  FGrid.CurrentCell := self.Text;

  SelStart := Newss;
  SelLength := Newsl;

  if Assigned(FGrid.OnClipboardAfterPasteCell) then
    FGrid.OnClipboardAfterPasteCell(Self,FGrid.Col,FGrid.Row,Text);
end;


procedure TAdvInplaceEdit.DoChange;
var
  s,c,d:string;
  i: Integer;
  se,ss: Integer;

begin
  SendMessage(Handle,EM_GETSEL,Integer(@se),LParam(@ss));

  if not WorkMode or (ss <> se) then
    Exit;

  if FGrid.LookupCaseSensitive then
    c := EditText
  else
    c := AnsiUpperCase(EditText);

  c := Copy(c,1,SelStart);

  if not Assigned(FGrid.LookupItems) then
    Exit;

  if (FGrid.LookupItems.Count > 0) and
     FGrid.Lookup then
    for i := 0 to FGrid.LookupItems.Count-1 do
    begin
      if FGrid.LookupCaseSensitive then
        d := FGrid.LookupItems.Strings[i]
      else
        d := AnsiUpperCase(FGrid.LookupItems.Strings[i]);

      if Pos(c,d) = 1  then
      begin
        s := Copy(Text,1,Length(c)) + Copy(FGrid.LookupItems.Strings[i],Length(c)+1,255);
        EditText := s;
        SendMessage(Handle,EM_SETSEL,Length(c),Length(s));
        GotKey := False;
        Exit;
      end;
    end;
end;

procedure TAdvInplaceEdit.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  if (msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
    Msg.Result := 1;
end;

procedure TAdvInplaceEdit.WMKeyDown(var Msg:TWMKeydown);
var
  Key: Char;
  oldval, txt: string;
  updown: boolean;
  ikey: word;
  ss: TShiftState;
begin
  FGrid.Edit_WMKeyDown(Msg);
  updown := false;
  FOldSelStart := SelStart;

  if Msg.CharCode = VK_ESCAPE then
  begin
    Self.Text := FGrid.OriginalCellValue;
    inherited;
    FGrid.HideInplaceEdit;
  end;

  if (Msg.CharCode = ord('A')) and (GetKeyState(VK_CONTROL) and $8000 = $8000) and (GetKeyState(VK_RMENU) and $8000 <> $8000) then
  begin
    SelStart := 0;
    SelLength := Length(Text);
    Msg.CharCode := 0;
    Msg.Result := 1;
    Exit;
  end;

  if (Msg.CharCode = VK_RETURN) and (GetKeyState(VK_CONTROL) and $8000 = $8000) and not
     (FGrid.Navigation.AllowCtrlEnter and (FGrid.WordWrap or FGrid.MultiLineCells)) then
  begin
    Msg.CharCode := 0;
    Msg.Result := 1;

    ikey := VK_RETURN;
    if Assigned(FGrid.OnKeyDown) then
      FGrid.OnKeyDown(FGrid, ikey, [ssCtrl]);
    Exit;
  end;

  //new cell value
  txt := self.Text;
  //get original cell value
  oldval := FGrid.FOldCellText;

  if (Msg.CharCode = VK_TAB) and FGrid.ShouldHandleTab then
  begin
    if not FGrid.ValidateCell(txt) then
    begin
      self.Text := FGrid.FNewCellText;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(Text);
      FGrid.FOldCellText := oldval;

      ss := [];
      ikey := VK_TAB;
      if (GetKeyState(VK_SHIFT) and $8000 = $8000) then
        ss := [ssShift];
      if Assigned(FGrid.OnKeyDown) then
        FGrid.OnKeyDown(FGrid, ikey, ss);
      Exit;
    end;

    self.Text := FGrid.FNewCellText;

    FGrid.HideInplaceEdit;

    if (goTabs in FGrid.Options) then
    begin
      Msg.CharCode := 0;
      Msg.Result := 1;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
    end
    else
    begin
      PostMessage(FGrid.Handle, WM_KEYDOWN, VK_TAB, 0);
    end;
    Exit;
  end;

  if (((Msg.CharCode in [VK_LEFT]) and (SelStart = 0)) or
     ((Msg.CharCode in [VK_RIGHT]) and (SelStart = length(Text)))) and
     (GetKeystate(VK_SHIFT) and $8000 = $8000) and (FGrid.Navigation.CursorWalkEditor) then
  begin
    FGrid.FValidating := true;
    FGrid.CurrentCell := txt;
    FGrid.FValidating := False;

    if not FGrid.ValidateCell(txt) then
    begin
      self.Text := FGrid.FNewCellText;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(txt);
      Repaint;
      FGrid.FOldCellText := oldval;
      Exit;
    end;

    self.Text := FGrid.FNewCellText;

    FGrid.HideInplaceEdit;
    FGrid.SetFocus;
    Exit;
  end;


  if ((Msg.CharCode in [VK_UP]) and (SendMessage(self.Handle,EM_LINEFROMCHAR,SelStart,0) = 0)) or
     ((Msg.CharCode in [VK_DOWN]) and
     ((SendMessage(self.Handle,EM_LINEFROMCHAR,SelStart,0) = SendMessage(self.Handle,EM_LINEFROMCHAR,Length(self.Text),0)))) then
  begin
    FGrid.FValidating := true;
    FGrid.CurrentCell := txt;
    FGrid.FValidating := False;

    if not FGrid.ValidateCell(txt) then
    begin
      self.Text := FGrid.FNewCellText;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(txt);
      Repaint;
      FGrid.FOldCellText := oldval;
      Exit;
    end;
    self.Text := FGrid.FNewCellText;
    updown := true;
  end;


  if (Msg.CharCode = VK_RETURN) and not FGrid.Navigation.LineFeedOnEnter and
     (GetKeystate(VK_CONTROL) and $8000 = $0) then
  begin

    if not FGrid.ValidateCell(txt) then
    begin
      self.Text := FGrid.FNewCellText;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(Text);

      // Repaint;
      FGrid.FOldCellText := oldval;
      Exit;
    end;

    self.Text := FGrid.FNewCellText;
  end;

  if (Msg.CharCode = VK_HOME) and
     (GetKeystate(VK_CONTROL) and $8000 = $0) and
     (GetKeystate(VK_SHIFT) and $8000 = $0) then
  begin
    SelStart := 0;
  end;

  if (Msg.CharCode = VK_END) and
     (GetKeystate(VK_CONTROL) and $8000 = $0) and
     (GetKeystate(VK_SHIFT) and $8000 = $0) then
  begin
    SelStart := Length(self.Text);
  end;


  if (Msg.CharCode = VK_RETURN) and
     (GetKeystate(VK_CONTROL) and $8000 = $8000) and
     FGrid.Navigation.LineFeedOnEnter then
  begin
    Key := #13;
    inherited KeyPress(Key);
  end
  else
  begin
    inherited;

    if FGrid.MouseActions.DisjunctRowSelect and updown then
    begin
      FGrid.ClearRowSelectInt;
      FGrid.RowSelect[FGrid.Row] := True;
    end;
  end;
end;

procedure TAdvInplaceEdit.WMKeyUp(var Msg:TWMKeydown);
var
  i: Integer;
  pt: TPoint;
begin
  inherited;

  if SelStart > 0 then
  begin
    i := SendMessage(Handle,EM_POSFROMCHAR,SelStart - 1,0);
    pt.x := loword(i);
    pt.y := hiword(i);
    FGrid.EditProgress(Text,pt,SelStart);
  end;

  if pos('=',Text) = 1 then
    FGrid.SetCellSelectMode(true)
  else
    FGrid.SetCellSelectMode(false);
end;

procedure TAdvInplaceEdit.WMLButtonDblClk(var Message: TWMLButtonDblClk);
begin
  inherited;
  if Assigned(FGrid.OnDblClickCell) then
    FGrid.OnDblClickCell(FGrid,FGrid.Row,FGrid.Col);
end;

procedure TAdvInplaceEdit.WMChar(var Msg: TWMKey);
var
  OldSelStart: Integer;
  s:string;
  Key: char;

begin
  if (Msg.CharCode = ord('.')) and
     FGrid.ExcelStyleDecimalSeparator and
     (Msg.KeyData and $400000 = $400000) then
  begin
    Msg.CharCode := Ord(DecimalSeparator);
  end;

  if (Msg.CharCode = 1) and
     (GetKeyState(VK_CONTROL) and $8000 = $8000) then
  begin
    Msg.CharCode := 0;
    Msg.Result := 1;
    Exit;
  end;

  if (Msg.CharCode = 10) and
     (GetKeyState(VK_CONTROL) and $8000 = $8000) and not
     (FGrid.Navigation.AllowCtrlEnter and (FGrid.WordWrap or FGrid.MultiLineCells)) then
  begin
    Msg.CharCode := 0;
    Msg.Result := 1;
    Exit;
  end;

  if (FLengthLimit > 0) and (Length(Text) = FLengthLimit) and (SelLength = 0)
     and (msg.CharCode <> VK_BACK) and (msg.CharCode <> VK_ESCAPE) and (msg.CharCode <> VK_RETURN) then
  begin
    Exit;
  end;

  if (FGrid.EditControl in [edNormal,edValidChars,edCapital,edUpperCase,edLowerCase,edMixedCase]) then
  begin
    if (msg.CharCode = VK_RETURN) and
       FGrid.Navigation.LineFeedOnEnter then
    begin
      DefaultHandler(Msg);
      Exit;
    end;
  end;

  case FGrid.EditControl of
  edNormal,edPassword: inherited;
  edNumeric:
    begin
      if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
        inherited
      else
        if (msg.CharCode in Numeric_Characters) and
            not ((msg.CharCode = ord('-')) and (pos('-',Text) > 0)) and
            not ((msg.CharCode = ord('-')) and (SelStart <> 0)) then inherited else MessageBeep(0);
    end;
  edValidChars:
    begin
      if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
        inherited
      else
      begin
        if (FGrid.ValidChars <> '') then
          if (pos(chr(msg.CharCode), FGrid.ValidChars) <> 0) or (msg.CharCode in [8,10,13]) then inherited else MessageBeep(0)
        else
        {$IFDEF DELPHI_UNICODE}
          if CharInSet(chr(msg.CharCode), FGrid.ValidCharSet) or (msg.CharCode in [8,10,13]) then inherited else MessageBeep(0);
        {$ENDIF}
        {$IFNDEF DELPHI_UNICODE}
          if (chr(msg.CharCode) in FGrid.ValidCharSet) or (msg.CharCode in [8,10,13]) then inherited else MessageBeep(0);
        {$ENDIF}
      end;
    end;
  edPositiveNumeric:
      if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
        inherited
      else
        if msg.CharCode in Positive_Numeric_Characters then inherited else MessageBeep(0);
  edFloat, edPositiveFloat:
    begin
      if CheckFloatNumNoExp(Chr(Msg.CharCode)) and ((msg.CharCode <> ord('-')) or (FGrid.EditControl = edFloat)) then

      //if (msg.CharCode in Float_Characters) and ((msg.CharCode <> ord('-')) or (FGrid.EditControl = edFloat)) then
      begin
        if ((Msg.CharCode = ord(DecimalSeparator)) and
           ((pos(DecimalSeparator,self.Text) > 0) and (pos(DecimalSeparator,self.SelText) = 0) )) then
          Exit;

        if (Msg.CharCode = ord(ThousandSeparator)) then
          Exit;

        if (msg.CharCode = ord('-')) and
           (((SelStart<>0) or (pos('-',self.Text)>0)) and not (pos('-',self.SelText)>0)) then
        begin
          MessageBeep(0);
          Exit;
        end;
        inherited;
      end;

      if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
        inherited;
    end;
  edCapital,edUpperCase:
    begin
      s := AnsiUpperCase(chr(msg.CharCode));
      msg.CharCode := Ord(s[1]);
      inherited;
    end;
  edLowerCase:
    begin
      s := AnsiLowerCase(chr(msg.CharCode));
      msg.CharCode := Ord(s[1]);
      inherited;
    end;
  edMixedCase:
    begin
      OldSelStart := SelStart;
      inherited;
      self.Text := ShiftCase(self.Text);
      SelStart := OldSelStart + 1;
    end;
  end;

  if FGrid.Navigation.AdvanceAuto and FGrid.Navigation.AdvanceOnEnter then
  if ((FGrid.MaxEditLength > 0) and (Length(self.Text) = FGrid.MaxEditLength)) and ((SelLength = 0) and (SelStart = Length(Text))) then
  begin
    Key := #13;
    FGrid.KeyPress(Key);
  end;
end;

procedure TAdvInplaceEdit.WMKillFocus(var Msg: TWMKillFocus);
begin
  FGrid.FStartEditChar := #0;

  if FGrid.LookupHistory then
  begin
    if FGrid.LookupItems.IndexOf(Text) = -1 then
    begin
      FGrid.LookupItems.Add(Text);
    end;
  end;

  FGrid.SetCellSelectMode(False);

  inherited;

  if FAltBack then
    Exit;

  // do not close editor when active window changes...
  {
  if not (GetActiveWindow = FGrid.GetParentForm(FGrid).Handle) then
  begin
    FGrid.SetCellSelectMode(True);
    FGrid.HideInplaceEdit;
    FGrid.EditProgress(self.Text,Point(-1,-1),-1);
    FGrid.DoneEditing(FColE, FRowE);
    Exit;
  end;
  }

  if (msg.FocusedWnd <> FGrid.Handle) then
  begin
    try
      FGrid.FValidating := true;
      FGrid.ValidateCell(Text);
      FGrid.FValidating := false;
      Text := FGrid.CurrentCell;
    finally
      FGrid.HideInplaceEdit;
      FGrid.FEditing := False;

      if FGrid.EditMode then
        FGrid.EditMode := False;
    end;

    FGrid.SelectCell(FColE,FRowE);
  end;

  //if FGrid.EditMode and (FGrid.FixedRows > 0) and not (FGrid.RowHeights[0] = 0) then
  //  FGrid.EditMode := False;

  FGrid.FNoEditChange := true;
  Text := FGrid.CurrentCell;
  FGrid.FNoEditChange := false;
  FGrid.EditProgress(self.Text,Point(-1,-1),-1);

  if FGotFocus then
  begin
    FGotFocus := false;
    if not TAdvStringGridEx(FGrid).EditCellSet then
      FGrid.DoneEditing(FGrid.RemapCol(FColE),FRowE);
  end;
end;

procedure TAdvInplaceEdit.WMSetFocus(var Msg: TWMSetFocus);
var
  lpPoint: TPoint;
  i: Integer;
begin
  inherited;

  FGotFocus := true;
  FGrid.FNoEditChange := false;

  FLengthLimit := FGrid.GetEditLimit;
  MaxLength := FLengthLimit;

  if Editmask <> '' then
    with FGrid do
    begin
      if not LButFlg and Navigation.ImproveMaskSel then
      begin
        SelStart := 0;
        SelLength := 1;
        Exit;
      end;
    end;

  if not FGrid.Navigation.EditSelectAll then
  begin
    SelStart := length(Text);
    SelLength := 1;
  end;

  if not FGrid.LButFlg then
    Exit;

  GetCursorPos(lpPoint);
  lpPoint := ScreenToClient(lpPoint);

  if (lpPoint.x < 0) or (lpPoint.y < 0) or
     (lpPoint.x > Width) or (lpPoint.y > Height) then
    Exit;

  i := SendMessage(Self.Handle,EM_CHARFROMPOS, 0,makelong(lpPoint.x,lpPoint.y));
  if i = -1 then
    Exit;

  SelStart := LoWord(i);
  SelLength := 0;

  FGrid.LButFlg := False;
end;


constructor TAdvInplaceEdit.Create(AOwner: TComponent);
begin
  inherited;
  FGrid := TAdvStringGrid(AOwner);
  FAltBack := false;
end;

procedure TAdvInplaceEdit.CreateWnd;
begin
  inherited CreateWnd;

  if FGrid.EditControl = edPassword then
  begin
    SendMessage(Handle, EM_SETPASSWORDCHAR, Ord(FGrid.PassWordChar), 0);
  end;

  FLengthLimit := FGrid.GetEditLimit;
end;

procedure TAdvInplaceEdit.CreateParams(var Params:TCreateParams);
const
  WordWraps: array[Boolean] of Integer = (0,ES_AUTOHSCROLL);
begin
  inherited CreateParams(Params);

  FGrid := (Parent as TAdvStringGrid);

  FWordWrap := FGrid.WordWrap;

  if FVAlign then
  begin
    Params.Style := Params.Style AND NOT ES_LEFT;
    Params.Style := Params.Style OR ES_RIGHT;
  end;

  if FGrid.EditControl = edPassword then
  begin
    Params.Style := Params.Style OR ES_PASSWORD;
    // multiline conflicts with ES_PASSWORD!
    Params.Style := Params.Style AND NOT ES_MULTILINE;
  end;

  Params.Style := Params.Style AND NOT WordWraps[fwordwrap];
  Params.Style := Params.Style OR ES_WANTRETURN;

//  if not FGrid.Navigation.AllowCtrlEnter then
//    Params.Style := Params.Style AND NOT ES_MULTILINE;

  GotKey := False;
  WorkMode := True;
end;

procedure TAdvInplaceEdit.UpdateContents;
var
  AState: TGridDrawState;
  HAlign: TAlignment;
  VAlign: TVAlignment;
  WW: Boolean;
  AColorTo, AMirrorColor, AMirrorColorTo: TColor;
  GD: TCellGradientDirection;

begin
  FGrid.FNoEditChange := true;

  inherited UpdateContents;

  FGrid.FNoEditChange := false;

  with FGrid do
  begin
    AState := [];
    GetVisualProperties(Col,Row,AState,False,False,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlign,VAlign,WW,GD);
    Self.Color := Canvas.Brush.Color;
    Self.Font.Assign(Canvas.Font);

    {$IFDEF DELPHIXE6_LVL}
    if not (seClient in StyleElements) then
      Font.Color := Canvas.Font.Color;
    {$ENDIF}

    FColE := Col;
    FRowE := Row;

    {$IFDEF DELPHI_UNICODE}
    Alignment := HAlign;
    {$ENDIF}

    DoGetEditorProp(Col,Row,nil);

    PostMessage(Self.Handle, WM_EDITPROP,0,0);
  end;
end;

procedure TAdvInplaceEdit.UpdateSize;
var
  r: TRect;
  Hold: Integer;
  dr: TRect;
  d, dh: integer;

begin
  r := FGrid.CellRect(FGrid.Col,FGrid.Row);

  Top := r.Top;
  Left := r.Left;

  if FGrid.UseRightToLeftAlignment then
  begin
    r.Left := r.Left + 1;
    if (FGrid.IsMergedCell(FGrid.Col, FGrid.Row)) then
    begin
      dr := FGrid.CellRect(FGrid.LeftCol,FGrid.TopRow);
      Hold := r.Right - r.Left;
      r.Left := dr.Left - (r.Right - dr.Right) + 1;
      r.Right := r.Left + Hold;
    end;
  end;

  d := 1;
  if FGrid.GridLineWidth > 1 then
    d := d + FGrid.GridLineWidth div 2;

  SetWindowPos(Handle, HWND_TOP, r.Left, r.Top, r.Right - r.Left - d,r.Bottom - r.Top - d,
    SWP_NOREDRAW or SWP_NOZORDER or SWP_SHOWWINDOW);

  dh := 1;
  if not FGrid.WordWrap and (FGrid.VAlignment <> vtaTop) then
  begin
    dh := r.Bottom - r.Top;

    if FGrid.VAlignment = vtaCenter then
      dh := (dh - 2 - FGrid.Canvas.TextHeight('gh')) div 2
    else
      dh := (dh - 4 - FGrid.Canvas.TextHeight('gh'));
  end;

  R := Rect(3, 2 + dh, Width - 4, Height - 0);

  SendMessage(Handle, EM_SETRECTNP, 0, LParam(@R));
  SendMessage(Handle, EM_SCROLLCARET, 0, 0);

  if FGrid.GridLineWidth > 1 then
    FGrid.Invalidate;

  if Grid.Focused then
    Windows.SetFocus(Handle);
end;

procedure TAdvInplaceEdit.WndProc(var Msg: TMessage);
var
  AState: TGridDrawState;
  HAlign: TAlignment;
  VAlign: TVAlignment;
  WW: Boolean;
  AColorTo, AMirrorColor, AMirrorColorTo: TColor;
  GD: TCellGradientDirection;

begin
  if (Msg.Msg = WM_EDITPROP) then
  begin
    //if not FGrid.EditMode then
    //  FGrid.EditMode := true;

    AState := [];
    FGrid.GetVisualProperties(FGrid.Col,FGrid.Row,AState,False,False,True,FGrid.Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,FGrid.Canvas.Font,HAlign,VAlign,WW,GD);
    Self.Color := FGrid.Canvas.Brush.Color;
    Self.Font.Assign(FGrid.Canvas.Font);

    FColE := FGrid.Col;
    FRowE := FGrid.Row;

    {$IFDEF DELPHI_UNICODE}
    Alignment := HAlign;
    {$ENDIF}

    FGrid.DoGetEditorProp(FGrid.Col,FGrid.Row,nil);

    {$IFDEF DELPHIXE3_LVL}
    //BoundsChanged;
    {$ENDIF}
    {$IFDEF DELPHIXE5_LVL}
    //UpdateSize;
    {$ENDIF}
  end;

  if (Msg.Msg = WM_SYSKEYDOWN) and (Msg.WParam = VK_BACK) then
    FAltBack := true;

  if (Msg.Msg = WM_SYSKEYUP) and (Msg.WParam = VK_BACK) then
    FAltBack := false;

  inherited;
end;


procedure TAdvInplaceEdit.Change;
begin
  inherited Change;

  if not FGrid.FNoEditChange then
  begin
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
  end;
end;

procedure TAdvInplaceEdit.BoundsChanged;
begin
  inherited;
  UpdateSize;
end;

procedure TAdvInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
var
  res1,res2: integer;
  swg: boolean;

begin
  FSelKeyDown := SelStart;

  case Key of
  VK_BACK,VK_DELETE:WorkMode := False;
  VK_UP:
  begin
    if SendMessage(self.Handle,EM_LINEFROMCHAR,SelStart,0) > 0 then
      Exit;
  end;
  VK_DOWN:
  begin
    res1 := SendMessage(self.Handle,EM_LINEFROMCHAR,SelStart,0);
    res2 := SendMessage(self.Handle,EM_LINEFROMCHAR,Length(self.Text),0);
    if (res1 < res2) then
      Exit;
  end;
  VK_RETURN:
  begin
    if not FGrid.Navigation.AllowCtrlEnter and (FGrid.WordWrap or FGrid.MultiLineCells) then
      FGrid.FEditing := False;

    // ctrl-enter pressed for a new line
    if (ssCtrl in Shift) or (ssShift in Shift) then
    with FGrid do
    begin
      if FSizeWhileTyping.Height and MultiLineCells then
      begin
        swg := ColumnSize.FSynchWithGrid;
        ColumnSize.FSynchWithGrid := false;

        if LinesInText(self.Text + #13#10 + ' ',FMultiLineCells) < MaxLinesInRow(Row) then
          AutoSizeRow(Row)
        else
          SizeToLines(Row,LinesInText(self.Text + #13#10 + ' ',FMultiLineCells),YOffsetSize);

        ColumnSize.FSynchWithGrid := swg;

        if Assigned(OnEndRowSize) then
          OnEndRowSize(FGrid,Row);
      end;
    end;
  end
  else
    WorkMode := True;
  end;

  FGrid.EditKeyDown(Key, Shift);

  inherited KeyDown(Key,shift);
end;

procedure TAdvInplaceEdit.KeyUp(var Key: Word; Shift: TShiftState);
var
  am: TAdvanceDirection;
  csx: integer;
  swg: boolean;
  FCellText: string;

begin
  case Key of
  VK_RIGHT:
  begin
    if (self.SelLength = 0) and (FOldSelStart = Length(Text)) and (Shift = []) then
      with FGrid do
      begin
        if Navigation.CursorWalkEditor then
        begin
          FCellText := self.Text;

          Key := 0;
          csx := CellSpan(Col,Row).X + 1;

          if (Col < ColCount - 1 - FixedRightCols) and HasStaticEdit(Col + csx, Row) then
          begin
            if ValidateCell(Self.Text) then
            begin
              HideInplaceEdit;
              Col := Col + csx;
            end;
          end
          else
          begin
            if ValidateCell(Self.Text) then
            begin
              am := Navigation.AdvanceDirection;
              if not (am in [adLeftRight, adLeftRightInRow]) then
                Navigation.AdvanceDirection := adLeftRight;
              AdvanceEdit(Col,Row,True,True,True,False, True);
              Navigation.AdvanceDirection := am;

              if not Navigation.CursorWalkAlwaysEdit then
              begin
                HideInplaceEdit;
                Key := 0;
              end
              else
                Key := VK_RETURN;
            end
            else
            begin
              Key := 0;
              self.Text := FCellText;
              SelectAll;
            end;
          end;
        end;
      end;
  end;
  VK_LEFT:
  begin
    if (self.SelLength = 0) and (FSelKeyDown = 0) and (SelStart = 0) and (Shift = []) then
    with FGrid do
    begin
      if Navigation.CursorWalkEditor then
      begin
        FCellText := self.Text;
        Key := 0;
        if (Col > FixedCols) and HasStaticEdit(Col - 1,Row) then
        begin
          if ValidateCell(Self.Text) then
          begin
            HideInplaceEdit;
            Col := Col - 1;
          end;
        end
        else
        begin
          if ValidateCell(Self.Text) then
          begin
            HideInplaceEdit;
            am := Navigation.AdvanceDirection;
            if not (am in [adLeftRight, adLeftRightInRow]) then
              Navigation.AdvanceDirection := adLeftRight;
            AdvanceEdit(Col,Row,True,True,False,False,True);
            Navigation.AdvanceDirection := am;
            if not Navigation.CursorWalkAlwaysEdit then
            begin
              HideInplaceEdit;
              Key := 0;
            end
            else
              Key := VK_RETURN;
          end
          else
          begin
            Key := 0;
            self.Text := FCellText;
            SelectALl;
          end;
        end;
      end;
    end;
  end;
  end;

  if Key in [VK_LEFT,VK_RIGHT] then
    Exit;

  inherited KeyUp(Key,shift);

  self.DoChange;

  with FGrid do
  begin
    if FSizeWhileTyping.Width then
      SizeToWidth(Col,True);

    // incompatible with virtual cells
    if FSizeWhileTyping.Height and WordWrap then
    begin
      swg := ColumnSize.FSynchWithGrid;
      ColumnSize.FSynchWithGrid := false;

      AutoSizeRow(Row);

      ColumnSize.FSynchWithGrid := swg;

      if Assigned(OnEndRowSize) then
        OnEndRowSize(FGrid,Row);
    end;
  end;
end;


procedure TAdvInplaceEdit.KeyPress(var Key: Char);
begin
  if (Key = #13) and not FGrid.Navigation.LineFeedOnEnter then
  begin
    if not FGrid.Validatecell(Text) then
    begin
      Text := FGrid.CurrentCell;
      Key := #0;
      Exit;
    end;
  end;

  inherited KeyPress(Key);

  if FGrid.Navigation.AdvanceAuto then
  if (Pos(' ',Text) = 0) and (SelStart = Length(Text)) and
     (EditMask <> '') then
  begin
    Key := #13;
    FGrid.KeyPress(Key);
  end;
end;

procedure TAdvInplaceEdit.SetVAlign(Value: Boolean);
begin
  FVAlign := Value;
  ReCreateWnd;
end;

procedure TAdvInplaceEdit.SetWordWrap(Value: Boolean);
begin
  FWordWrap := Value;
  ReCreateWnd;
end;


function TAdvStringGrid.BoolToCheckBoxState(bChecked: Boolean): TCheckBoxState;
begin
  if( bChecked ) then
    Result := cbChecked
  else
    Result := cbUnchecked;
end;

procedure TAdvStringGrid.AddTriStateCheckBoxColumn(ACol: integer; state: TCheckBoxState );
var
  i,fr: integer;
begin
  if MouseActions.CheckAllCheck then
    fr := 0
  else
    fr := FixedRows;
  for i := fr to RowCount - 1 do
  begin
    AddCheckBox( ACol, i, state);
  end;
end;

procedure TAdvStringGrid.AddCheckBox(ACol, ARow: Integer; State: TCheckBoxState );
begin
  if (ACol >= ColCount + NumHiddenColumns) or
     (ARow >= RowCount + NumHiddenRows) then
     raise Exception.Create('Invalid cell');

  with CreateCellGraphic(ACol,ARow) do
  begin
    case VAlignment of
    vtaTop: SetCheckBox(state, True, haBeforeText, vaTop);
    vtaCenter: SetCheckBox(state, True, haBeforeText, vaCenter);
    vtaBottom: SetCheckBox(state, True, haBeforeText, vaBottom);
    end;
  end;
end;

function TAdvStringGrid.GetCheckBoxState(ACol, ARow: Integer; var state: TCheckBoxState): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;
begin
  Result := False;

  if (NumHiddenRows > 0) then
  begin
    cp := TCellProperties(GetAllGraphicsObject(ACol,ARow));

    if Assigned(cp) then
    begin
      cg := TCellGraphic(GetCPGraphicObject(cp));

      if Assigned(cg) then
      begin
        if (cg.CellType = ctCheckBox) then
        begin
          state := BoolToCheckBoxState( cg.CellBoolean );
          Result := True;
        end;

        if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
        begin
          state := BoolToCheckBoxState(AllCells[ACol,ARow] = GetCheckTrue(ACol,ARow));
          Result := True;
        end;

        if (cg.CellType = ctTriStateCheckBox) then
        begin
          state := cg.CellCheckBoxState;
          Result := True;
        end;

        if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
        begin
          state := BoolToCheckBoxState(RowSelect[ARow]);
          Result := True;
        end;
      end;
    end
    else
    begin
      cg := GetCellGraphic(ACol, ARow);

      if cg = Nil then
        Exit;

      if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
      begin
        state := BoolToCheckBoxState(cg.CellBoolean);
        Result := True;
      end;

      if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
      begin
        state := BoolToCheckBoxState(Cells[ACol,ARow] = GetCheckTrue(ACol,ARow));
        Result := True;
      end;

      if ( cg.CellType = ctTriStateCheckBox) then
      begin
        state := cg.CellCheckBoxState;
        Result := True;
      end;
    end;
  end
  else
  begin
    cg := GetCellGraphic(ACol,ARow);
    if cg = Nil then
      Exit;

    if (cg.CellType = ctCheckBox) then
    begin
      state := BoolToCheckBoxState(cg.CellBoolean);
      Result := True;
    end;

    if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
    begin
      state := BoolToCheckBoxState(Cells[ACol,ARow] = GetCheckTrue(ACol,ARow));
      Result := True;
    end;

    if ( cg.CellType = ctTriStateCheckBox) then
    begin
      state := cg.CellCheckBoxState;
      Result := True;
    end;

    if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
    begin
      state := BoolToCheckBoxState(RowSelect[ARow]);
      Result := True;
    end;
  end;
end;

function TAdvStringGrid.GetParentForm(Control: TControl): TCustomForm;
begin
  Result := nil;

  if Assigned(Control) then
  begin
    if Control is TCustomForm then
    begin
      Result := Control as TCustomForm;
    end
    else
    begin
      if Assigned(Control.Parent) then
        Result := GetParentForm(Control.Parent);
    end;
  end;
end;

function TAdvStringGrid.GetEditMask(ACol, ARow: Longint): string;
var
  s: string;
begin
  s := FEditMask;
  if Assigned(OnGetEditMask) then
    OnGetEditMask(self, ACol, ARow, s);
  Result := s;
end;

function TAdvStringGrid.CreateEditor: TInplaceEdit;
begin
  Result := TAdvInplaceEdit.Create(Self);
end;

procedure LoadIconFromRes(AIcon: TIcon; Instance: THandle; AName: string);
begin
{$IFDEF DELPHI2006_LVL}
  AIcon.LoadFromResourceName(Instance, AName);
{$ENDIF}

{$IFNDEF DELPHI2006_LVL}
  AIcon.Handle := LoadIcon(Instance, PChar(AName));
{$ENDIF}
end;

constructor TAdvStringGrid.Create(AOwner:TComponent);
var
  i: Integer;
  VerInfo: TOSVersioninfo;
  FDesignTime: boolean;
  icon: TIcon;
  mni: TMenuItem;
begin
  inherited Create(AOwner);

  vscrlctrl := nil;
  hscrlctrl := nil;

  ControlStyle := ControlStyle + [csAcceptsControls];

  FDesignTime := (csDesigning in ComponentState) and not
    ((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState));

  {$IFDEF DELPHI2010_LVL}
  DrawingStyle := gdsClassic;
  {$ENDIF}

  FTouchScrollPt := Point(-1,-1);
  FLastTabCol := -1;
  FLastTabRow := -1;
  FHoverLink := -1;
  ptdown.Y := -1;
  ptdown.X := -1;
  {$IFDEF DELPHI_UNICODE}
  FEncoding := TEncoding.UTF8;
  {$ENDIF}

  FTones.Background.BrushColor := clNone;
  FTones.Background.BorderColor := clNone;

  FInWorkbook := false;
  FShowColNrs := true;
  FSaveFormula := false;
  FOleDragList := nil;
  FOleDragCol := -1;
  FISelect := nil;
  FOldOfficeTheme := otUnknown;
  FLastDesignChoice := -1;
  FFitCellsInGrid := True;
  FFilterNormalCellsOnly := True;
  FVirtualEdit := False;
  FValidateDblClick := False;
  FLastScrollCode := $FF;

  FFooterPanel := CreateFooter;
  FFooterPanel.Align := alBottom;
  FFooterPanel.Height := 0;
  FFooterPanel.BorderWidth := 0;

  FSearchPanel := TSearchPanel.Create(Self);
  FSearchPanel.Align := alBottom;
  FSearchPanel.Height := 0;
  FSearchPanel.BorderWidth := 0;
  FSearchPanel.OnEditChange := SearchEditChange;
  FSearchPanel.OnBackwardClick := SearchBackward;
  FSearchPanel.OnForwardClick := SearchForward;
  FSearchPanel.OnExitClick := SearchExit;
  FSearchPanel.OnHighlightClick := SearchHighLight;
  FSearchPanel.OnMatchCaseClick := SearchMatchCase;
  FScrollTimer := nil;
  FScrollStart := false;
  FScrollEnd := false;

  FHiddenRowLookup := nil;
  FHTMLKeepLineBreak := true;

  FAutoColor := TAutoColor.Create;

  cf := TFont.Create;

  FFocusHelper := TFocusHelper.Create(Self);

  FSearchFooter := TSearchFooter.Create(Self, FDesignTime);
  FSearchFooter.OnChange := SearchChanged;

  FFloatingFooter := TFloatingFooter.Create(Self);

  FPrintSettings := TPrintSettings.Create(Self);
  FHTMLSettings := THTMLSettings.Create;
  FSortSettings := TSortSettings.Create(Self);
  FDragDropSettings := TDragDropSettings.Create(Self);
  FDragScrollOptions := TDragScrollOptions.Create;

  FControlLook := TControlLook.Create(Self);
  FNavigation := TNavigation.Create;
  FNavigation.OnChange := OnNavigationChanged;
  FColumnSize := TColumnSize.Create(Self);
  FCellNode := TCellNode.Create(Self);
  FBands := TBands.Create;
  FBands.OnChange := BandsChanged;

  FSizeWhileTyping := TSizeWhileTyping.Create;
  FMouseActions := TMouseActions.Create(Self);
  FMouseActions.OnChange := OnMouseActionsChanged;
  FMouseActions.OnIsDesigning := OnMouseActionsIsDesigning;
  FMouseActions.OnInvalidate := OnMouseActionsInvalidate;

  FGrouping := TGrouping.Create;
  FColumnHeaders := TStringList.Create;
  FImageCache := THTMLPictureCache.Create;
  FColumnHeaders.OnChange := ColHeaderChanged;
  FLastValidation := true;
  FIsGrouping := false;
  FAutoFilterUpdate := true;
  FPaintCount := 0;
  FFilterCol := -1;

  FHoverFixedX := -1;
  FHoverFixedY := -1;
  FHoverFixedCells := hfNone;
  FBlockCellChange := false;
  FUseInternalHintClass := true;
  FSelectionColorMixerFactor := 50;
  FHintShowLargeTextPos := hpCell;

  FFilterLevel := 0;
  FFilterDropDownColumns := fdNormal;
  FFilterDropDownMultiCol := True;

  FXMLEncoding := 'ISO-8859-1';
  FFilterDropDownClear := '(All)';

  FNoAutoAdvance := false;

  FOrigColSizes := TIntList.Create(-1,-1);
  FSuppressColSizes := TIntList.Create(-1,-1);

  FFixedFont := TFont.Create;
  FFixedFont.Name := 'Tahoma';
  FFixedFont.Style := [fsBold];

  FLoaded := false;
  FIsColChanging := false;
  FShowDesignHelper := true;

  //if (csDesigning in ComponentState) then
  //  Font.Name := 'Tahoma';

  FEnhRowColMove := True;
  FFixedFont.OnChange := FixedFontChanged;

  FActiveCellFont := TFont.Create;

  if (csDesigning in ComponentState) then
    FActiveCellFont.Name := 'Tahoma';

  FDefaultEditor := edNormal;
  FDefaultAlignment := taLeftJustify;
  FDisabledFontColor := clSilver;
  FActiveCellFont.Style := [fsBold];
  FActiveCellFont.OnChange := FixedFontChanged;
  FActiveCellColor := clGray;
  FActiveCellColorTo := clNone;
  FUseDisabledFont := true;
  FXYOffset := Point(2,2);
  FPushedCellButton := Point(-1,-1);
  FOldSize := -1;
  FRowHeaders := TStringList.Create;
  FRowHeaders.OnChange := RowHeaderChanged;
  SortList := TStringList.Create;
  FLookupItems := TStringList.Create;
  FRowSelect := TList.Create;
  FColSelect := TList.Create;
  FSortIndexes := TSortIndexList.Create(0,0);
  FSortRowXRef := TIntList.Create(0,0);
  FUnSortRowXRef := TIntList.Create(0,0);
  FMergedColumns := TIntList.Create(0,0);
  FSelectedCells := TIntList.Create(0,0);
  FSelectedRows := TIntList.Create(0,0);
  FModifiedRows := TIntList.Create(0,0);
  FEnabledRows := TIntList.Create(0,0);
  FMergedColumns.OnChange := MergedColumnsChanged;
  FRowIndicator := TBitmap.Create;

  FBackground := TBackground.Create(Self);

  FScrollHintWnd := nil;

  FScrollHintShow := False;
  FScrollbars := ssBoth;
  FDeselectState := False;
  FMouseDown := False;
  FCtrlDown := False;
  FCtrlDownId := '';

  FTMSGradMirrorFrom := clNone;
  FTMSGradMirrorTo := clNone;

  FMouseResize := False;
  FEnableWheel := True;
  FUpdateCount := 0;
  FMinRowHeight := 0;
  FMaxRowHeight := 0;
  FMinColWidth := 0;
  FMaxColWidth := 0;
  FGroupColumn := -1;
  FClipTopLeft := Point(-1,-1);
  FSizeGrowOnly := False;
//  FPrintPreview := nil;
  FWordWrapEx := True;
  FIntelliZoom := True;
  FEditDisable := False;
  FEditChange := False;
  FNilObjects := False;
  FLoadFirstRow := True;
  FNumCellControls := 0;
  FControlList := TControlList.Create;
  FProgressAppearance := TGridProgressAppearance.Create;
  FProgressAppearance.OnChange := FixedFontChanged;

  FSyncGrid := TSyncGrid.Create(Self);

  FInvalidEntryIcon := ieWarning;

  SearchTics := 0;

  RowCount := 10;
  Width := 400;
  Height := 250;

  FGridItems := TCollection.Create(TGridItem);
  FFilter := TFilter.Create(self);
  AutoSize := False;
  Invokedchange := False;
  FHintColor := clInfoBk;
  FHighlightColor := clHighlight;
  FHighLightTextColor := clHighlightText;

  FSelectionColor := $EACAB6;
  FSelectionColorTo := clNone;
  FSelectionMirrorColor := clNone;
  FSelectionMirrorColorTo := clNone;

  FSelectionTextColor := clBlack;
  {
  FSelectionColor := clHighLight;
  FSelectionTextColor := clHighLightText;
  }
  FSelectionClick := False;
  FShowSelection := True;
  FHideFocusRect := False;
  FFixedAsButtons := False;
  FFixedCellPushed := False;
  FQuoteEmptyCells := True;
  FSelectionRectangleColor := clBlack;
  FAlwaysQuotes := False;
  FEnableHTML := True;
  FURLColor := clBlue;
  FVAlignment := vtaTop;
  FStartEditChar := #0;
  FMouseSelectMode := msNormal;
  FMouseSelectStart := -1;
  FOldRowSel := -1;
  FEditLink := nil;
  InvokedFocusChange := False;
  FShowNullDates := True;
  FVirtualCells := False;

  ResizeAssigned := False;
  FSaveFixedCells := True;
  FSaveFixedRows := False;
  FSaveFixedCols := False;
  FSaveHiddenCells := False;
  FSaveVirtCells := True;
  FSaveMergedCells := True;
  FDisableChange := False;
  FFindBusy := False;
  FComboIdx := -1;
  FPrintPageFrom := 1;
  FPrintPageTo := 1;
  FPrintPageNum := 0;
  FPrinterDriverFix := False;
  FExcelClipboardFormat := False;

  FOnShowHint := nil;

  FIsDBVersion:= False;

  FLastHintPos := Point(-1,-1);

  FBalloonSettings := TBalloonSettings.Create;
  FBalloonSettings.OnEnableChange := BalloonChange;

  FShowModified := TShowModified.Create;
  FShowModified.OnChange := ModifiedChanged;

  {
  if (AOwner is TForm) and not (csDesigning in ComponentState) then
  begin
    if Assigned( (AOwner as TForm).OnResize ) then
    begin
      FOnResize := (AOwner as TForm).OnResize;
      ResizeAssigned := True;
    end;

    (AOwner as TForm).OnResize := GridResize;
    PrevSizex := (AOwner as tform).Width;
    PrevSizey := (AOwner as tform).Height;
  end;
  }
  SetLength(FVisibleCol, ColCount);
  SetLength(FAllColWidths, ColCount);
  for i := 0 to ColCount - 1 do
    FVisibleCol[i] := True;

  FNumHidden := 0;
  FDelimiter := #0;
  FNoDefaultDraw := false;
  FFloatFormat := '%.2f';
  FPasswordChar := '*';
  FJavaCSV := False;
  FCheckTrue := 'Y';
  FCheckFalse := 'N';
  DefaultRowHeight := 22;
  FFixedRowHeight := DefaultRowHeight;
  FZoomFactor := 0;
  Colchgflg := True;
  Colclicked := -1;
  Rowclicked := -1;
  Colsized := False;
  Rowsized := False;
  SearchInc := '';
  LButFlg := False;
  FClearTextOnly := False;
  FSaveWithHTML := True;

  FLook := glXP;

  FTMSGradFrom := clWhite;
  FTMSGradTo := ColorToRGB(clBtnFace);

  FTMSGradMirrorFrom := clNone;
  FTMSGradMirrorTo := clNone;

  FOleDropTargetAssigned := False;

  //Screen.Cursors[crURLcursor] := LoadCursor(HInstance,PChar(crURLcursor));

  VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  GetVersionEx(verinfo);

  FIsWinXP := (verinfo.dwMajorVersion > 5) OR
    ((verinfo.dwMajorVersion = 5) AND (verinfo.dwMinorVersion >= 1));

  FIsWin7:= (verinfo.dwMajorVersion > 6) OR
    ((verinfo.dwMajorVersion = 6) AND (verinfo.dwMinorVersion >= 1));

  i := GetFileVersion('COMCTL32.DLL');
  i := (i shr 16) and $FF;

  FIsComCtl6 := (i > 5);

  if FIsWinXP then
    FBorderColor := $B99D7F
  else
    FBorderColor := clGray;

  FIsFlat := False;
  FScrollType := ssNormal;
  FScrollColor := clNone;
  FScrollWidth := GetSystemMetrics(SM_CXVSCROLL);

  FIsWinVista := IsVista;

  FRichEdit := nil;
  FInplaceRichEdit := nil;

  FNotifierList := TList.Create;
  FColumnOrder := TIntList.Create(0,0);

  FCellGraphic := TCellGraphic.Create;

  {$IFDEF TMSGDIPLUS}
  FOfficeHint := TAdvHintInfo.Create;
  {$ENDIF}

  FIgnoreColumns := TIntList.Create(-1,-1);

  FFilterDropDown := TFilterDropDown.Create;

  if FDesignTime then
  begin
    FFilterDropDown.TextChecked := 'Checked';
    FFilterDropDown.TextUnChecked := 'Unchecked';
  end;

  FFilterDropDown.OnChange := FilterDropDownChanged;
  FFilterIncremental := False;

  FDropList := TDropList.Create(Self);
  FDropList.Parent := Self;
  FDropList.Width := 0;
  FDropList.Height := 0;
  FDropList.Visible := False;
  FDropList.OnSelect := FilterSelect;

  FDropCheckList := TDropCheckList.Create(Self);
  FDropCheckList.Parent := Self;
  FDropCheckList.Width := 0;
  FDropCheckList.Height := 0;
  FDropCheckList.Visible := False;
  FDropCheckList.OnSelect := FilterCheck;

  FFilterList := TStringList.Create;
  FFilterList.Duplicates := dupignore;
  FFilterList.Sorted := true;
  ccuCall := True;

  FOldLeftCol := LeftCol;
  FOldTopRow := TopRow;

  FFilterEdit := TFilterEdit.Create(Self);

  FFltrList := TImageList.Create(Self);

  Icon := TIcon.Create;
  try
    LoadIconFromRes(icon, Hinstance, 'TMSGRDSTARTSWITH');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, HInstance, 'TMSGRDENDSWITH');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDCONTAINS');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDNOTCONTAINS');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDEQUAL');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDNOTEQUAL');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDLARGER');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDSMALLER');
    FFltrList.AddIcon(icon);

    LoadIconFromRes(icon, Hinstance, 'TMSGRDCLEAR');
    FFltrList.AddIcon(icon);
  finally
    icon.Free;
  end;

  FFltrPopup := TPopupMenu.Create(Self);
  FFltrPopup.Images := FFltrList;

  for i := 0 to 8 do
  begin
    mni := TMenuItem.Create(FFltrPopup);
    if FFilterEdit.TypeNames.Count > i then
    begin
      mni.Caption := FFilterEdit.TypeNames.Strings[i];
      mni.ImageIndex := i;
      mni.Tag := i;
      mni.OnClick := DoFilterType;
      FFltrPopup.Items.Add(mni);
    end;
  end;

  FHoverButtons := THoverButtons.Create(Self);

  if not (csDesigning in ComponentState) then
  begin
    FFocusWindow := TGridFocusWindow.Create(Self);

    ArwU := TArrowWindow.Init(Self,arrUp);
    ArwD := TArrowWindow.Init(Self,arrDown);
    ArwL := TArrowWindow.Init(Self,arrLeft);
    ArwR := TArrowWindow.Init(Self,arrRight);

    EditCombo := TGridCombo.Create(Self);
    EditCombo.Parent := Self;
    EditCombo.Enabled := False;
    EditCombo.Visible := False;
    EditCombo.IsWinXP := FIsWinXP;
    EditCombo.IsVista := IsVista and FIsComCtl6;

    FEditSpin := nil;
    FEditDate := nil;
    FEditDateTime := nil;

    FEditTrackbar := nil;
    FEditMemo := nil;
    FEditCalculator := nil;
    FEditTimePicker := nil;
    FEditDetailPicker := nil;
    FEditGridPicker := nil;
    FEditColorPicker := nil;
    FEditImagePicker := nil;
    FEditAdvGridPicker := nil;

    FStyle := tsWindowsXP;

    EditMode := False;
    EditControl := edNormal;

    EditTrans := TGridTransEdit.Create(Self);
    EditTrans.Parent := Self;
    EditTrans.Visible := False;
    EditTrans.BorderStyle := bsNone;
    EditTrans.FilterEdit := false;

    ComboTrans := TGridTransCombo.Create(Self);
    ComboTrans.Parent := Self;
    ComboTrans.Visible := False;

    {$IFDEF TMSUNICODE}
    // Deprecated from Delphi 2009
    EditUni := TGridUniEdit.Create(Self);
    EditUni.Parent := Self;
    EditUni.Enabled := False;
    EditUni.Visible := False;
    EditUni.Borderstyle := bsNone;

    MemoUni := TGridUniMemo.Create(Self);
    MemoUni.Parent := Self;
    MemoUni.Enabled := False;
    MemoUni.Visible := False;
    MemoUni.Borderstyle := bsNone;

    EditBtnUni := TGridUniEditBtn.Create(Self);
    EditBtnUni.Parent := Self;
    EditBtnUni.Enabled := False;
    EditBtnUni.Visible := False;
    EditBtnUni.Borderstyle := bsNone;
    EditBtnUni.IsWinXP := FIsWinXP;
    EditBtnUni.ButtonCaption := '...';
    EditBtnUni.OnClickBtn := WideEllipsClick;

    ComboUni := TGridUniCombo.Create(Self);
    ComboUni.Parent := Self;
    ComboUni.Enabled := False;
    ComboUni.Visible := False;
    ComboUni.IsWinXP := FIsWinXP;
    {$ENDIF}

    EditCheck := TGridCheckBox.Create(Self);
    EditCheck.Parent := Self;
    EditCheck.Enabled := False;
    EditCheck.Visible := False;

    EditBtn := TGridEditBtn.Create(Self);
    EditBtn.Parent := Self;
    EditBtn.Enabled := False;
    EditBtn.Visible := False;
    EditBtn.ButtonCaption := '...';
    EditBtn.Borderstyle := bsNone;
    EditBtn.IsWinXP := FIsWinXP;

    UnitEditBtn := TGridUnitEditBtn.Create(Self);
    UnitEditBtn.Parent := Self;
    UnitEditBtn.Enabled := False;
    UnitEditBtn.Visible := False;
    UnitEditBtn.Buttoncaption := '...';
    UnitEditBtn.BorderStyle := bsNone;
    UnitEditBtn.OnUnitChanged := UnitChanged;

    Gridbutton := TGridButton.Create(Self);
    Gridbutton.Parent := Self;
    Gridbutton.Enabled := False;
    Gridbutton.Visible := False;
    Gridbutton.OnClick := HandleButtonClick;

    MoveButton := THeaderDragButton.Create(Self);
    MoveButton.Grid := Self;
    MoveButton.Parent := Self;
    MoveButton.Enabled := False;
    MoveButton.Visible := False;

    FEditControl := TControlEdit.Create(Self);
    FEditControl.Parent := Self;
    FEditControl.Visible := False;

    FComboControl := TControlCombo.Create(Self);
    FComboControl.Parent := Self;
    FComboControl.Visible := False;
    FCtrlEditing := False;

    FScrollBar := TScrollBar.Create(Self);
    FPaintScrollBar := TScrollBar.Create(Self);

    FButtonForm := TNoActiveForm.CreateNew(Self);
    FButtonForm.Enabled := true;
    FButtonForm.BorderStyle := bsNone;
    {$IFDEF DELPHI_UNICODE}
    FButtonForm.OnMouseLeave := ButtonFormMouseLeave;
    {$ENDIF}
    FButtonForm.Width := 200;
    FButtonForm.Height := 22;
  end;

  crURLCursor := crHandPoint;
  {$IFDEF FREEWARE}
  cla := self.ClassName;
  {$ENDIF}
end;

destructor TAdvStringGrid.Destroy;
var
  RCnt,CCnt: integer;
begin
  // required to avoid memory leak, ie. to free cellgraphics for hidden rows
  if (FNumNodes > 0) then
    ExpandAll;

  RemoveAllFilters;
  DestroyMetroScrollers;

  if not (csDesigning in ComponentState) then
  begin
    BalloonDone;

    if (Owner is TForm) then  // restore owner resize Handler
    begin
      (Owner as TForm).OnResize := FOnResize;
    end;
  end;

  if FColumnSize.Save then
    SaveColSizes;

  FClearTextOnly := False;
  FSaveHiddenCells := False;

  RCnt := RowCount;
  CCnt := ColCount;

  UnHideColumnsAll;
  UnHideRowsAll;

  if (NumHiddenRows = 0) and (FNumNodes = 0) then
  begin
    if (FMaxRowCount > RCnt) then
      RCnt := FMaxRowCount;

    if (FMaxColCount > CCnt) then
      CCnt := FMaxColCount;
  end;

  if (RCnt > 0) and (CCnt > 0) then
  begin
    if FHasCellProps then
      ClearRect(0,0,CCnt - 1,RCnt - 1);
  end;

  if Assigned(FScrollTimer) then
    FScrollTimer.Free;

  if Assigned(FHiddenRowLookup) then
    FreeAndNil(FHiddenRowLookup);

  cf.Free;

  FHoverButtons.Free;
  FAutoColor.Free;
  FFilterEdit.Free;
  FFltrPopup.Free;
  FFltrList.Free;
  FFocusHelper.Free;
  FIgnoreColumns.Free;
  FProgressAppearance.Free;
  FFloatingFooter.Free;
  FCellGraphic.Free;
  FControlList.Free;
  FSortRowXRef.Free;
  FUnSortRowXRef.Free;
  FMergedColumns.Free;
  FSelectedCells.Free;
  FSelectedRows.Free;
  FModifiedRows.Free;
  FEnabledRows.Free;
  FNotifierList.Free;
  FPrintSettings.Free;
  FHTMLSettings.Free;
  FSortSettings.Free;
  FDragDropSettings.Free;
  FDragScrollOptions.Free;
  FControlLook.Free;
  FNavigation.Free;
  FColumnSize.Free;
  FColumnOrder.Free;
  FCellNode.Free;
  FBands.Free;
  FSizeWhileTyping.Free;
  FImageCache.Free;
  FMouseActions.Free;
  FColumnHeaders.Free;
  FGrouping.Free;
  FFixedFont.Free;
  FActiveCellFont.Free;
  FRowHeaders.Free;
  FLookupItems.Free;
  FRowSelect.Free;
  FColSelect.Free;
  FSortIndexes.Free;
  FRowIndicator.Free;
  FBackground.Free;
  FFooterPanel.Free;
  FSearchPanel.Free;
  FSearchFooter.Free;
  FBalloonSettings.Free;
  FBalloonSettings := nil;
  FShowModified.Free;
  FOrigColSizes.Free;
  FSuppressColSizes.Free;
  FFilterDropDown.Free;
  FDropList.Free;
  FDropCheckList.Free;
  FFilterList.Free;
  FSyncGrid.Free;
  FSyncGrid := nil;

  if not (csDesigning in ComponentState) then
  begin
    ArwU.Free;
    ArwD.Free;
    ArwL.Free;
    ArwR.Free;
  end;

  SortList.Free;
  {$IFDEF TMSGDIPLUS}
  FOfficeHint.Free;
  {$ENDIF}

  FGridItems.Free;
  FFilter.Free;

  Cursor := FOldCursor;

  if not (csDesigning in ComponentState) then
  begin
    FFocusWindow.Free;
    EditCombo.Free;
    EditTrans.Free;
    ComboTrans.Free;

    if Assigned(FEditDateTime) then
      FreeAndNil(FEditDateTime);

    if Assigned(FEditDate) then
      FreeAndNil(FEditDate);

    if Assigned(FEditSpin) then
      FreeAndNil(FEditSpin);

    if Assigned(FInplaceRichEdit) then
      FreeAndNil(FInplaceRichEdit);

    if Assigned(FRichEdit) then
      FreeAndNil(FRichEdit);

    /// EDITORINTEGRATION

    if Assigned(FEditTrackBar) then
      FreeAndNil(FEditTrackbar);

    if Assigned(FEditMemo) then
      FreeAndNil(FEditMemo);

    if Assigned(FEditCalculator) then
      FreeAndNil(FEditCalculator);

    if Assigned(FEditTimePicker) then
      FreeAndNil(FEditTimePicker);

    if Assigned(FEditDetailPicker) then
      FreeAndNil(FEditDetailPicker);

    if Assigned(FEditGridPicker) then
      FreeAndNil(FEditGridPicker);

    if Assigned(FEditColorPicker) then
      FreeAndNil(FEditColorPicker);

    if Assigned(FEditImagePicker) then
      FreeAndNil(FEditImagePicker);

    if Assigned(FEditAdvGridPicker) then
      FreeAndNil(FEditAdvGridPicker);

    /// EDITORINTEGRATION

    {$IFDEF TMSUNICODE}
    EditUni.Free;
    MemoUni.Free;
    EditBtnUni.Free;
    FreeAndNil(ComboUni);
    {$ENDIF}

    EditCheck.Free;
    EditBtn.Free;
    UnitEditBtn.Free;
    Gridbutton.Free;
    MoveButton.Free;
    FEditControl.Free;
    FComboControl.Free;
    FScrollBar.Free;
    FPaintScrollBar.Free;
    FButtonForm.Free;
  end;

  inherited Destroy;
end;


procedure TAdvStringGrid.DestroyMetroScrollers;
begin
  if Assigned(vscrlctrl) then
    FreeAndNil(vscrlctrl);

  if Assigned(hscrlctrl) then
    FreeAndNil(hscrlctrl);
end;

procedure TAdvStringGrid.InitScroll(PageScroll: boolean);
var
  i: integer;
  verInfo: TOSVersionInfo;
  mshwheel: THandle;
  Scrollmsg: Integer;

begin
  WheelMsg := 0;
  WheelScrl := 0;
  WheelPan := False;

  VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);

  GetVersionEx(verinfo);

  if ((verinfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS) AND
     ( (verinfo.dwMajorVersion <4) OR
       (verinfo.dwMajorVersion =4) AND (verinfo.dwMinorVersion<10)) ) or
     ( (verinfo.dwPlatformId = VER_PLATFORM_WIN32_NT) AND
       (verinfo.dwMajorVersion < 4)) then
  begin
    if PageScroll then
    begin
      mshwheel := FindWindow(MSH_WHEELMODULE_CLASS,MSH_WHEELMODULE_TITLE);
      if mshwheel > 0 then
      begin
        scrollmsg := RegisterWindowMessage(MSH_SCROLL_LINES);
        wheelmsg := RegisterWindowMessage(MSH_SCROLL_LINES);
        wheelscrl := SendMessage(mshwheel,scrollmsg,0,0);
      end;
    end;
  end
  else {is Win NT 4+ or Win98 ?}
  begin
    SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,@i,0);

    if (i = -1) then
      wheelscrl := VisibleRowCount
    else
      wheelscrl := i;

    wheelmsg := WM_MOUSEWHEEL;
  end;
end;

procedure TAdvStringGrid.CreateWnd;
begin
  if (csDestroying in Componentstate) then
    Exit;

  inherited CreateWnd;

  if not Assigned(Parent) or not (Parent is TWinControl) then
    Exit;

  if not (csDesigning in ComponentState) then
  begin
    if not (csLoading in ComponentState) then
      InitVCLStyle(false);

    if (FScrollHints <> shNone) and not Assigned(FScrollHintWnd) then
      FScrollHintWnd := THTMLHintWindow.Create(Self);

    if ScrollType = ssMetro then
      CreateMetroScrollers;

    FScrollBar.Visible := false;
    FScrollBar.Parent := Self;
    FScrollBar.TabStop := false;
    FScrollBar.Kind := sbVertical;
    FScrollBar.Ctl3D := false;

    FPaintScrollBar.Visible := false;
    FPaintScrollBar.Parent := Self;
    FPaintScrollBar.TabStop := false;
    FPaintScrollBar.Kind := sbVertical;
    FPaintScrollBar.Ctl3D := false;

    FDPIScale := GetDeviceCaps(Canvas.Handle, LOGPIXELSY) / 96;

    if Balloon.Enable then
      BalloonInit;
  end;

  FFooterPanel.Parent := Self;
  FFooterPanel.Visible := FFloatingFooter.Visible;

  FSearchPanel.Parent := Self;
  FSearchPanel.Visible := FSearchFooter.Visible;

  if FSearchFooter.Visible then
    FSearchPanel.Height := 32
  else
    FSearchPanel.Height := 0;

  if FColumnSize.Save then
    LoadColSizes;

  FGridTimerID := SetTimer(Handle,111,500,Nil);  // every 500ms

  if (csDesigning in ComponentState) and not FLoaded
    and not (csLoading in ComponentState) then
    Font.Name := 'Tahoma';

  if FIsWinXP then
  begin
    FIsWinXP := FIsWinXP and IsThemeActive;
  end;

  InitScroll(True);

  //reinitialize scrolling type after reparenting
  if (ScrollType <> ssNormal) and not (csLoading in ComponentState) then
  begin
    FlatInit;
    UpdateWidth;
    UpdateColor;
  end;
end;

procedure TAdvStringGrid.AssignCells(Source: TPersistent);
var
  ms: TMemoryStream;
begin
  if (Source is TAdvStringGrid) then
  begin
    ms := TMemoryStream.Create;
    (Source as TAdvStringGrid).SaveToStream(ms);
    ms.Position := 0;
    LoadFromStream(ms);
    ms.Free;
  end;
end;

procedure TAdvStringGrid.Assign(Source: TPersistent);
var
  i: integer;
begin
  if (Source is TAdvStringGrid) then
  begin
    Font.Assign((Source as TAdvStringGrid).Font);
    FActiveCellColor := (Source as TAdvStringGrid).ActiveCellColor;
    FActiveCellColorTo := (Source as TAdvStringGrid).ActiveCellColorTo;
    FActiveCellFont.Assign((Source as TAdvStringGrid).ActiveCellFont);
    FActiveCellShow := (Source as TAdvStringGrid).ActiveCellShow;
    FAutoColor.Assign((Source as TAdvStringGrid).AutoColor);
    ActiveRowShow := (Source as TAdvStringGrid).ActiveRowShow;
    Align := (Source as TAdvStringGrid).Align;
    FFilterDropDown.Assign((Source As TAdvStringGrid).FilterDropDown);
    FAnchorHint := (Source as TAdvStringGrid).AnchorHint;
    FAutoSize := (Source as TAdvStringGrid).AutoSize;
    FAutoColor.Assign((Source as TAdvStringGrid).AutoColor);
    FMouseActions.Assign((Source as TAdvstringGrid).MouseActions);
    FNavigation.Assign((Source as TAdvStringGrid).Navigation);
    FGrouping.Assign((Source as TAdvStringGrid).Grouping);
    FSearchFooter.Assign((Source as TAdvStringGrid).SearchFooter);
    FPrintSettings.Assign((Source as TAdvStringGrid).PrintSettings);
    FFilter.Assign((Source as TAdvStringGrid).Filter);
    FHTMLSettings.Assign((Source as TAdvStringGrid).HTMLSettings);
    FBands.Assign((Source as TAdvStringGrid).Bands);
    FBackGround.Assign((Source as TAdvStringGrid).Background);
    FCellNode.Assign((Source as TAdvStringGrid).CellNode);
    FSortSettings.Assign((Source as TAdvStringGrid).SortSettings);
    FDragScrollOptions.Assign((Source as TAdvStringGrid).DragScrollOptions);
    FDragDropSettings.Assign((Source as TAdvStringGrid).DragDropSettings);
    FProgressAppearance.Assign((Source as TAdvStringGrid).ProgressAppearance);
    FColumnSize.Assign((Source as TAdvStringGrid).ColumnSize);
    FSyncGrid.Assign((Source as TAdvStringGrid).SyncGrid);
    FFocusHelper.Assign((Source as TAdvStringGrid).FocusHelper);
    FFilterEdit.Assign((Source as TAdvStringGrid).FilterEdit);
    FHoverButtons.Assign((Source as TAdvStringGrid).HoverButtons);
    FShowModified.Assign((Source as TAdvStringGrid).ShowModified);
    FControlLook.Assign((Source as TAdvStringGrid).ControlLook);
    FBalloonSettings.Assign((Source as TAdvStringGrid).Balloon);

    {$IFDEF TMSGDIPLUS}
    FOfficeHint.Assign((Source as TAdvStringGrid).OfficeHint);
    {$ENDIF}

    FFixedRowAlways := (Source as TAdvStringGrid).FixedRowAlways;
    ColCount := (Source as TAdvStringGrid).ColCount;
    RowCount := (Source as TAdvStringGrid).RowCount;
    FixedRows := (Source as TAdvStringGrid).FixedRows;
    FixedCols := (Source as TAdvStringGrid).FixedCols;
    DefaultColWidth := (Source as TAdvStringGrid).DefaultColWidth;
    DefaultRowHeight := (Source as TAdvStringGrid).DefaultRowHeight;
    FixedRowHeight := (Source as TAdvStringGrid).FixedRowHeight;
    FixedColWidth := (Source as TAdvStringGrid).FixedColWidth;
    InvalidEntryTitle := (Source as TAdvStringGrid).InvalidEntryTitle;
    InvalidEntryIcon := (Source as TAdvStringGrid).InvalidEntryIcon;
    InvalidEntryText := (Source as TAdvStringGrid).InvalidEntryText;

    Options := (Source as TAdvStringGrid).Options;

    for i := 0 to ColCount - 1 do
    begin
      ColWidths[i] := (Source as TAdvStringGrid).ColWidths[i];
    end;

    ColumnHeaders.Assign((Source as TAdvStringGrid).ColumnHeaders);

    for i := 0 to RowCount - 1 do
      RowHeights[i] := (Source as TAdvStringGrid).RowHeights[i];

    FScrollProportional := (Source as TAdvStringGrid).ScrollProportional;
    FScrollSynch := (Source as TAdvStringGrid).ScrollSynch;
    FScrollWidth := (Source as TAdvStringGrid).ScrollWidth;
    FScrollHints := (Source as TAdvStringGrid).ScrollHints;
    FScrollbarAlways := (Source as TAdvStringGrid).ScrollBarAlways;
    ScrollBars := (Source as TAdvStringGrid).ScrollBars;
    ScrollColor := (Source as TAdvStringGrid).ScrollColor;
    ScrollType := (Source as TAdvStringGrid).ScrollType;
    ScrollWidth := (Source as TAdvStringGrid).ScrollWidth;
    Look := (Source as TAdvStringGrid).Look;

    FBorderColor := (Source as TAdvStringGrid).BorderColor;
    FSelectionColor := (Source as TAdvStringGrid).SelectionColor;
    FSelectionColorTo := (Source as TAdvStringGrid).SelectionColorTo;
    FSelectionMirrorColor := (Source as TAdvStringGrid).SelectionMirrorColor;
    FSelectionMirrorColorTo := (Source as TAdvStringGrid).SelectionMirrorColorTo;
    FSelectionTextColor := (Source as TAdvStringGrid).SelectionTextColor;
    FSelectionRTFKeep := (Source as TAdvStringGrid).SelectionRTFKeep;
    FSelectionResizer := (Source as TAdvStringGrid).SelectionResizer;
    FAutoFilterUpdate := (Source as TAdvStringGrid).AutoFilterUpdate;
    FAutoHideSelection := (Source as TAdvStringGrid).AutoHideSelection;
    FAutoNumAlign := (Source as TAdvStringGrid).AutoNumAlign;
    FAutoThemeAdapt := (Source as TAdvStringGrid).AutoThemeAdapt;
    FDefaultEditor := (Source as TAdvStringGrid).DefaultEditor;
    FDisabledFontColor := (Source as TAdvStringGrid).DisabledFontColor;
    FEditWithTags := (Source as TAdvStringGrid).EditWithTags;
    FEnableHTML := (Source as TAdvStringGrid).EnableHTML;
    FEnableBlink := (Source as TAdvStringGrid).EnableBlink;
    FEnhRowColMove := (Source as TAdvStringGrid).EnhRowColMove;
    FEnhTextSize := (Source as TAdvStringGrid).EnhTextSize;
    FExcelStyleDecimalSeparator := (Source as TAdvStringGrid).ExcelStyleDecimalSeparator;

    FFilterDropDownAuto := (Source as TAdvStringGrid).FilterDropDownAuto;
    FFilterDropDownCheck := (Source as TAdvStringGrid).FilterDropDownCheck;
    FFilterDropDownCheckUnCheckAll := (Source as TAdvStringGrid).FilterDropDownCheckUnCheckAll;
    FFilterDropDownClear := (Source as TAdvStringGrid).FilterDropDownClear;
    FFilterDropDownColumns := (Source as TAdvStringGrid).FilterDropDownColumns;
    FFilterDropDownMultiCol := (Source as TAdvStringGrid).FilterDropDownMultiCol;
    FilterDropDownRow := (Source as TAdvStringGrid).FilterDropDownRow;

    FFixedAsButtons := (Source as TAdvStringGrid).FixedAsButtons;
    FFixedFooters := (Source as TAdvStringGrid).FixedFooters;
    FFixedRightCols := (Source as TAdvStringGrid).FixedRightCols;

    GridLineColor := (Source as TAdvStringGrid).GridLineColor;
    GridLineWidth := (Source as TAdvStringGrid).GridLineWidth;
    FHighlightColor := (Source as TAdvStringGrid).HighlightColor;
    FHighLightTextColor := (Source as TAdvStringGrid).HighlightTextColor;
    FHintColor := (Source as TAdvStringGrid).HintColor;
    FHintShowCells := (Source as TAdvStringGrid).HintShowCells;
    FHintShowLargeText := (Source as TAdvStringGrid).HintShowLargeText;
    FHintShowLargeTextPos := (Source as TAdvStringGrid).HintShowLargeTextPos;
    FHovering := (Source as TAdvStringGrid).Hovering;
    FHoverRow := (Source as TAdvStringGrid).HoverRow;
    FHoverRowColor := (Source as TAdvStringGrid).HoverRowColor;
    FHoverRowColorTo := (Source as TAdvStringGrid).HoverRowColorTo;

    FIntelliZoom := (Source as TAdvStringGrid).IntelliZoom;
    FIntelliPan := (Source as TAdvStringGrid).IntelliPan;
    FIntegralHeight := (Source as TAdvStringGrid).IntegralHeight;
    FHTMLHint := (Source as TAdvStringGrid).HTMLHint;
    FHTMLKeepLineBreak := (Source as TAdvStringGrid).HTMLKeepLineBreak;

    FInvalidEntryIcon := (Source as TAdvStringGrid).InvalidEntryIcon;
    FInvalidEntryTitle := (Source as TAdvStringGrid).InvalidEntryTitle;
    FInvalidEntryText := (Source as TAdvStringGrid).InvalidEntryText;
    FLookupHistory := (Source as TAdvStringGrid).LookupHistory;
    FLookup := (Source as TAdvStringGrid).Lookup;
    FLookupItems.Assign((Source as TAdvStringGrid).LookupItems);
    FLookupCaseSensitive := (Source as TAdvStringGrid).LookupCaseSensitive;
    FMaxComboLength := (Source as TAdvStringGrid).MaxComboLength;
    FMaxEditLength := (Source as TAdvStringGrid).MaxEditLength;
    FMultilineCells := (Source as TAdvStringGrid).MultiLineCells;

    AssignCells(Source);
  end;
end;

procedure TAdvStringGrid.Invalidate;
begin
  if FEditChange then
  begin
    FEditChange := false;
    Exit;
  end;

  inherited;

  if not (csLoading in ComponentState) then
    if Assigned(FloatingFooter) then
      if FloatingFooter.Visible and Assigned(FFooterPanel) then
        FFooterPanel.Invalidate;
end;

procedure TAdvStringGrid.Resize;
begin
  inherited;

  if Assigned(FOnGridResize) then
    FOnGridResize(Self);

  if (Background.Display in [bdGradientHorz, bdGradientVert]) and (Background.ColorTo <> clNone) then
    Invalidate;

  UpdateScrollBars(false);

  CellControlsUpdate;

  InitScroll(false);

  if (csDesigning in ComponentState) then
    Invalidate;
end;

procedure TAdvStringGrid.UpdateScrollBars(Refresh: Boolean);
begin
  if (ScrollBarAlways = saNone) then
  begin
    if Refresh then
    begin
      // if no scrollbars, hide previously shown scrollbars
      if (VisibleRowCount + FixedRows >= RowCount) then
        ShowScrollBar(self.Handle, SB_VERT, False);

      if (VisibleColCount + FixedCols >= ColCount) then
        ShowScrollBar(self.Handle, SB_HORZ, False);
    end;
    Exit;
  end;

  if (VisibleRowCount + FixedRows >= RowCount) and (ScrollBars in [ssBoth, ssVertical])  then
    ShowScrollbar(self.Handle, SB_VERT, (ScrollBarAlways in [saBoth, saVert]));

  if (VisibleColCount + FixedCols >= ColCount) and (ScrollBars in [ssBoth, ssHorizontal]) then
    ShowScrollbar(self.Handle, SB_HORZ, (ScrollBarAlways in [saBoth, saHorz]));

  if (VisibleRowCount + FixedRows >= RowCount) then
    EnableScrollBar(self.Handle, SB_VERT, ESB_DISABLE_BOTH);

  if (VisibleColCount + FixedCols >= ColCount) then
    EnableScrollBar(self.Handle, SB_HORZ, ESB_DISABLE_BOTH);

  if (VisibleRowCount + FixedRows < RowCount) then
  begin
    EnableScrollBar(self.Handle, SB_VERT, ESB_ENABLE_BOTH);
  end;

  if (VisibleColCount + FixedCols < ColCount) then
    EnableScrollBar(self.Handle, SB_HORZ, ESB_ENABLE_BOTH);
end;


procedure TAdvStringGrid.SetBorderColor(const Value: TColor);
begin
  if (FBorderColor <> Value) then
  begin
    FBorderColor := Value;
    if Parent.HandleAllocated then
      NCPaintProc;
  end;
end;

procedure TAdvStringGrid.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  AScrollSize: Integer;
  ABorderSize: Integer;

begin
  if FIntegralHeight and (FUpdateCount = 0) and (DefaultRowHeight > 0) then
  begin
    if VisibleColCount + FixedCols < ColCount then
      AScrollSize := GetSystemMetrics(SM_CYHSCROLL)
    else
      AScrollSize := 0;

    if BorderStyle = bsSingle then
      ABorderSize := 2
    else
      ABorderSize := 0;

    AHeight := AHeight - AScrollSize - ABorderSize;
    AHeight := AHeight - (AHeight mod DefaultRowHeight);
    AHeight := AHeight + AScrollSize + ABorderSize * 2;
  end;

  inherited SetBounds(ALeft,ATop,AWidth,AHeight);

  if Assigned(Parent) then
    if Parent.HandleAllocated then
      NCPaintProc;
end;

procedure TAdvStringGrid.Loaded;
begin
  inherited;

  FOldCursor := Cursor;
  ShowColumnHeaders;
  ShowRowHeaders;

  with FDragDropSettings do
  if FOleDropTargetAssigned then
  begin
    FGridDropTarget.AcceptText := FOleAcceptText;
    FGridDropTarget.AcceptFiles := FOleAcceptFiles;
    FGridDropTarget.AcceptURLs := FOleAcceptURLs;
  end;

  if (FLook = glTMS) then
  begin
    FLook := glCustom;
    SetLook(glTMS);
  end;

  if AutoSize then
    AutoSizeColumns(false);

  if FColumnSize.Save then
    LoadColSizes;

  FFixedRowsMin := FixedRows;
  FFixedColsMin := FixedCols;

  MinRowHeight := DefaultRowHeight;
  MinColWidth := 10;

  FMaxColCount := ColCount;
  FMaxRowCount := RowCount;

  FLoaded := true;

  if (goAlwaysShowEditor in Options) then
  begin
    Navigation.AlwaysEdit := true;
    Options := Options - [goAlwaysShowEditor];
  end;

  if not FIsWinXP and (ControlLook.ControlStyle = csTheme) and not (csDesigning in ComponentState) then
    ControlLook.ControlStyle := csClassic;

  SearchFooter.AutoThemeAdapt := AutoThemeAdapt;
  SearchChanged(Self);

  UpdateScrollBars(false);

  if AutoThemeAdapt and not (csDesigning in ComponentState) and not IsLibrary then
  begin
    ThemeAdapt;
    ThemeNotifier(Self).RegisterWindow(Handle);
  end;

  FDisSelection := TGridRect(Rect(-1,-1,-1,-1));

  InitOrigColSizes;
  SetColumnOrder;

  if Balloon.Enable then
    BalloonInit;

  InitVCLStyle(false);
end;

procedure TAdvStringGrid.DateTimePickerChange(Sender: TObject);
begin
  if Assigned(OnDateTimeChange) then
    OnDateTimeChange(Self, Col, Row, EditDateTime.DateTime);
end;

procedure TAdvStringGrid.DatePickerChange(Sender: TObject);
begin
  if Assigned(OnEditChange) then
  begin
    if (Sender as TDateTimePicker).Kind = dtkDate then
      OnEditChange(Self, Col, Row, DateToStr(EditDate.Date))
    else
      OnEditChange(Self, Col, Row, TimeToStr(EditDate.Time));
  end;
end;


procedure TAdvStringGrid.DatePickerCloseUp(Sender: TObject);
begin
  if Assigned(FOnDatePickerCloseUp) then
    FOnDatePickerCloseUp(self, Row, Col);

  if MouseActions.DirectDateClose then
    HideInplaceEdit;
end;

procedure TAdvStringGrid.DatePickerDropDown(Sender: TObject);
const
  ShowTodayFlags: array[Boolean] of DWORD = (MCS_NOTODAY, 0);
  ShowTodayCircleFlags: array[Boolean] of DWORD = (MCS_NOTODAYCIRCLE, 0);
  WeekNumFlags: array[Boolean] of DWORD = (0, MCS_WEEKNUMBERS);
var
  mch: THandle;
  dwStyle: dword;
  rct: TRect;
begin
  mch := SendMessage((Sender as TGridDatePicker).Handle, DTM_GETMONTHCAL, 0,0);
  dwStyle := GetWindowLong(mch, GWL_STYLE);

  dwStyle := dwStyle or ShowTodayFlags[(Sender as TGridDatePicker).ShowToday]
    or ShowTodayCircleFlags[(Sender as TGridDatePicker).ShowTodayCircle]
    or WeekNumFlags[(Sender as TGridDatePicker).WeekNumbers];

  SetWindowLong(mch, GWL_STYLE, dwStyle);
  SendMessage(mch, MCM_GETMINREQRECT, 0, LParam(@rct));
  MoveWindow(mch, 0, 0, rct.Right + 2, rct.Bottom + 2, True);

  if Assigned(FOnDatePickerDropDown) then
    FOnDatePickerDropDown(Self, Row, Col);
end;

procedure TAdvStringGrid.GetCellHint(ACol, ARow: Integer;
  var AHint: string; var AWideHint: widestring);
begin
  if Assigned(FOnGridHint) then
  begin
    FOnGridHint(Self,ARow,ACol,AHint);
    {$IFDEF TMSGDIPLUS}
    OfficeHint.Notes.Text := AHint;
    {$ENDIF}
  end;

  if Assigned(FOnGridWideHint) then
  begin
    FOnGridWideHint(Self,ARow,ACol,AWideHint);
    if (AWideHint <> '') then    
      AHint := EncodeWideStr(AWideHint);
  end;

  {$IFDEF TMSGDIPLUS}
  if Assigned(FOnOfficeHint) then
  begin
    FOnOfficeHint(Self,ACol,ARow,OfficeHint);
  end;
  {$ENDIF}
end;


procedure TAdvStringGrid.GetCellColor(ACol,ARow: Integer;AState: TGridDrawState; ABrush: TBrush; AFont: TFont);
var
  RACol: Integer;
  cp: TCellProperties;

begin
  if FActiveCellShow then
  begin
    RACol := RemapColInv(ACol);
    if ((Row = ARow) and (RACol = FixedCols - 1) and (FixedCols > 0)) or
       ((Col = RACol) and (ARow = FixedRows - 1) and (FixedRows > 0)) then
    begin
      AFont.Assign(FActiveCellFont);
      ABrush.Color := ActiveCellColor;
    end;
  end;

  if HasCellProperties(ACol,ARow) then
  begin
    cp := CellProperties[ACol,ARow];

    if (CellTypes[ACol,ARow] in [ctEmpty,ctNone,ctCheckBox,ctRadioButton,ctComment,ctIcon,ctImages,ctImageList]) then
    begin
      if cp.BrushColor <> clNone then
        ABrush.Color := cp.BrushColor;
    end;

    if cp.FontColor <> clNone then
      AFont.Color := cp.FontColor;

    if cp.FontStyle <> [] then
      AFont.Style := cp.FontStyle;

    if cp.FontSize <> 0 then
      AFont.Size := cp.FontSize;

    if cp.FontName <> '' then
      AFont.Name := cp.FontName;
  end;

  if Assigned(OnGetCellColor) then
    OnGetCellColor(self,ARow,ACol,AState,ABrush,AFont);
end;

procedure TAdvStringGrid.GetCellBorder(ACol,ARow: Integer; APen:TPen;var Borders:TCellBorders);
begin
  if Grouping.HeaderUnderline then
  begin
    if IsNode(ARow) and (ACol > 0) then
    begin
      Borders := [cbBottom];
      APen.Color := Grouping.HeaderLineColor;
      APen.Width := Grouping.HeaderLineWidth;
    end;
  end;
  if Grouping.SummaryLine then
  begin
    if IsSummary(ARow) and (ACol > 0) then
    begin
      Borders := [cbTop];
      APen.Color := Grouping.SummaryLineColor;
      APen.Width := Grouping.SummaryLineWidth;
    end;
  end;

  if Assigned(OnGetCellBorder) then
    OnGetCellBorder(self,ARow,ACol,APen,Borders);
end;

procedure TAdvStringGrid.GetCellPrintBorder(ACol,ARow: Integer; APen:TPen;var borders:TCellBorders);
begin
  if Assigned(OnGetCellPrintBorder) then
    OnGetCellPrintBorder(self,ARow,ACol,APen,Borders);
end;

procedure TAdvStringGrid.GetCellPrintColor(ACol,ARow: Integer;AState: TGridDrawState; ABrush: TBrush; AFont: TFont);
begin
  if Assigned(OnGetCellPrintColor) then
    OnGetCellPrintColor(self,ARow,ACol,AState,ABrush,AFont);
end;

procedure TAdvStringGrid.GetCellAlign(ACol,ARow: Integer;var HAlign: TAlignment;var VAlign: TVAlignment);
begin
  if (ACol = 0) and (MouseActions.HotmailRowSelect) then
    HAlign := taCenter;

  if Assigned(OnGetAlignment) then
    OnGetAlignment(Self,ARow,ACol,HAlign,VAlign);
end;

procedure TAdvStringGrid.GetColFormat(ACol: Integer;var AStyle:TSortStyle;var aPrefix,aSuffix:string);
begin
  if Assigned(OnGetFormat) then
    OnGetFormat(Self,ACol,AStyle,aPrefix,aSuffix);
end;

function TAdvStringGrid.HasCombo(ACol,ARow: Integer; AEditor: TEditorType = edNone): Boolean;
var
  TheEditor: TEditorType;
begin
  Result := False;

  if Assigned(OnHasComboBox) then
    OnHasComboBox(Self,ACol,ARow,Result)
  else
  begin
    if ControlLook.DropDownAlwaysVisible then
    begin
      TheEditor := FDefaultEditor;

      if AEditor = edNone then
        GetCellEditor(ACol,ARow,TheEditor)
      else
        TheEditor := AEditor;

      Result := TheEditor in [edComboEdit, edComboList
      {$IFDEF TMSUNICODE}
      , edUniComboEdit, edUniComboList
      {$ENDIF}
      ];
    end;
  end;
end;

function TAdvStringGrid.HasEditBtn(ACol,ARow: Integer; AEditor: TEditorType = edNone): Boolean;
var
  TheEditor: TEditorType;
begin
  Result := False;

  if Assigned(OnHasEditBtn) then
    OnHasEditBtn(Self,ACol,ARow,Result)
  else
  begin
    if ControlLook.DropDownAlwaysVisible then
    begin
      TheEditor := FDefaultEditor;

      if AEditor = edNone then
        GetCellEditor(ACol,ARow,TheEditor)
      else
        TheEditor := AEditor;

      Result := TheEditor in [edEditBtn];
    end;
  end;
end;


procedure TAdvStringGrid.FilterEditUpdate(ACol: integer; Condition: string; FilterType: TFilterType);
begin
  if Assigned(OnFilterEditUpdate) then
    OnFilterEditUpdate(Self, ACol, Condition, FilterType);
end;

function TAdvStringGrid.HasFilterEdit(ACol, ARow: integer): boolean;
begin
  Result := FFilterEdit.Enabled and (ARow = FFilterEdit.Row);

  if Result and (FFilterEdit.Columns = fdNormal) then
  begin
    Result := (ACol >= FixedCols) and (ACol < AllColCount - FixedRightCols);
  end;

  if Result then
  begin
    if Assigned(OnHasFilterEdit) then
      OnHasFilterEdit(Self, ACol, Result);
  end;
end;

function TAdvStringGrid.HasSpinEdit(ACol,ARow: Integer; AEditor: TEditorType = edNone): Boolean;
var
  TheEditor: TEditorType;
begin
  Result := False;

  if (ACol >= FixedCols) and (ARow >= FixedRows) then
  begin
    if Assigned(OnHasSpinEdit) then
      OnHasSpinEdit(Self,ACol,ARow,Result)
    else
    begin
      if ControlLook.SpinButtonsAlwaysVisible then
      begin
        TheEditor := DefaultEditor;
        if AEditor = edNone then
          GetStaticCellEditor(ACol,ARow,TheEditor)
        else
          TheEditor := AEditor;
        Result := TheEditor in [edSpinEdit, edFloatSpinEdit, edTimeSpinEdit, edDateSpinEdit];
      end;
    end;
  end;
end;

procedure TAdvStringGrid.GetStaticCellEditor(ACol,ARow: Integer;var AEditor:TEditorType);
begin
  if Assigned(OnGetEditorType) then
    OnGetEditorType(Self,ACol,ARow,AEditor);
end;

procedure TAdvStringGrid.GetCellEditor(ACol,ARow: Integer;var AEditor:TEditorType);
begin
  if Assigned(OnGetEditorType) then
    OnGetEditorType(Self,ACol,ARow,AEditor);
end;

function TAdvStringGrid.GetEditorNone(ACol: Integer; ARow: Integer): boolean;
var
  AEditor: TEditorType;
begin
  Result := false;
  if Assigned(OnGetEditorType) then
  begin
    AEditor := edNormal;
    OnGetEditorType(Self,ACol,ARow,AEditor);
    Result := AEditor = edNone;
  end;
end;

procedure TAdvStringGrid.GetCellFixed(ACol,ARow: Integer; var IsFixed: Boolean);
begin
  IsFixed := IsFixed or ((FFixedRowAlways and (ARow <= FFixedRowsMin) and (RowCount = FFixedRowsMin)) or
             (FFixedColAlways and (ACol < FFixedColsMin) and (ColCount = FFixedColsMin)) or
             (ACol < FixedCols) or (ARow < FixedRows));

  if Assigned(OnIsFixedCell) and not IsFixed then
    OnIsFixedCell(Self,ARow,ACol,IsFixed);
end;

function TAdvStringGrid.GetCellFont(i, j: Integer): TFont;
var
  cp: TCellProperties;
begin
  if HasCellProperties(i,j) then
  begin
    cp := Cellproperties[i,j];
    cf.Name := cp.FontName;
    cf.Size := cp.FontSize;
    cf.Style := cp.FontStyle;
    cf.Color := cp.FontColor;
    Result := cf;
  end
  else
    Result := Font;
end;

procedure TAdvStringGrid.DoSetCellCursor(ACol, ARow, X, Y: Integer);
var
  ACursor: TCursor;
begin
  if Assigned(OnGetCellCursor) then
  begin
    ACursor := Screen.Cursor;
    OnGetCellCursor(Self, ACol, ARow, X, Y, ACursor);
    if ACursor <> Cursor then
      SetCursor(Screen.Cursors[ACursor]);
  end;
end;

procedure TAdvStringGrid.DoSearchFooterAction(AValue: string; ACol: Integer; ARow: Integer; ASearchAction: TSearchAction);
begin
  if Assigned(OnSearchFooterAction) then
    OnSearchFooterAction(Self, AValue, ACol, ARow, ASearchAction);
end;

procedure TAdvStringGrid.DoSearchFooterSearchEnd(var ContinueFromStart: boolean);
begin
  if Assigned(OnSearchFooterSearchEnd) then
    OnSearchFooterSearchEnd(Self, ContinueFromStart);
end;

procedure TAdvStringGrid.HandleButtonClick(Sender: TObject);
begin
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Self, Col, Row);
end;

procedure TAdvStringGrid.DoButtonClick(ACol: Integer; ARow: Integer);
begin
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Self, ACol, ARow);
end;

procedure TAdvStringGrid.DoExpandClick(ACol: Integer; ARow: Integer; Expanded: boolean);
var
  nh: integer;
begin
  if Assigned(FOnExpandClick) then
    FOnExpandClick(Self, ACol, ARow, Expanded);

  nh := GetExpandHeight(ACol,ARow,Expanded);

  RowHeights[ARow] := nh;
end;

procedure TAdvStringGrid.DoComboCloseUp(ARow: Integer; ACol: Integer);
begin
  if Assigned(OnComboCloseUp) then
    OnComboCloseUp(Self, ARow, ACol);
end;

procedure TAdvStringGrid.DoComboDropDown(ARow: Integer; ACol: Integer);
var
  ch: integer;
  r: TRect;
begin
  r := CellRect(ACol,ARow);
  ch := r.Bottom - r.Top;

  SendMessage(EditCombo.Handle, CB_SETITEMHEIGHT, -1, ch - 6);

  if Assigned(OnComboDropDown) then
    OnComboDropDown(Self, ARow, ACol);
end;

procedure TAdvStringGrid.DoCanSort(ACol: integer; var CanSort: boolean);
begin
  if (Assigned(FOnCanSort)) then
    FOnCanSort(self,ACol,CanSort);
end;

procedure TAdvStringGrid.DoCanEditCell(ACol,ARow: Integer; var CanEdit: boolean);
begin
  if Assigned(FOnCanEditCell) then
    FOnCanEditCell(Self,ARow,ACol,CanEdit);
end;

procedure TAdvStringGrid.GetCellReadOnly(ACol,ARow: Integer;var IsReadOnly: Boolean);
var
  BC: TPoint;
begin
  BC := BaseCell(ACol, ARow);

  if HasCellProperties(BC.X,BC.Y) and IsReadOnly then
  begin
    IsReadOnly := not (ReadOnly[BC.X,BC.Y]);
    if (not (goEditing in Options) and not FEditDisable) and not MouseActions.RangeSelectAndEdit then
      IsReadOnly := false;
    if BC.X < ColCount + NumHiddenColumns then
      DoCanEditCell(BC.X, BC.Y, IsReadOnly);
    Exit;
  end;

  if BC.X < ColCount + NumHiddenColumns then
    DoCanEditCell(BC.X, BC.Y, IsReadOnly)
  else
    IsReadOnly := true;
end;

procedure TAdvStringGrid.GetCellPassword(ACol,ARow: Integer;var IsPassword: Boolean);
begin
  if Assigned(OnIsPasswordCell) then
    OnIsPasswordCell(Self,ARow,ACol,IsPassword);
end;

procedure TAdvStringGrid.GetCellWordWrap(ACol,ARow: Integer;var WordWrap: Boolean);
begin
  if Assigned(OnGetWordWrap) then
    OnGetWordWrap(Self,ACol,ARow,WordWrap);
end;

procedure TAdvStringGrid.GetDefaultProps(ACol,ARow: Integer; AFont: TFont; ABrush: TBrush; var AColorTo, AMirrorColor, AMirrorColorTo: TColor;
  var HA: TAlignment; var VA: TVAlignment; var WW: boolean; var GD: TCellGradientDirection);
var
  AState: TGridDrawState;
  UDF: boolean;
begin
  AState := [];

  UDF := FUseDisabledFont;
  FUseDisabledFont := false;
  GD := GradientVertical;

  GetVisualProperties(ACol,ARow, AState, false, false, false, ABrush, AColorTo, AMirrorColor, AMirrorColorTo, AFont, HA, VA, WW, GD);

  FUseDisabledFont := UDF;

  if IsFixed(Acol,ARow) then
  begin
    ABrush.Color := clNone;
    AColorTo := clNone;
  end;

  if Bands.Active or (Background.Display in [bdGradientHorz, bdGradientVert]) then
  begin
    ABrush.Color := clNone;
    AColorTo := clNone;
  end;

  if (gdSelected in AState) then
  begin
    ABrush.Color := clNone;
    AColorTo := clNone;
  end;
end;

function TAdvStringGrid.GetCheckTrue(ACol,ARow: Integer): string;
begin
  Result := FCheckTrue;

  if Assigned(OnGetCheckTrue) then
    OnGetCheckTrue(Self,ACol,ARow,Result);
end;

function TAdvStringGrid.GetCheckFalse(ACol,ARow: Integer): string;
begin
  Result := FCheckFalse;

  if Assigned(OnGetCheckFalse) then
    OnGetCheckFalse(Self,ACol,ARow,Result);
end;

function TAdvStringGrid.GetFilter(ACol: Integer; Disp: boolean = false): Boolean;
var
  i: integer;
  s,sq: string;
  colfltr: boolean;
  dck: boolean;

begin
  FFilterList.Clear;
  FFilterList.CaseSensitive := FilterDropDown.CaseSensitive;
  FFilterList.Sorted := false;

  if FilterDropDownAuto and ((ACol >= FixedCols) or (FilterDropDownColumns = fdAll)) then
  begin
    FFilterList.Sorted := FilterDropdown.Sorted;

    dck := false;

    if IsDataCheckCol(ACol) and (FilterDropDown.TextChecked <> '') and (FilterDropDown.TextUnChecked <> '') then
    begin
      FFilterList.Add(FilterDropDown.TextChecked);
      FFilterList.Add(FilterDropDown.TextUnChecked);
      dck := true;
    end
    else
    begin
      // in visible rows
      for i := FixedRows to RowCount - 1 - FixedFooters do
      begin
        // skip node rows
        if IsNode(i) then
          Continue;

        s := SysUtils.Trim(StrippedCells[ACol, i]);

        if s = '' then
          s := #9'""';

        if (Pos(' ',s) > 0) then
        begin
          if Pos('"', s) > 0 then
            sq := StringReplace(s, '"','""',[rfReplaceAll])
          else
            sq := s;

          s := s + #9'"'+sq+'"';
        end;

        if dck then
        begin
          if (s = CheckTrue) or (s = CheckFalse) then
            Continue;
        end;

    //    if (s <> '') then
        begin
          if FFilterList.IndexOf(s) = -1 then
          begin
            FFilterList.Add(s);
          end;
        end;

        if Disp and (FFilterList.Count > 0) then
          break;
      end;
    end;

    colfltr := Filter.HasFilter(ACol);

    // in hidden row list
    if not (FilterIncremental or dck or (FilterDropDownMultiCol and not colfltr)) then
    begin
      for i := 1 to FGridItems.Count do
      begin
        s := SysUtils.Trim((FGridItems.Items[i - 1] as TGridItem).Items[ACol]);

        if Assigned(OnGetDisplText) then
          OnGetDisplText(Self, ACol, (FGridItems.Items[i - 1] as TGridItem).Idx, s);

        if s = '' then
          s := #9'""';

        if pos(' ',s) > 0 then
        begin
          if Pos('"', s) > 0 then
            sq := StringReplace(s, '"','""',[rfReplaceAll])
          else
            sq := s;

          s := s + #9'"'+sq+'"';
        end;

        if dck then
        begin
          if (s = CheckTrue) or (s = CheckFalse) then
            Continue;
        end;

        //if FFilterList.IndexOf(s) <> -1 then
        FFilterList.Add(s);

        if Disp and (FFilterList.Count > 0) then
          break;
      end;
    end;

    FFilterList.Sorted := false;

    if (FFilterDropDownClear <> '') and not FilterDropDownCheck then
      FFilterList.Insert(0,FFilterDropDownClear);

    if (FFilterDropDownCheckUnCheckAll <> '') and FilterDropDownCheck then
      FFilterList.Insert(0, FFilterDropDownCheckUnCheckAll);
  end;

  if Assigned(OnGetColumnFilter) then
    OnGetColumnFilter(Self, ACol, FFilterList);

  Result := FFilterList.Count > 0;
end;

function TAdvStringGrid.ColumnStatesToString: string;
var
  i: integer;
  res: string;
begin
  res := inttostr(ColCount + NumHiddenColumns) + '#';

  for i := 0 to ColCount - 1 + NumHiddenColumns do
  begin
    if i = 0 then
      res := res + inttostr(ColWidths[i])
    else
      res := res + ',' + inttostr(ColWidths[i]);
  end;

  res := res + '#';

  if FColumnOrder.Count = 0 then
  begin
    for i := 0 to ColCount - 1 + NumHiddenColumns do
    begin
      if i = 0 then
        res := res + IntToStr(i)
      else
        res := res + ',' + IntToStr(i);
    end;
  end
  else
    for i := 0 to FColumnOrder.Count - 1 do
    begin
      if i = 0 then
        res := res + IntToStr(FColumnOrder.Items[i])
      else
        res := res + ',' + IntToStr(FColumnOrder.Items[i]);
    end;

  res := res + '#';

  for i := 0 to ColCount - 1 + NumHiddenColumns do
  begin
    if i = 0 then
    begin
      if FVisibleCol[i] then
        res := res + '1'
      else
        res := res + '0';
    end
    else
    begin
      if FVisibleCol[i] then
        res := res + ',1'
      else
        res := res + ',0';
    end;
  end;

  Result := res;
end;

procedure TAdvStringGrid.StringToColumnStates(Value: string);
// sample: 5#27,64,22,64,64#4,0,1,2,3#1,1,1,1,1
var
  i,j: integer;
  il: TIntList;
  sl: TStringList;
  s: string;
  NewPos: integer;
  stretch: boolean;
begin
  if pos('#',value) = 0 then
    Exit;

  FColumnOrder.Clear;

  UnHideColumnsAll;

  // nr. of columns
  s := copy(value, 1, pos('#',value) - 1);

  ColCount := StrToInt(s);

  delete(value,1, pos('#',value));

  // order + visible part
  s := copy(value,pos('#',value) + 1,length(value));

  // order part
  s := copy(s,1, pos('#',s) - 1);

  sl := TStringList.Create;
  sl.CommaText := s;

  if s <> '' then
  begin
    for i := 0 to ColCount - 1 do
    begin
      if i < sl.Count then
      begin
        NewPos := StrToInt(sl.Strings[i]);
        if (NewPos <> -1) then
          FColumnOrder.Add(NewPos);
      end;
    end;

    // prepare reorganisation
    il := TIntList.Create(0,0);
    for i := 0 to ColCount - 1 do
    begin
      for j := 0 to FColumnOrder.Count - 1 do
      begin
        if (FColumnOrder[j] = i) then
          il.Add(j);
      end;
    end;

    FColumnOrder.Clear;
    for i := 0 to ColCount - 1 do
    begin
      FColumnOrder.Add(il.Items[i]);
    end;

    il.Free;

    // do reorganisation
    if FColumnOrder.Count > 0 then
      ResetColumnOrder;

    FColumnOrder.Clear;
    for i := 0 to ColCount - 1 do
    begin
      NewPos := StrToInt(sl.Strings[i]);
      if (NewPos <> -1) then
        FColumnOrder.Add(NewPos);
    end;
  end;

  // order + visible part
  s := copy(value,pos('#',value)+1,length(value));

  // visible part
  s := copy(s,pos('#',s)+1,length(s));

  sl.CommaText := s;

  for i := ColCount - 1 downto 0 do
  begin
    if sl.Strings[i] = '0' then
      HideColumn(i);
  end;

  s := copy(value,1,pos('#',value)-1);

  sl.CommaText := s;

  stretch := ColumnSize.Stretch;

  ColumnSize.Stretch := false;

  if stretch then
  begin
    if ColumnSize.StretchColumn = -1 then
      DefaultColWidth := ColWidths[ColCount - 1]
    else
      DefaultColWidth := ColWidths[ColumnSize.StretchColumn];
  end;

  for i := 0 to ColCount - 1 do
  begin
    ColWidths[i] := StrToInt(sl.Strings[i]);
  end;

  ColumnSize.Stretch := stretch;

  sl.Free;
end;

procedure TAdvStringGrid.SaveColSizes;
var
  i: Integer;
  IniFile: TCustomIniFile;

begin
  if (FColumnSize.Key<>'') and
     (FColumnSize.Section<>'') and
     (not (csDesigning in ComponentState)) then
  begin
    if FColumnSize.Location = clRegistry then
      IniFile := TRegistryIniFile.Create(FColumnSize.Key)
    else
      IniFile := TMemIniFile.Create(FColumnSize.Key);

    for i := 0 to ColCount - 1 do
      IniFile.WriteInteger(FColumnSize.section,'Col'+inttostr(i),ColWidths[i]);

    IniFile.UpdateFile;
    IniFile.Free;
  end;
end;

procedure TAdvStringGrid.LoadColSizes;
var
  i: Integer;
  IniFile: TCustomIniFile;
  NewWidth: Integer;
begin
  if (FColumnSize.Key <> '') and
     (FColumnSize.Section <> '') and
     (not (csDesigning in ComponentState)) then
  begin
    if FColumnSize.location = clRegistry then
      IniFile := TRegistryIniFile.Create(FColumnSize.Key)
    else
      IniFile := TMemIniFile(TMemIniFile.Create(FColumnSize.Key));

    for i := 0 to ColCount - 1 do
    begin
      NewWidth := IniFile.ReadInteger(FColumnSize.Section,'Col'+inttostr(i),ColWidths[i]);
      if (NewWidth <> ColWidths[i]) then
        ColWidths[i] := NewWidth;
    end;

    IniFile.UpdateFile;
    IniFile.Free;
  end;
end;

procedure TAdvStringGrid.SaveColPositions;
var
  i: Integer;
  IniFile: TCustomIniFile;

begin
  if (FColumnSize.Key <> '') and
     (FColumnSize.Section <> '') and
     (not (csDesigning in ComponentState)) then
  begin
    if FColumnSize.Location = clRegistry then
      IniFile := TRegistryIniFile.Create(FColumnSize.Key)
    else
      IniFile := TMemIniFile.Create(FColumnSize.Key);

    for i := 1 to FColumnOrder.Count do
      IniFile.WriteInteger(FColumnSize.section,'Pos'+inttostr(i-1),FColumnOrder.Items[i - 1]);

    IniFile.UpdateFile;
    IniFile.Free;
  end;
end;

procedure TAdvStringGrid.LoadColPositions;
var
  i,j: Integer;
  IniFile: TCustomIniFile;
  NewPos: Integer;
  il,hl: TIntList;
begin
  if (FColumnSize.Key <> '') and
     (FColumnSize.Section <> '') and
     (not (csDesigning in ComponentState)) then
  begin
    if FColumnSize.location = clRegistry then
      IniFile := TRegistryIniFile.Create(FColumnSize.Key)
    else
      IniFile := TMemIniFile(TMemIniFile.Create(FColumnSize.Key));

    NewPos := IniFile.ReadInteger(FColumnSize.Section,'Pos0',-1);

    if NewPos <> -1 then
    begin
      FColumnOrder.Clear;

      for i := 0 to AllColCount - 1 do
      begin
        NewPos := IniFile.ReadInteger(FColumnSize.Section,'Pos'+inttostr(i),-1);
        if (NewPos <> -1) then
          FColumnOrder.Add(NewPos);
      end;

      // prepare reorganisation
      il := TIntList.Create(0,0);
      hl := TIntList.Create(0,0);

      for i := 0 to AllColCount - 1 do
      begin

        for j := 0 to FColumnOrder.Count - 1 do
        begin
          if (FColumnOrder[j] = i) then
            il.Add(j);
        end;
      end;

      FColumnOrder.Clear;
      for i := 0 to AllColCount - 1 do
      begin
        if IsHiddenColumn(i) then
          hl.Add(i);
        FColumnOrder.Add(il.Items[i]);
      end;
      il.Free;

      UnHidecolumnsAll;

      // do reorganisation
      if FColumnOrder.Count > 0 then
        ResetColumnOrder;

      // hide columns again

      for I := 0 to hl.Count - 1 do
      begin
        HideColumn(hl.Items[I]);
      end;

      hl.Free;

      FColumnOrder.Clear;

      for i := 0 to AllColCount - 1 do
      begin
        NewPos := IniFile.ReadInteger(FColumnSize.Section,'Pos'+inttostr(i),-1);
        if (NewPos <> -1) then
          FColumnOrder.Add(NewPos);
      end;
    end;

    IniFile.UpdateFile;
    IniFile.Free;
  end;
end;

procedure TAdvStringGrid.LoadVisualProps(FileName: string);
var
  sl: TStringList;
  f: TextFile;

  function StringToBool(s: string): boolean;
  begin
    result := (Uppercase(s) = 'TRUE');
  end;

  function StringToFontStyle(s: string): TFontStyles;
  begin
    Result := [];
    if (pos('fsBold',s) > 0) then Result := Result + [fsBold];
    if (pos('fsItalic',s) > 0) then Result := Result + [fsItalic];
    if (pos('fsUnderline',s) > 0) then Result := Result + [fsUnderline];
    if (pos('fsStrikeOut',s) > 0) then Result := Result + [fsStrikeOut];
  end;

  function StringToColorEx(s: string): TColor;
  begin
    if s ='' then
      Result := clNone
    else
      Result := StringToColor(s);
  end;

begin
  AssignFile(f, FileName);
  {$i-}
  Reset(f);
  {$i+}
  if IOResult <> 0 then
    raise Exception.Create('Cannot open file ' + FileName);

  sl := TStringList.Create;

  sl.LoadFromFile(FileName);

  try
    Color := StringToColorEx(sl.Values['Color']);
    HintColor := StringToColorEx(sl.Values['HintColor']);
    SelectionColor := StringToColorEx(sl.Values['SelectionColor']);
    SelectionColorTo := StringToColorEx(sl.Values['SelectionColorTo']);
    SelectionMirrorColor := StringToColorEx(sl.Values['SelectionMirrorColor']);
    SelectionMirrorColorTo := StringToColorEx(sl.Values['SelectionMirrorColorTo']);
    SelectionTextColor := StringToColorEx(sl.Values['SelectionTextColor']);
    URLColor := StringToColorEx(sl.Values['URLColor']);
    URLShow := StringToBool(sl.Values['URLShow']);
    URLShowInText := StringToBool(sl.Values['URLShowInText']);

    ScrollColor := StringToColorEx(sl.Values['ScrollColor']);
    ActiveRowColor := StringToColorEx(sl.Values['ActiveRowColor']);
    ActiveRowShow := StringToBool(sl.Values['ActiveRowShow']);
    ActiveCellShow := StringToBool(sl.Values['ActiveCellShow']);
    Font.Color := StringToColorEx(sl.Values['Font.Color']);
    Font.Style := StringToFontStyle(sl.Values['Font.Style']);
    Font.Size := StrToInt(sl.Values['Font.Size']);
    Font.Name := sl.Values['Font.Name'];
    ActiveCellColor := StringToColorEx(sl.Values['ActiveCellColor']);
    ActiveCellColorTo := StringToColorEx(sl.Values['ActiveCellColorTo']);
    ActiveCellFont.Color := StringToColorEx(sl.Values['ActiveCellFont.Color']);
    ActiveCellFont.Style := StringToFontStyle(sl.Values['ActiveCellFont.Style']);
    ActiveCellFont.Size := StrToInt(sl.Values['ActiveCellFont.Size']);
    ActiveCellFont.Name := sl.Values['ActiveCellFont.Name'];
    FixedFont.Color := StringToColorEx(sl.Values['FixedFont.Color']);
    FixedFont.Style := StringToFontStyle(sl.Values['FixedFont.Style']);
    FixedFont.Size := StrToInt(sl.Values['FixedFont.Size']);
    FixedFont.Name := sl.Values['FixedFont.Name'];

    Balloon.BackGroundColor := StringToColorEx(sl.Values['Balloon.BackGroundColor']);
    Balloon.TextColor := StringToColorEx(sl.Values['Balloon.TextColor']);
    Balloon.Transparency := StrToInt(sl.Values['Balloon.Transparency']);

    Bands.PrimaryColor := StringToColorEx(sl.Values['Bands.PrimaryColor']);
    Bands.SecondaryColor := StringToColorEx(sl.Values['Bands.SecondaryColor']);
    Bands.Active := StringToBool(sl.Values['Bands.Active']);

    SortSettings.IndexColor := StringToColorEx(sl.Values['SortSettings.IndexColor']);
    FloatingFooter.Color := StringToColorEx(sl.Values['FloatingFooter.Color']);
    ControlLook.CheckSize := StrToInt(sl.Values['ControlLook.CheckSize']);
    ControlLook.Color := StringToColorEx(sl.Values['ControlLook.Color']);
    ControlLook.CommentColor := StringToColorEx(sl.Values['ControlLook.CommentColor']);

    if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csClassic') then
      ControlLook.ControlStyle := csClassic
    else if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csFlat') then
      ControlLook.ControlStyle := csFlat
    else if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csWinXP') then
      ControlLook.ControlStyle := csWinXP
    else if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csBorland') then
      ControlLook.ControlStyle := csBorland
    else if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csTMS') then
      ControlLook.ControlStyle := csTMS
    else if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csGlyph') then
      ControlLook.ControlStyle := csGlyph
    else if UpperCase(sl.Values['ControlLook.ControlStyle']) = UpperCase('csTheme') then
      ControlLook.ControlStyle := csTheme;

    ControlLook.FixedGradientFrom := StringToColorEx(sl.Values['ControlLook.FixedGradientFrom']);
    ControlLook.FixedGradientTo := StringToColorEx(sl.Values['ControlLook.FixedGradientTo']);
    ControlLook.RadioSize := StrToInt(sl.Values['ControlLook.RadioSize']);

    ControlLook.FlatButton := StringToBool(sl.Values['ControlLook.FlatButton']);
    ControlLook.ProgressBorderColor := StringToColorEx(sl.Values['ControlLook.ProgressBorderColor']);
    ControlLook.ProgressXP := StringToBool(sl.Values['ControlLook.ProgressXP']);

    if UpperCase(sl.Values['Look']) = UpperCase('glStandard') then
      Look := glStandard
    else if UpperCase(sl.Values['Look']) = UpperCase('glSoft') then
      Look := glSoft
    else if UpperCase(sl.Values['Look']) = UpperCase('glClassic') then
      Look := glClassic
    else if UpperCase(sl.Values['Look']) = UpperCase('glTMS') then
      Look := glTMS
    else if UpperCase(sl.Values['Look']) = UpperCase('glXP') then
      Look := glXP
    else if UpperCase(sl.Values['Look']) = UpperCase('glListView') then
      Look := glListView
    else if UpperCase(sl.Values['Look']) = UpperCase('glVista') then
      Look := glVista
    else if UpperCase(sl.Values['Look']) = UpperCase('glWin7') then
      Look := glWin7
    else if UpperCase(sl.Values['Look']) = UpperCase('glOffice2007') then
      Look := glOffice2007;

    SearchFooter.Color := StringToColorEx(sl.Values['SearchFooter.Color']);
    SearchFooter.ColorTo := StringToColorEx(sl.Values['SearchFooter.ColorTo']);

    GridLineColor := StringToColorEx(sl.Values['GridLineColor']);
    GridFixedLineColor := StringToColorEx(sl.Values['GridFixedLineColor']);

    Grouping.HeaderColor := StringToColorEx(sl.Values['Grouping.HeaderColor']);

    Grouping.HeaderColorTo := StringToColorEx(sl.Values['Grouping.HeaderColorTo']);
    Grouping.HeaderTextColor := StringToColorEx(sl.Values['Grouping.HeaderTextColor']);
    Grouping.HeaderUnderline := StringToBool(sl.Values['Grouping.HeaderUnderline']);
    Grouping.HeaderLineColor := StringToColorEx(sl.Values['Grouping.HeaderLineColor']);
    Grouping.HeaderLineWidth := StrToInt(sl.Values['Grouping.HeaderLineWidth']);
    Grouping.SummaryColor := StringToColorEx(sl.Values['Grouping.SummaryColor']);
    Grouping.SummaryColorTo := StringToColorEx(sl.Values['Grouping.SummaryColorTo']);
    Grouping.SummaryTextColor := StringToColorEx(sl.Values['Grouping.SummaryTextColor']);
    Grouping.SummaryLine := StringToBool(sl.Values['Grouping.SummaryLine']);
    Grouping.SummaryLineColor := StringToColorEx(sl.Values['Grouping.SummaryLineColor']);
    Grouping.SummaryLineWidth := StrToInt(sl.Values['Grouping.SummaryLineWidth']);

    BackGround.Top := StrToInt(sl.Values['BackGround.Top']);
    BackGround.Left := StrToInt(sl.Values['BackGround.Left']);

    if UpperCase(sl.Values['BackGround.Display']) = UpperCase('bdTile') then
      BackGround.Display := bdTile
    else if UpperCase(sl.Values['BackGround.Display']) = UpperCase('bdFixed') then
      BackGround.Display := bdFixed
    else if UpperCase(sl.Values['BackGround.Display']) = UpperCase('bdGradientHorz') then
      BackGround.Display := bdGradientHorz
    else if UpperCase(sl.Values['BackGround.Display']) = UpperCase('bdGradientVert') then
      BackGround.Display := bdGradientVert;

    if UpperCase(sl.Values['BackGround.Cells']) = UpperCase('bcNormal') then
      BackGround.Cells := bcNormal
    else if UpperCase(sl.Values['BackGround.Cells']) = UpperCase('bcFixed') then
      BackGround.Cells := bcFixed
    else if UpperCase(sl.Values['BackGround.Cells']) = UpperCase('bcAll') then
      BackGround.Cells := bcAll;

    BackGround.Color := StringToColorEx(sl.Values['BackGround.Color']);
    BackGround.ColorTo := StringToColorEx(sl.Values['BackGround.ColorTo']);

    if (sl.Values['TMSGradFrom'] <> '') then
    begin
      FTMSGradFrom := StringToColorEx(sl.Values['TMSGradFrom']);
      FTMSGradTo := StringToColorEx(sl.Values['TMSGradTo']);
      FTMSGradMirrorTo := StringToColorEx(sl.Values['TMSGradMirrorTo']);
      FTMSGradMirrorFrom := StringToColorEx(sl.Values['TMSGradMirrorFrom']);

      ControlLook.FixedGradientFrom := FTMSGradFrom;
      ControlLook.FixedGradientTo := FTMSGradTo;
      ControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      ControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      SelectionStyle := TGridSelectionStyle(StrToInt(sl.Values['SelectionStyle']))
    end;

    SelectionColor := StringToColorEx(sl.Values['SelectionColor']);
    SelectionColorTo := StringToColorEx(sl.Values['SelectionColorTo']);
    SelectionMirrorColor := StringToColorEx(sl.Values['SelectionMirrorColor']);
    SelectionMirrorColorTo := StringToColorEx(sl.Values['SelectionMirrorColorTo']);
    SelectionTextColor := StringToColorEx(sl.Values['SelectionTextColor']);


    FLook := glCustom;

  finally
    sl.Free;
    CloseFile(f);
  end;
end;

procedure TAdvStringGrid.SaveVisualProps(FileName: string);
var
  f: TextFile;
  sl: TStringList;

  procedure WriteColor(Name: string; Color: TColor);
  begin
    writeln(f,Name+'='+ColorToString(Color));
  end;

  procedure WriteBool(Name: string; b: Boolean);
  begin
    if b then
      writeln(f,Name+'=true')
    else
      writeln(f,Name+'=false');
  end;

  procedure WriteInt(Name: string; i: Integer);
  begin
    writeln(f,Name+'='+inttostr(i));
  end;

  procedure WriteString(Name, Value: string);
  begin
    writeln(f,Name+'='+Value);
  end;

  procedure WriteFont(Name: string; AFont: TFont);
  begin
    WriteColor(Name+'.Color',AFont.Color);
    sl.Clear;
    if fsBold in AFont.Style then       sl.Add('fsBold');
    if fsItalic in AFont.Style then     sl.Add('fsItalic');
    if fsUnderline in AFont.Style then  sl.Add('fsUnderline');
    if fsStrikeOut in AFont.Style then  sl.Add('fsStrikeOut');
    WriteString(Name + '.Style',sl.CommaText);
    WriteInt(Name + '.Size',AFont.Size);
    WriteString(Name + '.Name',AFont.Name);
  end;

begin
  AssignFile(f, FileName);
  {$i-}
  Rewrite(f);
  {$i+}
  if IOResult <> 0 then
    raise Exception.Create('Cannot Create ' + FileName);

  sl:= TStringList.Create;

  //--- Color
  WriteColor('Color',self.Color);
  WriteColor('HintColor',HintColor);
  WriteColor('SelectionColor',SelectionColor);
  WriteColor('SelectionColorTo',SelectionColorTo);
  WriteColor('SelectionMirrorColor',SelectionMirrorColor);
  WriteColor('SelectionMirrorColorTo',SelectionMirrorColorTo);
  WriteColor('SelectionTextColor',SelectionTextColor);

  WriteColor('URLColor',self.URLColor);
  WriteBool('URLShow',self.URLShow);
  WriteBool('URLShowInText',self.URLShowInText);
  WriteColor('ScrollColor',self.ScrollColor);
  WriteColor('ActiveRowColor',self.ActiveRowColor);
  WriteBool('ActiveRowShow',self.ActiveRowShow);
  WriteBool('ActiveCellShow',self.ActiveCellShow);

  WriteFont('Font',Font);

  //-- ActiveCellColors
  WriteColor('ActiveCellColor',ActiveCellColor);
  WriteColor('ActiveCellColorTo',ActiveCellColorTo);

  //-- ActiveCellFont;
  WriteFont('ActiveCellFont',ActiveCellFont);

  //-- FixedFont
  WriteFont('FixedFont',FixedFont);

  //-- Balloon
  WriteColor('Balloon.BackgroundColor',Balloon.BackGroundColor);
  WriteColor('Balloon.TextColor',Balloon.TextColor);
  WriteInt('Balloon.Transparency',Balloon.Transparency);


  //-- Bands
  WriteColor('Bands.PrimaryColor',Bands.PrimaryColor);
  WriteColor('Bands.SecondaryColor',Bands.SecondaryColor);
  WriteBool('Bands.Active',Bands.Active);

  //--SortSettings
  WriteColor('SortSettings.IndexColor',SortSettings.IndexColor);

  //--FloatingFooter
  WriteColor('FloatingFooter.Color',FloatingFooter.Color);

  //-- ControlLook

  WriteInt('ControlLook.CheckSize',ControlLook.CheckSize);

  WriteColor('ControlLook.Color',ControlLook.Color);
  WriteColor('ControlLook.CommentColor',ControlLook.CommentColor);
  
  case ControlLook.ControlStyle of
    csClassic:  WriteString('ControlLook.ControlStyle','csClassic');
    csFlat:     WriteString('ControlLook.ControlStyle','csFlat');
    csWinXP:    WriteString('ControlLook.ControlStyle','csWinXP');
    csBorland:  WriteString('ControlLook.ControlStyle','csBorland');
    csTMS:      WriteString('ControlLook.ControlStyle','csTMS');
    csGlyph:    WriteString('ControlLook.ControlStyle','csGlyph');
    csTheme:    WriteString('ControlLook.ControlStyle','csTheme');
  end;

  WriteColor('ControlLook.FixedGradientFrom',ControlLook.FixedGradientFrom);
  WriteColor('ControlLook.FixedGradientTo',ControlLook.FixedGradientTo);
  WriteInt('ControlLook.RadioSize',ControlLook.RadioSize);
  WriteBool('ControlLook.FlatButton',ControlLook.FlatButton);

  WriteColor('ControlLook.ProgressBorderColor',ControlLook.ProgressBorderColor);
  WriteBool('ControlLook.ProgressXP',ControlLook.ProgressXP);

  WriteString('Look',GetLookAsString(Look));

  //-- SearchFooter
  WriteColor('SearchFooter.Color',SearchFooter.Color);
  WriteColor('SearchFooter.ColorTo',SearchFooter.ColorTo);

  //-- Grouping;
  WriteColor('Grouping.HeaderColor', Grouping.HeaderColor);
  WriteColor('Grouping.HeaderColorTo', Grouping.HeaderColorTo);
  WriteColor('Grouping.HeaderTextColor', Grouping.HeaderTextColor);
  WriteBool('Grouping.HeaderUnderline',Grouping.HeaderUnderline);

  WriteColor('Grouping.HeaderLineColor',Grouping.HeaderLineColor);
  WriteInt('Grouping.HeaderLineWidth', Grouping.HeaderLineWidth);

  WriteColor('Grouping.SummaryColor',  Grouping.SummaryColor);
  WriteColor('Grouping.SummaryColorTo', Grouping.SummaryColorTo);
  WriteColor('Grouping.SummaryTextColor', Grouping.SummaryTextColor);

  WriteBool('Grouping.SummaryLine',Grouping.SummaryLine);

  WriteColor('Grouping.SummaryLineColor', Grouping.SummaryLineColor);
  WriteInt('Grouping.SummaryLineWidth', Grouping.SummaryLineWidth);

  WriteColor('GridLineColor',GridLineColor);
  WriteColor('GridFixedLineColor',GridFixedLineColor);

  //-- BackGround;
  WriteInt('BackGround.Top', BackGround.Top);
  WriteInt('BackGround.Left', BackGround.Left);

  case BackGround.Display of
    bdTile:          WriteString('BackGround.Display','bdTile');
    bdFixed:         WriteString('BackGround.Display','bdFixed');
    bdGradientHorz:  WriteString('BackGround.Display','bdGradientHorz');
    bdGradientVert:  WriteString('BackGround.Display','bdGradientVert');
  end;

  case BackGround.Cells of
    bcNormal:        WriteString('BackGround.Cells','bcNormal');
    bcFixed:         WriteString('BackGround.Cells','bcFixed');
    bcAll:           WriteString('BackGround.Cells','bcAll');
  end;

  WriteColor('BackGround.Color',BackGround.Color);
  WriteColor('BackGround.ColorTo',BackGround.ColorTo);

  WriteColor('TMSGradFrom',FTMSGradFrom);
  WriteColor('TMSGradTo',FTMSGradTo);
  WriteColor('TMSGradMirrorFrom',FTMSGradMirrorFrom);
  WriteColor('TMSGradMirrorTo',FTMSGradMirrorTo);
  WriteInt('SelectionStyle',integer(SelectionStyle));
  //-- end BackGround

  sl.Free;
  CloseFile(f);
end;

procedure TAdvStringGrid.SavePrintSettings(Key,Section:string);
var
  IniFile: TMemIniFile;

  function Bool2String(b: Boolean): string;
  begin
    if b then Result := 'Y' else Result := 'N';
  end;

  function Set2Int(fs:TFont): Integer;
  begin
    Result :=0;
    if (fsBold in fs.Style) then Result := Result + 1;
    if (fsItalic in fs.Style) then Result := Result + 2;
    if (fsUnderLine in fs.Style) then Result := Result + 4;
    if (fsStrikeOut in fs.Style) then Result := Result + 8;
  end;


begin
  IniFile := TMemIniFile.Create(Key);

  IniFile.writeInteger(section,'ColumnSpacing',FPrintSettings.ColumnSpacing);
  IniFile.WriteInteger(section,'RowSpacing',FPrintSettings.RowSpacing);
  IniFile.WriteInteger(section,'TitleSpacing',FPrintSettings.TitleSpacing);

  IniFile.writeInteger(section,'FixedHeight',FPrintSettings.FixedHeight);
  IniFile.writeInteger(section,'FixedWidth',FPrintSettings.FixedWidth);

  IniFile.WriteString(section,'Centered',bool2string(FPrintSettings.Centered));
  IniFile.WriteString(section,'NoAutoSize',bool2string(FPrintSettings.NoAutoSize));
  IniFile.WriteString(section,'NoAutoSizeRow',bool2string(FPrintSettings.NoAutoSizeRow));

  IniFile.WriteString(section,'UseFixedHeight',bool2string(FPrintSettings.UseFixedHeight));
  IniFile.WriteString(section,'UseFixedWidth',bool2string(FPrintSettings.UseFixedWidth));
  IniFile.WriteString(section,'RepeatFixedRows',bool2string(FPrintSettings.RepeatFixedRows));
  IniFile.WriteString(section,'RepeatFixedCols',bool2string(FPrintSettings.RepeatFixedCols));

  IniFile.WriteString(section,'UseDisplFont',bool2string(FPrintSettings.UseDisplayFont));
  IniFile.WriteString(section,'UseDefOrientation',bool2string(FPrintSettings.UseDefaultOrientation));

  IniFile.WriteInteger(section,'Borders',ord(FPrintSettings.Borders));
  IniFile.WriteInteger(section,'BorderColor',Integer(FPrintSettings.BorderColor));
  IniFile.WriteInteger(section,'BorderStyle',ord(FPrintSettings.BorderStyle));
  IniFile.WriteInteger(section,'Date',ord(FPrintSettings.Date));
  IniFile.WriteInteger(section,'PageNr',ord(FPrintSettings.PageNr));
  IniFile.WriteInteger(section,'Title',ord(FPrintSettings.Title));
  IniFile.WriteInteger(section,'Time',ord(FPrintSettings.Time));

  IniFile.WriteString(section,'DateFormat',FPrintSettings.DateFormat);
  IniFile.WriteString(section,'TitleText',FPrintSettings.TitleText);

  IniFile.WriteInteger(section,'FooterSize',FPrintSettings.FooterSize);
  IniFile.WriteInteger(section,'HeaderSize',FPrintSettings.HeaderSize);
  IniFile.WriteInteger(section,'LeftSize',FPrintSettings.LeftSize);
  IniFile.WriteInteger(section,'RightSize',FPrintSettings.RightSize);

  IniFile.WriteInteger(section,'FitToPage',ord(FPrintSettings.FitToPage));

  IniFile.WriteString(section,'FontName',FPrintSettings.Font.name);
  IniFile.WriteInteger(section,'FontSize',FPrintSettings.Font.Size);
  IniFile.WriteInteger(section,'FontStyle',Set2Int(FPrintSettings.Font));
  IniFile.WriteInteger(section,'FontColor',Integer(FPrintSettings.Font.Color));

  IniFile.WriteString(section,'HeaderFontName',FPrintSettings.HeaderFont.name);
  IniFile.WriteInteger(section,'HeaderFontSize',FPrintSettings.HeaderFont.Size);
  IniFile.WriteInteger(section,'HeaderFontStyle',Set2Int(FPrintSettings.HeaderFont));
  IniFile.WriteInteger(section,'HeaderFontColor',ord(FPrintSettings.HeaderFont.Color));

  IniFile.WriteString(section,'FooterFontName',FPrintSettings.FooterFont.name);
  IniFile.WriteInteger(section,'FooterFontSize',FPrintSettings.FooterFont.Size);
  IniFile.WriteInteger(section,'FooterFontStyle',Set2Int(FPrintSettings.FooterFont));
  IniFile.WriteInteger(section,'FooterFontColor',ord(FPrintSettings.FooterFont.Color));

  IniFile.WriteString(section,'PageNumSep',FPrintSettings.PageNumSep);
  IniFile.WriteString(section,'PageSuffix',FPrintSettings.PageSuffix);
  IniFile.WriteString(section,'PagePrefix',FPrintSettings.PagePrefix);

  IniFile.WriteInteger(section,'Orientation',ord(FPrintSettings.Orientation));

  IniFile.WriteString(section,'TitleLines',LFToCLF(FPrintSettings.TitleLines.Text));
  IniFile.WriteString(section,'PrintGraphics',bool2string(FPrintSettings.PrintGraphics));

  IniFile.UpdateFile;
  IniFile.Free;
end;

procedure TAdvStringGrid.LoadPrintSettings(Key,Section:string);
var
  IniFile: TMemIniFile;

  function Int2Set(i: Integer;fs:TFont): Integer;
  begin
    Result := 0;
    if i and 1 > 0 then fs.Style := fs.Style + [fsBold];
    if i and 2 > 0 then fs.Style := fs.Style + [fsItalic];
    if i and 4 > 0 then fs.Style := fs.Style + [fsUnderLine];
    if i and 8 > 0 then fs.Style := fs.Style + [fsStrikeOut];
  end;

  function Int2Pos(i: Integer):TPrintPosition;
  begin
    case i of
    0:Result := ppNone;
    1:Result := ppTopLeft;
    2:Result := ppTopRight;
    3:Result := ppTopCenter;
    4:Result := ppBottomLeft;
    5:Result := ppBottomRight;
    6:Result := ppBottomCenter;
    else Result := ppNone;
    end;
  end;

begin
  IniFile := TMemIniFile.Create(Key);

  FPrintSettings.ColumnSpacing := IniFile.readInteger(Section,'ColumnSpacing',20);
  FPrintSettings.RowSpacing := IniFile.readInteger(Section,'RowSpacing',20);
  FPrintSettings.TitleSpacing := IniFile.readInteger(Section,'TitleSpacing',20);

  FPrintSettings.FixedHeight := IniFile.readInteger(Section,'FixedHeight',0);
  FPrintSettings.FixedWidth := IniFile.readInteger(Section,'FixedWidth',0);

  FPrintSettings.Centered := IniFile.ReadString(Section,'Centered','Y') = 'Y';
  FPrintSettings.NoAutoSize := IniFile.ReadString(Section,'NoAutoSize','N') = 'Y';
  FPrintSettings.NoAutoSizeRow := IniFile.ReadString(Section,'NoAutoSizeRow','N') = 'Y';
  FPrintSettings.UseFixedHeight := IniFile.ReadString(Section,'UseFixedHeight','N') = 'Y';
  FPrintSettings.UseFixedWidth := IniFile.ReadString(Section,'UseFixedWidth','N') = 'Y';
  FPrintSettings.RepeatFixedRows := IniFile.ReadString(Section,'RepeatFixedRows','N') = 'Y';
  FPrintSettings.RepeatFixedCols := IniFile.ReadString(Section,'RepeatFixedCols','N') = 'Y';

  FPrintSettings.UseDisplayFont := IniFile.ReadString(Section,'UseDisplFont','N') = 'Y';
  FPrintSettings.UseDefaultOrientation := IniFile.ReadString(Section,'UseDefOrientation','N') = 'Y';

  FPrintSettings.DateFormat := IniFile.ReadString(Section,'DateFormat','');
  FPrintSettings.TitleText := IniFile.ReadString(Section,'TitleText','');

  FPrintSettings.FooterSize := IniFile.ReadInteger(Section,'FooterSize',100);
  FPrintSettings.HeaderSize := IniFile.ReadInteger(Section,'HeaderSize',100);
  FPrintSettings.LeftSize := IniFile.ReadInteger(Section,'LeftSize',100);
  FPrintSettings.RightSize := IniFile.ReadInteger(Section,'RightSize',100);

  FPrintSettings.PageNumSep := IniFile.ReadString(Section,'PageNumSep','');
  FPrintSettings.PageSuffix := IniFile.ReadString(Section,'PageSuffix','');
  FPrintSettings.PagePrefix := IniFile.ReadString(Section,'PagePrefix','');

  FPrintSettings.PrintGraphics := IniFile.ReadString(Section,'PrintGraphics','N') = 'Y';

  case IniFile.ReadInteger(Section,'Borders',0) of
  0:FPrintSettings.Borders := pbNoborder;
  1:FPrintSettings.Borders := pbSingle;
  2:FPrintSettings.Borders := pbDouble;
  3:FPrintSettings.Borders := pbVertical;
  4:FPrintSettings.Borders := pbHorizontal;
  5:FPrintSettings.Borders := pbAround;
  6:FPrintSettings.Borders := pbAroundVertical;
  7:FPrintSettings.Borders := pbAroundHorizontal;
  8:FPrintSettings.Borders := pbCustom;
  end;

  case IniFile.ReadInteger(Section,'BorderStyle',0) of
  0:FPrintSettings.BorderStyle := psSolid;
  1:FPrintSettings.BorderStyle := psDash;
  2:FPrintSettings.BorderStyle := psDot;
  3:FPrintSettings.BorderStyle := psDashDot;
  4:FPrintSettings.BorderStyle := psDashDotDot;
  5:FPrintSettings.BorderStyle := psClear;
  6:FPrintSettings.BorderStyle := psInsideFrame;
  end;

  FPrintSettings.BorderColor := TColor(IniFile.ReadInteger(Section, 'BorderColor', clBlack));

  FPrintSettings.Date := int2pos(IniFile.ReadInteger(Section,'Date',0));
  FPrintSettings.PageNr := int2pos(IniFile.ReadInteger(Section,'PageNr',0));
  FPrintSettings.Title := int2pos(IniFile.ReadInteger(Section,'Title',0));
  FPrintSettings.Time := int2pos(IniFile.ReadInteger(Section,'Time',0));

  case IniFile.ReadInteger(Section,'FitToPage',0) of
  0:FPrintSettings.FitToPage := fpNever;
  1:FPrintSettings.FitToPage := fpGrow;
  2:FPrintSettings.FitToPage := fpShrink;
  3:FPrintSettings.FitToPage := fpAlways;
  4:FPrintSettings.FitToPage := fpCustom;
  end;

  FPrintSettings.Font.name := IniFile.ReadString(Section,'FontName','Arial');
  FPrintSettings.Font.Size := IniFile.ReadInteger(Section,'FontSize',10);
  Int2Set(IniFile.ReadInteger(Section,'FontStyle',0),FPrintSettings.Font);
  FPrintSettings.Font.Color := IniFile.ReadInteger(Section,'FontColor',clBlack);

  FPrintSettings.HeaderFont.name := IniFile.ReadString(Section,'HeaderFontName','Arial');
  FPrintSettings.HeaderFont.Size := IniFile.ReadInteger(Section,'HeaderFontSize',10);
  Int2Set(IniFile.ReadInteger(Section,'HeaderFontStyle',0),FPrintSettings.HeaderFont);
  FPrintSettings.HeaderFont.Color := IniFile.ReadInteger(Section,'HeaderFontColor',clBlack);

  FPrintSettings.FooterFont.name := IniFile.ReadString(Section,'FooterFontName','Arial');
  FPrintSettings.FooterFont.Size := IniFile.ReadInteger(Section,'FooterFontSize',10);
  Int2Set(IniFile.ReadInteger(Section,'FooterFontStyle',0),FPrintSettings.FooterFont);
  FPrintSettings.FooterFont.Color := IniFile.ReadInteger(Section,'FooterFontColor',clBlack);

  FPrintSettings.TitleLines.Text := CLFToLF(IniFile.ReadString(Section,'TitleLines',''));

  case IniFile.ReadInteger(Section,'Orientation',0) of
  0:FPrintSettings.Orientation := poPortrait;
  1:FPrintSettings.Orientation := poLandScape;
  end;

  IniFile.UpdateFile;
  IniFile.Free;
end;

procedure TAdvStringGrid.AddBalloon(ACol, ARow: integer; Title, Text: string; Icon: TBalloonIcon);
var
  sl: TStringList;
  cg: TCellGraphic;
begin
  sl := TStringList.Create;
  sl.Add(Title);
  sl.Add(Text);

  cg := GetCellGraphic(ACol,ARow);

  if cg = nil then
  begin
    cg := CreateCellGraphic(ACol,ARow);
    cg.CellType := ctBalloon;
    cg.CellAngle := 0;
  end
  else
  begin
    if (cg.CellType in [ctCheckBox, ctDataCheckBox, ctRadioButton]) then
    begin
      cg.CellAngle := 1;
    end
    else
      Exit;
  end;

  cg.CellIndex := Integer(Icon);
  cg.CellBitmap := TBitmap(sl);
end;

procedure TAdvStringGrid.RemoveBalloon(ACol, ARow: integer);
var
  cg: TCellGraphic;
  sl: TStringList;
begin
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then Exit;

  if ((cg.CellType in [ctCheckBox, ctDataCheckBox, ctRadioButton]) and (cg.CellAngle = 1)) then
  begin
    cg.CellAngle := 0;
    sl := TStringList(cg.CellBitmap);
    cg.CellBitmap := nil;
    sl.Free;
  end
  else
    RemoveCellGraphic(ACol,ARow,ctBalloon);
end;

function TAdvStringGrid.HasBalloon(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow,[ctBalloon]);
end;

function TAdvStringGrid.IsBalloon(Acol,ARow: integer; var Title, Text: string; var Icon: TBalloonIcon): boolean;
var
  cg: TCellGraphic;
  sl: TStringList;
begin
  Result := False;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then Exit;

  Result := (cg.CellType = ctBalloon) or ((cg.CellType in [ctCheckBox, ctDataCheckBox, ctRadioButton]) and (cg.CellAngle = 1));

  if Result then
  begin
    if Assigned(cg.CellBitmap) then
    begin
      sl := TStringList(cg.CellBitmap);
      Title := sl.Strings[0];
      Text := sl.Strings[1];
      Icon := TBalloonIcon(cg.CellIndex);
    end;
  end;
end;

function TAdvStringGrid.IsCellGraphic(ACol,ARow: integer; CTSet: TCellTypeSet): boolean;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := False;
  if (ACol >= 0) and (Arow >= 0) then
  begin
    BC := BaseCell(ACol,ARow);
    cg := GetCellGraphic(BC.X,BC.Y);
    if cg = nil then
      Exit;
    Result := cg.CellType in CTSet;
  end;
end;

procedure TAdvStringGrid.AddRadio(ACol,ARow,DirRadio,IdxRadio: Integer;sl:TStrings);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctRadio;
    CellAngle := sl.Count;
    CellBoolean := (DirRadio <> 0);
    CellIndex := IdxRadio;
    CellBitmap := TBitmap(sl);
  end;
end;

function TAdvStringGrid.CreateRadio(ACol,ARow,DirRadio,IdxRadio: Integer): TStrings;
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctRadio;
    CellAngle := 0;
    CellBoolean := (DirRadio <> 0);
    CellIndex := IdxRadio;
    CellBitmap := TBitmap(TStringList.Create);
    Result := TStrings(CellBitmap);
    CellCreated := True;
  end;
end;

function TAdvStringGrid.GetRadioIdx(ACol,ARow: Integer;var IdxRadio: Integer): Boolean;
var
  cg: TCellGraphic;
begin
  Result := False;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;
  Result := cg.CellType = ctRadio;
  IdxRadio := cg.CellIndex;
end;

function TAdvStringGrid.SetRadioIdx(ACol,ARow,IdxRadio: Integer): Boolean;
var
  cg: TCellGraphic;
begin
  Result := False;

  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;
  Result := cg.CellType = ctRadio;
  cg.CellIndex := IdxRadio;

  if IdxRadio = -1 then
    Cells[ACol,ARow] := '';

  RepaintCell(ACol,ARow);
end;


function TAdvStringGrid.GetRadioStrings(ACol,ARow: Integer): TStrings;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := nil;

  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then
    Exit;

  if cg.CellType = ctRadio then
    Result := TStrings(cg.CellBitmap);
 end;

function TAdvStringGrid.IsRadio(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow,[ctRadio]);
end;

procedure TAdvStringGrid.RemoveRadio(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctRadio);
end;

function TAdvStringGrid.HasExpand(ACol,ARow: Integer): boolean;
begin
  Result := IsCellGraphic(ACol,ARow,[ctExpand]);
end;

procedure TAdvStringGrid.AddExpand(ACol,ARow, ExpandedHeight: integer);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctExpand;
    CellAngle := ExpandedHeight;
    CellVar := false;
    CellIndex := RowHeights[ARow];
  end;
end;

procedure TAdvStringGrid.RemoveExpand(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctExpand);
end;

function TAdvStringGrid.ToggleExpand(ACol,ARow: Integer): boolean;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := False;

  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then
    Exit;

  cg.CellVar := not cg.CellVar;
  Result := cg.CellVar;
end;

function TAdvStringGrid.GetExpandState(ACol,ARow: Integer): boolean;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := false;

  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then
    Exit;

  Result := cg.CellVar;
end;

function TAdvStringGrid.GetExpandHeight(ACol,ARow: Integer; Expanded: boolean): integer;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := DefaultRowHeight;

  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then
    Exit;

  if Expanded then
    Result := cg.CellAngle
  else
    Result := cg.CellIndex;
end;

{
procedure TAdvStringGrid.AddDetailRow(ARow,Height: Integer);
var
  rr: Integer;
begin
  rr := RemapRow(ARow);

  outputdebugstring(pchar(inttostr(rr)));

  AddNode(arow,1);
  InsertChildRow(ARow);

//  RowHeights[rr + 1] := Height;
//  MergeCells(FixedCols, rr + 1, ColCount - FixedCols,1);
//  SetNodeSpan(arow,2);

  ContractNode(arow);
end;

procedure TAdvStringGrid.RemoveDetailRow(ARow: Integer);
var
  w: Integer;
  rr: Integer;
begin
  rr := RemapRow(ARow);
  w := RowHeights[RowCount - 1];

  ExpandNode(rr);
  RemoveNode(rr);
  SplitCells(FixedCols, rr + 1);
  RemoveChildRow(rr + 1);

  RowHeights[RowCount - 1] := w;
end;
}

procedure TAdvStringGrid.AddNode(ARow,Span: Integer);
var
  i: Integer;

begin
  if Span < 1 then
    Exit;
  ARow := RemapRow(ARow);
  with CreateCellGraphic(0,ARow) do
  begin
    CellType := ctNode;
    CellAngle := ARow;
    CellBoolean := False;
    CellIndex := Span;
    CellHAlign := haBeforeText;
    CellVAlign := vaCenter;
    CellErrFrom := 0;
    CellVar := -1;
  end;

  for i := 1 to Span do
  begin
    if not HasCellProperties(0, ARow + i - 1) then
      CellProperties[0,ARow + i - 1].NodeLevel := 1
    else
      CellProperties[0,ARow + i - 1].NodeLevel := CellProperties[0,ARow + i - 1].NodeLevel + 1;
  end;

  if FNumNodes = 0  then
    InvalidateCol(0);

  Inc(FNumNodes);
  if Col = 0  then
    Col := Col + 1;
end;

procedure TAdvStringGrid.AddSummary(ARow: Integer);
begin
  ARow := RemapRow(ARow);
  CreateCellGraphic(0,ARow).CellType := ctSummary;
end;


procedure TAdvStringGrid.RemoveNode(ARow: Integer);
var
  i,dr,ns: Integer;

begin
  ExpandNodeInt(ARow);
  dr := DisplRowIndex(ARow);

  ns := GetNodeSpan(dr);  

  for i := 1 to ns do
    CellProperties[0,dr + i - 1].NodeLevel := CellProperties[0,dr + i - 1].NodeLevel - 1;

  //ARow := RemapRow(dr);
  RemoveCellGraphic(0,dr,ctNode);
  if (FNumNodes > 0) then
    Dec(FNumNodes);
end;

procedure TAdvStringGrid.RemoveAllNodes;
var
  i,j,k: Integer;
begin
  i := 0;

  while (i < RowCount) do
  begin
    if IsNode(i) then
    begin
      ExpandNode(i);
      k := GetNodeSpan(i);
      for j := 1 to k do
        CellProperties[0,i + j - 1].NodeLevel := CellProperties[0,i + j - 1].NodeLevel - 1;

      //k := i + k;

      //i := RemapRow(i);
      RemoveCellGraphic(0,i,ctNode);

      if (FNumNodes > 0) then
        Dec(FNumNodes);

      inc(i);
      //i := k;
    end
    else
      inc(i);
  end;
  Invalidate;
end;

function TAdvStringGrid.GetNodeState(ARow: Integer): Boolean;
var
  cg: TCellGraphic;
begin
  Result := False;
  cg := GetCellGraphic(0,ARow);

  if cg = nil then
    Exit;

  if cg.CellType = ctNode then
    Result := cg.CellBoolean;
end;

{
procedure TAdvStringGrid.ComboChange(Sender: TObject);
begin
  if Assigned(FOnComboChange) then
  begin
    if(ComboBox.ItemIndex >= 0) then
      FOnComboChange(Self,Col,Row,Combobox.ItemIndex,comboBox.Items[ComboBox.ItemIndex])
    else
      FOnComboChange(Self,Col,Row,Combobox.ItemIndex,'')
  end;

  if Assigned(FOnComboObjectChange) then
  begin
    if(ComboBox.ItemIndex >= 0) then
      FOnComboObjectChange(Self,Col,Row,ComboBox.ItemIndex,ComboBox.Items[ComboBox.ItemIndex],ComboBox.Items.Objects[ComboBox.ItemIndex])
    else
      FOnComboObjectChange(Self,Col,Row,ComboBox.ItemIndex,'',nil);
  end;
end;
}

function TAdvStringGrid.InNodeRect(ARow,x: Integer): Boolean;
var
  lvl,d: Integer;
  nw,lw: integer;
begin
  if not MouseActions.PreciseNodeClick then
  begin
    Result := true;
    Exit;
  end;

  lvl := GetNodeLevel(Arow);
  nw := 0;
  lw := 0;

  case CellNode.NodeType of
  cnFlat,cnXP: nw := 4;
  cnLeaf: nw := 8;
  cn3D: nw := 6;
  cnGlyph: if not CellNode.ExpandGlyph.Empty then
      nw := CellNode.ExpandGlyph.Width div 2;
  end;

  case CellNode.NodeType of
  cnFlat,cnXP: lw := 4;
  cnLeaf: lw := 2;
  cn3D: lw := 0;
  cnGlyph: if not CellNode.ExpandGlyph.Empty then
      lw := 2;
  end;

  if BiDiMode = bdRightToLeft then
  begin
    d := 0;
    if (VisibleRowCount < RowCount - FixedRows) then
      d := GetSystemMetrics(SM_CXVSCROLL);
    Result := (x + d >= Width - 2 - lvl * CellNode.NodeIndent - nw) and (x + d < Width - ((lvl - 1) * CellNode.NodeIndent))
  end
  else
    Result := (x < lvl * CellNode.NodeIndent + nw) and (x > (lvl - 1) * CellNode.NodeIndent + lw);
end;

function TAdvStringGrid.GetNodeLevel(ARow: Integer): Integer;
var
  cg: TCellGraphic;
begin
  Result := -1;
  cg := GetCellGraphic(0,ARow);

  if cg = nil then
    Exit;
  if (cg.CellType = ctNode) then
    Result := CellProperties[0,ARow].NodeLevel;
end;

procedure TAdvStringGrid.SetNodeState(ARow: Integer;Value: Boolean);
var
  cg:TCellGraphic;

begin
  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) then
  begin
    ARow := RemapRowInv(ARow);
    if Value <> cg.CellBoolean then
    if Value then
      ContractNode(ARow)
    else
      ExpandNode(ARow);
  end;
end;

function TAdvStringGrid.GetNodeSpan(ARow: Integer): Integer;
var
  cg:TCellGraphic;
begin
  Result := -1;

  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) then
    Result := cg.CellIndex;
end;

function TAdvStringGrid.GetSubNodeCount(ARow: Integer): Integer;
var
  cg:TCellGraphic;
begin
  Result := 0;

  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) then
    Result := cg.CellErrFrom;
end;


procedure TAdvStringGrid.UpdateSubNodeCount(ARow, Delta: Integer);
var
  cg:TCellGraphic;
begin
  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) then
    cg.CellErrFrom := cg.CellErrFrom + Delta;
end;



procedure TAdvStringGrid.UpdateNodeSpan(ARow, Delta: Integer);
var
  cg:TCellGraphic;
begin
  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) then
    cg.CellIndex := cg.CellIndex + Delta;
end;

procedure TAdvStringGrid.SetNodeSpan(ARow,Span: Integer);
var
  cg:TCellGraphic;
begin
  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) then
    cg.CellIndex := Span;
end;

procedure TAdvStringGrid.ExpandFast;
var
  hs,i,j,k,l,m: Integer;
begin
  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  k := FGridItems.Count - 1;

  l := 1;
  if FloatingFooter.Visible then
    l := 2;

  j := RowCount - l;

  m := FGridItems.Count;

  // prevent invalid cell access when HideSelection was done
  if Row >= RowCount then
    FocusCell(FixedCols, FixedRows);

  RowCount := RowCount + m;

  for i := RowCount - l downto 0 do
  begin
    if (k >= 0) then
      hs := (FGriditems.Items[k] as TGridItem).Idx
    else
      hs := -1;

    if (hs = i) and (k >= 0) then
    begin
      Rows[i].Assign((FGriditems.Items[k] as TGridItem).Items);
      RowHeights[i] := (FGriditems.Items[k] as TGridItem).Height;
      dec(k);
    end
    else
    begin
      if (i > j) and (j >= 0)  then
      begin
        Rows[i].Assign(Rows[j]);
        RowHeights[i] := RowHeights[j];
        dec(j);
      end;
    end;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  for i := FGridItems.Count - 1 downto 0 do
    FGridItems.Items[i].Free;

  CellControlsUpdate;
end;


procedure TAdvStringGrid.ExpandAll;
var
  i: Integer;
  cg: TCellGraphic;
begin
  ExpandFast;

  // update node states
  BeginUpdate;
  for i := FixedRows to AllRowCount - 1 do
    if IsNode(i) then
    begin
//      ExpandNode(i);
      cg := GetCellGraphic(0,i);
      cg.CellBoolean := False;
    end;
  EndUpdate;

  CalcFooter(-1);
end;


procedure TAdvStringGrid.ContractAll;
var
  i,j,iGNS: Integer;
  il: TIntList;
  cg: TCellGraphic;
  opennodes: boolean;
begin
  // check if there are open nodes, otherwise ContractAll is not needed
  opennodes := false;

  for i := FixedRows to RowCount - 1 do
  begin
    if IsNode(i) then
    begin
      cg := GetCellGraphic(0,i);
      if not cg.CellBoolean then
        opennodes := true;
    end;
  end;

  if not opennodes then
    Exit;

  BeginUpdate;

  try
    ExpandAll;

    il := TIntList.Create(0,0);

    i := FixedRows;
    while i < RowCount do
    begin
      if IsNode(i) then
      begin
        cg := GetCellGraphic(0,i);
        cg.CellBoolean := True;
        iGNS := GetNodeSpan(i);
        for j := 1 to iGNS - 1 do
        begin
          il.Add(i + j);
        end;

        i := i + iGNS;
      end
      else
        inc(i);
    end;

    HideRowList(il);

    il.Free;
  finally
    EndUpdate;
  end;

  CellControlsUpdate;
  CalcFooter(-1);
end;

procedure TAdvStringGrid.ExpandNode(ARow: Integer);
var
  i: Integer;
begin
  if CellNode.ExpandOne then
    for i := FixedRows to RowCount - 1 do
    begin
      if IsNode(i) then
        if not GetNodeState(i) then
          ContractNode(RealRowIndex(i));
    end;
  ExpandNodeInt(ARow);
end;

procedure TAdvStringGrid.ExpandNodeInt(ARow: Integer);
var
  i,j,c: Integer;
  cg: TCellGraphic;
  tr,cr: Integer;
  rs: boolean;
  ds: boolean;
  cp: TCellProperties;
  obj: TObject;

begin
  ARow := RemapRow(ARow);

  cg := GetCellGraphic(0,ARow);
  if (cg = nil) then Exit;

  // get node state & toggle node state
  if (cg.CellType = ctNode) and (cg.CellBoolean = True) then
    cg.CellBoolean := False
  else
    Exit;

  if IsNode(ARow) then
  begin
    for c := 0 to ColCount - 1 do
    begin
      obj := GridObjects[c,ARow];
      if Assigned(obj) then
      begin
        cp := TCellProperties(obj);
        cp.MergeCollaps := false;
      end;
    end;
  end;

  i := ARow + 1;
  if (cg.CellIndex = 0) then
    while (i < RowCount) do
    begin
      if IsNode(i) then Break;
      Inc(i);
    end;

  j := RemapRowInv(i);
  i := RemapRowInv(ARow);

  tr := TopRow;
  cr := Row;

  ds := MouseActions.DisjunctRowSelectDirect;
  MouseActions.DisjunctRowSelectDirect := false;

  rs := goRowSelect in Options;

  if rs then
    Options := Options - [goRowSelect];

  if FNumCellControls = 0 then
    BeginUpdate;

  try
    UnHideRows(i + 1,j - 1);

    if rs then
    begin
      Options := Options + [goRowSelect];
      Row := cr;
      TopRow := tr;
    end;
  finally
    MouseActions.DisjunctRowSelectDirect := ds;
    if FNumCellControls = 0 then
      EndUpdate;
  end;

  CalcFooter(-1);
end;

procedure TAdvStringGrid.ContractNode(ARow: Integer);
var
  i,j,k,d,c: Integer;
  cg: TCellGraphic;
  cp: TCellProperties;
  obj: TObject;
begin
  HideInplaceEdit;

  FForceSel := true;

  ARow := RemapRow(ARow);
  cg := GetCellGraphic(0,ARow);
  if cg = nil then
  begin
    FForceSel := false;
    Exit;
  end;

  if (cg.CellType = ctNode) and (cg.CellBoolean = False) then
    cg.CellBoolean := True
  else
  begin
    FForceSel := false;
    Exit;
  end;

  if IsNode(ARow) then
  begin
    for c := 0 to ColCount - 1 do
    begin
      obj := GridObjects[c,Arow];
      if Assigned(obj) then
      begin
        cp := TCellProperties(obj);
        cp.MergeCollaps := true;
      end;
    end;
  end;


  i := ARow + 1;

  // Cellspan based
  if (cg.CellIndex > 0) then
    i := ARow + cg.CellIndex
  else
    while (i < RowCount) do
    begin
      if IsNode(i) then Break;
      Inc(i);
    end;

  // new code here
  k :=  ARow + 1;
  j := k;

  while (k < i) do
  begin
    if IsNode(k) then
    begin
      if GetNodeState(k) then // contracted node here
      begin
        cg := GetCellGraphic(0,k);
        cg.CellBoolean := not cg.CellBoolean;

        if Assigned(CellControls[1,k + 1]) then
          CellControls[1,k + 1].Visible := False;

        d := k - j + 1;

        HideRows(RemapRowInv(j), RemapRowInv(k));
        i := i - cg.CellIndex - (k - j);
        k := k + 1 - d;
        j := k;
      end
      else
        inc(k);
    end
    else
      inc(k);
  end;

  (*
  rl := TIntList.Create(-1,-1);
  j := RemapRowinv(j);
  k := RemapRowInv(k - 1);

  for i := j to k do
    rl.Add(i);
  HideRowList(rl);
  rl.Free;
  *)

  HideRows(RemapRowinv(j), RemapRowInv(k - 1));

  FForceSel := false;

  // old single level code here
  (*
  j := RemapRowInv(l);
  i := RemapRowInv(ARow);
  HideRows(i + 1,j - 1);
  *)

  CalcFooter(-1);
end;

function TAdvStringGrid.GetParentRow(ARow: Integer): Integer;
var
  i, lvl, nlvl,nspan, delta: Integer;
begin
  Result := -1;
  if FNumNodes = 0 then
    Exit;

  if IsNode(ARow) then
  begin
    lvl := GetNodeLevel(ARow);
    Result := ARow;
  end
  else
    lvl := $FFFF;

  delta := 0;
  i := ARow;
  while (i >= FixedRows) do
  begin
    nlvl := GetNodeLevel(i);
    if IsNode(i) and (nlvl < lvl) then
    begin
      nspan := GetNodeSpan(i);

      if GetNodeState(i) then
        delta := delta  + (nspan - 1);

      if (nspan + i - delta > ARow) then
      begin
        Result := i;
        Exit;
      end;
    end;
    Dec(i);
  end;
end;

procedure TAdvStringGrid.RemoveNormalRow(ARow: Integer);
//var
  //RRow: integer;
  //j: Integer;
begin
  //RRow := ARow;
//  ARow := DisplRowIndex(ARow);

  RemoveRows(ARow,1);
//  DeleteRow(ARow);

  dec(FMaxRowCount);
  (*
  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx > RRow then
      (FGriditems.Items[j - 1] as TGridItem).Idx := (FGriditems.Items[j - 1] as TGridItem).Idx - 1;
  end;
  *)
end;

procedure TAdvStringGrid.InsertNormalRow(ARow: Integer);
var
  RRow,j: Integer;
begin
  RRow := ARow;

  ARow := DisplRowIndex(ARow);

  InsertRows(ARow,1);

  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx > RRow then
      (FGriditems.Items[j - 1] as TGridItem).Idx := (FGriditems.Items[j - 1] as TGridItem).Idx + 1;
  end;
end;

procedure TAdvStringGrid.InsertChildRow(ARow: Integer; InsertAt:integer = 1);
var
  pr,j: Integer;
  lvl: Integer;
  NRow,NLvl,RRow: Integer;
  n: boolean;
  isn: boolean;
  c: integer;
begin
  ARow := DisplRowIndex(ARow);

  lvl := 1;

  // update inner most node span
  if IsNode(ARow) then
    pr := ARow
  else
    pr := GetParentRow(ARow);

  RRow := RealRowIndex(pr);

  if pr <> -1 then
  begin
    UpdateNodeSpan(pr, 1);
    UpdateSubNodeCount(pr,1);
    ExpandNode(RealRowIndex(pr));
    lvl := CellProperties[0,pr].NodeLevel;
  end;

  // update spans of possible parent nodes here as well
  NLvl := lvl;
  NRow := pr;

  while (NLvl > 1) and (NRow <> -1) and (NRow >= FixedRows) do
  begin
    NRow := GetParentRow(NRow - 1);

    if CellProperties[0, NRow].NodeLevel < NLvl then
    begin
      NLvl := 0;
      if (NRow <> -1) then
      begin
        UpdateNodeSpan(NRow, 1);
        UpdateSubNodeCount(NRow, 1);
        //UpdateSubNodeCount(pr, 1);
        ExpandNode(RealRowIndex(NRow));
        Nlvl := CellProperties[0, NRow].NodeLevel;
      end;
    end;
  end;

  isn := IsNode(Arow);

  n := isn and (InsertAt = 0);

  if n then
    InsertAt := 1;

  // insert row after
  InsertRows(ARow + InsertAt,1);

  if n then
  begin
    for c := 0 to ColCount - 1 do
    begin
      Cells[c,ARow + 1] := Cells[c, ARow];
      if c > 0 then
        Objects[c, ARow + 1] := Objects[c, ARow];

      Cells[c, Arow] := '';
      if c > 0 then
        Objects[c, ARow] := nil;
    end;
  end;

  // set level of inserted row
  if (pr <> -1) then
    CellProperties[0,ARow + InsertAt].NodeLevel := lvl;

  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx > RRow then
      (FGriditems.Items[j - 1] as TGridItem).Idx := (FGriditems.Items[j - 1] as TGridItem).Idx + 1;
  end;
end;

procedure TAdvStringGrid.RemoveChildRow(ARow: Integer);
var
  sp, pr: Integer;
  lvl: Integer;
  i: Integer;
  ci: TControlItem;
begin
  ARow := DisplRowIndex(ARow);

  for i := 1 to FControlList.Count do
  begin
    ci := FControlList.Control[i - 1];
    if (ci.Y >= RealRowIndex(ARow)) then
      ci.Y := ci.Y - 1;
  end;

  pr := GetParentRow(ARow);

  if pr <> -1 then
  begin
    lvl := GetNodeLevel(pr);

    sp := GetNodeSpan(pr);
    if sp > 1 then
    begin
      UpdateNodeSpan(pr, - 1);
      UpdateSubNodeCount(pr, - 1);
    end;

    ExpandNode(RealRowIndex(pr));

    while (GetNodeLevel(pr) > 1)  do
    begin
      pr := GetParentRow(pr);

      if (pr <> -1) and (GetNodeLevel(pr) < lvl) then
      begin
        sp := GetNodeSpan(pr);
        if sp > 1 then
        begin
          UpdateNodeSpan(pr, - 1);
          UpdateSubNodeCount(pr, - 1);
        end;
        ExpandNode(RealRowIndex(pr));
      end
      else
        Break;
    end;
  end;

  // this remove the TGridItem
  RemoveRowsInternal(ARow,1);

  FMaxRowCount := FMaxRowCount - 1;

  {
  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx > pr then
      (FGriditems.Items[j - 1] as TGridItem).Idx := (FGriditems.Items[j - 1] as TGridItem).Idx - 1;
  end;
  }
  DestroyHiddenRowLookup;
end;


function TAdvStringGrid.IsNode(ARow: Integer): Boolean;
begin
  if (ARow < 0) then
    Result := False
  else
    Result := (CellTypes[0,ARow] = ctNode);
end;

function TAdvStringGrid.IsSummary(ARow: Integer): Boolean;
begin
  if ARow < 0 then
    Result := False
  else
    Result := (CellTypes[0,ARow] = ctSummary);
end;


function TAdvStringGrid.GetNodeSpanType(ARow: Integer): Integer;
var
  i: Integer;
begin
  Result := 0;

  if IsNode(ARow) then
  begin
    Exit;
  end;

  if ARow >= RowCount - FixedFooters - 1 then
  begin
    Result := 1;
    Exit;
  end;

  { code added }

  if HasCellProperties(0,ARow + 1) then
  begin
    if (CellProperties[0,ARow + 1].NodeLevel >= CellProperties[0,ARow].NodeLevel) then
      Result := 2
    else
      Result := 1;
  end
  else
  begin
    Result := 1;
  end;

  Exit;

  i := ARow;

  while ARow >= FixedRows do
  begin
    if IsNode(ARow) then
    begin
      if (i - ARow + 1 = GetNodeSpan(ARow)) and not GetNodeState(ARow) then
        Result := 1
      else
        Result := 2;
      Break;
    end;
    dec(ARow);
  end;

end;

procedure TAdvStringGrid.AddInterfacedCell(ACol,ARow: Integer; AObject: TInterfacedPersistent);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetInterfacedCell(AObject);
  end;
end;

procedure TAdvStringGrid.RemoveInterfacedCell(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctInterface);
end;

function TAdvStringGrid.GetInterfacedCell(ACol,ARow: Integer): TInterfacedPersistent;
var
  cg: TCellGraphic;
begin
  Result := nil;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;
  if (cg.CellType = ctInterface) then
  Result := TInterfacedPersistent(cg.CellBitmap);
end;

function TAdvStringGrid.CreateBitmap(ACol,ARow: Integer;transparent: Boolean;hal:TCellHalign;val:TCellValign):TBitmap;
var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetBitmap(bmp,transparent,hal,val);
    CellCreated := True;
  end;
  Result := bmp;
end;

procedure TAdvStringGrid.AddBitmap(ACol,ARow: Integer;abmp:TBitmap;transparent: Boolean;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetBitmap(abmp,transparent,hal,val);
  end;
end;

function TAdvStringGrid.HasBitmap(ACol,ARow: Integer): boolean;
begin
  Result := Assigned(GetBitmap(ACol,ARow));
end;

function TAdvStringGrid.GetBitmap(ACol,ARow: Integer): TBitmap;
var
  cg: TCellGraphic;
begin
  Result := nil;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;
  if (cg.CellType = ctBitmap) then
    Result := cg.CellBitmap;
end;

procedure TAdvStringGrid.RemoveBitmap(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctBitmap);
end;

procedure TAdvStringGrid.AddPicture(ACol,ARow: Integer;apicture:TPicture;transparent: Boolean;stretchmode:TStretchMode;
                                    padding: Integer;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetPicture(apicture,transparent,stretchmode,padding,hal,val);
  end;
end;

function TAdvStringGrid.CreatePicture(ACol,ARow: Integer;transparent: Boolean;stretchmode:TStretchMode;
                                      padding: Integer;hal:TCellHalign;val:TCellValign):TPicture;
var
  pic: TPicture;
begin
  pic := TPicture.Create;
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetPicture(pic,Transparent,StretchMode,Padding,hal,val);
    CellCreated := True;
  end;
  Result := pic;
end;

function TAdvStringGrid.HasPicture(ACol: Integer; ARow: Integer): boolean;
begin
  Result := Assigned(GetPicture(ACol,ARow));
end;

function TAdvStringGrid.GetPicture(ACol,ARow: Integer): TPicture;
var
  cg:TCellGraphic;
begin
  Result := nil;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;
  if (cg.CellType = ctPicture) then
    Result := TPicture(cg.CellBitmap);
end;

procedure TAdvStringGrid.RemovePicture(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctPicture);
end;

procedure TAdvStringGrid.AddFilePicture(ACol,ARow: Integer;AFilePicture:TFilePicture;transparent: Boolean;stretchmode:TStretchMode;
                                    padding: Integer;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetFilePicture(AFilePicture,transparent,stretchmode,padding,hal,val);
  end;
end;

function TAdvStringGrid.CreateFilePicture(ACol,ARow: Integer;Transparent: Boolean;stretchmode:TStretchMode;
                                      padding: Integer;hal:TCellHalign;val:TCellValign): TFilePicture;
var
  pic: TFilePicture;
begin
  pic := TFilePicture.Create;
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetFilePicture(pic,transparent,stretchmode,padding,hal,val);
    CellCreated := True;
  end;
  Result := pic;
end;

function TAdvStringGrid.CreateFooter: TFooterPanel;
begin
  Result := TFooterPanel.Create(Self);
end;

function TAdvStringGrid.GetFilePicture(ACol,ARow: Integer): TFilePicture;
var
  cg:TCellGraphic;
begin
  Result := nil;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;
  if (cg.CellType = ctFilePicture) then
    Result := TFilePicture(cg.CellBitmap);
end;

function TAdvStringGrid.HasFilePicture(ACol: Integer; ARow: Integer): boolean;
begin
  Result := Assigned(GetFilePicture(ACol,ARow));
end;


procedure TAdvStringGrid.RemoveFilePicture(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctFilePicture);
end;


function TAdvStringGrid.CreateIcon(ACol,ARow: Integer;hal:TCellHalign;val:TCellValign): TIcon;
var
  ico: TIcon;
begin
  ico := TIcon.Create;
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetIcon(ico,hal,val);
    CellCreated := True;
  end;
  Result := Ico;
end;


procedure TAdvStringGrid.CreateMetroScrollers;
begin
  if not Assigned(vscrlctrl) then
  begin
    vscrlctrl := TScrollControl.Create(Self);
    vscrlctrl.Direction := sdVertical;
    vscrlctrl.Parent := self;
    vscrlctrl.DoubleBuffered := true;
    vscrlctrL.Width := 6;
    vscrlctrl.Align := alRight;
    vscrlctrl.Visible := true;
  end;

  if not Assigned(hscrlctrl) then
  begin
    hscrlctrl := TScrollControl.Create(Self);
    hscrlctrl.Direction := sdHorizontal;
    hscrlctrl.Parent := self;
    hscrlctrl.DoubleBuffered := true;
    hscrlctrL.Height := 6;
    hscrlctrl.Align := alBottom;
    hscrlctrl.Visible := true;
  end;
end;

procedure TAdvStringGrid.AddIcon(ACol,ARow: Integer;AIcon:TIcon;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetIcon(AIcon,hal,val);
  end;
end;

procedure TAdvStringGrid.RemoveIcon(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctIcon);
end;

procedure TAdvStringGrid.AddProgressPie(ACol,ARow: Integer;Color: TColor; Value: Integer);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctProgressPie;
    CellHAlign := haBeforeText;
    CellVAlign := vaTop;
    CellBitmap := TBitmap(Color);
    CellAngle := Value;
  end;
end;

procedure TAdvStringGrid.SetProgressPie(ACol,ARow: Integer; Value: Integer);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then Exit;

  if cg.CellType = ctProgressPie then
  begin
    cg.CellAngle := Value;
    RepaintCell(ACol,ARow);
  end;
end;


procedure TAdvStringGrid.RemoveProgressPie(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctProgressPie);
end;

procedure TAdvStringGrid.AddAdvProgress(ACol,ARow: Integer;Min:integer=0;Max:integer=100);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctXPProgress;
    CellHAlign := haLeft;
    CellVAlign := vaTop;
    CellErrFrom := Min;
    CellErrLen := Max;
    CellBoolean := False;
    CellText := '';
  end;
end;

procedure TAdvStringGrid.RemoveAdvProgress(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctXPProgress);
end;

function TAdvStringGrid.HasProgress(ACol,ARow: Integer): boolean;
begin
  Result := IsCellGraphic(ACol,ARow, [ctProgress]);
end;

procedure TAdvStringGrid.AddProgress(ACol,ARow: Integer;FGColor,BkColor: TColor);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctProgress;

    CellHAlign := haLeft;
    CellVAlign := vaTop;

    CellBitmap := TBitmap(FGColor);
    CellIcon := TIcon(BKColor);
    CellErrFrom := 0;
    CellErrLen := 100;
    CellBoolean := False;
    CellText := '';
  end;

  if AutoNumAlign then
    Alignments[ACol,ARow] := taRightJustify;
end;

procedure TAdvStringGrid.AddProgressEx(ACol,ARow: Integer;FGColor,FGTextColor,BKColor,BKTextColor: TColor);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctProgress;
    CellHAlign := haLeft;
    CellVAlign := vaTop;
    CellBitmap := TBitmap(FGColor);
    CellIcon := TIcon(BKColor);
    CellIndex := TColor(FGTextColor);
    CellAngle := TColor(BKTextColor);

    CellErrFrom := 0;
    CellErrLen := 100;

    CellText := '';

    CellBoolean := True;
  end;
  if AutoNumAlign then
    Alignments[ACol,ARow] := taRightJustify;
end;

procedure TAdvStringGrid.AddProgressFormatted(ACol,ARow: Integer;FGColor,FGTextColor,BKColor,BKTextColor: TColor; Fmt: string; Min, Max: integer);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctProgress;
    CellHAlign := haLeft;
    CellVAlign := vaTop;
    CellBitmap := TBitmap(FGColor);
    CellIcon := TIcon(BKColor);
    CellIndex := TColor(FGTextColor);
    CellAngle := TColor(BKTextColor);

    CellErrFrom := Min;
    CellErrLen := Max;
    CellText := Fmt;

    CellBoolean := True;
  end;
  if AutoNumAlign then
    Alignments[ACol,ARow] := taRightJustify;
end;

procedure TAdvStringGrid.RemoveProgress(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctProgress);
end;

procedure TAdvStringGrid.AddRangeIndicator(ACol, ARow: Integer; Range: Integer = 100; NegColor: TColor = clRed; PosColor: TColor = clBlack; ShowValue: Boolean = false);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctRangeIndicator;
    CellHAlign := haLeft;
    CellVAlign := vaTop;
    CellIndex := Range;

    CellBitmap := TBitmap(NegColor);
    CellIcon := TIcon(PosColor);

    CellBoolean := ShowValue;
  end;
end;

procedure TAdvStringGrid.RemoveRangeIndicator(ACol, ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctRangeIndicator);
end;

procedure TAdvStringGrid.AddComment(ACol,ARow: Integer; Comment:string);
begin
  AddColorComment(ACol, ARow, Comment, ControlLook.CommentColor);
end;

procedure TAdvStringGrid.AddColorComment(ACol,ARow: Integer; Comment:string; Color: TColor);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);
  if not Assigned(cg) Then
  begin
    cg := CreateCellGraphic(ACol,ARow);
    cg.CellType := ctNone;
  end;
  cg.CellComment := Comment;
  cg.CommentColor := Color;
end;

function TAdvStringGrid.GetComment(ACol,ARow: Integer): string;
begin
  Result := '';
  IsComment(ACol,ARow, Result);
end;

procedure TAdvStringGrid.SetComment(ACol: Integer; ARow: Integer; value: string);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);

  if not Assigned(cg) then
    AddComment(Acol,ARow, Value)
  else
    cg.CellComment := Value;
end;


function TAdvStringGrid.IsComment(ACol,ARow: Integer;var comment:string): Boolean;
var
  cg: TCellGraphic;
begin
  Result := False;
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then Exit;

  Result := cg.CellComment <> '';
  if Result then
    Comment := cg.CellComment;
end;

procedure TAdvStringGrid.RemoveComment(ACol,ARow: Integer);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then Exit;
  cg.CellComment := '';
end;

procedure TAdvStringGrid.RemoveAllComments;
var
  i,j: Integer;
begin
  for i := 0 to ColCount - 1 do
    for j := 0 to RowCount - 1 do
      RemoveComment(i,j);
  Invalidate;
end;

procedure TAdvStringGrid.AddShape(ACol,ARow: Integer; Shape: TCellShape; FillColor,LineColor: TColor;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctShape;
    CellAngle := integer(Shape);
    CellIndex := integer(FillColor);
    CellBitmap := TBitmap(LineColor);
    CellHAlign := hal;
    CellVAlign := val;
  end;
end;

function TAdvStringGrid.HasShape(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow,[ctShape]);
end;


procedure TAdvStringGrid.RemoveShape(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctShape);
end;

procedure TAdvStringGrid.SetShapeColor(ACol,ARow: integer; FillColor: TColor);
begin
  if CellTypes[ACol,ARow] = ctShape then
    CellGraphics[ACol,ARow].CellIndex := integer(FillColor);
end;

function TAdvStringGrid.GetShapeColor(ACol,ARow: integer): TColor;
begin
  if CellTypes[ACol,ARow] = ctShape then
    Result := TColor(CellGraphics[ACol,ARow].CellIndex)
  else
    Result := clNone;
end;

procedure TAdvStringGrid.AddRating(ACol,ARow,Scale: Integer; FillColor, EmptyColor: TColor);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctRating;
    CellAngle := Scale;
    CellHAlign := haFull;
    CellIndex := integer(FillColor);
    CellBitmap := TBitmap(EmptyColor);
  end;
end;

procedure TAdvStringGrid.RemoveRating(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctRating);
end;

function TAdvStringGrid.HasRating(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow, [ctRating]);
end;

procedure TAdvStringGrid.AddScrollBar(ACol,ARow: Integer; AutoRange: boolean = false);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctScrollBar;
    CellAngle := 0;
    CellErrFrom := 100;
    CellBoolean := AutoRange;

    if AutoRange then
      CellTextChange(ACol, ARow);
  end;
end;

procedure TAdvStringGrid.RemoveScrollBar(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctScrollbar);
end;

function TAdvStringGrid.HasScrollBar(ACol, ARow: integer): boolean;
begin
  Result := IsCellGraphic(ACol,ARow, [ctScrollBar]);
end;

function TAdvStringGrid.HasAutoRangeScrollBar(ACol, ARow: integer): boolean;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := False;
  BC := BaseCell(ACol,ARow);
  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then
    Exit;
  Result := (cg.CellType = ctScrollBar) and (cg.CellBoolean);
end;


procedure TAdvStringGrid.SetScrollPosition(ACol, ARow, Pos: integer);
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then Exit;
  if cg.CellType = ctScrollBar then
  begin
    cg.CellIndex := Pos;
    RepaintCell(ACol,ARow);
  end;
end;

function TAdvStringGrid.GetScrollPosition(ACol, ARow: integer): integer;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result := -1;
  BC := BaseCell(ACol,ARow);
  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then Exit;
  if cg.CellType = ctScrollBar then
  begin
    Result := cg.CellIndex;
  end;
end;


procedure TAdvStringGrid.SetScrollProp(ACol, ARow: integer; Prop: TScrollProp);
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then Exit;
  if cg.CellType = ctScrollBar then
  begin
    cg.CellAngle := Prop.PageSize;
    cg.FCellErrFrom := Prop.Range;
  end;
end;

function TAdvStringGrid.GetScrollProp(ACol, ARow: integer): TScrollProp;
var
  cg: TCellGraphic;
  BC: TPoint;
begin
  Result.PageSize := -1;
  Result.Range := -1;
  BC := BaseCell(ACol,ARow);
  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = nil then Exit;
  if cg.CellType = ctScrollBar then
  begin
    Result.PageSize := cg.CellAngle;
    Result.Range := cg.CellErrFrom;
  end;
end;

procedure TAdvStringGrid.AddMarker(ACol,ARow,ErrPos,ErrLen: Integer);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);

  if not Assigned(cg) then
  begin
    cg := CreateCellGraphic(ACol,ARow);
    cg.CellType := ctEmpty;
  end;

  cg.CellErrFrom := ErrPos;
  cg.CellErrLen := ErrLen;
  InvalidateCell(ACol,ARow);
end;

procedure TAdvStringGrid.RemoveMarker(ACol,ARow: Integer);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);
  if not Assigned(cg) then Exit;

  if cg.CellType = ctEmpty then
    RemoveCellGraphic(ACol,ARow,ctEmpty)
  else
  begin
    cg.CellErrFrom := 0;
    cg.CellErrLen := 0;
  end;
end;

procedure TAdvStringGrid.RemoveAllMarkers;
var
  i,j: Integer;
begin
  for i := 0 to ColCount - 1 do
    for j := 0 to RowCount - 1 do
      RemoveMarker(i,j);
end;


procedure TAdvStringGrid.GetMarker(ACol,ARow: Integer;var ErrPos,ErrLen: Integer);
var
  cg: TCellGraphic;
begin
  ErrPos := 0;
  ErrLen := 0;

  cg := GetCellGraphic(ACol,ARow);
  if not Assigned(cg) then Exit;

  ErrPos := cg.CellErrFrom;
  ErrLen := cg.CellErrLen;
end;

procedure TAdvStringGrid.AddBitButton(ACol,ARow, bw, bh: Integer;Caption:string;Glyph: TBitmap;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetBitButton(bw,bh,Caption,Glyph,hal,val);
  end;
end;

function TAdvStringGrid.CreateBitButton(ACol,ARow, bw, bh: Integer;Caption:string;hal:TCellHalign;val:TCellValign): TBitmap;
var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetBitButton(bw,bh,Caption,bmp,hal,val);
    CellCreated := True;
  end;
  Result := bmp;
end;

procedure TAdvStringGrid.AddButton(ACol,ARow, bw, bh: Integer;caption:string;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetButton(bw,bh,caption,hal,val);
  end;
end;

procedure TAdvStringGrid.SetButtonText(ACol,ARow: Integer; Caption: string);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(RemapCol(ACol),ARow);
  if cg = nil then
    Exit;
  cg.CellText := Caption;
  RepaintCell(ACol,ARow);
end;

function TAdvStringGrid.GetButtonText(ACol: Integer; ARow: Integer): string;
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(RemapCol(ACol),ARow);
  if cg = nil then
    Exit;
  Result := cg.CellText;
end;

procedure TAdvStringGrid.RemoveBitButton(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctBitButton);
end;

procedure TAdvStringGrid.RemoveButton(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctButton);
  RemoveCellGraphic(ACol,ARow,ctBitButton);
end;

procedure TAdvStringGrid.RemoveAllButtons;
var
  i,j: Integer;
begin
  for i := 0 to ColCount - 1 do
    for j := 0 to RowCount - 1 do
    begin
      if HasButton(i,j) then
        RemoveButton(i,j);
    end;
end;

procedure TAdvStringGrid.PushButton(ACol,ARow: Integer;push: Boolean);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(RemapCol(ACol),ARow);
  if cg = nil then
    Exit;

  if cg.CellType <> ctNode then
  begin
    cg.CellBoolean := push;
    RepaintCell(ACol,ARow);
  end;
end;

function TAdvStringGrid.HasButton(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow, [ctButton,ctBitButton]);
end;

function TAdvStringGrid.ExpandRect(ACol,ARow: Integer): TRect;
var
  cr: TRect;
begin
  Result := Rect(0,0,0,0);
  if not IsCellGraphic(ACol,ARow, [ctExpand]) then
    Exit;
  cr := CellRect(ACol, ARow);
  Result := Rect(cr.Right - 13, cr.Top + 2, cr.Right - 2, cr.Top + 13);
end;

procedure TAdvStringGrid.ButtonFormMouseLeave(Sender: TObject);
begin
  ShowWindow(FButtonForm.Handle, SW_HIDE);
end;

function TAdvStringGrid.ButtonRect(ACol,ARow: Integer): TRect;
var
  l: Integer;
  cg: TCellGraphic;
  cr: TRect;

begin
  Result := Rect(0,0,0,0);

  cg := GetCellGraphic(RemapCol(ACol),ARow);
  if cg = nil then Exit;
  l := round(cg.CellValue);

  cr := CellRect(ACol, ARow);

  Result.Left := (l and $FFFF) + cr.Left;
  Result.Top := Integer(((l and $FFFF0000) shr 16)) + cr.Top;

  Result.Right := Result.Left+(cg.CellIndex and $FFFF);
  l := (cg.Cellindex and $FFFF0000) shr 16;
  Result.Bottom := Result.Top+l;

  if (cg.CellVAlign = vaFull) or (cg.CellHAlign = haFull) then
  begin
    cr := CellRect(ACol,ARow);
    if cg.CellVAlign = vaFull then
    begin
      Result.Top := cr.Top;
      Result.Bottom := cr.Bottom;
    end;
    if cg.CellHAlign = haFull then
    begin
      Result.Left := cr.Left;
      Result.Right := cr.Right;
    end;
  end;
end;

procedure TAdvStringGrid.AddCheckBoxColumn(ACol: Integer; DefaultState: boolean = false;DataCheckBox: boolean = false);
var
  i,fr: integer;
begin
  if MouseActions.CheckAllCheck then
    fr := 0
  else
    fr := FixedRows;

  for i := fr to RowCount - 1 - FixedFooters do
  begin
    if not IsSummary(i) then
    begin
      if IsNode(i) then
      begin
        if DefaultState then
          AddCheckBox(Acol,i,cbchecked)
        else
          AddCheckBox(Acol,i,cbUnchecked)
      end
      else
        AddCheckBox(ACol,i,DefaultState,DataCheckBox);
    end;
  end;
end;

procedure TAdvStringGrid.RemoveCheckBoxColumn(ACol: Integer);
var
  i,fr: integer;
begin
  if MouseActions.CheckAllCheck then
    fr := 0
  else
    fr := FixedRows;

  for i := fr to RowCount - 1 do
  begin
    if HasCheckBox(Acol,i) then
      RemoveCheckBox(ACol,i);
  end;
end;


procedure TAdvStringGrid.AddCheckBox(ACol,ARow: Integer; State,Data: Boolean);
var
  ha: TCellHAlign;
begin
  if (ACol >= ColCount + NumHiddenColumns) or
     (ARow >= RowCount + NumHiddenRows) then
     raise Exception.Create('Invalid cell');

  ha := haBeforeText;

  with CreateCellGraphic(ACol,ARow) do
  begin
    case VAlignment of
    vtaTop: SetCheckBox(state,Data,True,ha,vaTop);
    vtaCenter: SetCheckBox(state,Data,True,ha,vaCenter);
    vtaBottom: SetCheckBox(state,Data,True,ha,vaBottom);
    end;
  end;

  if Data and ((Cells[ACol,ARow] <> CheckTrue) and (Cells[ACol,ARow] <> CheckFalse)) then
  begin
    if State then
      Cells[ACol,ARow] := CheckTrue
    else
      Cells[ACol,ARow] := CheckFalse;
  end;
end;

procedure TAdvStringGrid.RemoveCheckBox(ACol,ARow: Integer);
var
  cg: TCellGraphic;
  sl: TStringList;

begin
  cg := GetCellGraphic(ACol,ARow);
  if cg = Nil then
    Exit;
  if cg.CellType in [ctCheckBox,ctDataCheckBox,ctTriStateCheckBox] then
  begin
    if (cg.CellAngle = 1) then // has associated balloon
    begin
      cg.CellAngle := 0;
      sl := TStringList(cg.CellBitmap);
      cg.CellBitmap := nil;
      if Assigned(sl) then
        sl.Free;
    end;

    FreeCellGraphic(ACol,ARow);
    RepaintCell(ACol,ARow);
  end;
end;

function TAdvStringGrid.IsInCheckBox(ACol,ARow,XPos,YPos: Integer): Boolean;
var
  cg: TCellGraphic;
  r,cr: TRect;
  sz: TSize;
begin
  Result := false;
  cg := GetCellGraphic(ACol,ARow);
  if cg = Nil then
    Exit;

  if cg.CellType in [ctCheckBox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRowCheckBox,ctRadioButton] then
  begin
    if not MouseActions.PreciseCheckBoxCheck then
      Result := True
    else
    begin
      cr := CellRect(DisplColIndex(ACol),ARow);

      case cg.FCellVAlign of
      vaTop: r.Top := cr.Top + 2;
      vaCenter: r.Top := cr.Top + (cr.Bottom - cr.Top - ControlLook.CheckSize) div 2;
      vaBottom: r.Top := cr.Bottom - 2 - ControlLook.CheckSize;
      end;

      r.Bottom := r.Top + ControlLook.CheckSize;

      case GetCellAlignment(ACol,ARow).Alignment  of
      taLeftJustify: r.Left := cr.Left + 2;
      taCenter: r.Left := cr.Left + (cr.Right - cr.Left - ControlLook.CheckSize) div 2;
      taRightJustify:
        begin
          r.Left := cr.Right - 2 - ControlLook.CheckSize;
          if Cells[ACol,ARow] <> '' then
          begin
            sz := GetCellTextSize(ACol, ARow);
            r.Left := r.Left - sz.cx;
          end;
        end;
      end;

      r.Right := r.Left + ControlLook.CheckSize;
      Result := PtInRect(r,point(xpos,ypos));
    end;
  end;
end;

function TAdvStringGrid.HasCheckBox(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow, [ctCheckBox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRowCheckBox]);
end;

function TAdvStringGrid.IsDataCheckCol(ACol: Integer): boolean;
begin
  Result := false;
  if HasDataCheckBox(ACol, FixedRows) then
  begin
    if (RowCount > FixedRows + 1) and HasDataCheckBox(ACol, FixedRows + 1) then
    begin
      Result := true;
    end;
  end;
end;

function TAdvStringGrid.HasDataCheckBox(ACol,ARow: Integer): Boolean;
begin
  Result := IsCellGraphic(ACol,ARow, [ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox]);
end;


procedure TAdvStringGrid.AddRadioButtonGroup(ACol,ARow: Integer; Group: TRadioButtonGroup; State: Boolean= false);
begin
  if (ACol >= ColCount + NumHiddenColumns) or
     (ARow >= RowCount + NumHiddenRows) then
     raise Exception.Create('Invalid cell');

  with CreateCellGraphic(ACol,ARow) do
  begin
    case VAlignment of
    vtaTop: SetRadioButton(state,true,haBeforeText,vaTop,Group);
    vtaCenter: SetRadioButton(state,True,haBeforeText,vaCenter,Group);
    vtaBottom: SetRadioButton(state,True,haBeforeText,vaBottom,Group);
    end;
  end;
end;


procedure TAdvStringGrid.AddRadioButton(ACol,ARow: Integer; State: Boolean= false);
begin
  if (ACol >= ColCount + NumHiddenColumns) or
     (ARow >= RowCount + NumHiddenRows) then
     raise Exception.Create('Invalid cell');

  with CreateCellGraphic(ACol,ARow) do
  begin
    case VAlignment of
    vtaTop: SetRadioButton(state,true,haBeforeText,vaTop,rgCol);
    vtaCenter: SetRadioButton(state,True,haBeforeText,vaCenter,rgCol);
    vtaBottom: SetRadioButton(state,True,haBeforeText,vaBottom,rgCol);
    end;
  end;
end;

procedure TAdvStringGrid.RemoveRadioButton(ACol,ARow: Integer);
var
  cg: TCellGraphic;
begin
  cg := GetCellGraphic(ACol,ARow);
  if cg = Nil then
    Exit;
  if cg.CellType in [ctRadioButton] then
  begin
    FreeCellGraphic(ACol,ARow);
    RepaintCell(ACol,ARow);
  end;
end;

function TAdvStringGrid.HasRadioButton(ACol,ARow: Integer): Boolean;
var
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] in [ctRadioButton]);
end;

function TAdvStringGrid.HasRadioButtonGroup(ACol,ARow: Integer; Group: TRadioButtonGroup): Boolean;
var
  BC: TPoint;
  cg: TCellGraphic;

begin
  Result := False;
  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);

  if cg = Nil then
    Exit;

  if (cg.CellType in [ctRadioButton]) then
    Result := (cg.CellAngle = integer(Group));
end;


procedure TAdvStringGrid.AddRadioButtonColumn(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    AddRadioButton(ACol,i,false);
  end;
end;

procedure TAdvStringGrid.AddRadioButtonGroupColumn(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    AddRadioButtonGroup(ACol,i,rgRow);
  end;
end;


procedure TAdvStringGrid.RemoveRadioButtonColumn(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    if HasRadioButton(Acol,i) then
      RemoveRadioButton(ACol,i);
  end;
end;

function TAdvStringGrid.IsRadioButtonChecked(ACol,ARow: integer): boolean;
var
  BC: TPoint;
  cg: TCellGraphic;
begin
  Result := false;
  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = Nil then
    Exit;

  Result := (cg.CellType = ctRadioButton) and (cg.CellBoolean);
end;

function TAdvStringGrid.SetRadioButtonState(ACol, ARow: integer; State: boolean): boolean;
var
  BC: TPoint;
  cg: TCellGraphic;
  RCol: integer;
begin
  Result := false;
  BC := BaseCell(ACol,ARow);

  cg := GetCellGraphic(BC.X,BC.Y);
  if cg = Nil then
    Exit;

  if (cg.CellType = ctRadioButton) then
  begin
    if state <> cg.CellBoolean then
    begin
      cg.CellBoolean := state;
      RCol := RemapColInv(ACol);
      RepaintCell(RCol, ARow);
    end;
    Result := true;
  end;
end;

procedure TAdvStringGrid.SetRadioButtonRowIndex(ARow, Index: integer);
var
  i: integer;
begin
  for i := FixedCols to ColCount - 1 do
  begin
    SetRadioButtonState(i, ARow, i = Index);
  end;
end;

procedure TAdvStringGrid.SetRadioButtonColumnIndex(ACol, Index: integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    SetRadioButtonState(ACol, i, i = Index);
  end;
end;

function TAdvStringGrid.GetRadioButtonColumnIndex(ACol: integer): integer;
var
  i: integer;
begin
  Result := -1;

  for i := FixedRows to RowCount - 1 do
  begin
    if IsRadioButtonChecked(Acol,i) then
    begin
      Result := i;
      break;
    end;
  end;
end;

procedure TAdvStringGrid.QueryAddRow(var AllowAdd: Boolean);
begin
  if Assigned(OnCanAddRow) then
    OnCanAddRow(Self, AllowAdd);
end;

procedure TAdvStringGrid.QueryAddCol(var AllowAdd: Boolean);
begin
  if Assigned(OnCanAddCol) then
    OnCanAddCol(Self, AllowAdd);
end;


procedure TAdvStringGrid.QueryInsertRow(ARow: Integer; var AllowInsert: Boolean);
begin
  if Assigned(OnCanInsertRow) then
    OnCanInsertRow(Self, ARow, AllowInsert);
end;

function TAdvStringGrid.HasDataCell(ACol,ARow: Integer): Boolean;
var
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] in [ctDataCheckBox,ctVirtCheckBox,ctDataImage,ctRowCheckBox]);
end;

function TAdvStringGrid.HasStaticEdit(ACol,ARow: Integer): Boolean;
var
  BC: TPoint;
  HasButtons: boolean;
begin
  Result := false;
  if (ACol >= 0) and (ARow >= 0) then
  begin
    BC := BaseCell(ACol,ARow);

    hasButtons := (CellTypes[BC.X,BC.Y] in [ctButton,ctBitButton]) and (Navigation.AllowEditButtonCells = false);

    Result := (CellTypes[BC.X,BC.Y] in [ctCheckBox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRadio,ctRowCheckBox,ctRadioButton]) or HasButtons;
  end;
end;

function TAdvStringGrid.IsChecked(ACol,ARow: integer): boolean;
begin
  Result := false;
  GetCheckBoxState(ACol,ARow,Result);
end;

function TAdvStringGrid.GetCheckBoxState(ACol,ARow: Integer;var State: Boolean): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;
  //r: integer;
begin
  Result := False;

  if (NumHiddenRows > 0) then
  begin
    if FMouseActions.HotmailRowSelect and (ACol = 0) then
    begin
      State := RowSelect[ARow];
      Result := true;
    end
    else
    begin
//      cp := TCellProperties(Objects[ACol,ARow]);

      if FIsNarrowDown then
      begin
        cg := CellGraphics[ACol,ARow];
        if Assigned(cg) and (cg.CellType in [ctCheckBox, ctVirtCheckBox, ctDataCheckBox]) then
        begin
          state := cg.CellBoolean;
        end;
        Exit;
      end;

      cp := TCellProperties(GetAllGraphicsObject(ACol,ARow));
      if Assigned(cp) then
      begin
        cg := TCellGraphic(GetCPGraphicObject(cp));

        if Assigned(cg) then
        begin
          if (cg.CellType = ctCheckBox) then
          begin
            State := cg.CellBoolean;
            Result := True;
          end;

          if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
          begin
            State := AllCells[ACol,ARow] = GetCheckTrue(ACol,ARow);
            Result := True;
          end;

          if (cg.CellType = ctTriStateCheckBox) then
          begin
            State := AllCells[ACol,ARow] = GetCheckTrue(ACol,ARow);
            Result := True;
          end;
          if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
          begin
            State := RowSelect[ARow];
            Result := True;
          end;
        end;
      end
      else
      begin
        cg := GetCellGraphic(ACol, ARow);

        if cg = Nil then
          Exit;

        if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
        begin
          State := cg.CellBoolean;
          Result := True;
        end;

        if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
        begin
          State := Cells[ACol,ARow] = GetCheckTrue(ACol,ARow);
          Result := True;
        end;

        if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
        begin
          State := RowSelect[ARow];
          Result := True;
        end;
      end;
    end;
  end
  else
  begin
    cg := GetCellGraphic(ACol,ARow);
    if cg = Nil then
      Exit;

    if (cg.CellType = ctCheckBox) then
    begin
      State := cg.CellBoolean;
      Result := True;
    end;

    if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
    begin
      State := Cells[ACol,ARow] = GetCheckTrue(ACol,ARow);
      Result := True;
    end;

    if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
    begin
      State := RowSelect[ARow];
      Result := True;
    end;
  end;
end;

function TAdvStringGrid.SetCheckBoxState(ACol,ARow: Integer; State: TCheckBoxState): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;

begin
  Result := False;

  if (NumHiddenRows > 0) then
  begin
    cp := TCellProperties(GetAllGraphicsObject(ACol,ARow));
    if Assigned(cp) then
    begin
      cg := TCellGraphic(GetCPGraphicObject(cp));
    end
    else
      cg := GetCellGraphic(ACol, ARow);
  end
  else
    cg := GetCellGraphic(ACol,ARow);

  if cg = nil then
    Exit;

  if cg.CellType = ctTriStateCheckBox then
  begin
    cg.CellCheckBoxState := state;
    RepaintCell(ACol,DisplRowIndex(ARow));
    Result := True;
  end;
end;


function TAdvStringGrid.SetCheckBoxState(ACol,ARow: Integer;State: Boolean): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;

begin
  Result := False;

  if (NumHiddenRows > 0) then
  begin
    cp := TCellProperties(GetAllGraphicsObject(ACol,ARow));
    if Assigned(cp) then
    begin
      cg := TCellGraphic(GetCPGraphicObject(cp));
    end
    else
      cg := GetCellGraphic(ACol, ARow);
  end
  else
    cg := GetCellGraphic(ACol,ARow);

  if cg = nil then
    Exit;

  if (cg.CellType = ctCheckBox) then
  begin
    cg.CellBoolean := state;
    RepaintCell(ACol,DisplRowIndex(ARow));
    Result := True;
  end;

  if cg.CellType = ctTriStateCheckBox then
  begin
    if State then
      cg.CellCheckBoxState := cbChecked
    else
      cg.CellCheckBoxState := cbUnChecked;

    RepaintCell(ACol,DisplRowIndex(ARow));
    Result := True;
  end;


  if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
  begin
    if state then
      Cells[ACol,ARow] := GetCheckTrue(ACol,ARow)
    else
      Cells[ACol,ARow] := GetCheckFalse(ACol,ARow);
    Result := True;
  end;

  if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
  begin
    RowSelect[ARow] := State;
    Result := True;
  end;
end;

function TAdvStringGrid.DoRatingChange(ACol,ARow: integer; var NewRate: double): boolean;
begin
  Result := true;
  if Assigned(OnRatingChange) then
    OnRatingChange(self, ACol, ARow, NewRate, Result);
end;

procedure TAdvStringGrid.DoCheckBoxChange(ACol: Integer; ARow: Integer; State: Boolean);
begin
  if Assigned(OnCheckBoxChange) then
    OnCheckBoxChange(self, ACol, ARow, State);
end;

procedure TAdvStringGrid.DoColorSelect(Sender: TObject);
begin
  if Assigned(OnColorSelect) then
    OnColorSelect(Self, Col, Row, EditColorPicker.SelectedColor, EditColorPicker.SelectedColorText);
end;

procedure TAdvStringGrid.DoImageSelect(Sender: TObject);
begin
  if Assigned(OnImageSelect) then
    OnImageSelect(Self, Col, Row, EditImagePicker.ItemIndex);
end;

function TAdvStringGrid.SetCheckBoxStateInt(ACol,ARow: Integer;State: Boolean): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;
  rr: Integer;
  curstate: boolean;
begin
  Result := False;
  
  if (NumHiddenRows > 0) then
  begin
    rr := RealRowIndex(ARow);
    cp := TCellProperties(GetAllGraphicsObject(ACol,rr));
    if Assigned(cp) then
    begin
      cg := TCellGraphic(GetCPGraphicObject(cp));
    end
    else
      cg := GetCellGraphic(ACol, rr);
  end
  else
    cg := GetCellGraphic(ACol,ARow);


  if cg = nil then
    Exit;

  if cg.CellType = ctCheckBox then
  begin
    if (cg.CellBoolean <> State) then
    begin
      cg.CellBoolean := state;
      DoCheckBoxChange(ACol,ARow,state);
      RepaintCell(ACol,ARow);
    end;
    Result := True;
  end;

  if cg.CellType = ctTriStateCheckBox then
  begin
    if state then
      cg.CellCheckBoxState := cbChecked
    else
      cg.CellCheckBoxState := cbUnChecked;
  end;

  if (cg.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
  begin
    curstate := (GetCheckTrue(ACol,ARow) = Cells[ACol,ARow]);

    if state then
      Cells[ACol,ARow] := GetCheckTrue(ACol,ARow)
    else
      Cells[ACol,ARow] := GetCheckFalse(ACol,ARow);

    if curstate <> state then
      DoCheckBoxChange(ACol,ARow,state);

    Result := True;
  end;

  if (cg.CellType = ctRowCheckBox) and (ACol = 0) then
  begin
    if (RowSelect[ARow] <> state) then
    begin
      RowSelect[ARow] := State;
      DoCheckBoxChange(ACol, ARow, state);
    end;

    Result := True;
  end;

end;

function TAdvStringGrid.ToggleRadio(ACol,ARow: Integer; FromEdit: Boolean): Boolean;
var
  cg: TCellGraphic;
  NewIdx: Integer;
  CanEdit: Boolean;

begin
  Result := False;

  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;

  if cg.CellType = ctRadio then
  begin
    if FromEdit and not ControlLook.RadioAlwaysActive then
    begin
      CanEdit := True;
      GetCellReadOnly(ACol,ARow,CanEdit);
      if not CanEdit then Exit;
    end;

    if cg.CellIndex >= 0 then
      NewIdx := cg.CellIndex + 1
    else
      NewIdx := TStrings(cg.CellBitmap).IndexOf(Cells[ACol,ARow]) + 1;

    if NewIdx >= TStrings(cg.CellBitmap).Count then
      NewIdx := 0;
    if cg.CellIndex >= -1 then
      cg.CellIndex := NewIdx;

    cg.CellVar := NewIdx;

    Cells[ACol,ARow] := TStrings(cg.CellBitmap).Strings[NewIdx];
  end;

end;

procedure TAdvStringGrid.CheckAll(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    SetCheckBoxStateInt(ACol,i, true);
  end;

  if NumHiddenColumns > 0 then
  begin
    RepaintCol(DisplColIndex(ACol));
  end;
end;

procedure TAdvStringGrid.UnCheckAll(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    SetCheckBoxStateInt(Acol,i, false);
  end;
end;

function TAdvStringGrid.ToggleCheck(ACol,ARow: Integer; FromEdit: Boolean): Boolean;
var
  cg: TCellGraphic;
  Canedit: Boolean;
  RColI: Integer;
  newstate: boolean;
  isnoderow: boolean;
  nodespan, parentrow, i: integer;
  nodestate,samestate,allow: boolean;
begin
  Result := False;

  cg := GetCellGraphic(ACol,ARow);

  if cg = nil then
    Exit;

  Allow := true;

  if Assigned(OnCheckBoxCanToggle) then
    OnCheckBoxCanToggle(Self, ACol,ARow, cg.CellBoolean, Allow);

  if not Allow then
    Exit;

  isnoderow := false;
  nodestate := false;
  nodespan := -1;
  parentrow := -1;

  if Grouping.AutoCheckGroup and (ARow >= FixedRows) then
  begin
    isnoderow := IsNode(ARow);
    if isnoderow then
    begin
      nodespan := GetNodeSpan(Arow);
      nodestate := GetNodeState(ARow);
    end
    else
    begin
      parentrow := GetParentRow(ARow);
      nodespan := GetNodeSpan(parentrow);
      nodestate := false;
    end;
  end;

  if cg.CellType in [ctCheckBox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRowCheckBox] then
  begin
    if FromEdit and not ControlLook.CheckAlwaysActive then
    begin
      CanEdit := True;
      GetCellReadOnly(ACol,ARow,CanEdit);
      if not CanEdit then Exit;
    end;

    newstate := false;

    if cg.CellType = ctCheckBox then
    begin
      cg.CellBoolean := not cg.CellBoolean;
      newstate := cg.CellBoolean;
    end
    else
    if (cg.CellType = ctTriStateCheckBox) then
    begin
      if isnoderow then
      begin
        case (cg.CellCheckBoxState) of
          cbChecked:  cg.CellCheckBoxState := cbUnchecked;
          cbUnchecked:cg.CellCheckBoxState := cbChecked;
          cbGrayed:   cg.CellCheckBoxState := cbChecked;
        end;
        newstate := (cg.CellCheckBoxState = cbChecked);
      end
      else
      begin
        case (cg.CellCheckBoxState) of
          cbChecked:  cg.CellCheckBoxState := cbUnchecked;
          cbUnchecked:
            begin
              if Navigation.ToggleTriStateCheck = tsAllStates then
                cg.CellCheckBoxState := cbGrayed
              else
                cg.CellCheckBoxState := cbChecked;
            end;
          cbGrayed:   cg.CellCheckBoxState := cbChecked;
        end;
      end;
    end
    else
    begin
      if (Cells[ACol,ARow] = GetCheckTrue(ACol,ARow)) then
      begin
        Cells[ACol,ARow] := GetCheckFalse(ACol,ARow);
        newstate := false;
      end
      else
      begin
        Cells[ACol,ARow] := GetCheckTrue(ACol,ARow);
        newstate := true;
      end;
    end;

    RColI := RemapColInv(ACol);

    RepaintCell(RColI,ARow);

    DoCheckBoxChange(ACol, ARow, newstate);

    if Grouping.AutoCheckGroup and (ARow >= FixedRows) then
    begin
      if isnoderow then
      begin
        for i := 1 to nodespan - 1 do
        begin
          if nodestate then
            SetCheckBoxState(ACol, RealRowIndex(ARow) + i, newstate)
          else
            SetCheckBoxState(ACol, RealRowIndex(ARow + i), newstate)
        end;
      end
      else
      begin
        begin
          GetCheckBoxState(ACol, RealRowIndex(parentrow + 1), newstate);
          samestate := true;

          for i := 1 to nodespan - 1 do
          begin
            GetCheckBoxState(ACol, RealRowIndex(parentrow + i), nodestate);
            if nodestate <> newstate then
              samestate := false;
          end;

          if not samestate then
            SetCheckBoxState(ACol, RealRowIndex(parentrow), cbGrayed)
          else
          begin
            if newstate then
              SetCheckBoxState(ACol, RealRowIndex(parentrow), cbChecked)
            else
              SetCheckBoxState(ACol, RealRowIndex(parentrow), cbUnChecked);
          end;
        end;
      end;
    end;

    Result := True;

    if Assigned(UndoRedo) then
    begin
      if not cg.CellBoolean then
        UndoRedo.RegisterChange(ACol,ARow,GetCheckFalse(ACol,ARow),GetCheckTrue(ACol,ARow))
      else
        UndoRedo.RegisterChange(ACol,ARow,GetCheckTrue(ACol,ARow),GetCheckFalse(ACol,ARow))
    end;
  end;
end;

function TAdvStringGrid.ToggleRadioButton(ACol,ARow: Integer; FromEdit: Boolean): Boolean;
var
  cg: TCellGraphic;
  Canedit: Boolean;
  RColI: Integer;
  r: integer;
begin
  Result := False;

  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;

  if cg.CellType = ctRadioButton then
  begin
    if FromEdit and not ControlLook.CheckAlwaysActive then
    begin
      CanEdit := True;
      GetCellReadOnly(ACol,ARow,CanEdit);
      if not CanEdit then Exit;
    end;

    if not cg.CellBoolean then
    begin
      cg.CellBoolean := true;

      RColI := RemapColInv(ACol);
      RepaintCell(RColI,ARow);

      case TRadioButtonGroup(cg.CellAngle) of
      rgCol:
        begin
          for r := ARow + 1 to RowCount - 1 do
          begin
            cg := GetCellGraphic(ACol,r);
            if Assigned(cg) and (cg.CellType = ctRadioButton) then
            begin
              if cg.CellBoolean then
              begin
                cg.CellBoolean := false;
                RepaintCell(RColI, r);
              end;
            end
            else
              break;
          end;

          for r := ARow - 1 downto 0 do
          begin
            cg := GetCellGraphic(ACol,r);
            if Assigned(cg) and (cg.CellType = ctRadioButton) then
            begin
              if cg.CellBoolean then
              begin
                cg.CellBoolean := false;
                RepaintCell(RColI, r);
              end;
            end
            else
              break;
          end;

        end;
      rgRow:
        begin
          for r := ACol + 1 to ColCount - 1 do
          begin
            cg := GetCellGraphic(r,ARow);
            if Assigned(cg) and (cg.CellType = ctRadioButton) then
            begin
              if cg.CellBoolean then
              begin
                cg.CellBoolean := false;
                RepaintCell(r, ARow);
              end;
            end
            else
              break;
          end;

          for r := ACol - 1 downto 0 do
          begin
            cg := GetCellGraphic(r,ARow);
            if Assigned(cg) and (cg.CellType = ctRadioButton) then
            begin
              if cg.CellBoolean then
              begin
                cg.CellBoolean := false;
                RepaintCell(r, ARow);
              end;
            end
            else
              break;
          end;
        end;
      end;

    end;
   Result := True;
  end;
end;


function TAdvStringGrid.ToggleCheckBox(ACol,ARow: Integer): Boolean;
begin
  Result := ToggleCheck(ACol,ARow,False);
end;

function TAdvStringGrid.GetImageIdx(ACol,ARow: Integer;var Idx: Integer): Boolean;
begin
  Result := False;
  if not Assigned(FGridImages) then
    Exit;

  if CellTypes[ACol,ARow] = ctImageList then
  begin
    Idx := GetCellGraphic(ACol,ARow).CellIndex;
    Result := True;
  end;
end;

procedure TAdvStringGrid.SetImageIdx(ACol, ARow, Idx: integer);
begin
  if not Assigned(FGridImages) then
    Exit;

  if CellTypes[ACol,ARow] = ctImageList then
    GetCellGraphic(ACol,ARow).CellIndex := Idx;
end;

procedure TAdvStringGrid.AddDataImage(ACol,ARow,AIdx: Integer;hal:TCellHalign;val:TCellValign);
begin
  if not Assigned(FGridImages) then
    Exit;

  with CreateCellGraphic(ACol,ARow) do
  begin
    SetDataImage(AIdx,hal,val);
    if (Cells[ACol,ARow] = '') then
      Ints[ACol,ARow] := AIdx;
  end;
end;

procedure TAdvStringGrid.RemoveDataImage(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctDataImage);
  Cells[ACol,ARow] := '';
end;

function TAdvStringGrid.HasDataImage(ACol,ARow: Integer): Boolean;
var
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] = ctDataImage);
end;


procedure TAdvStringGrid.AddMultiImage(ACol,ARow,Dir: Integer;hal:TCellHalign;val:TCellValign);
begin
  if not Assigned(FGridImages) then
    Exit;

  with CreateCellGraphic(ACol,ARow) do
  begin
    SetMultiImage(ACol,ARow,dir,hal,val,MultiImageChanged);
  end;
end;

procedure TAdvStringGrid.RemoveMultiImage(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctImages);
end;

procedure TAdvStringGrid.AddImageIdx(ACol,ARow,AIdx: Integer;hal:TCellHalign;val:TCellValign);
begin
  if not Assigned(FGridImages) then Exit;

  with CreateCellGraphic(ACol,ARow) do
  begin
    SetImageIdx(AIdx,hal,val);
  end;
end;

procedure TAdvStringGrid.RemoveImageIdx(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctImageList);
end;

procedure TAdvStringGrid.SetImages(Value: TCustomImageList);
begin
  if Value <> FGridImages then
  begin
    FGridImages := Value;
  end;
end;

procedure TAdvStringGrid.SetURLColor(Value: TColor);
begin
  if (FURLColor <> Value) then
  begin
    FURLColor := Value;
    if FURLShow then
      Invalidate;
  end;
end;

procedure TAdvStringGrid.SetURLShow(Value: Boolean);
begin
  if (FURLShow <> Value) then
  begin
    FURLShow := Value;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetURLShowInText(Value: Boolean);
begin
  if (FURLShowInText <> Value) then
  begin
    FURLShowInText := Value;
    Invalidate;
  end;
end;


procedure TAdvStringGrid.SetURLFull(Value: Boolean);
begin
  FURLFull := Value;
  if FURLShow then
    Invalidate;
end;

function TAdvStringGrid.GetLookAsString(Value: TGridLook): string;
begin
  case Value of
    glStandard:  result := 'glStandard';
    glSoft:      result := 'glSoft';
    glClassic:   result := 'glClassic';
    glTMS:       result := 'glTMS';
    glXP:        result := 'glXP';
    glListView:  result := 'glListView';
    glVista:     result := 'glVista';
    glWin7:      result := 'glWin7';
    glOffice2007:result := 'glOffice2007';
  end;
end;

function TAdvStringGrid.GetLookAsFriendlyString(Value: TGridLook): string;
begin
  case Value of
    glStandard:  Result := 'Standard';
    glSoft:      Result := 'Soft';
    glClassic:   Result := 'Classic';
    glTMS:       Result := 'TMS';
    glXP:        Result := 'Windows XP';
    glListView:  Result := 'ListView';
    glVista:     Result := 'Windows Vista';
    glWin7:      Result := 'Windows 7';
    glOffice2007:Result := 'Office2007';
  end;
end;

procedure TAdvStringGrid.SetLook(Value: TGridLook);
begin
  if FLook <> Value then
  begin
    FLook := Value;

    // Make sure to always clear mirror gradients that are not used in all styles
    if (Value <> glCustom) then
    begin
      ControlLook.FixedGradientMirrorFrom := clNone;
      ControlLook.FixedGradientMirrorTo := clNone;
      ControlLook.FixedGradientFrom := clNone;
      ControlLook.FixedGradientTo := clNone;
      FTMSGradFrom := clNone;
      FTMSGradTo := clNone;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      SortSettings.HeaderColor := clNone;
    end;

    case Value of
    glCustom:
      begin
        // do nothing
      end;
    glVista:
      begin
        SetStyle(gsWindowsVista);
        FStyle := tsWindowsVista;
        SelectionStyle := ssVista;
      end;
    glWin7:
      begin
        SetStyle(gsWindows7);
        FStyle := tsWindows7;
        SelectionStyle := ssWin7;
      end;
    glOffice2007:
      begin
        SetStyle(gsOffice2007Luna);
        FStyle := tsOffice2007Luna;
        SelectionStyle := ssOffice2007;
      end
    else
      begin
        if not (csDesigning in ComponentState) then
          SetEditorsStyle(tsWindowsXP);

        SelectionStyle := ssDefault;

        // preserve design time settings
        if not (csLoading in ComponentState) then
        begin
          if (Value in [glClassic, glSoft, glStandard]) then
          begin
            if not (csLoading in ComponentState) then
              FixedColor := clBtnFace;
            ControlLook.FixedGradientFrom := clBtnFace;
            ControlLook.FixedGradientTo := clNone;
          end
          else
          begin
            ControlLook.FixedGradientFrom := clWhite;
            ControlLook.FixedGradientTo := clBtnFace;
          end;

          GridFixedLineColor := clGray;
          ControlLook.FixedGradientMirrorFrom := clNone;
          ControlLook.FixedGradientMirrorTo := clNone;
          FTMSGradMirrorFrom := clNone;
          FTMSGradMirrorTo := clNone;

          GridFixedLineColor := clGray;
          GridLineColor := clSilver;

          if Value in [glXP,glTMS] then
          begin
            ActiveCellColor := $00EACAB6;
            ActiveCellColorTo := clNone;
            SelectionColor := $00EACAB6;
            SelectionColorTo := clNone;
            SelectionTextColor := clBlack;
            FSearchFooter.Color := FTMSGradFrom;
            FSearchFooter.ColorTo := FTMSGradTo;

            if Value = glXP then
            begin
              ControlLook.FixedGradientFrom := clWhite;
              ControlLook.FixedGradientTo := clBtnFace;
            end
            else
            begin
              ControlLook.FixedGradientFrom := clWhite;
              ControlLook.FixedGradientTo := clSilver;
            end;

            ControlLook.FixedGradientHoverFrom := $CFD0D1;
            ControlLook.FixedGradientHoverTo := $BEC6C8;
            ControlLook.FixedGradientHoverMirrorFrom := $BEC6C8;
            ControlLook.FixedGradientHoverMirrorTo := $ABBCBF;

            ControlLook.FixedGradientDownFrom := $868788;
            ControlLook.FixedGradientDownTo := $737C7E;
            ControlLook.FixedGradientDownMirrorFrom := $737C7E;
            ControlLook.FixedGradientDownMirrorTo := $627376;
          end
          else
          begin
            ActiveCellColor := clGray;
            ActiveCellColorTo := clNone;
            SelectionColor := clHighLight;
            SelectionTextColor := clHighlightText;
            FSearchFooter.Color := clBtnFace;
            FSearchFooter.ColorTo := clBtnFace;
          end;
        end;
      end;
    end;

    // default scroll & border style
    ScrollType := ssNormal;
    //BorderStyle := bsSingle;

    if Look <> glCustom then
      BorderColor := $B99D7F;
    //Flat := false;

    Repaint;

    if not (csLoading in ComponentState) then
    begin
      UpdateFooter;
    end;
  end;
end;

procedure TAdvStringGrid.AddRotated(ACol,ARow: Integer;AAngle:SmallInt;s:string);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    SetAngle(AAngle);
  end;
  Cells[ACol,ARow] := s;
end;

procedure TAdvStringGrid.SetRotated(ACol,ARow: Integer;AAngle:SmallInt);
var
  cg: TCellGraphic;
begin
  cg := GetCellgraphic(ACol,ARow);
  if not Assigned(cg) then
    cg := CreateCellGraphic(ACol,ARow);
  cg.SetAngle(AAngle);
end;

procedure TAdvStringGrid.RemoveRotated(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctRotated);
end;

function TAdvStringGrid.IsRotated(ACol,ARow: Integer;var aAngle: Integer): Boolean;
begin
  Result := CellTypes[ACol,ARow] = ctRotated;

  if Result then
    AAngle := GetCellGraphic(ACol,ARow).CellAngle;
end;

procedure TAdvStringGrid.ScrollInView(ColIndex,RowIndex: Integer; Position: TScrollPosition = spMiddle);
var
  nc,nr,lr: Integer;
  r: TRect;

begin
  if ColIndex >= ColCount then
    Exit;
  if RowIndex >= RowCount then
    Exit;

  nc := LeftCol;
  nr := TopRow;

  if (ColIndex < LeftCol) or (ColIndex >= LeftCol + VisibleColCount) then
  begin
    if IsSelectionHidden then
      UnHideSelection;

    if (ColIndex >= FixedCols) and (ColIndex < AllColCount) then
      Col := ColIndex;
    case Position of
      spMiddle: nc := ColIndex - (VisibleColCount shr 1);
      spTrailing: nc := ColIndex - VisibleColCount + 1;
      spLeading: nc := ColIndex;
    end;

    if nc < FixedCols then nc := FixedCols;
  end;

  if (RowIndex < TopRow) or (RowIndex >= TopRow + VisibleRowCount) then
  begin
    if (RowIndex >= FixedRows) and (RowIndex < AllRowCount) then 
      Row := RowIndex;
    case Position of
      spMiddle: nr := RowIndex - (VisibleRowCount shr 1);
      spTrailing: nr := RowIndex - VisibleRowCount + 1;
      spLeading: nr := RowIndex;
    end;

    if nr < FixedRows then nr := FixedRows;
  end;

  if nc > ColCount - (VisibleColCount - 1) then // - 1 to avoid partially visible last column
    nc := ColCount - (VisibleColCount - 1);

  if (ColCount > FixedCols + VisibleColCount) then
    LeftCol := nc;

  if nr > RowCount - (VisibleRowCount - 1) then // -1 to avoid partially visible last row
    nr := RowCount - (VisibleRowCount - 1);

  if RowCount > FixedRows + VisibleRowCount then
  begin
    TopRow := nr;

    if Searchfooter.Visible then
    begin
      // determine top of search panel
      lr := Height - SearchPanel.Height;
      if ColCount > VisibleColCount then
        lr := lr - GetSystemMetrics(SM_CYHSCROLL);

      r := CellRect(0,RowIndex);

      if r.Bottom < lr then
        Exit;

      // make sure row to highligh is above the search panel
      while (lr < r.Bottom) and (TopRow < RowCount - 1 - FixedFooters) do
      begin
        TopRow := TopRow + 1;
        r := CellRect(0,RowIndex);
      end;
    end;
  end;
end;

procedure TAdvStringGrid.MoveColumn(FromIndex, ToIndex: Integer);
var
  i: integer;
  iFilterCol: Integer;
  Rfi,Rti: Integer;
begin
  if FColumnOrder.Count = 0 then
    SetColumnOrder;

  if (FGroupColumn <> -1) and (Grouping.MergeHeader or Grouping.MergeSummary) then
  begin
    GroupSplit;
  end;

  Rfi := RemapCol(FromIndex);
  Rti := RemapCol(ToIndex);
  ColumnMoved(FromIndex,ToIndex);

  for i := 1 to FFilter.Count do
  begin
    iFilterCol := FFilter.Items [i - 1].Column;
    if (iFilterCol = Rfi) then
    begin
      FFilter.Items [i - 1].Column := Rti;
    end
    else if ((iFilterCol < Rfi) and (iFilterCol >= Rti)) then
    begin
      FFilter.Items [i - 1].Column := iFilterCol + 1;
    end
    else if ((iFilterCol > Rfi) and (iFilterCol <= Rti)) then
    begin
      FFilter.Items [i - 1].Column := iFilterCol - 1;
    end;
  end;
  if (FControlList.Count > 0) then
  begin
    for i := 0 to FControlList.Count - 1 do
    begin
      if FromIndex > ToIndex then
      begin
        if (FControlList.Control[i].X < FromIndex) and (FControlList.Control[i].X >= ToIndex) then
          FControlList.Control[i].X := FControlList.Control[i].X + 1
        else
          if (FControlList.Control[i].X = FromIndex)  then
            FControlList.Control[i].X := ToIndex;
      end
      else
      begin
        if (FControlList.Control[i].X > FromIndex) and (FControlList.Control[i].X <= ToIndex) then
          FControlList.Control[i].X := FControlList.Control[i].X - 1
        else
          if (FControlList.Control[i].X = FromIndex)  then
            FControlList.Control[i].X := ToIndex;
      end;
    end;

    CellControlsUpdate;
  end;

  if (FGroupColumn <> -1) and (Grouping.MergeHeader or Grouping.MergeSummary) then
  begin
    GroupMerge;
  end;
end;

procedure TAdvStringGrid.MoveRows(FromIndex, ToIndex, Count: Integer);
var
  i: integer;
  newindex: integer;
  rws: array of TStringList;
begin
  if (FromIndex = ToIndex) or (Count = 0) then
    Exit;

  SetLength(rws,Count);

  for i := FromIndex to FromIndex + Count - 1 do
  begin
    rws[i - FromIndex] := TStringList.Create;
    rws[i - FromIndex].Assign(Rows[i]);
  end;

  newindex := ToIndex;
  if newindex > FromIndex + Count then
    newindex := ToIndex - Count;

  RemoveRowsEx(FromIndex, Count);

  InsertRows(newindex,count,true);

  for i := 0 to Count - 1 do
  begin
    Rows[newindex + i].Assign(rws[i]);
    rws[i].Free;
  end;

end;

procedure TAdvStringGrid.MoveRow(FromIndex, ToIndex: Integer);
var
  i: integer;
begin
  RowMoved(FromIndex,ToIndex);

  if (FControlList.Count > 0) then
  begin
    for i := 0 to FControlList.Count - 1 do
    begin
      if FromIndex > ToIndex then
      begin
        if (FControlList.Control[i].Y < FromIndex) and (FControlList.Control[i].Y >= ToIndex) then
          FControlList.Control[i].Y := FControlList.Control[i].Y + 1
        else
          if (FControlList.Control[i].Y = FromIndex)  then
            FControlList.Control[i].Y := ToIndex;
      end
      else
      begin
        if (FControlList.Control[i].Y > FromIndex) and (FControlList.Control[i].Y <= ToIndex) then
          FControlList.Control[i].Y := FControlList.Control[i].Y - 1
        else
          if (FControlList.Control[i].Y = FromIndex)  then
            FControlList.Control[i].Y := ToIndex;
      end;
    end;
    CellControlsUpdate;
  end;

  if ShowModified.Enabled then
  begin
    for i := FModifiedRows.Count to RowCount do
     FModifiedRows.Add(0);

    FModifiedRows.Move(FromIndex, ToIndex);
  end;

end;

procedure TAdvStringGrid.UnHideSelection;
var
  nc: TGridRect;
begin
  FSelHidden := False;

  if (FOldSelection.Top < RowCount) and
     (FOldSelection.Left < ColCount) then
    Selection := FOldSelection
  else
  begin
    if FixedRowAlways and (FixedRows = RowCount) then
      nc.Top := 0
    else
      nc.Top := FixedRows;

    if FixedColAlways and (FixedCols = ColCount) then
      nc.Left := 0
    else
      nc.Left := FixedCols;

    nc.Right := nc.Left;
    nc.Bottom := nc.Top;

    Selection := nc;
  end;
end;

procedure TAdvStringGrid.UpdateEditMode;
begin
  SelectCell(Col,Row);
end;

function TAdvStringGrid.IsSelectionHidden: boolean;
begin
  Result := (Selection.Left = ColCount) and (Selection.Top = RowCount) and (Selection.Right = ColCount) and (Selection.Top = RowCount);
end;

procedure TAdvStringGrid.HideSelection;
begin
  FOldSelection := Selection;
  Selection := TGridRect(Rect(ColCount,RowCount,ColCount,RowCount));
  FSelHidden := True;
end;

procedure TAdvStringGrid.SuppressColumn(ColIndex: Integer);
begin
  FSuppressColSizes[ColIndex] := ColWidths[ColIndex];
  ColWidths[ColIndex] := 0;
end;

procedure TAdvStringGrid.UnSuppressColumn(ColIndex: Integer);
begin
  ColWidths[ColIndex] := FSuppressColSizes.Items[ColIndex];
end;

procedure TAdvStringGrid.UnSuppressAllColumns;
var
  i: integer;
begin
  for i := 0 to LastCol do
  begin
    if (FSuppressColSizes.Items[i] > 0) and (ColWidths[i] = 0) then
    begin
      ColWidths[i] := FSuppressColSizes.Items[i];
    end;
  end;

  FSuppressColSizes.Clear;
  for i := 0 to LastCol do
    FSuppressColSizes.Add(ColWidths[i]);
end;


/// <summary>Hides the column in the grid</summary>
/// <comments>Use UnHideColumn or UnHideColumnsAll to unhide columns</comments>
procedure TAdvStringGrid.HideColumn(Colindex: Integer);
begin
  HideColumns(Colindex,Colindex);
end;

procedure TAdvStringGrid.HideColumns(FromCol,ToCol: Integer);
var
  i,j: Integer;
  selh: boolean;
begin
  HideInplaceEdit;

  for j := FromCol to ToCol do
  begin
    if (GetVisibleCol(j)) and (j < ColCount + FNumHidden) and (ColCount >= 2) then
    begin
      FAllColWidths[j] := ColWidths[RemapColInv(j)];

      for i := RemapColInv(j) to ColCount - 2 do
        ColWidths[i] := ColWidths[i + 1];
      Inc(FNumHidden);
      SetVisibleCol(j,False);

      if Col = ColCount - 1 then
        Col := Col - 1;

      selh := IsSelectionHidden;
      if selh then
        UnHideSelection;

      ColCount := ColCount - 1;

      if selh then
        HideSelection;
    end;
  end;

  Invalidate;
end;

procedure TAdvStringGrid.UnHideColumn(Colindex: Integer);
begin
  UnHideColumns(Colindex,Colindex);
end;

procedure TAdvStringGrid.UnHideColumnsAll;
begin
  UnHideColumns(0,ColCount - 1 + FNumHidden);
end;

procedure TAdvStringGrid.UnHideColumns(FromCol,ToCol: Integer);
var
  i,j,k: Integer;
begin
  HideInplaceEdit;

  for j := FromCol to ToCol do
  begin
    if not GetVisibleCol(j) then
    begin
      Dec(FNumHidden);
      SetVisibleCol(j,True);
      ColCount := ColCount + 1;
      for i := ColCount - 1 downto RemapColinv(j + 1) do
        ColWidths[i] := ColWidths[i - 1];

      k := RemapColinv(j);

      ColWidths[k] := FAllColWidths[j];
    end;
  end;
  Invalidate;
end;

function TAdvStringGrid.IsHiddenColumn(Colindex: Integer): Boolean;
begin
  if (ColIndex < AllColCount) then
    IsHiddenColumn := not FVisibleCol[Colindex]
  else
    IsHiddenColumn := False;
end;

function TAdvStringGrid.NumHiddenColumns: Integer;
begin
  Result := FNumHidden;
end;

function TAdvStringGrid.TotalColCount: Integer;
begin
  Result := FNumHidden + ColCount;
end;

function TAdvStringGrid.RemapRowInv(ARow: Integer): Integer;
var
  i,k: Integer;
//  lh: TIntList;
begin
  i := 0;
  k := 0;

  if (NumHiddenRows = 0) then
  begin
    i := ARow + 1;
  end
  else
  begin
    //lh := nil;
    //try
      InitHiddenRowLookup;

      while (k <= ARow) do
      begin
        if not IsHiddenRow(i, FHiddenRowLookup) then Inc(k);
        Inc(i);
      end;

    //finally
    //  if (lh <> nil) then FreeAndNil(lh);
    //end;
  end;

  Result := i - 1;
end;

function TAdvStringGrid.RemapRow(ARow: Integer): Integer;
var
  i,j: Integer;
begin
  i := ARow;
  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx < i then
      Dec(ARow);
  end;
  Result := ARow;
end;

procedure TAdvStringGrid.SetGroupColumn(AGroupColumn: Integer);
begin
  if AGroupColumn = -1 then
    UnGroup
  else
    if (AGroupColumn > 0) then Group(AGroupColumn);
end;

procedure TAdvStringGrid.GroupSum(Colindex: Integer);
begin
  GroupCalc(Colindex,1);

  if FloatingFooter.Visible then
    FloatingFooter.ColumnCalc[Colindex] := acSum;
end;

procedure TAdvStringGrid.GroupAvg(Colindex: Integer);
begin
  GroupCalc(Colindex,2);

  if FloatingFooter.Visible then
    FloatingFooter.ColumnCalc[Colindex] := acAvg;
end;

procedure TAdvStringGrid.GroupMin(Colindex: Integer);
begin
  GroupCalc(Colindex,3);

  if FloatingFooter.Visible then
    FloatingFooter.ColumnCalc[Colindex] := acMin;
end;

procedure TAdvStringGrid.GroupMax(Colindex: Integer);
begin
  GroupCalc(Colindex,4);
  if FloatingFooter.Visible then
    FloatingFooter.ColumnCalc[Colindex] := acMax;
end;

procedure TAdvStringGrid.GroupCount(Colindex: Integer);
begin
  GroupCalc(Colindex,5);
  if FloatingFooter.Visible then
    FloatingFooter.ColumnCalc[Colindex] := acCOUNT;
end;

procedure TAdvStringGrid.GroupCustomCalc(Colindex: Integer);
begin
  GroupCalc(Colindex,6);
end;

procedure TAdvStringGrid.GroupDistinct(Colindex: Integer);
begin
  GroupCalc(Colindex,7);
end;

procedure TAdvStringGrid.GroupStdDev(Colindex: Integer);
begin
  GroupCalc(Colindex,8);
end;


procedure TAdvStringGrid.GroupCalc(Colindex,Method: Integer);
var
  i,j,k,iGNS: Integer;
begin
  i := FixedRows;
  while (i < RowCount) do
  begin
    if IsNode(i) then
    begin
      if not NodeState[i] then
      begin
        iGNS := GetNodeSpan(i);

        j := i + iGNS;
        if Grouping.Summary then
          k := j
        else
          k := i;

        case Method of
        1:Floats[Colindex,k] := ColumnSum(Colindex,i + 1,j - 1);
        2:Floats[Colindex,k] := ColumnAvg(Colindex,i + 1,j - 1);
        3:Floats[Colindex,k] := ColumnMin(Colindex,i + 1,j - 1);
        4:Floats[Colindex,k] := ColumnMax(Colindex,i + 1,j - 1);
        5:Ints[ColIndex,k] := j - 1 - i;
        6:Floats[ColIndex,k] := ColumnCustomCalcGrp(Colindex,i + 1,j - 1);
        7:Floats[ColIndex,k] := ColumnDistinct(ColIndex, i + 1, j - 1);
        8:Floats[ColIndex,k] := ColumnStdDev(ColIndex, i + 1, j - 1);
        end;

        i := j;
      end
      else
        inc(i);
    end
    else
      Inc(i);
  end;
end;

procedure TAdvStringGrid.SubUnGroup(ColIndex: Integer);
var
  i: Integer;
  nc: string;
  grpc: Integer;
begin
  ExpandAll;
  grpc := ColIndex;
  i := FixedRows;

  while i <= RowCount - 1 - FFixedFooters do
  begin
    if IsNode(i) then
    begin
      if CellGraphics[0,i].CellVar = ColIndex then
      begin
        {
        if Grouping.Summary then
        begin
          j := GetNodeSpan(i);

          if Grouping.MergeSummary then
            SplitCells(grpc,i + j)
          else
          begin
            if Grouping.SummaryColor <> clNone then
              RowColor[i + j] := clNone;
            if Grouping.SummaryColorTo <> clNone then
              RowColorTo[i + j] := clNone;
          end;

          ClearPropCell(0,i + j);
          IRemoveRows(i + j,1,false);
        end;
        }

        nc := Cells[grpc + 1,i];
        RemoveNode(i);

        //ClearPropCell(0,i);

        if Grouping.MergeHeader then
          SplitCells(grpc,i)
        else
        begin
          if Grouping.HeaderColor <> clNone then
            RowColor[i] := clNone;
          if Grouping.HeaderColorTo <> clNone then
            RowColorTo[i] := clNone;
        end;

        //ClearRect(0,i,ColCount - 1,i);
        RemoveChildRow(i);
        //IRemoveRows(i,1,false);
      end
      else
      begin
        inc(i);
      end;
    end
    else
    begin
      Cells[grpc,i] := nc;
      inc(i);
    end;
  end;
end;

procedure TAdvStringGrid.SubGroup(ColIndex: Integer);
var
  i,np: Integer;
  lc,nc: string;
  grp,grpc: Integer;
begin
  if (Colindex < FixedCols) then
    Exit;

//  if FGroupColumn <> -1 then
//    UnGroup;

  BeginUpdate;

  try
    FGroupColumn := Colindex;
    FGroupWidth := ColWidths[Colindex];

    if FixedRows > 0 then
      FGroupCaption := Cells[Colindex,0];

    if FixedFooters > 0 then
      FGroupFooter := Cells[ColIndex, RowCount - 1];

    grp := Colindex;
    //grpc := 1 {+ FixedCols};
    grpc := ColIndex;

    // sort the Column to group first

  //  if FSortSettings.AutoSortForGrouping then
  //  begin
  //    FSortSettings.Column := Colindex;
  //    QSortGroup;
  //  end;

    if grpc = Colindex then
      Inc(grpc);

    np := -1;
    lc := string(#255#254);

    i := FixedRows + 1;

    while (i < RowCount  - FFixedFooters) do
    begin
      nc := Cells[Colindex,i];

      if (lc <> nc) or IsNode(i) or IsSummary(i) then // difference detected
      begin
        if (np <> -1) then // number of identical column values was found
        begin
          // need to insert summary for the last group
          if (np > FixedRows) and not IsNode(i) and not IsSummary(i) and (Grouping.Summary) and (1 < 0) then
          begin
            InsertChildRow(np,0);

            AddSummary(np);

            // set style of group summary span
            if Grouping.MergeSummary and Grouping.Summary then
            begin
              MergeCells(grpc,np,ColCount - grpc,1);
              if Grouping.SummaryColor <> clNone then
                Colors[grpc,np] := ColorToRGB(Grouping.SummaryColor);
              if Grouping.SummaryColorTo <> clNone then
                ColorsTo[grpc,np] := ColorToRGB(Grouping.SummaryColorTo);
              if Grouping.SummaryTextColor <> clNone then
                FontColors[grpc,np] := ColorToRGB(Grouping.SummaryTextColor);
            end
            else
            begin
              if Grouping.SummaryColor <> clNone then
                RowColor[np] := ColorToRGB(Grouping.SummaryColor);
              if Grouping.SummaryColorTo <> clNone then
                RowColorTo[np] := ColorToRGB(Grouping.SummaryColorTo);
              if Grouping.SummaryTextColor <> clNone then
                RowFontColor[np] := ColorToRGB(Grouping.SummaryTextColor);
            end;

            inc(np);
            AddNode(np,i - np + 1);

            CellGraphics[0, np].CellVar := ColIndex;
            inc(i);
          end
          else
          begin
            // add node for identical rows found
            if not (IsNode(np) or IsSummary(np)) then
            begin
              AddNode(np,i - np);
              CellGraphics[0, np].CellVar := ColIndex;
            end;
          end;
        end;

        // insert group header row

        if not (IsNode(i) or IsSummary(i)) then
        begin
          InsertChildRow(i,0);

          Cells[grpc,i] := nc;

          //else
          //  inc(i);

          // set style of group header span
          if Grouping.MergeHeader then
          begin
            MergeCells(grpc,i,ColCount - grpc ,1);
            if Grouping.HeaderColor <> clNone then
              Colors[grpc,i] := ColorToRGB(Grouping.HeaderColor);
            if Grouping.HeaderColorTo <> clNone then
              ColorsTo[grpc,i] := ColorToRGB(Grouping.HeaderColorTo);
            if Grouping.HeaderTextColor <> clNone then
              FontColors[grpc,i] := ColorToRGB(Grouping.HeaderTextColor);
          end
          else
          begin
            if Grouping.HeaderColor <> clNone then
              RowColor[i] := ColorToRGB(Grouping.HeaderColor);
            if Grouping.HeaderColorTo <> clNone then
              RowColorTo[i] := ColorToRGB(Grouping.HeaderColorTo);
            if Grouping.HeaderTextColor <> clNone then
              RowFontColor[i] := ColorToRGB(Grouping.HeaderTextColor);
          end;
        end;

        np := i;
        Inc(i);
      end;

      if (i < RowCount ) and not IsNode(i - 1) and not IsSummary(i - 1) then
      begin
        lc := Cells[grp,i];
        Cells[grp,i] := '';
        inc(i);
      end
      else
      begin
        lc := string(#255#254);
      end;
    end;

    // handle last group

    if not IsSummary(np) then
    begin
      if (np <> -1)  then
      begin
        if (np > FixedRows) and (Grouping.Summary) and (1 < 0) then
        begin
          InsertChildRow(np,0);

          AddSummary(np);

          if Grouping.MergeSummary and Grouping.Summary then
          begin
            MergeCells(grpc,np,ColCount - grpc,1);
            if Grouping.SummaryColor <> clNone then
              Colors[grpc,np] := ColorToRGB(Grouping.SummaryColor);
            if Grouping.SummaryColorTo <> clNone then
              ColorsTo[grpc,np] := ColorToRGB(Grouping.SummaryColorTo);
            if Grouping.SummaryTextColor <> clNone then
              FontColors[grpc,np] := ColorToRGB(Grouping.SummaryTextColor);
          end
          else
          begin
            if Grouping.SummaryColor <> clNone then
              RowColor[np] := ColorToRGB(Grouping.SummaryColor);
            if Grouping.SummaryColorTo <> clNone then
              RowColorTo[np] := ColorToRGB(Grouping.SummaryColorTo);
            if Grouping.SummaryTextColor <> clNone then
              RowFontColor[np] := ColorToRGB(Grouping.SummaryTextColor);
          end;

          inc(np);
          inc(i);
        end;

        // !! was i - np + 1 !!
        AddNode(np,i - np );
        CellGraphics[0, np].CellVar := ColIndex;

        if Grouping.MergeHeader then
        begin
          MergeCells(grpc,np,ColCount - grpc,1);
          if Grouping.HeaderColor <> clNone then
            Colors[grpc,np] := Grouping.HeaderColor;
          if Grouping.HeaderColorTo <> clNone then
            ColorsTo[grpc,np] := Grouping.HeaderColorTo;
          if Grouping.HeaderTextColor <> clNone then
            FontColors[grpc,np] := Grouping.HeaderTextColor;
        end
        else
        begin
          if Grouping.HeaderColor <> clNone then
            RowColor[np] := Grouping.HeaderColor;
          if Grouping.HeaderColorTo <> clNone then
            RowColorTo[np] := Grouping.HeaderColorTo;
          if Grouping.HeaderTextColor <> clNone then
            RowFontColor[np] := Grouping.HeaderTextColor;
        end;
      end
      else
      begin
        InsertChildRow(i,0);

        AddNode(i, 2);
        Cells[grpc,i] := Cells[grp,i + 1];
        inc(i);
        Cells[grp,i] := '';

        //
        //AddNode(FixedRows,i - 1);
        //CellGraphics[0, FixedRows].CellVar := ColIndex;
      end;

      if (i <= RowCount - 1) and not IsNode(i - 1) and not IsSummary(i - 1) then
      begin
        lc := Cells[grp,i];
        Cells[grp,i] := '';
        inc(i);
      end;


      if Grouping.Summary then
      begin
        InsertRows(i,1);

        AddSummary(i);

        if Grouping.MergeSummary and Grouping.Summary then
        begin
          MergeCells(grpc,i,ColCount - grpc,1);
          if Grouping.SummaryColor <> clNone then
            Colors[grpc,i] := Grouping.SummaryColor;
          if Grouping.SummaryColorTo <> clNone then
            ColorsTo[grpc,i] := Grouping.SummaryColorTo;
          if Grouping.SummaryTextColor <> clNone then
            FontColors[grpc,i] := Grouping.SummaryTextColor;
        end
        else
        begin
          if Grouping.SummaryColor <> clNone then
            RowColor[i] := Grouping.SummaryColor;
          if Grouping.SummaryColorTo <> clNone then
            RowColorTo[i] := Grouping.SummaryColorTo;
          if Grouping.SummaryTextColor <> clNone then
            RowFontColor[i] := Grouping.SummaryTextColor;
        end;
      end;
    end;

    // RemoveCols(grp,1);

    Row := FixedRows;
  finally
    EndUpdate;
  end;
end;

procedure TAdvStringGrid.GroupMerge;
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    if IsNode(i) and Grouping.MergeHeader then
      MergeCells(FixedCols,i,ColCount - FixedCols,1)
    else
    if IsSummary(i) and Grouping.MergeSummary then
      MergeCells(FixedCols,i,ColCount - FixedCols,1);
  end;
end;

procedure TAdvStringGrid.GroupSplit;
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin

    if IsNode(i) and Grouping.MergeHeader then
      SplitRowCells(i)
    else
    if IsSummary(i) and Grouping.MergeSummary then
      SplitRowCells(i);
  end;
end;


procedure TAdvStringGrid.Group(Colindex: Integer);
var
  i,np,ff: Integer;
  lc,nc: string;
  grp,grpc: Integer;

begin
  if (Colindex < FixedCols) then
    Exit;


  if FGroupColumn <> -1 then
    UnGroup;

  if (RowCount - FixedRows < 1) then
    Exit;

  ff := 1;
  if FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) then
    ff := 2;

  BeginUpdate;

  FIsGrouping := true;

  try
    FGroupColumn := Colindex;
    FGroupWidth := ColWidths[Colindex];

    if FixedRows > 0 then
      FGroupCaption := GridCells[Colindex,0];

    if FixedFooters > 0 then
      FGroupFooter := GridCells[ColIndex, RowCount - 1];

    grp := Colindex;
    grpc := 1 {+ FixedCols};

    // sort the Column to group first

    if FSortSettings.AutoSortForGrouping then
    begin
      FSortSettings.Column := Colindex;
      QSort;
    end;

    if grpc = Colindex then
      Inc(grpc);

    np := -1;
    lc := string(#255#254);

    i := FixedRows;

    while i <= RowCount - 1 - FFixedFooters do
    begin
      Application.ProcessMessages;

      nc := GridCells[Colindex,i];

      if lc <> nc then
      begin
        if np <> -1 then
        begin
          if (np > fixedrows) and (Grouping.Summary) then // this is a summary row insert for the last group
          begin
            InsertRows(np,1);
            AddSummary(np);

            // set style of group summary span
            if Grouping.MergeSummary and Grouping.Summary then
            begin
              {
              MergeCells(grpc,np,ColCount - grpc,1);
              if Grouping.SummaryColor <> clNone then
                Colors[grpc,np] := ColorToRGB(Grouping.SummaryColor);
              if Grouping.SummaryColorTo <> clNone then
                ColorsTo[grpc,np] := ColorToRGB(Grouping.SummaryColorTo);
              if Grouping.SummaryTextColor <> clNone then
                FontColors[grpc,np] := ColorToRGB(Grouping.SummaryTextColor);
              }
            end
            else
            begin
              if Grouping.SummaryColor <> clNone then
                RowColor[np] := ColorToRGB(Grouping.SummaryColor);
              if Grouping.SummaryColorTo <> clNone then
                RowColorTo[np] := ColorToRGB(Grouping.SummaryColorTo);
              if Grouping.SummaryTextColor <> clNone then
                RowFontColor[np] := ColorToRGB(Grouping.SummaryTextColor);
            end;

            inc(np);
            AddNode(np,i - np + 1);
            inc(i);
          end
          else
          begin
            AddNode(np,i - np);
          end;
        end;

        // insert group header row
        InsertRows(i,1);
        Cells[grpc,i] := nc;

        // set style of group header span
        if Grouping.MergeHeader then
        begin
          {
          MergeCells(grpc,i,ColCount - grpc,1);
          if Grouping.HeaderColor <> clNone then
            Colors[grpc,i] := ColorToRGB(Grouping.HeaderColor);
          if Grouping.HeaderColorTo <> clNone then
            ColorsTo[grpc,i] := ColorToRGB(Grouping.HeaderColorTo);
          if Grouping.HeaderTextColor <> clNone then
            FontColors[grpc,i] := ColorToRGB(Grouping.HeaderTextColor);
          }
        end
        else
        begin
          if Grouping.HeaderColor <> clNone then
            RowColor[i] := ColorToRGB(Grouping.HeaderColor);
          if Grouping.HeaderColorTo <> clNone then
            RowColorTo[i] := ColorToRGB(Grouping.HeaderColorTo);
          if Grouping.HeaderTextColor <> clNone then
            RowFontColor[i] := ColorToRGB(Grouping.HeaderTextColor);
        end;

        np := i;
        Inc(i);

      end;
      if i < RowCount - 1 then
        lc := GridCells[grp,i];

      Inc(i);
    end;

    if np <> -1 then
    begin
      if (np > FixedRows) and (Grouping.Summary) then
      begin
        InsertRows(np,1);
        AddSummary(np);

        if Grouping.MergeSummary and Grouping.Summary then
        begin
          {
          MergeCells(grpc,np,ColCount - grpc,1);
          if Grouping.SummaryColor <> clNone then
            Colors[grpc,np] := ColorToRGB(Grouping.SummaryColor);
          if Grouping.SummaryColorTo <> clNone then
            ColorsTo[grpc,np] := ColorToRGB(Grouping.SummaryColorTo);
          if Grouping.SummaryTextColor <> clNone then
            FontColors[grpc,np] := ColorToRGB(Grouping.SummaryTextColor);
          }
        end
        else
        begin
          if Grouping.SummaryColor <> clNone then
            RowColor[np] := ColorToRGB(Grouping.SummaryColor);
          if Grouping.SummaryColorTo <> clNone then
            RowColorTo[np] := ColorToRGB(Grouping.SummaryColorTo);
          if Grouping.SummaryTextColor <> clNone then
            RowFontColor[np] := ColorToRGB(Grouping.SummaryTextColor);
        end;

        inc(np);
        inc(i);
      end;

      AddNode(np,i - np);

      if Grouping.MergeHeader then
      begin
        {
        MergeCells(grpc,np,ColCount - grpc,1);
        if Grouping.HeaderColor <> clNone then
          Colors[grpc,np] := Grouping.HeaderColor;
        if Grouping.HeaderColorTo <> clNone then
          ColorsTo[grpc,np] := Grouping.HeaderColorTo;
        if Grouping.HeaderTextColor <> clNone then
          FontColors[grpc,np] := Grouping.HeaderTextColor;
        }
      end
      else
      begin
        if Grouping.HeaderColor <> clNone then
          RowColor[np] := Grouping.HeaderColor;
        if Grouping.HeaderColorTo <> clNone then
          RowColorTo[np] := Grouping.HeaderColorTo;
        if Grouping.HeaderTextColor <> clNone then
          RowFontColor[np] := Grouping.HeaderTextColor;
      end;
    end
    else
      AddNode(FixedRows,i - 1);

    if Grouping.Summary then
    begin
      InsertRows(i,1);

      AddSummary(i);

      if Grouping.MergeSummary and Grouping.Summary then
      begin
        {
        MergeCells(grpc,i,ColCount - grpc,1);
        if Grouping.SummaryColor <> clNone then
          Colors[grpc,i] := Grouping.SummaryColor;
        if Grouping.SummaryColorTo <> clNone then
          ColorsTo[grpc,i] := Grouping.SummaryColorTo;
        if Grouping.SummaryTextColor <> clNone then
          FontColors[grpc,i] := Grouping.SummaryTextColor;
        }
      end
      else
      begin
        if Grouping.SummaryColor <> clNone then
          RowColor[i] := Grouping.SummaryColor;
        if Grouping.SummaryColorTo <> clNone then
          RowColorTo[i] := Grouping.SummaryColorTo;
        if Grouping.SummaryTextColor <> clNone then
          RowFontColor[i] := Grouping.SummaryTextColor;
      end;
    end;

    RemoveCols(grp,1);

    if Grouping.MergeHeader or (Grouping.MergeSummary and Grouping.Summary) then
      for i := FixedRows to RowCount - 1 do
      begin
        grpc := 1;
        if IsNode(i) and Grouping.MergeHeader then
        begin
          MergeCells(grpc,i,ColCount - grpc,1);
          if Grouping.HeaderColor <> clNone then
            Colors[grpc,i] := ColorToRGB(Grouping.HeaderColor);
          if Grouping.HeaderColorTo <> clNone then
            ColorsTo[grpc,i] := ColorToRGB(Grouping.HeaderColorTo);
          if Grouping.HeaderTextColor <> clNone then
            FontColors[grpc,i] := ColorToRGB(Grouping.HeaderTextColor);
        end;

        if (IsNode(i + 1) or (i = RowCount - ff)) and Grouping.MergeSummary and Grouping.Summary then
        begin
          MergeCells(grpc,i,ColCount - grpc,1);
          if Grouping.SummaryColor <> clNone then
            Colors[grpc,i] := Grouping.SummaryColor;
          if Grouping.SummaryColorTo <> clNone then
            ColorsTo[grpc,i] := Grouping.SummaryColorTo;
          if Grouping.SummaryTextColor <> clNone then
            FontColors[grpc,i] := Grouping.SummaryTextColor;
        end;
      end;

   if CellNode.ExpandOne then
    begin
      for i := FixedRows to AllRowCount - 1 do
        if IsNode(i) then
        begin
          ExpandNode(i);
          Break;
        end;
    end;
    if (Col >= ColCount) or (Row >= RowCount) or (Col < 0) or (Row < 0) then
    begin
      GotoCellInt(FixedCols,FixedRows);
    end;

    Row := FixedRows;
  finally
    FIsGrouping := false;
    EndUpdate;
    if SearchFooter.Visible then
    begin // force correction of painting issue!
      SearchPanel.Width := SearchPanel.Width + 1;
      SearchPanel.Width := SearchPanel.Width - 1;
    end;
  end;
end;

procedure TAdvStringGrid.UnGroup;
var
  i,j: Integer;
  nc: string;
  grpc: Integer;
  eo: boolean;
begin
  if FGroupColumn <= 0 then
    Exit;

  eo := CellNode.ExpandOne;
  CellNode.ExpandOne := false;

  ExpandAll;

  if FGroupColumn = 1 then
    grpc := 2
  else
    grpc := 1;

  InsertCols(FGroupColumn,1);

  ColWidths[FGroupColumn] := FGroupWidth;

  // restore the column group caption
  if FixedRows > 0 then
    Cells[FGroupColumn,0] := FGroupCaption;

  if FixedFooters > 0 then
    Cells[FGroupColumn, RowCount - 1] := FGroupFooter;

  i := FixedRows;

  FIsGrouping := true;

  while i <= RowCount - 1 - FFixedFooters do
  begin
    if IsNode(i) then
    begin
      if Grouping.Summary {Grouping.MergeSummary} then
      begin
        j := GetNodeSpan(i);

        if Grouping.MergeSummary then
          SplitCells(1,i + j)
        else
        begin
          if Grouping.SummaryColor <> clNone then
            RowColor[i + j] := clNone;
          if Grouping.SummaryColorTo <> clNone then
            RowColorTo[i + j] := clNone;
        end;

        //ClearPropCell(0,i + j);
        ClearRect(0,i + j, ColCount - 1, i + j);
        IRemoveRows(i + j,1,false);
      end;

      nc := GridCells[grpc,i];
      RemoveNode(i);

      ClearPropCell(0,i);

      if Grouping.MergeHeader then
        SplitCells(1,i)
      else
      begin
        if Grouping.HeaderColor <> clNone then
          RowColor[i] := clNone;
        if Grouping.HeaderColorTo <> clNone then
          RowColorTo[i] := clNone;
      end;

      ClearRect(0,i,ColCount - 1,i);

      IRemoveRows(i,1,false);
    end
    else
    begin
      Cells[FGroupColumn,i] := nc;
      inc(i);
    end;
  end;

  FIsGrouping := false;

  FGroupColumn := -1;
  CellNode.ExpandOne := eo;
  Invalidate;
end;

procedure TAdvStringGrid.InitHiddenRowLookup;
var
  j, iCount: Integer;
begin
  if (FHiddenRowLookup = nil) then
  begin
    FHiddenRowLookup := TIntList.Create(-1, -1);
    iCount := FGriditems.Count;
    for j := 1 to iCount do
      FHiddenRowLookup.Insert((FGridItems.Items[j-1] as TGridItem).Idx);
  end;
end;

procedure TAdvStringGrid.DestroyHiddenRowLookup;
begin
  if Assigned(FHiddenRowLookup) then
    FreeAndNil(FHiddenRowLookup);
end;

procedure TAdvStringGrid.HideRow(RowIndex: Integer);
begin
  HideRows(RowIndex,RowIndex);
end;

procedure TAdvStringGrid.HideRows(FromRow,ToRow: Integer);
var
  j,k,l,c: Integer;
  rlist: TIntList;
begin
  k := FromRow;
  l := 0;
  c := 0;

  DestroyHiddenRowLookup;

  rlist := TIntList.Create(-1,-1);

  //count nr. of hidden items under RowIndex
  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx < FromRow then
      inc(l);

    if (FGriditems.Items[j - 1] as TGridItem).Idx < FromRow then Dec(k);

    // Detect if already hidden
    if ((FGriditems.Items[j - 1] as TGridItem).Idx >= FromRow) and
       ((FGriditems.Items[j - 1] as TGridItem).Idx <= ToRow) then
    begin
      inc(c);
      rlist.Add((FGriditems.Items[j - 1] as TGridItem).Idx);
    end;

    //if (FGriditems.Items[j - 1] as TGridItem).Idx = FromRow then Exit;
  end;

  if c = ToRow - FromRow + 1 then
  begin
    rlist.Free;
    Exit;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  for j := FromRow to ToRow do
  begin
    if rlist.IndexOf(Pointer(j)) = -1 then
    begin
      with (FGridItems.Insert(l) as TGridItem) do
      begin
        Items.Assign(Rows[ k + j - FromRow]);
        Idx := FromRow + (j - FromRow);
        Height := RowHeights[k + j - FromRow];
      end;
      inc(l);
    end;
  end;

  if Assigned(CellControls[1,k]) then
    CellControls[1,k].Visible := False;

  IRemoveRows(k,ToRow - FromRow + 1 - c,false);

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  rlist.Free;

  CellControlsUpdate;
end;


procedure TAdvStringGrid.HideRowList(RowList: TIntList);
var
  i,j,k,r: integer;
  il: TIntList;
begin
  il := TIntList.Create(-1,-1);

  // save row heights
  for i := 1 to RowCount do
    il.Add(RowHeights[i - 1]);

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  // put rows in FGridItems
  for i := 1 to RowList.Count do
  begin
    r := RowList.Items[i - 1];
    with (FGridItems.Add as TGridItem) do
    begin
      Items.Assign(Rows[r]);
      Idx := r;
      Height := RowHeights[r];
      Level := FFilterLevel;
    end;
  end;

  inc(FFilterLevel);

  j := 0;
  k := 0;
  for i := 0 to RowCount - 1 do
  begin
    // found a row to hide
    if (k < RowList.Count) and (i = RowList.Items[k]) then
    begin
      inc(k);
    end
    else
    begin
      if (i <> j) then
      begin
        Rows[j].Assign(Rows[i]);
        RowHeights[j] := il.Items[i];
      end;
      inc(j);
    end;

  end;

  RowCount := RowCount - RowList.Count;

  il.Free;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  CellControlsUpdate;
end;

procedure TAdvStringGrid.HideRowsEx(FromRow,ToRow: Integer);
var
  j,k: Integer;
begin
  k := FromRow;

  //count nr. of hidden items under RowIndex
  for j := 1 to FGriditems.Count do
  begin
    if (FGridItems.Items[j - 1] as TGridItem).Idx < FromRow then Dec(k);
    // Exit if already hidden
    if (FGridItems.Items[j - 1] as TGridItem).Idx = FromRow then Exit;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  for j := FromRow to ToRow do
  begin
    with (FGriditems.Add as TGridItem) do
    begin
      Items.Assign(Rows[k + j - FromRow]);
      Idx := FromRow + (j - FromRow);
    end;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  RemoveRowsEx(k,ToRow - FromRow + 1);

  CellControlsUpdate;
end;

procedure TAdvStringGrid.UnHideRowsAll;
var
  hs,he,i,j: Integer;
begin
  i := 0;
  j := 0;
  hs := -1;
  he := -1;
  while (FGridItems.Count > 0) and (i <= FGridItems.Count - 1) do
  begin
    if (hs = -1) then
    begin
      hs := (FGriditems.Items[i] as TGridItem).Idx;
      he := hs;
      j := i;
    end;

    if (i < FGridItems.Count - 1) and
       ((FGriditems.Items[i] as TGridItem).Idx+1 = (FGriditems.Items[i+1] as TGridItem).Idx) then
    begin
      Inc(i);
      Inc(he);
    end
    else
    begin
      UnHideRows(hs,he);
      i := j;
      hs := -1;
    end;
  end;

  if hs <> -1 then
    UnHideRows(hs,he);
end;

procedure TAdvStringGrid.UnHideRowList;
var
  hs,i,j,k,l,m: Integer;
begin
  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  k := FGridItems.Count - 1;

  l := 1;
  if FloatingFooter.Visible then
    l := 2;

  j := RowCount - l;

  m := 0;
  for i := 0 to FGridItems.Count - 1 do
  begin
    if (FGridItems.Items[i] as TGridItem).Level = FFilterLevel - 1 then
     inc(m);
  end;

  // prevent invalid cell access when HideSelection was done
  if Row >= RowCount then
    FocusCell(FixedCols, FixedRows);

  RowCount := RowCount + m;

  for i := RowCount - l downto 0 do
  begin
    while (k >= 0) and ((FGridItems.Items[k] as TGridItem).Level < FFilterLevel - 1) do
      dec(k);

    if (k >= 0) then
      hs := (FGriditems.Items[k] as TGridItem).Idx
    else
      hs := -1;

    if (hs = i) and (k >= 0) then
    begin
      Rows[i].Assign((FGriditems.Items[k] as TGridItem).Items);
      RowHeights[i] := (FGriditems.Items[k] as TGridItem).Height;
      dec(k);
    end
    else
    begin
      if (i > j) and (j >= 0) then
      begin
        Rows[i].Assign(Rows[j]);
        RowHeights[i] := RowHeights[j];
        dec(j);
      end;
    end;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  if FFilterLevel > 1 then
  begin
    for i := FGridItems.Count - 1 downto 0 do
    begin
      if (FGridItems.Items[i] as TGridItem).Level = FFilterLevel - 1 then
       FGridItems.Items[i].Free;
    end;
  end
  else
    FGridItems.Clear;

  DestroyHiddenRowLookup;

  CellControlsUpdate;
end;


procedure TAdvStringGrid.UnHideRow(Rowindex: Integer);
var
  j,k,l: Integer;
  flg: Boolean;
  ci: TControlItem;
  shm: boolean;
begin
  k := RowIndex;
  Flg := False;
  l := 0;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  shm := ShowModified.Enabled;
  ShowModified.FEnabled := false;

  // count nr. of hidden items under Rowindex
  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j-1] as TGridItem).Idx < RowIndex then Dec(k);
    if (FGriditems.Items[j-1] as TGridItem).Idx = RowIndex then
    begin
      Flg := True;
      l := j-1;
    end;
  end;

  if Flg then
  begin
    InsertRowsEx(k,1,false);

    with (FGriditems.Items[l] as TGridItem) do
    begin
      Rows[k].Assign(Items);
      RowHeights[k] := Height;
    end;

    (FGriditems.Items[l] as TGridItem).Free;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  for j := 1 to FControlList.Count do
  begin
    ci := FControlList.Control[j - 1];
    if (ci.Y = RowIndex) then
      ci.Control.Visible := true;
  end;

  ShowModified.FEnabled := shm;

  CellControlsUpdate;
end;

procedure TAdvStringGrid.UnHideRows(FromRow,ToRow: Integer);
var
  i,j,k,l: Integer;
  Flg: Boolean;
  Num: Integer;
  r: TRect;
  lh: TIntList;
  shm: boolean;
  bCCUCall: boolean;

begin
  k := FromRow;
  Flg := False;
  bCCUCall := ccuCall;
  ccuCall := False;

  DestroyHiddenRowLookup;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  shm := ShowModified.Enabled;
  ShowModified.FEnabled := false;

  // count nr. of hidden items under Rowindex
  for j := 1 to FGridItems.Count do
  begin
    if (FGriditems.Items[j-1] as TGridItem).Idx < FromRow then
      Dec(k);
    if (FGriditems.Items[j-1] as TGridItem).Idx = FromRow then
      Flg := True;
  end;

  if Flg then
  begin
    (*
    Num := ToRow - FromRow + 1;

    for j := FromRow to ToRow do
      if not IsHiddenRow(j) then Dec(Num);
    *)
    if (NumHiddenRows = 0) then
    begin
      Num := 0;
    end
    else
    begin
      Num := ToRow - FromRow + 1;
      lh := nil;
      try
        for j := FromRow to ToRow do
          if not IsHiddenRow(j, lh) then Dec(Num);
      finally
        if (lh <> nil) then FreeAndNil (lh);
      end;
    end;

    if Num > 0 then
    begin
      InsertRowsEx(k,num,false);

      i := 0;
      while (i < FGridItems.Count) and (FGridItems.Count > 0) do
      begin
        l := (FGridItems.Items[i] as TGridItem).Idx;
        if (l >= FromRow) and (l <= ToRow) then
        begin
          Rows[k + l - FromRow].Assign((FGridItems.Items[i] as TGridItem).Items);
          RowHeights[k + l - FromRow] := (FGridItems.Items[i] as TGridItem).Height;
          (FGridItems.Items[i] as TGridItem).Free;

          if Assigned(CellControls[1,k + l - FromRow]) and (l = FromRow) then
          begin
            r := CellRect(1,k + l - FromRow);
            CellControls[1,k + l - FromRow].SetBounds(r.Left,r.Top,r.Right - r.Left,r.Bottom - r.Top - 1);
            CellControls[1,k + l - FromRow].Visible := True;
          end;
        end
        else Inc(i);
      end;
    end;
  end;

  ShowModified.FEnabled := shm;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  ccuCall := bCCUCall;
  CellControlsUpdate;
end;


function TAdvStringGrid.IsHiddenRow(Rowindex: Integer): Boolean;
var
  j: Integer;
begin
  Result := False;

  if FGriditems.Count = 0 then
    Exit;

  // search in hidden rows
  for j := 1 to FGridItems.Count do
  begin
    if (FGridItems.Items[j - 1] as TGridItem).Idx = RowIndex then
    begin
      Result := True;
      Break;
    end;
  end;
end;


function TAdvStringGrid.IsHiddenRow(Rowindex: Integer; var ListHidden: TIntList): Boolean;
var
  j, iCount: Integer;
begin
  // During the first call the list will be filled with Idx from FGridItems
  if (ListHidden = nil) then
  begin
    ListHidden := TIntList.Create(-1, -1);
    iCount := FGriditems.Count;
    for j := 1 to iCount do
      ListHidden.Insert((FGridItems.Items[j-1] as TGridItem).Idx);
  end;
  Result := ListHidden.SortedIndexOf(Rowindex) <> -1;
end;


function TAdvStringGrid.NumHiddenRows: Integer;
begin
  Result := FGridItems.Count;
end;

function TAdvStringGrid.TotalRowCount: Integer;
begin
  Result := RowCount + FGridItems.Count;
end;

function TAdvStringGrid.GetRealCol: Integer;
begin
  Result := RemapCol(Col);
end;

function TAdvStringGrid.GetTopRowEx;
begin
  Result := inherited TopRow;
end;

procedure TAdvStringGrid.SetTopRowEx(const value: integer);
begin
  if (Value < FixedRows) or (Value > RowCount - 1)  then
    Exit;
  inherited TopRow := Value;
end;

function TAdvStringGrid.GetRowEx: Integer;
begin
  Result := inherited Row;
end;

procedure TAdvStringGrid.SetRowEx(const Value: Integer);
begin
  if (Col >= ColCount) or (Col < 0) then
  begin
    FocusCell(FixedCols,Value);
    //GotoCellInt(FixedCols, Value);
  end;

  inherited Row := Value;

  FAECol := -1;
  FAERow := -1;

  if (FOldRowSel <> Row) and Assigned(FOnRowChanged) {and (FUpdateCount = 0)} then
  begin
    FOnRowChanged(Self,FOldRowSel,Row);
    FOldRowSel := Row;
  end;

  if (MouseActions.DisjunctRowSelect) then
  begin
    //if FRowIndicator.Empty then
    // ClearRowSelectInt;
    SelectToRowSelect(false);
  end;

  if Assigned(SyncGrid.Grid) then
  begin
    if SyncGrid.SelectionRow then
      SyncGrid.Grid.Row := inherited Row;
  end;

  if (Value = RowCount - 1) and (SearchFooter.Visible) then
    ScrollToLastRow;

  FDisSelection := Selection;
end;

function TAdvStringGrid.GetRealRow: Integer;
begin
  Result := RemapRowInv(Row);
end;

function TAdvStringGrid.RealRowIndex(ARow: Integer): Integer;
begin
  Result := RemapRowInv(ARow);
end;

function TAdvStringGrid.RealColIndex(ACol: Integer): Integer;
begin
  Result := RemapCol(ACol);
end;

function TAdvStringGrid.DisplRowIndex(ARow: Integer): Integer;
begin
  Result := RemapRow(ARow);
end;

function TAdvStringGrid.DisplColIndex(ACol: Integer): Integer;
begin
  Result := RemapColinv(ACol);
end;

function TAdvStringGrid.IsIgnoredColumn(ACol: Integer): boolean;
begin
  Result := FIgnoreColumns.HasValue(ACol);
end;

procedure TAdvStringGrid.SetVisibleCol(i: Integer;aValue: Boolean);
begin
  if (i >= 0) and (i <= High(FVisibleCol)) then
    FVisibleCol[i] := AValue;
end;

function TAdvStringGrid.GetVisibleCol(i: Integer): Boolean;
begin
  if (i >= 0) and (i <= High(FVisibleCol)) then
    Result := FVisibleCol[i]
  else
    Result := true;
end;

function TAdvStringGrid.RemapColInv(ACol: Integer): Integer;
var
  i: Integer;
  RemapValue: Integer;
begin
  if (ACol >= AllColCount) or (FNumHidden = 0) then
  begin
    Result := ACol;
    Exit;
  end;

  RemapValue := ACol;
  for i := 0 to ACol - 1 do
  begin
    if not FVisibleCol[i] then Dec(RemapValue);
  end;
  Result := RemapValue;
end;

function TAdvStringGrid.RemapCol(ACol: Integer): Integer;
var
  i: Integer;
  RemapValue: Integer;
begin
  if (ACol >= AllColCount) or (FNumHidden = 0) then
  begin
    RemapCol := ACol;
    Exit;
  end;

  RemapValue := 0;
  RemapCol := ACol;
  i := 0;

  while i < AllColCount do
  begin
    if (RemapValue = ACol) and FVisibleCol[i] then
    begin
      RemapCol := i;
      Exit;
    end;
   if FVisibleCol[i] then
     Inc(RemapValue);
   Inc(i);
  end;
end;

function TAdvStringGrid.GetUsedCells: TGridRect;
var
  i,j,minx,miny,maxx,maxy: integer;

begin
  minx := ColCount - 1;
  miny := RowCount - 1;
  maxx := 0;
  maxy := 0;

  for i := 0 to ColCount - 1 do
  begin
    for j := 0 to RowCount - 1 do
    begin
      if Cells[i,j] <> '' then
      begin
        if i < minx then
          minx := i;
        if j < miny then
          miny := j;
        if i  > maxx then
          maxx := i;
        if j > maxy then
          maxy := j;
       end;
    end;
  end;

  if (minx <= maxx) and (miny <= maxy) then
  begin
    Result := TGridRect(Rect(minx,miny,maxx,maxy));
  end
  else
    Result := TGridRect(Rect(0,0,0,0));
end;

function TAdvStringGrid.GetSaveStartCol: Integer;
begin
  if FSaveFixedCells or FSaveFixedCols then
    Result := 0
  else
    Result := FixedCols;
end;

function TAdvStringGrid.GetSaveStartRow: Integer;
begin
  if FSaveFixedCells or FSaveFixedRows then
    Result := 0
  else
    Result := FixedRows;
end;

function TAdvStringGrid.GetSaveEndCol: Integer;
begin
  if FSaveFixedCells or FSaveFixedCols then
    Result := ColCount - 1
  else
    Result := ColCount - FFixedRightCols - 1;
end;

function TAdvStringGrid.GetSaveEndRow: Integer;
begin
  if FSaveFixedCells or FSaveFixedRows then
    Result := RowCount - 1
  else
    Result := RowCount - FFixedFooters - 1;
end;

function TAdvStringGrid.GetSaveColCount: Integer;
begin
  if FSaveFixedCells or FSaveFixedCols then
    Result := ColCount
  else
    Result := ColCount - FixedCols - FFixedRightCols;
end;

function TAdvStringGrid.GetSaveRowCount: Integer;
begin
  if FSaveFixedCells or FSaveFixedRows then
    Result := RowCount
  else
    Result := RowCount - FixedRows - FFixedFooters;
end;

procedure TAdvStringGrid.ScreenToCell(pt:TPoint; var ACol,ARow: Integer);
begin
  pt := ScreenToClient(pt);
  MouseToCell(pt.x,pt.y,ACol,ARow);
end;

function TAdvStringGrid.InSizeZone(x,y: Integer): Boolean;
var
  c,r: Longint;
  cr: TRect;
begin
  Result := False;
  MouseToCell(x,y,c,r);
  if (c < 0) or (r < 0) then
    Exit;

  cr := CellRect(c,r);
  if (r <= FixedRows) and (goColSizing in Options) then
    Result := (Abs(x - cr.Left) < 4) or (Abs(x - cr.Right) < 4);

  if (c <= FixedCols) and (goRowSizing in Options) then
    Result := (Abs(y - cr.Top) < 4) or (Abs(y - cr.Bottom) < 4);
end;

procedure TAdvStringGrid.UpdateType;
begin
  case FScrollType of
  ssNormal:FlatSetScrollProp(WSB_PROP_VSTYLE,FSB_REGULAR_MODE,True);
  ssFlat:FlatSetScrollProp(WSB_PROP_VSTYLE,FSB_FLAT_MODE,True);
  ssEncarta:FlatSetScrollProp(WSB_PROP_VSTYLE,FSB_ENCARTA_MODE,True);
  end;
  case FScrollType of
  ssNormal:FlatSetScrollProp(WSB_PROP_HSTYLE,FSB_REGULAR_MODE,True);
  ssFlat:FlatSetScrollProp(WSB_PROP_HSTYLE,FSB_FLAT_MODE,True);
  ssEncarta:FlatSetScrollProp(WSB_PROP_HSTYLE,FSB_ENCARTA_MODE,True);
  end;
end;

procedure TAdvStringGrid.UpdateColor;
begin
  if FScrollColor = clNone then Exit;
  FlatSetScrollProp(WSB_PROP_VBKGCOLOR,Integer(FScrollColor),True);
  FlatSetScrollProp(WSB_PROP_HBKGCOLOR,Integer(FScrollColor),True);
end;

procedure TAdvStringGrid.UpdateWidth;
begin
  FlatSetScrollProp(WSB_PROP_CXVSCROLL,FScrollWidth,True);
  FlatSetScrollProp(WSB_PROP_CYHSCROLL,FScrollWidth,True);
end;

procedure TAdvStringGrid.UpdateFooter;
begin
  FFooterPanel.Invalidate;
end;

procedure TAdvStringGrid.CalcFooter(ACol: Integer = -1);
begin
  DoCalcFooter(ACol);
end;

procedure TAdvStringGrid.DoF2Edit;
begin
end;

procedure TAdvStringGrid.DoCalcFooter(ACol: Integer);
var
  ct: TColumnCalcType;
  co,ce,c: Integer;
  s: string;
  nh: Integer;
begin
  if FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) and FloatingFooter.EnableCalculation then
  begin
    if ACol = -1 then
    begin
      co := 0;
      ce := AllColCount - 1;
    end
    else
    begin
      co := ACol;
      ce := ACol;
    end;

    for c := co to ce do
      if HasCellProperties(c,RowCount - 1) then
      begin
        if FloatingFooter.CalculateHiddenRows then
          nh := NumHiddenRows
        else
          nh := 0;

        ct := CellProperties[c,RowCount - 1].CalcType;

        if ct <> acNONE then
        begin
          case ct of
          acSUM: Floats[c,RowCount - 1] := ColumnSum(c,FixedRows,RowCount - 2 + nh);
          acCOUNT: Ints[c,RowCount - 1] := RowCount - 1 - FixedRows + nh;
          acAVG: Floats[c,RowCount - 1] := ColumnAvg(c,FixedRows,RowCount - 2 + nh);
          acMIN: Floats[c,RowCount - 1] := ColumnMin(c,FixedRows,RowCount - 2 + nh);
          acMAX: Floats[c,RowCount - 1] := ColumnMax(c,FixedRows,RowCount - 2 + nh);
          acDISTINCT: Floats[c,RowCount - 1] := ColumnDistinct(c,FixedRows,RowCount - 2 + nh);
          acSTDDEV: Floats[c,RowCount - 1] := ColumnStdDev(c,FixedRows,RowCount - 2 + nh);
          acCUSTOM:
            begin
              if Assigned(FOnCalcFooter) then
              begin
                s := '';
                FOnCalcFooter(self,c,RowCount - 1 + nh,s);
                Cells[c,RowCount - 1] := s;
              end
              else
                if (Assigned(FloatingFooter.FOnCalcFooter)) then
                begin
                  s := '';
                  FloatingFooter.FOnCalcFooter(self,c,RowCount - 1 + nh,s);
                  Cells[c,RowCount - 1] := s;
                end
                else
                  Cells[c,RowCount - 1] := '';
            end;
          end;
        end;
        //else
        //  Cells[c,RowCount - 1] := '';
      end;
  end;
end;


procedure TAdvStringGrid.FloatFooterUpdate;
begin
  inherited;
  UpdateFooter;
end;

procedure TAdvStringGrid.SetShowDesignHelper(const Value: Boolean);
begin
  if (FShowDesignHelper <> Value) then
  begin
    FShowDesignHelper := Value;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetShowModified(const Value: TShowModified);
begin
  FShowModified.Assign(Value);
end;

procedure TAdvStringGrid.SetBalloonSettings(const Value: TBalloonSettings);
begin
  FBalloonSettings.Assign(Value);
end;

procedure TAdvStringGrid.SetScrollBarAlways(const Value: TScrollBarAlways);
begin
  FScrollBarAlways := Value;
  UpdateScrollBars(true);
end;

function TAdvStringGrid.GetSelectionEx: TGridRect;
begin
  Result := inherited Selection;
end;

procedure TAdvStringGrid.SetProgressAppearance(const Value: TGridProgressAppearance);
begin
  FProgressAppearance.Assign(Value);
end;

procedure TAdvStringGrid.SetSelectionEx(const Value: TGridRect);
begin
  inherited Selection := Value;
  if ActiveCellShow then
  begin
    InvalidateRow(0);
    InvalidateCol(0);
  end;
  if ActiveRowShow then
  begin
    RepaintRow(Value.Bottom);
  end;
end;

procedure TAdvStringGrid.DoAppendRow;
begin
  RowCount := RowCount + 1;
end;

procedure TAdvStringGrid.UpdateVScrollBar;
var
  Scrollinfo: TScrollInfo;
begin
  if not (ScrollBars in [ssBoth,ssVertical]) or not FIsFlat then
    Exit;

  ScrollInfo.FMask := SIF_ALL;
  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  GetScrollInfo(Handle,SB_VERT,ScrollInfo);

  FlatSetScrollInfo(SB_VERT,scrollinfo,True);
end;

procedure TAdvStringGrid.UpdateHScrollBar;
var
  ScrollInfo: TScrollinfo;
begin
  if not (ScrollBars in [ssBoth,ssHorizontal]) or not FIsFlat then
    Exit;

  ScrollInfo.fMask := SIF_ALL;
  ScrollInfo.cbSize := SizeOf(ScrollInfo);

  GetScrollInfo(Handle,SB_HORZ,ScrollInfo);
  FlatSetScrollInfo(SB_HORZ,ScrollInfo,True)
end;

procedure TAdvStringGrid.FlatSetScrollInfo(code: Integer;var Scrollinfo:TScrollInfo;FRedraw: bool);
var
  ComCtl32DLL: THandle;
  _FlatSB_SetScrollInfo:function(wnd:hwnd;code: Integer;var Scrollinfo:TScrollInfo;FRedraw: bool): Integer; stdcall;

begin
  ComCtl32DLL := GetModuleHandle(comctrl);
  if ComCtl32DLL > 0 then
  begin
    @_FlatSB_SetScrollInfo := GetProcAddress(ComCtl32DLL,'FlatSB_SetScrollInfo');
    if Assigned(_FlatSB_SetScrollInfo) then
    begin
      _FlatSB_SetScrollInfo(self.Handle,code,scrollinfo,fRedraw);
    end;
  end;
end;


procedure TAdvStringGrid.FlatSetScrollProp(index, newValue: Integer;
  FRedraw: bool);
var
  ComCtl32DLL: THandle;
  _FlatSB_SetScrollProp:function(wnd:hwnd;Index,newValue: Integer;fredraw:bool):bool stdcall;

begin
  if not FIsFlat then
    Exit;
  ComCtl32DLL := GetModuleHandle(comctrl);
  if ComCtl32DLL > 0 then
  begin
    @_FlatSB_SetScrollProp:=GetProcAddress(ComCtl32DLL,'FlatSB_SetScrollProp');
    if Assigned(_FlatSB_SetScrollProp) then
      _FlatSB_SetScrollProp(Handle,index,newValue,fRedraw);
  end;
end;


procedure TAdvStringGrid.FlatShowScrollBar(code: Integer;show:bool);
var
  ComCtl32DLL: THandle;
  _FlatSB_ShowScrollBar:function(wnd:hwnd;code: Integer;show:bool): Integer; stdcall;

begin
  if not FIsFlat then
    Exit;

  case code of
  SB_VERT:if not (ScrollBars in [ssBoth,ssVertical]) then Exit;
  SB_HORZ:if not (ScrollBars in [ssBoth,ssHorizontal]) then Exit;
  end;

  ComCtl32DLL := GetModuleHandle(comctrl);
  if ComCtl32DLL > 0 then
  begin
    @_FlatSB_ShowScrollBar:=GetProcAddress(ComCtl32DLL,'FlatSB_ShowScrollBar');
    if Assigned(_FlatSB_ShowScrollBar) then
      _FlatSB_ShowScrollBar(self.Handle,code,show);
  end;
end;

procedure TAdvStringGrid.FlatUpdate;
begin
  UpdateType;
  UpdateColor;
  UpdateWidth;
  if VisibleRowCount + FixedRows < RowCount then
  begin
    FlatShowScrollBar(SB_VERT,True);
    UpdateVScrollBar;
  end
  else
    FlatShowScrollBar(SB_VERT,False);

  if VisibleColCount + FixedCols < ColCount then
  begin
    FlatShowScrollBar(SB_HORZ,True);
    UpdateHScrollBar;
  end
  else
    FlatShowScrollBar(SB_HORZ,False);
end;

procedure TAdvStringGrid.FlatInit;
var
  ComCtl32DLL: THandle;
  _InitializeFlatSB: function(wnd:hwnd):Bool stdcall;
begin
  ComCtl32DLL := GetModuleHandle(comctrl);
  if ComCtl32DLL > 0 then
  begin
    @_InitializeFlatSB := GetProcAddress(ComCtl32DLL,'InitializeFlatSB');
    if Assigned(_InitializeFlatSB) then
      _InitializeFlatSB(self.Handle);
    FIsFlat := Assigned(_InitializeFlatSB);
  end;
end;


procedure TAdvStringGrid.FlatDone;
var
  ComCtl32DLL: THandle;
  _UninitializeFlatSB: function(wnd:hwnd):Bool stdcall;
begin
  FisFlat := False;
  ComCtl32DLL := GetModuleHandle(comctrl);
  if ComCtl32DLL > 0 then
  begin
    @_UninitializeFlatSB := GetProcAddress(ComCtl32DLL,'UninitializeFlatSB');
    if Assigned(_UninitializeFlatSB) then
      _UninitializeFlatSB(self.Handle);
  end;
end;

function TAdvStringGrid.GetRowIndicator: TBitmap;
begin
  Result := FRowIndicator;
end;

procedure TAdvStringGrid.SetRowIndicator(Value: TBitmap);
begin
  FRowIndicator.Assign(Value);
  RepaintCell(0,Row);
end;

procedure TAdvStringGrid.SetBackground(Value: TBackground);
begin
  FBackground.Assign(Value);
  Invalidate;
end;

procedure TAdvStringGrid.SetHighlightColor(const Value: TColor);
begin
  if (FHighlightColor <> Value) then
  begin
    FHighlightColor := Value;
    SetHighlightColors(FHighLightColor, FHighLightTextColor);
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetHighlightTextColor(const Value: TColor);
begin
  if (FHighlightTextColor <> Value) then
  begin
    FHighlightTextColor := Value;
    SetHighlightColors(FHighLightColor, FHighLightTextColor);
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetHoverButtons(const Value: THoverButtons);
begin
  FHoverButtons.Assign(Value);
end;

procedure TAdvStringGrid.SetHovering(Value: Boolean);
begin
  if Value <> FHovering then
  begin
    FHovering := Value;
  end;
end;

procedure TAdvStringGrid.SetHTMLKeepLineBreak(const Value: Boolean);
begin
  FHTMLKeepLineBreak := Value;
  ASG_KEEP_LINEBREAKS := Value;
end;

procedure TAdvStringGrid.SetAutoThemeAdapt(const Value: Boolean);
begin
  if (Value <> FAutoThemeAdapt) then
  begin
    FAutoThemeAdapt := Value;
    SearchFooter.AutoThemeAdapt := Value;
    if FAutoThemeAdapt then
    begin
      ThemeAdapt;
      Invalidate;
    end;

    if not (csDesigning in ComponentState) and
       HandleAllocated and not (csLoading in ComponentState) and not IsLibrary then
    begin
      if FAutoThemeAdapt then
        ThemeNotifier(Self).RegisterWindow(Handle)
      else
        ThemeNotifier(Self).UnRegisterWindow(Handle)
    end;
  end;
end;

procedure TAdvStringGrid.SetActiveCellShow(const Value: Boolean);
begin
  FActiveCellShow := Value;
  Invalidate;
end;

procedure TAdvStringGrid.SetActiveCellColor(const Value: TColor);
begin
  FActiveCellColor := Value;
  Invalidate;
end;

procedure TAdvStringGrid.SetActiveCellColorTo(const Value: TColor);
begin
  FActiveCellColorTo := Value;
  Invalidate;
end;


procedure TAdvStringGrid.SetActiveCellFont(const Value: TFont);
begin
  FActiveCellFont.Assign(Value);
  Invalidate;
end;

procedure TAdvStringGrid.UpdateXYOffset(X,Y: integer);
begin
  FXYOffset := Point(X,Y);
end;

function TAdvStringGrid.UseVCLStyles: boolean;
begin
  Result := FUseVCLStyles;
end;

procedure TAdvStringGrid.SetXYOffset(const Value: TPoint);
begin
  FXYOffset := Value;
  Invalidate;
end;

procedure TAdvStringGrid.SetScrollBarsEx(const Value: TScrollStyle);
begin
  FScrollBars := Value;
  inherited ScrollBars := Value;
end;

function TAdvStringGrid.GetScrollBarsEx: TScrollStyle;
begin
  Result := FScrollBars;
end;

procedure TAdvStringGrid.SetScrollType(const Value: TScrollType);
begin
  if (FScrollType <> Value) then
  begin
    FScrollType := Value;

    if FScrollType in [ssFlat,ssEncarta] then
    begin
      FlatInit;
      FlatUpdate;
    end
    else
    begin
      FlatDone;
    end;

    if HandleAllocated and (FScrollType = ssMetro) then
    begin
      CreateMetroScrollers;
      Scrollbars := ssNone;
    end;

    if HandleAllocated and (FScrollType <> ssMetro) and (Assigned(vscrlctrl) or Assigned(hscrlctrl)) then
    begin
      DestroyMetroScrollers;
      Scrollbars := ssBoth;
    end;

  end;
  UpdateType;
end;

procedure TAdvStringGrid.SetScrollColor(const Value: TColor);
begin
  FScrollColor := Value;
  UpdateColor;
end;

procedure TAdvStringGrid.SetScrollWidth(const Value: Integer);
begin
  FScrollWidth := Value;
  UpdateWidth;
end;

procedure TAdvStringGrid.SetScrollProportional(Value: Boolean);
var
  ScrollInfo: TScrollinfo;
begin
  FScrollProportional := Value;

  if Value then
  begin
    UpdateVScroller;
    UpdateHScroller;
  end
  else
    if FIsflat and (FScrollType = ssNormal) then
    begin
      FlatDone;
      ScrollInfo.cbSize := SizeOf(ScrollInfo);
      ScrollInfo.FMask := SIF_PAGE;
      ScrollInfo.nPage := 0;
      SetScrollInfo(Handle,SB_HORZ,ScrollInfo,True);
      ScrollInfo.cbSize := SizeOf(ScrollInfo);
      ScrollInfo.FMask := SIF_PAGE;
      ScrollInfo.nPage := 0;
      SetScrollInfo(Handle,SB_VERT,ScrollInfo,True);
    end;
end;

procedure TAdvStringGrid.WMGetDlgCode(var Msg: TWMNoParams);
begin
  inherited;

  if Navigation.AutoGotoWhenSorted then
    Msg.Result := Msg.Result or DLGC_WANTCHARS;

  if not (goEditing in Options) then
    Msg.Result := Msg.Result or DLGC_WANTCHARS;

  if (goTabs in Options) and (GetKeystate(VK_CONTROL) and $8000 <> $0) then
    Msg.Result := Msg.Result and not DLGC_WANTTAB;
end;

procedure TAdvStringGrid.WMHScroll(var WMScroll: TWMScroll);
var
  page: Integer;
  r:TRect;
  s:string;
  pt:TPoint;
  nr,nl: Integer;
  fcr,tcr:TRect;

begin
  if (FScrollHints in [shHorizontal,shBoth]) and Assigned(FScrollHintWnd) then
  begin
    if (wmScroll.ScrollCode = SB_ENDSCROLL) then
    begin
      FScrollHintWnd.ReleaseHandle;
      FScrollHintShow := False;
    end;

    if (wmScroll.ScrollCode = SB_THUMBTRACK) then
    begin
      nr := FixedCols + longmuldiv(wmScroll.pos,ColCount - VisibleColCount - FixedCols,MaxShortInt);
      s := 'Col : '+inttostr(nr);
      if Assigned(OnScrollHint) then
        OnScrollHint(self,nr,s);

      r := FScrollHintWnd.CalcHinTRect(100,s,Nil);
      FScrollHintWnd.Caption := s;
      FScrollHintWnd.Color := FHintColor;

      GetCursorPos(pt);
      r.Left := r.Left + pt.x + 10;
      r.Right := r.Right + pt.x + 10;
      r.Top := r.Top + pt.y;
      r.Bottom := r.Bottom + pt.y;

      FScrollHintWnd.ActivateHint(r,s);
      FScrollHintShow := True;
    end;
  end;

  if (Navigation.AlwaysEdit)  then
  begin
    if EditMode then
      HideInplaceEdit;
  end;

  if (wmScroll.ScrollCode = SB_THUMBPOSITION) and (FIsFlat) then
  begin
    Page := Round(128 * VisibleColCount/ColCount);
    if (Page <> 128) then
      wmScroll.Pos := Round(127*wmScroll.pos/(128 - Page));
  end;

  nl := FixedCols + longmuldiv(wmScroll.pos,ColCount-VisibleColCount - FixedCols,MaxShortInt);

  if (wmScroll.ScrollCode = SB_THUMBTRACK) and (FScrollSynch) then
  begin
    LeftCol := nl;
  end;

  // get previous background rectangle

  with FBackground do
  if not Bitmap.Empty and (Display = bdFixed) then
  begin
    MouseToCell(Left,Top,longint(fcr.Left),longint(fcr.Top));
    MouseToCell(Left + Bitmap.Width,Top + Bitmap.Height,longint(fcr.Right),longint(fcr.Bottom));
  end;

  if (FixedCols = 0) and (Col <= nl) then
  begin
    HideInplaceEdit;
  end;

  inherited;

  // get new background rectangle & repaint
  with FBackground do
  if not Bitmap.Empty and (Display = bdFixed) then
  begin
    MouseToCell(Left,Top,longint(tcr.Left),longint(tcr.Top));
    MouseToCell(Left + Bitmap.Width,top + Bitmap.Height,longint(tcr.Right),longint(tcr.Bottom));
    if (wmScroll.ScrollCode <> SB_THUMBTRACK) and not EqualRect(fcr,tcr) then
    begin
      RepaintRect(fcr);
      RepaintRect(tcr);
    end;
  end;

  if (BidiMode = bdRightToLeft) and (wmScroll.ScrollCode = SB_ENDSCROLL) and (FMergeCount > 0) then
  begin
    Invalidate;
  end;

  if (wmScroll.ScrollCode = SB_ENDSCROLL) and (ColCount = 1) then
    Repaint;

  UpdateHScrollBar;
  UpdateVScrollBar;

  if HasCheckBox(Col,Row) then
    HideEditor;

  UpdateFooter;
end;

procedure TAdvStringGrid.UpdateHScroller;
var
  R,GLW,RH: Integer;
//  TCW: Integer;
  TotalFixedWidth: Integer;
  TotalScrollableWidth: Integer;
  TotalHiddenWidth: Integer;
  ViewRatio: Single;
  IdealNMax: Single;
  IdealNPos: Single;
  ScrollInfo: TScrollInfo;
  GW: integer;
begin
  if HandleAllocated and Assigned(FSearchPanel) and FSearchPanel.Visible then
  begin
    // force control realign to workaround VCL alignment issue
    FSearchPanel.Top := ClientHeight - 32;
  end;

  if (csLoading in ComponentState) or
     (csDesigning in ComponentState) then
    Exit;

  if not (ScrollBars in [ssBoth, ssHorizontal]) then
    Exit;

  if not ScrollProportional or (ScrollType = ssMetro) then
    Exit;

  if FScrollLock then
    Exit;

  // Get current scroll information
  FillChar(ScrollInfo,SizeOf(ScrollInfo),0);
  ScrollInfo.cbSize := SizeOf(ScrollInfo);

  ScrollInfo.FMask := SIF_ALL;
  GetScrollInfo(Handle,SB_HORZ,ScrollInfo);

  // Calculate proper scrolling region ratio
  GLW := GridLineWidth;

  if VisibleRowCount + FixedRows < RowCount then
    GW := Width - GetSystemMetrics(SM_CXVSCROLL)
  else
    GW := Width;

  TotalFixedWidth := GLW;
  for R := 0 to FixedCols - 1 do
  begin
    Inc(TotalFixedWidth,ColWidths[R] + GLW);
  end;

  TotalScrollableWidth := GLW;
  TotalHiddenWidth := GLW;
  for R := FixedCols to ColCount - 1 do
  begin
    RH := ColWidths[R];
    if R < LeftCol then
      Inc(TotalHiddenWidth,RH + GLW);
    Inc(TotalScrollableWidth,RH + GLW);
  end;

//  TCW := 0;
//  for R := 0 to ColCount - 1 do
//    TCW := TCW + ColWidths[R];

  ViewRatio := (GW - TotalFixedWidth)/TotalScrollableWidth;

  if (ViewRatio >= 0.99999) then
    Exit;

  IdealNMax := (127 + ViewRatio) / (1 - ViewRatio);

  if (TotalScrollableWidth > GW) then
    IdealNPos := TotalHiddenWidth / (TotalScrollableWidth - GW) * 128
  else
    IdealNPos := ScrollInfo.nPos;

  // Set scroll information
  if TotalScrollableWidth + TotalFixedWidth - GW < 0 then
    Exit;

  ScrollInfo.nMax := Trunc(IdealNMax);
  ScrollInfo.nPage := ScrollInfo.nMax - 127 + 1;
  ScrollInfo.nPos := Trunc(IdealNPos);

  if ScrollInfo.nPage < 4000 then
    SetScrollInfo(Handle, SB_HORZ, ScrollInfo, TRUE);

  UpdateHScrollBar;

  // total column width smaller than grid width or no horiz. scrollbar selected, hide the scrollbar
  //if (ScrollBarAlways in [saNone, saVert]) then
  //  if (TCW < GW) or not (ScrollBars in [ssHorizontal,ssBoth]) then
  //  begin
  //    ShowScrollBar(Handle,SB_HORZ,False);
  //  end;
end;

procedure TAdvStringGrid.UpdateVScroller;
var
  R,GLW,RH,GH: Integer;
  TotalFixedHeight: Integer;
  TotalScrollableHeight: Integer;
  TotalHiddenHeight: Integer;
  ViewRatio: Single;
  IdealNMax: Single;
  IdealNPos: Single;
  ScrollInfo: TScrollInfo;
begin
  if (csLoading in ComponentState) or
     (csDesigning in ComponentState) then
    Exit;

  if not ScrollProportional or (ScrollType = ssMetro) then
    Exit;

  if not (ScrollBars in [ssBoth, ssVertical]) then
    Exit;

  if FScrollLock then
    Exit;

  if not (RowCount > VisibleRowCount + FixedRows) then
    Exit;

  { Get current scroll information }
  FillChar(ScrollInfo,SizeOf(ScrollInfo),0);
  ScrollInfo.cbSize := SizeOf(ScrollInfo);

  ScrollInfo.fMask  := SIF_ALL;
  GetScrollInfo(Handle,SB_VERT,ScrollInfo);

  { Calculate proper scrolling region ratio }
  GLW := GridLineWidth;
  if VisibleColCount < ColCount then
    GH := Height - GetSystemMetrics(SM_CYHSCROLL)
  else
    GH := Height;

  TotalFixedHeight := GLW;
  for R := 0 to FixedRows - 1 do
    Inc(TotalFixedHeight,RowHeights[R] + GLW);

  TotalScrollableHeight := GLW;
  TotalHiddenHeight := GLW;

  for R := FixedRows to RowCount - 1 do
  begin
    RH := RowHeights[R];
    if R < TopRow then
      Inc(TotalHiddenHeight,RH + GLW);
    Inc(TotalScrollableHeight,RH + GLW);
  end;

  if SearchFooter.Visible then
    TotalScrollableHeight := TotalScrollableHeight + SearchPanel.Height;


  if TotalScrollableHeight = 0 then
    Exit;

  ViewRatio := (GH - TotalFixedHeight)/TotalScrollableHeight;

  if ViewRatio >= 0.9999 then
    Exit;

  IdealNMax := (127 + ViewRatio) / (1 - ViewRatio);

  if TotalScrollableHeight > GH  then
    IdealNPos := TotalHiddenHeight / (TotalScrollableHeight - GH) * 128
  else
    IdealNPos := 127;

  { Set scroll information }
  ScrollInfo.nMax := Trunc(IdealNMax);
  ScrollInfo.nPage := ScrollInfo.nMax - 127 + 1;
  ScrollInfo.nPos := Trunc(IdealNPos);
  SetScrollInfo(Handle,SB_VERT,ScrollInfo,TRUE);

  UpdateVScrollBar;
//  if not (ScrollBars in [ssVertical,ssBoth]) then
//    ShowScrollBar(Handle,SB_VERT,False);
end;


procedure TAdvStringGrid.WMVScroll(var WMScroll: TWMScroll);
var
  r: TRect;
  s: String;
  pt: TPoint;
  nr: Integer;
  fcr,tcr: TRect;
  oldpos: integer;
  linedownend: boolean;

begin
  if (csDesigning in ComponentState) then
  begin
    inherited;
    Exit;
  end;

  linedownend := (FLastScrollCode in [SB_LINEDOWN, SB_PAGEDOWN, SB_THUMBPOSITION]) and (wmscroll.ScrollCode = SB_ENDSCROLL);

  FLastScrollCode := wmscroll.ScrollCode;

  if WMScroll.ScrollBar = FScrollBar.Handle then
  begin
    SendMessage(FScrollBar.Handle, WMScroll.Msg, WMScroll.ScrollCode, WMScroll.Pos);
    oldpos := FScrollBar.Position;

    case WMSCroll.ScrollCode of
    0: FScrollBar.Position := Max(FScrollBar.Min, FScrollBar.Position - 10);
    1: FScrollBar.Position := Min(FScrollBar.Max, FScrollBar.Position + 10);
    2: FScrollBar.Position := FScrollBar.Position - 100;
    3: FScrollBar.Position := FScrollBar.Position + 100;
    5: FScrollBar.Position := WMScroll.Pos;
    end;

    if (oldpos <> FScrollBar.Position) then
    begin
      WMScroll.Result := 1;
      SetScrollPosition(FScrollCol,FScrollRow, FScrollBar.Position);
      RepaintCell(FScrollCol, FScrollRow);
      DoCellScroll(FScrollCol, FScrollRow, FScrollBar.Position, FScrollBar.Min, FScrollBar.Max);
    end;

    Exit;
  end;

  if (FScrollHints in [shVertical,shBoth]) and Assigned(FScrollHintWnd) then
  begin
    if (wmScroll.ScrollCode = SB_ENDSCROLL) then
    begin
      FScrollHintWnd.ReleaseHandle;
      FScrollHintShow := False;
    end;

    if wmScroll.ScrollCode = SB_THUMBTRACK then
    begin
      nr := FixedRows + longmuldiv(wmScroll.pos,RowCount - VisibleRowCount - FixedRows,maxshortint);
      s := 'Row : '+inttostr(nr);
      if Assigned(OnScrollHint) then
        OnScrollHint(self,nr,s);
      r := FScrollHintWnd.CalcHintRect(100,s,Nil);
      FScrollHintWnd.Caption := s;
      FScrollHintWnd.Color := FHintColor;
      GetCursorPos(pt);
      r.Left := r.Left + pt.x + 10;
      r.Right := r.Right + pt.x + 10;
      r.Top := r.Top + pt.y;
      r.Bottom := r.Bottom + pt.y;
      FScrollHintWnd.ActivateHint(r,s);
      FScrollHintShow := True;
    end;
  end;

  if (Navigation.AlwaysEdit)  then
  begin
    if EditMode then
      HideInplaceEdit;
  end;

  if (wmScroll.scrollcode = SB_THUMBTRACK) and (FScrollSynch) then
  begin
    TopRow := FixedRows + longmuldiv(wmScroll.pos,RowCount - VisibleRowCount - FixedRows,MaxShortInt);
  end;

  // get previous background rectangle

  with FBackground do
  if not Bitmap.Empty and (Display = bdFixed) then
  begin
    MouseToCell(Left,Top,longint(fcr.Left),longint(fcr.Top));
    MouseToCell(Left + Bitmap.Width,Top + Bitmap.Height,longint(fcr.Right),longint(fcr.Bottom));
  end;

  if ((wmScroll.ScrollCode = SB_ENDSCROLL) or (wmScroll.ScrollCode = SB_LINEDOWN)) and SearchFooter.Visible then
  begin
    if IsScrolledToLastRow then
    begin
      wmscroll.Result := 1;
      Exit;
    end;
  end;

  inherited;

  if (wmScroll.ScrollCode = SB_LINEUP) and SearchFooter.Visible then
  begin

    if TopRow = RowCount - VisibleRowCount then
    begin
      TopRow := TopRow - 1;
    end;
  end;

  if (linedownend or (wmScroll.ScrollCode = SB_LINEDOWN)) and SearchFooter.Visible then
  begin
    if TopRow = RowCount - VisibleRowCount then
    begin
      ScrollToLastRow;
    end;
  end;

  // get new background rectangle & repaint
  with FBackground do
  if not Bitmap.Empty and (Display = bdFixed) then
  begin
    MouseToCell(Left,Top,longint(tcr.Left),longint(tcr.Top));
    MouseToCell(Left + Bitmap.Width,Top + Bitmap.Height,longint(tcr.Right),longint(tcr.Bottom));
    if (wmScroll.ScrollCode <> SB_THUMBTRACK) and not EqualRect(fcr,tcr) then
    begin
      RepaintRect(fcr);
      RepaintRect(tcr);
    end;
  end;

  UpdateVScrollBar;
  UpdateHScrollBar;

  if HasCheckBox(Col,Row) then
    HideEditor;
end;

procedure TAdvStringGrid.Notification(AComponent: TComponent; AOperation: TOperation);
begin

  if (AOperation = opRemove) then
  begin
    if (AComponent = FGridImages) then
      FGridImages := nil
    else if (AComponent = FContainer) then
      FContainer := nil
    else if (AComponent = FCellChecker) then
      FCellChecker := nil
    else if (AComponent = FFixedDropDownMenu) then
      FFixedDropDownMenu := nil
    else if (AComponent = FToolBarPopup) then
      FToolBarPopup := nil
    else if (not (csDestroying in ComponentState)) and Assigned(FSyncGrid) and (AComponent = FSyncGrid.Grid) then
      FSyncGrid.Grid := nil;
  end;

  inherited;
end;

procedure TAdvStringGrid.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
var
  CurrentlyScrolling:boolean;
begin
  if not(FDragScrollOptions.Active) then
  begin
    if Assigned(FDragTmr) then
    begin
      FDragTmr.Enabled := false;
      FDragTmr.Free;
      FDragTmr := nil;
    end;
    inherited;
    Exit;
  end;

  CurrentlyScrolling := (FDragScrollDirection = []);

  FDragScrollDirection := [];
  
  case State of
  dsDragEnter,dsDragMove:
    begin
      //Moving in the Grid, Check the Borders
      if y < FDragScrollOptions.Margins.TopMargin then
        Include(FDragScrollDirection,dsdUp)
      else
        if y > (Height - FDragScrollOptions.Margins.BottomMargin) then
          Include(FDragScrollDirection,dsdDown);

      if x < FDragScrollOptions.Margins.LeftMargin then
        Include(FDragScrollDirection,dsdLeft)
      else
        if x > (Width - FDragScrollOptions.Margins.RightMargin) then
          Include(FDragScrollDirection,dsdRight);
        //Any Borders hit?
      if FDragScrollDirection=[] then
      begin
        //Turn Timer off
        if Assigned(FDragTmr) then
        begin
          FDragTmr.Enabled := False;
          FDragTmr.Free;
          FDragTmr := nil;
        end;
      end
      else
      begin
        if not(Assigned(FDragTmr)) then
        begin
          FDragTmr := TTimer.Create(Parent);
          FDragTmr.Interval := FDragScrollOptions.Delays.InitialDelay;
          FDragTmr.OnTimer := DragTimerProc;
          FDragTmr.Enabled := True;
        end
        else
        begin
          //Reset the Timer if a new scroll is required
          if not(CurrentlyScrolling) then
            FDragTmr.Interval := FDragScrollOptions.Delays.InitialDelay;
        end;
      end;
    end;
  dsDragLeave:
    begin
      if Assigned(FDragTmr) then
      begin
        FDragTmr.Enabled := False;
        FDragTmr.Free;
        FDragTmr := nil;
      end;
    end;
  end;
  inherited;
end;

procedure TAdvStringGrid.ScrollTimerProc(Sender: TObject);
begin
  if FScrollSteps = 0 then
    Exit;

  if FScrollVert then
    TopRow := Max(FixedRows,TopRow + FScrollDelta)
  else
    LeftCol := Max(FixedCols, LeftCol + FScrollDelta);

  dec(FScrollSteps);
  FScrollEnd := false;
  FScrollTimer.Enabled := FScrollSteps <> 0;
end;

procedure TAdvStringGrid.DragTimerProc(Sender: TObject);
var
  CanScroll: Boolean;
  DSD: TDragScrollDirection;
begin
  if not(FDragScrollOptions.Active) then
  begin
    FDragTmr.Enabled := False;
    FDragTmr.Free;
    FDragTmr := nil;
    Exit;
  end;

  FDragTmr.Interval := FDragScrollOptions.Delays.RepeatDelay;

  //Do Scroll if User is OK with it
  DSD := FDragScrollDirection;
  if Assigned(fOnDragScroll) then
  begin
    CanScroll := True;
    FOnDragScroll(Self,TopRow,LeftCol,DSD,CanScroll);
    if not (CanScroll) then
      Exit;
  end;

  //Allow scroll
  if dsdUp in DSD then
  begin
    if TopRow > FixedRows then
      TopRow := TopRow - 1;
  end;
  if dsdDown in DSD then
  begin
    if (TopRow + VisibleRowCount) < (RowCount) then
      TopRow := TopRow + 1;
  end;

  if dsdLeft in DSD then
  begin
    if LeftCol > FixedCols then
      LeftCol := LeftCol - 1;
  end;

  if dsdRight in DSD then
  begin
    if (LeftCol + VisibleColCount) < (ColCount) then
      LeftCol := LeftCol + 1;
  end;
end;

{$IFDEF TMSUNICODE}
procedure TAdvStringGrid.WideEllipsClick(Sender: TObject);
var
  ws: widestring;
begin
  if Assigned(OnWideEllipsClick) then
  begin
    ws := UniEditBtn.Text;
    OnWideEllipsClick(Self, Col,Row, ws);
    if  (ws <> UniEditBtn.Text) then
      UniEditBtn.Text := ws;
  end;
end;
{$ENDIF}

procedure TAdvStringGrid.SizeChanged(OldColCount, OldRowCount: longint);
begin
  if ((Parent = Nil) or
      (csLoading in ComponentState) or
      (csReading in ComponentState)) or
     Application.Terminated then Exit;

  if FColumnSize.FStretch then
    StretchColumn(FColumnSize.StretchColumn);

  inherited SizeChanged(OldColCount,OldRowCount);

  FlatShowScrollBar(SB_VERT,visibleRowCount + FixedRows < RowCount);
  UpdateVScrollBar;

  FlatShowScrollBar(SB_HORZ,visibleColCount + FixedCols < ColCount);
  UpdateHScrollBar;

//  if (FFixedFooters > 0) or (FFixedRightCols > 0) then
//    Invalidate;
end;

function TAdvStringGrid.GetArrowColor: TColor;
begin
  Result := ArwU.Color;
end;

procedure TAdvStringGrid.SetArrowColor(Value: TColor);
begin
  ArwU.Color := Value;
  ArwD.Color := Value;
  ArwL.Color := Value;
  ArwR.Color := Value;
end;

procedure TAdvStringGrid.StretchColumns;
begin
  ColumnSize.FStretchAll := true;
  ColumnSize.FStretch := true;
  StretchColumn(-1);
end;

procedure TAdvStringGrid.StretchColumn(ACol: Integer; NewWidth: integer = -1);
var
  i,w,d,nw: Integer;

begin
  if (csLoading in ComponentState) or (csDestroying in ComponentState) or Application.Terminated then
  	Exit;

  if NewWidth = -1 then
    nw := ClientRect.Right - ClientRect.Left
  else
    nw := NewWidth;

  if ACol = - 1 then
    ACol := ColCount - 1;

  if ACol >= ColCount then
    raise Exception.Create('Stretch column index out of range');

  if (ColCount = 0) or not FColumnSize.FStretch then
    Exit;

  if FIsColChanging then
    Exit;

  FIsColChanging := true;

  ColchgFlg := False;

  if ColCount = 1 then
  begin
    ColWidths[0] := ClientRect.Right;
    ColchgFlg := True;
    FIsColChanging := False;
    Exit;
  end;

  w := 0;

  if ColumnSize.StretchAll then
  begin
    if (ColCount - FixedCols - FixedRightCols > 0) then
    begin
      // available width
      d := nw;

      for i := 1 to FixedCols do
        d := d - ColWidths[i - 1];

      for i := 1 to FixedRightCols do
        d := d - ColWidths[ColCount - i];

      w := d div (ColCount - FixedCols - FixedRightCols);
      d := d mod (ColCount - FixedCols - FixedRightCols);

      for i := FixedCols to ColCount - FixedRightCols - 1 do
      begin
        if d > 0 then
        begin
          ColWidths[i] := w + 1;
          dec(d);
        end
        else
          ColWidths[i] := w;
      end;
    end;
  end
  else
  begin
    // real used Column Width is ColWidth[] + 1 !
    for i := 0 to ColCount - 1 do
    begin
      if i <> ACol then
        w := w + ColWidths[i];
    end;

    if w < ClientRect.Right then
    begin
      ColWidths[ACol] := nw - w {- 1};
    end
    else
    begin
      if LeftCol = FixedCols then
        ColWidths[ACol] := DefaultColWidth;
    end;
  end;

  ColchgFlg := True;

  FIsColChanging := false;

  if FloatingFooter.Visible then
    FFooterPanel.Align := alBottom;
end;

procedure TAdvStringGrid.StretchRightColumn;
begin
  StretchColumn(ColCount - 1);
end;

procedure TAdvStringGrid.UpdateColSize(ACol: Integer;
  var NewWidth: Integer);
begin
  if Assigned(FOnUpdateColumnSize) then
  begin
    FOnUpdateColumnSize(Self,ACol,NewWidth);
  end;
end;

procedure TAdvStringGrid.UpdateAutoColSize(ACol: Integer;
  var NewWidth: Integer);
begin
  if Assigned(FOnUpdateColumnSize) then
  begin
    FOnUpdateColumnSize(Self,ACol,NewWidth);
  end;
end;

procedure TAdvStringGrid.UpdateColHeaders;
begin

end;

procedure TAdvStringGrid.ColWidthsChanged;
var
  i,nw: Integer;
  Ratio: Double;
  r: TRect;

begin
  if ColchgFlg and HandleAllocated then
    StretchColumn(FColumnSize.StretchColumn);

  if csDesigning in ComponentState then
  begin
    if FScrollHintShow and Assigned(FScrollHintWnd) then
      FScrollHintWnd.ReleaseHandle;
    FScrollHintShow := False;
  end;

  inherited ColWidthsChanged;

  ColSizeFlg := True;

  if Colsized and FMouseActions.AllColumnSize and (ColclickedSize > 0) then
  begin
    ColSized := False;
    Ratio := ColWidths[Colclicked]/ColClickedSize;
    for i := FixedCols to ColCount - 1 do
      if i <> ColClicked then
        ColWidths[i] := Round(ColWidths[i] * Ratio);
    ColSized := True;
  end;

  if Assigned(FOnEndColumnSize) and ColSized then
    FOnEndColumnSize(Self,ColClicked);

  if ColSized then
  begin
    nw := ColWidths[ColClicked];
    UpdateColSize(ColClicked,nw);

    if nw <> ColWidths[ColClicked] then
    begin
      ColSized := False;
      ColWidths[CoLClicked] := nw;
    end;
  end;

  if ColSized then
  begin
    Colclicked := -1;
    Rowclicked := -1;
  end;

  if EditMode and Assigned(EditCtrl) then
  begin
    r := CellRect(Col,Row);
    EditCtrl.Left := r.Left;
    EditCtrl.Width := r.Right - r.Left;
    EditCtrl.Height := r.Bottom - r.Top;
    EditCtrl.Top := r.Top;
  end;

  Colsized := False;

  if HasCheckBox(Col,Row) then
    HideEditor;

  UpdateFooter;
  CellControlsUpdate;

  if ColumnSize.Stretch and ScrollProportional and not (ScrollType = ssMetro) then
    UpdateVScroller;
end;

procedure TAdvStringGrid.RowHeightsChanged;
var
  i: Integer;
  Ratio:double;
  rh: TIntList;
begin
  if csDesigning in ComponentState then
  begin
    if FScrollHintShow and Assigned(FScrollHintWnd) then
      FScrollHintWnd.ReleaseHandle;
    FScrollHintShow := False;
  end;

  inherited RowHeightsChanged;

  if Rowsized and FMouseActions.AllRowSize then
  begin
    Rowsized := False;
    Ratio := RowHeights[Rowclicked]/RowClickedSize;

    rh := TIntList.Create(-1,-1);
    for i := 0 to FixedRows - 1 do
      rh.Add(RowHeights[i]);

    for i := FixedRows to RowCount - 1 do
      if i <> RowClicked then
        RowHeights[i] := Round(RowHeights[i] * Ratio);

    DefaultRowHeight := RowHeights[FixedRows];

    for i := 0 to FixedRows - 1 do
      RowHeights[i] := rh.Items[i];

    rh.Free;

    Rowsized := True;
  end;

  if Assigned(FOnEndRowSize) and Rowsized then
    FOnEndRowSize(self,Rowclicked);

  if Rowsized then
  begin
    ColClicked := -1;
    RowClicked := -1;
  end;

  Rowsized := False;

  if HasCheckBox(Col,Row) then
    HideEditor;

  CellControlsUpdate;
end;

procedure TAdvStringGrid.RegisterSelListener(AListener: ITAdvStringGridSelect);
begin
  FISelect := AListener;
end;

procedure TAdvStringGrid.RegisterValidateInterface(AValidate: ITMSCellValidate);
begin
  FICellValidate := AValidate;
end;

procedure TAdvStringGrid.UnRegisterSelListener(AListener: ITAdvStringGridSelect);
begin
  FISelect := nil;
end;

procedure TAdvStringGrid.UnregisterValidateInterface;
begin
  FICellValidate := nil;
end;

procedure TAdvStringGrid.RegisterNotifier(ANotifier: TGridChangeNotifier);
begin
  if FNotifierList.IndexOf(ANotifier) = -1 then
    FNotifierList.Add(ANotifier);
end;

procedure TAdvStringGrid.UnRegisterNotifier(ANotifier: TGridChangeNotifier);
var
  Idx: Integer;
begin
  Idx := FNotifierList.IndexOf(ANotifier);

  if Idx <> -1 then
    FNotifierList.Delete(Idx);
end;

procedure TAdvStringGrid.ClearComboString;
begin
  EditCombo.Items.Clear;
end;

function TAdvStringGrid.RemoveComboString(const s:string): Boolean;
var
  i: Integer;
begin
  Result := False;
  i := EditCombo.Items.IndexOf(s);
  if (i <> -1) then
  begin
    EditCombo.Items.Delete(i);
    Result := True;
  end;
end;

function TAdvStringGrid.SetComboSelectionString(const s:string): Boolean;
var
  i: Integer;
begin
  Result := False;
  i := EditCombo.Items.IndexOf(s);
  if (i <> -1) then
  begin
    FComboIdx := i;
    Result := True;
  end;
end;

procedure TAdvStringGrid.AddComboString(const s:string);
begin
  EditCombo.Items.Add(s);
end;

procedure TAdvStringGrid.AddComboStringObject(const s: string; AObject: TObject);
var
  i: Integer;
begin
  i := EditCombo.Items.Add(s);
  EditCombo.Items.Objects[i] := AObject;
end;

procedure TAdvStringGrid.SetComboIndex(ACol, ARow: Integer;
  const Value: Integer);
begin
  DoGetEditorProp(ACol,ARow,nil);
  Cells[ACol,ARow] := EditCombo.Items[Value];
end;

procedure TAdvStringGrid.SetComboSelection(idx: Integer);
begin
  FComboIdx := Idx;
  FForceComboSel := true;
end;

function TAdvStringGrid.GetComboCount: Integer;
begin
  GetComboCount := EditCombo.Items.Count;
end;

function TAdvStringGrid.GetComboIndex(ACol, ARow: Integer): Integer;
begin
  DoGetEditorProp(ACol,ARow,nil);
  Result := EditCombo.Items.IndexOf(Cells[ACol,ARow]);
end;

function TAdvStringGrid.IsPassword(ACol,ARow: Integer): Boolean;
var
  IsPassword: Boolean;
begin
  IsPassword := False;
  GetCellPassword(ACol,ARow,IsPassword);
  Result := IsPassword;
end;

function TAdvStringGrid.IsEditable(ACol,ARow: Integer): Boolean;
begin
  Result := False;

  if not ((goEditing in Options) or MouseActions.RangeSelectAndEdit) and not FEditDisable then
    Exit;

  Result := IsEditableInt(ACol,ARow);
end;

function TAdvStringGrid.IsEditableInt(ACol,ARow: Integer): Boolean;
var
  IsFixed,IsEdit: Boolean;
  BC: TPoint;

begin
  if IsMergedCell(ACol, ARow) and not IsBaseCell(ACol, ARow) then
    BC := BaseCell(ACol,ARow)
  else
    BC := Point(ACol,ARow);

  IsFixed := False;
  IsEdit := True;

  GetCellReadOnly(BC.X,BC.Y,IsEdit);
  GetCellFixed(BC.X,BC.Y,IsFixed);
  Result := IsEdit and not IsFixed;
end;


function TAdvStringGrid.IsFixed(ACol,ARow: Integer): Boolean;
var
  IsFixed: Boolean;
  pt: TPoint;
begin
  IsFixed := False;

  pt := BaseCell(RemapCol(ACol),ARow);

  pt.X := RemapColInv(pt.X);

  if (pt.Y >= RowCount - FixedFooters) or
     (pt.X >= ColCount - FixedRightCols) and (pt.X < ColCount) { + NumHiddenColumns} then
  begin
    Result := true;
    Exit;
  end;

  GetCellFixed(pt.X, pt.Y, IsFixed);

  Result := IsFixed;
end;

procedure TAdvStringGrid.UpdateOnSelection(var GR: TGridRect);
begin
end;

procedure TAdvStringGrid.OnMouseActionsChanged(Sender: TObject);
begin

end;

procedure TAdvStringGrid.OnMouseActionsInvalidate(Sender: TObject);
begin
  Invalidate;
end;

procedure TAdvStringGrid.OnMouseActionsDisableEdit(Sender: TObject);
begin
  Options := Options - [goEditing];
end;

procedure TAdvStringGrid.OnMouseActionsIsDesigning(Sender: TObject; var IsDesigning: boolean);
begin
  IsDesigning := (csDesigning in ComponentState)
end;

procedure TAdvStringGrid.OnNavigationChanged(Sender: TObject);
begin
  //
end;

procedure TAdvStringGrid.UpdateEditingCell(ACol,ARow: Integer; Value: string);
begin
  SetEditText(RemapColInv(ACol),ARow,Value);
  Cells[ACol,ARow] := Value;
end;

procedure TAdvStringGrid.HideEditControl(ACol,ARow: Integer);
var
  OldFmt: string;
  {$IFDEF TMSUNICODE}
  ws: widestring;
  {$ENDIF}
  newval: string;
  newidx: integer;
  newcolor: TColor;
  st: _SYSTEMTIME;
begin
  if csDestroying in ComponentState then
    Exit;

  FSpecialEditor := False;
  FBlockKill := True;

  EditCtrl := nil;

  if FocusHelper.Enabled then
    HideFocusHelper;

  ACol := RemapCol(ACol);
  FStartEditChar := #0;

  case EditControl of
  edComboEdit,edComboList:
  begin
    if EditMode then
    begin
      EditMode := False;
      UpdateEditingCell(ACol,ARow,EditCombo.Text);
      EditCombo.Visible := False;
      EditCombo.Enabled := False;
    end;
  end;

  /// EDITORINTEGRATION
  ///
  edTrackbarDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditTrackBar.Text);
      EditTrackBar.Visible := false;
      EditTrackBar.Enabled := false;
    end;
  end;
  edMemoDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      newval := EditMemo.MemoText.Text;
      UpdateEditingCell(ACol,ARow,newval);
      EditMemo.Visible := false;
      EditMemo.Enabled := false;
    end;
  end;
  edCalculatorDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditCalculator.Text);
      EditCalculator.Visible := false;
      EditTimePicker.Enabled := false;
    end;
  end;
  edTimePickerDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditTimePicker.Text);
      EditTimePicker.Visible := false;
      EditTimePicker.Enabled := false;
    end;
  end;
  edDetailDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditDetailPicker.Text);
      EditDetailPicker.Visible := false;
      EditDetailPicker.Enabled := false;
    end;
  end;
  edGridDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditGridPicker.Text);
      EditGridPicker.Visible := false;
      EditGridPicker.Enabled := false;
    end;
  end;
  edAdvGridDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditAdvGridPicker.Text);
      EditAdvGridPicker.Visible := false;
      EditAdvGridPicker.Enabled := false;
    end;
  end;
  edControlDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      UpdateEditingCell(ACol,ARow,EditControlPicker.Text);
      EditControlPicker.Visible := false;
      EditControlPicker.Enabled := false;
    end;
  end;
  edColorPickerDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;
      newcolor := EditColorPicker.SelectedColor;
      newval := EditColorPicker.SelectedColorText;

      if Assigned(OnColorSelected) then
        OnColorSelected(Self, ACol, ARow, newcolor, newval);

      UpdateEditingCell(ACol,ARow,newval);

      if CellTypes[ACol,ARow] = ctShape then
      begin
        SetShapeColor(ACol,ARow, newcolor);
      end
      else
        Colors[ACol, ARow] := newcolor;

      EditColorPicker.Visible := false;
      EditColorPicker.Enabled := false;
    end;
  end;
  edImagePickerDropDown:
  begin
    if EditMode then
    begin
      EditMode := false;

      newidx := EditImagePicker.ImageIndex;

      if Assigned(OnImageSelected) then
        OnImageSelected(Self, ACol, ARow, newidx);

      //
      if CellTypes[ACol,ARow] = ctImageList then
      begin
        SetImageIdx(ACol, ARow, newidx);
      end;

      if CellTypes[ACol, ARow] = ctDataImage then
      begin
        UpdateEditingCell(ACol, ARow, IntToStr(newidx));
      end;

      EditImagePicker.Visible := false;
      EditImagePicker.Enabled := false;
    end;
  end;

  /// EDITORINTEGRATION

  {$IFDEF TMSUNICODE}
  edUniEdit:
  begin
    EditMode := False;
    ws := EditUni.Text;
    if Assigned(OnSetEditWideText) then
      OnSetEditWideText(Self, ACol, ARow, ws);
    WideCells[ACol,ARow] := ws;
    EditUni.Enabled := False;
    EditUni.Visible := False;
  end;
  edUniComboEdit,edUniComboList:
  begin
    EditMode := False;

    ws := ComboUni.Text;
    if Assigned(OnSetEditWideText) then
      OnSetEditWideText(Self, ACol, ARow, ws);

    WideCells[ACol,ARow] := ws;
    ComboUni.Enabled := False;
    ComboUni.Visible := False;
  end;
  edUniEditBtn:
  begin
    EditMode := False;

    ws := EditBtnUni.Text;
    if Assigned(OnSetEditWideText) then
      OnSetEditWideText(Self, ACol, ARow, ws);

    WideCells[ACol,ARow] := ws;
    EditBtnUni.Enabled := False;
    EditBtnUni.Visible := False;
  end;
  edUniMemo:
  begin
    EditMode := False;

    ws := MemoUni.Text;
    if Assigned(OnSetEditWideText) then
      OnSetEditWideText(Self, ACol, ARow, ws);

    WideCells[ACol,ARow] := ws;
    MemoUni.Enabled := False;
    MemoUni.Visible := False;
  end;
  {$ENDIF}

  edSpinEdit,edFloatSpinEdit,edTimeSpinEdit,edDateSpinEdit:
  begin
    EditMode := False;

    if (EditSpin.AllowEmptyValue) and (SysUtils.Trim(EditSpin.Text)= '') then
      Cells[ACol,ARow] := ''
    else
      case EditControl of
        edSpinEdit: Ints[ACol,ARow] := EditSpin.Value;
        edTimeSpinEdit: UpdateEditingCell(ACol,ARow,EditSpin.Text);
        edFloatSpinEdit: Floats[ACol,ARow] := EditSpin.FloatValue;
        edDateSpinEdit: Dates[ACol,ARow] := EditSpin.DateValue;
      end;

    EditSpin.Enabled := False;
    EditSpin.Visible := False;
  end;
  edDateTimeEdit:
  begin
    if ComCtrlOk then
    begin
      if EditDateTime.Checked then
        UpdateEditingCell(ACol,ARow,FormatDateTime(ShortDateFormat + ' ' + ShortTimeFormat,EditDateTime.DateTime))
      else
        UpdateEditingCell(ACol,ARow,'');

      EditMode := False;
      EditDateTime.Enabled := False;
      EditDateTime.Visible := False;
    end;

  end;
  edDateEdit,edDateEditUpDown:
  begin
    if ComCtrlOk then
    begin
      if EditDate.Checked then
      begin
        FillChar(st,0,SizeOf(st));
        if SendMessage(EditDate.Handle, DTM_GETSYSTEMTIME,0, longint(@st))= GDT_VALID then
        begin
          if (st.wYear <> 0) and (st.wMonth <> 0) and (st.wDay <> 0) then
            UpdateEditingCell(ACol,ARow,DateToStr(SystemTimeToDateTime(st)));
        end;
      end
      else
        UpdateEditingCell(ACol,ARow,'');

      EditMode := False;
      EditDate.Enabled := False;
      EditDate.Visible := False;

      ShowWindow(EditDate.GetCalendarHandle, SW_HIDE);
    end;
  end;
  edTimeEdit:
  begin
    if ComCtrlOk then
    begin
      OldFmt := LongTimeFormat;

      if EditDate.Format <> '' then
        {$IFNDEF DELPHIXE_LVL}
        SysUtils.LongTimeFormat := EditDate.Format;
        {$ENDIF}
        {$IFDEF DELPHIXE_LVL}
        FormatSettings.LongTimeFormat := EditDate.Format;
        {$ENDIF}

      UpdateEditingCell(ACol,ARow,EditDate.Text);
      {$IFNDEF DELPHIXE_LVL}
      SysUtils.LongTimeFormat := OldFmt;
      {$ENDIF}
      {$IFDEF DELPHIXE_LVL}
      FormatSettings.LongTimeFormat := OldFmt;
      {$ENDIF}

      EditMode := False;
      EditDate.Enabled := False;
      EditDate.Visible := False;

      ShowWindow(EditDate.GetCalendarHandle, SW_HIDE);
    end;
  end;
  edCheckBox:
  begin
    EditCheck.Enabled := False;
    EditCheck.Visible := False;
    EditMode := False;
  end;
  edEditBtn,edMaskEditBtn,edNumericEditBtn,edFloatEditBtn:
  begin
    if EditMode then
    begin
      EditMode := False;
      UpdateEditingCell(ACol,ARow,EditBtn.Text);
      EditBtn.Enabled := False;
      EditBtn.Visible := False;
    end;
  end;
  edUnitEditBtn, edNumericUnitEditBtn, edFloatUnitEditBtn:
  begin
    UpdateEditingCell(ACol,ARow,UnitEditBtn.Text + UnitEditBtn.UnitID);
    UnitEditBtn.Enabled := False;
    UnitEditBtn.Visible := False;
    EditMode := False;
  end;
  edRichEdit:
  begin
    UpdateEditingCell(ACol,ARow,RichToString(InplaceRichEdit));
    InplaceRichEdit.Enabled := False;
    InplaceRichEdit.Visible := False;
    EditMode := False;
  end;
  edButton:
  begin
    Gridbutton.Enabled := False;
    Gridbutton.Visible := False;
    EditMode := False;
  end;
  edCustom:
  begin
    if ControlLook.DropDownAlwaysVisible then
      GetStaticCellEditor(ACol,ARow,EditControl);

    if Assigned(EditLink) {and EditMode} then
    begin
      UpdateEditingCell(ACol,ARow,EditLink.GetEditorValue);
      if EditLink.EditStyle <> esPopup then
        EditLink.SetVisible(False);
      if Assigned(EditLink) then
      begin
        EditLink.RestoreWinProc;
      end;
      EditMode := False;
    end;
  end;
  end;

  if not (EditControl in [edNormal,edValidChars,edCapital]) and (FEditActive) then
  begin
    DoneEditing(ACol,ARow);
  end;

  FBlockKill := False;
  FEditActive := False;
end;

procedure TAdvStringGrid.HideCellEdit;
begin
  HideEditControl(Col,Row);
end;

procedure TAdvStringGrid.ShowCellEdit;
begin
  if not (goEditing in Options) and MouseActions.RangeSelectAndEdit then
  begin
    Options := Options + [goEditing];
  end;

  Perform(WM_KEYDOWN ,VK_F2,0);
end;

procedure TAdvStringGrid.DoCheckBoxClick(ACol,ARow: integer; AState: boolean);
begin
  if Assigned(OnCheckBoxClick) then
    OnCheckBoxClick(Self, ACol, ARow, AState);
end;

procedure TAdvStringGrid.DoClickCell(ARow, ACol: integer);
begin
  if Assigned(OnClickCell) then
    OnClickCell(Self,ARow,ACol);
end;

procedure TAdvStringGrid.DoClickSort(ACol: integer);
begin
  if Assigned(FOnClickSort) then
    FOnClickSort(self,ACol);
end;

procedure TAdvStringGrid.DoClipboardPasteDone(CellRect: TGridRect);
begin
  if Assigned(OnClipboardPasteDone) then
    OnClipboardPasteDone(Self,CellRect);
end;

procedure TAdvStringGrid.DoGetEditorProp(ACol: Integer; ARow: Integer; EditLink: TEditLink);
begin
  if Assigned(OnGetEditorProp) then
    OnGetEditorProp(Self, ACol, ARow, EditLink);

  if Assigned(OnGetEditorPropInt) then
    OnGetEditorPropInt(Self, ACol, ARow);
end;

procedure TAdvStringGrid.DoGetPrintPageNum(PageNum, PageNumCol: integer;
  var Value: string);
begin
  if Assigned(OnPrintGetPageNum) then
    OnPrintGetPageNum(Self, PageNum, PageNumCol, Value);
end;

procedure TAdvStringGrid.ShowEditControl(ACol,ARow: Integer);
var
  r: TRect;
  s, c: string;
  pt: TPoint;
  CellWidth,CellHeight,OCol: Integer;
  EditColor, CClr: TColor;
  AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  EditFont: TFont;
  AState: TGridDrawState;
  HAlign: TAlignment;
  VAlign: TVAlignment;
  WW: Boolean;
  GD: TCellGradientDirection;
  ValD: Double;
  Err, ValI, idx: Integer;
  EcC, EwT: boolean;
  PForm: TComponent;
  dt: TDateTime;
  {$IFNDEF DELPHI_UNICODE}
  ws: array of widestring;
  wo: array of TObject;
  {$ENDIF}

  {$IFDEF TMSUNICODE}
  wt: widestring;
  i: integer;
  {$ENDIF}
  FStartEditChar_old : Char;

begin
  FEditing := True;
  FSpecialEditor := True;
  FEditActive := True;

  r := CellRect(ACol,ARow);

  if UseRightToLeftAlignment then
  begin
    r.Left := r.Left + 1;
  //  dr := CellRect(LeftCol,TopRow);
  //  Hold := r.Right - r.Left;
  //  r.Left := dr.Left - (r.Right - dr.Right);
  //  r.Right := r.Left + Hold;
  end;

  OCol := ACol;
  ACol := RemapCol(ACol);

  CellWidth := R.Right - R.Left - 1;
  CellHeight := R.Bottom - R.Top - 1;

  AState := [];
  GetVisualProperties(OCol,Row,AState,False,False,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlign,VAlign,WW,GD);

  EditColor := Canvas.Brush.Color;
  EditFont := Canvas.Font;

  // Make sure the grid is no longer in selecting state
  FGridState := gsNormal;

  EditCtrl := nil;

  if EditControl <> edCustom then
    FLastValidation := true;

  case EditControl of
  edComboEdit:
    begin
      EditMode := True;

      EditCombo.DropDownCount := ControlLook.DropDownCount;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditCombo.Width := 0;
      EditCombo.Height := 0;
      EditCombo.Top := r.Top;
      EditCombo.Left := r.Left;


      EditCombo.Enabled := True;
      EditCombo.DroppedDown := False;

      EditCombo.Style := csDropDown;
      SendMessage(EditCombo.Handle,CB_SETITEMHEIGHT,-1,CellHeight - 6);

      EditCombo.Width := CellWidth;
      EditCombo.Height := CellHeight + (EditCombo.DropDownCount + 1) * EditCombo.ItemHeight;

      EditCombo.Text := GetEditText(OCol,ARow);

      if (FComboIdx <> -1) then
      begin
        if (EditCombo.ItemIndex = -1) then
          EditCombo.ItemIndex := FComboIdx;
      end;

      EditCombo.MaxLength := FMaxComboLength;

      EditCombo.Visible := True;

      EditCombo.Flat := Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007];
      EditCombo.Etched := Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007];

      EditCombo.Color := EditColor;

      if FNavigation.AutoComboDropSize then
        EditCombo.SizeDropDownWidth
      else
        if EditCombo.DropWidth > 0 then
          SendMessage(EditCombo.Handle,CB_SETDROPPEDWIDTH,EditCombo.DropWidth,0);

      EditCombo.SetFocus;
      EditCombo.DroppedDown := FMouseActions.DirectComboDrop or ControlLook.DropDownAlwaysVisible;

      if FMouseActions.DirectEdit and FMouseActions.DirectComboDrop then
        SelectionChanged(Selection.Left,Selection.Top,Selection.Right,Selection.Bottom);

      if FStartEditChar <> #0 then
        PostMessage(EditCombo.Handle,WM_CHAR,Ord(FStartEditChar),0);

      EditCtrl := EditCombo;

      if not MouseActions.DirectComboDrop then
        SendMessage(EditCombo.Handle,CB_SETITEMHEIGHT,-1,CellHeight - 6);

    end;
  edComboList:
    begin
      EditMode := True;

      FForceComboSel := false;

      EditCombo.DropDownCount := ControlLook.DropDownCount;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditCombo.Top := r.Top;
      EditCombo.Left := r.Left;

      EditCombo.Width := 0;
      EditCombo.Height := 0;
      EditCombo.DroppedDown := False;
      EditCombo.Enabled := True;

      EditCombo.Style := csDropDownList;

      // EditCombo.DropDownCount := 8;
      EditCombo.Itemindex := EditCombo.Items.IndexOf(Cells[ACol,ARow]);

      EcC := false;

      if ((FComboIdx = -1) and (EditCombo.ItemIndex = -1)) then
      begin
        EditCombo.ItemIndex := EditCombo.Items.IndexOf(GetEditText(OCol,ARow));

        if (EditCombo.ItemIndex = -1) and Navigation.AutoComboSelect then
          EditCombo.ItemIndex := 0;
        EditCombo.Change;
        EcC := Navigation.AutoComboSelect;
      end
      else
        if (EditCombo.ItemIndex = -1) or FForceComboSel then
          EditCombo.ItemIndex := FComboIdx;

      EditCombo.Width := CellWidth;
      EditCombo.Height := CellHeight + (EditCombo.DropDownCount + 1) * EditCombo.ItemHeight;

//      EditCombo.Text := GetEditText(OCol,ARow);

      EditCombo.Visible := True;

      EditCombo.Flat := Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007];
      EditCombo.Etched := Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007];

      EditCombo.Color := EditColor;

      if FNavigation.AutoComboDropSize then
        EditCombo.SizeDropDownWidth
      else
        if EditCombo.DropWidth > 0 then
          SendMessage(EditCombo.Handle,CB_SETDROPPEDWIDTH,EditCombo.DropWidth,0);

      EditCombo.SetFocus;

      EditCombo.DroppedDown := FMouseActions.DirectComboDrop or ControlLook.DropDownAlwaysVisible;

      if FMouseActions.DirectEdit and FMouseActions.DirectComboDrop then
        SelectionChanged(Selection.Left,Selection.Top,Selection.Right,Selection.Bottom);

      if EcC then
      begin
        if Assigned(OnComboChange) and (EditCombo.Items.Count > 0) then
          OnComboChange(Self, ACol,ARow, 0, EditCombo.Items[0]);

        if Assigned(OnComboObjectChange) and (EditCombo.Items.Count > 0) then
          OnComboObjectChange(Self, ACol, ARow, 0, EditCombo.Items[0], EditCombo.Items.Objects[0]);
      end;

      if FStartEditChar <> #0 then
        PostMessage(EditCombo.Handle,WM_CHAR,Ord(FStartEditChar),0);

      EditCtrl := EditCombo;

      if not MouseActions.DirectComboDrop then
        SendMessage(EditCombo.Handle,CB_SETITEMHEIGHT,-1,CellHeight - 6);
    end;

  /// EDITORINTEGRATION
  edTrackBarDropDown:
    begin
      EditMode := true;

      EditTrackBar.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditTrackBar.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditTrackBar.SetComponentStyle(FStyle);

      EditTrackBar.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditTrackBar.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditTrackBar.Top := r.Top;
      EditTrackBar.Left := r.Left;

      EditTrackBar.Width := 0;
      EditTrackBar.Height := 0;
      EditTrackBar.Enabled := True;
      EditTrackBar.BorderStyle := bsNone;

      EditTrackBar.Width := CellWidth;
      EditTrackBar.Height := CellHeight;

      s := GetEditText(OCol,ARow);
      Val(s,ValI,Err);
      EditTrackBar.Position := ValI;
      EditTrackBar.Color := EditColor;

      EditTrackBar.Visible := True;

      EditTrackBar.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditTrackBar.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditTrackBar.DoShowDropDown;

      EditCtrl := EditTrackBar;
    end;

  edMemoDropDown:
    begin
      EditMode := true;

      EditMemo.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditMemo.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditMemo.SetComponentStyle(FStyle);

      EditMemo.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditMemo.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditMemo.Top := r.Top;
      EditMemo.Left := r.Left;

      EditMemo.Width := 0;
      EditMemo.Height := 0;
      EditMemo.Enabled := True;
      EditMemo.BorderStyle := bsNone;

      EditMemo.Width := CellWidth;
      EditMemo.Height := CellHeight;

      EditMemo.SetText(GetEditText(OCol,ARow));
      EditMemo.Color := EditColor;

      EditMemo.Visible := True;

      EditMemo.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditMemo.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditMemo.DoShowDropDown;

      EditMemo.SelStart := 0;
      EditMemo.SelLength := 0;

      EditCtrl := EditMemo;
    end;

  edCalculatorDropDown:
    begin
      EditMode := true;

      EditCalculator.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditCalculator.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditCalculator.SetComponentStyle(FStyle);

      EditCalculator.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditCalculator.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditCalculator.Top := r.Top;
      EditCalculator.Left := r.Left;

      EditCalculator.Width := 0;
      EditCalculator.Height := 0;
      EditCalculator.Enabled := True;
      EditCalculator.BorderStyle := bsNone;

      EditCalculator.Width := CellWidth;
      EditCalculator.Height := CellHeight;

      EditCalculator.Text := GetEditText(OCol,ARow);
      EditCalculator.Color := EditColor;

      EditCalculator.Visible := True;

      EditCalculator.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditCalculator.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditCalculator.DoShowDropDown;

      EditCtrl := EditCalculator;
    end;

  edTimePickerDropDown:
    begin
      EditMode := true;

      EditTimePicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditTimePicker.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditTimePicker.SetComponentStyle(FStyle);

      EditTimePicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditTimePicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditTimePicker.Top := r.Top;
      EditTimePicker.Left := r.Left;

      EditTimePicker.Width := 0;
      EditTimePicker.Height := 0;
      EditTimePicker.Enabled := True;
      EditTimePicker.BorderStyle := bsNone;

      EditTimePicker.Width := CellWidth;
      EditTimePicker.Height := CellHeight;

      EditTimePicker.SetText(GetEditText(OCol,ARow));
      EditTimePicker.Color := EditColor;
      EditTimePicker.EditorEnabled := true;

      EditTimePicker.Visible := True;

      EditTimePicker.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditTimePicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditTimePicker.DoShowDropDown;

      EditCtrl := EditTimePicker;
    end;

  edDetailDropDown:
    begin
      EditMode := true;

      EditDetailPicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditDetailPicker.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditDetailPicker.SetComponentStyle(FStyle);

      EditDetailPicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditDetailPicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditDetailPicker.Top := r.Top;
      EditDetailPicker.Left := r.Left;

      EditDetailPicker.Width := 0;
      EditDetailPicker.Height := 0;
      EditDetailPicker.Enabled := True;
      EditDetailPicker.BorderStyle := bsNone;

      EditDetailPicker.Width := CellWidth;
      EditDetailPicker.Height := CellHeight;

      EditDetailPicker.SetText(GetEditText(OCol,ARow));
      EditDetailPicker.Color := EditColor;
      EditDetailPicker.EditorEnabled := true;

      EditDetailPicker.Visible := True;

      EditDetailPicker.SetFocus;

      ValI := EditDetailPicker.Items.IndexOf(EditDetailPicker.Text);

      if ValI >= 0 then
        EditDetailPicker.ItemIndex := ValI;

      if FStartEditChar <> #0 then
        PostMessage(EditDetailPicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditDetailPicker.DoShowDropDown;

      EditCtrl := EditDetailPicker;
    end;

  edGridDropDown:
    begin
      EditMode := true;

      EditGridPicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditGridPicker.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditGridPicker.SetComponentStyle(FStyle);

      EditGridPicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditGridPicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      EditGridPicker.Color := EditColor;
      EditGridPicker.EditorEnabled := true;

      DoGetEditorProp(ACol,ARow,EditLink);

      // force to initialize the lookup list
      EditGridPicker.BeginUpdate;
      EditGridPicker.EndUpdate;

      EditGridPicker.Top := r.Top;
      EditGridPicker.Left := r.Left;

      EditGridPicker.Width := 0;
      EditGridPicker.Height := 0;
      EditGridPicker.Enabled := True;
      EditGridPicker.BorderStyle := bsNone;

      EditGridPicker.Width := CellWidth;
      EditGridPicker.Height := CellHeight;

      s := GetEditText(OCol,ARow);

      if s = '' then
        EditGridPicker.ItemIndex := 0
      else
        EditGridPicker.ItemIndex := EditGridPicker.GetItemIndex(s);

      EditGridPicker.SetText(s);

      EditGridPicker.Visible := True;

      EditGridPicker.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditGridPicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditGridPicker.DoShowDropDown;

      EditCtrl := EditGridPicker;
    end;

  edAdvGridDropDown:
    begin
      EditMode := true;

      EditAdvGridPicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditAdvGridPicker.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditAdvGridPicker.SetComponentStyle(FStyle);

      EditAdvGridPicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditAdvGridPicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      EditAdvGridPicker.Color := EditColor;
      EditAdvGridPicker.EditorEnabled := true;
      EditAdvGridPicker.Grid.FixedRowAlways := true;

      DoGetEditorProp(ACol,ARow,EditLink);

      // force to initialize the lookup list
      EditAdvGridPicker.BeginUpdate;
      EditAdvGridPicker.EndUpdate;

      EditAdvGridPicker.Top := r.Top;
      EditAdvGridPicker.Left := r.Left;

      EditAdvGridPicker.Width := 0;
      EditAdvGridPicker.Height := 0;
      EditAdvGridPicker.Enabled := True;
      EditAdvGridPicker.BorderStyle := bsNone;

      EditAdvGridPicker.Width := CellWidth;
      EditAdvGridPicker.Height := CellHeight;

      s := GetEditText(OCol,ARow);

      if EditAdvGridPicker.UseItems then
      begin
        if s = '' then
          EditAdvGridPicker.ItemIndex := 0
        else
        begin
          EditAdvGridPicker.LookupInColumn(s, c, idx);
          EditAdvGridPicker.ItemIndex := idx;
        end;
      end;

      EditAdvGridPicker.SetText(s);

      EditAdvGridPicker.Visible := True;

      EditAdvGridPicker.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditAdvGridPicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditAdvGridPicker.DoShowDropDown;

      EditCtrl := EditAdvGridPicker;
    end;
  edControlDropDown:
    begin
      EditMode := true;

      EditControlPicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditControlPicker.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditControlPicker.SetComponentStyle(FStyle);

      EditControlPicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditControlPicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      EditControlPicker.Color := EditColor;
      EditControlPicker.EditorEnabled := true;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditControlPicker.Top := r.Top;
      EditControlPicker.Left := r.Left;

      EditControlPicker.Width := 0;
      EditControlPicker.Height := 0;
      EditControlPicker.Enabled := True;
      EditControlPicker.BorderStyle := bsNone;


      EditControlPicker.Width := CellWidth;
      EditControlPicker.Height := CellHeight;

      s := GetEditText(OCol,ARow);
      EditControlPicker.SetText(s);

      EditControlPicker.Visible := True;

      EditControlPicker.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditControlPicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditControlPicker.DoShowDropDown;

      EditCtrl := EditControlPicker;
    end;

  edColorPickerDropDown:
    begin
      EditMode := true;
      EditColorPicker.BeginUpdate;
      EditColorPicker.EndUpdate;

      EditColorPicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditColorPicker.DropDownHeader.Assign(ControlLook.DropDownHeader);

      EditColorPicker.SetComponentStyle(FStyle);

      EditColorPicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditColorPicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditColorPicker.Top := r.Top;
      EditColorPicker.Left := r.Left;

      EditColorPicker.Width := 0;
      EditColorPicker.Height := 0;
      EditColorPicker.Enabled := True;
      EditColorPicker.BorderStyle := bsNone;

      EditColorPicker.Width := CellWidth;
      EditColorPicker.Height := CellHeight;

      //EditColorPicker.SetText(GetEditText(OCol,ARow));

      if CellTypes[OCol, ARow] = ctShape then
      begin
        EditColorPicker.SelectedColor := GetShapeColor(ACol, ARow);
      end
      else
      begin
        CClr := Colors[ACol, ARow];
        if CClr = clNone then
          CClr := Color;

        EditColorPicker.SelectedColor := CClr;
      end;

      EditColorPicker.Visible := True;

      EditColorPicker.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditGridPicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditColorPicker.DoShowDropDown;

      EditCtrl := EditColorPicker;
    end;
  edImagePickerDropDown:
    begin
      EditMode := true;

      EditImagePicker.DropDownFooter.Assign(ControlLook.DropDownFooter);
      EditImagePicker.DropDownHeader.Assign(ControlLook.DropDownHeader);
      EditImagePicker.SetComponentStyle(FStyle);

      EditImagePicker.OnDropDownHeaderButtonClick := DoHeaderButtonClick;
      EditImagePicker.OnDropDownFooterButtonClick := DoFooterButtonClick;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditImagePicker.Top := r.Top;
      EditImagePicker.Left := r.Left;

      EditImagePicker.Width := 0;
      EditImagePicker.Height := 0;
      EditImagePicker.Enabled := True;
      EditImagePicker.BorderStyle := bsNone;

      EditImagePicker.Width := CellWidth;
      EditImagePicker.Height := CellHeight;

      if (CellTypes[OCol, ARow] in [ctImageList, ctDataImage]) then
      begin
        EditImagePicker.Images := GridImages;

        if EditImagePicker.Items.Count = 0 then
        begin
          EditImagePicker.AddImagesFromImageList;
        end;

        if CellTypes[OCol, ARow] = ctImageList then
        begin
          GetImageIdx(OCol, ARow, ValI);
          EditImagePicker.ImageIndex := ValI;
        end
        else
          EditImagePicker.ImageIndex := Ints[OCol, ARow];
      end;

      if EditImagePicker.ImageIndex <> -1 then
        EditImagePicker.Text := EditImagePicker.Items[EditImagePicker.ImageIndex].Caption
      else
        EditImagePicker.Text := '';

      EditImagePicker.Visible := True;

      EditImagePicker.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditGridPicker.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FMouseActions.DirectComboDrop then
        EditImagePicker.DoShowDropDown;

      EditCtrl := EditImagePicker;
    end;
  /// EDITORINTEGRATION

  {$IFDEF TMSUNICODE}
  edUniEdit:
    begin
      EditMode := True;
      EditUni.ReCreate;
      EditUni.Top := r.Top + 1 + XYOffset.Y;
      EditUni.Left := r.Left + 1 + XYOffset.X;
      EditUni.Width := CellWidth - 2 - XOffsetSize;
      EditUni.Height := CellHeight - 2 - YOffsetSize;
      EditUni.Visible := True;
      EditUni.Enabled := True;
      EditUni.Color := EditColor;
      EditUni.Font.Assign(Canvas.Font);

      wt := WideCells[ACol, ARow];

      if Assigned(OnGetEditWideText) then
        OnGetEditWideText(self, ACol, ARow, wt);

      EditUni.Text := wt;
      EditUni.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditUni.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := EditUni;
    end;
  edUniMemo:
    begin
      EditMode := True;
      MemoUni.ReCreate;
      MemoUni.Top := r.Top + 1 + XYOffset.Y;
      MemoUni.Left := r.Left + 1 + XYOffset.X;
      MemoUni.Width := CellWidth - 2 - XOffsetSize;
      MemoUni.Height := CellHeight - 2 - YOffsetSize;
      MemoUni.Visible := True;
      MemoUni.Enabled := True;
      MemoUni.Color := EditColor;
      MemoUni.Font.Assign(Canvas.Font);

      wt := WideCells[ACol, ARow];

      if Assigned(OnGetEditWideText) then
        OnGetEditWideText(self, ACol, ARow, wt);

      MemoUni.Text := wt;
      MemoUni.SetFocus;
      if length(wt) > 0 then      
        MemoUni.SelectAll;

      if FStartEditChar <> #0 then
        PostMessage(MemoUni.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := MemoUni;
    end;
  edUniEditBtn:
    begin
      EditMode := True;
      EditBtnUni.ReCreate;
      EditBtnUni.Top := r.Top;
      EditBtnUni.Left := r.Left;
      EditBtnUni.Width := CellWidth;
      EditBtnUni.Height := CellHeight;
      EditBtnUni.Visible := True;
      EditBtnUni.Enabled := True;
      EditBtnUni.Color := EditColor;
      EditBtnUni.Font.Assign(Canvas.Font);

      wt := WideCells[ACol, ARow];

      if Assigned(OnGetEditWideText) then
        OnGetEditWideText(self, ACol, ARow, wt);

      EditBtnUni.Text := wt;
      EditBtnUni.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditBtnUni.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := EditBtnUni;
    end;


  edUniComboEdit,edUniComboList:
    begin
      SetLength(ws,combouni.Items.Count);
      SetLength(wo,combouni.Items.Count);

      // copy widestrings as control recreate causes to push items back to 8bit
      for i := 1 to combouni.Items.Count do
      begin
        ws[i - 1] := combouni.Items[i - 1];
        wo[i - 1] := combouni.Items.Objects[i - 1];
      end;

      EditMode := True;

      ComboUni.Top := r.Top;
      ComboUni.Left := r.Left;

      ComboUni.Width := 0;
      ComboUni.Height := 0;
      ComboUni.DroppedDown := False;
      ComboUni.Enabled := True;

      if EditControl = edUniComboEdit then
        ComboUni.Style := csDropDown
      else
      begin
        ComboUni.Style := csDropDownList;
      end;

      ComboUni.Items.Clear;

      for i := 0 to High(ws) do
      begin
        ComboUni.items.AddObject(ws[i],wo[i]);
      end;

      wt := WideCells[ACol, ARow];

      if Assigned(OnGetEditWideText) then
        OnGetEditWideText(self, ACol, ARow, wt);

      if EditControl= edUniComboList then
        ComboUni.Itemindex := ComboUni.Items.IndexOf(wt);

      if ((FComboIdx = -1) and (ComboUni.ItemIndex = -1)) then
        ComboUni.ItemIndex := 0
      else
        if (ComboUni.ItemIndex = -1) then
          ComboUni.ItemIndex := FComboIdx;

      ComboUni.Width := CellWidth;
      ComboUni.Height := CellHeight + (ComboUni.DropDownCount+1) * ComboUni.ItemHeight;

      ComboUni.Text := wt;
      ComboUni.Color := EditColor;

      ComboUni.Visible := True;
      ComboUni.Font.Assign(Canvas.Font);
      ComboUni.Flat := Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007];
      ComboUni.Etched := Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007];

      if FNavigation.AutoComboDropSize then
        ComboUni.SizeDropDownWidth;

      ComboUni.SetFocus;
      ComboUni.DroppedDown := FMouseActions.DirectComboDrop or ControlLook.DropDownAlwaysVisible;

      if ComboUni.DropWidth > 0 then
        SendMessage(ComboUni.Handle,CB_SETDROPPEDWIDTH,ComboUni.DropWidth,0);

      EditCtrl := ComboUni;
    end;
  {$ENDIF}

  edSpinEdit,edFloatSpinEdit,edTimeSpinEdit,edDateSpinEdit:
    begin
      EditMode := True;
      EditSpin.ReCreate;
      EditSpin.Top := r.Top;
      EditSpin.Left := r.Left;
      EditSpin.Width := CellWidth;
      EditSpin.Height := CellHeight;
      EditSpin.Visible := True;
      EditSpin.Enabled := True;
      EditSpin.Color := EditColor;
      EditSpin.ExcelStyleDecimalSeparator := ExcelStyleDecimalSeparator;

      DoGetEditorProp(ACol,ARow,EditLink);

      s := GetEditText(OCol,ARow);

      case EditControl of
      edSpinEdit:
        begin
          Val(s,ValI,Err);
          EditSpin.Value := ValI;
          EditSpin.SpinType := sptNormal;
        end;
      edFloatSpinEdit:
        begin
          s := RemoveSeps(s);
          Val(s,ValD,Err);
          EditSpin.FloatValue := ValD;
          EditSpin.SpinType := sptFloat;
        end;
      edTimeSpinEdit:
        begin
          EditSpin.Text := GetEditText(ACol,ARow);
          EditSpin.SpinType := sptTime;
        end;
      edDateSpinEdit:
        begin
          try
            if s = '' then
              EditSpin.DateValue := Now
            else
              EditSpin.DateValue := StrToDate(s);
          except
            EditSpin.DateValue := Now;
          end;
          EditSpin.SpinType := sptDate;
        end;
      end;
      EditSpin.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(EditSpin.Handle,WM_CHAR,Ord(FStartEditChar),0);

      if FSpinUpClick then
      begin
        EditSpin.DoInc(false);
        EditSpin.DoClick(true);
      end;

      if FSpinDnClick then
      begin
        EditSpin.DoDec(false);
        EditSpin.DoClick(false);
      end;

      FSpinUpClick := false;
      FSpinDnClick := false;
      EditCtrl := EditSpin;
    end;

  edDateTimeEdit:
    begin
      if ComCtrlOk then
      begin
        EditMode := True;
        EditDateTime.Parent := Self;

        s := GetEditText(OCol,ARow);

        if s = '' then
        begin
          dt := Now;
        end
        else
        begin
          try
            //dt := VarToDateTime(s);
            dt := StrToDateTime(s);
          except
            dt := Now;
          end;
        end;

        FOriginalDateTime := dt;
        EditDateTime.DateTime := dt;
        EditDateTime.Kind := dkDateTime;
        EditDateTime.BorderStyle := bsNone;

        EditDateTime.Top := r.Top;
        EditDateTime.Left := r.Left;
        EditDateTime.Width := CellWidth;

        if CellHeight > EditDateTime.Height then
          EditDateTime.Height := CellHeight;

        DoGetEditorProp(ACol,ARow,EditLink);

        EditDateTime.Enabled := True;
        EditDateTime.Visible := True;
        EditDateTime.Color := EditColor;
        EditDateTime.SetFocus;
      end;
    end;

  edDateEdit,edDateEditUpdown:
    begin
      if ComCtrlOk then
      begin
        EditMode := True;
        EditDate.Parent := Self;
        EditDate.ReCreate;

        s := GetEditText(OCol,ARow);

        try
          if s = '' then
          begin
            if (EditDate.MaxDate = 0) and (EditDate.MinDate = 0) then
              EditDate.Date := Now
            else
            begin
              if Now > EditDate.MaxDate then
                EditDate.Date := EditDate.MaxDate
              else
                if Now < EditDate.MinDate then
                  EditDate.Date := EditDate.MinDate
                    else
                      EditDate.Date := Now;
            end;
          end
          else
          begin
            if Assigned(FOnCustomStrToDate) then
            begin
              dt := Now;
              FOnCustomStrToDate(Self, S, dt);
              EditDate.Date := dt;
            end
            else
            begin
              dt := VarToDateTime(s);
              //dt := StrToDateTime(s);

              if EditDate.MaxDate <> 0 then
                if dt > EditDate.MaxDate then
                  dt := EditDate.MaxDate - 1;

              if EditDate.MinDate <> 0 then
                if dt <= EditDate.MinDate then
                  dt := EditDate.MinDate + 1;

              EditDate.Date := dt;
            end;
          end;
        except
          EditDate.Date := Now;
        end;

        EditDate.Kind := dtkDate;

        if EditControl = edDateEditUpdown then
          EditDate.DateMode := dmUpDown
        else
          EditDate.DateMode := dmComboBox;

        DoGetEditorProp(ACol,ARow,EditLink);

        EditDate.Top := r.Top;
        EditDate.Left := r.Left;
        EditDate.Width := CellWidth;

        if CellHeight <> EditDate.Height then
          EditDate.Height := CellHeight;

        EditDate.Enabled := True;
        EditDate.Visible := True;
        EditDate.Color := EditColor;
        EditDate.SetFocus;

        if FMouseActions.DirectDateDrop then
          SendMessage(EditDate.Handle, WM_KEYDOWN, VK_F4, 0);

        if FStartEditChar <> #0 then
          PostMessage(EditDate.Handle,WM_CHAR,Ord(FStartEditChar),0);

        EditCtrl := EditDate;
      end;
   end;
  edTimeEdit:
    begin
      if ComCtrlOk then
      begin
        EditMode := True;
        EditDate.Parent := Self;
        EditDate.ReCreate;
        s := GetEditText(OCol,ARow);

        try
          if s = '' then
            EditDate.Time := Now
          else
            EditDate.Time := StrToTime(GetEditText(OCol,ARow));
        except
          EditDate.Time := Now;

        end;
        EditDate.Kind := dtkTime;
        EditDate.Top := r.Top;
        EditDate.Left := r.Left;
        EditDate.Height := CellHeight;
        EditDate.Width := CellWidth;
        EditDate.Enabled := True;
        EditDate.Visible := True;
        EditDate.Color := EditColor;

        DoGetEditorProp(ACol,ARow,EditLink);

        EditDate.SetFocus;

        EditCtrl := EditDate;
      end;
    end;
  edCheckBox:
    begin
      EditMode := True;
      EditCheck.ReCreate;
      EditCheck.Top := r.Top;
      EditCheck.Left := r.Left;
      EditCheck.Width := CellWidth;
      EditCheck.Height := CellHeight;
      EditCheck.Caption := GetEditText(OCol,ARow);
      EditCheck.Enabled := True;
      EditCheck.Checked := False;
      EditCheck.State := cbUnchecked;
      EditCheck.Visible := True;
      EditCheck.SetFocus;
   end;
  edEditBtn,edMaskEditBtn,edFloatEditBtn,edNumericEditBtn:
    begin
      EditMode := True;
      EditBtn.ReCreate;
      EditBtn.Top := r.Top;
      EditBtn.Left := r.Left;
      EditBtn.Width := CellWidth;
      EditBtn.Text := GetEditText(OCol,ARow);
      EditBtn.MaxLength := GetEditLimit;
      EditBtn.Visible := True;
      EditBtn.Enabled := True;
      EditBtn.Color := EditColor;
      EditBtn.ButtonWidth := ControlLook.DropDownButtonWidth + 2;

      DoGetEditorProp(ACol,ARow,EditLink);

      EditBtn.SetFocus;
      EditBtn.Height := CellHeight;

      //EditBtn.EditMask := '9999';
      if (EditControl = edMaskEditBtn) then
        EditBtn.EditMask := GetEditMask(ACol,ARow)
      else
        EditBtn.EditMask := '';

      if FStartEditChar <> #0 then
        PostMessage(EditBtn.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := EditBtn;
    end;
  edUnitEditBtn, edNumericUnitEditBtn, edFloatUnitEditBtn:
    begin
      EditMode := True;
      UnitEditBtn.ReCreate;
      UnitEditBtn.Top := r.Top;
      UnitEditBtn.Left := r.Left;
      UnitEditBtn.Width := CellWidth;
      s := GetEditText(OCol,ARow);
      UnitEditBtn.MaxLength := GetEditLimit;
      UnitEditBtn.UnitID := '';
      UnitEditBtn.Text := '';

      UnitEditBtn.TextAndUnit := s;

      DoGetEditorProp(ACol,ARow,EditLink);

      UnitEditBtn.Visible := True;
      UnitEditBtn.Enabled := True;
      UnitEditBtn.Color := EditColor;
      UnitEditBtn.SetFocus;
      UnitEditBtn.Height := CellHeight;

      if FStartEditChar <> #0 then
        PostMessage(UnitEditBtn.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := UnitEditBtn;
    end;
  edButton:
    begin
      EditMode := True;
      Gridbutton.ReCreate;
      Gridbutton.Top := r.Top - 1;
      Gridbutton.Left := r.Left - 1;
      Gridbutton.Width := CellWidth + 2;
      Gridbutton.Height := CellHeight + 2;
      Gridbutton.Text := GetEditText(OCol,ARow);
      DoGetEditorProp(ACol,ARow,EditLink);
      Gridbutton.Visible := True;
      Gridbutton.Enabled := True;
      Gridbutton.SetFocus;
      EditCtrl := GridButton;
    end;

  edRichEdit:
    begin
      EditMode := True;
      InplaceRichEdit.ReCreate;
      InplaceRichEdit.Parent := Self;
      InplaceRichEdit.BorderStyle := bsNone;
      InplaceRichEdit.HideSelection := False;

      InplaceRichEdit.Top := r.Top;
      InplaceRichEdit.Left := r.Left;
      InplaceRichEdit.Width := CellWidth;
      InplaceRichEdit.Height := CellHeight;

      DoGetEditorProp(ACol,ARow,EditLink);

      InplaceRichEdit.Lock;

      CellToRich(ACol, ARow, InplaceRichEdit);

      if Navigation.EditSelectAll then
      begin
        InplaceRichEdit.SelStart := 0;
        InplaceRichEdit.SelLength := Length(InplaceRichEdit.Text);
      end;

      InplaceRichEdit.Visible := True;
      InplaceRichEdit.Enabled := True;

      r := Rect(2,2,r.Right - r.Left - 2,r.Bottom - r.Top - 2);
      SendMessage(InplaceRichEdit.Handle,EM_SETRECT,0,LParam(@r));

      InplaceRichEdit.Color := EditColor;
      InplaceRichEdit.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(InplaceRichEdit.Handle,WM_CHAR,Ord(FStartEditChar),0);

      InplaceRichEdit.UnLock;
      EditCtrl := InplaceRichEdit;
    end;

  edCustom:
    begin
      if Assigned(EditLink) then
      begin
        EditMode := True;
        EditLink.FOwner := Self;
        EditLink.FEditCell := Point(ACol,ARow);

        if EditLink.EditStyle = esPopup then
        begin
          if EditLink.AutoPopupWidth then
            EditLink.PopupWidth := r.Right - r.Left;

          if (EditLink.FPopupForm = nil) then
          begin
            PForm := Application.FindComponent('gridform');
            if Assigned(PForm) then
              PForm.Free;

      	    EditLink.FPopupForm := TForm.Create(Application);
           	EditLink.FPopupForm.Name := 'gridform';
          end;

          if ((EditLink.PopupLeft <> -1) and (EditLink.PopupTop <> -1)) then
            pt := Point(EditLink.PopupLeft,EditLink.PopupTop)
          else
            pt := ClientToScreen(Point(r.Left,r.Top));

          {$IFDEF DELPHI9_LVL}
          EditLink.FPopupForm.Left := pt.x;
          EditLink.FPopupForm.Top := pt.y;
          {$ENDIF}

          EditLink.FPopupForm.Left := pt.x;
          EditLink.FPopupForm.Top := pt.y;

          EditLink.FPopupForm.OnDeactivate := EditLink.FormExit;
          EditLink.FPopupForm.Width := 0;
          EditLink.FPopupForm.Height := 0;
          EditLink.FPopupForm.FormStyle := fsStayOnTop;

          EditLink.FPopupForm.BorderStyle := bsNone;
          EditLink.FPopupForm.Show;

          {$IFDEF DELPHI9_LVL}
          EditLink.FPopupForm.Left := pt.x;
          EditLink.FPopupForm.Top := pt.y;
          {$ENDIF}

          EditLink.FPopupForm.Width := EditLink.FPopupWidth;
          EditLink.FPopupForm.Height := EditLink.FPopupHeight;

          EditLink.CreateEditor(EditLink.FPopupForm);
        end
        else
        begin
          EditLink.CreateEditor(Self);
        end;

        if EditLink.EditStyle = esPopup then
          EditLink.SetRect(Rect(0,0,EditLink.FPopupWidth,EditLink.FPopupHeight))
        else
          EditLink.SetRect(Rect(r.Left,r.Top,r.Right,r.Bottom));

        EditLink.SetVisible(True);

        EditLink.SetCellProps(EditColor,EditFont);

        EditLink.SetProperties;

        DoGetEditorProp(ACol,ARow,EditLink);

        EwT := EditWithTags;

        if EditLink.WantHTML then
          EditWithTags := true;

        EditLink.SetEditorValue(GetEditText(OCol,ARow));
        EditLink.SetFocus(True);

        EditWithTags := EwT;

        EditLink.SetFocus(True);

        FStartEditChar_old := FStartEditChar;

        FEditActive := True;
        FStartEditChar := FStartEditChar_old;

        if FStartEditChar <> #0 then
        begin
          if (EditLink.GetEditControl <> nil) then
            PostMessage(EditLink.GetEditControl.Handle,WM_CHAR,Ord(FStartEditChar),0);
        end;

        EditCtrl := EditLink.GetEditControl;
      end;
    end;
  end;
  FStartEditChar := #0;

  (*
  if Assigned(PopupToolBar) and (PopupToolBarMode = tbEditedCell) then
  begin
    Objects[Col,Row] := Objects[Col,Row];
    FToolBarPopupCell.X := Col;
    FToolBarPopupCell.Y := Row;
    r := CellRect(Col,Row);
    PopupToolBar.Grid := Self;
    PopupToolBar.GridCell := FToolBarPopupCell;
    PopupToolBar.Show(ClientToScreen(Point(r.Left, r.Top - 44)));
  end;
  *)

end;

procedure TAdvStringGrid.RestoreCache;
begin
  Cells[RemapCol(Col),Row] := FCellCache;
  //cause an edit update when cell is remapped due to hidden Column
  Cells[Col,Row] := Cells[Col,Row];
end;

function TAdvStringGrid.ShouldHandleTab: Boolean;
begin
  Result := (goTabs in Options) or Assigned(OnCellValidate) or Assigned(OnCellValidateWide);
end;

function TAdvStringGrid.CanEditShow: Boolean;
var
  RCol: Integer;
  BC: TPoint;
begin
  Result := False;

  if FValidating then
    Exit;

  Result := inherited CanEditshow;

  if csDesigning in ComponentState then
    Exit;

  RCol := RemapCol(Col);
  BC := BaseCell(RCol,Row);

  if Result and not EditMode and HasStaticEdit(BC.X,BC.Y) then
  begin
    Result := False;
    Exit;
  end;

  if Result and not EditMode then
  begin
    FNoEditChange := true;

    FCellCache := GetCurrentCell;

    EditControl := FDefaultEditor;

    GetCellEditor(BC.X,BC.Y,EditControl);

    if (EditControl = edNone) then
    begin
      Result := False;
      Exit;
    end;

    EditMode := True;
    if not (EditControl in [edNormal,edValidChars,edNumeric,edPositiveNumeric,edFloat,edPositiveFloat,edCapital,
      edMixedCase,edPassword,edUpperCase,edLowerCase]) then
    begin
      BC := BaseCell(Col,Row);
      ShowEditControl(BC.X,BC.Y);
      FEntered := True;
      Result := False;

      if FocusHelper.Enabled then
      begin
        FocusGrid := Self;
        ShowFocusHelper(CellRect(Col,Row));
      end;
    end
    else
      if Result then
        FShowEditProcess := True;
  end;

  if Result then
  begin
    FEntered := True;
    FEditing := True;
  end;

  if Result and FocusHelper.Enabled then
  begin
    FocusGrid := Self;
    ShowFocusHelper(CellRect(Col,Row));
  end;

  (*
  if Result and Assigned(PopupToolBar) and (PopupToolBarMode = tbEditedCell) then
  begin
    Objects[Col,Row] := Objects[Col,Row];
    FToolBarPopupCell.X := Col;
    FToolBarPopupCell.Y := Row;
    r := CellRect(Col,Row);
    PopupToolBar.Grid := Self;
    PopupToolBar.GridCell := FToolBarPopupCell;
    PopupToolBar.Show(ClientToScreen(Point(r.Left, r.Top - 44)));
  end;
  *)
end;

function TAdvStringGrid.CanShowFixedDropDown(ACol: integer): boolean;
begin
  Result := true;
  if Assigned(FOnCanShowFixedDropDown) then
    FOnCanShowFixedDropDown(Self,ACol,Result);
end;

function TAdvStringGrid.CanShowSelection: Boolean;
begin
  Result := ShowSelection and (not AutoHideSelection or (AutoHideSelection and (GetFocus = Handle)));
end;

function TAdvStringGrid.CanTabToNextRow: boolean;
begin
  Result := true;
end;

procedure TAdvStringGrid.DoStartBlockFocus;
begin
  if Assigned(FOnStartBlockFocus) then
    FOnStartBlockFocus(Self);
end;

procedure TAdvStringGrid.DoEndBlockFocus;
begin
  if Assigned(FOnEndBlockFocus) then
    FOnEndBlockFocus(Self);
end;

procedure TAdvStringGrid.DoCellScroll(ACol,ARow: Integer; ScrollPosition, ScrollMin,ScrollMax: integer);
begin
  if Assigned(OnScrollCell) then
    OnScrollCell(Self, FScrollCol, FScrollRow, FScrollBar.Position, FScrollBar.Min, FScrollBar.Max);
end;

procedure TAdvStringGrid.DoCellChanging(ACol,ARow: integer; var CanChange: Boolean);
begin
  if (ACol <> Col) and Assigned(FOnColChanging) then
    FOnColChanging(Self,Col,ACol,Canchange);
  if (ARow <> Row) and Assigned(FOnRowChanging) then
    FOnRowChanging(Self,Row,ARow,Canchange);



  if ((ACol <> Col) or (ARow <> Row)) and Assigned(FOnCellChanging)
    and not FDisableChange then
    FOnCellChanging(Self,Row,Col,ARow,ACol,CanChange);
end;

function TAdvStringGrid.SelectCell(ACol, ARow: LongInt): Boolean;
var
  CanEdit: Boolean;
  CanChange: Boolean;
  ECol, ERow, OCol, ORow, OSC,OSR: Integer;
  IsNormalEdit: Boolean;
  R: TRect;
  OrgCellVal, OrgStr: string;
  pt: TPoint;
  oldsel: TGridRect;
  sph: integer;
begin
  oldsel := Selection;

  if (ACol < 0) or (ARow < 0) then
  begin
    Result := false;
    Exit;
  end;

  if FForceSel then
  begin
    // still update row indicator when needed
    if Assigned(FRowIndicator) and (FixedCols > 0) then
    begin
      if not FRowIndicator.Empty then
      begin
        RepaintCell(0,Row);
        RepaintCell(0,ARow);
      end;
    end;

    Result := true;
    Exit;
  end;

  if not (Parent is TWinControl) then
  begin
    Result := true;
    Exit;
  end;

  CanChange := True;
  Result := False;
  FEditText := Cells[ACol,ARow];

  sph := 0;
  if SearchFooter.Visible then
    sph := SearchPanel.Height + 2;

  // floating bottomrow
  if FloatingFooter.Visible then
  begin
    if FloatingFooter.FooterStyle in [fsColumnPreview, fsCustomPreview, fsCustomPaint] then
    begin
      FFooterPanel.Invalidate;

      R := CellRect(ACol,ARow);
      if (R.Bottom > ClientRect.Bottom - FloatingFooter.Height +2 - sph) and
        (ARow < RowCount) then
        TopRow := TopRow + 1;
    end
    else
    begin
      if not IsDSEdit then
      begin

        if ARow >= TopRow + VisibleRowCount then
        begin
          TopRow := ARow - VisibleRowCount + FixedRows;
        end;

        R := CellRect(ACol,ARow);
        if (R.Bottom > ClientRect.Bottom - FloatingFooter.Height + 2 - sph) and
          (ARow < RowCount - 1) then
        begin
          TopRow := TopRow + 1;
        end;

        if (ARow = RowCount - 1) then
          Exit;
      end;
    end;
  end;

  // floating bottomrow
  if SearchFooter.Visible then
  begin
    R := CellRect(ACol,ARow);
    while (R.Bottom > ClientRect.Bottom - SearchPanel.Height + 2) and
      (ARow <= RowCount - 1) and (TopRow < RowCount - 1) do
    begin
      TopRow := TopRow + 1;
      R := CellRect(ACol,ARow);
    end;
  end;

  // invalid coordinates
  if (ACol < 0) or (ARow < 0) then
    Exit;

  // force selection on base cell of merged cells
  if IsMergedNonBaseCell(ACol,ARow) {and not (goRangeSelect in Options)} then
  begin
    pt := BaseCell(ACol,ARow);
    // select base cell instead
    MoveColRow(pt.x,pt.Y,true,true);
    // Col := pt.X;
    // Row := pt.Y;
    RepaintCell(pt.x,pt.y);

    if MouseActions.DirectEdit or (ControlLook.DropDownAlwaysVisible and HasCombo(ACol,ARow)) then
      ShowEditor;

    Exit;
  end;

  // prevent selection of first cell when nodes are used
  if ((ACol = 0) and (FNumNodes > 0) and not (goRowSelect in Options)) or not CanChange then
    Exit;

  // prevent selection of disabled rows
  if FUseEnabledRows and Navigation.SkipDisabledRows then
  begin
    if not RowEnabled[ARow] then
    begin
      Result := false;
      Exit;
    end;
  end;

  OSC := Selection.Left;
  OSR := Selection.Top;
  OCol := Col;
  ORow := Row;

  ERow := Row;
  ECol := RemapCol(ACol);

  // Moved original cell value assignment after cell validation
  OrgCellVal := Cells[ECol,ARow];

  IsNormalEdit := Assigned(NormalEdit);

  if IsNormalEdit then
    IsNormalEdit := (GetFocus = NormalEdit.Handle);

  if not HasStaticEdit(ECol,ARow) then
  begin
    CanEdit := (goEditing in Options) or FEditDisable;

    GetCellReadOnly(ECol,ARow,CanEdit);

    if CanEdit and (MouseActions.DirectEdit) then
    begin
      EditControl := FDefaultEditor;
      if GetEditorNone(ECol,ARow) then
      begin
        CanEdit := false;
      end;
    end;

    if MouseActions.EditOnDblClickOnly then
      CanEdit := false;

    if CanEdit then
    begin
      // Moved inside CanEdit condition
      FEditDisable := False;
      if not (goEditing in Options) then
      begin
        FEditChange := True;
        if not FEditing then
          InitValidate(ACol,ARow);

        if (goRowSelect in Options) and (MouseActions.RangeSelectAndEdit) then
          Options := Options - [goRowSelect];

        Options := Options + [goEditing];
      end;

      if FEditing then
      begin
        HideInplaceEdit;
        OrgCellVal := Cells[ECol,ARow];
      end;
    end
    else
    begin
      if FEditing then
      begin
        HideInplaceEdit;
        OrgCellVal := Cells[ECol,ARow];
      end;

      if (goEditing in Options) then
      begin
        EditMode := false;
        FEditDisable := True;
        FEditChange := True;
        Options := Options - [goEditing];
        EditorMode := false;
      end;
    end;
  end
  else
  begin
    CanEdit := true;
    GetCellReadOnly(ECol,ARow,CanEdit);

    if not FEditDisable then
      FEditDisable := (not CanEdit) and ((goEditing in Options) or MouseActions.RangeSelectAndEdit);

    if not (goEditing in Options) and not (goRowSelect in Options) and CanEdit then
    begin
      FEditChange := True;
      Options := Options + [goEditing];
    end;
  end;

  if FEditing and not IsNormalEdit then
  begin
    OrgStr := OriginalCellValue;
    if IsWideCell(ECol,Row) then
      Result := ValidateCellWide(FEditWideText)
    else
      Result := ValidateCell(CurrentCell);

    CanChange := true;
    DoCellChanging(ACol,ARow,CanChange);

    if not CanChange then
      Result := false;

    if Result then
      Result := inherited SelectCell(ACol,ARow);

    if not Result then
      OrgCellVal := OrgStr;
  end
  else
  begin
    if EditMode and Navigation.AlwaysEdit then
      HideInplaceEdit;;

    DoCellChanging(ACol,ARow,CanChange);

    if IsFixed(ACol,ARow) or not CanChange then
    begin
      Result := (CanChange and (goRowSelect in Options)) or (FixedRowAlways and (RowCount = FixedRows));
    end
    else
      Result := inherited SelectCell(ACol,ARow);
  end;

  if Assigned(FRowIndicator) and (FixedCols > 0) then
  begin
    if not FRowIndicator.Empty then
    begin
      RepaintCell(0,ERow);
      RepaintCell(0,ARow);
    end;
  end;

  if FISelect <> nil then
    FISelect.SelectionChange(Col,ARow);

  if ActiveCellShow then
  begin
    UpdateActiveCells(OCol,ORow,ACol,ARow);
    if (OSC <> OCol) and (OSR <> ORow) then
      UpdateActiveCells(OSC,OSR,ACol,ARow);
  end;

  if ActiveRowShow then
  begin
    RepaintRow(ARow);
    RepaintRow(OSR);
  end;

  if SelectionRectangle then
  begin
    RepaintRect(TRect(Selection));
  end;

  if not (csLoading in ComponentState) then
  begin
    if (FOldRowSel <> ARow) and Assigned(FOnRowChanged) {and (FUpdateCount = 0)} then
    begin
      FOnRowChanged(Self,FOldRowSel,ARow);
      FOldRowSel := ARow;
    end;
  end;

  if HasCustomCellBorder then
  begin
    RepaintRect(Rect(FixedRows, oldsel.Top, FixedRows + VisibleColCount, oldsel.Bottom));
  end;

  (*
  if CanChange then
  begin
    FScrollBar.Visible := false;

    if HasScrollbar(ACol,ARow) then
    begin
      R := CellRect(ACol,ARow);
      FScrollBar.Position := GetScrollPosition(ACol,ARow);
      FScrollBar.Top := R.Top + GridLineWidth;
      FScrollBar.Left := R.Right - FScrollBar.Width - GridLineWidth;
      FScrollBar.Height := R.Bottom - R.Top - 2 * GridLineWidth;
      FScrollBar.Visible := true;
      //CellControlsUpdate;
    end;
  end;
  *)

  if (ScrollType = ssMetro) then
  begin
    if Assigned(vscrlctrl) then
      vscrlctrl.Invalidate;
    if Assigned(hscrlctrl) then
      hscrlctrl.Invalidate;
  end;

  FCellCache := OrgCellVal;

(*
  if Assigned(SyncGrid.Grid) then
  begin
    if SyncGrid.SelectionColumn then
      SyncGrid.Grid.Col := ACol;

    if SyncGrid.SelectionRow then
      SyncGrid.Grid.Row := ARow;
  end;
*)
  {
  if SearchFooter.Visible then
  begin
    r := CellRect(ACol,ARow);
    if (r.Bottom > Height - SearchPanel.Height) then
    begin
      TopRow := TopRow + 1;
    end;
  end;
  }
end;

procedure TAdvStringGrid.UpdateActiveCells(co,ro,cn,rn: Integer);
begin
  if FixedRows > 0 then
    RepaintCell(co,FixedRows - 1);
  if Fixedcols > 0 then
    RepaintCell(FixedCols - 1,ro);
  if FixedRows > 0 then
    RepaintCell(cn,FixedRows - 1);
  if FixedCols > 0 then
    RepaintCell(FixedCols - 1,rn);
end;

function TAdvStringGrid.FreeCellGraphic(ACol,ARow: Integer): Boolean;
var
  cg:TCellGraphic;
begin
  Result := False;

  cg := GetCellGraphic(ACol,ARow);

  if cg = nil then
    Exit
  else
  begin
    GraphicObjects[ACol,ARow] := nil;
    if not (cg.CellType in [ctVirtCheckBox,ctRowCheckBox]) then
      cg.Free;
  end;
  if not (csDestroying in ComponentState) then
    RepaintCell(ACol,ARow);
  Result := True;
end;

function TAdvStringGrid.RemoveCellGraphic(ACol,ARow: Integer;celltype:TCellType): Boolean;
begin
  Result := False;
  if CellTypes[ACol,ARow] = celltype then
  begin
    Result := FreeCellGraphic(ACol,ARow);
  end;
end;

function TAdvStringGrid.CreateCellGraphic(ACol,ARow: Integer): TCellGraphic;
var
  cg: TCellGraphic;
  rc: Integer;

begin
  cg := GetCellGraphic(ACol,ARow);

  if Assigned(cg) then
    cg.Free;

  cg := TCellGraphic.Create;
  if (Cells[ACol,ARow] = '') then
  begin
    // make sure cell gets allocated
    Cells[ACol,ARow] := ' ';
    GraphicObjects[ACol,ARow] := cg;
    Cells[ACol,ARow] := '';
  end
  else
    GraphicObjects[ACol,ARow] := cg;

  //++2.4.0.4 -> update correct cell for hidden columns
  if FNumHidden > 0 then
  begin
    rc := RemapColInv(ACol);
    if ACol <> rc then
      RepaintCell(rc,ARow);
  end;

  Result := cg;
end;

function TAdvStringGrid.GetCellGraphic(ACol,ARow: Integer): TCellGraphic;
var
  ry: Integer;

begin
  Result := nil;

  if Assigned(GraphicObjects[ACol,ARow]) then
  begin
    if not (GraphicObjects[ACol,ARow] is TCellGraphic) then
      Exit;
    Result := (GraphicObjects[ACol,ARow] as TCellGraphic);
  end;

  if (ACol = 0) and (MouseActions.HotmailRowSelect) then
  begin
    FCellGraphic.CellType := ctRowCheckBox;

    if ARow = 0 then
    begin
      if (FSelectedRows.Count = 0) or (FSelectedRows.Count >= RowCount - FixedRows) then
        FCellGraphic.CellAngle := 0
      else
        FCellGraphic.CellAngle := 1;
      // grayed
      FCellGraphic.CellBoolean := (FSelectedRows.Count >= RowCount - FixedRows);
    end
    else
      FCellGraphic.CellAngle := 0;

    FCellGraphic.CellTransparent := ControlLook.ControlStyle = csFlat;

    ry := RealRowIndex(Arow);
    if ARow <> 0 then
      FCellGraphic.CellBoolean := RowSelect[ry];

    Result := FCellGraphic;
  end;
end;

function TAdvStringGrid.GetCellGraphicSize(ACol,ARow: Integer): TPoint;
begin
  Result := GetCellGraphicSizeEx(ACol,ARow,0);
end;

function TAdvStringGrid.GetCellGraphicSizeEx(ACol,ARow,Padding: Integer): TPoint;
begin
  Result := GetCellGraphicSizeEx(Canvas, ACol, ARow, Padding, 1);
end;

function TAdvStringGrid.GetCellGraphicSizeEx(ACanvas: TCanvas; ACol, ARow, Padding: Integer; ResFactor: double): TPoint;
var
  cg: TCellGraphic;
  w,h,i,cnt: Integer;
  s: string;
  CDIM: TPoint;
  r: TRect;
  NoHaFull: boolean;
  io: TInterfacedPersistent;
  icg: ICellGraphic;
  FImages: TCustomImageList;

begin
  Result.x := 0;
  Result.y := 0;

  //if ResFactor = 0 then
  //  ResFactor := 1;


  NoHaFull := false;

  cg := CellGraphics[ACol,ARow];
  if cg = nil then
    Exit;

  w := 0;
  h := 0;
  s := Cells[ACol,ARow];

  case cg.celltype of
  ctIcon:
  begin
    if cg.CellHAlign in [haBeforeText,haAfterText] then
      w := cg.CellIcon.Width
    else
      if s = '' then
        w := cg.CellIcon.Width;
    h := cg.CellIcon.Height;
  end;

  ctPicture:
  begin
    CDIM := CellSize(ACol,ARow);
    CDIM.Y := CDIM.Y - 1 - YOffsetSize - Padding;
    CDIM.X := CDIM.X - 1 - XOffsetSize;
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    w := Result.x;
    h := Result.y;
  end;

  ctFilePicture:
  begin
    CDIM := CellSize(ACol,ARow);
    CDIM.Y := CDIM.Y - 1 - YOffsetSize - Padding;
    CDIM.X := CDIM.X - 1 - XOffsetSize;
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    w := Result.x;
    h := Result.y;
  end;

  ctButton,ctBitButton:
  begin
    w := cg.CellIndex and $FFFF;
    h := (cg.CellIndex and $FFFF0000) shr 16;

    if (s <> '') then
    begin
      if (cg.CellHAlign in [haCenter]) then
        w := 0;

      if (cg.CellHAlign in [haFull]) then
        w := Round((ACanvas.TextWidth(cg.FCellText) + 4) / ResFactor);

      if not (cg.CellVAlign in [vaAboveText,vaUnderText]) and not (cg.CellHAlign in [haBeforeText, haAfterText]) then
        h := 0;

      if (cg.CellVAlign in [vaAboveText,vaUnderText]) then
        w := 0;
    end
    else
    begin
      if (cg.CellHAlign in [haFull]) then
      begin
        if IsFixed(Acol,ARow) then
          ACanvas.Font.Assign(FixedFont)
        else
          ACanvas.Font.Assign(Font);

        w := Round((ACanvas.TextWidth(cg.FCellText) + 8)/ResFactor);
        NoHaFull := cg.FCellText <> '';
      end;
    end;
  end;

  ctInterface:
  begin
    io := TInterfacedPersistent(cg.CellBitmap);
    if io.GetInterface(ICellGraphic, icg) then
    begin
      w := icg.CellWidth;
      h := icg.CellHeight;
    end;

    if (w = 0) or (h = 0)  then
    begin
      CDIM := CellSize(ACol,ARow);

      w := CDIM.x;
      h := CDIM.y;
    end;
  end;
  
  ctBitmap:
  begin
    if cg.CellHAlign in [haBeforeText,haAfterText] then
      w := cg.CellBitmap.Width
    else
      if s = '' then
        w := cg.CellBitmap.Width;

    if cg.CellVAlign in [vaAboveText,vaUnderText] then
      h := cg.CellBitmap.Height
    else
      if s = '' then
        h := cg.CellBitmap.Height

  end;
  ctImageList,ctDataImage:
  begin
    FImages := GetCellImageList(ACol,ARow);

    if Assigned(FImages) then
    begin
      if cg.CellHAlign in [haBeforeText,haAfterText] then
        w := FImages.Width
      else
        if s = '' then
          w := FImages.Width;
      if cg.CellVAlign in [vaUnderText, vaAboveText] then
        h := FImages.Height
      else
        if s = '' then
          h := FImages.Height
    end;
  end;
  ctProgressPie:
  begin
    w := 20;
    h := 20;
  end;
  ctRadioButton:
  begin
    w := FControlLook.RadioSize;
    h := FControlLook.RadioSize;
  end;
  ctCheckbox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRowCheckBox:
  begin
    w := FControlLook.CheckSize;
    h := FControlLook.CheckSize;
  end;
  ctRadio:
  begin
    cnt := TStringList(cg.CellBitmap).Count;
    if not cg.CellBoolean then
    begin
      w := 12;
      for i := 1 to cnt do
      begin
        if 12 + ACanvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]) > w then
         w := 12 + ACanvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]);
      end;

      h := Max(16,Round(((3 + ACanvas.TextHeight('gh')) * cnt)/ResFactor));
    end
    else
    begin
      w := 0;
      h := ACanvas.TextHeight('gh');
      for i := 1 to TStringList(cg.CellBitmap).Count do
      begin
        w := w + 12 + ACanvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]);
      end;
    end;
  end;
  ctRating:
  begin
    W := 18 * cg.CellAngle;
    H := 16;
    NoHaFull := true;
  end;
  ctShape:
  begin
    W := DefaultRowHeight - 4;
    H := W;
  end;

  ctImages:
  begin
    FImages := GetCellImageList(ACol,ARow);

    if Assigned(FImages) then
    begin
      if cg.CellBoolean then
      begin
        w := CellImages[ACol,ARow].Count * FImages.Width;
        h := FImages.Height;
      end
      else
      begin
        h := CellImages[ACol,ARow].Count * FImages.Height;
        w := FImages.Width;
      end;
    end;
  end;
  end;

  if not NoHaFull then
  begin
    if (cg.CellVAlign = vaFull) or (cg.CellHAlign = haFull) then
    begin
      r := CellRect(ACol,ARow);
      if cg.CellVAlign = vaFull then
      begin
        h := r.Bottom - r.Top;
      end;
      if cg.CellHAlign = haFull then
      begin
        w := r.Right - r.Left;
      end;
    end;
  end;

  Result.x := w;
  Result.y := h;
end;

function TAdvStringGrid.GetPrintGraphicSize(ACol,ARow,CW,RH: Integer;ResFactor: Double): TPoint;
var
  cg: TCellGraphic;
  w,h,i: Integer;
  s: string;
  CDIM: TPoint;
  io: TInterfacedPersistent;
  icg: ICellGraphic;
  cr: TRect;
  FImages: TCustomImageList;

begin
  Result.x := 0;
  Result.y := 0;

  cg := CellGraphics[ACol,ARow];
  if cg = nil then
    Exit;

  w := 0;
  h := 0;
  s := Cells[ACol,ARow];
  CDIM := Point(CW,RH);

  case cg.celltype of
  ctIcon:
  begin
    w := cg.CellIcon.Width;
    h := cg.CellIcon.Height;
  end;

  ctPicture:
  begin
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    w := Round(Result.X);
    h := Round(Result.Y);
  end;

  ctFilePicture:
  begin
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    w := Round(Result.X);
    h := Round(Result.Y);
  end;

  ctButton,ctBitButton:
  begin
    w := cg.CellIndex and $FFFF;
    h := (cg.CellIndex and $FFFF0000) shr 16;
  end;

  ctInterface:
  begin
    io := TInterfacedPersistent(cg.CellBitmap);
    if io.GetInterface(ICellGraphic, icg) then
    begin
      w := icg.CellWidth;
      h := icg.CellHeight;

      if (w = 0) or (h = 0) then
      begin
        cr := CellRect(ACol, ARow);

        if (w = 0) then
          w := cr.Right - cr.Left;

        if (h = 0) then
          h := cr.Bottom - cr.Top;
      end;
    end;
  end;
  ctBitmap:
  begin
    w := cg.CellBitmap.Width;
    h := cg.CellBitmap.Height;
  end;
  ctDataImage:
  begin
    FImages := GetCellImageList(ACol,ARow);
    if Assigned(FImages) then
    begin
      w := FImages.Width;
      h := FImages.Height;
    end;
  end;
  ctImageList:
  begin
    FImages := GetCellImageList(ACol,ARow);
    if Assigned(FImages) then
    begin
      if cg.CellHAlign in [haBeforeText,haAfterText] then
        w := FImages.Width
      else
        if s = '' then
          w := FImages.Width;
      h := FImages.Height;
    end;
  end;
  ctRadioButton:
  begin
    w := FControlLook.RadioSize;
    h := FControlLook.RadioSize;
  end;
  ctCheckbox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRowCheckBox:
  begin
    w := FControlLook.CheckSize;
    h := FControlLook.CheckSize;
  end;
  ctProgressPie:
  begin
    w := 20;
    h := 20;
  end;
  ctNode:
  begin
    w := 20;
    h := 20;
  end;
  ctRadio:
  begin
    if not cg.CellBoolean then
    begin
      w := 12;
      for i := 1 to TStringList(cg.CellBitmap).Count do
      begin
        if 12 + Canvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]) > w then
         w := 12 + Canvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]);
      end;

      h := (Canvas.TextHeight('gh')) * TStringList(cg.CellBitmap).Count;
    end
    else
    begin
      w := 0;
      h := Canvas.TextHeight('gh');
      for i := 1 to TStringList(cg.CellBitmap).Count do
      begin
        w := w + 12 + Canvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]);
      end;

    end;
  end;
  ctImages:
  begin
    FImages := GetCellImageList(ACol,ARow);
    if Assigned(FImages) then
    begin
      if cg.CellBoolean then
      begin
        w := CellImages[ACol,ARow].Count * FImages.Width;
        h := FImages.Height;
      end
      else
      begin
        h := CellImages[ACol,ARow].Count * FImages.Height;
        w := FImages.Width;
      end;
    end;
  end;
  ctProgress,ctXPProgress:
  begin
    h := RowHeights[ARow];
    w := ColWidths[ACol];
  end;
  ctShape:
  begin
    h := RowHeights[ARow] - FXYOffset.Y * 2;
    w := h;
  end;
  end;

  Result.x := w;
  Result.y := h;
end;


procedure TAdvStringGrid.GetDisplText(c,r: Integer; var Value: string);
var
  ns: integer;
begin
  inherited;

  // auto URL handling

  if URLShowInText then
  begin
    if not MakeHTMLHyperlink(Value,'HTTP://',Value) then
      if not MakeHTMLHyperLink(Value,'WWW.',Value) then
        if not MakeHTMLHyperlink(Value,'MAILTO:',Value) then
          if not MakeHTMLHyperlink(Value,'HTTPS://',Value) then
            if not MakeHTMLHyperlink(Value,'NNTP://',Value) then
              if not MakeHTMLHyperlink(Value,'FILE://',Value) then
                MakeHTMLHyperlink(Value,'FTP://',Value);
  end;

  if Grouping.ShowGroupCount and (c = 1) and IsNode(r) then
  begin
    ns := (GetNodeSpan(r) - 1) - GetSubNodecount(r);

    if Grouping.GroupCountFormat <> '' then
      value := value + SysUtils.Format(Grouping.GroupCountFormat,[ns])
    else
      value := value + ' (' + IntToStr(ns)+')';
  end;
end;

function TAdvStringGrid.ShouldDrawSortIndicator(ACol, ARow: integer): boolean;
var
  csp: integer;
begin
  if IsMergedCell(ACol, ARow) then
  begin
    csp := CellSpan(ACol,ARow).Y;
    Result := (ARow + csp = SortSettings.Row);
  end
  else
    Result := (ARow = SortSettings.Row);

  Result := Result and ((SortSettings.Show) and (RowCount > FixedRows + 1));
end;

function TAdvStringGrid.HasNodes: Boolean;
begin
  Result := FNumNodes > 0;
end;

function TAdvStringGrid.NodeIndent(ARow: Integer): Integer;
begin
  Result := 0;

  if (FNumNodes > 0) and (ARow >= 0) then
  begin
    if HasCellProperties(0,ARow) then
      Result := CellProperties[0,ARow].NodeLevel * CellNode.NodeIndent;
  end;
end;

function TAdvStringGrid.GetCellType(ACol,ARow: Integer): TCellType;
begin
  Result := ctEmpty;
  if (ARow < 0) or (ACol < 0) then
    Exit;

  if Assigned(GraphicObjects[ACol,ARow]) then
  begin
    if not (GraphicObjects[ACol,ARow] is TCellGraphic) then
      Exit;
    Result := (GraphicObjects[ACol,ARow] as TCellGraphic).CellType;
  end;

  if (MouseActions.HotmailRowSelect) and (ACol = 0) then
    Result := ctRowCheckBox;
end;

function TAdvStringGrid.GetCellEmpty(ACol,ARow: Integer): boolean;
var
  cg: TCellGraphic;

begin
  Result := true;

  if (ARow < 0) or (ACol < 0) then
    Exit;

  if Assigned(GraphicObjects[ACol,ARow]) then
  begin
    if not (GraphicObjects[ACol,ARow] is TCellGraphic) then
      Exit;

    cg := GraphicObjects[ACol,ARow] as TCellGraphic;

    Result := (cg.CellType = ctNone) and (cg.CellComment = '');
  end;
end;


function TAdvStringGrid.GetCellImages(ACol,ARow: Integer): TIntList;
begin
  if CellTypes[ACol,ARow] = ctImages then
    Result := TIntList((GraphicObjects[ACol,ARow] as TCellGraphic).CellBitmap)
  else
    Result := nil;
end;

function TAdvStringGrid.GetCellImageIdx(ACol,ARow: Integer): Integer;
begin
  case CellTypes[ACol,ARow] of
  ctImageList:Result := TCellGraphic(GraphicObjects[ACol,ARow]).CellIndex;
  ctIcon:Result := Integer(TCellGraphic(GraphicObjects[ACol,ARow]).CellIcon);
  ctBitmap:Result := Integer(TCellGraphic(GraphicObjects[ACol,ARow]).CellBitmap);
  else
    Result := -1;
  end;
end;


function TAdvStringGrid.GetCellImageList(ACol, ARow: integer): TCustomImageList;
begin
  Result := FGridImages;
end;

procedure TAdvStringGrid.SetInts(ACol,ARow: Integer;const Value: Integer);
var
  rc: integer;
begin
  Cells[ACol,ARow] := IntToStr(Value);

  if NumHiddenColumns > 0 then
  begin
    rc := RemapColInv(ACol);
    RepaintCell(rc,ARow);
  end;
end;

function TAdvStringGrid.GetInts(ACol,ARow: Integer): Integer;
var
  s: string;
  Res,Err: Integer;
  d: double;

begin
  s := SysUtils.Trim(StrippedCells[ACol,ARow]);
  if (s = '') or (s = '-') then
    s := '0';

  if (pos(DecimalSeparator, s) > 0) or (pos(ThousandSeparator,s) > 0) then
  begin
    Val(s,d,Err);
    Res := Round(d);
  end
  else
    Val(s,Res,Err);

  if Err <> 0 then
    raise EAdvGridError.Create('Cell does not contain integer value');

  GetInts := Res;
end;

procedure TAdvStringGrid.SetAllInts(ACol,ARow: Integer;const Value: Integer);
begin
  AllCells[ACol,ARow] := IntToStr(Value);
end;

function TAdvStringGrid.GetAllInts(ACol,ARow: Integer): Integer;
var
  s: string;
  Res,Err: Integer;

begin
  s := SysUtils.Trim(AllCells[ACol,ARow]);
  if (s = '') or (s = '-') then
    s := '0';

  Val(s,Res,Err);

  if Err <> 0 then
    raise EAdvGridError.Create('Cell does not contain integer value');

  Result := Res;
end;

function TAdvStringGrid.GetCellFloatFormat(ACol,ARow: Integer): string;
var
  isFloat: boolean;
  fmt: string;
begin
  Result := FFloatFormat;
  if Assigned(OnGetFloatFormat) then
  begin
    OnGetFloatFormat(Self, ACol,ARow, IsFloat, Fmt);
    if isFloat then
      Result := Fmt;
  end;
end;

procedure TAdvStringGrid.SetFloats(ACol,ARow: Integer;const Value:double);
begin
  Cells[ACol,ARow] := Format(GetCellFloatFormat(ACol,ARow),[Value]);
end;

function TAdvStringGrid.GetFloats(ACol,ARow: Integer): Double;
var
  s: string;
  Res: Double;
  Err: Integer;
begin
  s := RemoveSeps(StrippedCells[ACol,ARow]);

  if (s = '') or (s = '-') then
    s := '0';

  Val(s,Res,Err);

  if Err <> 0 then
  begin
    raise EAdvGridError.Create('Cell does not contain a float value');
  end
  else
    Result := Res;

end;

procedure TAdvStringGrid.SetAllFloats(ACol,ARow: Integer;const Value:double);
begin
  AllCells[ACol,ARow] := Format(FFloatFormat,[Value]);
end;

function TAdvStringGrid.GetAllFloats(ACol,ARow: Integer): Double;
var
  s: string;
  Res: Double;
  Err: Integer;
begin
  s := RemoveSeps(AllCells[ACol,ARow]);

  if (s = '') or (s = '-') then
    s := '0';

  Val(s,Res,Err);
  if Err <> 0 then
    raise EAdvGridError.Create('Cell does not contain a float value');
  GetAllFloats := Res;
end;


function TAdvStringGrid.GetCtrlVal(ACol, ARow: Integer;
  ID: string): string;
var
  s:string;
begin
  Result := '';
  if GetControlValue(Cells[ACol,ARow],ID,s) then
    Result := s;
end;

procedure TAdvStringGrid.SetVersion(const Value: string);
begin

end;

function TAdvStringGrid.GetVersion: string;
var
  vn: Integer;
begin
  vn := GetVersionNr;
  Result := IntToStr(Hi(Hiword(vn)))+'.'+IntToStr(Lo(Hiword(vn)))+'.'+IntToStr(Hi(Loword(vn)))+'.'+IntToStr(Lo(Loword(vn)));
end;

function TAdvStringGrid.HasColumnsProp: boolean;
begin
  Result := false;
end;

procedure TAdvStringGrid.SetCtrlVal(ACol, ARow: Integer; ID: string;
  const Value: string);
var
  s:string;
begin
  s := Cells[ACol,ARow];
  if SetControlValue(s,ID,Value) then
    Cells[ACol,ARow] := s;
end;

function TAdvStringGrid.GetPrintColWidth(ACol: Integer): Integer;
begin
  Result := -1;
  if (ACol < AllColCount) and (ACol >= 0) then
    Result := MaxWidths[ACol]
 else
    EAdvGridError.Create('Columns is not in valid range');
end;

function TAdvStringGrid.GetPrintColOffset(ACol: Integer): Integer;
begin
  Result := -1;
  if (ACol < AllColCount) and (ACol >= 0) then
    Result := Indents[ACol]
  else
    EAdvGridError.Create('Columns is not in valid range');
end;

procedure TAdvStringGrid.SetLookupItems(Value: TStringList);
begin
  if Assigned(Value) then
    Flookupitems.Assign(Value);
end;

procedure TAdvStringGrid.FixedFontChanged(Sender:TObject);
begin
  Invalidate;
end;

procedure TAdvStringGrid.UndoColumnMerge;
var
  i: Integer;
begin
  for i := 1 to ColCount do
    SplitColumnCells(i - 1);
end;

procedure TAdvStringGrid.ApplyColumnMerge;
var
  i: Integer;
begin
  for i := 1 to MergedColumns.Count do
    MergeColumnCells(FMergedColumns.Items[i - 1],i=1);
end;    

procedure TAdvStringGrid.MergedColumnsChanged(Sender: TObject; ACol,ARow: Integer);
begin
  UndoColumnMerge;
  ApplyColumnMerge;
end;

procedure TAdvStringGrid.MultiImageChanged(Sender: TObject; ACol,ARow: Integer);
begin
  // force a cell update
  RepaintCell(ACol,ARow);
end;

procedure TAdvStringGrid.RichSelChange(Sender: TObject);
begin
  if Assigned(FOnRichEditSelectionChange) then
    FOnRichEditSelectionChange(Self);
end;

procedure TAdvStringGrid.SetFixedFont(Value:tFont);
begin
  FFixedFont.Assign(Value);
  Invalidate;
end;

procedure TAdvStringGrid.SetColumnHeaders(Value: TStringList);
begin
  FColumnHeaders.Assign(Value);
  if FixedRows > 0 then
    ClearColumnHeaders;
  ShowColumnHeaders;
end;

procedure TAdvStringGrid.ColHeaderChanged(Sender:TObject);
begin
  UpdateColHeaders;
  ShowColumnHeaders;
end;

procedure TAdvStringGrid.ClearColumnHeaders;
var
  i: Integer;
begin
  if ColCount > 0 then
    for i := 0 to ColCount - 1 do
      Cells[i,0] := '';
end;

procedure TAdvStringGrid.ShowColumnHeaders;
var
  I: Integer;
  iCHCount: Integer;
  iTCCount: Integer;
begin
  if FixedRows > 0 then
  begin
    iCHCount := FColumnHeaders.Count;
    iTCCount := TotalColCount;
    for i := 0 to iCHCount - 1 do
    begin
      if i < iTCCount then
      begin
        Cells[i,0] := CLFToLF(FColumnHeaders[i]);
      end;
    end;
  end;
end;

procedure TAdvStringGrid.SetRowHeaders(Value: TStringList);
begin
  FRowHeaders.Assign(Value);
  if (csDesigning in ComponentState) then
  begin
    if FixedCols > 0 then
      ClearRowHeaders;
  end;
  ShowRowHeaders;
end;

procedure TAdvStringGrid.RowHeaderChanged(Sender:tObject);
begin
  ShowRowHeaders;
end;

procedure TAdvStringGrid.ClearRowHeaders;
var
  i: Integer;
begin
  if RowCount > 0 then
    for i := 0 to RowCount - 1 do
      Cells[0,i] := '';
end;

procedure TAdvStringGrid.SetFontStyle(GridRect: TGridRect; AStyle: TFontStyle; DoSet: boolean);
var
  i,j: integer;
begin
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      if DoSet then
        FontStyles[i,j] := FontStyles[i,j] + [AStyle]
      else
        FontStyles[i,j] := FontStyles[i,j] - [AStyle];
    end;
end;

function TAdvStringGrid.IsFontStyle(GridRect: TGridRect; AStyle: TFontStyle): boolean;
var
  i,j: integer;
begin
  Result := true;
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      if not (AStyle in FontStyles[i,j]) then
      begin
        Result := false;
        break;
      end;
    end;
end;

procedure TAdvStringGrid.SetCellColor(GridRect: TGridRect; AColor: TColor);
var
  i,j: integer;
begin
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      Colors[i,j] := AColor;
    end;
end;

procedure TAdvStringGrid.SetCellTextColor(GridRect: TGridRect; AColor: TColor);
var
  i,j: integer;
begin
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      FontColors[i,j] := AColor;
    end;
end;

procedure TAdvStringGrid.SetCellFontName(GridRect: TGridRect; AFontName: string);
var
  i,j: integer;
begin
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      FontNames[i,j] := AFontName;
    end;
end;

procedure TAdvStringGrid.SetCellFontSize(GridRect: TGridRect; AFontSize: integer);
var
  i,j: integer;
begin
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      FontSizes[i,j] := AFontSize;
    end;
end;

procedure TAdvStringGrid.SetAlignment(GridRect: TGridRect; AAlignment: TAlignment);
var
  i,j: integer;
begin
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      Alignments[i,j] := AAlignment;
    end;
end;

function TAdvStringGrid.IsAlignment(GridRect: TGridRect; AAlignment: TAlignment): boolean;
var
  i,j: integer;
begin
  Result := true;
  for i := GridRect.Left to GridRect.Right do
    for j := GridRect.Top to GridRect.Bottom do
    begin
      if not (Alignments[i,j] = AAlignment) then
      begin
        Result := false;
        break;
      end;
    end;
end;

procedure TAdvStringGrid.ShowRowHeaders;
var
  i: Integer;
  iRHCount: Integer;
  iRCount: Integer;
begin
  if FixedCols > 0 then
  begin
    iRHCount := FRowHeaders.Count;
    iRCount := RowCount;
    for i := 0 to iRHCount - 1 do
    begin
      if i < iRCount then
      begin
        Cells[0,i] := CLFToLF(FRowHeaders[i]);
      end;
    end;
  end;
end;

procedure TAdvStringGrid.MarkCells(s,tag:string;DoCase: boolean; FromCol,FromRow,ToCol,ToRow: Integer; FullCell: boolean = false);
var
  r,c: Integer;
  ct,h: string;

begin
  s := FixMarkup(s,false);

  for r := FromRow to ToRow do
    for c := FromCol to ToCol do
    begin
      if IsBaseCell(c,r) then
      begin
        if Assigned(OnGetDisplText) then
          ct := Cells[c,r]
        else
          ct := GridCells[c,r];

        //ct := FixMarkup(ct,false);

        h := Hilight(ct,s,tag,DoCase,FullCell);

        if h <> ct then
          Cells[c,r] := h;
      end;
    end;
end;

procedure TAdvStringGrid.UnMarkCells(tag:string;FromCol,FromRow,ToCol,ToRow: Integer);
var
  r,c: Integer;
  ct: string;
begin
  for r := FromRow to ToRow do
    for c := FromCol to ToCol do
    begin
      if IsBaseCell(c,r) then
      begin
        if Assigned(OnGetDisplText) then
          ct := Cells[c,r]
        else
          ct := GridCells[c,r];

       ct := UnFixMarkup(ct,false);
       Cells[c,r] := UnHilight(ct,tag);
      end;
    end;
end;

function TAdvStringGrid.HilightText(DoCase: Boolean; S,Text: string):string;
begin
  Result := Hilight(S,Text,'hi',DoCase,false);
end;

function TAdvStringGrid.UnHilightText(S: string):string;
begin
  Result := UnHilight(S,'hi');
end;

function TAdvStringGrid.MarkText(DoCase: Boolean; S,Text: string):string;
begin
  Result := Hilight(S,Text,'e',DoCase, false);
end;

function TAdvStringGrid.UnMarkText(S: string):string;
begin
  Result := UnHilight(S,'e');
end;

procedure TAdvStringGrid.HilightInCell(DoCase: Boolean; Col,Row: Integer; HiText: string; FullText: boolean = false);
begin
  MarkCells(HiText,'hi',DoCase,Col,Row,Col,Row, FullText);
end;

procedure TAdvStringGrid.HilightInCol(DoFixed,DoCase: Boolean; Col: Integer; HiText: string; FullText: boolean = false);
var
  rs,re: Integer;
begin
  if DoFixed then
  begin
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  MarkCells(HiText,'hi',DoCase,Col,rs,Col,re, FullText);
end;

procedure TAdvStringGrid.HilightInRow(DoFixed,DoCase: Boolean; Row: Integer; HiText: string; FullText: boolean = false);
var
  cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols;
  end;
  MarkCells(HiText,'hi',DoCase,cs,Row,ce,Row, FullText);
end;

procedure TAdvStringGrid.HilightInGrid(DoFixed,DoCase: Boolean; HiText: string; FullText: boolean = false);
var
  rs,re,cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1;
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols + NumHiddenColumns;
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  MarkCells(HiText,'hi',DoCase,cs,rs,ce,re, FullText);
end;

procedure TAdvStringGrid.UnHilightInCell(Col,Row: Integer);
begin
  UnMarkCells('hi',Col,Row,Col,Row);
end;

procedure TAdvStringGrid.UnHilightInCol(DoFixed: Boolean; Col: Integer);
var
  rs,re: Integer;
begin
  if DoFixed then
  begin
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  UnMarkCells('hi',Col,rs,Col,re);
end;

procedure TAdvStringGrid.UnHilightInRow(DoFixed: Boolean; Row: Integer);
var
  cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1 + NumHiddenColumns;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols + NumHiddenColumns;
  end;

  UnMarkCells('hi',cs,Row,ce,Row);
end;

procedure TAdvStringGrid.UnHilightInGrid(DoFixed: Boolean);
var
  rs,re,cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1 + NumHiddenColumns;
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols + NumHiddenColumns;
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  UnMarkCells('hi',cs,rs,ce,re);
end;

procedure TAdvStringGrid.MarkInCell(DoCase: Boolean; Col,Row: Integer; HiText: string);
begin
  MarkCells(HiText,'e',DoCase,Col,Row,Col,Row);
end;

procedure TAdvStringGrid.MarkInCol(DoFixed,DoCase: Boolean; Col: Integer; HiText: string);
var
  rs,re: Integer;
begin
  if DoFixed then
  begin
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;
  MarkCells(HiText,'e',DoCase,Col,rs,Col,re);
end;

procedure TAdvStringGrid.MarkInRow(DoFixed,DoCase: Boolean; Row: Integer; HiText: string);
var
  cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols;
  end;
  MarkCells(HiText,'e',DoCase,cs,Row,ce,Row);
end;

procedure TAdvStringGrid.MarkInGrid(DoFixed,DoCase: Boolean; HiText: string);
var
  rs,re,cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1;
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols;
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  MarkCells(HiText,'e',DoCase,cs,rs,ce,re);
end;

procedure TAdvStringGrid.UnMarkInCell(Col,Row: Integer);
begin
  UnMarkCells('e',Col,Row,Col,Row);
end;

procedure TAdvStringGrid.UnMarkInCol(DoFixed: Boolean; Col: Integer);
var
  rs,re: Integer;
begin
  if DoFixed then
  begin
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  UnMarkCells('e',Col,rs,Col,re);
end;

procedure TAdvStringGrid.UnMarkInRow(DoFixed: Boolean; Row: Integer);
var
  cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1 + NumHiddenColumns;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols + NumHiddenColumns;
  end;

  UnMarkCells('e',cs,Row,ce,Row);
end;

procedure TAdvStringGrid.UnMarkInGrid(DoFixed: Boolean);
var
  rs,re,cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1 + NumHiddenColumns;
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols + NumHiddenColumns;
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  UnMarkCells('e',cs,rs,ce,re);
end;

function TAdvStringGrid.CheckCells(FromCol,FromRow,ToCol,ToRow: Integer): Boolean;
var
  r,c: Integer;
  CurRow, CurCol: Integer;
begin
  Result := True;

  if not Assigned(FCellChecker) then
    Exit;

  FCellChecker.StartCheck;

  CurRow := Self.Row;
  CurCol := Self.Col;

  for r := FromRow to ToRow do
  begin
    for c := FromCol to ToCol do
    begin
      if not CheckCell(c,r) then
        Result := False;
      if CellChecker.LastResult <> mrOK then
        break;
    end;
    if CellChecker.LastResult <> mrOK then
      break;
  end;

  FCellChecker.StopCheck;

  if FCellChecker.GotoCell then
  begin
    Self.Row := CurRow;
    Self.Col := CurCol;
  end;
end;

function TAdvStringGrid.CheckCell(Col,Row: Integer): Boolean;
var
  NewValue,OrigValue: string;
begin
  Result := True;
  if not Assigned(CellChecker) then Exit;

  OrigValue := UnMarkText(Cells[Col,Row]);

  if CellChecker.GotoCell then
    MoveColRow(Col,Row,True,True);

  NewValue := OrigValue;

  if CellChecker.UseCorrect then
    NewValue := CellChecker.Correct(Col,Row,OrigValue);

  if CellChecker.UseMarkError then
    NewValue := CellChecker.MarkError(Col,Row,OrigValue);

  Cells[Col,Row] := NewValue;

  Result := NewValue = OrigValue;
end;

function TAdvStringGrid.CheckCol(DoFixed: Boolean; Col: Integer): Boolean;
var
  rs,re: Integer;
begin
  if DoFixed then
  begin
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  Result := CheckCells(Col,rs,Col,re);
end;

function TAdvStringGrid.CheckRow(DoFixed: Boolean; Row: Integer): Boolean;
var
  cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols;
  end;

  Result := CheckCells(cs,Row,ce,Row);
end;

function TAdvStringGrid.CheckGrid(DoFixed: Boolean): Boolean;
var
  rs,re,cs,ce: Integer;
begin
  if DoFixed then
  begin
    cs := 0;
    ce := ColCount - 1;
    rs := 0;
    re := RowCount - 1;
  end
  else
  begin
    cs := FixedCols;
    ce := ColCount - 1 - FFixedRightCols;
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  Result := CheckCells(cs,rs,ce,re);
end;

procedure TAdvStringGrid.TextFill(DoFixed: Boolean; Txt : string);
var
  i,j: Integer;
  ro,co,re,ce: Integer;
begin
  if DoFixed then
  begin
    ro := 0;
    co := 0;
    re := RowCount - 1;
    ce := ColCount - 1;
  end
  else
  begin
    ro := FixedRows;
    co := FixedCols;
    re := RowCount - 1 - FFixedFooters;
    ce := ColCount - 1 - FFixedRightCols;
  end;

  for i := ro to re do
    for j := co to ce do
      Cells[j,i] := Txt;

  CellsLoaded;
end;

procedure TAdvStringGrid.FormatFill(DoFixed: Boolean; Fmt: string);
var
  i,j: Integer;
  ro,co,re,ce: Integer;
begin
  if DoFixed then
  begin
    ro := 0;
    co := 0;
    re := RowCount - 1;
    ce := ColCount - 1;
  end
  else
  begin
    ro := FixedRows;
    co := FixedCols;
    re := RowCount - 1 - FFixedFooters;
    ce := ColCount - 1 - FFixedRightCols;
  end;

  for i := ro to re do
    for j := co to ce do
      Cells[j,i] := Format(fmt,[j,i]);

  CellsLoaded;
end;

procedure TAdvStringGrid.RandomFill(DoFixed: Boolean = false;rnd: Integer = 100);
var
  i,j: Integer;
  ro,co,re,ce: Integer;
begin
  if DoFixed then
  begin
    ro := 0;
    co := 0;
    re := RowCount - 1;
    ce := ColCount - 1;
  end
  else
  begin
    ro := FixedRows;
    co := FixedCols;
    re := RowCount - 1 - FFixedFooters;
    ce := ColCount - 1 - FFixedRightCols;
  end;

  for i := ro to re do
    for j := co to ce do
      Ints[j,i] := Random(rnd);

  CellsLoaded;
end;

procedure TAdvStringGrid.LinearFill(DoFixed: Boolean = false);
var
  i,j: Integer;
  ro,co,re,ce: Integer;
begin
  if DoFixed then
  begin
    ro := 0;
    co := 0;
    re := RowCount - 1;
    ce := ColCount - 1;
  end
  else
  begin
    ro := FixedRows;
    co := FixedCols;
    re := RowCount - 1 - FFixedFooters;
    ce := ColCount - 1 - FFixedRightCols;
  end;

  for i := ro to re do
    for j := co to ce do
      Cells[j,i] := IntToStr(j)+':'+IntToStr(i);

  CellsLoaded;
end;


procedure TAdvStringGrid.SetDates(ACol,ARow: Integer;const Value:TDateTime);
begin
  if (Value > 0) or ShowNullDates then
    Cells[ACol,ARow] := DateToStr(Value)
  else
    Cells[ACol,ARow] := '';
end;

function TAdvStringGrid.GetDates(ACol,ARow: Integer):TDateTime;
begin
  GetDates := StrToDate(Cells[ACol,ARow]);
end;

procedure TAdvStringGrid.SetTimes(ACol,ARow: Integer;const Value:TDateTime);
begin
  Cells[ACol,ARow] := TimeToStr(Value);
end;

function TAdvStringGrid.GetTimes(ACol,ARow: Integer):TDateTime;
begin
  GetTimes := StrToTime(Cells[ACol,ARow]);
end;

function TAdvStringGrid.GetRowSelect(ARow: Integer): Boolean;
var
  i,j: Integer;

begin
 if ((ARow >= RowCount + NumHiddenRows) or (ARow < 0)) and not MouseActions.RowSelectPersistent then
 begin
   raise EAdvGridError.Create('Invalid row ' + IntToStr(Arow) + ' accessed');
 end;

  if MouseActions.DisjunctRowSelect then
  begin
    //SelectToRowSelect(false);
    i := FRowSelect.Count;

    if i < ARow + 1 then
    begin
      FRowSelect.Count := RowCount;
      for j := i to FRowSelect.Count - 1 do
        FRowSelect.Items[j] := nil;
    end;
    Result := (FRowSelect.Items[ARow] <> nil);
  end
  else
  begin
    i := Selection.Top;
    j := Selection.Bottom;
    if (i > j) then
    begin
      i := Selection.Bottom;
      j := Selection.Top;
    end;

    Result := (ARow >= i) and (ARow <= j);
  end;
end;

function TAdvStringGrid.GetColSelect(ACol: Integer): Boolean;
var
  i,j: Integer;
begin
  if (ACol >= ColCount + NumHiddenColumns) or (ACol < 0) then
    raise EAdvGridError.Create('Invalid column accessed');

  i := FColSelect.Count;

  if i < ACol + 1 then
  begin
    FColSelect.Count := ACol + 1;
    for j := i to FColSelect.Count - 1 do
      FColSelect.Items[j] := nil;
  end;

  GetColSelect := (FColSelect.Items[ACol] <> nil);
end;

procedure TAdvStringGrid.RepaintRect(r: TRect);
var
  r1,r2,ur: TRect;
begin
  if (r.Left < 0) or (r.Right < 0) or (r.Top < 0) or (r.Bottom < 0) then
    Exit;

  r1 := CellRect(r.Left,r.Top);
  r2 := CellRect(Min(VisibleColCount + FixedCols,r.Right),r.Bottom);
  UnionRect(ur,r1,r2);
  if IsRectEmpty(r1) or IsRectEmpty(r2) then
    Repaint
  else
    InvalidateRect(Handle,@ur,True);
end;

procedure TAdvStringGrid.RepaintCell(c,r: Integer);
var
  rc: TRect;
begin
  if ((r < TopRow) and (r >= FixedRows)) or (r > TopRow + VisibleRowCount) then
    Exit;
  if ((c < LeftCol) and (c >= FixedCols)) or(c > LeftCol + VisibleColCount) then
    Exit;

  rc := CellRect(c,r);
  InvalidateRect(Handle,@rc,True);
end;

procedure TAdvStringGrid.RepaintRow(ARow: Integer);
var
  r1,r2: TRect;
begin
  r1 := CellRect(0,ARow);
  r2 := CellRect(LeftCol + VisibleColCount, ARow);
  r2.Left := r1.Left;
  InvalidateRect(Handle,@r2, false);
  //InvalidateRow(ARow);
end;

procedure TAdvStringGrid.RepaintCol(ACol: Integer);
var
  r1,r2: TRect;
begin
  r1 := CellRect(ACol, TopRow);
  r2 := CellRect(ACol, TopRow + VisibleRowCount);
  r2.Top := r1.Top;
  InvalidateRect(Handle,@r2, false);
end;

procedure TAdvStringGrid.SwapCells(FromCell,ToCell: TGridCoord);
var
  s: string;
  obj: TObject;
begin
  s := GridCells[FromCell.X, FromCell.Y];
  obj := GridObjects[FromCell.X, FromCell.Y];
  GridCells[FromCell.X, FromCell.Y] := GridCells[ToCell.X, ToCell.Y];
  GridObjects[FromCell.X, FromCell.Y] := GridObjects[ToCell.X, ToCell.Y];

  GridCells[ToCell.X, ToCell.Y] := s;
  GridObjects[ToCell.X, ToCell.Y] := obj;
end;

procedure TAdvStringGrid.GotoCellInt(Col,Row: Integer);
begin
  //Selection := TGridRect(Rect(Col,Row,Col,Row));
  MoveColRow(Col,Row,true,true);
end;

procedure TAdvStringGrid.GotoCell(ACol,ARow: Integer);
begin
  Row := ARow;
  Col := ACol;
  //Selection := TGridRect(Rect(Col,Row,Col,Row));
  //MoveColRow(Col,Row,true,true);
end;

procedure TAdvStringGrid.EditCell(ACol: Integer; ARow: Integer);
begin
  SetFocus;
  GotoCell(ACol,ARow);
  ShowInplaceEdit;
end;

procedure TAdvStringGrid.FocusCell(ACol,ARow: Integer);
begin
  Selection := TGridRect(Rect(ACol,ARow,ACol,ARow));
end;

// unselecting rows only makes sense and is only applicable in disjunct row selection mode
procedure TAdvStringGrid.UnSelectRows(RowIndex, RCount: Integer);
var
  i,j: Integer;
begin
  if FMouseActions.DisjunctRowSelect then
  begin
    for i := RowIndex to RowIndex + RCount - 1 do
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      if j < RowCount then
        RowSelect[j] := False;
    end;
  end;
  FSelChange := false;
end;

procedure TAdvStringGrid.SelectRows(RowIndex, RCount: Integer);
var
  gr: TGridRect;
  i,j: Integer;
begin
  if RowIndex + RCount > RowCount then
    RCount := RowCount - RowIndex;

  if FMouseActions.DisjunctRowSelect then
  begin
    for i := RowIndex to RowIndex + RCount - 1 do
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      if j < RowCount then
        RowSelect[j] := True;
    end;
  end
  else
  begin
    gr.Left := FixedCols;
    gr.Right := ColCount - 1;
    gr.Top := Rowindex;
    gr.Bottom := Rowindex + rcount - 1;
    Selection := gr;
  end;

  if not RowIndicator.Empty then
    RepaintCol(0);
  FSelChange := false;
end;

procedure TAdvStringGrid.UnSelectCols(ColIndex, CCount: Integer);
var
  i: Integer;
begin
  if FMouseActions.DisjunctColSelect then
  begin
    for i := ColIndex to ColIndex + CCount - 1 do
      if i < ColCount then
        ColSelect[i] := False;
  end;
end;

function TAdvStringGrid.DistinctValues(ACol: integer; CaseSensitive: boolean = true): TStrings;
var
  i: integer;
  s,u: string;
  sl: tstringlist;
begin
  Result := TStringList.Create;
  (Result as TStringList).Duplicates := dupIgnore;
  (Result as TStringList).Sorted := true;

  sl := TStringList.Create;
  sl.Duplicates := dupIgnore;

  try
    for i := FixedRows to RowCount - FixedFooters - 1 do
    begin
      s := SaveCell(ACol,i);

      if not CaseSensitive then
        u := Uppercase(s)
      else
        u := s;

      if sl.IndexOf(u) = -1 then
      begin
        Result.Add(s);
        sl.Add(u);
      end;
    end;
  finally
    sl.Free;
  end;
end;


procedure TAdvStringGrid.SelectCols(ColIndex, CCount: Integer);
var
  gr: TGridRect;
  i: Integer;
begin
  if FMouseActions.DisjunctColSelect then
  begin
    for i := ColIndex to ColIndex + CCount - 1 do
      if i < ColCount then
        ColSelect[i] := True;
  end
  else
  begin
    gr.Left := ColIndex;
    gr.Right := ColIndex + CCount - 1;
    gr.Top := FixedRows;
    gr.Bottom := RowCount - 1;
    Selection := gr;
  end;
end;

procedure TAdvStringGrid.SelectRange(FromCol,ToCol,FromRow,ToRow: Integer);
var
  gr: TGridRect;
begin
  Row := ToRow;
  Col := ToCol;
  gr.Left := FromCol;
  gr.Right := ToCol;
  gr.Top := FromRow;
  gr.Bottom := ToRow;
  Selection := gr;
end;

procedure TAdvStringGrid.ClearRowSelectInt;
var
  i: Integer;
  flg: boolean;
begin
  if FRowSelect.Count <= 0 then
    Exit;

  for i := 0 to FRowSelect.Count - 1 do
  begin
    flg := FRowSelect.Items[i] <> nil;
    if flg then
      RepaintRow(i);
    FRowSelect.Items[i] := nil;

    if flg and Assigned(FOnRowDisjunctSelected) then
        FOnRowDisjunctSelected(Self, i);

    FSelectedRows.Clear;
  end;
end;

procedure TAdvStringGrid.ClearRowSelect;
begin
  ClearRowSelectInt;

  if not MouseActions.DisjunctRowSelect then
    HideSelection;

//  Selection := TGridRect(Rect(ColCount,RowCount,ColCount,RowCount));
end;

procedure TAdvStringGrid.ClearColSelect;
var
  i: Integer;
begin
  if FColSelect.Count <= 0 then
    Exit;

  for i := 0 to FColSelect.Count - 1 do
  begin
    if FColSelect.Items[i] <> nil then
      RepaintCol(i);
    FColSelect.Items[i] := nil;
  end;
end;

function TAdvStringGrid.IsScrolledToLastRow: boolean;
var
  R: TRect;
begin
  Result := false;

  if SearchFooter.Visible and (RowCount - 1 <= TopRow + VisibleRowCount) then
  begin
    R := CellRect(0,RowCount - 1);
    Result := (R.Bottom < ClientRect.Bottom - SearchPanel.Height + 2);
  end;
end;

procedure TAdvStringGrid.ScrollToLastRow;
var
  R: TRect;
begin
  if SearchFooter.Visible and (SearchPanel.Height + DefaultRowHeight < ClientRect.Bottom - ClientRect.Top) then
  begin
    R := CellRect(0,RowCount - 1);
    while (R.Bottom > ClientRect.Bottom - SearchPanel.Height + 2) and
      (Row <= RowCount - 1) and (TopRow < RowCount - 1) do
    begin
      TopRow := TopRow + 1;
      R := CellRect(0,RowCount - 1);
    end;
  end;
end;

function TAdvStringGrid.SelectToRowSelect(IsShift: Boolean): boolean;
var
  i,j: Integer;
  sel: TGridRect;
begin
  Result := false;

  if (FDisSelection.Top = Selection.Top) then
    Exit;

  sel := Selection;
  if sel.Bottom >= RowCount - FixedFooters then
    sel.Bottom := RowCount - FixedFooters - 1;

  for i := FixedRows to RowCount - 1 do
  begin
    if IsShift or
       ((i >= sel.Top) and (i <= sel.Bottom)) then
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      RowSelect[j] := (i >= sel.Top) and (i <= sel.Bottom);

      if FRowSelMod then
      begin
        Result := true;
      end;
    end;
  end;

  if (NumHiddenRows > 0) then
    Invalidate;

  FDisSelection := Selection;
end;

procedure TAdvStringGrid.SelectToColSelect(IsShift: Boolean);
var
  i: Integer;
begin
  for i := FixedCols to ColCount - 1 do
  begin
    if IsShift or
       ((i >= Selection.Left) and (i <= Selection.Right)) then
      ColSelect[i] := (i >= Selection.Left) and (i <= Selection.Right);
  end;
end;


function TAdvStringGrid.GetRowSelectCount: Integer;
var
  Res,i: Integer;
begin
  Res := 0;

  if MouseActions.DisjunctRowSelect then
  begin
    for i := 1 to Min(RowCount + NumHiddenRows, FRowSelect.Count) do
      if FRowSelect.Items[i-1] <> nil then
        Inc(Res);
  end
  else
  begin
    if (goRowSelect in Options) then
    begin
      Res := Selection.Bottom - Selection.Top;
      if Res < 0 then
        Res := -Res;
      Inc(Res);
    end;
  end;
  
  Result := Res;
end;

function TAdvStringGrid.GetColSelectCount: Integer;
var
  Res,i: Integer;
begin
  if MouseActions.DisjunctColSelect then
  begin
    Res := 0;
    for i := 1 to FColSelect.Count do
      if FColSelect.Items[i - 1] <> nil then Inc(Res);
    Result := Res;
  end
  else
    Result := Selection.Right - Selection.Left + 1;
end;

function TAdvStringGrid.GetColumnCheckFalse(ACol: Integer): string;
begin
  Result := CheckFalse;
end;

function TAdvStringGrid.GetColumnCheckTrue(ACol: Integer): string;
begin
  Result := CheckTrue;
end;

function TAdvStringGrid.ModifiedRowCount;
var
  i,r: integer;
begin
  r := 0;

  for i := 0 to FModifiedRows.Count - 1 do
    if (FModifiedRows[i] = 1) then inc(r);

  Result := r;
end;

function TAdvStringGrid.GetRowModified(ARow: Integer): boolean;
begin
  Result := false;
  if ARow < FModifiedRows.Count then
  begin
    Result := (FModifiedRows[ARow] = 1);
  end;
end;

procedure TAdvStringGrid.SetRowModified(ARow: Integer; Value: boolean);
var
  i,j: Integer;
  dr: integer;
begin
  i := FModifiedRows.Count;

  if i < ARow + 1 then
  begin
    FModifiedRows.Count := ARow + 1;
    for j := i to FModifiedRows.Count - 1 do
      FModifiedRows[j] := 0;
  end;
  if Value then
    FModifiedRows[ARow] := 1
  else
     FModifiedRows[ARow] := 0;

  dr := DisplRowIndex(Arow);

  RepaintCell(0, dr);
end;

function TAdvStringGrid.GetRowEnabled(ARow: Integer): boolean;
begin
  Result := true;
  if ARow < FEnabledRows.Count then
  begin
    Result := (FEnabledRows[ARow] = 0);
  end;
end;

procedure TAdvStringGrid.SetRowEnabled(ARow: Integer; Value: boolean);
var
  i,j: Integer;
begin
  if (ARow = Row) then
  begin
    j := -1;
    for i := FixedRows to RowCount - 1 do
    begin
      if (i <> ARow) and RowEnabled[i] then
      begin
        j := i;
        break;
      end;
    end;
    if (j <> -1) then
      Row := j;
  end;

  FUseEnabledRows := true;

  i := FEnabledRows.Count;

  if i < ARow + 1 then
  begin
    FEnabledRows.Count := ARow + 1;
    for j := i to FEnabledRows.Count - 1 do
      FEnabledRows[j] := 0;
  end;

  if Value then
    FEnabledRows[ARow] := 0
  else
     FEnabledRows[ARow] := 1;

  RepaintRow(ARow);
end;


procedure TAdvStringGrid.SetRowSelect(ARow: Integer; Value: Boolean);
var
  i,j: Integer;
  Allow, Flg: boolean;

begin
  FRowSelMod := false;

  if ( (ARow >= RowCount + NumHiddenRows)and(RowCount>FixedRows) ) or (ARow < 0) then
    raise EAdvGridError.Create('Invalid row accessed');

  Allow := true;
  Flg := false;

  i := FRowSelect.Count;
  if (i < ARow) or ((ARow < i) and (Assigned(FRowSelect.Items[ARow]) <> Value)) then
  begin
    Flg := true;
    if Assigned(FOnRowDisjunctSelect) then
      FOnRowDisjunctSelect(Self, ARow, Value, Allow);
  end;

  if not Allow then
    Exit;

  if i < ARow + 1 then
  begin
    FRowSelect.Count := ARow + 1;
    for j := i to FRowSelect.Count - 1 do
      FRowSelect.Items[j] := nil;
  end;

  if Value then
  begin
    if FRowSelect.Items[ARow] <> Pointer(1) then
    begin
      //RepaintRow(RemapRow(ARow));
      RepaintRow(ARow);
    end;

    FRowSelMod := FRowSelect.Items[ARow] <> Pointer(1);

    FRowSelect.Items[ARow] := Pointer(1);

    if not FSelectedRows.HasValue(ARow) and (ARow >= FixedRows) then
    begin
      FSelectedRows.Add(ARow);

      if (ARow = Row) and (MouseActions.DisjunctRowSelect) then
      begin
        if Assigned(OnSelectionChanged) then
          OnSelectionChanged(Self, 0, ARow, ColCount - 1, ARow);
      end;

    end;
  end
  else
  begin
    if FRowSelect.Items[ARow] <> nil then
      //RepaintRow(RemapRow(ARow));
      RepaintRow(ARow);

    FRowSelMod := FRowSelect.Items[ARow] <> nil;

    FRowSelect.Items[ARow] := nil;
    FSelectedRows.DeleteValue(ARow);

    if (ARow = Row) and (MouseActions.DisjunctRowSelect) then
    begin
      if Assigned(OnSelectionChanged) then
        OnSelectionChanged(Self, 0, ARow, ColCount - 1, ARow);
    end;

  end;

  if Flg and Assigned(FOnRowDisjunctSelected) then
    FOnRowDisjunctSelected(Self, ARow);
end;

procedure TAdvStringGrid.SetColSelect(ACol: Integer;Value: Boolean);
var
  i,j: Integer;
begin
  if (ACol >= ColCount) or (ACol < 0) then
    raise EAdvGridError.Create('Invalid column accessed');

  i := FColSelect.Count;
  if i < ACol + 1 then
  begin
    FColSelect.Count := ACol + 1;
    for j := i to FColSelect.Count - 1 do
      FColSelect.Items[j] := nil;
  end;

  if Value then
  begin
    if FColSelect.Items[ACol] <> Pointer(1) then
      RepaintCol(ACol);
    FColSelect.Items[ACol] := Pointer(1);
  end
  else
  begin
    if FColSelect.Items[ACol] <> nil then
      RepaintCol(ACol);
    FColSelect.Items[ACol] := nil;
  end;
end;


function TAdvStringGrid.GetInplaceEditor:TAdvInplaceEdit;
begin
  Result := TAdvInplaceEdit(InplaceEditor);
end;

procedure TAdvStringGrid.AdvanceHTMLEdit(ACol,ARow: Integer; CtrlID: string);
var
  NewID: string;
  ml,hl,XPos,YPos,XSize, YSize: Integer;
  r, hr,CR: TRect;
  CV,CT: string;
  s,Anchor,Stripped,FocusAnchor,AnchorHint: string;

begin
  NewID := GetNextControlID(Cells[ACol,ARow],CtrlID);

  if (NewID <> '') then
  begin
    s := Cells[ACol,ARow];
    r := CellRect(ACol,ARow);
    r.Left := r.Left + 1 + FXYOffset.X;
    r.Top := r.Top + 1 + FXYOffset.Y;

    if HasCheckBox(ACol,ARow) then
      r.Left := r.Left + ControlLook.CheckSize;
      
    XPos := -1;
    YPos := -1;

    HTMLDrawEx(Canvas,s,r,Gridimages,XPos,YPos,-1,0,1,
               True,False,False,False,False,False,not EnhTextSize,False,'',
               0.0,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
               XSize,YSize,ml,hl,hr,CR,NewID,CV,CT,FImageCache,FContainer,self.Handle,BidiMode);

    ControlEnter(s,CT,NewID,CV,CR,ACol,ACol,ARow);
  end
  else
    SetFocus;
end;

procedure TAdvStringGrid.AdvanceEdit(ACol,ARow: Integer;advance,show,frwrd,recurs,fromedit: Boolean);
var
  OldCol,OldRow, rm, i: Integer;
  AllowAdd,CanChange,flg: Boolean;
  Span,NextCell: TPoint;
  AEditor: TEditorType;
  CanEdit: boolean;
  CR: TRect;
begin
  if (not FNavigation.AdvanceOnEnter) and (not Advance) then
    Exit;

  if MouseActions.RangeSelectAndEdit then
  begin
    if not (goEditing in Options) then
    begin
      Options := Options + [goEditing];
    end;
  end;

//  Span := BaseCell(ACol,ARow);
//  ACol := Span.X;
//  ARow := Span.Y;

  if not Recurs then
  begin
    FAECol := ACol;
    FAERow := ARow;
  end
  else
    if (FAECol = ACol) and (FAERow = ARow) then
      Exit;

  OldCol := ACol;
  OldRow := ARow;
  FStartEditChar := #0;

  Span := CellSpan(ACol,ARow);

  if Frwrd then
  begin
    if (FNavigation.AdvanceDirection in [adLeftRight, adLeftRightInRow]) then
    begin
      if (ACol + Span.X >= ColCount - 1 - NumFixedRightVis) then
      begin
        if (FNavigation.AdvanceDirection = adLeftRightInRow) then
        begin
          if Navigation.AdvanceOnEnterLoop then
            ACol := FixedColsVis
          else
            Exit;
        end
        else
        begin
          if ARow = RowCount - 1 - FFixedFooters then
          begin
            if FNavigation.AdvanceInsert then {automatic ARowinsert}
            begin
              AllowAdd := True;
              QueryAddRow(AllowAdd);
              ACol := FixedColsVis;
              if AllowAdd then
              begin
                AddRow;
                ARow := ARow + 1;
                if Assigned(FOnAutoAddRow) then
                  FOnAutoAddRow(Self,RowCount - 1 - FFixedFooters);

                // check if any cells in the added row can be edited
                flg := false;
                for i := FixedCols to ColCount - 1 do
                begin
                  rm := RemapCol(i);
                  if IsEditable(rm,ARow) then
                    flg := true;
                end;
                // if not, stop the advance process
                if not flg then
                  Exit;
              end;
            end
            else {skip back to first cell}
            begin
              if Navigation.AdvanceOnEnterLoop then
              begin
                ARow := FixedRows;
                ACol := FixedColsVis;
              end
              else
                Exit;
            end;
          end
          else
          begin
            ARow := ARow + 1;
            ACol := FixedColsVis;
          end;
        end;
      end
      else
      begin
        ACol := ACol + 1 + Span.X;
      end;
    end;

    if (FNavigation.AdvanceDirection in [adTopBottom, adTopBottomInCol]) then
    begin
      if ARow = RowCount - 1 - FFixedFooters then
      begin
        if (FNavigation.AdvanceDirection = adTopBottomInCol) then
        begin
          if FNavigation.AdvanceInsert then
          begin
            AllowAdd := True;
            QueryAddRow(AllowAdd);
            //ACol := FixedColsVis;
            if AllowAdd then
            begin
              AddRow;
              ARow := ARow + 1;
              if Assigned(FOnAutoAddRow) then
                FOnAutoAddRow(Self,RowCount - 1 - FFixedFooters);
            end;
          end
          else
          begin
            if Navigation.AdvanceOnEnterLoop then
              ARow := FixedRows
            else
              Exit;
          end
        end
        else
        begin
          if (ACol = ColCount - 1 - FFixedRightCols) then
          begin
            if FNavigation.AdvanceInsert then
            begin
              AllowAdd := True;
              QueryAddCol(AllowAdd);
              if AllowAdd then
              begin
                ColCount := ColCount + 1;
                ACol := ACol + 1 + Span.X;
                ARow := FixedRows;
                if Assigned(FOnAutoInsertCol) then
                  FOnAutoInsertCol(Self,ColCount - 1 - FFixedRightCols);
              end;
            end
            else
            begin
              if Navigation.AdvanceOnEnterLoop then
              begin
                ARow := FixedRows;
                ACol := FixedColsVis;
              end
              else
               Exit;
            end;
          end
          else
          begin
            ARow := FixedRows;
            ACol := ACol + 1 {+ Span.X};
            if ACol >= ColCount then
              ACol := FixedColsVis;
          end;
          Repaint;
        end;
      end
      else
      begin
        ARow := ARow + 1;
      end;
    end;
  end
 //Handle backward case
  else
  begin
    if FNavigation.AdvanceDirection = adLeftRight then
    begin
      if ACol > FixedColsVis then
        ACol := ACol - 1
      else
        if ARow > FixedRows then
        begin
          ARow := ARow - 1;
          ACol := ColCount - 1 - FFixedRightCols;
        end
        else
        begin
          ARow := RowCount - 1 - FFixedFooters;
          ACol := ColCount - 1 - FFixedRightCols;
        end;
    end;

    if FNavigation.AdvanceDirection = adTopBottom then
    begin
      if ARow > FixedRows then
        ARow := ARow - 1
      else
        if ACol > FixedColsVis then
        begin
          ACol := ACol - 1;
          ARow := RowCount - 1 - FFixedFooters;
        end
        else
        begin
          ACol := ColCount - 1 - FFixedRightCols;
          ARow := RowCount - 1 - FFixedFooters;
        end;
    end;
  end;

  ACol := NextCol(ACol);

  rm := RemapCol(ACol);

  CanEdit := not IsFixed(ACol,ARow);
  GetCellReadOnly(rm,ARow,CanEdit);

  if not CanEdit {IsEditable(rm,ARow)} then
  begin
    if not Navigation.AdvanceOnEnterLoop then
    begin
      NextCell := NextVisitableCell(ACol,ARow);
      if (NextCell.X = -1) and (NextCell.Y = -1) then
        Exit;
    end;

    if Navigation.AdvanceSkipReadOnlyCells then
      AdvanceEdit(ACol,ARow,Advance,Show,Frwrd,True,fromEdit)
    else
    begin
      Col := ACol;
      Row := ARow;
    end;
  end
  else
  begin
    CanChange := True;

    if Assigned(FOnAutoAdvance) then
      FOnAutoAdvance(Self,FAERow,FAECol,ARow,ACol,CanChange);

    if CanChange then
    begin
      if Assigned(FOnCellChanging) then
        FOnCellChanging(Self,FAERow,FAECol,ARow,ACol,CanChange);

      FDisableChange := True;

      if CanChange then
      begin
        Col := ACol;
        Row := ARow;
      end
      else
        SelectCell(OldCol,OldRow);
    end
    else
      SelectCell(OldCol,OldRow);

    FDisableChange := False;
  end;

  if not FromEdit then
    Exit;

  if Assigned(CellControls[rm,ARow]) then
  begin
    if (CellControls[rm,ARow] is TWinControl) then
      TWinControl(CellControls[rm,ARow]).SetFocus;
    Col := OldCol;
    Row := OldRow;
    Exit;
  end;

  if (Show and FNavigation.AdvanceAutoEdit) or HasStaticEdit(rm,ARow)  then
  begin
    if not IsEditable(rm,ARow) then
      Exit;

    ShowEditor;

    if HasStaticEdit(rm,ARow) then
    begin
      FDisableChange := True;

      Col := OldCol;
      Row := OldRow;

      Col := ACol;
      Row := ARow;
      CR := CellRect(ACol,ARow);

      span.X := CR.Left + 2;
      span.Y := CR.Top + 2;

      if not HasStaticEdit(OldCol,OldRow) then
      begin
        MouseDown(mbLeft,[],span.X,span.Y);
        MouseUp(mbLeft,[],span.X,span.Y);

        if (Navigation.AdvanceDirection <> adLeftRight) then
          HideEditor;
      end;

      FDisableChange := False;

      if Assigned(FOnCellChanging) then
        FOnCellChanging(Self,OldRow,OldCol,Row,Col,CanChange);

      AEditor := FDefaultEditor;

      GetCellEditor(OldCol,OldRow,AEditor);

      if not (AEditor in [edNormal,edFloat,edPositiveFloat,edNumeric,edUpperCase,edLowerCase,edPositiveNumeric,edLowerCase,edCapital,edMixedCase,edPassword,edValidChars]) then
      begin
        HideEditor;
      end;
    end;
  end;

  if MouseActions.DisjunctRowSelect then
  begin
    ClearRowSelectInt;
    RowSelect[Row] := true;
  end;
end;

procedure TAdvStringGrid.KeyPress(var Key:Char);
var
  p: Integer;
  RCol: Integer;
  hasfocus: boolean;
begin
  if Key = #27 then
  begin
    if (goEditing in Options) and FEditing then
      RestoreCache;
    if Assigned(OnKeyPress) then
      OnKeyPress(Self,Key);
    Exit;
  end;

  RCol := RealCol;

  if (Key = #13) and not EditMode and not Navigation.AdvanceOnEnter then
  begin
    if not IsEditable(RCol,Row) then
    begin
      if Assigned(OnKeyPress) then
        OnKeyPress(Self, Key);
      Key := #0;
      Exit;
    end;
  end;

  hasfocus := GetFocus = Handle;

  if (Key = #13) and (RowCount = FFixedRowsMin) and Navigation.AdvanceOnEnter then
  begin
    if Assigned(OnKeyPress) then
      OnKeyPress(Self, Key);

    if Navigation.AdvanceInsert then
    begin
      RowCount := RowCount + 1;
      ClearRows(RowCount - 1, 1);
    end;

    Exit;
  end;

  if (Key = #13) and (not hasfocus or HasStaticEdit(RCol,Row)) then
  begin
    if not hasfocus then
      SetFocus;

    AdvanceEdit(Col,Row,False,False,True,False,EditMode);

    if Navigation.AdvanceOnEnter and not Navigation.AdvanceAutoEdit then
    begin
      if Assigned(OnKeyPress) then
        OnKeyPress(Self, Key);
      Key := #0;
      Exit;
    end;

    if HasStaticEdit(RCol,Row) then
    begin
      if Assigned(OnKeyPress) then
        OnKeyPress(Self,Key);
      if Navigation.AdvanceOnEnter then
        ShowInplaceEdit;
      Exit;
    end;
  end;

  if not (goEditing in Options) and
     FNavigation.AutoGotoWhenSorted then
  begin
    if FNavigation.AutoGotoIncremental then
    begin
      if Key = #8 then
        Delete(searchinc,Length(searchinc),1)
      else
        SearchInc := SearchInc + Key;

      SearchTics := 0;
    end
    else
      SearchInc := Key;

    p := Search(AnsiUpperCase(SearchInc));
    if p <> -1 then
    begin
      Row := p;
    end
    else
      SearchInc := '';
  end;

  inherited Keypress(Key);
end;

procedure TAdvStringGrid.SetFixedFooters(Value: Integer);
begin
  FFixedFooters := Value;
  Invalidate;
end;


function TAdvStringGrid.GetDefRowHeightEx: Integer;
begin
  Result := inherited DefaultRowHeight;
end;

procedure TAdvStringGrid.SetDefaultAlignment(const Value: TAlignment);
begin
  if (FDefaultAlignment <> Value) then
  begin
    FDefaultAlignment := Value;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetDefRowHeightEx(const Value: Integer);
begin
  inherited DefaultRowHeight := Value;

  if (csDesigning in ComponentState) then
    FFixedRowHeight := Value;

  FFloatingFooter.FHeight := Value;
  if FFloatingFooter.Visible then
  begin
    FFooterPanel.Height := Value;
  end;
end;


procedure TAdvStringGrid.SetRowCountEx(Value: Integer);
var
  lr: integer;
  flg: boolean;
begin
  lr := RowCount;

  if (RowCount = FixedRows) and (FixedRowAlways) and FSelHidden then
    UnHideSelection;

  flg := (Col = ColCount) or (Row = RowCount);

  if flg then
    FocusCell(FixedCols,FixedRows);

  inherited RowCount := Value;

  if (RowCount > FFixedRowsMin) and FixedRowAlways then
    FixedRows := FFixedRowsMin;

  if Value > FMaxRowCount then
    FMaxRowCount := Value;

  NormalRowCount := Value;
  UpdateFooter;
  UpdateVScroller;
  UpdateHScroller;
  UpdateScrollBars(false);

  if SearchFooter.Visible then
  begin
    TopRow := TopRow + 1;
    TopRow := TopRow - 1;
  end;

  if ScrollType <> ssNormal then
    FlatUpdate;

  // move last row when floating footer is visible
  if (FloatingFooter.Visible) and (Value <> lr) then
  begin
    Rows[Value - 1] := Rows[lr - 1];
    FNilObjects := true;
    ClearRows(lr - 1,1);
    CalcFooter(-1);
    FNilObjects := false;
  end;
end;

function TAdvStringGrid.GetRowCountEx: Integer;
begin
  Result := inherited RowCount;
end;

procedure TAdvStringGrid.SetColCountEx(Value: Integer);
var
  diff,i: integer;
begin
  diff := Length(FVisibleCol);

  inherited ColCount := Value;

  SetLength(FVisibleCol, ColCount + FNumHidden);

  for i := diff to ColCount + FNumHidden - 1 do
    FVisibleCol[i] := true;

  SetLength(FAllColWidths, ColCount + FNumHidden);

  if (ColCount > FFixedColsMin) and FixedColAlways then
    FixedCols := FFixedColsMin;

  if Value > FMaxColCount then
    FMaxColCount := Value;

  i := FSuppressColSizes.Count;
  while i < ColCount do
  begin
    FSuppressColSizes.Add(ColWidths[i]);
    inc(i);
  end;


  UpdateFooter;
  SetBounds(Left,Top,Width,Height);
  UpdateHScroller;
  UpdateVScroller;
  UpdateScrollBars(false);
end;

procedure TAdvStringGrid.SetColEx(const Value: Integer);
begin
  inherited Col := Value;

  FDisSelection := Selection;

  FAECol := -1;
  FAERow := -1;

  if Assigned(FSyncGrid.Grid) then
  begin
    if FSyncGrid.SelectionColumn then
      FSyncGrid.Grid.Col := inherited Col;
  end;
end;

function TAdvStringGrid.GetColCountEx: Integer;
begin
  Result := inherited ColCount;
end;

function TAdvStringGrid.GetColEx: Integer;
begin
  Result := inherited Col;
end;

procedure TAdvStringGrid.SetFixedRowsEx(Value: Integer);
begin
  if (Value >= RowCount) and FFixedRowAlways then
    inherited FixedRows := RowCount - 1
  else
    inherited FixedRows := Value;
  if not (csLoading in ComponentState) then
    FFixedRowsMin := Value;
end;

function TAdvStringGrid.GetFixedRowsEx: Integer;
begin
  Result := inherited FixedRows;
  if (Result = 0) and FixedRowAlways then
    Result := 1;
end;

procedure TAdvStringGrid.SetFixedColsEx(Value: Integer);
begin
  if (Value >= ColCount) and FFixedColAlways then
    inherited FixedCols := ColCount - 1
  else
    inherited FixedCols := Value;

  if not (csLoading in ComponentState) then
    FFixedColsMin := Value;
end;

function TAdvStringGrid.GetFixedColsEx: Integer;
begin
  Result := inherited FixedCols;
  if (Result=0) and FixedColAlways then
    Result := 1;
end;

procedure TAdvStringGrid.SetFixedColWidth(Value: Integer);
var
  i: Integer;
begin
  if not (csLoading in ComponentState) then
    if Value <> DefaultColWidth then
      for i := 1 to FixedCols do
        ColWidths[i - 1] := Value;
end;

function TAdvStringGrid.GetFixedColWidth: Integer;
begin
  Result := ColWidths[0];
end;

procedure TAdvStringGrid.SetFixedRowHeight(Value: Integer);
var
  i: Integer;
begin
  FFixedRowHeight := Value;
  if not (csLoading in ComponentState) then
  begin
    if (Value <> DefaultRowHeight) then
    begin
       for i := 1 to FixedRows do
         RowHeights[i - 1] := Value;
    end
  end;
//  else
//    DefaultRowHeight := Value;
end;

function TAdvStringGrid.GetFixedRowHeight: Integer;
begin
  Result := FFixedRowHeight;
end;

procedure TAdvStringGrid.SetFixedRightCols(Value: Integer);
begin
  FFixedRightCols := Value;
  Invalidate;
end;

function TAdvStringGrid.GetWordWrapEx: boolean;
begin
  Result := FWordWrapEx;
end;

procedure TAdvStringGrid.SetWordWrapEx(Value: Boolean);
begin
  inherited WordWrap := Value;
  FWordWrapEx := Value;
  if InplaceEditor <> nil then
  begin
    TAdvInplaceEdit(self.Inplaceeditor).WordWrap := Value;
  end;
  if FUpdateCount = 0 then
    Invalidate;
end;

function TAdvStringGrid.MatchFilter(ARow: Integer): Boolean;
var
  i,j: Integer;
  s,cond:string;
  temp: Boolean;
  AStyle: TSortStyle;
  APrefix, ASuffix: string;
  AImgIdx: integer;

begin
  Result := True;

  for i := 1 to FFilter.Count do
  begin
    if FFilter.Items[i - 1].Enabled then
    begin

      with FFilter.Items[i - 1] do
      begin
        case FFilter.Items[i - 1].Data of
        fcVirtual:
          begin
            s := Cells[Column, ARow];

            if pos('</', s) > 0 then
              s := HTMLStrip(s);

            if (s = '') then
            begin
              AStyle := ssAutomatic;
              APrefix := '';
              ASuffix := '';
              GetColFormat(Column, AStyle, APrefix, ASuffix);
              if AStyle = ssImages then
              begin
                if GetImageIdx(Column, ARow, AImgIdx) then
                  S := IntToStr(AImgIdx)
                else
                  S:='-1';
              end;
            end;
          end;
        fcNormal: s := GridCells[Column, ARow];
        fcStripHTML: s := Strippedcells[Column, ARow];
        fcCalculated: s := CalcCell(Column, ARow);
        fcRow:
          begin
            if FIgnoreColumns.Count > 0 then
            begin
              s := '';
              for j := 0 to ColCount - 1 do
              begin
                if not FIgnoreColumns.HasValue(j) then
                  s := s + ',' + GridCells[j,ARow];
              end;
            end
            else
            begin
              s := Rows[ARow].Text;
            end;
          end;
        end;

        if RemoveAccented then
        begin
          s := RemoveAccentedStr(Trim(s));
          cond := RemoveAccentedStr(Condition);
        end
        else
        begin
          s := SysUtils.Trim(s);
          cond := Condition;
        end;

        if (pos('|\',s) > 0) then
          s := DecodeWideStr(s);

        if FFilter.Items[i - 1].Data = fcRow then
        begin
          temp := Pos(Uppercase(cond), Uppercase(s)) > 0;
        end
        else
        begin

          if Prefix <> '' then
            if Pos(Prefix,s) = 1 then
              Delete(s,1,Length(Prefix));

          if Suffix <> '' then
            if Pos(Suffix,s) = 1 + Length(s) - Length(Suffix) then
              Delete(s,1 + Length(s) - Length(Suffix),Length(s));

          temp := true;
          try
            if (cond <> '') then
            begin

              case Method of
              fmExpression: temp := MatchStrEx(cond,s,CaseSensitive);
              fmLiteral:
                begin
                  if cond = '""' then
                    temp := s = ''
                  else
                    temp := cond = s;
                end;
              end;
            end;

            //  temp := Condition = '=""'
            //else
          except
            temp := false;
          end;
        end;

        case FFilter.Items[i - 1].Operation of
        foSHORT:
          begin
            Result := temp;
            if not Result then
              Break;
          end;
        foNONE: Result := temp;
        foAND: Result := Result AND temp;
        foOR:  Result := Result OR temp;
        foXOR: Result := Result XOR temp;
        end;
      end;
    end;
  end;

  if Assigned(FOnCustomFilter) then
  begin
    temp := Result;
    FOnCustomFilter(Self, ARow, temp);
    Result := temp;
  end;

end;

procedure TAdvStringGrid.FilterDropDownChanged(Sender: TObject);
begin
  Invalidate;
end;

procedure TAdvStringGrid.FilterRow(ARow: Integer);
begin
  if not MatchFilter(ARow) then
  begin
    HideRow(RemapRowInv(ARow));
  end;
end;

procedure TAdvStringGrid.SaveFilter(FileName: string);
var
  i: integer;
  inif: TINIFile;
  section: string;
begin
  try
    inif := TINIFile.Create(FileName);

    try
      inif.WriteInteger('FILTER','COUNT',Filter.Count);

      for i := 0 to Filter.Count - 1 do
      begin
        section := 'ITEM'+inttostr(i);
        inif.WriteString(section,'CONDITION',Filter.Items[i].Condition);
        inif.WriteInteger(section,'COLUMN',Filter.Items[i].Column);
        inif.WriteInteger(section,'OPERATION',integer(Filter.Items[i].Operation));
        inif.WriteInteger(section,'METHOD',integer(Filter.Items[i].Method));
        inif.WriteBool(section,'CASE',Filter.Items[i].CaseSensitive);
        inif.WriteBool(section,'ENABLED',Filter.Items[i].Enabled);
        inif.WriteBool(section,'REMOVEACCENTED',Filter.Items[i].RemoveAccented);

        inif.WriteString(section,'PREFIX',Filter.Items[i].Prefix);
        inif.WriteString(section,'SUFFIX',Filter.Items[i].Suffix);
        inif.WriteString(section,'FRIENDLYNAME',Filter.Items[i].FriendlyName);
      end;
    finally
      inif.Free;
    end;
  except
  end;
end;

procedure TAdvStringGrid.LoadFilter(FileName: string);
var
  i,cnt: integer;
  inif: TINIFile;
  section: string;
  fd: TFilterData;
begin
  try
    inif := TINIFile.Create(FileName);

    try
      cnt := inif.ReadInteger('FILTER','COUNT',-1);

      if cnt > 0 then
      begin
        Filter.Clear;

        for i := 0 to cnt - 1 do
        begin
          fd := Filter.Add;

          section := 'ITEM'+inttostr(i);
          fd.Condition := inif.ReadString(section,'CONDITION','');
          fd.Column := inif.ReadInteger(section,'COLUMN',0);
          fd.Operation := TFilterOperation(inif.ReadInteger(section,'OPERATION',0));
          fd.Method := TFilterMethod(inif.ReadInteger(section,'METHOD',0));
          fd.CaseSensitive := inif.ReadBool(section,'CASE',false);
          fd.Enabled := inif.ReadBool(section,'ENABLED',true);
          fd.RemoveAccented := inif.ReadBool(section,'REMOVEACCENTED',false);

          fd.Prefix := inif.ReadString(section,'PREFIX','');
          fd.Suffix := inif.ReadString(section,'SUFFIX','');
          fd.FriendlyName := inif.ReadString(section,'FRIENDLYNAME','');
        end;
      end;

    finally
      inif.Free;
    end;
  except
  end;
end;

procedure TAdvStringGrid.RemoveAllFilters;
begin
  if FFilterLevel = 0 then
    Filter.Clear
  else
    while (FFilterLevel >= 1) do
      RemoveLastFilter;

  FIsNarrowDown := false;
end;

function TAdvStringGrid.RemoveLastFilter: boolean;
begin
  Result := false;
  if (FFilterLevel > 0) then
  begin
    UnHideRowList;
    FixedRows := FFilterFixedRows;
    if FSelHidden then
      UnHideSelection;
    // update floating footer if necessary
    CalcFooter(-1);
    dec(FFilterLevel);
    if FFilterLevel > 1 then
      Result := true;
    if Filter.Count > 0 then
      Filter.Delete(Filter.Count - 1);
  end;
  FIsNarrowDown := false;
end;

procedure TAdvStringGrid.NarrowDown(ACondition: string; AColumn: integer = -1);
begin
  NarrowDown(ACondition, false, AColumn);
end;

procedure TAdvStringGrid.NarrowDown(ACondition: string; DoRemoveAccented: boolean; AColumn: integer = -1);
var
  isincr: boolean;
begin
  isincr := false;

  FIsNarrowDown := (ACondition <> '');

  FixedRowAlways := true;

  if Length(ACondition) = Length(FLastFilter) + 1 then
  begin
    if Pos(FLastFilter, ACondition) = 1 then
    begin
      isincr := true;
      Filter.Clear;
      with Filter.Add do
      begin
        if AColumn <> -1 then
        begin
          Data := fcNormal;

          Condition := '*' + ACondition + '*';

          if pos(' ', Condition) > 0 then
            Condition := '"' + Condition +'"';
        end
        else
        begin
          Data := fcRow;
          Condition := ACondition;
        end;
        RemoveAccented := DoRemoveAccented;
        CaseSensitive := false;
        Column := AColumn;
      end;
      ApplyFilter;
    end;
  end;

  if (length(ACondition) + 1 = length(FLastFilter)) and (ACondition <> '') then
  begin
    if Pos(ACondition, FLastFilter) = 1 then
    begin
      isincr := true;
      RemoveLastFilter;
    end;
  end;

  if not isincr then
  begin
    RemoveAllFilters;

    if (ACondition <> '') then
    begin
      Filter.Clear;
      with Filter.Add do
      begin
        if AColumn <> -1 then
        begin
          Data := fcNormal;
          Condition := '*'+ACondition+'*';
        end
        else
        begin
          Data := fcRow;
          Condition := ACondition;
        end;

        RemoveAccented := DoRemoveAccented;
        CaseSensitive := false;
        Column := AColumn;
      end;
      ApplyFilter;
    end;
  end;

  FLastFilter := ACondition;

  if ACondition = '' then
    FGridItems.Clear;
end;

procedure TAdvStringGrid.ApplyFilter;
var
  i: Integer;
  RowsToDo,RowsDone: Integer;
  il: TIntList;

begin
  FFilterFixedRows := FFixedRowsMin;

  RowsDone := 0;
  RowsTodo := RowCount - FFixedFooters - FFixedRowsMin;

  if RowsTodo = 0 then
    Exit;

  il := TIntList.Create(0,0);

  for i := FixedRows to RowCount - FFixedFooters - 1 do
  begin
    if FFilterNormalCellsOnly and (IsNode(i) or IsSummary(i)) then
      Continue;

    if not MatchFilter(i) then
      il.Add(i);

    Inc(RowsDone);

    if Assigned(FOnFilterProgress) and (RowsTodo > 0) then
      FOnFilterProgress(Self, Round(100* (RowsDone / RowsTodo)));
  end;

  // il = list of indexes of rows to hide
  HideRowList(il);
  il.Free;

  if Assigned(FOnFilterProgress) and (RowsTodo > 0) then
    FOnFilterProgress(Self, Round(100* (RowsDone / RowsTodo)));
end;

procedure TAdvStringGrid.FilterCheck(Sender: TObject; ItemIndex: Integer);
var
  i,j: integer;
  F,FN,C,FNC: string;
  allchecked: boolean;
begin
  if (ItemIndex < 0) or (ItemIndex >= FDropCheckList.Count) then
    Exit;

  if (FilterColumn >= 0) and (FilterColumn < AllColCount) then
  begin
    GetFilter(FilterColumn);

    if FAutoFilterUpdate then
      FilterActive := False;

    if FilterDropDownMultiCol then
    begin
      for i := Filter.Count - 1 downto 0 do
      begin
        if Filter.Items[i].Column = FilterColumn  then
          Filter.Delete(i);
      end;
    end
    else
      Filter.Clear;

    C := '';
    FNC := '';

    allchecked := false;

    if FilterDropDownAuto then
    begin
      allchecked := true;
      j := 0;
      if (FFilterDropDownCheckUnCheckAll <> '') then
      begin
        j := 1;

        if (ItemIndex > 0) and not FDropCheckList.Checked[ItemIndex] then
        begin
         FDropCheckList.Checked[0]  := false;
        end;
      end;

      for i := j to FDropCheckList.Items.Count - 1 do
      begin
        if not FDropCheckList.Checked[i] then
          allchecked := false;
      end;
    end;

    if (FDropCheckList.ItemIndex = 0) and (FFilterDropDownCheckUnCheckAll = FDropCheckList.Items[ItemIndex]) and
      (FFilterDropDownCheckUnCheckAll <> '') then
    begin
      for i := 1 to FDropCheckList.Count - 1 do
         FDropCheckList.Checked[i] := FDropCheckList.Checked[0];
    end;

    if Assigned(FOnFilterCheckClick) then
      FOnFilterCheckClick(Self,FilterColumn,ItemIndex,FDropCheckList.Checked[ItemIndex],FDropCheckList);

    if not allchecked then
    begin
      for i := 0 to FDropCheckList.Items.Count - 1 do
      begin
        if FDropCheckList.Checked[i] and (i < FilterList.Count) then
        begin
          F := FilterList[i];
          if Pos(#9,F) > 0 then
            FN := Copy(F,1,Pos(#9,F)-1)
          else
            FN := F;

          if (F = '') or (F = ' ') then
            F := '""';

          if Pos(#9,F) > 0 then
            F := Copy(F,Pos(#9,F) + 1,Length(F))
          else
          begin
            if Pos('&',F) > 0 then
              F := '"' + F + '"'
            else
            if Pos('(',F) > 0 then
              F := '"' + F + '"'
            else
            if Pos(')',F) > 0 then
              F := '"' + F + '"';
          end;

          if F = FilterDropDownClear then
            F := '';

          if F = FilterDropDownCheckUnCheckAll then
            F := '';

         if Assigned(FOnFilterCheck) then
            FOnFilterCheck(Self,FilterColumn,i,FN,F,FDropCheckList);

         if C = '' then
           C := F
         else
           C := C + '|' + F;

         if FNC = '' then
           FNC := FN
         else
           FNC := FNC + '|' + FN;

          (*
          with Filter.Add do
          begin
            Condition := F;
            Column := FilterColumn;
            if Filter.Count > 1 then
              Operation := foOR
            else
              Operation := foNone;
          end;
          *)
        end;
      end;

      if C <> '' then
      begin
        with Filter.Add do
        begin
          FriendlyName := FNC;
          Condition := C;
          Column := FilterColumn;
          CaseSensitive := FilterDropDown.CaseSensitive;

          if (pos('</',C) > 0) then
            Method := fmLiteral;
          if Filter.Count > 1 then
            Operation := foAND
          else
            Operation := foNone;
        end;
      end;

      FilterActive := Filter.Count > 0;

      DoFilterDone;
    end;
    FDropCheckList.Invalidate;
  end;
end;

procedure TAdvStringGrid.FilterSelect(Sender: TObject; ItemIndex: Integer);
var
  F,FN: string;
  dck: boolean;
begin
  SetFocus;

  if (FilterColumn >= 0) and (FilterColumn < AllColCount) then
  begin
    if (ItemIndex >= 0) and (ItemIndex < DropList.Items.Count) then
    begin
      dck := IsDataCheckCol(FilterColumn);

      GetFilter(FilterColumn);

      F := FilterList[ItemIndex];

      if Pos(#9,F) > 0 then
        FN := Copy(F,1,Pos(#9,F)-1)
      else
        FN := F;

      if dck then
      begin
        if F = FilterDropDown.TextChecked then
          F := GetColumnCheckTrue(FilterColumn);

        if F = FilterDropDown.TextUnchecked then
          F := GetColumnCheckFalse(FilterColumn);
      end;

//      if FAutoFilterDisplay then
//        FColumnCollection.Items[FilterColumn].Header := FN;

      if FAutoFilterUpdate then
        FilterActive := False;

      if Pos(#9,F) > 0 then
        F := Copy(F,Pos(#9,F) + 1,Length(F));

      if F = FilterDropDownClear then
        F := '';

      if (Pos('&',f) > 0) and (f[1] <> '"') then
        f := '"' + f + '"';

      if Assigned(FOnFilterSelect) then
        FOnFilterSelect(Self,FilterColumn,ItemIndex,FN,F);

      if not FFilterDropDownMultiCol then
        Filter.Clear;

      if F <> '' then
      begin
        Filter.ColumnFilter[FilterColumn].FriendlyName := FN;
        Filter.ColumnFilter[FilterColumn].Condition := F;
      end
      else
        Filter.RemoveColumnFilter(FilterColumn);

      //Filter.ColumnFilter[FilterColumn].CaseSensitive :=
      //  FColumnCollection.Items[FilterColumn].FilterCaseSensitive;

      if FAutoFilterUpdate then
      begin
        FixedRowAlways := true;
        FilterActive := True;

        if not ((RowCount = FixedRows) or ((RowCount = 1) and FixedRowAlways)) then
          Row := FixedRows;

        DoFilterDone;
      end;
    end;
  end;

  FilterColumn := -1;
end;

procedure TAdvStringGrid.SetFilterRow(const Value: Integer);
begin
  if (Value < FixedRows) then
  begin
    FFilterRow := Value;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetFilterActive(const Value: Boolean);
begin
  // Do nothing when component is loading
  if csLoading in ComponentState then
    Exit;

  if FFilterActive <> Value then
  begin
    FFilterActive := Value;


    if FFilterActive then
    begin
      if (Row >= RowCount) or (Col >= ColCount) then
        FocusCell(FixedCols, FixedRows);

      BeginUpdate;
      try
        ApplyFilter;
      finally
        EndUpdate;
      end;

      FSelHidden := False;
      {
      if (RowCount = FixedFooters + FFilterFixedRows) and not FixedRowAlways then
      begin
        RowCount := FixedFooters + FFilterFixedRows + 1;
        FixedRows := FFilterFixedRows;
      end
      else
        FFilterFixedRows := 0;
      }
      TopRow := FixedRows;
    end
    else
    begin
      {
      if (RowCount = FixedRows + FixedFooters + 1) and (FFilterFixedRows > 0) then
      begin
        FFilterFixedRows := FixedRows;
        RowCount := RowCount - 1;
      end
      else
        FFilterFixedRows := FixedRows;
      }
      UnHideRowList;

      FixedRows := FFilterFixedRows;

      if FSelHidden then
        UnHideSelection;

      TopRow := FixedRows;
    end;
  end;
  // update floating footer if necessary
  CalcFooter(-1);
end;

procedure TAdvStringGrid.SetFilterDropDownAuto(const Value: Boolean);
begin
  if (FFilterDropDownAuto <> Value) then
  begin
    FFilterDropDownAuto := Value;
    Invalidate;
    if FFilterDropDownAuto then
      FixedRowAlways := true;

  end;
end;


procedure TAdvStringGrid.SetFilterEdit(const Value: TFilterEdit);
begin
  FFilterEdit.Assign(Value);
end;

procedure TAdvStringGrid.SetDragScrollOptions(value: TDragScrollOptions);
begin
  FDragScrollOptions.Assign(Value);
end;

procedure TAdvStringGrid.SetSelectionColor(AColor: TColor);
begin
  if (FSelectionColor <> AColor) then
  begin
    FSelectionColor := AColor;
    Invalidate;
  end;  
end;

procedure TAdvStringGrid.SetSelectionColorMixer(const Value: boolean);
begin
  if (FSelectionColorMixer <> Value) then
  begin
    FSelectionColorMixer := Value;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetSelectionColorMixerFactor(const Value: integer);
begin
  if (FSelectionColorMixerFactor <> Value) then
  begin
    if Value > 100 then
      FSelectionColorMixerFactor := 100
    else
    if Value < 0 then
      FSelectionColorMixerFactor := 0
    else
      FSelectionColorMixerFactor := Value;

    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetSelectionColorTo(AColor: TColor);
begin
  if (FSelectionColorTo <> AColor) then
  begin
    FSelectionColorTo := AColor;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetSelectionMirrorColor(AColor: TColor);
begin
  if (FSelectionMirrorColor <> AColor) then
  begin
    FSelectionMirrorColor := AColor;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetSelectionMirrorColorTo(AColor: TColor);
begin
  if (FSelectionMirrorColorTo <> AColor) then
  begin
    FSelectionMirrorColorTo := AColor;
    Invalidate;
  end;
end;


procedure TAdvStringGrid.SetSelectionTextColor(AColor: TColor);
begin
  if (FSelectionTextColor <> AColor) then
  begin
    FSelectionTextColor := AColor;
    Invalidate;
  end;  
end;

procedure TAdvStringGrid.SetSelectionRectangle(AValue: Boolean);
begin
  if (FSelectionRectangle <> AValue) then
  begin
    FSelectionRectangle := AValue;
    Invalidate;
  end;  
end;

procedure TAdvStringGrid.SetSelectionResizer(const Value: Boolean);
begin
  if (FSelectionResizer <> Value) then
  begin
    FSelectionResizer := Value;
    Invalidate;
  end;    
end;

procedure TAdvStringGrid.SetMaxEditLength(const AValue: Integer);
begin
  FMaxEditLength := AValue;
  if Assigned(NormalEdit) then
    NormalEdit.LengthLimit := AValue;
end;

procedure TAdvStringGrid.SetShowSelection(AValue: Boolean);
begin
  if FShowSelection <> AValue then
  begin
    FShowSelection := AValue;
    FShowSel := AValue;
    Invalidate;
  end;
end;

procedure TAdvStringGrid.SetSizeWithForm(const Value: Boolean);
begin
  if (FSizeWithForm <> Value) then
  begin
    FSizeWithForm := Value;
    Anchors := [akLeft,akTop,akBottom,akRight];
  end;
end;

procedure TAdvStringGrid.SetSortSettings(const Value: TSortSettings);
begin
  FSortSettings.Assign(Value);
end;

procedure TAdvStringGrid.SetSpreadSheet(const Value: boolean);
begin
  FSpreadSheet := Value;
  SelectionRectangle := true;
  SelectionResizer := true;
  Navigation.AllowSmartClipboard := true;
  Options := Options + [goEditing, goRangeSelect];
  MouseActions.RangeSelectAndEdit := true;
end;

procedure TAdvStringGrid.SetVAlignment(AVAlignment:TVAlignment);
begin
  FVAlignment := AVAlignment;
  FVAlign := DT_VCENTER;
  case FVAlignment of
  vtaTop:FVAlign := DT_TOP;
  vtaBottom:FVAlign := DT_BOTTOM;
  end;
  if FUpdateCount = 0 then
    Invalidate;
end;

{$IFDEF TMSGDIPLUS}
procedure TAdvStringGrid.SetOfficeHint(const Value: TAdvHintInfo);
begin
  FOfficeHint.Assign(Value);
end;
{$ENDIF}

procedure TAdvStringGrid.SetAutoColor(const Value: TAutoColor);
begin
  FAutoColor.Assign(Value);
end;

procedure TAdvStringGrid.SetAutoSizeP(AAutoSize: Boolean);
begin
  FAutoSize := AAutoSize;
  if FAutosize and not (csLoading in ComponentState) then
    AutoSizeColumns(False,10);
end;

procedure TAdvStringGrid.SetFlat(const AValue: Boolean);
begin
  FFlat := AValue;
  if not (csLoading in ComponentState) then
    Invalidate;
end;

function TAdvStringGrid.GetCellAlignment(ACol,ARow: Integer): TCellAlignment;
var
  HAlign: TAlignment;
  VAlign: TVAlignment;
  s: string;
  formula: boolean;

begin
  HAlign := FDefaultAlignment;
  VAlign := VAlignment;
  formula := false;

  if FAutoNumAlign then
  begin
    s := Cells[ACol,ARow];
    if (s <> '') then
    begin
      formula := Pos('=',s) = 1;
      if formula then
        s := CalcCell(ACol,ARow);

      if Length(s) > 3 then
      begin
        if (s[1] = '|') and (s[2] = '\') and (ord(s[4]) = 61) then
        begin
          s := CalcCell(ACol,ARow);
        end;
      end;

      if IsType(SysUtils.Trim(s)) in [AdvUtil.atNumeric,AdvUtil.atFloat,AdvUtil.atScientific] then
      begin
        HAlign := taRightJustify;
      end;
    end;
  end;

  if not FAutoNumAlign and (HasCellProperties(ACol,ARow) and not Formula) then
    HAlign := CellProperties[ACol,ARow].Alignment;

  GetCellAlign(ACol,ARow,HAlign,VAlign);

  Result.Alignment := HAlign;
  Result.VAlignment := VAlign;
end;

function TAdvStringGrid.GetCellTextSize(ACol,ARow: Integer;VS: Boolean = false; SB: boolean = false): TSize;
var
  RCol: integer;
begin
  RCol := RemapColInv(ACol);
  Result := GetCellTextSizeInt(ACol,RCol,ARow,False,VS,SB);
end;

function TAdvStringGrid.GetCellTextSizeInt(ACol,RCol,ARow: Integer;ColSize: boolean; VS: Boolean = false; SB: boolean = false): TSize;
var
  s,su,Anchor,Stripped,FocusAnchor,AnchorHint: string;
  MaxSize,NewSize,NumLines,hl,ml: Integer;
  r,hr,cr: TRect;
  ctt: TTextType;
  AState: TGridDrawState;
  CID,CT,CV: string;
  AAngle: Integer;
  AAngleRad: double;
  AAngleSin: double;
  AAngleCos: double;
  x1,x2,y1,y2: Integer;
  th: Integer;
  {$IFDEF TMSUNICODE}
  ws: widestring;
  {$ENDIF}
  FImages: TCustomImageList;
  rotated: boolean;
  flg: DWORD;

begin
  MaxSize := 0;
  NumLines := 0;

  if EditMode and (Col = ACol) and (ARow = Row) then
  begin
    if Assigned(NormalEdit) then
      s := NormalEdit.Text
    else
      s := GetFormattedCell(ACol,ARow);
  end
  else
    s := GetFormattedCell(RCol,ARow);

  ctt := TextType(s,FEnableHTML);

  AState := [];

  // Faster version to use just for font purposes
  GetFontProperties(ACol,RCol,ARow,AState,Canvas.Font,Canvas.Brush, true);

  if ((ARow < FixedRows) or (ACol < FixedCols)) and ActiveCellShow and (fsBold in ActiveCellFont.Style) then
  begin
    Canvas.Font.Style := Canvas.Font.Style + [fsBold];
  end;

  //GetVisualProperties(RCol,ARow,AState,False,True,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlign,VAlign,WW,GD);
  if Canvas.Font.Size + FZoomFactor <> 0 then
    Canvas.Font.Size := Canvas.Font.Size + FZoomFactor
  else
    Canvas.Font.Size := 1;

  if ctt = ttFormula then
    s := CalcCell(ACol,ARow);

  r := CellRect(ACol,ARow);

  if FXYOffsetTopLeftOnly then
  begin
    r.Left := r.Left + FXYOffset.X;
    r.Top := r.Top + FXYOffset.Y;
  end
  else
    InflateRect(r, - FXYOffset.X, - FXYOffset.Y);

  // has a scrollbar
  if SB then
    r.Right := r.Right - 17;

  if ctt = ttHTML then
  begin
    if ColSize then
      r.Right := $ffff;

    r.Bottom := $ffff;

    FImages := GetCellImageList(ACol, ARow);

    HTMLDrawEx(Canvas,s,r,FImages,0,0,-1,0,1,False,True,False,True,True,False,not EnhTextSize,false,'',
               0.0,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
               Integer(Result.cx),Integer(Result.cy),hl,ml,hr,cr,CID,CT,CV,FImageCache,FContainer,Handle,BidiMode);

    Result.cx := Result.cx + 2 {+ XOffsetSize};
    Result.cy := Result.cy + 2 {+ YOffsetSize};
    Exit;
  end;

  if (ctt = ttRTF) and not (csDesigning in ComponentState) then
  begin
    RichEdit.Clear;
    RichEdit.Left := 0;
    RichEdit.Top := 0;
    RichEdit.Width := 0;
    RichEdit.Height := 0;

    RichEdit.WordWrap := false;

    CellToRich(ACol,ARow,RichEdit);

    Canvas.Font.Name := RichEdit.SelAttributes.Name;
    Canvas.Font.Size := RichEdit.SelAttributes.Size;
    Canvas.Font.Style := RichEdit.SelAttributes.Style;
    s := RichEdit.Text;
  end;

  {$IFDEF TMSUNICODE}
  if ctt = ttUnicode then
  begin
    ws := WideCells[ACol,ARow];

    {
    GetTextExtentPoint32W(Canvas.Handle,PWidechar(ws),Length(ws),sz);
    Result.cy := sz.cy;
    Result.cx := sz.cx + 2 * FXYOffset.X;
    }

    if Win32Platform = VER_PLATFORM_WIN32_NT then
    begin
      if WordWrap or MultiLineCells then
        Result.cy := DrawTextExW(Canvas.Handle,PWidechar(ws),Length(ws),r,DT_LEFT or DT_WORDBREAK or DT_NOPREFIX or DT_CALCRECT,nil)
      else
        Result.cy := DrawTextExW(Canvas.Handle,PWidechar(ws),Length(ws),r,DT_LEFT or DT_SINGLELINE or DT_NOPREFIX or DT_CALCRECT,nil);
    end
    else
    begin
      ExtTextOutW(Canvas.Handle,r.Left,r.Top,ETO_CLIPPED,@r,PWideChar(ws),Length(ws),nil);
    end;

    s := ws;

    Result.cx := (r.Right - r.Left);
    Exit;
  end;
  {$ENDIF}

  rotated := IsRotated(ACol,ARow,AAngle);

  if VS then
  begin
    //InflateRect(r,-2, -2);

    // if editing cell and return pressed, calculate height assuming new line
    if EditMode and (RCol = Col) and (ARow = Row) and (length(s) > 0) then
    begin
      if s[length(s)] = #10 then
        s := s + 'w';
    end;

    if ColSize then
      r.Right := $FFFF;

    if rotated then
      flg := DT_EDITCONTROL or DT_CALCRECT or DT_SINGLELINE or DT_LEFT or DT_NOPREFIX or DT_EXPANDTABS
    else
      flg := DT_EDITCONTROL or DT_CALCRECT or DT_WORDBREAK or DT_LEFT or DT_NOPREFIX or DT_EXPANDTABS;

    if (s <> '') then
    begin
      Result.cy := DrawTextEx(Canvas.Handle,PChar(s),Length(s),r,flg,nil) {+ YOffsetSize};
      Result.cx := (r.Right - r.Left);
    end
    else
    begin
      Result.cx := 0;
      Result.cy := 0;
    end;
  end
  else
  begin
    if (s <> '') then
    begin
      repeat
        su := GetNextLine(s,FMultiLineCells);

        if URLShow and not URLFull and (ctt = ttText) then
          StripURLProtoCol(su);

        NewSize := Canvas.TextWidth(su);
        if NewSize > MaxSize then
          MaxSize := NewSize;
        Inc(NumLines);
      until s = '';

      Result.cx := MaxSize;
      th := Canvas.TextHeight('gh');
      Result.cy := NumLines * th;
    end
    else
    begin
      Result.cx := 0;
      Result.cy := 0;
    end;
  end;

  if rotated then
  begin
    AAngleRad := AAngle * Pi/180;
    AAngleSin := Sin(AAngleRad);
    AAngleCos := Cos(AAngleRad);

    x1 := Abs(Trunc(Result.cx * AAngleCos));
    x2 := Abs(Trunc(Result.cy * AAngleSin));

    y1 := Abs(Trunc(Result.cx * AAngleSin));
    y2 := Abs(Trunc(Result.cy * AAngleCos));

    // distance + correction for font corners
    Result.cx := Abs(x2 - x1) + 12;
    Result.cy := Abs(y2 - y1) + 12;
  end;

  if (ctt = ttRTF) and not (csDesigning in ComponentState) then
  begin
    RichEdit.Width := r.Right - r.Left;
    RichEdit.Height := r.Bottom - r.Top;

    RichEdit.WordWrap := True;
    RichEdit.WordWrap := False;
    RichEdit.WordWrap := FWordWrapEx;

    SetTranspWindow(RichEdit.Handle);

    {
    // force control recreation.
    // Is necessary to force correct recalculation somehow for TRichEdit
    FRichEdit.Width := MaxSize;
    FRichEdit.Height := 2;
    FRichEdit.WordWrap := True;
    FRichEdit.WordWrap := False;
    FRichEdit.WordWrap := FWordWrapex;
    SetTranspWindow(FRichEdit.Handle);

    // We need to force a proper REQUESTRESIZE.
    // Direct message EM_RESIZEREQUEST does not work on Win2K!
    }

    {$IFNDEF DELPHI_UNICODE}
    RichEdit.Lines.Add('');
    RichEdit.Lines.Delete(RichEdit.Lines.Count - 1);
    {$ENDIF}
    Result.cx := RichEdit.ReqWidth;
    Result.cy := RichEdit.ReqHeight + 4; // account for RTF drawing offset
  end;
end;

procedure TAdvStringGrid.NCPaintProc;
var
  DC: HDC;
  WindowBrush:hBrush;
  Canvas: TCanvas;
  {$IFDEF DELPHIXE2_LVL}
  LStyle: TCustomStyleServices;
  {$ENDIF}
begin
  if not (Look in [glSoft,glTMS,glXP,glVista,glListView,glWin7,glOffice2007,glCustom]) then
    Exit;

  {$IFDEF DELPHIXE2_LVL}
  LStyle := StyleServices;
  if LStyle.Enabled and (LStyle.Name <> 'Windows') then
    Exit;
  {$ENDIF}

  if (BorderStyle = bsNone) or (BorderColor = clNone) then
    Exit;

  if Flat and (Look <> glCustom) then
    Exit;

  DC := GetWindowDC(Handle);
  WindowBrush := 0;
  Canvas := TCanvas.Create;
  try
    Canvas.Handle := DC;
    WindowBrush := CreateSolidBrush(ColorToRGB(clRed));

    Canvas.Pen.Color := BorderColor;

    if FFitCellsInGrid then
    begin
      Canvas.MoveTo(1,Height);
      Canvas.LineTo(1,1);
      Canvas.LineTo(Width - 2,1);
      Canvas.LineTo(Width - 2,Height - 2);
      Canvas.LineTo(1,Height - 2);

      if (Parent is TWinControl) then
      begin
        Canvas.Pen.Color := (Parent as TWinControl).Brush.Color;
        Canvas.MoveTo(0,Height);
        Canvas.LineTo(0,0);
        Canvas.LineTo(Width - 1,0);
        Canvas.LineTo(Width - 1,Height - 1);
        Canvas.LineTo(0,Height-1);
      end;
    end
    else
    begin
      if FIsComCtl6 then // themed xp app
      begin
        Canvas.MoveTo(0,Height - 1);
        Canvas.LineTo(0,0);
        Canvas.LineTo(Width - 1,0);
        Canvas.LineTo(Width - 1,Height - 1);
        Canvas.LineTo(0,Height - 1);
      end;
    end;

  finally
    Canvas.Free;
    DeleteObject(WindowBrush);
    ReleaseDC(Handle,DC);
  end;
end;

procedure TAdvStringGrid.WMNotify(var Message: TWMNOTIFY);
var
  buffer:array[0..255] of char;
  pt: TPoint;
  di: PNMTTDispInfo;
  ATitle, AText, s: string;
  AIcon: Integer;
  cellX,cellY,cellRX: Integer;
  len1, len2, i: Integer;
  FDateTime: TDateTime;
  bi: TBalloonIcon;

begin

  with Message.NMHdr^ do
    case code of
    TTN_NEEDTEXT:
    begin
      if not Balloon.Enable then
        Exit;

      di := PNMTTDispInfo(TMessage(Message).LParam);

      GetCursorPos(pt);
      pt := ScreenToClient(pt);

      MouseToCell(pt.X,pt.Y,cellX,cellY);
      IsBaseCellEx(cellX,cellY,cellX,cellY);

      //ATitle := 'test';
      //AText := 'hello world '+inttostr(cellx)+':'+inttostr(celly);

      cellRX := RealColIndex(cellX);

      if (cellx <> -1) and (celly <> -1) then
      begin
        s := Cells[cellRX,cellY];

        case TextType(s,FEnableHTML) of
        ttUnicode: s := WideCells[cellRX, cellY];
        ttRTF:
          begin
            CellToRich(cellRX, cellY, RichEdit);
            s := RichEdit.Text;
          end;
        ttHTML: s := HTMLStrip(s);
        else
          s := Cells[cellRX, cellY];
        end;

        AText := s;
      end;

      len1 := Length(AText);
      len2 := SizeOf(FTooltipBuffer) div 4;

      // balloon tooltip cannot handle tabs well
      i := 1;
      while i < len1 do
      begin
        if AText[i] = #9 then
          AText[i] := #32;
        inc(i);
      end;

      i := 1;
      if AText <> '' then
        while (AText[i] = #13) or (AText[i] = #10) or (AText[i] = #9) do
          inc(i);

      if len1 > len2 then
        AText := Copy(AText, i, len2 - 3) + '...'
      else
        if i > 1 then
          AText := Copy(AText, i, len1 - i + 1);

      bi := biInfo;

      // for some reason, balloon tips will not show multiline when there is no title  ...
      if ATitle = '' then
        ATitle := ' ';

      if (CellX >= 0) and (CellY >= 0) then
        IsBalloon(cellRX, cellY, Atitle, Atext, bi);

      AIcon := Integer(bi);

      if Assigned(OnCellBalloon) then
         OnCellBalloon(self, cellRX, cellY, ATitle, AText, AIcon);

      FLastBalloonPos := Point(cellX, cellY);

      strpcopy(ftooltipbuffer,AText);

      if length(ATitle) > 100 then
        ATitle := copy(ATitle,1, 97) + '...';

      strpcopy(buffer,ATitle);

      di^.lpszText := @ftooltipbuffer;

      SendMessage(fhtooltip, TTM_SETMAXTIPWIDTH, 0, 300);

      if Balloon.TextColor <> clNone then
        SendMessage(fhtooltip, TTM_SETTIPTEXTCOLOR, ColorToRgb(Balloon.TextColor), 0);
      if Balloon.BackgroundColor <> clNone then
        SendMessage(fhtooltip, TTM_SETTIPBKCOLOR, ColorToRgb(Balloon.BackgroundColor), 0);

      SendMessage(fhtooltip,TTM_SETTITLE,AIcon,LParam(@buffer));
    end;

    TTN_SHOW:
    begin
    end;
    TTN_POP:
    begin
    end;

    DTN_DATETIMECHANGE:
    begin
      if Assigned(FOnDateTimeChange) then
      begin
        with PNMDateTimeChange(Message.NMHdr)^ do
        begin
          if (st.wYear > 0) and (st.wMonth > 0) and (st.wDay > 0) then
            FDateTime := SystemTimeToDateTime(st)
          else
            FDateTime := 0;
          FOnDateTimeChange(Self, Col, Row, FDateTime);
        end;
      end;
      inherited;
    end;
    else
      inherited;
    end;
end;


procedure TAdvStringGrid.WMNCPaint(var Message: TMessage);
begin
  inherited;

  if FUpdateCount > 0 then
    Exit;
  NCPaintProc;

  Message.Result := 0;
end;


function TAdvStringGrid.MouseOverDesignChoice(X, Y: Integer): Integer;
var
  r: TRect;
  fh: Integer;
  h: Integer;
  sl: string;
begin
  Result := -1;

  r := ClientRect;
  Canvas.Font.Name := 'Tahoma';
  Canvas.Font.Size := 8;

  fh := Canvas.TextHeight('gh') + 2;

  h := 4 * fh + 10;

  if (x > r.Right - 16) and
    (y > r.Bottom - h) and
    (y < r.Bottom - h + 16) then
    Result := 4;

  if (x > r.Right - 150) and (x < r.Right - 150 + Canvas.TextWidth(s_Edit) + 18) and
    (y > r.Bottom - h + fh + 4) and
    (y < r.Bottom - h + 2 * fh + 4) then
    Result := 1;

  if (x > r.Right - 150) and (x < r.Right - 150 + Canvas.TextWidth(s_ColNr) + 18) and
    (y > r.Bottom - h + 2 * fh + 4) and
    (y < r.Bottom - h + 3 * fh + 4) then
    Result := 2;

  sl := s_Look + ': ' + GetLookAsFriendlyString(Look);

  if (x > r.Right - 150) and (x < r.Right - 150 + Canvas.TextWidth(sl)) and
    (y > r.Bottom - h + 3 * fh + 4) and
    (y < r.Bottom - h + 4 * fh + 4) then
    Result := 3;
end;


procedure TAdvStringGrid.CMDesignHitTest(var Msg: TCMDesignHitTest);
var
  r: TRect;
  p: TPoint;
  nc: Integer;
begin
  inherited;
  if (csDesigning in ComponentState) and FShowDesignHelper then
  begin
    GetCursorPos(P);
    P := ScreenToClient(P);

    nc := MouseOverDesignChoice(P.X, P.Y);

    if nc <> FLastDesignChoice then
    begin
      r := ClientRect;
      r := Rect(r.Right - 150, r.Bottom - 70, r.Right, r.Bottom);
      InvalidateRect(Handle, @r, true);
    end;
    FLastDesignChoice := nc;
    if nc in [1, 2, 3, 4] then
      Msg.Result := 1;
  end;
end;


procedure UpdateAlphaWindow(Wnd: HWND; AlphaMap: TGridAlphaMask);
var
  Blend: _BlendFunction;
  Rect: TRect;
  P1, P2: TPoint;
  S: TSize;
  DC: HDC;
begin
  if AlphaMap.Height = 0 then
    Exit;

  SetWindowLong(Wnd, GWL_EXSTYLE, GetWindowLong(Wnd, GWL_EXSTYLE) or WS_EX_LAYERED);
  GetWindowRect(Wnd, Rect);
  P1.X := Rect.Left;
  P1.Y := Rect.Top;
  SetWindowPos(Wnd, 0, 0, 0, AlphaMap.Width, AlphaMap.Height, SWP_NOACTIVATE or SWP_NOMOVE);

  with Blend do
  begin
    BlendOp := AC_SRC_OVER;
    BlendFlags := 0;
    SourceConstantAlpha := AlphaMap.Opacity;
    AlphaFormat := AC_SRC_ALPHA;
  end;

  DC := GetDC(0);
  P2 := Point(0, 0);
  S.cx := AlphaMap.Width;
  S.cy := AlphaMap.Height;

  Dynalink_UpdateLayeredWindow(Wnd, DC, @P1, @S, AlphaMap.Canvas.Handle, @P2, 0, Blend, ULW_ALPHA);

  ReleaseDC(0, DC);
end;

procedure TAdvStringGrid.HideFocusHelper;
begin
  FocusGrid := nil;
  if Assigned(FFocusWindow) and FFocusWindow.HandleAllocated then
    ShowWindow(FFocusWindow.Handle, SW_HIDE);
end;

procedure TAdvStringGrid.MoveFocusHelper;
const
  FocusHelperSize = 4;
var
  r: TRect;
  pt: TPoint;
  W,H: integer;
begin
  r := CellRect(Col,Row);
  if (Col >= LeftCol) and (Row >= TopRow) and
     (Col < LeftCol + VisibleColCount) and
     (Row < TopRow + VisibleRowCount) then
  begin
    pt := ClientToScreen(Point(0,0));
    W := r.Right - r.Left + (FocusHelperSize * 2) + 1;
    H := r.Bottom - r.Top + (FocusHelperSize * 2) + 1;
    OffsetRect(r,pt.X, pt.Y);
    MoveWindow(FFocusWindow.Handle, r.Left - FocusHelperSize, r.Top - FocusHelperSize, W, H, true);
  end
  else
  begin
    HideFocusHelper;
  end;
end;

procedure TAdvStringGrid.ShowFocusHelper(R: TRect);
const
  FocusHelperSize = 4;
  FocusHelperRounding = 5;
  FocusHelperBlur = 3;
  FocusHelperColor = $00FDD397;
  FocusHelperOpacity = 230;
var
  A,B,C: THandle;
  AlphaMask: TGridAlphaMask;
  Bitmap: TBitmap;
  MaskBitmap: TBitmap;
  W,H: integer;
  pt: TPoint;
begin
  W := r.Right - r.Left + (FocusHelperSize * 2) + 1;
  H := r.Bottom - r.Top + (FocusHelperSize * 2) + 1;

  FFocusWindow.Visible := false;
  FFocusWindow.Width := W;
  FFocusWindow.Height := H;

  AlphaMask := TGridAlphaMask.Create;
  try
    MaskBitmap := TBitmap.Create;
    MaskBitmap.PixelFormat := pf24bit;
    MaskBitmap.Width := W;
    MaskBitmap.Height := H;

    Bitmap := TBitmap.Create;
    Bitmap.PixelFormat := pf24bit;
    Bitmap.Width := W;
    Bitmap.Height := H;

    try
      MaskBitmap.Canvas.Brush.Color := clBlack;
      MaskBitmap.Canvas.Brush.Style := bsSolid;
      MaskBitmap.Canvas.Pen.Color := clBlack;
      MaskBitmap.Canvas.Pen.Style := psSolid;
      MaskBitmap.Canvas.Rectangle(0,0,W,H);

      DrawRoundRect(MaskBitmap, W, H, FocusHelperSize, FocusHelperRounding, FocusHelperBlur);

      Bitmap.Canvas.Pen.Color := FocusHelperColor;
      Bitmap.Canvas.Pen.Width := 1;
      Bitmap.Canvas.Brush.Color := FocusHelperColor;
      Bitmap.Canvas.Brush.Style := bsSolid;
      Bitmap.Canvas.Rectangle(0,0,bitmap.width,bitmap.height);

      AlphaMask.MergeMask(MaskBitmap, Bitmap, clYellow);
    finally
      Bitmap.Free;
      MaskBitmap.Free;
    end;

    AlphaMask.Opacity := FocusHelperOpacity;
    UpdateAlphaWindow(FFocusWindow.Handle, AlphaMask);
  finally
    AlphaMask.Free;
  end;

  A := CreateRectRgn(0, 0, W, H);
  B := CreateRectRgn(0, 0, R.Right - R.Left, R.Bottom - R.Top);

  OffsetRgn(B, FocusHelperSize, FocusHelperSize);
  C := CreateRectRgn(0, 0, 1, 1);
  CombineRgn(C, A, B, RGN_XOR);
  SetWindowRgn(FFocusWindow.Handle, C, False);
  DeleteObject(A);
  DeleteObject(B);

  pt := ClientToScreen(Point(0,0));
  OffsetRect(r,pt.X, pt.Y);

  MoveWindow(FFocusWindow.Handle, r.Left - FocusHelperSize, r.Top - FocusHelperSize, W, H, true);
  ShowWindow(FFocusWindow.Handle, SW_SHOWNOACTIVATE);
end;

procedure TAdvStringGrid.PaintBackground;
var
  R,CR: TRect;
  HRGN1: THandle;
  HRGN2: THandle;
  HRGN3: THandle;
  flg: boolean;
  btm: integer;
  acol,arow: integer;
begin
  // check if bottom-right cell is visible;
  acol := ColCount - 1;
  arow := RowCount - 1;

  if (arow + 1 > TopRow + VisibleRowCount) and (acol + 1 > LeftCol + VisibleColCount) then
    Exit;

  if (Background.Display in [bdGradientHorz, bdGradientVert]) and (Background.ColorTo = clNone) then
    Exit;

  CR := ClientRect;
  R := CellRect(acol, TopRow);
  InflateRect(R,GridLineWidth,GridLineWidth);

  HRGN1 := 0;
  HRGN2 := 0;
  HRGN3 := 0;

  flg := false;

  btm := ClientRect.Bottom;

  if (R.Right < ClientRect.Right) and (acol < LeftCol + VisibleColCount) then
  begin
    HRGN1 := CreateRectRgn(R.Right,0,ClientRect.Right,btm);
    HRGN3 := CreateRectRgn(R.Right,0,ClientRect.Right,btm);
    flg := true;
  end;

  R := CellRect(LeftCol, arow);
  InflateRect(R,GridLineWidth,GridLineWidth);

  if (R.Bottom < ClientRect.Bottom) and (arow < TopRow + VisibleRowCount) then
  begin
    if flg then
    begin
      HRGN2 := CreateRectRgn(0,R.Bottom,CR.Right,btm);
      CombineRgn(HRGN3,HRGN1,HRGN2, RGN_OR);
    end
    else
      HRGN3 := CreateRectRgn(0,R.Bottom,CR.Right,btm);

    flg := true;
  end;

  if FSearchFooter.Visible then
    CR.Bottom := CR.Bottom - 32;
  if FloatingFooter.Visible then
    CR.Bottom := CR.Bottom - FFooterPanel.Height;

  if flg then
  begin
    SelectClipRgn(Canvas.Handle,HRGN3);

    if not FBackground.Bitmap.Empty then
    begin
      if FBackground.Display = bdTile then
      begin
        R := CR;

        if Background.Cells = bcNormal then
        begin
          R.Top := CellRect(FixedCols,FixedRows).Top;
          R.Left := CellRect(FixedCols,FixedRows).Left;
        end;

        R.Top := R.Top + XYOffset.Y;
        R.Left := R.Left + XYOffset.X;

        if not (Background.Cells = bcFixed) then
          DrawWallPaperTile(R)
      end
      else
      begin
        DrawWallPaperFixed(CR);
      end;
    end
    else
    begin
      if (FBackground.Display in [bdGradientVert, bdGradientHorz]) then
        DrawGradient(Canvas,FBackground.Color, FBackground.ColorTo, 128, CR,FBackground.Display = bdGradientHorz);
    end;

    SelectClipRgn(Canvas.Handle,0);

    if HRGN1 <> 0 then DeleteObject(HRGN1);
    if HRGN2 <> 0 then DeleteObject(HRGN2);
    if HRGN3 <> 0 then DeleteObject(HRGN3);
  end;
end;

procedure TAdvStringGrid.HandleDesignChoice(X,Y: integer);
var
  i,j: integer;
  popmenu: THandle;
  pt: TPoint;
  flg: longint;
  f: TCustomForm;
begin

  i := MouseOverDesignChoice(X, Y);

  if i = 1 then
  begin
    if goEditing in Options then
      Options := Options - [goEditing]
    else
      Options := Options + [goEditing];
  end;

  if i = 2 then
  begin
    FShowColNrs := not FShowColNrs;
    Invalidate;
  end;

  if i = 3 then
  begin
    popmenu := CreatePopupMenu;

    //(glStandard,glSoft,glClassic,glTMS,glXP,glListView,glVista,glWin7,glOffice2007,glCustom);

    if Look = glStandard then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 1 , pchar('Standard'));

    if Look = glSoft then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 2 , pchar('Soft'));

    if Look = glClassic then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 3 , pchar('Classic'));

    if Look = glTMS then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 4 , pchar('TMS'));

    if Look = glListView then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 6 , pchar('ListView'));

    if Look = glOffice2007 then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 9 , pchar('Office 2007'));

    if Look = glXP then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 5 , pchar('Windows XP'));

    if Look = glVista then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 7 , pchar('Windows Vista'));

    if Look = glWin7 then flg := MF_CHECKED else flg := 0;

    InsertMenu(popmenu, $FFFFFFFF, MF_BYPOSITION or flg, 8 , pchar('Windows 7'));
  
    pt := ClientToScreen(Point(X,Y));
    j := integer(TrackPopupMenu(popmenu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RETURNCMD, pt.X, pt.Y, 0, Handle, nil));
    DestroyMenu(popmenu);

    if j > 0 then
      Look := TGridLook(j - 1);
  end;

  if (i = 4) then
  begin
    ShowDesignHelper := false;
  end;

  if (i in [1,2,3]) then
  begin

    //------------------------ Notifying Designer
    f := GetParentForm(Self);
    if Assigned(f) then
    begin
      //f.Designer.Modified;
      f.Width := F.Width - 1;
      f.Width := F.Width + 1;
    end;
    //------------------------

(*
    SendMessage(Handle, WM_LBUTTONUP, 0,  MakeLParam(0,0));
    SendMessage(Handle, WM_LBUTTONDOWN, 0,  MakeLParam(X,Y-30));
    SendMessage(Handle, WM_MOUSEMOVE, MK_LBUTTON, MakeLParam(X+ 8 ,Y-30));
    SendMessage(Handle, WM_LBUTTONUP, 0,  MakeLParam(X + 16,Y-30));
    SendMessage(Handle, WM_LBUTTONDOWN, 0,  MakeLParam(X,Y-30));
    SendMessage(Handle, WM_MOUSEMOVE, MK_LBUTTON, MakeLParam(X - 8 ,Y-30));
    SendMessage(Handle, WM_LBUTTONUP, 0,  MakeLParam(X + 16,Y-30));
*)
  end;
end;

procedure TAdvStringGrid.PaintDesigner;
var
  R: TRect;
  fh,i: Integer;
  P: TPoint;
  sl: string;
  bmp: TBitmap;
begin
  if not FShowDesignHelper then
    Exit;

  if (csDesigning in ComponentState) then
  begin
    r := ClientRect;

    Canvas.Font.Name := 'Tahoma';
    Canvas.Font.Size := 8;
    Canvas.Brush.Color := clInfoBk;
    Canvas.Pen.Color := clGray; //$B99D7F;

    Canvas.Font.Color := clNavy;
    Canvas.Font.Style := [fsUnderline];
    fh := Canvas.TextHeight('gh') + 2;

    r.Left := r.Right - 150;
    r.Top := r.Bottom - (4 * fh) - 10;

    Canvas.Rectangle(r);
    Canvas.TextOut(r.Left + 4, r.Top + 4, s_QuickConfig+ ' [v'+GetVersion+']');


    bmp := TBitmap.Create;
    bmp.LoadFromResourceName(hinstance,'ASGCLOSE');

    Canvas.Draw(r.Right - 16, r.Top + 2, bmp);

    bmp.Free;

    GetCursorPos(P);
    P := ScreenToClient(P);

    i := MouseOverDesignChoice(P.X, P.Y);

    DrawCheck(Rect(r.Left + 4, r.Top + 2 + fh, r.Left + 4 + 16, r.Top + 2 + fh + 16), goEditing in Options, true, false, csWinXP);

    if i = 1 then
      Canvas.Font.Style := [fsUnderline]
    else
      Canvas.Font.Style := [];

    Canvas.TextOut(r.Left + 4 + 18, r.Top + 4 + fh, s_Edit);

    DrawCheck(Rect(r.Left + 4, r.Top + 2 + 2 * fh, r.Left + 4 + 16, r.Top + 2 + 2 * fh + 16), FShowColNrs, true, false, csWinXP);

    if i = 2 then
      Canvas.Font.Style := [fsUnderline]
    else
      Canvas.Font.Style := [];

    Canvas.TextOut(r.Left + 4 + 18, r.Top + 4 + 2 * fh, s_ColNr);

    sl := s_Look +': '+ GetLookAsFriendlyString(Look);

    if i = 3 then
      Canvas.Font.Style := [fsUnderline]
    else
      Canvas.Font.Style := [];

    Canvas.TextOut(r.Left + 4, r.Top + 4 + 3 * fh, sl);
  end;
end;

procedure TAdvStringGrid.Paint;
var
  R: TRect;
begin
  Canvas.Pen.Style := psSolid;
  Canvas.Brush.Style := bsSolid;

  inherited Paint;

  if FEditing then
  begin

    if GridLineWidth > 0 then
      Canvas.Pen.Color := GridLineColor
    else
      Canvas.Pen.Color := Color;

    r := CellRect(Col,Row);
    {
    // v2.8.4.2 change for DBAdvGrid
    r.Right := r.Right - 1;

    if (goHorzLine in Options) then
    begin
      Canvas.MoveTo(r.Left,r.Bottom - 1);
      Canvas.LineTo(r.Right,r.Bottom - 1);
    end;

    if (goVertLine in Options) then
    begin
      Canvas.MoveTo(r.Right,r.Top);
      Canvas.LineTo(r.Right,r.Bottom);
    end
    else
    begin
      Canvas.Pen.Color := Color;
      Canvas.MoveTo(r.Right - 1,r.Top);
      Canvas.LineTo(r.Right - 1,r.Bottom - 1);
    end;
    }

    if not (goHorzLine in Options) and not (goVertLine in Options) then
      Canvas.Pen.Color := Color;

    Canvas.Rectangle(r.Left,r.Top,r.Right,r.Bottom);
  end;

  Canvas.Pen.Color := clBlack;

  if ((not Background.Bitmap.Empty) or (Background.ColorTo <> clNone)) then
    PaintBackground;

  PaintDesigner;

  if Assigned(OnPainted) then
    OnPainted(Self);
end;

procedure TAdvStringGrid.DrawSizingLine(X: Integer);
var
  OldPen: TPen;
  R: TRect;
begin
  OldPen := TPen.Create;
  with Canvas do
  begin
    OldPen.Assign(Pen);
    Pen.Color := clBlack;
    Pen.Style := psDot;
    Pen.Mode := pmXor;
    Pen.Width := 1;

    MoveTo(X, 0);

    R := CellRect(0,RowCount - 1);

    LineTo(X, Max(Height,R.Bottom));

    Pen := OldPen;
  end;
  OldPen.Free;
end;

procedure TAdvStringGrid.DrawSizingLineR(Y: Integer);
var
  OldPen: TPen;
  R: TRect;
begin
  OldPen := TPen.Create;
  with Canvas do
  begin
    OldPen.Assign(Pen);
    Pen.Color := clBlack;
    Pen.Style := psDot;
    Pen.Mode := pmXor;
    Pen.Width := 1;
    MoveTo(0, Y);
    R := CellRect(ColCount - 1,0);
    LineTo(Max(Width,R.Right), Y);
    Pen := OldPen;
  end;
  OldPen.Free;
end;



procedure TAdvStringGrid.RTFPaint(ACol,ARow: Integer;Canvas:TCanvas;ARect:TRect);
type
  rFormatRange = record
    hdcSrc: HDC;
    hdcTarget: HDC;
    rc: TRect;
    rcPage: TRect;
    chrg: TCharRange;
  end;

var
  fr:rFORMATRANGE;
  nLogPixelsX,nLogPixelsY: Integer;
  mm: Integer;
  pt: TPoint;
  FocusCell: Boolean;
  RtfOffsetX,RtfOffsetY,RRow: Integer;


begin
  if (csDesigning in ComponentState) then
    Exit;
    
  CellToRich(ACol, ARow, RichEdit);

  if FMouseActions.RowSelectPersistent then
    RRow := RemapRowInv(ARow)
  else
    RRow := ARow;

  RichEdit.Brush.Style := bsClear;

  FocusCell := (ARow = Row) and (ACol = Col) and
               (GetFocus = Handle) and not (goDrawFocusSelected in Options);

  if (((ACol >= Selection.Left) and (ACol <= Selection.Right) and
     (ARow >= Selection.Top) and (ARow <= Selection.Bottom)) and not FocusCell
      and not MouseActions.DisjunctRowSelect ) or
     (MouseActions.DisjunctRowSelect and RowSelect[RRow]) or
     (MouseActions.DisjunctColSelect and ColSelect[ACol]) then
  begin
    if (not FSelectionRTFKeep) and (GetMapMode(Canvas.Handle) = MM_TEXT) then
    begin
      RichEdit.SelStart := 0;
      RichEdit.SelLength := $FFFF;
      if FSelectionTextColor <> clNone then
        RichEdit.SelAttributes.Color := FSelectionTextColor;
    end;
  end;

  FillChar(fr, SizeOf(TFormatRange), 0);

  lptodp(Canvas.Handle,ARect.Topleft,1);
  lptodp(Canvas.Handle,ARect.Bottomright,1);

  nLogPixelsX := GetDeviceCaps(Canvas.Handle,LOGPIXELSX);
  nLogPixelsY := GetDeviceCaps(Canvas.Handle,LOGPIXELSY);

  if nLogPixelsX = 0 then
    nLogPixelsX := 96;

  if nLogPixelsY = 0 then
    nLogPixelsY := 96;

  pt.x := XYOffset.X;
  pt.y := XYOffset.Y;

  dptolp(Canvas.Handle,pt,1);

  RtfOffsetX := ((pt.x * nLogPixelsX) div 96);
  RtfOffsetY := ((pt.x * nLogPixelsX) div 96);

  fr.hdcSrc := Canvas.Handle;
  fr.hdcTarget := Canvas.Handle;
  {convert to twips}
  fr.rcPage.Left := Round(((ARect.Left + RtfOffsetX)/nLogPixelsX) * RTF_TWIPS);
  fr.rcPage.Top := Round(((ARect.Top + RtfOffsetY)/nLogPixelsY) * RTF_TWIPS);
  fr.rcPage.Right := fr.rcPage.Left + Round(((ARect.Right - ARect.Left - 2*RtfOffsetX)/nLogPixelsX) * RTF_TWIPS);
  fr.rcPage.Bottom := (fr.rcPage.Top + Round(((ARect.Bottom - ARect.Top - 2*RtfOffsetY)/nLogPixelsY) * RTF_TWIPS));
  fr.rc.Left := fr.rcPage.Left;  { 1440 TWIPS = 1 inch. }
  fr.rc.Top := fr.rcPage.Top;
  fr.rc.Right := fr.rcPage.Right;
  fr.rc.Bottom := fr.rcPage.Bottom;
  fr.chrg.cpMin := 0;
  fr.chrg.cpMax := -1;


  mm := GetMapMode(Canvas.Handle);
  SetMapMode(Canvas.Handle,mm_text);

  SendMessage(RichEdit.Handle,EM_FORMATRANGE,1,LParam(@fr));

  {clear the richtext cache}
  SendMessage(RichEdit.Handle,EM_FORMATRANGE,0,0);

  SetMapMode(Canvas.Handle,mm);
end;

function TAdvStringGrid.ExportCell(ACol, ARow: Integer): string;
begin
  Result := Cells[ACol,ARow];
end;

procedure TAdvStringGrid.ExportNotification(AState: TGridExportState; ARow: Integer);
begin
end;

procedure TAdvStringGrid.ImportNotification(AState: TGridImportState; ARow: Integer);
begin
end;

procedure TAdvStringGrid.SelectionChanged(ALeft, ATop, ARight, ABottom: integer);
var
  r: TRect;
begin
  if (Look in [glVista, glOffice2007, glWin7]) {and not (goHorzLine in Options)} then
  begin
    r.Left := Selection.Left;
    r.Top := Selection.Top;
    r.Right := Selection.Right;
    r.Bottom := Selection.Bottom;
    RepaintRect(r);
  end;

  FSelChange := true;

  FDisSelection := Selection;

  if Assigned(FSelectionChanged) then
    FSelectionChanged(Self, ALeft, ATop, ARight, ABottom);
end;

procedure TAdvStringGrid.EditProgress(Value: string; pt: TPoint; SelPos: Integer);
begin

end;

procedure TAdvStringGrid.DoInsertRow(ARow: Integer);
var
  DRow: integer;
begin
  if (FNumNodes = 0) then
    InsertRows(ARow,1)
  else
  begin
    DRow := DisplRowIndex(ARow);
    if GetParentRow(DRow) = -1 then
    begin
      InsertNormalRow(ARow)
    end
    else
    begin
      InsertChildRow(ARow,0);
    end;
  end;

//  if Assigned(FOnAutoInsertRow) then
//    FOnAutoInsertRow(self,ARow);
end;

procedure TAdvStringGrid.DoIntelliZoom;
begin
  if Assigned(OnIntelliZoom) then
    OnIntelliZoom(Self);
end;

procedure TAdvStringGrid.DoFilterClose(ACol: integer);
begin
  if Assigned(OnFilterClose) then
    OnFilterClose(Self,ACol);
end;

procedure TAdvStringGrid.DoFilterDone;
begin
  if Assigned(OnFilterDone) then
    OnFilterDone(Self);
end;

procedure TAdvStringGrid.DoFilterShow(ACol: integer; var Allow: boolean);
begin
  if Assigned(OnFilterShow) then
    OnFilterShow(Self,ACol,Allow);
end;

procedure TAdvStringGrid.DoFilterEditDone(ACol: Integer; ft: TFilterType);
var
  fd: TFilterData;
  fdata: string;
begin
  FilterActive := false;

  if integer(ft) = 8 then
  begin
    Cells[ACol, FFilterEdit.Row] := '';
    ft := ftContains;
  end;

  if not Filter.HasFilter(ACol) then
  begin
    fd := Filter.Add;
    fd.FilterType := ftContains;
  end
  else
    fd := Filter.ColumnFilter[ACol];

  fd.CaseSensitive := FilterEdit.CaseSensitive;
  fd.Column := ACol;
  if ft <> ftNone then
    fd.FilterType := ft;

  fdata := Cells[ACol, FFilterEdit.Row];

  fd.BuildCondition(fdata);
  fd.Enabled := fdata <> '';

  FilterEditUpdate(ACol, Cells[ACol,FFilterEdit.Row], fd.FilterType);

  FilterActive := true;
  RepaintRow(0);

  DoFilterDone;
end;

procedure TAdvStringGrid.DoFilterType(Sender: TObject);
begin
  DoFilterEditDone(FFltrPopup.Tag,TFilterType((Sender as TMenuItem).Tag));
end;

procedure TAdvStringGrid.DoFixedCellEdit(ACol, ARow: integer;
  AEditor: TGridFixedCellEditor; Values: TStrings);
begin
  if Assigned(FOnFixedEdit) then
    FOnFixedEdit(Self,ACol,ARow,AEditor,Values);
end;

procedure TAdvStringGrid.DoDeleteRow(ARow: Integer);
begin
  if FNumNodes = 0 then
  begin
    if (RowCount - FixedRows - FixedFooters = 1) and not FixedRowAlways then
      ClearRows(ARow,1)
    else
      RemoveRowsInternal(ARow,1);
  end
  else
  begin
    if GetParentRow(ARow) = -1 then
      RemoveNormalRow(ARow)
    else
      RemoveChildRow(ARow);
  end;

  if Assigned(FOnAutoDeleteRow) then
    FOnAutoDeleteRow(self,ARow);
end;


function TAdvStringGrid.CalcCell(ACol,ARow: Integer): string;
begin
  Result := Cells[ACol,ARow];
end;

procedure TAdvStringGrid.LoadCell(ACol,ARow: Integer; Value: string);
begin
  if Assigned(FOnLoadCell) then
    FOnLoadCell(Self,Acol,ARow,Value);

  GridCells[ACol,ARow] := Value;
end;

function TAdvStringGrid.SaveCell(ACol,ARow: Integer): string;
var
  State: Boolean;
  rr: integer;
  cbState: TCheckBoxState;
begin
  if FSaveVirtCells then
    Result := DisplCells[ACol,ARow]
  else
    Result := GridCells[ACol,ARow];

  if not FSaveMergedCells then
  begin
    if not IsBaseCell(ACol,ARow) then
      Result := '';
  end;

  if (Result = '') then
  begin
    rr := ARow;
    if (CellTypes[ACol,ARow] in [ctCheckBox, ctTriStateCheckBox]) then
      rr := RealRowIndex(ARow);

    if (CellTypes[ACol,ARow] = ctCheckBox) then
    begin
      GetCheckBoxState(ACol,rr,State);
      if State then
        Result := GetCheckTrue(ACol,ARow)
      else
       Result := GetCheckFalse(ACol,ARow);
    end
    else 
    if( CellTypes[ ACol, ARow ] = ctTriStateCheckBox) then
    begin
      GetCheckBoxState( ACol, rr, cbState);
      if (cbState = cbChecked) then
        Result := GetCheckTrue(ACol,ARow)
      else
        Result := GetCheckFalse(ACol,ARow);
    end;
  end;

  case TextType(Result,true) of
  ttHTML: if not FSaveWithHTML then
            Result := HTMLStrip(Result);
  ttRTF:
    if not FSaveWithRTF then
    begin
      CellToRich(ACol, ARow, RichEdit);
      Result := RichEdit.Text;
    end
    else
    begin
      // avoids linefeeds in RTF
      Result := StringReplace(Result,#13,'',[rfReplaceAll]);
      Result := StringReplace(Result,#10,'',[rfReplaceAll]);
    end;
  end;

  if Assigned(FOnSaveCell) then
    FOnSaveCell(Self,Acol,ARow,Result);
end;


procedure TAdvStringGrid.DrawSortIndicator(Canvas:TCanvas;Col,x,y: Integer);
var
  left,vpos,idx: Integer;
begin

  if UseRightToLeftAlignment then
  begin
    ChangeGridOrientation(False);
    left := ClientWidth - x - 4;

    if FSortSettings.IndexShow then
    begin
      if (FSortSettings.IndexUpGlyph.Empty) or (FSortSettings.IndexDownGlyph.Empty) then
      begin
        left := left - 7;
      end
      else
        left := left - 7 - FSortSettings.IndexUpGlyph.Width;
    end
    else
    begin
      if (FSortSettings.UpGlyph.Empty) or (FSortSettings.DownGlyph.Empty) then
      begin
        left := left - 7;
      end
      else
        left := left - 7 - FSortSettings.UpGlyph.Width;
    end;

    vpos := y;
  end
  else
  begin
    left := x;
    vpos := y;
  end;


  if FSortSettings.IndexShow then
  begin
    idx := SortIndexes.FindIndex(Col);
    if idx = -1 then
      Exit;

    Canvas.Brush.Color := FSortSettings.IndexColor;
    SetBKMode(Canvas.Handle,Transparent);
    Canvas.Font.Color := clBlack;
    Canvas.Font.Size := 6;

    if (SortIndexes.Items[idx] and $80000000 = $80000000) then
    begin
      if (FSortSettings.IndexUpGlyph.Empty) or (FSortSettings.IndexDownGlyph.Empty) then
        Canvas.Polygon([Point(Left-7,vpos-5), Point(Left+7,vpos-5), Point(Left, vpos+8)])
      else
      begin
        FSortSettings.IndexUpGlyph.Transparent := True;
        FSortSettings.IndexUpGlyph.TransparentMode := tmAuto;
        Canvas.Draw(Left - 7,vpos - 7,FSortSettings.IndexUpGlyph);
      end;
      Canvas.Textout(Left - 2,vpos - 4,inttostr(idx+1));
    end
    else
    begin
      if (FSortSettings.IndexUpGlyph.Empty) or (FSortSettings.IndexDownGlyph.Empty) then
        Canvas.Polygon([Point(left-6,vpos+8), Point(left+6,vpos+8), Point(left, vpos-4)])
      else
      begin
        FSortSettings.IndexDownGlyph.Transparent := True;
        FSortSettings.IndexDownGlyph.TransparentMode := tmAuto;
        Canvas.Draw(Left - 7,vpos - 7,FSortSettings.IndexDownGlyph);
      end;
      Canvas.Textout(Left - 2,vpos - 2,inttostr(idx+1));
    end;

    if UseRightToLeftAlignment then
    begin
      ChangeGridOrientation(True);
    end;

    Exit;
  end;

  if FSortSettings.Direction = sdDescending then
  begin
    {draw a full Colored triangle}
    if (FSortSettings.UpGlyph.Empty) or (FSortSettings.DownGlyph.Empty) then
    begin
      Canvas.Pen.Color := clWhite;
      Canvas.Pen.Width := 1;
      Canvas.MoveTo(left+4,vpos-4);
      Canvas.LineTo(left,vpos+4);
      Canvas.pen.Color := clGray;
      Canvas.LineTo(left-4,vpos-4);
      Canvas.LineTo(left+4,vpos-4);
      Canvas.pen.Color := clBlack;
    end
    else
    begin
      FSortSettings.DownGlyph.Transparent := True;
      FSortSettings.DownGlyph.TransparentMode := tmAuto;
      Canvas.Draw(left - 4,vpos - 4,FSortSettings.DownGlyph);
      {reset bk Color since this is a Delphi 3 bug}
      SetBKColor(Canvas.Handle,ColorToRGB(FixedColor));
    end;
  end
  else
  begin
    if (FSortSettings.UpGlyph.Empty) or (FSortSettings.DownGlyph.Empty) then
    begin
      Canvas.Pen.Color := clWhite;
      Canvas.Pen.Width := 1;
      Canvas.MoveTo(left - 4,vpos + 4);
      Canvas.LineTo(left + 4,vpos + 4);
      Canvas.LineTo(left,vpos - 4);
      Canvas.Pen.Color := clGray;
      Canvas.LineTo(left - 4,vpos + 4);
      Canvas.Pen.Color := clBlack;
    end
    else
    begin
      FSortSettings.UpGlyph.Transparent := True;
      FSortSettings.UpGlyph.TransparentMode := tmAuto;
      Canvas.Draw(Left - 4,vpos - 4,FSortSettings.UpGlyph);
      {reset bk Color since this is a Delphi 3 bug}
      SetBKColor(Canvas.Handle,ColorToRGB(FixedColor));
    end;
  end;

  if UseRightToLeftAlignment then
  begin
    ChangeGridOrientation(True);
  end;
end;


procedure TAdvStringGrid.DrawCell(ACol, ARow : longint; ARect : TRect;
  AState : TGridDrawState);
begin
  inherited DrawCell(ACol,ARow,ARect,AState);
end;

procedure TAdvStringGrid.GetFontProperties(ACol,RCol,ARow: Integer; var AState: TGridDrawState; AFont: TFont; ABrush: TBrush; Remap: boolean);
var
  cp: TCellProperties;
  FixedCell: Boolean;
begin
  FixedCell := IsFixed(ACol,ARow) or (ACol < FixedCols) or  (ARow < FixedRows);

  if FixedCell then
    AFont.Assign(FFixedFont)
  else
    AFont.Assign(Font);

  if HasCellProperties(RCol,ARow) then
  begin
    cp := CellProperties[RCol,ARow];

    if cp.FontColor <> clNone then
      AFont.Color := cp.FontColor;

    if cp.FontStyle <> [] then
      AFont.Style := cp.FontStyle;

    if cp.FontSize <> 0 then
      AFont.Size := cp.FontSize;

    if cp.FontName <> '' then
      AFont.Name := cp.FontName;
  end;

  GetCellColor(RCol,ARow,AState,ABrush,AFont);
end;

function BlendColor(Col1,Col2:TColor; BlendFactor:Integer): TColor;
var
  r1,g1,b1: Integer;
  r2,g2,b2: Integer;

begin
  if BlendFactor >= 100 then
  begin
    Result := Col1;
    Exit;
  end;
  if BlendFactor <= 0 then
  begin
    Result := Col2;
    Exit;
  end;
  if Col1 = clNone then
  begin
    Result := Col2;
    Exit;
  end;

  if Col2 = clNone then
  begin
    Result := Col1;
    Exit;
  end;

  Col1 := Longint(ColorToRGB(Col1));
  r1 := GetRValue(Col1);
  g1 := GetGValue(Col1);
  b1 := GetBValue(Col1);

  Col2 := Longint(ColorToRGB(Col2));
  r2 := GetRValue(Col2);
  g2 := GetGValue(Col2);
  b2 := GetBValue(Col2);

  r1 := Round( BlendFactor/100 * r1 + (1 - BlendFactor/100) * r2);
  g1 := Round( BlendFactor/100 * g1 + (1 - BlendFactor/100) * g2);
  b1 := Round( BlendFactor/100 * b1 + (1 - BlendFactor/100) * b2);

  // in case someone screws up the rounding mode!
  if (r1 > 255) then r1 := 255;
  if (g1 > 255) then g1 := 255;
  if (b1 > 255) then b1 := 255;

  Result := RGB(r1,g1,b1);
end;

function ColorMixer(Color1,Color2: TColor; UseMixer: boolean; Factor: integer): TColor;
begin
   if not UseMixer then
   begin
     Result := Color1;
     Exit;
   end;

   Result := BlendColor(Color1,Color2,Factor);
end;

procedure TAdvStringGrid.GetVisualProperties(ACol,ARow: Integer; var AState: TGridDrawState; Print, Select, Remap: Boolean;
  ABrush: TBrush; var AColorTo,AMirrorColor,AMirrorColorTo: TColor; AFont: TFont; var HA: TAlignment; var VA: TVAlignment;
  var WW: Boolean; var GD: TCellGradientDirection);
var
  CA: TCellAlignment;
  FixedCell: Boolean;
  RCol, RRow: Integer;
  cp: TCellProperties;
  isCtrl: boolean;
  ct: TCellType;
  hasBrush: boolean;
  hascp: boolean;
  at:AdvUtil.TAutoType;
  dbl: double;
  normalcolor,normaltextcolor,bkclr: TColor;

begin
  if (ACol < FixedCols) or (ARow < FixedRows) then
  begin
    if Print and not PrintSettings.UseDisplayFont then
      AFont.Assign(PrintSettings.FixedFont)
    else
      AFont.Assign(FFixedFont);
  end
  else
  begin
    if Print and not PrintSettings.UseDisplayFont then
      AFont.Assign(PrintSettings.Font)
    else
    begin
      AFont.Assign(Font);
    end;
  end;

  if Remap then
    RCol := RemapCol(ACol)
  else
    RCol := ACol;

  if (MouseActions.DisjunctRowSelect and MouseActions.RowSelectPersistent) or FUseEnabledRows then
    RRow := RemapRowInv(ARow)
  else
    RRow := ARow;

  ABrush.Color := clNone;
  AColorTo := clNone;
  AMirrorColor := clNone;
  AMirrorColorTo := clNone;
  isCtrl := false;
  hasBrush := false;
  hascp := false;

  if HasCellProperties(RCol,ARow) {and PrintSettings.UseDisplayFont} then
  begin
    cp := CellProperties[RCol,ARow];
    ct := CellTypes[ACol,ARow];

    if (ct in [ctEmpty,ctNone,ctRotated]) then
    begin
      if cp.BrushColor <> clNone then
      begin
        hascp := true;
        ABrush.Color := cp.BrushColor;
      end;
    end
    else
    begin
      isCtrl := ct in [ctCheckBox, ctRadio, ctDataCheckBox, ctButton, ctRadioButton];
      ABrush.Color := cp.BrushColor;
      hasBrush := isCtrl and (ABrush.Color <> clNone);
    end;

    if cp.FontColor <> clNone then
      AFont.Color := cp.FontColor;

    if cp.FontStyle <> [] then
      AFont.Style := cp.FontStyle;

    if PrintSettings.UseDisplayFont then
    begin
      if cp.FontSize <> 0 then
        AFont.Size := cp.FontSize;

      if cp.FontName <> '' then
        AFont.Name := cp.FontName;
    end;

    ww := cp.WordWrap;

    AColorTo := cp.BrushColorTo;

    GD := cp.GradientDirection;
  end;

  if (gdSelected in AState) then
    GD := GradientVertical;

  if ((ABrush.Color = clNone) or isCtrl) and not hasBrush then
  begin
     if ABrush.Color = clNone then
      ABrush.Color := self.Color;

    if FBands.Active and ((FBands.Print = Print) or not Print) and
       (ACol >= FixedCols) and (ACol < ColCount - FixedRightCols + FNumHidden)
       and (ARow >= FixedRows) and (ARow < RowCount - FixedFooters) then
    begin
      if FBands.TotalLength > 0 then
      begin
        if (((ARow - FixedRows) mod FBands.TotalLength) < FBands.PrimaryLength) then
          ABrush.Color := FBands.PrimaryColor
        else
          ABrush.Color := FBands.SecondaryColor;
      end
      else
      begin
        if ABrush.Color = clNone then
          ABrush.Color := self.Color;
      end;
    end;

    if (ACol < FixedCols) or (ARow < FixedRows) or
       (DisplColIndex(ACol) >= ColCount - FixedRightCols) or (ARow >= RowCount - FixedFooters) then
      ABrush.Color := FixedColor;
  end;

  FixedCell := IsFixed(ACol,ARow) or (ACol < FixedCols) or  (ARow < FixedRows);

  if FixedCell and not Print and not hascp then
  begin
    ABrush.Color := FixedColor;
    AFont.Assign(FFixedFont);
    AState := AState + [gdFixed];
  end;

  if FixedCell and not hascp and not (Look in [glStandard,glSoft,glClassic,glListView]) then
  begin
    ABrush.Color := FTMSGradFrom;
    AColorTo := FTMSGradTo;
    AMirrorColor := FTMSGradMirrorFrom;
    AMirrorColorTo := FTMSGradMirrorTo;
  end;

  if (ARow = FFilterEdit.Row) and HasFilterEdit(RCol, ARow) then
  begin
    ABrush.Color := FFilterEdit.Color;
    AColorTo := ABrush.Color;
    AMirrorColor := ABrush.Color;
    AMirrorColorTo := ABrush.Color;
  end;

  if AutoColor.ColorsDefined then
  begin
    at := IsType(Cells[RCol,ARow]);
    if (at in [AdvUtil.atNumeric, AdvUtil.atFloat]) then
    begin

      dbl := Floats[RCol,ARow];

      if (dbl < 0) and (AutoColor.NegativeNumber.TextColor <> clNone) then
        AFont.Color := AutoColor.NegativeNumber.TextColor;

      if (dbl < 0) and (AutoColor.NegativeNumber.BkgColor <> clNone) then
        ABrush.Color := AutoColor.NegativeNumber.BkgColor;

      if (dbl >= 0) and (AutoColor.PositiveNumber.TextColor <> clNone) then
        AFont.Color := AutoColor.PositiveNumber.TextColor;

      if (dbl >= 0) and (AutoColor.PositiveNumber.BkgColor <> clNone) then
        ABrush.Color := AutoColor.PositiveNumber.BkgColor;
    end;
  end;

  if Print then
    GetCellPrintColor(RCol,ARow,AState,ABrush,AFont)
  else
    GetCellColor(RCol,ARow,AState,ABrush,AFont);

  if Assigned(OnGetCellGradient) then
  begin
    bkclr := ABrush.Color;
    OnGetCellGradient(Self, ARow, RCol, bkclr, AColorTo, AMirrorColor, AMirrorColorTo, GD);
    ABrush.Color := bkclr;
  end;

  normalcolor := ABrush.Color;
  normaltextcolor := AFont.Color;

  if (ACol >= FixedCols) and (ARow >= FixedRows) and MouseActions.DisjunctRowSelect
    and not Print and Select and CanShowSelection and not FixedCell then
  begin
    if (not (FMouseDown and (ARow = Row)) and RowSelect[RRow]) or
       (FMouseDown and not RowSelect[RRow] and (gdSelected in AState)) then
    begin
      AState := [gdSelected];

      if ABrush.Color <> Color then
        ABrush.Color := ColorMixer(FSelectionColor, ABrush.Color, FSelectionColorMixer, FSelectionColorMixerFactor)
      else
        ABrush.Color := FSelectionColor;

      AColorTo := FSelectionColorTo;
      AMirrorColor := FSelectionMirrorColor;
      AMirrorColorTo := FSelectionMirrorColorTo;

      if FSelectionTextColor <> clNone then
        AFont.Color := FSelectionTextColor;
    end
    else
      AState := AState - [gdSelected];
  end;

  if (ARow >= FixedRows) and (ACol >= FixedCols) and MouseActions.DisjunctColSelect
    and not Print and Select and CanShowSelection and not FixedCell then
  begin
    if (not (FMouseDown and (ACol = Col)) and ColSelect[ACol]) or
       (FMouseDown and not ColSelect[ACol] and (gdSelected in AState)) then
    begin
      AState := [gdSelected];
      ABrush.Color := FSelectionColor;
      AColorTo := FSelectionColorTo;
      AMirrorColor := FSelectionMirrorColor;
      AMirrorColorTo := FSelectionMirrorColorTo;

      if FSelectionTextColor <> clNone then
        AFont.Color := FSelectionTextColor;
    end;
  end;

  if not Print and Select and CanShowSelection and not FixedCell and
    (IsSelected(ACol,ARow) and not (MouseActions.DisjunctRowSelect or MouseActions.DisjunctColSelect))
    or ((gdSelected in AState) and FMouseDown and CanShowSelection) then
  begin
    if ABrush.Color <> Color then
      ABrush.Color := ColorMixer(FSelectionColor, ABrush.Color, FSelectionColorMixer, FSelectionColorMixerFactor)
    else
      ABrush.Color := FSelectionColor;

    AColorTo := FSelectionColorTo;
    AMirrorColor := FSelectionMirrorColor;
    AMirrorColorTo := FSelectionMirrorColorTo;

    if (FSelectionTextColor <> clNone) then
      AFont.Color := FSelectionTextColor;

    AState := AState + [gdSelected];
  end;

  if MouseActions.DisjunctCellSelect and CanShowSelection then
    if FSelectedCells.IndexOf(Pointer(MakeLong(ACol,ARow))) <> -1 then
    begin
      ABrush.Color := FSelectionColor;
      AColorTo := FSelectionColorTo;
      AMirrorColor := FSelectionMirrorColor;
      AMirrorColorTo := FSelectionMirrorColorTo;

      if FSelectionTextColor <> clNone then
        AFont.Color := FSelectionTextColor;
      AState := AState + [gdSelected];
    end
    else
    begin
      if (ACol = Col) and (ARow = Row) then
      begin
        AState := AState - [gdSelected];
        ABrush.Color := normalcolor;
        AFont.Color := normaltextcolor;
      end;
    end;

  {$IFDEF FREEWARE}
  if (ARow = RowCount - 1) then
    AFont.Color := clSilver;
  {$ENDIF}

  if FUseDisabledFont then
  begin
    if FUseEnabledRows then
    begin
      if not RowEnabled[RRow] then
        AFont.Color := FDisabledFontColor;
    end;

    if not Enabled then
      AFont.Color := FDisabledFontColor;
  end;

  if (IsSelected(ACol,ARow)) and CanShowSelection and not Print and (Arow <> Row) and (MouseActions.DisjunctRowSelect) and (FSelectionColorTo = clNone) then
    ABrush.Color := ChangeColorPerc(ABrush.Color,-10);

  GetCellWordWrap(RCol, ARow, WW);
  CA := GetCellAlignment(RCol, ARow);
  HA := CA.Alignment;
  VA := CA.VAlignment;
end;


function TAdvStringGrid.GetGraphicDetails(ACol,ARow: Integer; var W,H: Integer; var DisplText: Boolean;
  var HA: TCellHAlign;var VA: TCellVAlign): TCellGraphic;
var
  cg: TCellGraphic;
  pt: TPoint;
  icg: ICellGraphic;
  io: TInterfacedPersistent;
  FImages:TCustomImageList;

begin
  cg := CellGraphics[ACol,ARow];
  Result := cg;
  W := 0;
  H := 0;
  DisplText := True;
  HA := haLeft;
  VA := vaTop;

  if Assigned(cg) then
  begin
    case cg.CellType of
    ctShape:
    begin
      w := RowHeights[ARow] - XYOffset.Y * 2;
      h := w;
    end;
    ctBitmap:
    begin
      W := cg.CellBitmap.Width;
      H := cg.CellBitmap.Height;
    end;
    ctRating:
    begin
      W := 18 * cg.CellAngle;
      H := 16;
      DisplText := false;
    end;
    ctInterface:
    begin
      io := TInterfacedPersistent(cg.CellBitmap);
      if io.GetInterface(ICellGraphic, icg) then
      begin
        W := icg.CellWidth;
        H := icg.CellHeight;
      end;
    end;
    ctButton,ctBitButton:
    begin
      W := cg.CellIndex and $FFFF;
      H := (cg.CellIndex and $FFFF0000) shr 16;
    end;
    ctFilePicture, ctPicture:
    begin
      pt := CellSize(DisplColIndex(ACol),ARow);
      pt := cg.GetPictureSize(pt.X,pt.Y,False);
      W := pt.X;
      H := pt.Y;
    end;
    ctRadioButton:
    begin
      W := FControlLook.RadioSize + 4;
      H := FControlLook.RadioSize + 4;
    end;
    ctCheckBox, ctTriStateCheckBox:
    begin
      W := FControlLook.CheckSize;
      H := FControlLook.CheckSize;
    end;
    ctProgressPie:
    begin
      W := 20;
      H := 20;
    end;
    ctProgress,ctRangeIndicator,ctXPProgress:
    begin
      DisplText := False;
    end;
    ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox:
    begin
      W := FControlLook.CheckSize;
      H := FControlLook.CheckSize;
      DisplText := False;
    end;
    ctIcon:
    begin
      W := cg.CellIcon.Width;
      H := cg.CellIcon.Height;
    end;
    ctImageList,ctDataImage:
    begin
      FImages := GetCellImageList(ACol,ARow);

      if Assigned(FImages) then
      begin
        W := FImages.Width;
        H := FImages.Height;
        if cg.CellType = ctDataImage then
          DisplText := False;
      end;
    end;
    ctImages:
    begin
      FImages := GetCellImageList(ACol,ARow);
      if Assigned(FImages) then
      begin
        if cg.CellBoolean then
        begin
          W := FImages.Width * CellImages[ACol,ARow].Count;
          H := FImages.Height;
        end
        else
        begin
          H := FImages.Height * CellImages[ACol,ARow].Count;
          W := FImages.Width;
        end;
      end;
    end;
    ctRotated:
    begin
      DisplText := False;
    end;
    ctRadio:
    begin
      DisplText := False;
    end;
    end;
    HA := cg.CellHAlign;
    VA := cg.CellVAlign;
  end;
end;

procedure TAdvStringGrid.SetColorTones(ATones: TColorTones);
begin
  FTones := ATones;
  Look := glClassic;
  Flat := true;
  ScrollType := ssMetro;
  FixedColor := ATones.Foreground.BrushColor;
  FixedFont.Color := ATones.Foreground.TextColor;
  FixedFont.Name := GetMetroFont;
  Color := ATones.Background.BrushColor;
  Font.Name := GetMetroFont;
  Font.Color := ATones.Background.TextColor;
  SelectionColor := ATones.Selected.BrushColor;
  SelectionTextColor := ATones.Selected.TextColor;
  SelectionColorTo := clNone;
  GridLineColor := RGB(230,230,230);
  GridFixedLineColor := ChangeColorPerc(ATones.Foreground.BrushColor,-20);

  BorderStyle := bsNone;

  ControlLook.ControlStyle := csGlyph;
  ControlLook.CheckedGlyph.LoadFromResourceName(Hinstance,'metrocheckon');
  ControlLook.UnCheckedGlyph.LoadFromResourceName(Hinstance,'metrocheckoff');

  ControlLook.RadioOffGlyph.LoadFromResourceName(Hinstance,'metroradiooff');
  ControlLook.RadioOnGlyph.LoadFromResourceName(Hinstance,'metroradioon');

  if not (csDesigning in ComponentState) then
  begin
    BtnEdit.Button.ButtonColor := ATones.Background.BrushColor;
    BtnEdit.Button.ButtonColorHot := ATones.Hover.BrushColor;
    BtnEdit.Button.ButtonColorDown := ATones.Selected.BrushColor;
    BtnEdit.Button.ButtonBorderColor := ATones.Background.BorderColor;

    Combobox.BorderColor := Color;
    Combobox.ButtonColor := ATones.Background.BrushColor;
    Combobox.ButtonColorHot := ATones.Hover.BrushColor;
    Combobox.ButtonColorDown := ATones.Selected.BrushColor;
    Combobox.ButtonBorderColor := ATones.Background.BorderColor;
    Combobox.Flat := true;
    SpinEdit.Button.ButtonColor := ATones.Background.BrushColor;
    SpinEdit.Button.ButtonColorHot := ATones.Hover.BrushColor;
    SpinEdit.Button.ButtonColorDown := ATones.Selected.BrushColor;
    SpinEdit.Button.ButtonBorderColor := ATones.Background.BorderColor;

    DateTimePicker.ButtonColor := ATones.Background.BrushColor;
    DateTimePicker.ButtonColorHot := ATones.Hover.BrushColor;
    DateTimePicker.ButtonColorDown := ATones.Selected.BrushColor;
    DateTimePicker.ButtonBorderColor := ATones.Background.BorderColor;
    DateTimePicker.BorderColor := ATones.Background.BrushColor;
    DateTimePicker.MetroStyle := true;
  end;

  if Assigned(FEditMemo) then
    FEditMemo.SetColorTones(FTones);
  if Assigned(FEditTrackBar) then
    FEditTrackBar.SetColorTones(FTones);
  if Assigned(FEditTimePicker) then
    FEditTimePicker.SetColorTones(FTones);
  if Assigned(FEditCalculator) then
    FEditCalculator.SetColorTones(FTones);
  if Assigned(FEditAdvGridPicker) then
    FEditAdvGridPicker.SetColorTones(FTones);
  if Assigned(FEditDetailPicker) then
    FEditDetailPicker.SetColorTones(FTones);
  if Assigned(FEditGridPicker) then
    FEditGridPicker.SetColorTones(FTones);
  if Assigned(FEditColorPicker) then
    FEditColorPicker.SetColorTones(FTones);
  if Assigned(FEditImagePicker) then
    FEditImagePicker.SetColorTones(FTones);
  ControlLook.FlatButton := true;

  FloatingFooter.Color := ATones.Foreground.BrushColor;
  SearchFooter.Color := ATones.Foreground.BrushColor;
  SearchFooter.ColorTo := ATones.Foreground.BrushColor;
  CellNode.NodeType := cnFlat;
end;

procedure TAdvStringGrid.SetComponentStyleAndAppColor(AStyle: TTMSStyle; AppColor: TColor);
begin
  FStyle := AStyle;
  SetStyleAndAppColor(TAdvGridStyle(AStyle), AppColor);
  if not (csDesigning in ComponentState) then
    SetEditorsStyle(AStyle);
  if (AStyle <> tsCustom) and (ScrollType = ssMetro) then
    ScrollType := ssNormal;
end;

procedure TAdvStringGrid.SetComponentStyle(AStyle: TTMSStyle);
begin
  SetComponentStyleAndAppColor(AStyle, clNone);
end;

procedure TAdvStringGrid.SetEditorsStyle(AStyle: TTMSStyle);
begin
  if Assigned(FEditColorPicker) then
    FEditColorPicker.SetComponentStyle(AStyle);

  if Assigned(FEditImagePicker) then
    FEditImagePicker.SetComponentStyle(AStyle);

  if Assigned(FEditGridPicker) then
    FEditGridPicker.SetComponentStyle(AStyle);

  if Assigned(FEditDetailPicker) then
    FEditDetailPicker.SetComponentStyle(AStyle);

  if Assigned(FEditTimePicker) then
    FEditTimePicker.SetComponentStyle(AStyle);

  if Assigned(FEditCalculator) then
    FEditCalculator.SetComponentStyle(AStyle);

  if Assigned(FEditMemo) then
    FEditMemo.SetComponentStyle(AStyle);
end;

procedure TAdvStringGrid.SetStyle(AStyle: TAdvGridStyle);
begin
  SetStyleAndAppColor(AStyle, clNone);
end;

procedure TAdvStringGrid.SetStyleAndAppColor(AStyle: TAdvGridStyle; AppColor: TColor);
begin
  SelectionColor := clHighLight;
  SelectionColorTo := clNone;
  SelectionMirrorColor := clNone;
  SelectionMirrorColorTo := clNone;

  SelectionTextColor := clHighlightText;
  SelectionStyle := ssDefault;
  SortSettings.FHeaderColor := clNone;
  SortSettings.FHeaderColorTo := clNone;
  SortSettings.FHeaderMirrorColor := clNone;
  SortSettings.FHeaderMirrorColorTo := clNone;
  FActiveCellFont.Color := clWindowText;
  FixedFont.Color := clBlack;

  ControlLook.Init;

  case AStyle of
    gsOffice2003Blue:
      begin
      Look := glXP;
      FTMSGradFrom := $FCE1CB;
      FTMSGradTo := $E0A57D;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $FCE1CB;
      FSearchFooter.ColorTo := $E0A57D;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      FSelectionColor := $0094E6FB;
      FSelectionColorTo := $001595EE;
      FSelectionTextColor := clBlack;
      end;
    gsOffice2003Silver:
      begin
      Look := glXP;
      FTMSGradFrom := $ECE2E1;
      FTMSGradTo := $B39698;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $ECE2E1;
      FSearchFooter.ColorTo := $B39698;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      FSelectionColor := $0094E6FB;
      FSelectionColorTo := $001595EE;
      FSelectionTextColor := clBlack;
      end;
    gsOffice2003Olive:
      begin
      Look := glXP;
      FTMSGradFrom := $CFF0EA;
      FTMSGradTo := $8CC0B1;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $CFF0EA;
      FSearchFooter.ColorTo := $8CC0B1;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      FSelectionColor := $0094E6FB;
      FSelectionColorTo := $001595EE;
      FSelectionTextColor := clBlack;
      end;
    gsOffice2003Classic:
      begin
      Look := glXP;
      FActiveCellColor := $d8d5d4;
      FActiveCellColorTo := $d8d5d4;
      FTMSGradFrom := clWhite;
      FTMSGradTo := $ccd4d8;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      FSearchFooter.Color := clWhite;
      FSearchFooter.ColorTo := $d8d5d4;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      end;
    gsOffice2007Luna:
      begin
      Look := glOffice2007;
      FActiveCellColor := $9DD8F9;
      FActiveCellColorTo := $5EC1F1;
      FTMSGradFrom := $FBF9F6;
      FTMSGradTo := $E8DBD2;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $FFEFE3;
      FSearchFooter.ColorTo := $FFD2AF;
      GridLineColor := $F1EDEB; //$E5D7D0;
      GridFixedLineColor := $D1BBA4;
      SelectionColor := $5EC1F1;
      SelectionTextColor := clBlack;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $E4E2DF;
      FControlLook.FixedGradientHoverTo := $DBD3CD;
      FControlLook.FixedGradientHoverMirrorFrom := $DBD3CD;
      FControlLook.FixedGradientHoverMirrorTo := $D2C5BC;
      FControlLook.FixedGradientHoverBorder := $B79F87;

      FControlLook.FixedGradientDownFrom := $E4C19D;
      FControlLook.FixedGradientDownTo := $E4C19D;
      FControlLook.FixedGradientDownMirrorFrom := $E4C19D;
      FControlLook.FixedGradientDownMirrorTo := $E4C19D;
      FControlLook.FixedGradientDownBorder := $E4C19D;;

      if Look = glOffice2007 then
        SelectionStyle := ssOffice2007;
      end;
    gsOffice2007Obsidian:
      begin
      Look := glOffice2007;
      FActiveCellColor := $9DD8F9;
      FActiveCellColorTo := $5EC1F1;
      FTMSGradFrom := $F7F7F7;
      FTMSGradTo := $DEDEDE;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $F2F1F0;
      FSearchFooter.ColorTo := $C9C2BD;

      GridLineColor := $E5D7D0;
      GridFixedLineColor := clGray;
      SelectionColor := $5EC1F1;
      SelectionTextColor := clBlack;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      end;
    gsOffice2007Silver:
      begin
      Look := glOffice2007;
      FActiveCellColor := $99CCFF;
      FActiveCellColorTo := $699CFF;
      FTMSGradFrom := $F3F3F1;
      FTMSGradTo := $CAC9C8;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $EEEEEE;
      FSearchFooter.ColorTo := $C1C1C1;
      GridLineColor := $E5D7D0;
      GridFixedLineColor := clGray;
      SelectionColor := $95C7F5;
      SelectionTextColor := clBlack;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      
      end;
    gsWindowsXP:
      begin
      Look := glXP;
      FActiveCellColor := clBtnFace;
      FActiveCellColorTo := clBtnFace;
      FTMSGradFrom := clBtnFace;
      FTMSGradTo := clBtnFace;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      FSearchFooter.Color := clBtnFace;
      FSearchFooter.ColorTo := clBtnFace;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      Look := glXP;
      end;
    gsWindowsVista:
      begin
      Look := glVista;
      FTMSGradFrom := $FFFFFF;
      FTMSGradTo := $FFFFFF;
      FTMSGradMirrorFrom := $FAF8F7;
      FTMSGradMirrorTo := $F4F2F1;

      FTMSGradHoverFrom := $FFF7E3;
      FTMSGradHoverTo := $FFF7E3;
      FTMSGradHoverMirrorFrom := $FFEDBD;
      FTMSGradHoverMirrorTo := $FBE7B7;
      FTMSGradHoverBorder := $E3C993;
      //FTMSGradHoverBorder := $F9D996;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;
      FControlLook.FixedGradientHoverFrom := FTMSGradHoverFrom;
      FControlLook.FixedGradientHoverTo := FTMSGradHoverTo;
      FControlLook.FixedGradientHoverMirrorFrom := FTMSGradHoverMirrorFrom;
      FControlLook.FixedGradientHoverMirrorTo := FTMSGradHoverMirrorTo;
//9DC1E4
      FControlLook.FixedGradientDownFrom := $F9E4BC;
      FControlLook.FixedGradientDownTo := $F9E4BC;
      FControlLook.FixedGradientDownMirrorFrom := $F7D68D;
      FControlLook.FixedGradientDownMirrorTo := $F5D18A;
      FControlLook.FixedGradientDownBorder := $AE904F;

      SortSettings.HeaderColor := $FCF9F2;
      SortSettings.HeaderColorTo := $FCF9F2;
      SortSettings.HeaderMirrorColor := $F9F1E1;
      SortSettings.HeaderMirrorColorTo := $F6ECD8;

      FActiveCellColor := $FDF8F1;
      FActiveCellColorTo := $FCEFD5;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $00EACAB6;
      SelectionTextColor := clBlack;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssVista;
      //GridLineColor := clSilver;
      GridLineColor := $ECECF0;
      GridFixedLineColor := $D4D2D1;
      end;

    gsWindows7:
      begin
      Look := glWin7;
      FTMSGradFrom := $FDFCFA;
      FTMSGradTo := $FAF0E6;
      FTMSGradMirrorFrom := $F4E6DC;
      FTMSGradMirrorTo := $F7E9DD;

      FTMSGradHoverFrom := $FDF8F3;
      FTMSGradHoverTo := $F9F3EF;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := $EEE8E3;
      //FTMSGradHoverBorder := $F9D996;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $FEFBF8;
      FControlLook.FixedGradientHoverTo := $FAF2ED;
      FControlLook.FixedGradientHoverMirrorFrom := $F4E4D7;
      FControlLook.FixedGradientHoverMirrorTo := $E8D2C1;

      FControlLook.FixedGradientDownFrom := $F1E8DD;
      FControlLook.FixedGradientDownTo := $F1E4D8;
      FControlLook.FixedGradientDownMirrorFrom := $ECDBCF;
      FControlLook.FixedGradientDownMirrorTo := $EDDCCF;
      FControlLook.FixedGradientDownBorder := $D5BCAA;

      SortSettings.HeaderColor := $FCF9F2;
      SortSettings.HeaderColorTo := $FCF9F2;
      SortSettings.HeaderMirrorColor := $F9F1E1;
      SortSettings.HeaderMirrorColorTo := $F6ECD8;

      FActiveCellColor := $FCEBDC;
      FActiveCellColorTo := $FCDBC1;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $00EACAB6;
      SelectionTextColor := clBlack;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssWin7;
      //GridLineColor := clSilver;
      GridLineColor := $ECECF0;
      GridFixedLineColor := $D4D2D1;
      end;

    gsWhidbey:
      begin
//      FActiveCellColor := clWhite;
//      FActiveCellColorTo := $00FFD9B3;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FTMSGradFrom := clWhite;
      FTMSGradTo := clBtnFace;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      FSearchFooter.Color := $00EBEEEF;
      FSearchFooter.ColorTo := $007E9898; ///$00FFD9B3;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;
      end;
    gsOffice2010Blue:
      begin
      Look := glOffice2007;
      FTMSGradFrom := $F5E7DA;
      FTMSGradTo := $F5E7DA;
      FTMSGradMirrorFrom := $F5E7DA;
      FTMSGradMirrorTo := $F5E7DA;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $6BDFFF;
      FControlLook.FixedGradientHoverTo := $AFEFFF;
      FControlLook.FixedGradientHoverMirrorFrom := $AFEFFF;
      FControlLook.FixedGradientHoverMirrorTo := $E6FCFF;
      FControlLook.FixedGradientHoverBorder := $3ABFE8;

      FControlLook.FixedGradientDownFrom := $5BD5FF;
      FControlLook.FixedGradientDownTo := $64E0FF;
      FControlLook.FixedGradientDownMirrorFrom := $64E0FF;
      FControlLook.FixedGradientDownMirrorTo := $71EFFF;
      FControlLook.FixedGradientDownBorder := $308AC2;

      SortSettings.HeaderColor := $D6CEC7;
      SortSettings.HeaderColorTo := $D6CEC7;
      SortSettings.HeaderMirrorColor := $D6CEC7;
      SortSettings.HeaderMirrorColorTo := $D6CEC7;

      FActiveCellColor := $5BD5FF;
      FActiveCellColorTo := $71EFFF;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $FFDBB7;
      SelectionTextColor := clBlack;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $C0C0C0;
      GridFixedLineColor := $C7B0A0;
      end;

    gsOffice2010Silver:
      begin
      Look := glOffice2007;
      FTMSGradFrom := $E8E3DF;
      FTMSGradTo := $E8E3DF;
      FTMSGradMirrorFrom := $E8E3DF;
      FTMSGradMirrorTo := $E8E3DF;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $6BDFFF;
      FControlLook.FixedGradientHoverTo := $AFEFFF;
      FControlLook.FixedGradientHoverMirrorFrom := $AFEFFF;
      FControlLook.FixedGradientHoverMirrorTo := $E6FCFF;
      FControlLook.FixedGradientHoverBorder := $3ABFE8;

      FControlLook.FixedGradientDownFrom := $5BD5FF;
      FControlLook.FixedGradientDownTo := $64E0FF;
      FControlLook.FixedGradientDownMirrorFrom := $64E0FF;
      FControlLook.FixedGradientDownMirrorTo := $71EFFF;
      FControlLook.FixedGradientDownBorder := $308AC2;

      SortSettings.HeaderColor := $AAAAAA;
      SortSettings.HeaderColorTo := $AAAAAA;
      SortSettings.HeaderMirrorColor := $AAAAAA;
      SortSettings.HeaderMirrorColorTo := $AAAAAA;

      FActiveCellColor := $5BD5FF;
      FActiveCellColorTo := $71EFFF;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $FFDBB7;
      SelectionTextColor := clBlack;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $C0C0C0;
      GridFixedLineColor := $BAB5B1;
      end;

      gsOffice2010Black:
      begin
      Look := glOffice2007;
      FTMSGradFrom := $6A6A6A;
      FTMSGradTo := $6A6A6A;
      FTMSGradMirrorFrom := $6A6A6A;
      FTMSGradMirrorTo := $6A6A6A;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $6BDFFF;
      FControlLook.FixedGradientHoverTo := $AFEFFF;
      FControlLook.FixedGradientHoverMirrorFrom := $AFEFFF;
      FControlLook.FixedGradientHoverMirrorTo := $E6FCFF;
      FControlLook.FixedGradientHoverBorder := $3ABFE8;

      FControlLook.FixedGradientDownFrom := $5BD5FF;
      FControlLook.FixedGradientDownTo := $64E0FF;
      FControlLook.FixedGradientDownMirrorFrom := $64E0FF;
      FControlLook.FixedGradientDownMirrorTo := $71EFFF;
      FControlLook.FixedGradientDownBorder := $308AC2;

      SortSettings.HeaderColor := $BABABA;
      SortSettings.HeaderColorTo := $BABABA;
      SortSettings.HeaderMirrorColor := $BABABA;
      SortSettings.HeaderMirrorColorTo := $BABABA;

      FActiveCellColor := $5BD5FF;
      FActiveCellColorTo := $71EFFF;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $FFDBB7;
      SelectionTextColor := clBlack;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $C0C0C0;
      GridFixedLineColor := $444444;
      end;

    gsWindows8, gsWindows10:
      begin
      Look := glOffice2007;

      Bordercolor:= $E4E3E2;

      FTMSGradFrom := $F7F6F5;
      FTMSGradTo := $F7F6F5;
      FTMSGradMirrorFrom := $F7F6F5;
      FTMSGradMirrorTo := $F7F6F5;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $F7EFE8;
      FControlLook.FixedGradientHoverTo := $F7EFE8;
      FControlLook.FixedGradientHoverMirrorFrom := $F7EFE8;
      FControlLook.FixedGradientHoverMirrorTo := $F7EFE8;
      FControlLook.FixedGradientHoverBorder := $F9CEA4;

      FControlLook.FixedGradientDownFrom := $F7E0C9;
      FControlLook.FixedGradientDownTo := $F7E0C9;
      FControlLook.FixedGradientDownMirrorFrom := $F7E0C9;
      FControlLook.FixedGradientDownMirrorTo := $F7E0C9;
      FControlLook.FixedGradientDownBorder := $E4A262;

      SortSettings.HeaderColor := $F7F6F5;
      SortSettings.HeaderColorTo := $F7F6F5;
      SortSettings.HeaderMirrorColor := $F7F6F5;
      SortSettings.HeaderMirrorColorTo := $F7F6F5;

      FActiveCellColor := $F7F6F5;
      FActiveCellColorTo := $F7F6F5;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $DAA026;
      SelectionTextColor := clWhite;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $DCDBDA;
      GridFixedLineColor := $DCDBDA;
      end;

    gsOffice2013White:
      begin
      Look := glOffice2007;

      Bordercolor:= $D4D4D4;

      FTMSGradFrom := $EEEEEE;
      FTMSGradTo := $EEEEEE;
      FTMSGradMirrorFrom := $EEEEEE;
      FTMSGradMirrorTo := $EEEEEE;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $FCF0E4;
      FControlLook.FixedGradientHoverTo := $FCF0E4;
      FControlLook.FixedGradientHoverMirrorFrom := $FCF0E4;
      FControlLook.FixedGradientHoverMirrorTo := $FCF0E4;
      FControlLook.FixedGradientHoverBorder := $EAB47E;

      FControlLook.FixedGradientDownFrom := $FCE2C8;
      FControlLook.FixedGradientDownTo := $FCE2C8;
      FControlLook.FixedGradientDownMirrorFrom := $FCE2C8;
      FControlLook.FixedGradientDownMirrorTo := $FCE2C8;
      FControlLook.FixedGradientDownBorder := $E59D56;

      SortSettings.HeaderColor := $EEEEEE;
      SortSettings.HeaderColorTo := $EEEEEE;
      SortSettings.HeaderMirrorColor := $EEEEEE;
      SortSettings.HeaderMirrorColorTo := $EEEEEE;

      FActiveCellColor := $EEEEEE;
      FActiveCellColorTo := $EEEEEE;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $DAA026;
      SelectionTextColor := clWhite;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $D4D4D4;
      GridFixedLineColor := $D4D4D4;
      end;

    gsOffice2013LightGray:
      begin
      Look := glOffice2007;

      Bordercolor:= $C6C6C6;

      FTMSGradFrom := $FAFAFA;
      FTMSGradTo := $FAFAFA;
      FTMSGradMirrorFrom := $FAFAFA;
      FTMSGradMirrorTo := $FAFAFA;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $FCF0E4;
      FControlLook.FixedGradientHoverTo := $FCF0E4;
      FControlLook.FixedGradientHoverMirrorFrom := $FCF0E4;
      FControlLook.FixedGradientHoverMirrorTo := $FCF0E4;
      FControlLook.FixedGradientHoverBorder := $EAB47E;

      FControlLook.FixedGradientDownFrom := $FCE2C8;
      FControlLook.FixedGradientDownTo := $FCE2C8;
      FControlLook.FixedGradientDownMirrorFrom := $FCE2C8;
      FControlLook.FixedGradientDownMirrorTo := $FCE2C8;
      FControlLook.FixedGradientDownBorder := $E59D56;

      SortSettings.HeaderColor := $FAFAFA;
      SortSettings.HeaderColorTo := $FAFAFA;
      SortSettings.HeaderMirrorColor := $FAFAFA;
      SortSettings.HeaderMirrorColorTo := $FAFAFA;

      FActiveCellColor := $FAFAFA;
      FActiveCellColorTo := $FAFAFA;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $DAA026;
      SelectionTextColor := clWhite;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $C6C6C6;
      GridFixedLineColor := $C6C6C6;
      end;

    gsOffice2013Gray:
      begin
      Look := glOffice2007;

      Bordercolor:= $ABABAB;

      FTMSGradFrom := $F3F3F3;
      FTMSGradTo := $F3F3F3;
      FTMSGradMirrorFrom := $F3F3F3;
      FTMSGradMirrorTo := $F3F3F3;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := $FCF0E4;
      FControlLook.FixedGradientHoverTo := $FCF0E4;
      FControlLook.FixedGradientHoverMirrorFrom := $FCF0E4;
      FControlLook.FixedGradientHoverMirrorTo := $FCF0E4;
      FControlLook.FixedGradientHoverBorder := $EAB47E;

      FControlLook.FixedGradientDownFrom := $FCE2C8;
      FControlLook.FixedGradientDownTo := $FCE2C8;
      FControlLook.FixedGradientDownMirrorFrom := $FCE2C8;
      FControlLook.FixedGradientDownMirrorTo := $FCE2C8;
      FControlLook.FixedGradientDownBorder := $E59D56;

      SortSettings.HeaderColor := $F3F3F3;
      SortSettings.HeaderColorTo := $F3F3F3;
      SortSettings.HeaderMirrorColor := $F3F3F3;
      SortSettings.HeaderMirrorColorTo := $F3F3F3;

      FActiveCellColor := $F3F3F3;
      FActiveCellColorTo := $F3F3F3;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $DAA026;
      SelectionTextColor := clWhite;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $ABABAB;
      GridFixedLineColor := $ABABAB;
      end;
    gsOffice2016White:
      begin
      Look := glOffice2007;

      Bordercolor:= $ABABAB;

      FTMSGradFrom := $FFFFFF;
      FTMSGradTo := $FFFFFF;
      FTMSGradMirrorFrom := $FFFFFF;
      FTMSGradMirrorTo := $FFFFFF;

      FTMSGradHoverFrom := clNone;
      FTMSGradHoverTo := clNone;
      FTMSGradHoverMirrorFrom := clNone;
      FTMSGradHoverMirrorTo := clNone;
      FTMSGradHoverBorder := clNone;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
      FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

      FControlLook.FixedGradientHoverFrom := ChangeColor(AppColor, -60);
      FControlLook.FixedGradientHoverTo := ChangeColor(AppColor, -60);
      FControlLook.FixedGradientHoverMirrorFrom := ChangeColor(AppColor, -60);
      FControlLook.FixedGradientHoverMirrorTo := ChangeColor(AppColor, -60);
      FControlLook.FixedGradientHoverBorder := $B1B1B1;

      FControlLook.FixedGradientDownFrom := ChangeColor(AppColor, -20);
      FControlLook.FixedGradientDownTo := ChangeColor(AppColor, -20);
      FControlLook.FixedGradientDownMirrorFrom := ChangeColor(AppColor, -20);
      FControlLook.FixedGradientDownMirrorTo := ChangeColor(AppColor, -20);
      FControlLook.FixedGradientDownBorder := $ABABAB;


      SortSettings.HeaderColor := $FFFFFF;
      SortSettings.HeaderColorTo := $FFFFFF;
      SortSettings.HeaderMirrorColor := $FFFFFF;
      SortSettings.HeaderMirrorColorTo := $FFFFFF;

      FActiveCellColor := $E1E1E1;
      FActiveCellColorTo := $E1E1E1;
      FActiveCellFont.Color := Appcolor;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      SelectionColor := $C6C6C6;
      SelectionTextColor := clBlack;

      FSearchFooter.Color := FTMSGradFrom;
      FSearchFooter.ColorTo := FTMSGradMirrorTo;

      SelectionStyle := ssdefault;
      GridLineColor := $D4D4D4;
      GridFixedLineColor := $D5D5D5;
      end;

    gsOffice2016Gray:
      begin
        Look := glOffice2007;

        Bordercolor:= $999999;

        FTMSGradFrom := $6A6A6A;
        FTMSGradTo := $6A6A6A;
        FTMSGradMirrorFrom := $6A6A6A;
        FTMSGradMirrorTo := $6A6A6A;


        FTMSGradHoverFrom := clNone;
        FTMSGradHoverTo := clNone;
        FTMSGradHoverMirrorFrom := clNone;
        FTMSGradHoverMirrorTo := clNone;
        FTMSGradHoverBorder := clNone;

        FControlLook.FixedGradientFrom := FTMSGradFrom;
        FControlLook.FixedGradientTo := FTMSGradTo;
        FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
        FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

        FControlLook.FixedGradientHoverFrom := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverTo := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverMirrorFrom := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverMirrorTo := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverBorder := $B1B1B1;

        FControlLook.FixedGradientDownFrom := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownTo := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownMirrorFrom := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownMirrorTo := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownBorder := $ABABAB;


        SortSettings.HeaderColor := $6A6A6A;
        SortSettings.HeaderColorTo := $6A6A6A;
        SortSettings.HeaderMirrorColor := $6A6A6A;
        SortSettings.HeaderMirrorColorTo := $6A6A6A;

        FActiveCellColor := $262626;
        FActiveCellColorTo := $262626;

        FControlLook.FixedGradientFrom := clNone;
        FControlLook.FixedGradientTo := clNone;
        SelectionColor := $C6C6C6;
        SelectionTextColor := clBlack;

        FSearchFooter.Color := FTMSGradFrom;
        FSearchFooter.ColorTo := FTMSGradMirrorTo;

        SelectionStyle := ssdefault;
        GridLineColor := $D4D4D4;
        GridFixedLineColor := $D3D3D3;
        FixedFont.Color := clWhite;
        FActiveCellFont.Color := clWhite;
      end;

    gsOffice2016Black:
      begin
        Look := glOffice2007;

        Bordercolor:= $999999;

        FTMSGradFrom := $252525;
        FTMSGradTo := $252525;
        FTMSGradMirrorFrom := $252525;
        FTMSGradMirrorTo := $252525;

        FTMSGradHoverFrom := clNone;
        FTMSGradHoverTo := clNone;
        FTMSGradHoverMirrorFrom := clNone;
        FTMSGradHoverMirrorTo := clNone;
        FTMSGradHoverBorder := clNone;

        FControlLook.FixedGradientFrom := FTMSGradFrom;
        FControlLook.FixedGradientTo := FTMSGradTo;
        FControlLook.FixedGradientMirrorFrom := FTMSGradMirrorFrom;
        FControlLook.FixedGradientMirrorTo := FTMSGradMirrorTo;

        FControlLook.FixedGradientHoverFrom := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverTo := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverMirrorFrom := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverMirrorTo := ChangeColor(AppColor, -60);
        FControlLook.FixedGradientHoverBorder := $B1B1B1;

        FControlLook.FixedGradientDownFrom := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownTo := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownMirrorFrom := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownMirrorTo := ChangeColor(AppColor, -20);
        FControlLook.FixedGradientDownBorder := $ABABAB;


        SortSettings.HeaderColor := $252525;
        SortSettings.HeaderColorTo := $252525;
        SortSettings.HeaderMirrorColor := $252525;
        SortSettings.HeaderMirrorColorTo := $252525;

        FActiveCellColor := $646464;
        FActiveCellColorTo := $646464;

        FControlLook.FixedGradientFrom := clNone;
        FControlLook.FixedGradientTo := clNone;
        SelectionColor := $C6C6C6;
        SelectionTextColor := clBlack;

        FSearchFooter.Color := FTMSGradFrom;
        FSearchFooter.ColorTo := FTMSGradMirrorTo;

        SelectionStyle := ssdefault;
        GridLineColor := $D4D4D4;
        GridFixedLineColor := $B0B0B0;
        FixedFont.Color := clWhite;
        FActiveCellFont.Color := clWhite;
      end;

   gsTerminal:
     begin
       Look := glStandard;
     end;
  end;
  Invalidate;
end;

procedure TAdvStringGrid.SetSyncGrid(const Value: TSyncGrid);
begin
  FSyncGrid.Assign(Value);
end;

procedure TAdvStringGrid.SetTheme(Scheme: TXPColorScheme);
begin
  case Scheme of
  xpBlue:
    begin
      FTMSGradFrom := $FCE1CB;
      FTMSGradTo := $E0A57D;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $FCE1CB;
      FSearchFooter.ColorTo := $E0A57D;
    end;
  xpGreen:
    begin
      FTMSGradFrom := $CFF0EA;
      FTMSGradTo := $8CC0B1;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $CFF0EA;
      FSearchFooter.ColorTo := $8CC0B1;
    end;
  xpGray:
    begin
      FTMSGradFrom := $ECE2E1;
      FTMSGradTo := $B39698;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;
      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;
      FSearchFooter.Color := $ECE2E1;
      FSearchFooter.ColorTo := $B39698;
    end;
  vistaAero:
    begin
      // blueish selection color
      //FTMSGradFrom := $FDFBF6;
      //FTMSGradTo := $FCEFD5;

      FTMSGradFrom := $FFFFFF;
      FTMSGradTo := $FFFFFF;
      FTMSGradMirrorFrom := $FAF8F7;
      FTMSGradMirrorTo := $F4F2F1;

      FActiveCellColor := $94E6FB;
      FActiveCellColorTo := $1595EE;

      FControlLook.FixedGradientFrom := FTMSGradFrom;
      FControlLook.FixedGradientTo := FTMSGradTo;

      FSearchFooter.Color := $ECE2E1;
      FSearchFooter.ColorTo := $B39698;
    end
  else
    begin
      FActiveCellColor := clWhite;
      FActiveCellColorTo := $00FFD9B3;
      FTMSGradFrom := clWhite;
      FTMSGradTo := clBtnFace;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      FSearchFooter.Color := clWhite;
      FSearchFooter.ColorTo := $00FFD9B3;
    end;
  end;
end;

procedure TAdvStringGrid.ThemeAdapt;
var
  ot: TOfficeTheme;
begin
  if (csDesigning in ComponentState) then
    Exit;

  ot := GetOfficeTheme;

  if (ot = FOldOfficeTheme) then
    Exit;

  case ot of
  ot2003Classic: SetComponentStyle(tsOffice2003Classic);
  ot2003Blue: SetComponentStyle(tsOffice2003Blue);
  ot2003Olive: SetComponentStyle(tsOffice2003Olive);
  ot2003Silver: SetComponentStyle(tsOffice2003Silver);
  ot2007Blue: SetComponentStyle(tsOffice2007Luna);
  ot2007Silver: SetComponentStyle(tsOffice2007Silver);
  ot2007Black: SetComponentStyle(tsOffice2007Obsidian);
  ot2010Blue: SetComponentStyle(tsOffice2010Blue);
  ot2010Silver: SetComponentStyle(tsOffice2010Silver);
  ot2010Black: SetComponentStyle(tsOffice2010Black);
  ot2013White: SetComponentStyle(tsOffice2013White);
  ot2013Silver: SetComponentStyle(tsOffice2013LightGray);
  ot2013Gray: SetComponentStyle(tsOffice2013Gray);
  ot2016White: SetComponentStyle(tsOffice2016White);
  ot2016Gray: SetComponentStyle(tsOffice2016Gray);
  ot2016Black: SetComponentStyle(tsOffice2016Black);
  end;

  FOldOfficeTheme := ot;
end;


function TAdvStringGrid.GetFormattedCell(ACol,ARow: Integer): string;
var
  IsFloat: Boolean;
  Fmt: string;
  f: extended;
  d: integer;
begin
  Result := ExportCell(ACol,ARow);

  if Assigned(OnGetFloatFormat) then
  begin
    IsFloat := IsType(Result) in [AdvUtil.atNumeric,AdvUtil.atFloat,AdvUtil.atScientific];
    if IsFloat then
    begin
      Fmt := FloatFormat;
      OnGetFloatFormat(Self,ACol,ARow,IsFloat,Fmt);

      if IsFloat and (fmt <> '') then
      begin
        case FormatType of
          ftVCL:
            begin
              try
                if (pos('d',fmt) > 0) or (pos('x',fmt) > 0)  then
                begin
                  d := Ints[ACol,ARow];
                  Result := Format(fmt,[d]);
                end
                else
                begin
                  f := Floats[ACol,ARow];
                  Result := Format(fmt,[f]);
                end;
              except
              end;

            end;
          ftExcel:
            begin
              try
                {$IFDEF DELPHIXE_LVL}
                f := Floats[ACol,ARow];
                Result := XlsFormat(f, fmt);
                {$ENDIF}
              except
              end;
            end;
        end;
      end;
    end;
  end;
end;

procedure TAdvStringGrid.DrawWallPaperFixed(crect: TRect);
var
  SrcRect,DstRect,Irect: TRect;
  x,y,ox,oy: Integer;
  dst: TPoint;

begin
  dst.x := FBackground.Left;
  dst.y := FBackground.Top;
  x := FBackground.Bitmap.Width;
  y := FBackground.Bitmap.Height;

  DstRect.Top := dst.y;
  DstRect.Left := dst.x;
  DstRect.Right := DstRect.Left + x;
  DstRect.Bottom := DstRect.Top + y;

  if not IntersectRect(irect,crect,dstRect) then
    Exit;

  SetBkMode(Canvas.Handle,TRANSPARENT);

  ox := crect.Left - dst.x;
  oy := crect.Top - dst.y;

  SrcRect.Left := ox;
  SrcRect.Top := oy;
  SrcRect.Right := ox + crect.Right - crect.Left;
  SrcRect.Bottom := oy + crect.Bottom - crect.Top;

  DstRect := crect;

  if ox <= 0 then
  begin
    DsTRect.Left := dst.x;
    SrcRect.Left := 0;
    SrcRect.Right := DstRect.Right - DstRect.Left;
  end;

  if oy <= 0 then
  begin
    DstRect.Top := dst.y;
    SrcRect.Top := 0;
    SrcRect.Bottom := DstRect.Bottom - DstRect.Top;
  end;

  if (SrcRect.Left + (DstRect.Right - DstRect.Left) > x) then
  begin
    DstRect.Right := DstRect.Left + x - SrcRect.Left;
    SrcRect.Right := x;
  end;

  if (SrcRect.Top + DsTRect.Bottom - DsTRect.Top > y) then
  begin
    DsTRect.Bottom := DsTRect.Top + y - SrcRect.Top;
    SrcRect.Bottom := y;
  end;
  Canvas.CopyRect(DstRect,FBackground.Bitmap.Canvas,SrcRect);
end;


procedure TAdvStringGrid.DrawWallPaperTile(crect:TRect);
var
  SrcRect,DsTRect:TRect;
  x,y,xo,yo,ox,oy: Integer;
begin
  x := FBackground.Bitmap.Width;
  y := FBackground.Bitmap.Height;
  SetBkMode(Canvas.Handle,TRANSPARENT);

  ox := 0;
  oy := 0;
  ox := ox mod x;
  oy := oy mod y;

  SrcRect.Left := ox;
  SrcRect.Top := oy;
  SrcRect.Right := x;
  SrcRect.Bottom := y;

  yo := cRect.Top - 1;

  while yo < cRect.Bottom do
  begin
    xo := cRect.Left -1;
    SrcRect.Left := ox;
    SrcRect.Right := x;
    while xo < cRect.Right do
    begin
      DstRect := Rect(xo,yo,xo + SrcRect.Right - SrcRect.Left,yo + SrcRect.Bottom - SrcRect.Top);

      if DstRect.Right > crect.Right then
      begin
        DstRect.Right := crect.Right;
        SrcRect.Right := SrcRect.Left + (dstRect.Right - dstRect.Left);
      end;
      if DstRect.Bottom > crect.Bottom then
      begin
        DstRect.Bottom := crect.Bottom;
        SrcRect.Bottom := SrcRect.Top + (dstRect.Bottom - dstRect.Top);
      end;

      Canvas.CopyRect(DstRect,FBackground.Bitmap.Canvas,SrcRect);
      xo := xo + SrcRect.Right - SrcRect.Left;
      SrcRect.Left := 0;
      SrcRect.Right := x;
    end;
    yo := yo + SrcRect.Bottom - SrcRect.Top;
    SrcRect.Top := 0;
    SrcRect.Bottom := y;
  end;
end;

function TAdvStringGrid.IsDSEdit: boolean;
begin
  Result := false;
end;

procedure TAdvStringGrid.DrawRadio(Canvas: TCanvas;R:TRect;Num,Idx: Integer;dir,dis: Boolean;sl: TStrings; Selected:boolean; ACol,ARow: integer; Style: TControlStyle; ResFactor: real; Print: boolean = false);
var
  DrawState: Integer;
  DrawRect: TRect;
  DrawNum: Integer;
  DrawOfs,Th, DirFactor: Integer;
  s: string;
  Bmp: TBitmap;
  RadioOn: Boolean;
  HTheme: THandle;
  OldColor: TColor;
  cstyle: TControlStyle;

begin
  if ControlLook.NoDisabledCheckRadioLook or ControlLook.RadioAlwaysActive then
    dis := false;

  DrawOfs := 0;
  DirFactor := 1;
  if Print then
    DirFactor := -1;

  SetBkMode(Canvas.Handle,TRANSPARENT);

  for DrawNum := 1 to Num do
  begin
    RadioOn := False;
    s := '';

    if Assigned(sl) then
    begin
      if Selected and CanShowSelection then
        Canvas.Font.Color := SelectionTextColor;

      if DrawNum <= sl.Count then
      begin
        s := sl.Strings[DrawNum - 1];
        if (idx = -1) and (s = Cells[ACol,ARow]) then
          RadioOn := True;
      end;
    end;

    if (DrawNum - 1 = Idx) then
     RadioOn := True;

    cstyle := Style; //ControlLook.ControlStyle;

    if (cstyle = csTheme) and not FIsWinXP then
      cstyle := csClassic;

    case cstyle of
    csClassic,csFlat:
      begin
        DrawState := DFCS_BUTTONRADIO;

        if ControlLook.ControlStyle = csFlat then
          DrawState := DrawState or DFCS_FLAT;

        if Dis then
          DrawState := DrawState or DFCS_INACTIVE;

        if RadioOn then
          DrawState := DrawState or DFCS_CHECKED;

        if dir then
        begin
          DrawRect.Left := DrawOfs + R.Left + 2 + (DrawNum - 1) * ControlLook.RadioSize;
          DrawRect.Top := R.Top + (R.Bottom - R.Top - ControlLook.RadioSize) div 2;

          if s <> '' then
          begin
            Canvas.TextOut(DrawRect.Left + Round(ControlLook.RadioSize * ResFactor),DrawRect.Top - 2,s);
            DrawOfs := DrawOfs + Canvas.TextWidth(s);
          end;
        end
        else
        begin
          th := Canvas.TextHeight('gh');

          if s <> '' then
          begin
            DrawRect.Left := R.Left + 2;
            DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
            Canvas.TextOut(DrawRect.Left + Round((ControlLook.RadioSize + 4) * ResFactor),DrawRect.Top - 2,s);
          end
          else
          begin
            DrawRect.Left := R.Left + (R.Right - R.Left - Round((ControlLook.RadioSize * ResFactor))) div 2;
            DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
          end;
        end;

        if ControlLook.ControlStyle = csFlat then
        begin
          DrawRect.Right := DrawRect.Left + Round((ControlLook.RadioSize + 2) * ResFactor);
          DrawRect.Bottom := DrawRect.Top + Round((ControlLook.RadioSize + 2) * ResFactor);
        end
        else
        begin
          DrawRect.Right := DrawRect.Left + Round(ControlLook.RadioSize * ResFactor);
          DrawRect.Bottom := DrawRect.Top + Round(ControlLook.RadioSize * ResFactor);
        end;

        DrawFrameControl(Canvas.Handle,DrawRect,DFC_BUTTON,DrawState);
      end;
    csTMS, csWinXP, csGlyph:
      begin
        bmp := TBitmap.Create;

        if dir then
        begin
          DrawRect.Left := DrawOfs + R.Left + 2 + (DrawNum - 1) * 16;
          DrawRect.Top := R.Top + (R.Bottom - R.Top - 16) div 2;

          if s <> '' then
          begin
            Canvas.Textout(DrawRect.Left + 16,DrawRect.Top + 1,s);
            DrawOfs := DrawOfs + Canvas.TextWidth(s);
          end
        end
        else
        begin
          th := Max(16,Canvas.TextHeight('gh'));
          if s <> '' then
          begin
            DrawRect.Left := R.Left + 2;
            DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
            Canvas.Textout(DrawRect.Left + 16,Drawrect.Top + 1,s);
          end
          else
          begin
            DrawRect.Left := R.Left + (R.Right - R.Left - 16) div 2;
            DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
          end;
        end;

        if RadioOn then
        begin
          case ControlLook.ControlStyle of
          csTMS:
            begin
              if not dis then
                Bmp.LoadFromResourceName(hinstance,'ASGRAD01')
              else
                Bmp.LoadFromResourceName(hinstance,'ASGRAD03');
            end;
          csWinXP:
            begin
              if not dis then
                Bmp.LoadFromResourceName(hinstance,'ASGRAD05')
              else
                Bmp.LoadFromResourceName(hinstance,'ASGRAD07');
            end;
          csGlyph:
            Bmp.Assign(ControlLook.RadioOnGlyph);
          end;
        end
        else
        begin
          case ControlLook.ControlStyle of
          csTMS:
            begin
              if not dis then
                Bmp.LoadFromResourceName(hinstance,'ASGRAD02')
              else
                Bmp.LoadFromResourceName(hinstance,'ASGRAD04');
            end;
          csWinXP:
            begin
              if not dis then
                Bmp.LoadFromResourceName(hinstance,'ASGRAD06')
              else
                Bmp.LoadFromResourceName(hinstance,'ASGRAD08');
            end;
          csGlyph:
            Bmp.Assign(ControlLook.RadioOffGlyph);
          end;
        end;

        Bmp.Transparent := True;
        Bmp.TransparentMode := tmAuto;

        Canvas.Draw(DrawRect.Left,DrawRect.Top,Bmp);
        Bmp.free;
      end;
    csBorland:
      begin
        if dir then
        begin
          DrawRect.Left := DrawOfs + R.Left + 2 + (DrawNum - 1) * 16;
          DrawRect.Top := R.Top + (R.Bottom - R.Top - 16) div 2;

          if s <> '' then
          begin
           Canvas.Textout(DrawRect.Left + 16,DrawRect.Top - 2,s);
           DrawOfs := DrawOfs + Canvas.TextWidth(s);
          end
        end
        else
        begin
          th := Max(16,Canvas.TextHeight('gh'));
          if s <> '' then
          begin
            DrawRect.Left := R.Left + 2;
            DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
            Canvas.Textout(DrawRect.Left + 16 + 2,Drawrect.Top - 2,s);
          end
          else
          begin
            DrawRect.Left := R.Left + (R.Right - R.Left - 16) div 2;
            DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
          end;
        end;

        OldColor := Canvas.Brush.Color;

        Canvas.Brush.Color := clBtnFace;

        Canvas.Polygon([Point(DrawRect.Left + 2,DrawRect.Top + 8),
                        Point(DrawRect.Left + 8,DrawRect.Top + 2),
                        Point(DrawRect.Left + 14,DrawRect.Top + 8),
                        Point(DrawRect.Left + 8,DrawRect.Top + 14)]);

        if RadioOn then
          Canvas.Pen.Color := clGray
        else
          Canvas.Pen.Color := clWhite;

        Canvas.MoveTo(DrawRect.Left + 8,DrawRect.Top + 14);
        Canvas.LineTo(DrawRect.Left + 2,DrawRect.Top + 8);
        Canvas.LineTo(DrawRect.Left + 8,DrawRect.Top + 2);

        if RadioOn then
          Canvas.Pen.Color := clWhite
        else
          Canvas.Pen.Color := clGray;

        Canvas.LineTo(DrawRect.Left + 14,DrawRect.Top + 8);
        Canvas.LineTo(DrawRect.Left + 8,DrawRect.Top + 14);

        Canvas.Brush.Color := ControlLook.Color;
        Canvas.Pen.Color := ControlLook.Color;

        if RadioOn then
        Canvas.Polygon([Point(DrawRect.Left + 6,DrawRect.Top + 8),
                        Point(DrawRect.Left + 8,DrawRect.Top + 6),
                        Point(DrawRect.Left + 10,DrawRect.Top + 8),
                        Point(DrawRect.Left + 8,DrawRect.Top + 10)]);


        Canvas.Brush.Color := OldColor;


      end;
    csTheme:
      begin
        if FIsWinXP then
        begin

          if dir then
          begin
            DrawRect.Left := DrawOfs + R.Left + 2 + (DrawNum - 1) * 16;
            DrawRect.Top := R.Top + (R.Bottom - R.Top - 16) div 2;

            if s <> '' then
            begin
             Canvas.Textout(DrawRect.Left + 16,DrawRect.Top - 2,s);
             DrawOfs := DrawOfs + Canvas.TextWidth(s);
            end
          end
          else
          begin
            th := Max(16,Canvas.TextHeight('gh'));
            if s <> '' then
            begin
              DrawRect.Left := R.Left + 2;
              DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
              Canvas.Textout(DrawRect.Left + 16 + 2,Drawrect.Top-2,s);
            end
            else
            begin
              DrawRect.Left := R.Left + (R.Right - R.Left - 16) div 2;
              DrawRect.Top := R.Top + 2 + (DrawNum - 1) * th * DirFactor;
            end;
          end;

          DrawRect.Right := DrawRect.Left + 16;
          DrawRect.Bottom := DrawRect.Top + 16;


          HTheme := OpenThemeData(self.Handle,'button');

          if RadioOn then
          begin
            if not dis then
              DrawThemeBackground(HTheme,Canvas.Handle, BP_RADIOBUTTON,RBS_CHECKEDNORMAL,@DrawRect,nil)
            else
              DrawThemeBackground(HTheme,Canvas.Handle, BP_RADIOBUTTON,RBS_CHECKEDDISABLED,@DrawRect,nil)
          end
          else
          begin
            if not dis then
              DrawThemeBackground(HTheme,Canvas.Handle, BP_RADIOBUTTON,RBS_UNCHECKEDNORMAL,@DrawRect,nil)
            else
              DrawThemeBackground(HTheme,Canvas.Handle, BP_RADIOBUTTON,RBS_UNCHECKEDDISABLED,@DrawRect,nil)
          end;

          CloseThemeData(HTheme);
        end;
      end;
    end;
  end;
end;

procedure TAdvStringGrid.DrawCheck(R: TRect; State,Enabled,Grayed: Boolean; ControlStyle: TControlStyle;  bTriState: Boolean; cbState: TCheckBoxState);
var
  DrawState: Integer;
  DrawRect,DRect: TRect;
  BMP: TBitmap;
  HTheme: THandle;
  cstyle: TControlStyle;
  hold: Integer;

begin
  if ControlLook.NoDisabledCheckRadioLook or ControlLook.CheckAlwaysActive then
    Enabled := true;

  cstyle := ControlStyle;
  if (cstyle = csTheme) and (not FIsComCtl6 or not FIsWinXP) then
    cstyle := csClassic;

  if (bTriState) then
  begin
    State := false;  //something dummy
    case cbState of
    cbGrayed: Grayed := true;
    cbUnchecked: State:= false;
    cbChecked: State := true;
    end;
  end;

  case cstyle of
  csClassic,csFlat:
    begin
      if State then
        DrawState := DFCS_BUTTONCHECK or DFCS_CHECKED
      else
        DrawState := DFCS_BUTTONCHECK;

      if Grayed then
        DrawState := DrawState or DFCS_BUTTON3STATE or DFCS_CHECKED;

      if ControlStyle = csFlat then
        DrawState := DrawState or DFCS_FLAT;

      if not Enabled then
        DrawState := DrawState or DFCS_INACTIVE;

      DrawRect.Left := R.Left + (R.Right - R.Left - FControlLook.CheckSize) div 2;
      DrawRect.Top:= R.Top + (R.Bottom - R.Top - FControlLook.CheckSize) div 2;
      DrawRect.Right := DrawRect.Left + FControlLook.CheckSize;
      DrawRect.Bottom := DrawRect.Top + FControlLook.CheckSize;

      if UseRightToLeftAlignment then
      begin
        DRect := DrawRect;

        if not FNoRTLOrientation then
        begin
          DrawRect.Left := ClientWidth - DrawRect.Left;
          DrawRect.Right := ClientWidth - DrawRect.Right;
        end
        else
        begin
          DrawRect.Left := DrawRect.Left - XYOffset.X;
          DrawRect.Right := DrawRect.Right + XYOffset.X;
        end;

        Hold := DrawRect.Left;
        DrawRect.Left := DrawRect.Right;
        DrawRect.Right := Hold;
        ChangeGridOrientation(False);
      end;

      DrawFrameControl(Canvas.Handle,DrawRect,DFC_BUTTON,DrawState);

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
        DrawRect := DRect;
      end;
    end;
  csTMS:
    begin
      Bmp := TBitmap.Create;
      if State then
      begin
        if Enabled then
          Bmp.LoadFromResourceName(hinstance,'ASGCHK01')
        else
          Bmp.LoadFromResourceName(hinstance,'ASGCHK03');
      end
      else
      begin
        if Enabled then
          Bmp.LoadFromResourceName(hinstance,'ASGCHK02')
        else
          Bmp.LoadFromResourceName(hinstance,'ASGCHK04');
      end;

      Bmp.Transparent := True;
      Bmp.TransparentMode := tmAuto;

      if UseRightToLeftAlignment then
      begin
        if not FNoRTLOrientation then
        begin
          R.Left := ClientWidth - R.Left;
          R.Right := ClientWidth - R.Right;
        end
        else
        begin
          R.Left := R.Left - XYOffset.X;
          R.Right := R.Right + XYOffset.X;
        end;

        Hold := R.Left;
        R.Left := R.Right;
        R.Right := Hold;

        ChangeGridOrientation(False);
      end;

      Canvas.Draw(R.Left,R.Top,bmp);
      Bmp.free;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
      end;

    end;
  csGlyph:
    begin
      if UseRightToLeftAlignment then
      begin
        if not FNoRTLOrientation then
        begin
          R.Left := ClientWidth - R.Left;
          R.Right := ClientWidth - R.Right;
        end
        else
        begin
          R.Left := R.Left - XYOffset.X;
          R.Right := R.Right + XYOffset.X;
        end;

        Hold := R.Left;
        R.Left := R.Right;
        R.Right := Hold;

        ChangeGridOrientation(False);
      end;

      if State and not ControlLook.CheckedGlyph.Empty then
      begin
        ControlLook.CheckedGlyph.Transparent := True;
        ControlLook.CheckedGlyph.TransparentMode := tmAuto;
        Canvas.Draw(R.Left,R.Top,ControlLook.CheckedGlyph);
      end;

      if not State and not ControlLook.UnCheckedGlyph.Empty then
      begin
        ControlLook.UnCheckedGlyph.Transparent := True;
        ControlLook.UnCheckedGlyph.TransparentMode := tmAuto;
        Canvas.Draw(R.Left,R.Top,ControlLook.UnCheckedGlyph);
      end;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
      end;

    end;
  csTheme:
    begin
      if FIsWinXP then
      begin
        HTheme := OpenThemeData(Self.Handle,'button');

        r := Rect(R.Left, R.Top, R.Left + FControlLook.CheckSize, R.Top + FControlLook.CheckSize);

        if Grayed then
        begin
          if Enabled then
            DrawThemeBackground(HTheme,Canvas.Handle, BP_CHECKBOX,CBS_MIXEDNORMAL,@r,nil)
          else
            DrawThemeBackground(HTheme,Canvas.Handle, BP_CHECKBOX,CBS_MIXEDDISABLED,@r,nil);
        end
        else
        begin
          if State then
          begin
            if Enabled then
              DrawThemeBackground(HTheme,Canvas.Handle, BP_CHECKBOX,CBS_CHECKEDNORMAL,@r,nil)
            else
              DrawThemeBackground(HTheme,Canvas.Handle, BP_CHECKBOX,CBS_CHECKEDDISABLED,@r,nil);
          end
          else
          begin
            if Enabled then
              DrawThemeBackground(HTheme,Canvas.Handle, BP_CHECKBOX,CBS_UNCHECKEDNORMAL,@r,nil)
            else
              DrawThemeBackground(HTheme,Canvas.Handle, BP_CHECKBOX,CBS_UNCHECKEDDISABLED,@r,nil);
          end;
        end;

        CloseThemeData(HTheme);
      end;
    end;
  csWinXP:
    begin
      Bmp := TBitmap.Create;
      if State then
      begin
        if Enabled then
          Bmp.LoadFromResourceName(hinstance,'ASGCHK05')
        else
          Bmp.LoadFromResourceName(hinstance,'ASGCHK07');
      end
      else
      begin
        if Enabled then
          Bmp.LoadFromResourceName(hinstance,'ASGCHK06')
        else
          Bmp.LoadFromResourceName(hinstance,'ASGCHK08');
      end;

      Bmp.Transparent := True;
      Bmp.TransparentMode := tmAuto;

      if UseRightToLeftAlignment then
      begin
        if not FNoRTLOrientation then
        begin
          R.Left := ClientWidth - R.Left;
          R.Right := ClientWidth - R.Right;
        end
        else
        begin
          R.Left := R.Left - XYOffset.X;
          R.Right := R.Right + XYOffset.X;
        end;

        Hold := R.Left;
        R.Left := R.Right;
        R.Right := Hold;

        ChangeGridOrientation(False);
      end;

      Canvas.Draw(R.Left,R.Top,bmp);
      Bmp.free;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
      end;

    end;

  csBorland:
    begin
      if Enabled then
        Canvas.Brush.Color := clBtnFace
      else
        Canvas.Brush.Color := clBtnShadow;

      Canvas.Pen.Color := clBtnFace;
      Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);
      Canvas.Pen.Color := clBtnHighLight;
      Canvas.MoveTo(R.Left,R.Bottom);
      Canvas.LineTo(R.Left,R.Top);
      Canvas.LineTo(R.Right,R.Top);
      Canvas.Pen.Color := clBtnShadow;
      Canvas.LineTo(R.Right,R.Bottom);
      Canvas.LineTo(R.Left,R.Bottom);

      if UseRightToLeftAlignment then
      begin

        if not FNoRTLOrientation then
        begin
          R.Left := ClientWidth - R.Left;
          R.Right := ClientWidth - R.Right;
        end
        else
        begin
          R.Left := R.Left - XYOffset.X;
          R.Right := R.Right + XYOffset.X;
        end;

        Hold := R.Left;
        R.Left := R.Right;
        R.Right := Hold;

        ChangeGridOrientation(False);
      end;

      if State then
      begin
        if Enabled then
          Canvas.Pen.Color := FControlLook.Color
        else
          Canvas.Pen.Color := clGray;

        Canvas.Pen.Width := 1;
        Dec(R.Top);
        Dec(R.Bottom);
        Canvas.MoveTo(R.Left + 2,R.Top + FControlLook.CheckSize div 2 + 1);
        Canvas.LineTo(R.Left + 2,R.Bottom - 1);
        Canvas.MoveTo(R.Left + 3,R.Top + FControlLook.CheckSize div 2);
        Canvas.LineTo(R.Left + 3,R.Bottom - 2);
        Canvas.MoveTo(R.Left + 2,R.Bottom - 1);
        Canvas.LineTo(R.Right - 2,R.Top + 3);
        Canvas.MoveTo(R.Left + 3,R.Bottom - 1);
        Canvas.LineTo(R.Right - 1,R.Top + 3);
      end;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
      end;

    end;
  end;
end;


procedure TAdvStringGrid.DrawGridCell(Canvas: TCanvas; ACol, ARow : longint; ARect : TRect;
  AState : TGridDrawState);
const
  Alignments: array[TAlignment] of DWORD = (DT_LEFT,DT_RIGHT,DT_CENTER);
  VAlignments: array[TVAlignment] of DWORD = (DT_TOP,DT_VCENTER,DT_BOTTOM);

var
  GraphicWidth,GraphicHeight: Integer;
  MaxTextWidth,MaxTextHeight: Integer;
  HAlignment: TAlignment;
  VAlign: TVAlignment;
  hal: TCellHAlign;
  val: TCellVAlign;
  tal: TAlignment;
  displtext: Boolean;
  vpos: Integer;
  LFont: TLogFont;
  hOldFont,hNewFont: HFont;
  Anchor,Stripped,FocusAnchor,AnchorHint,BtnCap: string;
  xsize,ysize: Integer;
  ctt: TTextType;
  cg: TCellGraphic;
  OCol,RRow,RCol: Integer;
  FOldBrushColor,FOldFontColor, AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  BRect, CRect, WRect: TRect;
  OrigRight,lvl: Integer;
  HTheme: THandle;
  pt: TPoint;
  CellWW: boolean;
  GD: TCellGradientDirection;
  Settings: TGaugeSettings;
  ci: integer;
  brshColor: TColor;
  brdrColor: TColor;
  BStyle: dword;
  ScrollPos: integer;
  sp: TScrollProp;
  io: TInterfacedPersistent;
  icg: ICellGraphic;
  ratevalue: double;
  bc: TPoint;
  gs: TGridRect;
  gla: TBitmap;
  Editable: boolean;
  CellIsFixed: boolean;
  CellHasFilter: boolean;
  CtrlStyle: TControlDrawStyle;
  CtrlState: TControlState;
  FDidVCLStyles: boolean;
  fe: boolean;
  cp: TCellProperties;
  cellc: boolean;
  AEditor: TEditorType;
  {$IFDEF DELPHIXE2_LVL}
  LStyle: TCustomStyleServices;
  LDetails: TThemedElementDetails;
  SaveIndex: integer;
  {$ENDIF}

  function Limit(d: double): double;
  begin
    if d < 0 then
      Result := 0
    else
      if d > 100 then
        Result := 100
      else
        Result := d;
  end;

  procedure DrawBorders(ACol,ARow: Integer;tr: TRect);
  var
    Oldpen: TPen;
    Borders: TCellBorders;
    GLWH,GLWV: Integer;
    PenL,PenR,PenT,PenB: TPen;
  begin
    OldPen := TPen.Create;
    OldPen.Assign(Canvas.Pen);
    borders := [];
    GetCellBorder(ACol,ARow,Canvas.Pen,Borders);

    PenL := TPen.Create;
    PenL.Assign(Canvas.Pen);
    PenR := TPen.Create;
    PenR.Assign(Canvas.Pen);
    PenB := TPen.Create;
    PenB.Assign(Canvas.Pen);
    PenT := TPen.Create;
    PenT.Assign(Canvas.Pen);

    if not IsFixed(OCol,ARow) then
      tr.Left := tr.Left - 1;

    tr.Top := tr.Top + 1;

    if Assigned(OnGetCellBorderProp) then
      OnGetCellBorderProp(Self, ARow, ACol, PenL, PenT, PenR, PenB);

    GLWV := (Canvas.Pen.Width + 1) shr 1;

    if not (goVertLine in Options) then
     GLWV := 0;

    GLWH := (Canvas.Pen.Width + 1) shr 1;

    if not (goHorzLine in Options) then
     GLWH := 0;

    tr.Left := tr.Left + GLWV;
    tr.Right := tr.Right - GLWV;
    tr.Top := tr.Top + GLWH;
    tr.Bottom := tr.Bottom - GLWH;

    if cbLeft in Borders then
    begin
      Canvas.Pen.Assign(PenL);
      Canvas.MoveTo(Max(0,tr.Left), tr.Top - GLWH - 1);
      Canvas.LineTo(Max(0,tr.Left), tr.Bottom);
    end;

    if cbRight in Borders then
    begin
      Canvas.Pen.Assign(PenR);
      Canvas.MoveTo(tr.Right - 1,tr.Top - GLWH - 1);
      Canvas.LineTo(tr.Right - 1,tr.Bottom);
    end;

    if cbTop in Borders then
    begin
      Canvas.Pen.Assign(PenT);
      if GridLineWidth = 0 then
      begin
        Canvas.MoveTo(tr.Left,tr.Top  + 1);
        Canvas.LineTo(tr.Right,tr.Top  + 1);
      end
      else
      begin
        Canvas.MoveTo(tr.Left,Max(0,tr.Top  - GridLineWidth));
        Canvas.LineTo(tr.Right,Max(0,tr.Top  - GridLineWidth));
      end;
    end;

    if cbBottom in Borders then
    begin
      Canvas.Pen.Assign(PenB);
      Canvas.MoveTo(tr.Left,tr.Bottom - 1);
      Canvas.LineTo(tr.Right,tr.Bottom - 1);
    end;

    Canvas.Pen.Assign(OldPen);
    OldPen.Free;
    PenL.Free;
    PenB.Free;
    PenR.Free;
    PenT.Free;
  end;

  // Draws a checkbox in the cell

  //procedure DrawCheck(R:TRect;State,Enabled: Boolean; ControlStyle: TControlStyle);

  // Draws graphic in the cell
  procedure DrawCellGraphic(r: TRect; CellGraphic: TCellGraphic; VertAlign: TVAlignment);
  var
    TgtRect,SrcRect,DrwRect: TRect;
    //tmpbmp: TBitmap;
    srcColor: TColor;
    idx,deltx,delty,tw,mlw: Integer;
    s,ln: string;
    sz: TSize;
    IsEdit,ml: Boolean;
    HTheme: THandle;
    VA: TCellVAlign;
    io: TInterfacedPersistent;
    icg: ICellGraphic;
    FImages: TCustomImageList;

  begin
    SrcRect.Top := 0;
    SrcRect.Left := 0;
    SrcRect.Right := GraphicWidth;
    SrcRect.Bottom := GraphicHeight;

    if not (CellGraphic.CellType in [ctProgress,ctRangeIndicator,ctXPProgress, ctNode]) then
      InflateRect(r, -XYOffset.X + 1, -XYOffset.Y + 1);

    if MaxTextWidth > 0 then
      MaxTextWidth := MaxTextWidth + 2;

    case CellGraphic.CellHAlign  of
    haLeft:
      begin
        TgtRect.Left := r.Left + 1;
        TgtRect.Right := TgtRect.Left + GraphicWidth;
      end;
    haRight:
      begin
        TgtRect.Right := r.Right - 1;
        TgtRect.Left := TgtRect.Right - GraphicWidth;
      end;
    haCenter:
      begin
        if (GraphicWidth < r.Right - r.Left) then
        begin
          TgtRect.Left := r.Left + (r.Right - r.Left - GraphicWidth) shr 1;
          TgtRect.Right := TgtRect.Left + GraphicWidth;
        end
        else
        begin
          TgtRect.Left := r.Left + 1;
          TgtRect.Right := TgtRect.Left + GraphicWidth;
        end;
      end;
    haBeforeText:
      begin
        case tal of
        taLeftJustify:
          begin
            TgtRect.Left := r.Left + 1;
            TgtRect.Right := TgtRect.Left + GraphicWidth;
          end;
        taRightJustify:
          begin
            TgtRect.Left := r.Right - MaxTextWidth - GraphicWidth;
            TgtRect.Right := TgtRect.Left + GraphicWidth;
            if TgtRect.Left < r.Left then
              TgtRect.Left := r.Left + 1;
          end;
        taCenter:
          begin
            TgtRect.Left := r.Left + ((r.Right - r.Left - MaxTextWidth - GraphicWidth) div 2);
            TgtRect.Right := TgtRect.Left + GraphicWidth;
            if TgtRect.Left < r.Left then
              TgtRect.Left := r.Left + 1;
          end;
        end;

      end;
    haAfterText:
      begin
        case tal of
        taLeftJustify:
          begin
            TgtRect.Left := r.Left + MaxTextWidth;
            TgtRect.Right := TgtRect.Left + GraphicWidth;
          end;
        taRightJustify:
          begin
            TgtRect.Right := r.Right - 1;
            TgtRect.Left := TgtRect.Right - GraphicWidth;
          end;
        taCenter:
          begin
            TgtRect.Left := r.Left + MaxTextWidth + ((r.Right - r.Left - MaxTextWidth - GraphicWidth) div 2);
            TgtRect.Right := TgtRect.Left + GraphicWidth;
            if TgtRect.Left < r.Left then
              TgtRect.Left := r.Left + 1;
          end;
        end;

        if tal = taRightJustify then
        begin
        end
        else
      end;
    haFull:
      begin
        TgtRect.Right := r.Right;
        TgtRect.Left := r.Left;
      end;
    end;

    VA := CellGraphic.CellVAlign;

    if CellGraphic.CellType in [ctCheckBox, ctDataCheckBox, ctVirtCheckBox, ctTriStateCheckBox, ctRowCheckBox,ctRadioButton] then
    begin
      if (VertAlign <> VAlignment) then
      begin
        case VertAlign of
        vtaTop: VA := vaTop;
        vtaCenter: VA := vaCenter;
        vtaBottom: VA := vaBottom;
        end;
      end;
    end;


    case VA  of
    vaTop,vaAboveText:
      begin
        TgtRect.Top := r.Top + 1;
        TgtRect.Bottom := TgtRect.Top + GraphicHeight;
      end;
    vaBottom:
      begin
        TgtRect.Bottom := r.Bottom - 1;
        TgtRect.Top := TgtRect.Bottom - GraphicHeight;
      end;
    vaCenter:
      begin
        if GraphicHeight < (r.Bottom - r.Top) then
        begin
          TgtRect.Top := r.Top + (r.Bottom - r.Top - GraphicHeight) shr 1;
          TgtRect.Bottom := TgtRect.Top + GraphicHeight;
        end
        else
        begin
          TgtRect.Top := r.Top + 1;
          TgtRect.Bottom := TgtRect.Top + GraphicHeight;
        end;
      end;
    vaUnderText:
      begin
        TgtRect.Top := r.Bottom - GraphicHeight;
        TgtRect.Bottom := r.Bottom;
      end;
    vaFull:
      begin
        TgtRect.Top := r.Top;
        TgtRect.Bottom := r.Bottom;
      end;
    end;

    case CellGraphic.CellType of
    ctCheckBox,ctDataCheckBox,ctTriStateCheckBox,ctVirtCheckBox,ctRowCheckBox,ctRadioButton:
    begin
      if Assigned(OnGetAlignment) or HasColumnsProp then
      begin
        case HAlignment of
        taLeftJustify:
          begin
            TgtRect.Left := r.Left + 1;
            TgtRect.Right := TgtRect.Left + GraphicWidth;
          end;
        taRightJustify:
          begin
            if CellGraphic.CellType in [ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox] then
              TgtRect.Left := r.Right - GraphicWidth - 1
            else
              TgtRect.Left := r.Right - MaxTextWidth - GraphicWidth - 1;

            if TgtRect.Left < r.Left then
              TgtRect.Left := r.Left + 1;
            TgtRect.Right := TgtRect.Left + GraphicWidth;
          end;
        taCenter:
          begin
            if CellGraphic.CellType in [ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox] then
              TgtRect.Left := r.Left + (Max(0,(r.Right - GraphicWidth - r.Left)) shr 1)
            else
            begin
              if MaxTextWidth > 0 then
                TgtRect.Left := r.Left - GraphicWidth + Max(0,(r.Right - MaxTextWidth - r.Left)) shr 1
              else
                TgtRect.Left := r.Left + Max(0,(r.Right - GraphicWidth - r.Left)) shr 1;
            end;
            if TgtRect.Left < r.Left then TgtRect.Left := r.Left + 1;
              TgtRect.Right := TgtRect.Left + GraphicWidth;
          end;
        end;
      end;

      IsEdit := True;

      GetCellReadOnly(ACol,ARow,IsEdit);

      if (CellGraphic.CellType in [ctCheckBox,ctRowCheckBox]) then
        DrawCheck(TgtRect,CellGraphic.CellBoolean,IsEdit,CellGraphic.CellAngle > 0, FControlLook.ControlStyle)
      else
        if (CellGraphic.CellType in [ctDataCheckBox,ctVirtCheckBox]) then
          DrawCheck(TgtRect,Cells[ACol,ARow] = GetCheckTrue(ACol,ARow),IsEdit, false, FControlLook.ControlStyle)
        else
        if ( CellGraphic.CellType = ctTriStateCheckBox) then
          DrawCheck( TgtRect, False{dummy}, IsEdit, CellGraphic.CellAngle > 0, FControlLook.ControlStyle, True, CellGraphic.CellCheckBoxState )
        else
        begin
          TgtRect.Left := TgtRect.Left + XYOffset.X;
          TgtRect.Right := TgtRect.Left + FControlLook.FRadioSize;
          TgtRect.Bottom := TgtRect.Top + FControlLook.FRadioSize;

          if CellGraphic.CellBoolean then
            DrawRadio(Canvas, TgtRect, 1, 0, false, not IsEdit, nil, false, ACol, ARow, FControlLook.ControlStyle, 1.0, false)
          else
            DrawRadio(Canvas, TgtRect, 1, -1, false, not IsEdit, nil, false, ACol, ARow, FControlLook.ControlStyle, 1.0, false)
        end;

    end;

    ctRotated:
    begin
      SrcRect := r;
      TgtRect := r;

      ml := (Abs(CellGraphic.CellAngle) = 90) and (LinesInText(Cells[ACol,ARow], MultiLineCells or WordWrap) > 1);

      s := GetFormattedCell(ACol,ARow);

      if ml then
        s := GetLongestLine(Canvas, s);

      CalcTextPos(SrcRect,sz, CellGraphic.CellAngle, s, HAlignment, VAlign);

      tw := sz.cy;

      if ml then
      begin
        mlw := 0;
        s := GetFormattedCell(ACol,ARow);
        repeat
          ln := GetNextLine(s,true);
          if ln <> '' then
          begin
            SrcRect.Right := SrcRect.Right + sz.cx;
            mlw := mlw + tw;
          end;
        until ln = '';

        if HAlignment = taCenter then
        begin
          srcRect.Left := srcRect.Left - ((mlw -tw) div 2);
        end;

        if HAlignment = taRightJustify then
        begin
          srcRect.Left := r.Right - mlw;
          srcRect.Right := r.Right;
        end;
      end;

      GetObject(Canvas.Font.Handle,SizeOf(LFont),Addr(LFont));
      LFont.lfEscapement := CellGraphic.CellAngle * 10;
      LFont.lfOrientation := CellGraphic.CellAngle * 10;

      hNewFont := CreateFontIndirect(LFont);
      hOldFont := SelectObject(Canvas.Handle,hNewFont);

      SetTextAlign(Canvas.Handle,TA_TOP);

      InflateRect(r,-1,-1);

      Canvas.Brush.Style := bsCLear;

      s := GetFormattedCell(ACol,ARow);

      if ml then
      begin
        repeat
          ln := GetNextLine(s,true);
          Canvas.TextRect(r,SrcRect.Left,SrcRect.Top,ln);
          SrcRect.Left := SrcRect.Left + tw;
        until ln = '';
      end
      else
        Canvas.TextRect(r,SrcRect.Left,SrcRect.Top,s);

      hNewFont := SelectObject(Canvas.Handle,hOldFont);
      DeleteObject(hNewFont);

      if ShouldDrawSortIndicator(ACol,ARow) and
         ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and
         (FixedRows > 0) and ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
        begin
         if not ((SortIndexes.FindIndex(ACol) > 0) and not FSortSettings.IndexShow) then
            DrawSortIndicator(Canvas,ACol,TgtRect.Right - 10,TgtRect.Top + 8);
        end;
    end;

    {
    ctComment:
    begin
      if ControlLook.CommentColor <> clNone then
      begin
        Canvas.Pen.Color := ControlLook.CommentColor;

        if TColor(CellGraphic.CellIndex) <> clNone then
          Canvas.Pen.Color := TColor(CellGraphic.CellIndex);

        Canvas.Brush.Color := Canvas.Pen.Color;
        Canvas.Polygon([Point(r.Right-8 + xyoffset.x ,r.Top + 1 - XYOffset.Y),Point(r.Right-3 + xyoffset.x,r.Top + 1 - XYOffset.y),Point(r.Right - 3 + XYOffset.x,r.Top + 6 - XYOffset.y)]);
        Canvas.Brush.Color := Self.Color;
      end;
    end;
    }
    ctProgressPie:
    begin
      DrawProgressPie(Canvas,Rect(TgtRect.left,TgtRect.Top,TgtRect.left+20,TgtRect.Top+20),TColor(CellGraphic.CellBitmap),CellGraphic.CellAngle, false);
    end;

    ctRangeIndicator:
    begin
      InflateRect(r,-ControlLook.ProgressMarginX,-ControlLook.ProgressMarginY);

      with CellGraphic do
        DrawRangeIndicator(Canvas,r,Ints[ACol,ARow],CellIndex,CellBoolean,TColor(CellBitmap),TColor(CellIcon));
    end;

    ctXPProgress:
    begin
      Settings.Level0Color := FProgressAppearance.Level0Color;
      Settings.Level0ColorTo := FProgressAppearance.Level0ColorTo;
      Settings.Level1Color := FProgressAppearance.Level1Color;
      Settings.Level1ColorTo := FProgressAppearance.Level1ColorTo;
      Settings.Level2Color := FProgressAppearance.Level2Color;
      Settings.Level2ColorTo := FProgressAppearance.Level2ColorTo;
      Settings.Level3Color := FProgressAppearance.Level3Color;
      Settings.Level3ColorTo := FProgressAppearance.Level3ColorTo;
      Settings.Level1Perc := FProgressAppearance.Level1Perc;
      Settings.Level2Perc := FProgressAppearance.Level2Perc;
      Settings.ShowBorder := FProgressAppearance.ShowBorder;
      Settings.BorderColor := FProgressAppearance.BorderColor;
      Settings.Stacked := FProgressAppearance.Stacked;
      Settings.ShowPercentage := FProgressAppearance.ShowPercentage;
      Settings.CompletionSmooth := FProgressAppearance.CompletionSmooth;
      Settings.ShowGradient := FProgressAppearance.ShowGradient;
      Settings.Font  := Font;
      Settings.FontColor := FProgressAppearance.FCompleteFontColor;
      Settings.Orientation := goHorizontal;
      Settings.Steps := FProgressAppearance.Steps;

      if FProgressAppearance.UnCompleteColor <> clNone then
        Settings.BackgroundColor := FProgressAppearance.UnCompleteColor
      else
        Settings.BackgroundColor := Brush.Color;

      InflateRect(r,-ControlLook.ProgressMarginX,-ControlLook.ProgressMarginY);
      r.Bottom := r.Bottom - 1;
      r.Right := r.Right - 1;

      DrawGauge(Canvas, R, Round(Abs(Ints[ACol,ARow] - CellGraphic.CellErrFrom) / (CellGraphic.CellErrLen - CellGraphic.CellErrFrom) * 100), Settings);
    end;

    ctProgress:
    begin
      if (ControlLook.ControlStyle in [csWinXP,csTheme]) and FIsWinXP and ControlLook.ProgressXP then
      begin
        HTheme := OpenThemeData(self.Handle,'Progress');

        InflateRect(r,-ControlLook.ProgressMarginX,-ControlLook.ProgressMarginY);

        DrawThemeBackground(HTHeme,Canvas.Handle,PP_BAR,0,@r,nil);

        InflateRect(r,-2,-2);
        SrcRect := r;

        SrcRect.Right := SrcRect.Left + Round((SrcRect.Right-SrcRect.Left)*(Limit(Floats[ACol,ARow]))/100);

        DrawThemeBackground(HTHeme,Canvas.Handle,PP_CHUNK,1,@SrcRect,nil);

        CloseThemeData(HTheme);
      end
      else
      begin
        InflateRect(r,-2,-2);

        with CellGraphic do
          if CellBoolean then
            DrawProgressLin(Canvas,r,TColor(CellBitmap),TColor(CellIndex),
              TColor(CellIcon),TColor(CellAngle),Floats[ACol,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor,false)
          else
            DrawProgressLin(Canvas,r,TColor(CellBitmap),TColor(CellBitmap) xor $FFFFFF,
              TColor(CellIcon),TColor(CellIcon) xor $FFFFFF,Floats[ACol,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor,false);

      end;
    end;

    ctInterface:
    begin
      io := TInterfacedPersistent(cg.CellBitmap);
	    if io.GetInterface(ICellGraphic, icg) then
      begin
        icg.Draw(Canvas, Rect(r.Left-1,r.Top-1,r.Right,r.Bottom), ACol,ARow, (gdSelected in AState), self);
      end;
    end;

    ctBitmap:
    begin
      if (CellGraphic.CellTransparent) then
      begin
        (*
        TmpBmp := TBitmap.Create;
        TmpBmp.Height := GraphicHeight;
        TmpBmp.Width := GraphicWidth;

        if ShowSelection and (((gdSelected in AState) and not MouseActions.DisjunctRowSelect) or (MouseActions.DisjunctRowSelect and
           RowSelect[RRow] and (goRowSelect in Options) and (ACol >= FixedCols)) )
            {and not (gdFocused in AState) }then
        begin
          TmpBmp.Canvas.Brush.Color := FSelectionColor
        end
        else
          TmpBmp.Canvas.Brush.Color := Canvas.Brush.Color;
        *)

        if BidiMode = bdRightToLeft then
        begin
          idx := tgtrect.Left;
          tgtrect.Left := tgtrect.Right;
          tgtrect.Right := idx;
        end;
        {
        SrcColor := CellGraphic.CellBitmap.Canvas.pixels[0,0];
        TmpBmp.Canvas.BrushCopy(SrcRect,CellGraphic.CellBitmap,SrcRect,srcColor );
        Canvas.CopyRect(TgtRect, TmpBmp.Canvas, SrcRect);
        TmpBmp.Free;
        }

        CellGraphic.CellBitmap.Transparent := true;
        CellGraphic.CellBitmap.TransparentMode := tmAuto;
        Canvas.Draw(tgtrect.Left, tgtrect.Top, CellGraphic.CellBitmap);
      end
      else
        Canvas.Draw(TgtRect.Left,TgtRect.Top,CellGraphic.CellBitmap);
    end;

    ctButton,ctBitButton,ctExpand:
    begin
      CellGraphic.CellValue := MakeLong(TgtRect.Left - ARect.Left,TgtRect.Top - ARect.Top);
      s := CellGraphic.CellText;
      SrcColor := SetBKColor(Canvas.Handle,ColorToRGB(clBtnFace));

      IsEdit := true;

      if not ControlLook.NoDisabledButtonLook then
        GetCellReadOnly(ACol,ARow,IsEdit);

      if ControlLook.FlatButton then
        CtrlStyle := cdsFlat
      else
      begin
        if not FIsWinXP then
          CtrlStyle := cdsClassic
        else
          CtrlStyle := cdsXPTheme;
      end;

      if Flat and (FTones.Background.BrushColor <> clNone) then
        CtrlStyle := cdsMetro;

      if CellGraphic.cellBoolean then
        CtrlState := csDown
      else
      begin
        if (FHoverButton.X = ACol) and (FHoverButton.Y = ARow) then
          CtrlState := csHover
        else
          CtrlState := csNormal;
      end;

      if not IsEdit and (CellGraphic.CellType <> ctExpand) then
        CtrlState := csDisabled;

      if CellGraphic.CellType = ctExpand then
      begin
        tgtrect.Left := r.Right - 13;
        tgtrect.Right := r.Right;
        tgtrect.Top := r.Top;
        tgtrect.Bottom := r.Top + 13;
      end;

      DrawButton(Canvas, Handle, TgtRect, CtrlStyle, CtrlState, FTones, ControlLook.ButtonPrefix);

      if (CtrlState = csDown) then
        OffsetRect(TgtRect,1,1);

      if CellGraphic.CellType = ctBitButton then
      begin
        if not Cellgraphic.CellBitmap.Empty then
        begin
          Cellgraphic.CellBitmap.TransparentMode := tmAuto;
          Cellgraphic.CellBitmap.Transparent := true;

          deltx := (tgtrect.Right - tgtrect.Left) - Cellgraphic.CellBitmap.Width;
          delty := (tgtrect.Bottom - tgtrect.Top) - Cellgraphic.CellBitmap.Height;

          if delty > 0 then
            delty := delty div 2
          else
            delty := 3;

          if (deltx > 0) and (s = '') then
          begin
            Canvas.Draw(TgtRect.Left + deltx div 2, TgtRect.Top + delty, Cellgraphic.CellBitmap);
            TgtRect.Left := TgtRect.Left + deltx div + Cellgraphic.CellBitmap.Width + 4;
          end
          else
          begin
            Canvas.Draw(TgtRect.Left + 3, TgtRect.Top + delty, Cellgraphic.CellBitmap);
            TgtRect.Left := TgtRect.Left + Cellgraphic.CellBitmap.Width + 4;
          end;
        end;
      end;

      if Pos(#13,s) = 0 then
        BStyle := DT_SINGLELINE
      else
        BStyle := DT_WORDBREAK;

      TgtRect.Left := TgtRect.Left + 1;

      SetBkMode(Canvas.Handle,TRANSPARENT);

      DrwRect := TgtRect;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(False);

        drwRect.Left := ClientRect.Right - TgtRect.Right;
        drwRect.Right := ClientRect.Right - TgtRect.Left;
      end;

      if CtrlStyle = cdsMetro then
      begin
        case CtrlState of
        csNormal: Canvas.Font.Color := FTones.Background.TextColor;
        csDisabled: Canvas.Font.Color := FTones.Disabled.TextColor;
        csHover: Canvas.Font.Color := FTones.Hover.TextColor;
        csDown: Canvas.Font.Color := FTones.Selected.TextColor;
        end;
      end;

      if CellGraphic.CellType = ctExpand then
      begin
        Canvas.Pen.Color := clBlack;
        Canvas.Pen.Width := 1;

        if CellGraphic.CellVar = false then // collapsed or expanded state
        begin
          Canvas.MoveTo(r.Right - 10, r.Top + 5);
          Canvas.LineTo(r.Right - 7, r.Top + 8);
          Canvas.LineTo(r.Right - 3, r.Top + 4);
        end
        else
        begin
          Canvas.MoveTo(r.Right - 10, r.Top + 8);
          Canvas.LineTo(r.Right - 7, r.Top + 5);
          Canvas.LineTo(r.Right - 3, r.Top + 9);
        end;
      end
      else
      begin
        if not ControlLook.ButtonPrefix then
          BStyle := BStyle or DT_NOPREFIX;

        DrawText(Canvas.Handle,PChar(s),Length(s),drwRect,DT_CENTER or DT_VCENTER or DT_END_ELLIPSIS or BStyle);
        SetBKColor(Canvas.Handle,srcColor);

        if UseRightToLeftAlignment then
        begin
          ChangeGridOrientation(True);
        end;

        TgtRect.Left := TgtRect.Left - 1;
      end;
    end;

    ctPicture:
    begin
      DrwRect := TgtRect;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(False);

        DrwRect.Left := ClientRect.Right - TgtRect.Right;
        DrwRect.Right := ClientRect.Right - TgtRect.Left;
      end;

      if not (goVertLine in Options) then
        DrwRect.Left := DrwRect.Left - 1;

      if not (goHorzLine in Options) then
        DrwRect.Top := DrwRect.Top - 2;

      if (CellGraphic.CellAngle = 0) then
        Canvas.Draw(DrwRect.Left,DrwRect.Top,TPicture(CellGraphic.CellBitmap).Graphic)
      else
        Canvas.StretchDraw(DrwRect,TPicture(CellGraphic.CellBitmap).Graphic);

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(true);
      end;

    end;

    ctFilePicture:
    begin
      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(False);
      end;


      TFilepicture(CellGraphic.CellBitmap).DrawPicture(Canvas,TgtRect);
      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(true);
      end;
    end;

    ctIcon:
    begin
      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(False);
      end;

      Canvas.Draw(TgtRect.Left,TgtRect.Top,CellGraphic.cellIcon);
      
      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(true);
      end;
    end;

    ctRadio:
    begin
      IsEdit := True;
      GetCellReadOnly(ACol,ARow,IsEdit);

      DrawRadio(Canvas,r,GetRadioStrings(ACol,ARow).Count,CellGraphic.CellIndex,CellGraphic.cellBoolean,not IsEdit,
                TStringList(CellGraphic.cellbitmap), gdSelected in AState, ACol,ARow, ControlLook.ControlStyle, 1.0);
    end;

    ctShape:
    begin
      DrawShape(Canvas, TgtRect.Left,TgtRect.Top, TgtRect.Right - TgtRect.Left - 1,TgtRect.Bottom - TgtRect.Top - 1, TCellShape(CellGraphic.CellAngle), TColor(CellGraphic.CellIndex), TColor(CellGraphic.CellBitmap));
    end;

    ctRating:
    begin
      ratevalue := trunc(Floats[ACol,ARow] * 2) / 2;

      for idx := 1 to CellGraphic.FCellAngle do
      begin
        if idx <= ratevalue then
          DrawShape(Canvas, TgtRect.Left, TgtRect.Top, 16,16, csStar, TColor(CellGraphic.FCellIndex), TColor(CellGraphic.FCellIndex))
        else
          DrawShape(Canvas, TgtRect.Left, TgtRect.Top, 16,16, csStar, TColor(CellGraphic.FCellBitmap), TColor(CellGraphic.FCellBitmap));

        if (idx > ratevalue) and (idx - 1 < ratevalue) then
        begin
          DrawShape(Canvas, TgtRect.Left, TgtRect.Top, 16,16, csHalfStar, TColor(CellGraphic.FCellIndex), TColor(CellGraphic.FCellIndex));
        end;

        TgtRect.Left := TgtRect.Left + 18;
      end;
      DisplText := false;
    end;

    ctImageList:
    begin
      FImages := GetCellImageList(ACol,ARow);
      if Assigned(FImages) then
        FImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,CellGraphic.CellIndex);
    end;

    ctImages:
    begin
      FImages := GetCellImageList(ACol,ARow);
      if Assigned(FImages) then
      begin
        for idx := 1 to TIntList(CellGraphic.CellBitmap).Count do
        begin
          FImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,TIntList(CellGraphic.CellBitmap).Items[idx-1]);
           if CellGraphic.CellBoolean then
             TgtRect.Left := TgtRect.Left + FImages.Width
           else
             TgtRect.Top := TgtRect.Top + FImages.Height;
        end;
      end;
    end;

    ctDataImage:
    begin
      FImages := GetCellImageList(ACol,ARow);
      if Assigned(FImages) then
      begin
        if Cells[ACol,ARow] <> '' then
          idx := Ints[ACol,ARow]
        else
          idx := -1;

        if (idx >= 0) and (idx < FImages.Count) then
        begin
          FImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,idx {+ CellGraphic.CellIndex});
        end;
      end;
    end;

    ctNode:
    begin
      r.Left := NodeIndent(ARow) - CellNode.NodeIndent;

      if FCellNode.ShowTree and (ARow >= FixedRows) then
      begin
        Canvas.Pen.Color := FCellNode.TreeColor;
        Canvas.Pen.Width := 1;

        if (NodeIndent(ARow + 1) > 0) and (ARow + 1 < RowCount) and not (NodeState[ARow] and (NodeIndent(ARow + 1) < NodeIndent(ARow))  )  then
        begin
          Canvas.MoveTo(r.Left + 2 + CellNode.NodeIndent div 2,r.Top + (r.Bottom - r.Top) div 2);
          Canvas.LineTo(r.Left + 2 + CellNode.NodeIndent div 2,r.Bottom);
        end;

        if (NodeIndent(ARow - 1) >= NodeIndent(ARow)) then
        begin
          Canvas.MoveTo(r.Left + 2 + CellNode.NodeIndent div 2,r.Top);
          Canvas.LineTo(r.Left + 2 + CellNode.NodeIndent div 2,r.Top + (r.Bottom - r.Top) div 2);
        end;

        if (ACol < FixedCols) and not Flat and (Flook in [glTMS,glXP,glListView,glSoft]) then
          r.Left := r.Left + 1;
      end;

      r.Left := NodeIndent(ARow) - CellNode.NodeIndent div 2 - 4;

      if Canvas.Brush.Color <> clNone then
        brshColor := Canvas.Brush.Color
      else
        if FixedCols > 0 then
          brshColor := self.FixedColor
        else
          brshColor := self.Color;

      if CanShowSelection and (((gdSelected in AState) and not MouseActions.DisjunctRowSelect) or (MouseActions.DisjunctRowSelect and
         RowSelect[RRow] and (goRowSelect in Options) and (ACol >= FixedCols)) ) then
         brshColor := SelectionColor;

      if FCellNode.NodeType = cn3D then
      begin
        Canvas.Brush.Color := FCellNode.Color;
        Canvas.Rectangle(r.Left,r.Top,r.Right,r.Bottom);
        Frame3D(Canvas,r,clWhite,clGray,1);
      end;

      if (FCellNode.NodeType = cnLeaf) then
      begin
        OffsetRect(r,0,(r.Bottom - r.Top - 12) div 2);

        if CellGraphic.CellBoolean then
          DrawBitmapResourceTransp(Canvas,brshColor,r,'ASGLEAFCLOSE')
        else
          DrawBitmapResourceTransp(Canvas,brshColor,r,'ASGLEAFOPEN');
        Exit;
      end;

      if (FCellNode.NodeType = cnXP) then
      begin
        OffsetRect(r,4,(r.Bottom - r.Top - 10) div 2);

        if CellGraphic.CellBoolean then
          DrawBitmapResourceTransp(Canvas,brshColor,r,'XPNODEC')
        else
          DrawBitmapResourceTransp(Canvas,brshColor,r,'XPNODEO');
        Exit;
      end;

      if (FCellNode.NodeType = cnGlyph) and
         (not FCellNode.ExpandGlyph.Empty) and
         (not FCellNode.ContractGlyph.Empty) then
      begin
        CRect := r;
        CRect.Top := CRect.Top + (r.Bottom - r.Top - FCellNode.FContractGlyph.Height) div 2;

        if CellGraphic.CellBoolean then
          DrawBitmapTransp(Canvas,FCellNode.FContractGlyph,brshColor,CRect)
        else
          DrawBitmapTransp(Canvas,FCellNode.FExpandGlyph,brshColor,CRect);

        Exit;
      end;

      Canvas.Brush.Color := FCellNode.Color;
      r.Left := r.Left + 4;
      r.Right := r.Left + 8;
      r.Top := r.Top + (Max(0,r.Bottom - r.Top - 8) shr 1);
      r.Bottom := r.Top + 8;

      if FCellNode.NodeType = cnFlat then
      begin
        Canvas.Pen.Color := FCellNode.NodeColor;
        Canvas.Rectangle(r.Left - 0,r.Top - 0,r.Right + 1,r.Bottom + 1);
        if CellGraphic.CellBoolean then
        begin
          Canvas.MoveTo(r.Left + 2,r.Top+4);
          Canvas.LineTo(r.Left + 7,r.Top+4);

          Canvas.MoveTo(r.Left + 4,r.Top+2);
          Canvas.LineTo(r.Left + 4,r.Top+7);
        end
        else
        begin
          Canvas.MoveTo(r.Left + 2,r.Top + 4);
          Canvas.LineTo(r.Left + 7,r.Top + 4);
        end;
      end
      else
      begin
        if CellGraphic.CellBoolean then
          DrawEdge(Canvas.Handle,r,EDGE_RAISED,BF_RECT or BF_SOFT)
        else
          DrawEdge(Canvas.Handle,r,EDGE_SUNKEN,BF_RECT or BF_SOFT);
      end;
    end;
    end;

    if (CellGraphic.CellComment <> '') then
    begin
      Canvas.Pen.Color := ControlLook.CommentColor;
      if TColor(CellGraphic.CellIndex) <> clNone then
        Canvas.Pen.Color := CellGraphic.CommentColor;

      if Canvas.Pen.Color <> clNone then
      begin
        Canvas.Brush.Color := Canvas.Pen.Color;
        Canvas.Polygon([Point(r.Right-8 + xyoffset.x ,r.Top + 1 - XYOffset.Y),Point(r.Right-3 + xyoffset.x,r.Top + 1 - XYOffset.y),Point(r.Right - 3 + XYOffset.x,r.Top + 6 - XYOffset.y)]);
        Canvas.Brush.Color := Self.Color;
      end;
    end;

  end;

  procedure DrawWallPaperFixed(crect: TRect);
  var
    SrcRect,DstRect,Irect: TRect;
    x,y,ox,oy: Integer;
    dst: TPoint;

  begin
    dst.x := FBackground.Left;
    dst.y := FBackground.Top;
    x := FBackground.Bitmap.Width;
    y := FBackground.Bitmap.Height;

    DstRect.Top := dst.y;
    DstRect.Left := dst.x;
    DstRect.Right := DstRect.Left + x;
    DstRect.Bottom := DstRect.Top + y;

    if not IntersectRect(irect,crect,dstRect) then
      Exit;

    SetBkMode(Canvas.Handle,TRANSPARENT);

    ox := crect.Left - dst.x;
    oy := crect.Top - dst.y;

    SrcRect.Left := ox;
    SrcRect.Top := oy;
    SrcRect.Right := ox + crect.Right - crect.Left;
    SrcRect.Bottom := oy + crect.Bottom - crect.Top;

    DstRect := crect;

    if ox <= 0 then
    begin
      DsTRect.Left := dst.x;
      SrcRect.Left := 0;
      SrcRect.Right := DstRect.Right - DstRect.Left;
    end;

    if oy <= 0 then
    begin
      DstRect.Top := dst.y;
      SrcRect.Top := 0;
      SrcRect.Bottom := DstRect.Bottom - DstRect.Top;
    end;

    if (SrcRect.Left + (DstRect.Right - DstRect.Left) > x) then
    begin
      DstRect.Right := DstRect.Left + x - SrcRect.Left;
      SrcRect.Right := x;
    end;

    if (SrcRect.Top + DsTRect.Bottom - DsTRect.Top > y) then
    begin
      DsTRect.Bottom := DsTRect.Top + y - SrcRect.Top;
      SrcRect.Bottom := y;
    end;
    Canvas.CopyRect(DstRect,FBackground.Bitmap.Canvas,SrcRect);
  end;

  procedure DrawWallPaperTile(crect:TRect);
  var
    SrcRect,DsTRect:TRect;
    x,y,xo,yo,ox,oy,i: Integer;
  begin
    x := FBackground.Bitmap.Width;
    y := FBackground.Bitmap.Height;
    SetBkMode(Canvas.Handle,TRANSPARENT);

    if FBackGround.FBackgroundCells = bcNormal then
      xo := FixedCols else xo:=0;

    ox := 0;
    for i := xo + 1 to ACol do
      ox := ox + ColWidths[i - 1];

    if FBackGround.FBackgroundCells = bcNormal then
       yo := FixedRows else yo := 0;

    oy := 0;
    for i := yo + 1 to ARow do
      oy := oy + RowHeights[i - 1];

    ox := ox mod x;
    oy := oy mod y;

    SrcRect.Left := ox;
    SrcRect.Top := oy;
    SrcRect.Right := x;
    SrcRect.Bottom := y;

    yo := cRect.Top - 1;

    while yo < cRect.Bottom do
    begin
      xo := cRect.Left -1;
      SrcRect.Left := ox;
      SrcRect.Right := x;
      while xo < cRect.Right do
      begin
        DstRect := Rect(xo,yo,xo + SrcRect.Right - SrcRect.Left,yo + SrcRect.Bottom - SrcRect.Top);

        if DstRect.Right > crect.Right then
        begin
          DstRect.Right := crect.Right;
          SrcRect.Right := SrcRect.Left + (dstRect.Right - dstRect.Left);
        end;
        if DstRect.Bottom > crect.Bottom then
        begin
          DstRect.Bottom := crect.Bottom;
          SrcRect.Bottom := SrcRect.Top + (dstRect.Bottom - dstRect.Top);
        end;

        Canvas.CopyRect(DstRect,FBackground.Bitmap.Canvas,SrcRect);
        xo := xo + SrcRect.Right - SrcRect.Left;
        SrcRect.Left := 0;
        SrcRect.Right := x;
      end;
      yo := yo + SrcRect.Bottom - SrcRect.Top;
      SrcRect.Top := 0;
      SrcRect.Bottom := y;
    end;
  end;

  procedure DrawGradientBackground(crect:TRect);
  var
    C1,C2: TColor;
  begin
    if FBackground.Display = bdGradientVert then
    begin
      C1 := GradientAt(FBackground.Color, FBackground.ColorTo, 0, self.Height, crect.Top);
      C2 := GradientAt(FBackground.Color, FBackground.ColorTo, 0, self.Height, crect.Bottom);
    end
    else
    begin
      C1 := GradientAt(FBackground.Color, FBackground.ColorTo, 0, self.Width, crect.Left);
      C2 := GradientAt(FBackground.Color, FBackground.ColorTo, 0, self.Width, crect.Right);
    end;

    Canvas.Brush.Color := C2;
    Canvas.Pen.Color := C2;

    if not (goHorzLine in Options) then
      crect.Bottom := crect.Bottom + 1;

    DrawGradient(Canvas,C1,C2,128,crect,FBackground.Display = bdGradientHorz);
  end;

  procedure DrawCellText;
  var
    AlignValue: TAlignment;
    FontHeight: Integer;
    DCRect,Hr,CR, MR: TRect;
    TmpStr: string;
    SortWidth: Integer;
    URLCol,OldCol: TColor;
    c,ml,hl,sortindent: Integer;
    DrawStyle: DWord;
    ErrPos,ErrLen: Integer;
    FltrBmp: TBitmap;
    CID,CV,CT: string;
    DRect: TRect;
    Hold: Integer;
    HoL: integer;
    {$IFDEF TMSUNICODE}
    ws: widestring;
    {$ENDIF}
    //ch: integer;
    CLIPRGN: THandle;
    FImages: TCustomImageList;
    lit,th,dtsz: integer;
    ft: TFilterType;
    fltrstr: string;
    ld: integer;
  begin
    URLCol := FURLColor;

    if ((gdSelected in Astate) or
       (RowSelect[RRow] and (goRowSelect in Options) and (ACol >= FixedCols) and (ACol < ColCount - FixedRightCols))) {and not
       ((gdFocused in AState) and not
       (goDrawFocusSelected in Options))} and not IsFixed(OCol,RRow) then
    begin
      if CanShowSelection then
      begin
        if FSelectionColor <> clNone then
          Canvas.Brush.Color := FSelectionColor;
        if (FSelectionTextColor <> clNone) and Enabled then
          Canvas.Font.Color := FSelectionTextColor;

        URLCol := FSelectionTextColor;
      end;

      if (not (GetFocus = Handle) or (HasCheckBox(ACol,ARow))) and not CanShowSelection  then
      begin
        Canvas.Brush.Color := FOldBrushColor;
        Canvas.Font.Color := FOldFontColor;
        URLCol := FURLColor;
      end;
    end;

    TmpStr := GetFormattedCell(ACol,ARow);

    if (FSearchPanel.FHiliteButton.Down or FSearchFooter.AlwaysHighLight) and
       (FSearchPanel.EditControl.Text <> '') and
       (ARow >= FixedRows) and (ARow < RowCount - FFixedFooters) and
       ((FSearchFooter.SearchColumn = ACol) or
        ((FSearchFooter.SearchColumn = -1) and (ACol >= FixedCols) and (ACol < ColCount - FFixedRightCols + NumHiddenColumns))) then
    begin
      TmpStr := HiLight(TmpStr, FSearchPanel.EditControl.Text, 'hi', FSearchPanel.FMatchCase.Checked, FSearchFooter.HighLight = hFullCell);
    end;

    ctt := TextType(TmpStr,FEnableHTML);

    if ctt = ttFormula then
    begin
      TmpStr := CalcCell(ACol,ARow);
      ctt := TextType(TmpStr,FEnableHTML);
    end;

    GetMarker(ACol,ARow,ErrPos,ErrLen);

    if IsPassword(ACol,ARow) then
      StringToPassword(TmpStr,PasswordChar);

    DCRect := ARect;

    if IsFixed(OCol,ARow) then
    begin
      DCRect.Left := DCRect.Left + GridLineWidth;
      DCRect.Top := DCRect.Top + GridLineWidth;
    end;

    MR := DCRect;

    CLIPRGN := 0;

    if ScrollPos > 0 then
    begin
      CLIPRGN := CreateRectRgn(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
      SelectClipRgn(Canvas.Handle,CLIPRGN);
    end;

    DCRect.Top := DCRect.Top - ScrollPos;

    if CellHasFilter then
    begin
      gla := FilterDropDown.Glyph;
      if Filter.HasFilter(ACol) then
        gla := FilterDropDown.GlyphActive;

      if gla.Empty then
      begin
        FltrBmp := TBitmap.Create;
        FltrBmp.LoadFromResourceName(HInstance,'ASGFILT');
        DCRect.Left := DCRect.Right - 16;
        DrawBitmapTransp(Canvas, FltrBmp, FixedColor, DCRect);
        FltrBmp.Free;
        DCRect := MR;
      end
      else
      begin
        DCRect.Left := DCRect.Right - 16;
        gla.Transparent := true;
        gla.TransparentMode := tmAuto;
        Canvas.Draw(DCRect.Left, DCRect.Top, gla);
        DCRect := MR;
      end;
    end;

    if (ACol >= FixedCols) and (ARow >= FixedRows) and not FMouseDown then

      if ((FMouseActions.DisjunctRowSelect and not RowSelect[RRow]) or
         (FMouseActions.DisjunctColSelect and not ColSelect[OCol])) then
      begin
        URLCol := FURLColor;
        Canvas.Brush.Color := Color;
        Canvas.Font.Color := Font.Color;
        GetCellColor(ACol,ARow,AState,Canvas.Brush,Canvas.Font);
        Canvas.Font.Size := Canvas.Font.Size + ZoomFactor;
      end;

    // enhanced code to always draw background image
    if (FBackGround.Bitmap.Empty = False) and (Colors[ACol,ARow] = clNone) and
       (((FBackGround.Cells in [bcFixed,bcAll]) and (gdFixed in Astate)) or ((FBackGround.Cells in [bcNormal,bcAll]) and not (gdFixed in Astate)))
       and ((CanShowSelection = false) or not (gdSelected in AState)) then
       //and (((not ((gdSelected in Astate) and not (gdFocused in Astate))) and
       //not ((gdFocused in Astate) and (goDrawFocusSelected in Options))) or (FShowSelection = False)) then
    begin
      WRect := DCRect;
      WRect.Left := DCRect.Left + 1 - GridLineWidth;
      WRect.Top := DCRect.Top + 1 - GridLineWidth;

      if FBackground.Display = bdTile then
        DrawWallPaperTile(WRect)
      else
        DrawWallPaperFixed(WRect);
    end;

    if (FBackground.Display in [bdGradientVert, bdGradientHorz]) and ((Colors[ACol,ARow] = clNone) or (CellTypes[ACol,ARow] in [ctCheckBox,ctDataCheckBox,ctRadio,ctButton,ctRadioButton])) and
       (((FBackGround.Cells in [bcFixed,bcAll]) and (gdFixed in Astate)) or ((FBackGround.Cells in [bcNormal,bcAll]) and not (gdFixed in Astate)))
       and (((not ((gdSelected in Astate) {and (gdFocused in Astate)})) and
       not ((gdFocused in Astate) and (goDrawFocusSelected in Options))) or (CanShowSelection = False)) then
    begin
      WRect := DCRect;
      WRect.Left := DCRect.Left - 1;
      WRect.Top := DCRect.Top - 1 - (GridLineWidth - 1);
      WRect.Bottom := DCRect.Bottom + (GridLineWidth - 1);

      DrawGradientBackground(WRect);
    end;

    // do the selection rectangle painting here
    c := ACol;
    ACol := RemapColInv(ACol);

    if FSelectionRectangle and IsInGridRect(Selection,ACol,ARow) and not IsFixed(ACol,ARow) then
    begin
      Canvas.Pen.Color := FSelectionRectangleColor;
      if not (goHorzLine in Options) and not (goVertLine in Options) then
      begin
        Canvas.Pen.Width := 1;
        ld := 0;
      end
      else
      begin
        Canvas.Pen.Width := 2;
        ld := 1;
      end;

      with Canvas do
      begin
        gs := Selection;

        if IsMergedCell(ACol,ARow) then
        begin
          bc := BaseCell(Selection.Left,Selection.Top);
          gs := TGridRect(Rect(bc.X, bc.Y, bc.X, bc.Y));
        end;

        if gs.Left = ACol then
        begin
          MoveTo(DCRect.Left + ld - GridLineWidth, DCRect.Bottom);
          LineTo(DCRect.Left + ld - GridLineWidth, DCRect.Top - GridLineWidth );
        end;

        if gs.Right = ACol then
        begin
          MoveTo(DCRect.Right - 1, DCRect.Bottom);
          LineTo(DCRect.Right - 1, DCRect.Top - GridLineWidth );
        end;

        if gs.Top = ARow then
        begin
          if gs.Left = ACol then
            MoveTo(DCRect.Left - GridLineWidth ,DCRect.Top + ld - GridLineWidth )
          else
            MoveTo(DCRect.Left - 1 - GridLineWidth ,DCRect.Top + ld - GridLineWidth );

          if gs.Right = ACol then
            LineTo(DCRect.Right - 1, DCRect.Top + ld - GridLineWidth )
          else
            LineTo(DCRect.Right, DCRect.Top + ld - GridLineWidth )
        end;

        if gs.Bottom = ARow then
        begin
          if gs.Left = ACol then
            MoveTo(DCRect.Left - GridLineWidth ,DCRect.Bottom - 1 + ld)
          else
            MoveTo(DCRect.Left - 1 - GridLineWidth ,DCRect.Bottom - 1 + ld);

          if gs.Right = ACol then
            LineTo(DCRect.Right - 1,DCRect.Bottom - 1 + ld)
          else
            LineTo(DCRect.Right,DCRect.Bottom - 1 + ld);
        end;
      end;

      if SelectionResizer and
         (ARow = Selection.Bottom) and (ACol = Selection.Right) then
      begin
        CR := CellRect(Selection.Right,Selection.Bottom);
        CR.Top := DCRect.Bottom - Round(4 * FDPIScale);
        CR.Left := DCRect.Right - Round(4 * FDPIScale);
        CR.Right := CR.Left + Round(4 * FDPIScale);
        {
        if BidiMode = bdLeftToRight then
        begin
          CR.Left := Rect.Right - 4;
        end
        else
        begin
          CR.Right := Rect.Left + 4;
        end;
        }
        OldCol := Canvas.Brush.Color;
        Canvas.Brush.Color := SelectionRectangleColor;
        Canvas.Rectangle(CR.Left,CR.Top,CR.Right,CR.Bottom);
        Canvas.Brush.Color := OldCol;
      end;

      Canvas.Pen.Width := 1;
    end;

    ACol := c;

    if not DisplText then
    begin
      if (CLIPRGN <> 0) then
      begin
        SelectClipRgn(Canvas.Handle,0);
        DeleteObject(CLIPRGN);
      end;
      Exit;
    end;

    // drawing of text
    if not FXYOffsetTopLeftOnly then
        Dec(DCRect.Right,FXYOffset.X);
      Inc(DCRect.Left,FXYOffset.X);
      Inc(DCRect.Top,FXYOffset.Y);

    // determine text alignment

    AlignValue := HAlignment;

    tal := AlignValue;

    sortindent := 0;

    // centering text in cell
    FontHeight := Canvas.TextHeight('hg');

    // change here cell rectangle dependant of bitmap
    if (HAlignment = taLeftJustify) and (hal = haBeforeText) then
    begin
      DCRect.Left := DCRect.Left + GraphicWidth;
      sortindent := GraphicWidth;
    end;

    if (hal = haLeft) then
    begin
      sortindent := GraphicWidth;
    end;

    if (HAlignment in [taLeftJustify,taCenter]) and (hal = haAfterText) then
    begin
      DCRect.Right := DCRect.Right - GraphicWidth;
    end;

    if (HAlignment = taRightJustify) and (hal = haAfterText) then
    begin
      DCRect.Right := DCRect.Right - GraphicWidth;
    end;

    if (HAlignment in [taRightJustify,taCenter]) and (hal = haBeforeText) then
    begin
      DCRect.Left := DCRect.Left + GraphicWidth;
    end;

    if val = vaAboveText then
    begin
      DCRect.Top := DCRect.Top + GraphicHeight;
    end;

    if val = vaUnderText then
    begin
      DCRect.Bottom := DCRect.Bottom - GraphicHeight;
    end;

    if (ACol = 0) and (FNumNodes > 0) and not IsNode(ARow) then
    begin
      DCRect.Left := DCRect.Left + NodeIndent(ARow);
    end;

    fltrstr := '';

    if HasFilterEdit(ACol, ARow) then
    begin
      ft := Filter.HasFilterType(ACol);
      FFltrList.Draw(Canvas, DcRect.Left, DcRect.Top,integer(ft),true);
      DcRect.Left := DcRect.Left + 18;
      sortindent := sortindent + 18;
      if integer(ft) < FFilterEdit.TypeNames.Count then
        fltrstr := FFilterEdit.TypeNames.Strings[integer(ft)];
    end;

    if ctt = ttHTML then
    begin
      if CellHasFilter then
        DCRect.Right := DCRect.Right - 18;

      DCRect.Left := DCRect.Left - 1;

      if ShouldDrawSortIndicator(ACol,ARow) and
         ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and (FixedRows > 0) and
         ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      begin
        DCRect.Right := DCRect.Right - 10;
      end;

      if UseRightToLeftAlignment then
      begin
        DRect := DCRect;

        if not FNoRTLOrientation then
        begin
          DCRect.Left := ClientWidth - DCRect.Left;
          DCRect.Right := ClientWidth - DCRect.Right;
        end
        else
        begin
          DCRect.Left := DCRect.Left - XYOffset.X;
          DCRect.Right := DCRect.Right + XYOffset.X;
        end;

        Hold := DCRect.Left;
        DCRect.Left := DCRect.Right;
        DCRect.Right := Hold;
        ChangeGridOrientation(False);
      end;

      FImages := GetCellImageList(ACol,ARow);

      if (FHoverCell.X = ACol) and (FHoverCell.Y = ARow) then
        Hol := FHoverLink
      else
        Hol := -1;

      HTMLDrawEx(Canvas,TmpStr,DCRect,FImages,
               DCRect.Left,DCRect.Top,-1,Hol,1,False,False,False,False,FGridBlink,FURLUnderlineOnHover,not EnhTextSize,FCtrlDown,FCtrlDownID,
               0.0,URLCol,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
               XSize,YSize,ml,hl,hr,cr,CID,CT,CV,FImageCache,FContainer,Handle,BidiMode);

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
        DCRect := DRect;
      end;

      if ShouldDrawSortIndicator(ACol,ARow) and
         ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and (FixedRows > 0) and
         ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      begin
        case VAlign of
        vtaTop:vpos := DCRect.Top + 8;
        vtaCenter:vpos := Top +((DCRect.Bottom - DCRect.Top) shr 1);
        vtaBottom:vpos := DCRect.Bottom - 8;
        end;

        if not ((SortIndexes.FindIndex(ACol) > 0) and not FSortSettings.IndexShow) then
          DrawSortIndicator(Canvas,ACol,DCRect.Right + 2,vpos);
      end;

      //Solves the problem that DrawFocusRect only takes the Canvas Color of the last drawn Font!
      Canvas.TextOut(DCRect.Left,DCRect.Top,'');

      MaxTextWidth := XSize + 2;

      if CLIPRGN <> 0 then
      begin
        SelectClipRgn(Canvas.Handle,0);
        DeleteObject(CLIPRGN);
      end;

      Exit;
    end;

    if ctt = ttRTF then
    begin
      Canvas.Pen.Color := Canvas.Brush.Color;
      if not (gdSelected in aState) or (gdFocused in aState) or (FSelectionColor <> clNone) then
        Canvas.Rectangle(DCRect.Left,DCRect.Top,DCRect.Right,DCRect.Bottom);
      Canvas.Brush.Style := bsClear;

      if UseRightToLeftAlignment then
      begin
        DRect := DCRect;
        if not FNoRTLOrientation then
        begin
          DCRect.Left := ClientWidth - DCRect.Left;
          DCRect.Right := ClientWidth - DCRect.Right;
        end
        else
        begin
          DCRect.Left := DCRect.Left - XYOffset.X;
          DCRect.Right := DCRect.Right + XYOffset.X;
        end;

        Hold := DCRect.Left;
        DCRect.Left := DCRect.Right;
        DCRect.Right := Hold;
        ChangeGridOrientation(False);
      end;

      RTFPaint(ACol,ARow,Canvas,DCRect);
      Canvas.Brush.Style := bsSolid;
      Canvas.Font.Color := clWhite;
      Canvas.Font.Color := clBlack; // forces a canvas font reinitialize

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
        DCRect := DRect;
      end;

      if CLIPRGN <> 0 then
      begin
        SelectClipRgn(Canvas.Handle,0);
        DeleteObject(CLIPRGN);
      end;

      Exit;
    end;

    {$IFDEF TMSUNICODE}
    if ctt = ttUnicode then
    begin
      ws := DecodeWideStr(TmpStr);

      //ws := WideCells[ACol,ARow];
      TmpStr := ws;

      if ShouldDrawSortIndicator(ACol,ARow) and
         ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and (FixedRows > 0) and
         ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      begin
        DCRect.Right := DCRect.Right - 10;
        case VAlign of
        vtaTop:vpos := DCRect.Top + 8;
        vtaCenter:vpos := Top +((DCRect.Bottom - DCRect.Top) shr 1);
        vtaBottom:vpos := DCRect.Bottom - 8;
        end;

        if not ((SortIndexes.FindIndex(ACol)>0) and not FSortSettings.IndexShow) then
          DrawSortIndicator(Canvas,ACol,DCRect.Right + 3,vpos);
      end;

//      Canvas.Pen.Color := Canvas.Brush.Color;
//      if (not (gdSelected in aState) or (gdFocused in aState) or (FSelectionColor <> clNone)) and not IsFixed(ACol,ARow) then
//        Canvas.Rectangle(Rect.Left,Rect.Top,Rect.Right,Rect.Bottom);

      DrawStyle := VAlignments[VAlign] or Alignments[HAlignment];

      if UseRightToLeftAlignment then
      begin
        DRect := DCRect;
        if not FNoRTLOrientation then
        begin
          DCRect.Left := ClientWidth - DCRect.Left;
          DCRect.Right := ClientWidth - DCRect.Right;
        end
        else
        begin
          DCRect.Left := DCRect.Left - XYOffset.X;
          DCRect.Right := DCRect.Right + XYOffset.X;
        end;

        Hold := DCRect.Left;
        DCRect.Left := DCRect.Right;
        DCRect.Right := Hold;
        ChangeGridOrientation(False);
      end;

      if Win32Platform = VER_PLATFORM_WIN32_NT then
      begin
        Canvas.Brush.Style := bsClear;

        if CellWW or MultiLineCells then
          DrawTextExW(Canvas.Handle,PWidechar(ws),Length(ws),DCRect,DT_LEFT or DT_NOPREFIX or DT_WORDBREAK OR DT_END_ELLIPSIS or DrawStyle,nil)
        else
          DrawTextExW(Canvas.Handle,PWidechar(ws),Length(ws),DCRect,DT_LEFT or DT_NOPREFIX or DrawStyle or DT_SINGLELINE or DT_END_ELLIPSIS,nil);
      end
      else
      begin
        ExtTextOutW(Canvas.Handle,DCRect.Left,DCRect.Top,ETO_CLIPPED,@rect,PWideChar(ws),Length(ws),nil);
      end;

      if UseRightToLeftAlignment then
      begin
        ChangeGridOrientation(True);
        DCRect := DRect;
      end;

      if CLIPRGN <> 0 then
      begin
        SelectClipRgn(Canvas.Handle,0);
        DeleteObject(CLIPRGN);
      end;

      Exit;
    end;
    {$ENDIF}

    if (HAlignment = taCenter) and (ARow = FSortSettings.Row) and FSortSettings.Show and
       (ACol = FSortSettings.Column) then
    begin
      DCRect.Left := DCRect.Left + 10;
    end;

    {
    if (ARow = 0) and
       ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and
       FSortSettings.Show then
      SortWidth := 14
    else
      SortWidth := 0;
    }

    if URLShow then
      if IsURL(Cells[ACol,ARow]) then
      begin
        if not URLFull then
          StripURLProtoCol(TmpStr);
        Canvas.Font.Style := Canvas.Font.Style + [fsUnderline];
        Canvas.Font.Color := URLCol;
      end;

    DrawStyle := DT_EDITCONTROL;

    lit := LinesInText(TmpStr,FMultiLineCells);
    if lit = 1 then
    begin
      if not CellWW then
      begin
        TmpStr := GetNextLine(TmpStr,False);
        DrawStyle := DT_SINGLELINE;
        if FEnhTextSize then
          DrawStyle := DrawStyle or DT_END_ELLIPSIS;
      end;
    end;

    if CellWW and not MultiLineCells and FEnhTextSize then
      DrawStyle := DrawStyle or DT_END_ELLIPSIS;

    {$IFDEF CUSTOMIZED}
    if Pos('*',TmpStr) = 1 then Delete(TmpStr,1,1);
    {$ENDIF}

    FVALign := VAlignments[VAlign];

    DrawStyle := DrawStyle or DT_EXPANDTABS or DT_NOPREFIX or
      Alignments[HAlignment] or FVAlign;

    if CellWW {or MultiLineCells} then
      DrawStyle := DrawStyle or DT_WORDBREAK or DT_EDITCONTROL
    else
      DrawStyle := DrawStyle or DT_SINGLELINE;

    DrawStyle := DrawTextBiDiModeFlags(DrawStyle);

    SetBkMode(Canvas.Handle,TRANSPARENT);

    {
    case HAlignment of
    taLeftJustify:DCRect.Right := DCRect.Right - SortWidth;
    taRightJustify: DCRect.Left := DCRect.Left + SortWidth;
    //taCenter:
    end;
    }

    if CellHasFilter then
      DCRect.Right := DCRect.Right - 16;

    if UseRightToLeftAlignment then
    begin
      DRect := DCRect;
      if not FNoRTLOrientation then
      begin
        DCRect.Left := ClientWidth - DCRect.Left;
        DCRect.Right := ClientWidth - DCRect.Right;
      end
      else
      begin
        DCRect.Left := DCRect.Left - XYOffset.X;
        DCRect.Right := DCRect.Right + XYOffset.X;
      end;

      Hold := DCRect.Left;
      DCRect.Left := DCRect.Right;
      DCRect.Right := Hold;
      ChangeGridOrientation(False);
    end;

    if Assigned(cg) and (TmpStr <> '') then
    begin
      CR := DCRect;
      DrawTextEx(Canvas.Handle,PChar(TmpStr),Length(TmpStr), CR, DrawStyle OR DT_CALCRECT, nil);
      MaxTextWidth := CR.Right - DCRect.Left + 2;
    end;


    if MultiLineCells and (lit > 1) then
    begin
      ct := TmpStr;
      CR := DCRect;
      th := DrawTextEx(Canvas.Handle,PChar('gh'),2, CR, DT_SINGLELINE or DT_CALCRECT or DT_TOP, nil);

      case VAlign of
      vtaCenter: dcRect.Top := dcRect.Top + ((dcRect.Bottom - dcRect.Top) - (th * lit)) div 2;
      vtaBottom: dcRect.Top := dcrect.Bottom - (th * lit);
      end;

      DrawStyle := DrawStyle AND NOT DT_VCENTER;
      DrawStyle := DrawStyle AND NOT DT_BOTTOM;
      DrawStyle := DrawStyle OR DT_TOP;

      while (ct <> '') do
      begin
        cv := GetNextLine(ct, true);
        dcrect.Top := dcrect.Top + DrawTextEx(Canvas.Handle,PChar(cv),Length(cv), DCRect, DrawStyle, nil) ;
      end;
    end
    else
    begin
      if (TmpStr = '') and (fltrstr <> '') then
      begin
        Canvas.Font.Style := [fsItalic];
        Canvas.Font.Color := clGray;
        TmpStr := fltrstr;
      end
      else
        if (fltrstr <> '') then
          Canvas.Font.Style := [];

      dtsz := Length(TmpStr);
      if DrawStyle and DT_SINGLELINE = DT_SINGLELINE then
        dtsz := Min(4096,dtsz);

      DrawTextEx(Canvas.Handle,PChar(TmpStr),dtsz, DCRect, DrawStyle, nil);
    end;

    if UseRightToLeftAlignment then
    begin
      ChangeGridOrientation(True);
      DCRect := DRect;
    end;

    if (ErrLen > 0) and Assigned(cg) and (cg.CellType in [ctEmpty, ctValue]) then
    begin
      DrawErrorLines(Self,Canvas, TmpStr, DCRect, FontHeight, ErrPos, ErrLen);
    end;

    MaxTextHeight := FontHeight;
    DCRect := ARect;

    if CellHasFilter then
      DCRect.Right := DCRect.Right - 16;

    if ShouldDrawSortIndicator(ACol,ARow) and
       ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and
       (FixedRows > 0) and ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      begin
        SortWidth := Min(DCRect.Right - DCRect.Left - 16,Canvas.TextWidth(TmpStr));

        if SortWidth < 0 then
          SortWidth := 0;

        case AlignValue of
        taLeftJustify:DCRect.Left := DCRect.Left + SortWidth + 10 + sortindent;
        taRightJustify:DCRect.Left := DCRect.Right - SortWidth - 10;
        taCenter: DCRect.Left := DCRect.Left + 8;
        end;

        case VAlign of
        vtaTop:vpos := DCRect.Top + 8;
        vtaCenter:vpos := DCRect.Top + ((DCRect.Bottom - DCRect.Top) shr 1);
        vtaBottom:vpos := DCRect.Bottom - 8;
        end;

        if not ((SortIndexes.FindIndex(ACol) > 0) and not FSortSettings.IndexShow) then
          DrawSortIndicator(Canvas,ACol,DCRect.Left,vpos);
      end;

      if URLShow then
        Canvas.Font.Style := Canvas.Font.Style - [fsUnderline];

      if CLIPRGN <> 0 then
      begin
        SelectClipRgn(Canvas.Handle,0);
        DeleteObject(CLIPRGN);
      end;
  end;

begin
  MaxTextWidth := 0;
  MaxTextHeight := 0;

  Ctl3d := not FFlat;

  OCol := ACol;

  // calculate real Col based on hidden Cols
  ACol := RemapCol(ACol);
  tal := taLeftJustify;

  if MouseActions.DisjunctRowSelect and MouseActions.RowSelectPersistent then
    RRow := RemapRowInv(ARow)
  else
    RRow := ARow;

  CellHasFilter := false;

  if (ARow = FilterDropDownRow) then
  begin
    CellHasFilter := GetFilter(ACol,true);
  end;

  ScrollPos := 0;

  if HasScrollBar(ACol,ARow) then
  begin
    FPaintScrollBar.Position := GetScrollPosition(ACol,ARow);
    sp := GetScrollProp(ACol,ARow);

    if sp.PageSize < sp.Range then
    begin
      FPaintScrollBar.PageSize := sp.PageSize;
      FPaintScrollBar.Min := 0;
      FPaintScrollBar.Max := sp.Range;

      ScrollPos := FPaintScrollBar.Position;
      FPaintScrollBar.Height := ARect.Bottom - ARect.Top;
      ARect.Right := ARect.Right - FPaintScrollBar.Width;
      FPaintScrollBar.PaintTo(Canvas.Handle, ARect.Right, ARect.Top);
    end;
  end;

  CellWW := WordWrap;

  GetVisualProperties(OCol,ARow,AState,False,False,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlignment,VAlign,CellWW,GD);

  tal := HAlignment;

  (*
  AState := CustomCellProps.AState;
  Canvas.Brush.Assign(CustomCellProps.ABrush);
  AColorTo := CustomCellProps.AColorTo;
  AMirrorColor := CustomCellProps.AMirrorColor;
  AMirrorColorTo := CustomCellProps.AMirrorColorTo;
  Canvas.Font.Assign(CustomCellProps.AFont);
  HAlignment := CustomCellProps.HA;
  VAlign := CustomCellProps.VA;
  CellWW := CustomCellProps.WW;
  *)

  cg := GetGraphicDetails(ACol,ARow,GraphicWidth,GraphicHeight,DisplText,hal,val);

  if (ACol = 0) and (IsNode(ARow)) then
    GraphicWidth := 4 + GetNodeLevel(ARow) * 12;

  if (gdSelected in Astate) and not (gdFocused in Astate) then
  begin
    if FSelectionColor = clNone then
      Canvas.Brush.Color := clHighLight
  end;

  if Canvas.Font.Size + FZoomFactor <> 0 then
    Canvas.Font.Size := Canvas.Font.Size + FZoomFactor
  else
    Canvas.Font.Size := 1;

  FOldBrushColor := Canvas.Brush.Color;
  FOldFontColor := Canvas.Font.Color;

  CellIsFixed := (IsFixed(OCol,ARow) or (OCol < FixedCols) or (ARow < FixedRows));

  if (ARow = FHoverRowIdx) and (hcFixed in HoverRowCells) then
    CellIsFixed := false;

  FDidVCLStyles := false;

  {$IFDEF DELPHIXE2_LVL}
  LStyle := StyleServices;

  cp := nil;

  if HasCellProperties(ACol,ARow) then
  begin
    cp := CellProperties[ACol,ARow];
    if cp.BrushColor = clNone then
      cp := nil;
  end;

  cellc := Assigned(cp) and not (gdSelected in AState);

  {$IFDEF DELPHIXE6_LVL}
  if not (seClient in StyleElements) then
    cellc := not CellIsFixed;
  {$ENDIF}

  if LStyle.Enabled and (LStyle.Name <> 'Windows') and not cellc and (CellIsFixed or ((gdSelected in AState) and CanShowSelection)) then
  begin
    FDidVCLStyles := true;

    if CellIsFixed then
    begin
      ARect.Bottom := ARect.Bottom + 2;
      ARect.Right := ARect.Right + 1;
    end
    else
    begin
      //InflateRect(ARect,1,1);
      ARect.Top := ARect.Top - 1;
      ARect.Left := ARect.Left - 1;
    end;

    if CellIsFixed then
      LDetails := LStyle.GetElementDetails(tgFixedCellNormal)
    else
      if (gdSelected in Astate) then
        LDetails := LStyle.GetElementDetails(tgCellSelected);

    SaveIndex := SaveDC(Canvas.Handle);
    try
      LStyle.DrawElement(Canvas.Handle, LDetails, ARect, ARect);
    finally
      RestoreDC(Canvas.Handle, SaveIndex);
    end;

    Canvas.Brush.Style := bsClear;

    if CellIsFixed then
    begin
      ARect.Bottom := ARect.Bottom - 2;
      ARect.Right := ARect.Right - 1;
    end
    else
    begin
      ARect.Top := ARect.Top + 1;
      ARect.Left := ARect.Left + 1;
    end;
  end;

  if LStyle.Enabled and (LStyle.Name <> 'Windows') and (gdSelected in AState) and not CanShowSelection then
  begin
    Canvas.Pen.Color := Canvas.Brush.Color;
    Canvas.Pen.Style := psSolid;
    Canvas.Brush.Style := bsSolid;
    ARect.Left := ARect.Left - 1;
    ARect.Top := ARect.Top - 1;
    if not (goVertLine in Options) then
      ARect.Right := ARect.Right + 1;
    if  not (goHorzLine in Options) then
      ARect.Bottom := ARect.Bottom + 1;

    Canvas.Rectangle(ARect);
    ARect.Left := ARect.Left + 1;
    ARect.Top := ARect.Top + 1;
    Canvas.Brush.Style := bsClear;
  end;
  {$ENDIF}

  // paint fixed cell background
  if CellIsFixed and not FDidVCLStyles and ((Flook in [glTMS,glXP,glVista,glWin7,glOffice2007]) {and not Flat}) then
  begin
    if HoverFixedCell(OCol,ARow) and ((OCol = FHoverFixedX) and (FGridState <> gsColMoving) and (ARow = FHoverFixedY) or
       ((FGridState = gsColMoving) and (MoveCell = OCol))) and not (csDesigning in ComponentState) then
    begin
      ARect.Bottom := ARect.Bottom + 1;

      if FMouseDownMove or ((FGridState = gsColMoving) and (MoveCell >= 0)) then
      begin
        if ControlLook.FixedDropDownButton and CanShowFixedDropDown(ACol) then
        begin
          if FDropDownDown then
          begin
            DrawVistaGradient(Canvas, Rect(ARect.Right - 16,ARect.Top, ARect.Right, ARect.Bottom), FTMSGradDownFrom, FTMSGradDownTo, FTMSGradDownMirrorFrom, FTMSGradDownMirrorTo, True, FTMSGradDownBorder, false);
            DrawVistaGradient(Canvas, Rect(ARect.Left,ARect.Top, ARect.Right - 16, ARect.Bottom), FTMSGradHoverFrom, FTMSGradHoverTo, FTMSGradHoverMirrorFrom, FTMSGradHoverMirrorTo, True, FTMSGradHoverBorder, false);
          end
          else
          begin
            DrawVistaGradient(Canvas, Rect(ARect.Left,ARect.Top, ARect.Right - 16, ARect.Bottom), FTMSGradDownFrom, FTMSGradDownTo, FTMSGradDownMirrorFrom, FTMSGradDownMirrorTo, True, FTMSGradDownBorder, false);
            DrawVistaGradient(Canvas, Rect(ARect.Right - 16,ARect.Top, ARect.Right, ARect.Bottom), FTMSGradHoverFrom, FTMSGradHoverTo, FTMSGradHoverMirrorFrom, FTMSGradHoverMirrorTo, True, FTMSGradHoverBorder, false);
          end;
        end
        else
          DrawVistaGradient(Canvas, ARect, FTMSGradDownFrom, FTMSGradDownTo, FTMSGradDownMirrorFrom, FTMSGradDownMirrorTo, True, FTMSGradDownBorder, false)
      end
      else
      begin
        DrawVistaGradient(Canvas, ARect, FTMSGradHoverFrom, FTMSGradHoverTo, FTMSGradHoverMirrorFrom, FTMSGradHoverMirrorTo, True, FTMSGradHoverBorder, false);
      end;

      if ControlLook.FixedDropDownButton and CanShowFixedDropDown(ACol) then
      begin
        if FMouseDownMove then
          Canvas.Pen.Color := FTMSGradDownBorder
        else
          Canvas.Pen.Color := FTMSGradHoverBorder;

        Canvas.MoveTo(ARect.Right -16, ARect.Top);
        Canvas.LineTo(ARect.Right -16, ARect.Bottom);

        DrawTriangle(Canvas, ARect.Right - 8, ARect.Top + 8, clBlack);

        ARect.Right := ARect.Right - 16;
      end;
    end
    else
    begin
      if FActiveCellShow and
        (((Row = ARow) and (OCol = FixedCols - 1) and (FixedCols > 0)) or
        ((Col = OCol) and (ARow = FixedRows - 1) and (FixedRows > 0))) then
        DrawVistaGradient(Canvas, ARect, ActiveCellColor,ActiveCellColorTo,clNone, clNone, True, clNone)
      else
      begin
        if Look = glVista then
          brdrColor := clWhite
        else
          brdrColor := clNone;

        if (SortSettings.Column <> -1) and (SortSettings.HeaderColor <> clNone) and (ACol = SortSettings.Column) and (ARow = FixedRows - 1) and
           ((OCol + 1 > FixedCols) or FSortSettings.FixedCols) then
          DrawVistaGradient(Canvas, ARect, SortSettings.HeaderColor, SortSettings.HeaderColorTo, SortSettings.HeaderMirrorColor, SortSettings.HeaderMirrorColorTo, True, clNone, true)
        else
        begin
          if not Flat then
            DrawVistaGradient(Canvas, ARect, Canvas.Brush.Color, AColorTo, AMirrorColor, AMirrorColorTo, True, brdrColor, true);
        end;
      end;
    end;
  end;

  // text draw with alignment
  if (ACol = 0) and (ARow = Row) and (FixedCols > 0) and Assigned(FRowIndicator) and not ((RowCount = FixedRows) and FixedRowAlways) then
  begin
    if not FRowIndicator.Empty then
    begin
      RowIndicator.TransparentMode := tmAuto;
      RowIndicator.Transparent := true;
      case VAlignment of
      vtaTop: Canvas.Draw(ARect.Left + 2, ARect.Top, RowIndicator);
      vtaCenter: Canvas.Draw(ARect.Left + 2, ARect.Top + (ARect.Bottom - ARect.Top - RowIndicator.Height) div 2, RowIndicator);
      vtaBottom: Canvas.Draw(ARect.Left + 2, ARect.Bottom - RowIndicator.Height, RowIndicator);
      end;
      ARect.Left := ARect.Left + FRowIndicator.Width + 2;
    end;
  end;

  if CellIsFixed and not FDidVCLStyles and ((Flook in [glListView]) and not Flat) then
  begin
    if FIsWinXP then
    begin
      ARect.Bottom := ARect.Bottom + 1;
      GetCursorPos(pt);
      pt := ScreenToClient(pt);

      HTheme := OpenThemeData(Self.Handle,'header');

      if PtInRect(ARect,pt) then
      begin
        if FMouseDownMove then
          DrawThemeBackground(HTheme, Canvas.Handle, HP_HEADERITEM, HIS_PRESSED,@ARect,nil)
        else
          DrawThemeBackground(HTheme, Canvas.Handle, HP_HEADERITEM, HIS_HOT,@ARect,nil)
      end
      else
        DrawThemeBackground(HTheme, Canvas.Handle, HP_HEADERITEMRIGHT, HIS_NORMAL,@ARect,nil);

      CloseThemeData(HTheme);

      Canvas.Pen.Color := clWhite;
      Canvas.MoveTo(ARect.Left,ARect.Top);
      Canvas.LineTo(ARect.Right,ARect.Top);
    end
    else
    begin
      Canvas.Brush.Color := clBtnFace;
      Canvas.Pen.Color := clWhite;
      Canvas.Rectangle(ARect.Left,ARect.Top,ARect.Right,ARect.Bottom);
    end;
  end;

  if (OCol = 0) and ShowModified.Enabled and RowModified[RealRowIndex(ARow)] then
  begin
    Canvas.Brush.Color := ShowModified.Color;
    Canvas.Pen.Color := ShowModified.Color;
    Canvas.Rectangle(ARect.Right - 4,ARect.Top, ARect.Right, ARect.Bottom);
  end;

  if Assigned(OnCustomCellBkgDraw) then
  begin
    OnCustomCellBkgDraw(Self,Canvas,ACol,ARow,AState,ARect,False);
  end;

  OrigRight := ARect.Right;

  if not IsFixed(OCol,ARow) and (ControlLook.DropDownAlwaysVisible or ControlLook.SpinButtonsAlwaysVisible) then
  begin
    if ControlLook.FlatButton then
      CtrlStyle := cdsFlat
    else
    begin
      if not FIsWinXP then
        CtrlStyle := cdsClassic
      else
        CtrlStyle := cdsXPTheme;
    end;

    if Flat and (FTones.Background.BrushColor <> clNone) then
      CtrlStyle := cdsMetro;

    RCol := RealColIndex(OCol);

    Editable := true;
    GetCellReadOnly(RCol,ARow,Editable);

    if Editable then
      CtrlState := csNormal
    else
      CtrlState := csDisabled;

    AEditor := edNone;

    if ControlLook.DropDownAlwaysVisible or ControlLook.SpinButtonsAlwaysVisible then
    begin
      AEditor := DefaultEditor;
      GetCellEditor(RCol, ARow, AEditor);
    end;

    if ControlLook.DropDownAlwaysVisible then
    begin
      if HasCombo(RCol,ARow,AEditor) then
      begin
        DrawComboButton(Canvas, Handle, Rect(ARect.Left - 2, ARect.Top - 1 , ARect.Right + 1, ARect.Bottom), CtrlStyle, CtrlState, FTones, FDPIScale);
        ARect.Right := ARect.Right - Round(ControlLook.DropDownButtonWidth * FDPIScale);
      end;

      if HasEditBtn(RCol,ARow,AEditor) then
      begin
        if Assigned(BtnEdit) then
          btncap := BtnEdit.Button.ButtonCaption
        else
          btncap := '...';

        DrawButton(Canvas, Handle, Rect(ARect.Right - ControlLook.DropDownButtonWidth - 3, ARect.Top - 2 , ARect.Right - 1, ARect.Bottom - 1), CtrlStyle, CtrlState, FTones, ControlLook.ButtonPrefix, btncap);
        ARect.Right := ARect.Right - ControlLook.DropDownButtonWidth;
      end;
    end;

    if ControlLook.SpinButtonsAlwaysVisible then
    begin
      if HasSpinEdit(RCol,ARow,AEditor) then
      begin
        DrawSpinButtons(Canvas, Handle, ARect, CtrlStyle, CtrlState, FTones);
        ARect.Right := ARect.Right - 16;
      end;
    end;
  end;

  if Assigned(cg) then
  begin
    if cg.CellType = ctInterface then
    begin
      io := TInterfacedPersistent(cg.CellBitmap);
      if io.GetInterface(ICellGraphic, icg) then
      begin
        if icg.IsBackground then
        begin
          InflateRect(ARect,1,1);
          DrawCellGraphic(ARect, cg, VAlign);
          InflateRect(ARect,-1,-1);
        end;
      end;
    end;
    if not NoImageAndText then
      if not ((Assigned(OnDrawCell) or Assigned(OnCustomCellDraw)) and NoDefaultDraw) then
        DrawCellText;
  end
  else
  begin
    if not ((Assigned(OnDrawCell) or Assigned(OnCustomCellDraw)) and NoDefaultDraw) then
      DrawCellText;
  end;

  ARect.Right := OrigRight;

  {$IFDEF FREEWARE}
  if (ARow = RowCount - 1) then
  begin
    BRect := GetCellRect(FixedCols,ARow);
    Anchor := ClassName  + trialversion + GetVersionString;
    Canvas.Font.Color := clNavy;
    Canvas.TextOut(BRect.Left + 4,BRect.Top,Anchor);
  end;
  {$ENDIF}

  Canvas.Brush.Color := FOldBrushColor;
  Canvas.Font.Color := FOldFontColor;

  InflateRect(ARect,1,1);

  DrawBorders(ACol,ARow,ARect);

  if (OCol = 0) and (ARow = Row) and (FixedCols > 0) and Assigned(FRowIndicator) then
  begin
    ARect.Left := ARect.Left - FRowIndicator.Width;
  end;

  fe := not HasFilterEdit(ACol,ARow);

  if CellIsFixed and fe and ((Flook = glClassic) and not Flat) then
  begin
    ARect.Top := ARect.Top + 1;
    ARect.Bottom := ARect.Bottom + 1;
    ARect.Left := ARect.Left + 1;

    DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_LEFT);
    DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOP);
    DrawEdge(Canvas.Handle, ARect, EDGE_RAISED, BF_BOTTOM or BF_RIGHT);

    Canvas.Pen.Color := clBlack;
    Canvas.MoveTo(ARect.Right - 1,ARect.Top);
    Canvas.LineTo(ARect.Right - 1,ARect.Bottom - 1);
    Canvas.LineTo(ARect.Left - 1,ARect.Bottom - 1);
  end;

  if CellIsFixed and fe and ((Flook in [glTMS,glXP]) and not Flat) then
  begin
    ARect.Bottom := ARect.Bottom + 1;

    if (goFixedHorzLine in Options) then
    begin
      Canvas.Pen.Color := DarkenColor(FixedColor);
      Canvas.MoveTo(ARect.Left,ARect.Bottom - 1);
      Canvas.LineTo(ARect.Right - 1,ARect.Bottom - 1);
      Canvas.Pen.Color := clWhite;
      Canvas.MoveTo(ARect.Right - 2,ARect.Top + 1);
      Canvas.LineTo(ARect.Left + 1,ARect.Top + 1);
      Canvas.LineTo(ARect.Left + 1,ARect.Bottom - 1);
    end;
  end;

  if CellIsFixed and fe and ((FLook = glSoft) and not Flat) then
  begin
    if Ctl3D then
    begin
      ARect.Right := ARect.Right + 1;
      ARect.Bottom := ARect.Bottom + 1;

      if (goFixedHorzLine in Options) then
      begin
        Canvas.Pen.Color := DarkenColor(FixedColor);
        Canvas.MoveTo(ARect.Left,ARect.Bottom - 1);
        Canvas.LineTo(ARect.Right - 1,ARect.Bottom - 1);
        Canvas.Pen.Color := clWhite;
        Canvas.MoveTo(ARect.Right,ARect.Top + 1);
        Canvas.LineTo(ARect.Left + 1,ARect.Top + 1);
        Canvas.LineTo(ARect.Left + 1,ARect.Bottom - 1);
      end;

      if (goFixedVertLine in Options) then
      begin
        Canvas.Pen.Color := DarkenColor(FixedColor);
        Canvas.MoveTo(ARect.Right - 2,ARect.Top);
        Canvas.LineTo(ARect.Right - 2,ARect.Bottom - 1);
        Canvas.Pen.Color := clWhite;
        Canvas.MoveTo(ARect.Right - 1,ARect.Top);
        Canvas.LineTo(ARect.Right - 1,ARect.Bottom - 1);
      end;
    end
    else
    begin
      Canvas.Pen.Color := clBlack;
      Canvas.Pen.Width := 1;
      if (goFixedHorzLine in Options) then
      begin
        Canvas.MoveTo(ARect.Left - 1,ARect.Top - 1);
        Canvas.LineTo(ARect.Right + 1,ARect.Top - 1);
        Canvas.MoveTo(ARect.Left - 1,ARect.Bottom + 1);
        Canvas.LineTo(ARect.Right + 1,ARect.Bottom + 1);
      end;

      if (goFixedVertLine in Options) then
      begin
        Canvas.MoveTo(ARect.Left - 1,ARect.Top - 1);
        Canvas.LineTo(ARect.Left - 1,ARect.Bottom + 1);
        Canvas.MoveTo(ARect.Right + 1,ARect.Top - 1);
        Canvas.LineTo(ARect.Right + 1,ARect.Bottom + 1);
      end;
    end;
  end;

  if (FFixedRightCols > 0) and (ColCount - ACol + FNumHidden <= FFixedRightCols)
     and (Look <> glClassic) then
  begin
    if Ctl3D then
    begin
     // DrawEdge(Canvas.Handle, aRect, BDR_RAISEDINNER, FrameFlags1);
     // DrawEdge(Canvas.Handle, aRect, BDR_RAISEDINNER, FrameFlags2);
    end
    else
    begin
      if Flat then
        Canvas.Pen.Color := clGray
      else
        Canvas.Pen.Color := clBlack;

      Canvas.Pen.Width := 1;

      if goFixedHorzLine in Options then
      begin
        Canvas.MoveTo(ARect.Left - 1,ARect.Top - 1);
        Canvas.LineTo(ARect.Right + 1,ARect.Top - 1);
        Canvas.MoveTo(ARect.Left - 1,ARect.Bottom + 1);
        Canvas.LineTo(ARect.Right + 1,ARect.Bottom + 1);
      end;

      if goFixedVertLine in Options then
      begin
        Canvas.MoveTo(ARect.Left -1,ARect.Top - 1);
        Canvas.LineTo(ARect.Left -1,ARect.Bottom + 1);
        Canvas.MoveTo(ARect.Right + 1,ARect.Top - 1);
        Canvas.LineTo(ARect.Right + 1,ARect.Bottom + 1);
      end;
    end;
  end;

  if (FNumNodes > 0) and (ACol = 0) and (ARow >= FixedRows) and (FCellNode.ShowTree) then
  begin
    Canvas.Pen.Color := FCellNode.TreeColor;
    Canvas.Pen.Width := 1;

    lvl := CellProperties[0,ARow].NodeLevel;

    ARect.Left := NodeIndent(ARow);

    ci := ARect.Left - CellNode.NodeIndent + 2 + CellNode.NodeIndent div 2;

    if (lvl > 0) then
    begin
      // horizontal node line
      Canvas.MoveTo(ci,ARect.Top + (ARect.Bottom - ARect.Top) shr 1);

      if FCellNode.ShowTreeFull then
        Canvas.LineTo(ARect.Right,ARect.Top + (ARect.Bottom - ARect.Top) shr 1)
      else
        Canvas.LineTo(ARect.Left + 4,ARect.Top + (ARect.Bottom - ARect.Top) shr 1);
    end;

    case GetNodeSpanType(ARow) of
    1:begin
        Canvas.MoveTo(ci,ARect.Top);
        Canvas.LineTo(ci,ARect.Top + (ARect.Bottom - ARect.Top) shr 1);
      end;
    2:begin
        Canvas.MoveTo(ci, ARect.Top );
        Canvas.LineTo(ci, ARect.Bottom + 4);
      end;
    end;

    if HasCellProperties(0,ARow) then
    begin
      // draw straight interconnecting lines
      for vpos := 1 to CellProperties[0,ARow].NodeLevel do
      begin
        // draw line till middle of cell
        Canvas.MoveTo(ci - CellNode.NodeIndent * vpos, ARect.Top );
        Canvas.LineTo(ci - CellNode.NodeIndent * vpos, ARect.Top + (ARect.Bottom - ARect.Top) shr 1);

        if (ARow < RowCount - 1) then
        begin
          if (CellProperties[0, ARow + 1].NodeLevel < CellProperties[0, ARow].NodeLevel - vpos) then
          begin
            if (vpos < CellProperties[0, ARow].NodeLevel) then
              Canvas.LineTo(ci - CellNode.NodeIndent * vpos + CellNode.NodeIndent, ARect.Top + (ARect.Bottom - ARect.Top) shr 1)
          end
          else
            // draw till bottom
            Canvas.LineTo(ci  - CellNode.NodeIndent * vpos, ARect.Bottom + 4);
        end
        else
        begin
          if (vpos < CellProperties[0,ARow].NodeLevel) then
            Canvas.LineTo(ci - CellNode.NodeIndent * vpos + CellNode.NodeIndent, ARect.Top + (ARect.Bottom - ARect.Top) shr 1);

//          Canvas.LineTo(ci  - CellNode.NodeIndent * vpos, ARect.Bottom + 4);
        end;
      end;
    end;

    Canvas.Pen.Style := psSolid;
  end;

  if Assigned(cg) then
  begin
    if cg.CellType = ctInterface then
    begin
      io := TInterfacedPersistent(cg.CellBitmap);
	  if io.GetInterface(ICellGraphic, icg) then
      begin
        if not icg.IsBackground then
         DrawCellGraphic(ARect, cg, VAlign);
      end;
    end
    else
    begin
      BRect := ARect;
      if CellIsFixed then
        BRect.Top := BRect.Top + 1;

      DrawCellGraphic(BRect,cg, VAlign);

      ARect := BRect;
    end;
  end;

  if Assigned(OnDrawCell) then
  begin
    BRect := ARect;
    ARect.Top := ARect.Top {+ 1};
    ARect.Left := ARect.Left {+ 1};
    ARect.Bottom := ARect.Bottom - GridLineWidth;
    ARect.Right := ARect.Right - GridLineWidth;
    OnDrawCell(Self,ACol,ARow,ARect,AState);
    ARect := BRect;
  end;

  if Assigned(OnCustomCellDraw) then
  begin
    OnCustomCellDraw(Self,Canvas,ACol,ARow,AState,ARect,False);
  end;

  if not FHideFocusRect then
//    if (gdFocused in AState) then
    if (BaseCell(OCol,ARow).X = Col) and (BaseCell(OCol,ARow).Y = Row) and (GetFocus = Handle)
        {and (goDrawFocusSelected in Options)} then
    begin
      if not (goRowSelect in Options) and (Row >= FixedRows) and (Col >= FixedCols) then
      begin
        InflateRect(ARect,GridLineWidth - 1,GridLineWidth - 1);
        ARect.Right := ARect.Right - 1;
        ARect.Bottom := ARect.Bottom - 1;
        Canvas.DrawFocusRect(ARect);
      end;
    end;

  if (csDesigning in ComponentState) and FShowColNrs then
  begin
    Canvas.Brush.Style := bsClear;
    if (ARow = 0) then
    begin
      Canvas.Font.Name := '';
      Canvas.Font.Size := 8;
      Canvas.Font.Style := [];
      Canvas.Font.Color := clGray;
      Stripped := IntToStr(ACol);
      ARect.Right := ARect.Right - 2;
      DrawText(Canvas.Handle, PChar(Stripped) , Length(Stripped), ARect, DT_RIGHT or DT_SINGLELINE or DT_BOTTOM);
    end;
  end;
end;


function TAdvStringGrid.Search(s:string): Integer;
var
  i: Integer;
  c: string;
  res,sCol: Integer;

begin
  Search := -1;

  if RowCount < 2 then
    Exit;

  Res := -1;

  if FSortSettings.Show then
  begin
    if not FSortSettings.IndexShow then
    begin
      sCol := FSortSettings.Column
    end
    else
    begin
      if SortIndexes.Count > 0 then
        sCol := SortIndexes.SortColumns[0]
      else
        sCol := FixedCols;
    end;
  end
  else
    sCol := FixedCols;

  if sCol = -1 then
    Exit;

  for i := FixedRows to RowCount - 1 do
  begin
    c := StrippedCells[sCol,i];
    c := AnsiUpperCase(Copy(c,1,Length(s)));
    if s = c then
    begin
      Res := i;
      Break;
    end;
  end;

  Search := Res;
end;

function TAdvStringGrid.MatchCell(Col,Row: Integer; IsWide: Boolean): Boolean;
var
  res1,res2: Boolean;
  ct,cs: string;
  ctw: widestring;
  ic: Integer;
begin
  res2 := True;
  if not (fnIncludeHiddenColumns in FFindParams) then
    Col := RemapCol(Col);

  if IsWide then
  begin
    if not (fnMatchCase in FFindParams) then
      ctw := WideUpperCase(WideCells[Col,Row])
    else
      ctw := WideCells[Col,Row];
  end
  else
  begin
    if fnIncludeHiddenRows in FFindParams then
      cs := AllCells[Col,Row]
    else
      cs := Cells[Col,Row];

    if not (fnMatchCase in FFindParams) then
      ct := AnsiUpperCase(cs)
    else
      ct:= cs;
  end;

  if fnIgnoreHTMLTags in FFindParams then
    ct := HTMLStrip(ct);

  if SearchCache = '""' then
  begin
    MatchCell := ct = '';
    Exit;
  end;

  if SearchCacheWide = '""' then
  begin
    MatchCell := ctw = '';
    Exit;
  end;

  if IsWide then
    ic := StrPosWide(SearchCacheWide,ctw)
  else
    ic := Pos(SearchCache,ct);

  if fnMatchStart in FFindParams then
    res1 := ic = 1
  else
    res1 := ic > 0;

  if IsWide then
  begin
    if fnMatchFull in FFindParams then
      res2 := SearchCacheWide = ctw;
  end
  else
  begin
    if fnMatchFull in FFindParams then
      res2 := SearchCache = ct;
  end;

  if fnMatchRegular in FFindParams then
  begin
    MatchCell := MatchStrEx(SearchCache,ct,(fnMatchCase in FFindParams));
  end
  else
    MatchCell := res1 and res2;
end;

function TAdvStringGrid.Replace(OrigStr,NewStr: string; FindParams: TFindParams): integer;
var
  FirstSearch: boolean;
  FGridCell: TPoint;
  OldValue,NewValue: string;
  NumRepl: Integer;
begin

  FirstSearch := true;
  FGridCell := Point(-1,-1);
  NumRepl := 0;

  while FirstSearch or ((FGridCell.X <> -1) and (FGridCell.Y <> -1)) do
  begin
    FGridCell := Find(FGridCell,OrigStr,FindParams);

    if (FGridCell.X <> -1) and (FGridCell.Y <> -1) then
    begin
      OldValue := Cells[FGridCell.X,FGridCell.Y];
      NewValue := StringReplace(OldValue,OrigStr,NewStr,[rfReplaceAll,rfIgnoreCase]);
      Cells[FGridCell.X,FGridCell.Y] := NewValue;
      if ShowModified.Enabled then
        RowModified[FGridCell.Y] := true;

      Inc(NumRepl);
    end;

    FirstSearch := False;
  end;

  Result := NumRepl;
end;

function TAdvStringGrid.Find(StartCell:TPoint; s:string; FindParams: TFindParams): TPoint;
var
  ff: integer;
begin
  if (StartCell.X = -1) and (StartCell.Y = -1) then
    ExportNotification(esExportStart, -1);

  BeginUpdate;
  Result := FindInternal(StartCell,s,'',False,FindParams);
  EndUpdate;

  // make cell visible
  if (fnAutoGoto in FindParams) then
  begin
    if MouseActions.DisjunctCellSelect then
    begin
      SelectCells(Col,Row,Col,Row);
    end;

    ff := 0;
    if (FloatingFooter.Visible) then
      ff := 2;
    if (Row > TopRow + VisibleRowCount - 2 - ff) and (VisibleRowCount + FixedRows + ff < RowCount) then
      TopRow := TopRow + 1 + ff;
  end;

  if (Result.X = -1) and (Result.Y = -1) then
    ExportNotification(esExportDone, -1)
  else
    ExportNotification(esExportFail, -1);

end;

function TAdvStringGrid.FindWide(StartCell:TPoint; s:widestring; FindParams: TFindParams):TPoint;
begin
  ExportNotification(esExportStart, -1);
  Result := FindInternal(StartCell,'',s,True,FindParams);
  if (Result.X = -1) and (Result.Y = -1) then
    ExportNotification(esExportDone, -1)
  else
    ExportNotification(esExportFail, -1);
end;

function TAdvStringGrid.FindInternal(StartCell:TPoint; s:string; sw: widestring; IsWide: Boolean; FindParams: TFindParams):TPoint;
var
  MaxCol,MinCol: Integer;
  MaxRow,MinRow: Integer;
  i,j,pr,nr: Integer;
  FOldCell: TPoint;

  function GetNodeFromRow(row: integer): integer;
  var
    k,l: integer;
  begin
    k := FixedRows;
    l := FixedRows;

    while (k < RowCount - 1) do
    begin
      if IsNode(k) then
        l := l + GetNodeSpan(k);

      if l >= Row then
      begin
        break;
      end
      else
        inc(k);
    end;
    Result := k;
  end;

begin
  Result.x := -1;
  Result.y := -1;

  FOldCell := Point(Col,Row);

  FFindParams := FindParams;
  FFindBusy := True;

  if not (fnMatchCase in FindParams) then
    SearchCache := AnsiUpperCase(s)
  else
    SearchCache := s;

  if not (fnMatchCase in FindParams) then
    SearchCacheWide := WideUpperCase(sw)
  else
    SearchCacheWide := sw;

  if (ColCount = FixedCols) or (ColCount = 0) then Exit;
  if (RowCount + NumHiddenRows = FixedRows) or (RowCount = 0) then Exit;

  if (fnIncludeFixed in FindParams) then
  begin
    MaxCol := ColCount - 1;
    MaxRow := RowCount - 1;
    MinCol := 0;
    MinRow := 0;
  end
  else
  begin
    MaxCol := ColCount - 1 - FixedRightCols;
    MaxRow := RowCount - 1 - FixedFooters;
    MinCol := FixedCols;
    MinRow := FixedRows;
  end;

  if fnSelectedCells in FindParams then
  begin
    MaxCol := Selection.Right;
    MaxRow := Selection.Bottom;
    MinCol := Selection.Left;
    MinRow := Selection.Top;
  end;

  if fnIncludeHiddenColumns in FindParams then
    MaxCol := MaxCol + NumHiddenColumns;

  if (fnIncludeHiddenRows in FindParams) {and (FNumNodes > 0)} then
    MaxRow := MaxRow + NumHiddenRows;

  if (StartCell.x = -1) and (StartCell.y = -1) then
  begin
    if fnBackward in FindParams then
    begin
      StartCell.x := MaxCol;
      StartCell.y := MaxRow;
    end
    else
    begin
      StartCell.x := MinCol;
      StartCell.y := MinRow;
    end;
  end
  else
  begin
    if fnDirectionLeftRight in Findparams then
    begin
      if fnBackward in FindParams then
      begin
        if StartCell.x >= MinCol then
          Dec(StartCell.x)
        else
          if StartCell.y >= MinRow then
            Dec(StartCell.y)
          else
          begin
            StartCell.x := MaxCol;
            StartCell.y := MaxRow;
          end;
      end
      else
      begin
        if StartCell.x <= MaxCol then
          Inc(StartCell.x)
        else
          if StartCell.y <= MaxRow then
            Inc(StartCell.y)
          else
          begin
            StartCell.x := MinCol;
            StartCell.y := MinRow;
          end;
      end;
    end
    else
    begin
      if fnBackward in FindParams then
      begin
        if StartCell.y >= MinRow then
          Dec(StartCell.y)
        else
          if StartCell.x >= MinCol then
            Dec(StartCell.x)
          else
          begin
            StartCell.x := MaxCol;
            StartCell.y := MaxRow;
          end;
      end
      else
      begin
        if StartCell.y <= MaxRow then
          Inc(StartCell.y)
        else
          if StartCell.x <= MaxCol then
            Inc(StartCell.x)
          else
          begin
            StartCell.x := MinCol;
            StartCell.y := MinRow;
          end;
      end;
    end;
  end;

  i := StartCell.x;
  j := StartCell.y;

  if fnFindInCurrentRow in Findparams then
  begin
    j := Row;
    MaxRow := Row;
    MinRow := Row;
  end;

  if fnFindInPresetRow in Findparams then
  begin
    j := FFindRow;
    MaxRow := FFindRow;
    MinRow := FFindRow;
  end;

  if fnFindInCurrentCol in Findparams then
  begin
    i := Col;
    MaxCol := Col;
    MinCol := Col;
  end;

  if fnFindInPresetCol in Findparams then
  begin
    i := FFindCol;
    MaxCol := FFindCol;
    MinCol := FFindCol;
  end;

  StartCell.x := i;
  StartCell.y := j;

  if fnDirectionLeftRight in Findparams then
  begin
    while (j <= MaxRow) and (j >= MinRow) do
    begin
      while (i <= MaxCol) and (i >= MinCol) do
      begin
        ExportNotification(esExportNextRow,j);

        if not IsIgnoredColumn(i) then
        begin

          if MatchCell(i,j,IsWide) then
          begin
            FSearchCell.x := i;
            FSearchCell.y := j;
            Result := FSearchCell;
            if fnAutoGoto in FindParams then
            begin
              nr := j;

              if (fnIncludeHiddenRows in FindParams) and (NumHiddenRows > 0) then
              begin
                if IsHiddenRow(j) and (FNumNodes > 0) then
                begin
                  pr := GetNodeFromRow(j);
                  if pr <> -1 then
                  begin
                    pr := RealRowIndex(pr);
                    ExpandNode(pr);
                  end;
                end;
                nr := DisplRowIndex(nr);
              end;

              if MouseActions.DisjunctRowSelect then
              begin
                ClearRowSelectInt;
                RowSelect[nr] := true;
                Row := nr;
              end
              else
              begin
                Row := nr;
                Col := i;
              end;
            end;
            Exit;
          end;

        end;

        if fnBackward in FindParams then
          Dec(i)
        else
          Inc(i);
      end;

    if fnFindInCurrentCol in FindParams then
      i := Col
    else
    begin
      if fnBackward in FindParams then
        i := MaxCol
      else
        i := MinCol;
    end;

    if fnBackward in FindParams then
      Dec(j)
    else
      Inc(j);
    end;
  end
  else
  begin
    while (i <= MaxCol) and (i >= MinCol) do
    begin
      while (j <= MaxRow) and (j >= MinRow) do
      begin
        ExportNotification(esExportNextRow,j);
        if MatchCell(i,j,IsWide) then
        begin
          FSearchCell.x := i;
          FSearchCell.y := j;
          Result := FSearchcell;
          if fnAutoGoto in Findparams then
          begin
            nr := j;

            if (fnIncludeHiddenRows in FindParams) and (NumHiddenRows > 0) then
            begin
              if IsHiddenRow(j) and (FNumNodes > 0) then
              begin
                pr := GetNodeFromRow(j);

                if pr <> -1 then
                begin
                  pr := RealRowIndex(pr);
                  ExpandNode(pr);
                end;
              end;
              nr := DisplRowIndex(nr);
            end;

            if MouseActions.DisjunctRowSelect then
            begin
              ClearRowSelectInt;
              RowSelect[nr] := true;
              Row := nr;
            end
            else
            begin
              Row := nr;
              Col := i;
            end;
          end;
          Exit;
        end;

        if fnBackward in Findparams then
          Dec(j)
        else
          Inc(j);
      end;

    if fnFindInCurrentRow in Findparams then
      j := Row
    else
    begin
      if fnBackward in FindParams then
        j := MaxRow
      else
        j := MinRow;
    end;

    if fnBackward in Findparams then
      Dec(i)
    else
      Inc(i);
    end;
  end;

  // Restore DB pointer to old position
  if (Result.X = -1) or (Result.Y = -1) then
    ExportNotification(esExportNewRow, FOldCell.Y);

  FFindBusy := False;
end;


function TAdvStringGrid.FindFirst(s:string;FindParams: TFindParams):TPoint;
begin
  FSearchCell := Find(Point(-1,-1),s,FindParams);
  Result := FSearchCell;
end;

function TAdvStringGrid.FindNext:TPoint;
begin
  FSearchCell := Find(FSearchCell,SearchCache,FFindParams);
  Result := FSearchCell;
end;

function TAdvStringGrid.MatchesMulti(ARow: integer): boolean;
var
  i: integer;
  s: string;
begin
  Result := true;

  for i := Low(FColumns) to High(FColumns) do
  begin
    s := Cells[FColumns[i], ARow];
    if not MatchStr(FConditions[i],s,FCase[i]) then
    begin
      Result := false;
      break;
    end;
  end;
end;

function TAdvStringGrid.FindMulti(Conditions: array of string; Columns: array of integer; Searchtypes: array of TSearchType; CaseSensitive: array of boolean; AutoGoto: boolean = false): integer;
var
  i: integer;

  function BuildCondition(st: TSearchType; s: string): string;
  begin
    if Pos(' ',s) > 0 then
      s := '"' + s + '"';

    case st of
    stEqual: Result := s;
    stStartsWith: Result := s + '*';
    stEndsWith: Result := '*' + s;
    stContains: Result := '*' + s + '*';
    stNotContains: Result := '!*' + s + '*';
    stNotEqual: Result := '!' + s;
    end;
  end;

begin
  Result := -1;

  if High(conditions) <> High(Columns) then
    raise Exception.Create('Array size of parameters not matching');

  if High(conditions) <> High(SearchTypes) then
    raise Exception.Create('Array size of parameters not matching');

  if High(conditions) <> High(CaseSensitive) then
    raise Exception.Create('Array size of parameters not matching');

  SetLength(FConditions,Length(Conditions));

  for i := Low(Conditions) to High(Conditions) do
    FConditions[i] := BuildCondition(SearchTypes[i], Conditions[i]);

  SetLength(FColumns, Length(Columns));

  for i := Low(Columns) to High(Columns) do
    FColumns[i] := Columns[i];

  SetLength(FCase, Length(CaseSensitive));

  for i := Low(CaseSensitive) to High(CaseSensitive) do
    FCase[i] := CaseSensitive[i];

  i := FixedRows;

  FSearchCell := Point(0, -1);

  while (i < RowCount - FixedFooters) do
  begin
    if MatchesMulti(i) then
    begin
      Result := i;
      FSearchCell := Point(0, i);
      if AutoGoto then
        Row := i;
      break;
    end
    else
      inc(i);
  end;
end;

function TAdvStringGrid.FindMultiNext: integer;
var
  i: integer;
begin
  i := FSearchCell.Y + 1;
  Result := -1;

  while (i < RowCount - FixedFooters) do
  begin
    if MatchesMulti(i) then
    begin
      Result := i;
      FSearchCell := Point(0, i);
      break;
    end
    else
      inc(i);
  end;
end;

procedure TAdvStringGrid.FixedEditChange(Sender: TObject);
begin
  if Assigned(OnEditChange) then
    OnEditChange(Self, FFixedColEdit, FFixedRowEdit, EditTrans.Text);
end;

procedure TAdvStringGrid.FixedComboSelect(Sender: TObject);
var
  sv: string;
begin
  sv := '';
  if ComboTrans.ItemIndex >= 0 then
    sv := ComboTrans.Items[ComboTrans.ItemIndex];

  if Assigned(OnComboChange) then
    OnComboChange(Self,FFixedColEdit,FFixedRowEdit,ComboTrans.ItemIndex,sv);
end;


procedure TAdvStringGrid.SearchEditChange(Sender: TObject);
var
  DefaultSearch: boolean;
  //ff: integer;
begin
  DefaultSearch := true;

  if Assigned(FOnSearchEditChange) then
    FOnSearchEditChange(self, FSearchPanel.FEdit.Text, DefaultSearch);

  if not DefaultSearch then
    Exit;

  if not SearchFooter.AutoSearch then
    Exit;

  FFindParams := [fnAutoGoto];

  if FSearchPanel.FHiliteButton.Down or FSearchFooter.AlwaysHighLight then
    FFindParams := FFindParams + [fnIgnoreHTMLTags];

  if FSearchPanel.FMatchCase.Checked then
    FFindParams := FFindParams + [fnMatchCase];

  if FSearchFooter.SearchActiveColumnOnly then
    FFindParams := FFindParams + [fnFindInCurrentCol];

  if FSearchFooter.SearchMatchStart then
    FFindParams := FFindParams + [fnMatchStart];

  if FSearchFooter.SearchFixedCells then
    FFindParams := FFindParams + [fnIncludeFixed];

  if FSearchFooter.SearchHiddenRows then
    FFindParams := FFindParams + [fnIncludeHiddenRows];

  if FSearchFooter.SearchDirection = sdLeftRight then
    FFindParams := FFindParams + [fnDirectionLeftRight];

  if (FSearchFooter.SearchColumn >= 0) and (FSearchFooter.SearchColumn < ColCount) then
  begin
    FindCol := DisplColIndex(FSearchFooter.SearchColumn);
    FFindParams := FFindParams + [fnFindInPresetCol];
  end;

  if FSearchPanel.FHiliteButton.Down or FSearchFooter.AlwaysHighLight then
  begin
    if FSearchFooter.SearchColumn <> - 1 then
      InvalidateCol(FSearchFooter.SearchColumn)
    else
      InvalidateGrid;
  end;

  if (FSearchPanel.FEdit.Text <> '') then
  begin
    FSearchCell := Find(Point(-1,-1), FSearchPanel.FEdit.Text, FFindParams);

    if (GetFocus <> FSearchPanel.EditControl.Handle) and (FSearchPanel.EditControl.Enabled) then
      FSearchPanel.EditControl.SetFocus;

    DoSearchFooterAction(FSearchPanel.FEdit.Text, FSearchCell.X, FSearchCell.Y, saFindFirst);

    if FSearchCell.X = -1 then
    begin
      FSearchPanel.FEdit.Color := clRed;
      FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width + 1;
      FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width - 1;
    end
    else
    begin
      FSearchPanel.FEdit.Color := clWindow;
      FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width + 1;
      FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width - 1;

      ScrollInView(FSearchCell.X, FSearchCell.Y);

      if FSearchPanel.FHiliteButton.Down or FSearchFooter.AlwaysHighLight then
      begin
        if FSearchFooter.SearchColumn <> - 1 then
          InvalidateCol(FSearchFooter.SearchColumn)
        else
          InvalidateGrid;
      end;
    end;
  end
  else
  begin
    FSearchPanel.FEdit.Color := clWindow;
    FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width + 1;
    FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width - 1;

    if FSearchPanel.FHiliteButton.Down then
    begin
      if FSearchFooter.SearchColumn <> - 1 then
        InvalidateCol(FSearchFooter.SearchColumn)
      else
        InvalidateGrid;
    end;
  end;

  {
  ff := 0;
  if (FloatingFooter.Visible) then
    ff := 2;

  if (Row > TopRow + VisibleRowCount - 2 - ff) and (VisibleRowCount + FixedRows + ff < RowCount) then
    TopRow := TopRow + 2;
  }
end;

procedure TAdvStringGrid.SearchBackward(Sender: TObject);
begin
  HideInplaceEdit;
  SearchBackwardInt(false);
end;

procedure TAdvStringGrid.SearchBackwardInt(Loop: boolean);
var
  ff: integer;
  contflg: boolean;
begin
  if not SearchFooter.AutoSearch then
  begin
    if (SearchFooter.LastSearch <> FSearchPanel.FEdit.Text) then
      FSearchCell := Point(-1,-1);
    SearchFooter.LastSearch := FSearchPanel.FEdit.Text;
  end;

  FFindParams := [fnAutoGoto, fnBackward];

  if FSearchPanel.FHiliteButton.Down or FSearchFooter.AlwaysHighLight then
    FFindParams := FFindParams + [fnIgnoreHTMLTags];

  if FSearchPanel.FMatchCase.Checked then
    FFindParams := FFindParams + [fnMatchCase];

  if FSearchFooter.SearchDirection = sdLeftRight then
    FFindParams := FFindParams + [fnDirectionLeftRight];

  if FSearchFooter.SearchActiveColumnOnly then
    FFindParams := FFindParams + [fnFindInCurrentCol];

  if FSearchFooter.SearchMatchStart then
    FFindParams := FFindParams + [fnMatchStart];

  if FSearchFooter.SearchFixedCells then
    FFindParams := FFindParams + [fnIncludeFixed];

  if (FSearchFooter.SearchColumn >= 0) and (FSearchFooter.SearchColumn < ColCount) then
  begin
    FindCol := DisplColIndex(FSearchFooter.SearchColumn);
    FFindParams := FFindParams + [fnFindInPresetCol];
    FFindParams := FFindParams - [fnDirectionLeftRight];
  end;

  FSearchCell := Find(FSearchCell,FSearchPanel.FEdit.Text,FFindParams);

  ff := 0;
  if (FloatingFooter.Visible) then
    ff := 1;

  if (Row > TopRow + VisibleRowCount - 2 - ff) and (VisibleRowCount + FixedRows + ff < RowCount) then
    TopRow := TopRow + 2;

  contflg := (FSearchCell.X = -1);

  if not contflg then
    ScrollInView(FSearchCell.X, FSearchCell.Y);

  DoSearchFooterAction(FSearchPanel.FEdit.Text, FSearchCell.X, FSearchCell.Y, saFindPrevious);

  if contflg and not loop then
  begin
    DoSearchFooterSearchEnd(contflg);

    if contflg then
      SearchBackWardInt(true);
  end;

  SearchPanel.Invalidate;
end;

procedure TAdvStringGrid.SearchForward(Sender: TObject);
begin
  HideInplaceEdit;
  SearchForwardInt(false);
end;

procedure TAdvStringGrid.SearchForwardInt(Loop: boolean);
var
  ff: integer;
  contflg: boolean;

begin
  if not SearchFooter.AutoSearch then
  begin
    if (SearchFooter.LastSearch <> FSearchPanel.FEdit.Text) then
      FSearchCell := Point(-1,-1);
    SearchFooter.LastSearch := FSearchPanel.FEdit.Text;
  end;

  FFindParams := [fnAutoGoto];

  if FSearchPanel.FHiliteButton.Down or FSearchFooter.AlwaysHighLight then
    FFindParams := FFindParams + [fnIgnoreHTMLTags];

  if FSearchPanel.FMatchCase.Checked then
    FFindParams := FFindParams + [fnMatchCase];

  if FSearchFooter.SearchActiveColumnOnly then
    FFindParams := FFindParams + [fnFindInCurrentCol];

  if FSearchFooter.SearchMatchStart then
    FFindParams := FFindParams + [fnMatchStart];

  if FSearchFooter.SearchDirection = sdLeftRight then
    FFindParams := FFindParams + [fnDirectionLeftRight];

  if FSearchFooter.SearchFixedCells then
    FFindParams := FFindParams + [fnIncludeFixed];

  if (FSearchFooter.SearchColumn >= 0) and (FSearchFooter.SearchColumn < ColCount) then
  begin
    FindCol := DisplColIndex(FSearchFooter.SearchColumn);
    FFindParams := FFindParams + [fnFindInPresetCol];
    FFindParams := FFindParams - [fnDirectionLeftRight];
  end;

  FSearchCell := Find(FSearchCell,FSearchPanel.FEdit.Text,FFindParams);

  contflg := FSearchCell.X = -1;

  if not contflg then
    ScrollInView(FSearchCell.X, FSearchCell.Y);

  ff := 0;
  if (FloatingFooter.Visible) then
    ff := 1;

  if (Row > TopRow + VisibleRowCount - 2 - ff) and (VisibleRowCount + FixedRows + ff < RowCount) then
    TopRow := TopRow + 2;

  DoSearchFooterAction(FSearchPanel.FEdit.Text, FSearchCell.X, FSearchCell.Y, saFindNext);

  if contflg and not loop then
  begin
    DoSearchFooterSearchEnd(contflg);

    if contflg then
      SearchForWardInt(true);
  end;

  SearchPanel.Invalidate;
end;

procedure TAdvStringGrid.SearchExit(Sender: TObject);
begin
  if Assigned(OnSearchFooterClose) then
    OnSearchFooterClose(Self);

  SearchFooter.Visible := false;
end;

procedure TAdvStringGrid.SearchHighLight(Sender: TObject);
begin
  if FSearchFooter.SearchColumn <> - 1 then
    Invalidate
//    InvalidateCol(FSearchFooter.SearchColumn)
  else
    InvalidateGrid;
end;

procedure TAdvStringGrid.SearchMatchCase(Sender: TObject);
begin
  if FSearchPanel.FHiliteButton.Down then
  begin
    SearchEditChange(self);
  end;
end;

procedure TAdvStringGrid.Click;
begin
  inherited Click;
  FEntered := False;
  InitValidate(Col,Row);
end;

procedure TAdvStringGrid.InitValidate(ACol,ARow: Integer);
var
  RCol: integer;
begin
  FOldCol := ACol;
  FOldRow := ARow;
  RCol := RemapCol(FOldCol);

//  FOldCellText := inherited GetEditText(RemapCol(FOldCol), FOldRow);

  FOldCellText := GetEditCell(RCol, FOldRow);
  FOldCellTextWide := WideCells[RCol, FOldRow];

  FOldModifiedValue := FModified;
end;

procedure TAdvStringGrid.InitVCLStyle(init: boolean);
{$IFDEF DELPHIXE2_LVL}
var
  LStyle: TCustomStyleServices;
  LDetails: TThemedElementDetails;
  clr: TColor;
  DoClr: boolean;
{$ENDIF}
begin
  FUseVCLStyles := False;

{$IFDEF DELPHIXE2_LVL}
  LStyle := StyleServices;

  DoClr := true;

  {$IFDEF DELPHIXE6_LVL}
  if not (seClient in StyleElements) then
    DoClr := false;
  {$ENDIF}

  if LStyle.Enabled and (LStyle.Name <> 'Windows') then
  begin
    FUseVCLStyles := DoClr;

    if DoClr then
    begin
      LStyle.GetElementColor(LStyle.GetElementDetails(tgCellNormal), ecFillColor, clr);
      Color := clr;
    end;
    LStyle.GetElementColor(LStyle.GetElementDetails(tgCellNormal), ecBorderColor, clr);
    GridLineColor := clr;

    LStyle.GetElementColor(LStyle.GetElementDetails(tgFixedCellNormal), ecBorderColor, clr);
    GridFixedLineColor := clr;

    Options := Options - [goFixedVertLine] - [goFixedHorzLine];


    if DoClr then
    begin
      LStyle.GetElementColor(LStyle.GetElementDetails(tgCellNormal), ecTextColor, clr);
      LDetails := LStyle.GetElementDetails(tgCellNormal);
      if LStyle.GetElementColor(LDetails, ecTextColor, clr) and (clr <> clNone) then
        Font.Color := clr;
    end;

    LDetails := LStyle.GetElementDetails(tgCellSelected);
    if LStyle.GetElementColor(LDetails, ecTextColor, clr) and (clr <> clNone) then
      SelectionTextColor := clr;

    LDetails := LStyle.GetElementDetails(tgFixedCellNormal);
    if LStyle.GetElementColor(LDetails, ecTextColor, clr) and (clr <> clNone) then
      FixedFont.Color := clr;
  end
  else
  begin
    if init then
    begin
      Color := clWindow;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      Options := Options + [goFixedVertLine] + [goFixedHorzLine];
      Font.Color := clBlack;
    end;
  end;
{$ENDIF}
end;

procedure TAdvStringGrid.CellsLoaded;
begin
  CalcFooter(-1);
end;

procedure TAdvStringGrid.CellsChanged(R:TRect);
var
  Idx: Integer;
begin
  for Idx := 1 to FNotifierList.Count do
    TGridChangeNotifier(FNotifierList.Items[Idx - 1]).CellsChanged(R);

  if Assigned(FOnCellsChanged) then
    FOnCellsChanged(Self,R);

  CalcFooter(-1);
end;

procedure TAdvStringGrid.UpdateCell(ACol,ARow: Integer);
begin
  CalcFooter(ACol);
end;

function TAdvStringGrid.ValidateCell(const NewValue:string): Boolean;
var
  Value: String;
  Valid: Boolean;
  ROldCol: Integer;
  ROldRow: Integer;
  AE: Boolean;
  pt: TPoint;
  cc: boolean;
  ebt: TEditBalloonTip;
  title, Text: Widestring;
  icon: Integer;
  cbi: TComboBoxInfo;

begin
  Result := True;
  if not FEditing then Exit;
  if FValidating then Exit;

  FEditing := False;
  FValidating := True;

  Valid := True;
  ROldCol := RemapCol(FOldCol);
  ROldRow := FOldRow;
  FNewCellText := NewValue;

  try
    if (FOldCellText <> NewValue) or FAlwaysValidate then
    begin
      cc := (FOldCellText <> NewValue);

      AE := Navigation.AdvanceOnEnter;
      Navigation.AdvanceOnEnter := false;

      Value := NewValue;
      Valid := True;

      if Assigned(CellChecker) then
      begin
        if CellChecker.AutoCorrect then
          Value := CellChecker.Correct(ROldCol,FOldRow,Value);
      end;

      if Assigned(FOnCellValidate) then
        FOnCellValidate(Self,ROldCol,FOldRow,Value,Valid);

      if Assigned(FICellValidate) then
        FICellValidate.ValidateCell(ROldCol,FOldRow,Value,Valid);

      if Assigned(CellChecker) then
      begin
        if CellChecker.AutoMarkError then
          Value := CellChecker.MarkError(ROldCol, ROldRow, Value);
      end;

      if (FOldCellText <> Value) then
        Modified := true;

      if {ShowModified.Enabled and }(FixedCols > 0) and (FOldCellText <> Value) then
      begin
        RowModified[RealRowIndex(Row)] := true;
        if ShowModified.Enabled then
          RepaintCell(0,Row);
      end;

      if Valid then
        UpdateCell(ROldCol,FOldRow);

      if Assigned(CellChecker) then
        if CellChecker.AutoMarkError then
          Value := CellChecker.MarkError(ROldCol,ROldRow,Value);

      if Valid and Assigned(UndoRedo) then
        UndoRedo.RegisterChange(ROldCol,ROldRow,FOldCellText,Value);

      if Valid and cc then
        CellsChanged(Rect(ROldCol,ROldRow,ROldCol,ROldRow));

      // Since Value is also a VAR parameter, we always
      // use it if it was changed in OnCellValidate.

      Navigation.AdvanceOnEnter := AE;

      FNewCellText := Value;

      if not Valid then
      begin
        FLastValidation := false;
        FValidateDblClick := MouseActions.EditOnDblClickOnly;
        MouseActions.EditOnDblClickOnly := false;

        if (Value <> NewValue) then
        begin
          HideEditor;
          Cells[ROldCol,FOldRow] := Value;
          MoveColRow(FOldCol,ROldRow,True,True);
          FValidating := False;
          FEditing := True;
          ShowInplaceEdit;
        end
        else
        begin
          // 2.7.0.5 change
          if EditMode then
            FValidating := False;

          HideEditor;
          Cells[ROldCol,FOldRow] := FOldCellText;
          MoveColRow(FOldCol,ROldRow,True,True);
          FValidating := False;
          FEditing := True;
          ShowInplaceEdit;
          if FOldCol <> Col then
            InvalidateEditor;
        end;

        FModified := FOldModifiedValue;

        if (InvalidEntryText <> '') or (InvalidEntryTitle <> '') then
        begin
          Title := WideString(InvalidEntryTitle);
          Text := WideString(InvalidEntryText);
          Icon := integer(InvalidEntryIcon);

          with ebt do
          begin
            cbStruct := SizeOf(ebt);
            pszTitle := PWideChar(title);
            pszText := PWideChar(Text);
            ttiIcon := icon;
          end;

          if not FSpecialEditor and EditMode then
          begin
            SendMessage(NormalEdit.Handle, EM_SHOWBALLOONTIP, 0, LParam(@ebt));
          end
          else
          begin
            if (EditCtrl is TASGComboBox) and ((EditCtrl as TASGComboBox).Style <> csDropDownList) then
            begin
              cbi.cbSize := sizeof(TComboBoxInfo);
              GetComboBoxInfo(EditCtrl.Handle, cbi);
              SendMessage(cbi.hwndItem, EM_SHOWBALLOONTIP, 0, LParam(@ebt));
            end
            else
            begin
              // does not work for datepicker control ?
              if Assigned(EditCtrl) then
                SendMessage(EditCtrl.Handle, EM_SHOWBALLOONTIP, 0, LParam(@ebt));
            end;
          end;
        end;
      end
      else
      begin
        Cells[ROldCol,ROldRow] := Value;
        if not IsBaseCell(ROldCol, ROldRow) then
        begin
          pt := BaseCell(ROldCol, ROldRow);
          Cells[pt.X, pt.Y] := Value;
        end;
      end;
      FOldCellText := GridCells[ROldCol,FOldRow];
    end
    else
      MouseActions.EditOnDblClickOnly := FValidateDblClick;
  finally
    InitValidate(Col,Row);
    FValidating := False;
  end;

  Result := Valid;

  if Result then
    HideFocusHelper;
end;

function TAdvStringGrid.ValidateCellWide(const NewValue: widestring): Boolean;
var
  Value: WideString;
  Valid: Boolean;
  ROldCol: Integer;
  cc: boolean;
begin
  Result := True;
  if not FEditing then Exit;
  if FValidating then Exit;

  FEditing := False;
  FValidating := True;

  Valid := True;
  ROldCol := RemapCol(FOldCol);


  if (FOldCellTextWide <> NewValue) or FAlwaysValidate then
  begin
    cc := (FOldCellTextWide <> NewValue);
    UpdateCell(ROldCol,FOldRow);
    Value := NewValue;
    Valid := True;

    if Assigned(FOnCellValidateWide) then
      FOnCellValidateWide(Self,ROldCol,FOldRow,Value,Valid);

    // Since Value is also a VAR parameter, we always
    // use it if it was changed in OnCellValidate.
    if not Valid then
    begin
      if Value <> NewValue then
      begin
        HideEditor;
        WideCells[ROldCol,FOldRow] := Value;
        MoveColRow(FOldCol,FOldRow,True,True);
        FValidating := False;
        FEditing := True;
        ShowInplaceEdit;
      end
      else
      begin
        HideEditor;
        WideCells[ROldCol,FOldRow] := FOldCellTextWide;
        MoveColRow(FOldCol,FOldRow,True,True);
        FValidating := False;
        FEditing := True;
        ShowInplaceEdit;
        if FOldCol <> Col then
          InvalidateEditor;
      end;

      FModified := FOldModifiedValue;
    end
    else
    begin
      WideCells[ROldCol,FOldRow] := Value;
    end;

    if (FOldCellTextWide <> NewValue) then
      Modified := true;
    
    if ShowModified.Enabled and (FixedCols > 0) and (FOldCellTextWide <> NewValue) then
    begin
      RowModified[FOldRow] := true;
      RepaintCell(0,FOldRow);
    end;

    if Valid and cc then
      CellsChanged(Rect(ROldCol,FOldRow,ROldCol,FOldRow));

    FOldCellTextWide := WideCells[ROldCol,FOldRow];
  end;

  InitValidate(Col,Row);
  FValidating := False;
  Result := Valid;
end;

procedure TAdvStringGrid.WMSetCursor(var Msg: TWMSetCursor);
var
  pt: TPoint;
  C,R: integer;

begin
  GetCursorPos(pt);
  pt := ScreenToClient(pt);

  {$IFNDEF DELPHI2007_LVL}
  if (ColCount > VisibleColCount) and (FMouseSelectMode = msRow) then
  begin
    if (pt.Y > Height - GetSystemMetrics(SM_CYHSCROLL)) then
      FMouseSelectMode := msNormal;
  end;

  if (RowCount > VisibleRowCount) and (FMouseSelectMode = msColumn) then
  begin
    if (pt.X > Width - GetSystemMetrics(SM_CXVSCROLL)) then
      FMouseSelectMode := msNormal;
  end;
  {$ENDIF}

  if (FMouseSelectMode <> msNormal) and not
     (FGridState in [gsColSizing,gsRowSizing])
  then
  begin
   case FMouseSelectMode of
   msAll,msResize: SetCursor(LoadCursor(HInstance,MakeIntResource(crAsgCross)));
   msRow: SetCursor(LoadCursor(HInstance,MakeIntResource(crHorzArr)));
   msColumn: SetCursor(LoadCursor(HInstance,MakeIntResource(crVertArr)));
   end;
  end
  else
    if FCellSelectorMode then
      SetCursor(LoadCursor(HInstance,MakeIntResource(crAsgCell)))
    else
    begin
      inherited;
      MouseToCell(pt.X, pt.Y, C, R);

      if (R <> -1) and (C <> -1) then
        DoSetCellCursor(C,R, PT.X, PT.Y);
    end;

  if FSizeFixed or FSizingFixed then
    SetCursor(Screen.Cursors[crHSplit]);

  if FSizeFixedR or FSizingFixedR then
    SetCursor(Screen.Cursors[crVSplit]);
end;


procedure TAdvStringGrid.WMKillFocus(var Msg: TWMKillFocus);
begin
  if FBlockKill then
  begin
    Msg.Result := 1;
    Exit;
  end;

  inherited;

  // remove focus border from entire cell
  if IsMergedCell(Col,Row) then
    RepaintCell(Col,Row);

  if FCtrlDown then
  begin
    FCtrlDown := False;
    RepaintCell(FCtrlXY.X,FCtrlXY.Y);
  end;

  if HoverButtons.Enabled then
  begin
    ShowWindow(FButtonForm.Handle, SW_HIDE);
  end;
end;

procedure TAdvStringGrid.WMSetFocus(var Msg: TWMSetFocus);
var
  editable: boolean;
  r: TRect;
  pt: TPoint;
begin
  if InvokedFocusChange then
    Exit;

  inherited;

  if HasCheckBox(Col,Row) then
    Exit;

  if Assigned(FInplaceRichEdit) and FInplaceRichEdit.Visible then
  begin
    HideInplaceEdit;
  end;

  if Assigned(NormalEdit) then
  begin
    if (Msg.FocusedWnd <> NormalEdit.Handle) and
       not (FGridstate in [gsColMoving,gsRowMoving]) and
        FNavigation.AlwaysEdit and (EditControl in [edNormal,edValidChars,edCapital,edMixedCase,edLowerCase,edUpperCase]) then
    begin
      GetCellReadOnly(Col, Row, Editable);

      if (Col >= LeftCol) and (Col < LeftCol + VisibleColCount) and
         (Row >= TopRow) and (Row < TopRow + VisibleRowCount) and Editable then
         begin
           ShowInplaceEdit;
           Msg.Result := 0;
           Exit;
         end;

    end;
  end
  else
    if FNavigation.AlwaysEdit then
    begin
      GetCellReadOnly(Col,Row,Editable);

      if (Col >= LeftCol) and (Col < LeftCol + VisibleColCount) and
         (Row >= TopRow) and (Row < TopRow + VisibleRowCount) and Editable then
         begin
           if not (FMouseActions.DirectEdit or ControlLook.DropDownAlwaysVisible) and HasCombo(Col,Row) then
           begin
             ShowInplaceEdit;
           end;
         end;
    end;

//  if ((RowCount = 1) and (FixedRowAlways)) or
//     ((ColCount = 1) and (FixedColAlways)) then HideSelection;

  if IsMergedCell(Col,Row) then
  begin
    pt := CellSpan(Col,Row);
    r := Rect(Col,Row,Col + pt.X, Row + pt.Y);
    RepaintRect(r);
  end;
end;

procedure TAdvStringGrid.DoEnter;
begin
  if EditMode and Assigned(EditLink) then
    if EditLink.KeepFocus then
      Exit;

  if FBlockFocus then
    Exit;
  try
    inherited DoEnter;
    // FEntered := True;
    if (goEditing in Options) or (MouseActions.RangeSelectAndEdit) then
    begin
      if (Col >= 0) and (Row >= 0) and (Col < ColCount) and (Row < RowCount) then
        SelectCell(Col,Row);
    end;
  finally
    if (Col >= 0) and (Row >= 0) and (Col < ColCount) and (Row < RowCount) then
      InitValidate(Col,Row);
  end;
end;

procedure TAdvStringGrid.DoExit;
begin
  if  FBlockKill then
    Exit;

  // ensure row select states are captured
  if FSelChange and MouseActions.DisjunctRowSelect then
    SelectToRowSelect(false);

  FSelChange := false;

  inherited DoExit;
end;

function TAdvStringGrid.GetCellEditorControl: TWinControl;
begin
  Result := nil;
  if EditMode then
  begin
    if Assigned(EditCtrl) then
      Result := EditCtrl
    else
      Result := NormalEdit;
  end;
end;

function TAdvStringGrid.EditSpin: TGridSpin;
begin
  if not Assigned(FEditSpin) then
  begin
    FEditSpin := TGridSpin.Create(Self);
    FEditSpin.Parent := Self;
    FEditSpin.Enabled := False;
    FEditSpin.Visible := False;
    FEditSpin.Borderstyle := bsNone;
    FEditSpin.IsWinXP := FIsWinXP;
  end;

  Result := FEditSpin;
end;


function TAdvStringGrid.EditDate: TGridDatePicker;
begin
  if not Assigned(FEditDate) then
  begin
    FEditDate := TGridDatePicker.Create(Self);
    FEditDate.Parent := Self;
    FEditDate.Enabled := False;
    FEditDate.Visible := False;
    FEditDate.OnCloseUp := DatePickerCloseUp;
    FEditDate.OnDropDown := DatePickerDropDown;
    FEditDate.OnChange := DatePickerChange;
  end;

  Result := FEditDate;
end;

function TAdvStringGrid.GetRichEdit: TAdvRichEdit;
begin
  if not Assigned(FRichEdit) then
  begin
    FRichEdit := TAdvRichEdit.Create(Self);
    FRichEdit.Parent := Self;
    FRichEdit.Visible := False;
    FRichEdit.Left := 0;
    FRichEdit.Top := 0;
    FRichEdit.Width := 0;
    FRichEdit.Height := 0;
    FRichEdit.BorderStyle := bsNone;
    SetTranspWindow(FRichEdit.Handle);
  end;

  Result := FRichEdit;
end;

function TAdvStringGrid.EditRichEdit: TAdvRichEdit;
begin
  if not Assigned(FInplaceRichEdit) then
  begin
    FInplaceRichEdit := TAdvRichEdit.Create(Self);
    FInplaceRichEdit.OnSelectionChange := RichSelChange;
    FInplaceRichEdit.Parent := Self;
    FInplaceRichEdit.Visible := false;
  end;

  Result := FInplaceRichEdit;
end;

function TAdvStringGrid.EditDateTime: TGridDateTimePicker;
begin
  if not Assigned(FEditDateTime) then
  begin
    FEditDateTime := TGridDateTimePicker.Create(Self);
    FEDitDateTime.Parent := Self;
    FEditDateTime.Visible := False;
    FEDitDateTime.Enabled := False;
    FEditDateTime.AutoTab := True;
    FEditDateTime.OnCloseUp := DatePickerCloseUp;
    FEditDateTime.OnTimeChange := DateTimePickerChange;
  end;
  Result := FEditDateTime;
end;


function TAdvStringGrid.EditAdvGridPicker: TGridAdvGridDropDown;
begin
  if not Assigned(FEditAdvGridPicker) then
  begin
    FEditAdvGridPicker := TGridAdvGridDropDown.Create(Self);
    FEditAdvGridPicker.Parent := self;
    FEditAdvGridPicker.Visible := false;
    FEditAdvGridPicker.SetComponentStyle(FStyle);
    FEditAdvGridPicker.SetColorTones(FTones);
  end;

  Result := FEditAdvGridPicker;
end;

function TAdvStringGrid.EditTrackBar: TGridTrackBarDropDown;
begin
  if not Assigned(FEditTrackBar) then
  begin
    FEditTrackBar := TGridTrackBarDropDown.Create(Self);
    FEditTrackBar.Parent := self;
    FEditTrackBar.EditorEnabled := true;
    FEditTrackBar.Visible := false;
    FEditTrackBar.SetComponentStyle(FStyle);
    FEditTrackBar.SetColorTones(FTones);
  end;

  Result := FEditTrackBar;
end;

function TAdvStringGrid.EditMemo:TGridMemoDropDown;
begin
  if not Assigned(FEditMemo) then
  begin
    FEditMemo := TGridMemoDropDown.Create(Self);
    FEditMemo.Parent := self;
    FEditMemo.Visible := false;
    FEditMemo.SetComponentStyle(FStyle);
    FEditMemo.SetColorTones(FTones);
    FEditMemo.OnChange:= DoMemoChanged;
  end;

  Result := FEditMemo;
end;

function TAdvStringGrid.EditCalculator:TGridCalculatorDropDown;
begin
  if not Assigned(FEditCalculator) then
  begin
    FEditCalculator := TGridCalculatorDropDown.Create(Self);
    FEditCalculator.Parent := self;
    FEditCalculator.EditorEnabled := true;
    FEditCalculator.Visible := false;
    FEditCalculator.SetComponentStyle(FStyle);
    FEditCalculator.SetColorTones(FTones);
  end;

  Result := FEditCalculator;
end;

function TAdvStringGrid.EditTimePicker:TGridTimePickerDropDown;
begin
  if not Assigned(FEditTimePicker) then
  begin
    FEditTimePicker := TGridTimePickerDropDown.Create(Self);
    FEditTimePicker.Parent := self;
    FEditTimePicker.Visible := false;
    FEditTimePicker.SetComponentStyle(FStyle);
    FEditTimePicker.SetColorTones(FTones);
  end;

  Result := FEditTimePicker;
end;

function TAdvStringGrid.EditDetailPicker:TGridDetailPickerDropDown;
begin
  if not Assigned(FEditDetailPicker) then
  begin
    FEditDetailPicker := TGridDetailPickerDropDown.Create(Self);
    FEditDetailPicker.Parent := self;
    FEditDetailPicker.Visible := false;
    FEditDetailPicker.SetComponentStyle(FStyle);
    FEditDetailPicker.SetColorTones(FTones);
  end;

  Result := FEditDetailPicker;
end;

function TAdvStringGrid.EditGridPicker:TGridGridDropDown;
begin
  if not Assigned(FEditGridPicker) then
  begin
    FEditGridPicker := TGridGridDropDown.Create(Self);
    FEditGridPicker.Parent := self;
    FEditGridPicker.Visible := false;
    FEditGridPicker.SetComponentStyle(FStyle);
    FEditGridPicker.SetColorTones(FTones);
  end;

  Result := FEditGridPicker;
end;

function TAdvStringGrid.EditColorPicker: TGridColorDropDown;
begin
  if not Assigned(FEditColorPicker) then
  begin
    FEditColorPicker := TGridColorDropDown.Create(Self);
    FEditColorPicker.Parent := self;
    FEditColorPicker.Visible := false;
    FEditColorPicker.AddDefaultColors;
    FEditColorPicker.OnSelect := DoColorSelect;
    FEditColorPicker.SetComponentStyle(FStyle);
    FEditColorPicker.SetColorTones(FTones);
  end;

  Result := FEditColorPicker;
end;

function TAdvStringGrid.EditImagePicker: TGridImageDropDown;
begin
  if not Assigned(FEditImagePicker) then
  begin
    FEditImagePicker := TGridImageDropDown.Create(Self);
    FEditImagePicker.Parent := self;
    FEditImagePicker.Visible := false;
    FEditImagePicker.OnSelect := DoImageSelect;
    FEditImagePicker.SetComponentStyle(FStyle);
    FEditImagePicker.SetColorTones(FTones);
  end;

  Result := FEditImagePicker;
end;

function TAdvStringGrid.EditControlPicker: TGridControlDropDown;
begin
  if not Assigned(FEditControlPicker) then
  begin
    FEditControlPicker := TGridControlDropDown.Create(Self);
    FEditControlPicker.Parent := self;
    FEditControlPicker.Visible := false;
    FEditControlPicker.SetComponentStyle(FStyle);
    FEditControlPicker.SetColorTones(FTones);
  end;

  Result := FEditControlPicker;
end;


function TAdvStringGrid.GetEditLimit: Integer;
begin
  Result := MaxEditLength;
end;

procedure TAdvStringGrid.CMDialogChar(var Msg: TCMDialogChar);
begin
  if SearchFooter.Visible then
  begin
    if IsAccel(Msg.CharCode, SearchPanel.FForwardButton.Caption) then
    begin
      if SearchPanel.FForwardButton.Visible and SearchPanel.FForwardButton.Enabled then
      begin
        SearchForward(Self);
        Msg.Result := 1;
        Exit;
      end;
    end;

    if IsAccel(Msg.CharCode, SearchPanel.FBackwardButton.Caption) then
    begin
      if SearchPanel.FBackwardButton.Visible and SearchPanel.FBackwardButton.Enabled then
      begin
        SearchBackward(self);
        Msg.Result := 1;
        Exit;
      end;
    end;

    if IsAccel(Msg.CharCode, SearchPanel.FHiliteButton.Caption) then
    begin
      if SearchPanel.FHiliteButton.Visible and SearchPanel.FHiliteButton.Enabled then
      begin
        SearchHighLight(self);
        Msg.Result := 1;
        Exit;
      end;
    end;
  end;

  //Msg.CharCode := 0;
  Msg.Result := 0;
  Exit;

  if (ssAlt in KeyDataToShiftState(Msg.KeyData)) or (csDesigning in ComponentState) then
  begin
    inherited
  end
  else
  begin
    if GetFocus = handle then
    begin
      Msg.CharCode := 0;
      Msg.Result := 1;
    end
    else
      inherited;
  end;
end;

procedure TAdvStringGrid.CMHintShow(var Msg: TMessage);
var
  CanShow: Boolean;
  hi: PHintInfo;

begin
  CanShow := True;
  hi := PHintInfo(Msg.LParam);
  ShowHintProc(hi.HintStr,CanShow,hi^);

  Msg.Result := Ord(Not CanShow);
end;

procedure TAdvStringGrid.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  Invalidate;
end;

procedure TAdvStringGrid.CMColorChanged(var Message: TMessage);
begin
  inherited;
  if FloatingFooter.Visible then
    FloatingFooter.Invalidate;
end;

procedure TAdvStringGrid.CMFontChanged(var Message: TMessage);
begin
  inherited;
end;

procedure TAdvStringGrid.CMCursorChanged(var Message: TMessage);
begin
  inherited;
  if not InvokedChange then
    FMouseSelectMode := msNormal;
  InvokedChange := False;
end;

procedure TAdvStringGrid.ResetFixedCellHighlight;
var
  hx,hy: Integer;
begin
  FSizeFixed := false;
  FSizeFixedR := false;
  FNoMouseLeave := false;

  if not FNoMouseLeave and (FHoverFixedCells <> hfNone) and ((FHoverFixedX <> -1) or (FHoverFixedY <> -1)) then
  begin
    hx := FHoverFixedX;
    hy := FHoverFixedY;
    FHoverFixedX := -1;
    FHoverFixedY := -1;
    RepaintCell(hx,hy);
  end;
end;

procedure TAdvStringGrid.BeginUpdate;
begin
  if not Visible then
    Exit;

  Inc(FUpdateCount);

  if HandleAllocated then
    SendMessage(Handle,WM_SETREDRAW,integer(False),0);
end;

procedure TAdvStringGrid.StartUpdate;
begin
  Inc(FUpdateCount);
end;

procedure TAdvStringGrid.EndUpdate;
begin
  if not Visible then
    Exit;

  if (FUpdateCount > 0) then
    Dec(FUpdateCount);

  if (csDestroying in ComponentState) then
    Exit;

  if (FUpdateCount = 0) then
  begin
    FSelChange := false;
    if HandleAllocated then
    begin
      SendMessage(Handle,WM_SETREDRAW,integer(True),0);
      InvalidateRect(Handle, Nil, False);
      NCPaintProc;

      if SearchFooter.Visible and SearchPanel.HandleAllocated and not (GetFocus = SearchPanel.EditControl.Handle) then
      begin
        SearchFooter.Visible := true;
      end;

      if FControlList.Count > 0 then
        CellControlsUpdate;
    end;
  end;
end;

procedure TAdvStringGrid.ResetUpdate;
begin
  FUpdateCount := 0;
end;

function TAdvStringGrid.IsUpdating: boolean;
begin
  Result := FUpdateCount > 0;
end;

function TAdvStringGrid.GetLockFlag : Boolean;
begin
  Result := FUpdateCount <> 0;
end;

procedure TAdvStringGrid.SetLockFlag(AValue : Boolean);
begin
  if AValue then
    BeginUpdate
  else
    EndUpdate;
end;

procedure TAdvStringGrid.WMTimer(var Msg: TWMTimer);
var
  lp: TPoint;
  ACol,ARow,OldTopRow,OldRow: Longint;
  r: TRect;
  i,j: Integer;
begin
  if (integer(msg.TimerID) = FGridTimerID) then
  begin
    inc(FTimerTicks);

    if Navigation.AutoGotoIncremental then
    begin
      inc(SearchTics);

      if (SearchTics = 4) then
      begin
        SearchInc := '';
        SearchTics := 0;
      end;
    end;

    if FHovering and not (csDesigning in Componentstate)  then
    begin
      GetCursorPos(lp);
      if WindowFromPoint(lp) = self.Handle then
      begin
        r := GetClienTRect;
        lp := ScreenToClient(lp);
         if PtInRect(r,lp) then
         begin
           MouseToCell(lp.x,lp.y,ACol,ARow);
           if (ACol >= FixedCols) and (ARow >= FixedRows) and (ACol < ColCount) and (ARow < RowCount) then
           begin
             SetFocus;
             Row := ARow;
             Col := ACol;
           end;
         end;
       end;
     end;

     if FEnableBlink then
     begin
       FGridBlink := not FGridBlink;

       for i := TopRow to TopRow + VisibleRowCount - 1 do
       begin
         for j := LeftCol to LeftCol + VisibleColCount -1 + NumHiddenColumns do
         begin
           if (FIPos('<BLI',Cells[j,i]) > 0) then RepaintCell(DisplColIndex(j),i);
         end;
       end;

       for i := 0 to FixedRows - 1 do
         for j := LeftCol to LeftCol + VisibleColCount -1 do
         begin
           if (FIPos('<BLI',Cells[j,i]) > 0) then RepaintCell(DisplColIndex(j),i);
         end;

       for i := 0 to FixedCols - 1 do
         for j := TopRow to TopRow + VisibleRowCount -1 do
         begin
           if (FIPos('<BLI',Cells[i,j]) > 0) then RepaintCell(DisplColIndex(i),j);
         end;
      end;
    end
  else
  begin
    OldTopRow := TopRow;
    OldRow := Row;
    inherited;
    if MouseActions.NoScrollOnPartialRow then
    begin
      if (TopRow <> OldTopRow) then
        TopRow := OldTopRow;
      if (Row <> OldRow) and (OldRow >= 0) and (OldRow < RowCount) then
        Row := OldRow;
    end;

  end;
end;

procedure TAdvStringGrid.WMPaint(var Msg: TWMPaint);
var
  DC, MemDC: HDC;
  MemBitmap, OldBitmap: HBITMAP;
  PS: TPaintStruct;

begin
  if FUpdateCount > 0 then
    Msg.Result := 0
  else
  begin
    if not FDoubleBuffered or (Msg.DC <> 0) then
    begin
      if not (csCustomPaint in ControlState) and (ControlCount = 0) then
        inherited
      else
        PaintHandler(Msg);
    end
    else
    begin
      DC := GetDC(0);
      MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
      ReleaseDC(0, DC);
      MemDC := CreateCompatibleDC(0);
      OldBitmap := SelectObject(MemDC, MemBitmap);
      try
        DC := BeginPaint(Handle, PS);
        Perform(WM_ERASEBKGND, MemDC, MemDC);
        Msg.DC := MemDC;
        WMPaint(Msg);
        Msg.DC := 0;
        BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY);
        EndPaint(Handle, PS);
      finally
        SelectObject(MemDC, OldBitmap);
        DeleteDC(MemDC);
        DeleteObject(MemBitmap);
      end;
    end;
  end;

  if not TabStop and (FPaintCount = 0) then
  begin
    inc(FPaintCount);
    UpdateVScroller;
  end;
end;

procedure TAdvStringGrid.WMEraseBkGnd(var Message: TMessage);
begin
  Message.Result := 0
  (*
  if FUpdateCount > 0 then
    Message.Result := 0
  else
    inherited;
  *)
end;

procedure TAdvStringGrid.WMSize(var Msg: TWMSize);
var
  r: Double;
  i,tw,sc: Integer;
  us: Boolean;
  scol,ecol: integer;

begin
  if FInWMSize then
  begin
    Msg.Result := 1;
    Exit;
  end;

  us := True;

  if Assigned(FSearchPanel) and FSearchPanel.Visible then
  begin
    // force control realign to workaround VCL alignment issue
    FSearchPanel.Height := 33;
    FSearchPanel.Height := 32;
    FSearchPanel.Align := alBottom;
  end;

  if not Assigned(FColumnSize) then
    Exit;

  if (FOldSize > 0) and (FColumnSize.FSynchWithGrid) then
  begin
    HideInplaceEdit;
    if BorderStyle = bsSingle then
      r := (Msg.Width + 2) / FOldSize
    else
      r := Msg.Width / FOldSize;

    if FColumnSize.FSynchNormalCellsOnly then
    begin
      scol := FixedCols;
      ecol := ColCount - 1 - FixedRightCols;
    end
    else
    begin
      scol := 0;
      ecol := ColCount - 1;
    end;

    for i := scol to ecol do
      if FOrigColSizes.Count > i then
        ColWidths[i] := Trunc(FOrigColSizes[i] * r);
  end;

  if FColumnSize.FStretch and (ScrollBarAlways in [saNone, saVert]) then
  begin
    FInWMSize := true;

    tw := 0;
    sc := FColumnSize.StretchColumn;
    if sc = -1 then
      sc := ColCount - 1;

    for i := 1 to ColCount do
      if i - 1 <> sc then
      tw := tw + ColWidths[i - 1];

    if tw < Msg.Width then
    begin
      StretchColumn(FColumnSize.StretchColumn, Msg.Width);
      us := False;
    end;
      FInWMSize := false;

    if (ScrollBars in [ssBoth, ssHorizontal]) and (ScrollbarAlways = saNone) then
      ShowScrollbar(Handle,SB_HORZ,(tw + ColWidths[sc] > Msg.Width ));

    if (ScrollBars in [ssBoth, ssVertical]) and (ScrollbarAlways = saNone)  then
      ShowScrollbar(Handle,SB_VERT,RowCount - FixedRows > VisibleRowCount);

    if (ScrollBars in [ssBoth, ssVertical]) and (ScrollbarAlways = saVert)  then
      ShowScrollbar(Handle,SB_VERT,TRUE);

    if ScrollProportional and not (ScrollType = ssMetro) then
    begin
      UpdateHScroller;
      UpdateVScroller;
    end;

    if (not us) and (ScrollBarAlways = saNone) then
    begin
      if Assigned(OnResize) then
        OnResize(Self);
    end;

    if FloatingFooter.Visible then
      inherited
    else
      Msg.Result := 1;
    Exit;
  end;

  inherited;

  if ScrollProportional and not (ScrollType = ssMetro) then
  begin
    UpdateHScroller;
    UpdateVScroller;
  end;

  if us and not FDisableSize then
  begin
    FDisableSize := true;
    UpdateVScrollBar;
    UpdateHScrollBar;

    FlatShowScrollBar(SB_HORZ,VisibleColCount + FixedCols < ColCount);
    FlatShowScrollBar(SB_VERT,VisibleRowCount + FixedRows < RowCount);

    if not (FScrollBars in [ssBoth, ssHorizontal]) then
      ShowScrollbar(Handle,SB_HORZ,false);

    if not (FScrollBars in [ssBoth, ssVertical]) then
      ShowScrollbar(Handle,SB_VERT,false);

    FDisableSize := false;
  end;
end;

procedure TAdvStringGrid.WMChar(var Msg: TWMChar);
var
  r: TRect;
  rc,rm: Integer;
  ch: char;
  canedit: boolean;
  keyhandled: boolean;
  ctt: TTextType;

begin
  rm := RemapCol(Col);

  ctt := TextType(Cells[Col,Row],EnableHTML);
  if (ctt = ttHTML) and (pos('<CONTROL',UpperCase(Cells[Col,Row])) > 0) then
  begin
    msg.Result := 1;
    Exit;
  end;

  if MouseActions.EditOnDblClickOnly then
  begin
    GetCellReadOnly(col, row, CanEdit);
    if CanEdit then
      Options := Options + [goEditing];
  end;

  if Navigation.AllowClipboardShortCuts then
  begin
    if (GetKeyState(VK_CONTROL) and $8000 = $8000) and (Ord(Msg.CharCode) in [3,22,24]) then
    begin
      Msg.CharCode := 0;
      Exit;
    end;
  end;

  if FMouseActions.RangeSelectAndEdit and not HasStaticEdit(Col,Row) and IsEditable(rm,Row)
    and (Msg.CharCode <> 9) and (Msg.CharCode <> 27) and (GetKeyState(VK_CONTROL) and $8000 <> $8000) then
  begin
    ch := chr(Msg.CharCode);
    if Assigned(OnKeyPress) then
      OnKeyPress(self, ch);

    FStartEditChar := chr(Msg.CharCode);
    Options := Options + [goEditing];
    if (Col > LeftCol + VisibleColCount) or (Row > TopROw + VisibleRowCount) or
       (Col < LeftCol) or (Row < TopRow) then
      ScrollInView(Col,Row);

    r := CellRect(Col,Row);
    if Msg.CharCode <> 13 {not Navigation.AdvanceAutoEdit} then
      MouseDown(mbLeft,[],r.Left + 2,r.Top + 2);
    inherited;
    Exit;
  end;

  if (Msg.CharCode = Ord('.')) and FExcelStyleDecimalSeparator and
     (Msg.KeyData and $400000 = $400000) then
  begin
    Msg.CharCode := Ord(DecimalSeparator);
  end;

  rc := RealCol;

  keyhandled := false;

  if HasStaticEdit(rc,Row) then
  begin
    //if (Char(Msg.CharCode) = #32) and (HasStaticEdit(RealCol,Row)) then
      //Msg.CharCode := 0;

    if ((Msg.CharCode in [VK_RETURN]) and Navigation.AdvanceOnEnter) then
    begin
      keyhandled := true;
      inherited;
    end;
  end;

  ch := chr(Msg.CharCode);

  if (goEditing in Options) and (Msg.CharCode <> VK_TAB) and
     ( (ch = ^H) or ((ch >= #32) and (ch <= #255)) ) then
  begin
    if Assigned(OnKeyPress) then
    begin
      OnKeyPress(Self,ch);
      Msg.CharCode := Ord(ch);
    end;

    FStartEditChar := Char(Msg.CharCode);
    if not HasStaticEdit(rc,Row) then
    begin
      ShowEditorChar(Char(Msg.CharCode));
    end;
  end
  else
  begin
    if not keyhandled and (GetFocus = Handle) then
      inherited;
  end;
end;

function TAdvStringGrid.GetFooterCanvas: TCanvas;
begin
  Result := FFooterPanel.Canvas;
end;

function TAdvStringGrid.GetFooterPanel: TFooterPanel;
begin
  Result := FFooterPanel;
end;

procedure TAdvStringGrid.HoverButtonClick(Sender: TObject);
var
  idx: integer;
begin
  idx := (Sender as TAsgSpeedButton).Tag;
  if Assigned(OnHoverButtonClick) then
    OnHoverButtonClick(Self, FHoverButtonRow, HoverButtons.Buttons[idx]);
end;

function TAdvStringGrid.HoverFixedCell(col: Integer; row: Integer): boolean;
begin
  Result := false;

  if (HoverFixedCells in [hfAll, hfFixedColumns, hfFixedRows]) then
  begin
    if (col < FixedCols) and (HoverFixedCells in [hfAll, hfFixedColumns]) then
      Result := true;
    if (row < FixedRows) and (HoverFixedCells in [hfAll, hfFixedRows]) then
      Result := true;
  end;
end;

function TAdvStringGrid.FixedColsVis: Integer;
begin
  if (FixedCols = 0) and HasNodes then
    Result := 1
  else
    Result := FixedCols;
end;

function TAdvStringGrid.NumFixedRightVis: Integer;
var
  i: Integer;
begin

  if FNumHidden > 0 then
  begin
    Result := 0;
    for i := 1 to FFixedRightCols do
      if not IsHiddenColumn(ColCount + FNumHidden - i) then
        Result := Result + 1;
  end
  else
    Result := FFixedRightCols;
end;

procedure TAdvStringGrid.TabToNextRowAtEnd;
begin
  Row := FixedRows;
end;

procedure TAdvStringGrid.EditKeyDown(var Key: Word; Shift: TShiftState);
begin
end;

procedure TAdvStringGrid.Edit_WMKeyDown(var Msg: TWMKeydown);
begin
end;

function TAdvStringGrid.CanVisitCell(ACol,ARow: Integer): boolean;
begin
  if (goEditing in Options) then
    Result := IsEditable(RemapCol(ACol),ARow)
//    Result := IsEditable(ACol,ARow)
  else
    Result := not IsFixed(ACol,ARow);

  if Assigned(OnSelectCell) then
    OnSelectCell(Self,ACol,ARow, Result);
end;

function TAdvStringGrid.NextCol(ACol: Integer): Integer;
var
  dir: boolean;
  cnext: Integer;
begin
  if ACol >= ColCount then
    ACol := ColCount - 1;

  if ACol < FixedCols then
    ACol := FixedCols;

  dir := ACol > Col;

  cnext := ACol;

  if dir then
  begin
    while (ColWidths[cnext] = 0) and (cnext < ColCount - FixedRightCols) do
    begin
     Inc(cnext);
    end;
    if cnext = ColCount - FixedRightCols then
      Result := ACol
    else
      Result := cnext;
  end
  else
  begin
    while (ColWidths[cnext] = 0) and (cnext >= FixedCols) do
    begin
      Dec(cnext);
    end;
    if cnext < FixedCols then
      Result := ACol
    else
      Result := cnext;
  end;
end;

function TAdvStringGrid.NextVisitableCell(ACol,ARow: Integer): TPoint;
var
  c,r: integer;
begin
  Result := Point(-1,-1);

  c := ACol;
  r := ARow;

  if Navigation.AdvanceDirection in [adTopBottom,adTopBottomInCol] then
  begin
    repeat

      if (r < RowCount - 1 - FixedFooters) then
        inc(r)
      else
      begin
        if (Navigation.AdvanceDirection = adTopBottom) then
        begin
          r := FixedRows;
          inc(c);
        end
        else
          break;
      end;

      if CanVisitCell(c,r) then
      begin
        Result := Point(c,r);
        break;
      end;
    until (c = ColCount - 1 - FixedRightCols) and (r = RowCount - 1 - FixedFooters);
  end;

  if Navigation.AdvanceDirection in [adLeftRight, adLeftRightInRow] then
  begin
    repeat
      if (c < ColCount - 1 - FixedRightCols) then
        inc(c)
      else
      begin
        if (Navigation.AdvanceDirection = adLeftRight) then
        begin
          c := FixedCols;
          inc(r);
        end
        else
          break;
      end;

      if CanVisitCell(c,r) then
      begin
        Result := Point(c,r);
        break;
      end;
    until (c = ColCount - 1 - FixedRightCols) and (r = RowCount - 1 - FixedFooters);
  end;

end;

function TAdvStringGrid.FirstCellInRow(ARow: integer): integer;
var
  i: integer;
begin
  Result := -1;

  for i := 0 to ColCount - 1 do
  begin
    if CanVisitCell(i, ARow) then
    begin
      Result := i;
      Break;
    end;
  end;
end;

function TAdvStringGrid.LastCellInRow(ARow: integer): integer;
var
  i: integer;
begin
  Result := -1;

  for i := ColCount - 1 downto 0 do
  begin
    if CanVisitCell(i, ARow) then
    begin
      Result := i;
      Break;
    end;
  end;
end;


function TAdvStringGrid.TabEdit(Dir: Boolean): boolean;
var
  Key,X,Y: word;
  Shift: TShiftState;
  pt: TPoint;
  fc: integer;
  allow: boolean;
  AllowAdd: boolean;
  flg: boolean;

begin
  Result := true;
  flg := false;

  if Navigation.AlwaysEdit then
    HideInplaceEdit;

  if Assigned(OnKeyDown) then
  begin
    Key := VK_TAB;
    if dir then Shift := [ssShift] else Shift := [];
    OnKeyDown(Self,Key,Shift);
    if Key <> VK_TAB then
      Exit;
  end;

  if (FLastTabCol = Col) and (FLastTabRow = Row) then
    Exit;

  if (Col >= ColCount) or (Col < 0) or (Row >= RowCount) or (Row < 0) then
    Exit;
  FLastTabCol := Col;
  FLastTabRow := Row;

  if Dir then
  begin
    if Navigation.TabAdvanceDirection = adLeftRight then
    begin
      if (Col > FixedColsVis) then
      begin
        X := 1;

        while ((Col - x >= FixedColsVis) and not CanVisitCell(Col - X, Row)) or
          ((Col - X >= FixedColsVis) and (not IsBaseCell(Col - X,Row))) do
        begin
          inc(X);
        end;

        if (Col - x < FixedColsVis) then
        begin
          if Row > FixedRows then
          begin
            fc := LastCellInRow(Row - 1);
            if (fc >= 0) then
            begin
              if FIsDBVersion then
              begin
               Row := Row - 1;
               Col := fc;
              end
              else
              begin
                Selection := TGridRect(Rect(fc, Row - 1, fc, Row - 1));
              end;
            end;
            //Row := Row - 1;
            //Col := ColCount - NumFixedRightVis - 1;
          end
          else
          begin
            fc := LastCellInRow(RowCount - 1 - FixedFooters);
            if (fc >= 0) then
            begin
              if FIsDBVersion then
              begin
               Row := RowCount - 1 - FixedFooters;
               Col := fc;
              end
              else
              begin
                Selection := TGridRect(Rect(fc, RowCount - 1 - FixedFooters, fc, RowCount - 1 - FixedFooters));
              end;
              ScrollInView(Col,Row);
            end;
          end;

          if not IsBaseCell(Col,Row) then
          begin
            pt := BaseCell(Col,Row);
            Col := pt.X;
            Row := pt.Y;
          end;
        end
        else
          Col := Col - X;
      end
      else
      begin
        X := 1;
        while not CanVisitCell(ColCount - NumFixedRightVis - X,Row) and (ColCount - NumFixedRightVis - X >= FixedCols) do
          inc(X);

        Col := ColCount - NumFixedRightVis - X;

        if Row > FixedRows then
        begin
          Row := Row - 1
        end
        else
          Row := RowCount - FixedFooters - 1;
      end;
    end
    else
    begin
      if Row > FixedRows then
        Row := Row - 1
      else
      begin
        Row := RowCount - FixedFooters - 1;
        if Col > FixedColsVis then
          Col := Col - 1
        else
          Col := ColCount - NumFixedRightVis - 1;
      end;
    end;
  end
  else
  begin
    if Navigation.TabAdvanceDirection = adLeftRight then
    begin
      if Col + CellSpan(Col,Row).X + 1 < ColCount - NumFixedRightVis  then
      begin
        X := 1;

        while (not CanVisitCell(Col + CellSpan(Col,Row).X + X,Row)) and
              (Col + CellSpan(Col,Row).X + X < ColCount - NumFixedRightVis) {and (not IsBaseCell(Col + x,Row) or (X = 1))} do
        begin
          inc(X);
        end;

        if (Col + CellSpan(Col,Row).X + X = ColCount - NumFixedRightVis) then
        begin
          FForceSel := true;

          if Row < RowCount - FixedFooters - 1 then
          begin
            fc := FirstCellInRow(Row + 1);

            allow := true;
            if Assigned(OnRowChanging) then
              OnRowChanging(Self, Row, Row + 1, allow);

            if Assigned(OnCellChanging) then
              OnCellChanging(Self, Row, Col, Row + 1, fc, Allow);

            if Assigned(OnColChanging) then
              OnColChanging(Self, Col, fc, Allow);

            if allow and CanTabToNextRow then
            begin
              if (fc >= 0) then
              begin
                // Selection := TGridRect(Rect(fc, Row + 1, fc, Row + 1));
                Col := fc;
                Row := Row + 1;
              end
              else
              begin
                Col := FixedCols;
                Row := Row + 1;
              end;
            end;
          end
          else
          begin
            fc := FirstCellInRow(Row + 1);
            if (fc >= 0) then
            begin
              if FIsDBVersion then
              begin
               Row := FixedRows;
               Col := fc;
              end
              else
                Selection := TGridRect(Rect(fc, FixedRows, fc, FixedRows));
            end;

            if (Parent is TWinControl) and Navigation.TabToNextAtEnd then
            begin
              PostMessage((Parent as TWinControl).Handle, WM_KEYDOWN, VK_TAB, 0);
              Result := false;
            end;
            // else
            //  TabEdit(dir);
          end;
          FForceSel := false;
        end
        else
        begin
          if CanVisitCell(Col + CellSpan(Col,Row).X + X, Row) then
            Col := Col + CellSpan(Col,Row).X + X
          else
          begin
            if Row + 1 < RowCount then
            begin
              fc := FirstCellInRow(Row + 1);
              if (fc >= 0) then
                Selection := TGridRect(Rect(fc, Row + 1, fc, Row + 1));
            end
            else
            begin
              fc := FirstCellInRow(FixedRows);
              if (fc >= 0) then
                Selection := TGridRect(Rect(fc, FixedRows, fc, FixedRows));
            end;

          end;
          if not IsBaseCell(Col,Row) then
          begin
            TabEdit(Dir);
            flg := true;
          end;

        end;
      end
      else
      begin
        X := FixedColsVis;

        if Row < RowCount - FixedFooters - 1 then
        begin

          while (not IsBaseCell(X,Row + 1) or not CanVisitCell(X,Row + 1)) and (X < ColCount) do
          begin
            inc(X);
          end;

          if (X = ColCount) then
          begin
            Y := Row + 2;
            while (FirstCellInRow(y) = - 1) and (y < RowCount) do
            begin
              inc(y);
            end;

            if (y = RowCount) then
            begin
              Row := RowCount - 1;
              Col := ColCount - 1;
              TabEdit(Dir);
              flg := true;
            end
            else
            begin
              Row := y;
              Col := FirstCellInRow(y);
            end;
          end
          else
          begin
            //FocusCell(X,Row + 1);
            if CanTabToNextRow then
            begin
              FForceSel := true;
              Col := X;
              Row := Row + 1;
              FForceSel := false;
            end;
          end;
         end
        else
        begin
          if not Navigation.TabToNextAtEnd and Navigation.AdvanceInsert then
          begin
            AllowAdd := True;
            QueryAddRow(AllowAdd);
            if AllowAdd then
            begin
              if FloatingFooter.Visible then
              begin
                InsertRows(RowCount - 1, 1);
                Row := RowCount - 2;
              end
              else
              begin
                RowCount := RowCount + 1;
                Row := RowCount - 1;
              end;

              if Assigned(FOnAutoAddRow) then
                FOnAutoAddRow(Self,RowCount - 1 - FFixedFooters);
            end
            else
              TabToNextRowAtEnd;
          end
          else
            TabToNextRowAtEnd;

          Col := FirstCellInRow(Row);

          if (Parent is TWinControl) and Navigation.TabToNextAtEnd then
          begin
            PostMessage((Parent as TWinControl).Handle, WM_KEYDOWN, VK_TAB, 0);
            Result := false;
          end;
          //else
          //  TabEdit(Dir);
        end;

      end;
    end
    else
    begin
      if Row + CellSpan(Col,Row).Y + 1 < RowCount - FixedFooters  then
        Row := Row + CellSpan(Col,Row).Y + 1
      else
      begin
        TabToNextRowAtEnd;

        if Col < ColCount - NumFixedRightVis - 1 then
          Col := Col + 1
        else
        begin
          Col := FixedColsVis;
          // tab to next control here
          if (Parent is TWinControl) and Navigation.TabToNextAtEnd then
          begin
            PostMessage((Parent as TWinControl).Handle, WM_KEYDOWN, VK_TAB, 0);
            Result := false;
          end;
        end;
      end;
    end;
  end;

  if not IsEditable(RemapCol(Col),Row) and (goEditing in Options) then
  begin
    TabEdit(Dir);
    flg := true;
  end;

  // force start of edit in new cell!
  if not flg and Navigation.AdvanceAutoEdit and not HasStaticEdit(RealColIndex(Col),Row) then
  begin
    ForceMouseOnCell(Col,Row);
  end;

  if IsMergedCell(FLastTabCol, FLastTabRow) then
  begin
    RepaintCell(FLastTabCol, FLastTabRow);
  end;

  FLastTabCol := -1;
  FLastTabRow := -1;

  if Navigation.AlwaysEdit then
  begin
    SetFocus;
  end;

  //if Navigation.AdvanceAutoEdit then
  //  ShowInplaceEdit;

  if MouseActions.DisjunctRowSelect then
  begin
    ClearRowSelectInt;
    RowSelect[Row] := true;
  end;

end;

procedure TAdvStringGrid.WMKeyUp(var Msg: TWMKeyDown);
begin
  inherited;

  if MouseActions.RangeSelectAndEdit and not (goEditing in Options) and (Msg.CharCode in [VK_F2, VK_RETURN]) then
  begin
    if IsEditable(RemapCol(Col),Row) then
    begin
      Options := Options + [goEditing];
      ShowInplaceEdit;
    end
  end;

end;

function TAdvStringGrid.IsOnLastRow: boolean;
begin
  Result := (Row = RowCount - 1 - FixedFooters) or ((Row = RowCount - 2) and FloatingFooter.Visible);
end;

function TAdvStringGrid.HasCustomCellBorder: boolean;
begin
  Result := Assigned(OnGetCellBorder);
end;

procedure TAdvStringGrid.AppendLastRow;
var
  Allow: boolean;
  sl: TStringList;
  i: integer;
begin
  Allow := true;
  if Assigned(OnCanAddRow) then
    OnCanAddRow(Self, Allow);

  if Allow then
  begin
    if FloatingFooter.Visible then
    begin

      sl := TStringList.Create;
      sl.Assign(Rows[RowCount - 1]);
      DoAppendRow;
      for i := 0 to ColCount + NumHiddenColumns - 1 do
      begin
        GridCells[i, RowCount - 2] := '';
        GridObjects[i, RowCount - 2] := nil;
      end;
      Rows[RowCount - 1].Assign(sl);
      sl.Free;
    end
    else
    begin
      DoAppendRow;
      for i := 0 to ColCount + NumHiddenColumns - 1 do
      begin
        GridCells[i, RowCount - 1] := '';
        GridObjects[i, RowCount - 1] := nil;
      end;
    end;

    if FloatingFooter.Visible or (FixedFooters > 0) then
      Row := Row + 1;

    if FloatingFooter.Visible then
    begin
      CalcFooter(-1);
    end;

    if Assigned(OnAutoAddRow) then
      OnAutoAddRow(Self, RowCount - FixedFooters - 1);
  end;
end;

procedure TAdvStringGrid.WMKeydown(var Msg: TWMKeyDown);
const
  VK_C = $43;
  VK_V = $56;
  VK_X = $58;
  VK_A = $41;

var
  nc,nr,i: Integer;
  CC: word;
  CanEdit,Chk: Boolean;
  Allow: Boolean;
  SelCol,SelRow,RCol,NewIdx: Integer;
  IsCtrl,IsShift,IsAlt: Boolean;
  OldLeftCol: Integer;
  RRow,ORow: Integer;
  SS: TShiftState;
  GR: TGridRect;
  R: TRect;
  chw: word;
  OnLastRow: Boolean;
  DownChar: Boolean;
  ctt: TTextType;
  hscrflg: boolean;
  tr,rr: integer;
  updflg: boolean;
  CR: TRect;
  wc: TCustomForm;
  rngsel: boolean;
  sfv,rs,flt: boolean;

  procedure SelChange;
  begin
    if not EqualRect(TRect(FMoveSelection), TRect(Selection)) then
    begin
      SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);
      FMoveSelection := Selection;
    end;
  end;

begin
  OldLeftCol := LeftCol;

  FMoveSelection := Selection;
  SelCol := Col;
  SelRow := Row;
  RCol := RemapCol(Col);

  DownChar := (Msg.CharCode = VK_DOWN);

  IsCtrl := GetKeyState(VK_CONTROL) and $8000 = $8000;
  IsShift := GetKeyState(VK_SHIFT) and $8000 = $8000;
  IsAlt := GetKeyState(VK_LMENU) and $8000 = $8000;

  SS := [];

  if IsCtrl then
    SS := SS + [ssCtrl];
  if IsShift then
    SS := SS + [ssShift];
  if IsAlt then
    SS := SS + [ssAlt];

  hscrflg := (Msg.CharCode in [VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT]) and (goRowSelect in Options) and (LeftCol <> FixedCols)
    and FNavigation.KeepHorizScroll;

  if Navigation.MoveScrollOnly and (Msg.CharCode in [VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT,VK_HOME,VK_END]) then
  begin
    case Msg.CharCode of
    VK_UP: if TopRow > FixedRows then TopRow := TopRow - 1;
    VK_DOWN: if TopRow + VisibleRowCount < RowCount then TopRow := TopRow + 1;
    VK_NEXT: if TopRow + VisibleRowCount < RowCount then TopRow := TopRow + VisibleRowCount;
    VK_PRIOR: if TopRow > VisibleRowCount + FixedRows then TopRow := TopRow - VisibleRowCount
               else
                 TopRow := FixedRows;
    VK_HOME: TopRow := FixedRows;
    VK_END: TopRow := RowCount - VisibleRowCount;
    end;

    Msg.Result := 1;
    Exit;
  end;

  if MouseActions.EditOnDblClickOnly and (Msg.CharCode in [VK_F2, VK_RETURN]) and not (goEditing in Options) then
  begin
    rngsel := MouseActions.RangeSelectAndEdit;
    MouseActions.RangeSelectAndEdit := true;
    if IsEditable(RCol,Row) then
    begin
      Options := Options + [goEditing];
      //ShowInplaceEdit;
    end;
    MouseActions.RangeSelectAndEdit := rngsel;
  end;


  if MouseActions.RangeSelectAndEdit and not (goEditing in Options) and (Msg.CharCode in [VK_F2, VK_RETURN]) then
  begin
    if IsEditable(RCol,Row) then
    begin
    //  Move code to WMKeyUp
    //  Options := Options + [goEditing];
    //  ShowInplaceEdit;
    end
    else
    begin
      CC := Msg.CharCode;
      if Assigned(OnKeyDown) then
        OnKeyDown(Self, CC, SS);
      Msg.CharCode := 0;
      Msg.Result := 1;
      Exit;
    end;
  end;

  if (Msg.CharCode = ord('F')) and IsCtrl and SearchFooter.Visible then
  begin
    SearchPanel.EditControl.SetFocus;
  end;

  if (Msg.CharCode in [VK_F2, VK_RETURN]) then
  begin
    if (goEditing in Options) and not IsEditable(RCol,Row) then
    begin
      CC := Msg.CharCode;
      if Assigned(OnKeyDown) then
        OnKeyDown(Self, CC, SS);

      Msg.CharCode := 0;
      Msg.Result := 1;
      Exit;
    end;

    ctt := TextType(Cells[Col,Row],EnableHTML);

    if (ctt = ttHTML) and (pos('<CONTROL',uppercase(Cells[Col,Row]))> 0) then
    begin
      Msg.Result := 1;
      Exit;
    end;
  end;

  if (Msg.CharCode = VK_RETURN) then
  begin
    if not IsEditable(RCol,Row) then
    begin
      wc := GetParentForm(self);
      if Assigned(wc) then
      begin
        if wc.KeyPreview then
        begin
          inherited;
          Exit;
        end;
      end;

      CC := Msg.CharCode;
      if Assigned(OnKeyDown) then
         OnKeyDown(Self, CC, SS);
      Msg.CharCode := 0;
      Msg.Result := 1;

      Exit;

      inherited;
      Exit;
    end;
  end;

  if (Msg.CharCode in [VK_SPACE, VK_RETURN]) then
  begin
    if HasStaticEdit(RCol,Row) then
    begin
      Canedit := (goEditing in Options) or (MouseActions.RangeSelectAndEdit);
      GetCellReadOnly(RCol,Row,CanEdit);

      if (CanEdit or ControlLook.CheckAlwaysActive) and HasCheckBox(RCol,Row) and (Msg.CharCode = VK_SPACE) then
      begin
        ToggleCheck(RCol,Row,True);

        if ShowModified.Enabled then
        begin
          RowModified[Row] := true;
          RepaintCell(0,Row);
        end;

        RRow := RealRowIndex(Row);
        GetCheckBoxState(RCol,RRow,Chk);

        DoCheckBoxClick(Col,Row,Chk);
      end;

      if (CanEdit or ControlLook.RadioAlwaysActive) and IsRadio(RCol,Row) and (Msg.CharCode = VK_SPACE) then
      begin
        ToggleRadio(RCol,Row,True);
        GetRadioIdx(RCol,Row,NewIdx);
        if Assigned(FOnRadioClick) then
          FOnRadioClick(Self,RCol,Row,NewIdx);
      end;

      if (CanEdit or ControlLook.RadioAlwaysActive) and HasRadioButton(RCol,Row) and (Msg.CharCode = VK_SPACE) then
      begin
        if HasRadioButtonGroup(RCol,Row, rgRow) then
          SetRadioButtonRowIndex(Row,RCol)
        else
          SetRadioButtonColumnIndex(RCol,Row);
        if Assigned(FOnRadioButtonClick) then
          FOnRadioButtonClick(Self,RCol,Row);
      end;

      if CanEdit then
        if HasButton(RCol,Row) then
          DoButtonClick(Col,Row);

      RepaintCell(Col,Row);
    end;
  end;

  if (Msg.CharCode = VK_HOME) and (FNavigation.HomeEndKey = heFirstLastCell)
    and not IsCtrl then
  begin
    Col := FixedCols;
    Row := FixedRows;
    SelectBaseCell;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);

    SelChange;

    Msg.Result := 0;
    Exit;
  end;

  if (Msg.CharCode = VK_HOME) and (FNavigation.HomeEndKey = heFirstLastRow)
    and not IsCtrl then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;

    Row := FixedRows;
    SelectBaseCell;

    if not IsShift and MouseActions.DisjunctRowSelect then
    begin
      ClearRowSelectInt;
      SelectToRowSelect(False);
    end;

    if IsShift and MouseActions.DisjunctRowSelect then
    begin
      Selection := TGridRect(Rect(0,SelRow, ColCount -1, FixedRows));
      SelectToRowSelect(false);
    end;

    if IsShift and not MouseActions.DisjunctRowSelect then
      Selection := TGridRect(Rect(0,SelRow, ColCount -1, FixedRows));

    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);

    Msg.Result := 0;

    if (goRowSelect in Options) and FNavigation.KeepHorizScroll then
    begin
      StartUpdate;
      LeftCol := OldLeftCol;
      ResetUpdate;
    end;

    SelChange;

    Exit;
  end;

  if (Msg.CharCode = VK_HOME) and (FNavigation.HomeEndKey = heFirstLastColumn) and IsCtrl then
  begin
    Row := FixedRows;
    Col := FirstCellInRow(Row);
    SelectBaseCell;
    LeftCol := FixedColsVis;
    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);

    SelChange;

    Msg.Result := 0;
    Exit;
  end;

  if (Msg.CharCode = VK_HOME) and (FNavigation.HomeEndKey = heFirstLastColumn) and not
     (goRowSelect in Options) and not IsCtrl then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;

    if IsShift then
    begin
      Selection := TGridRect(Rect(Col, Row, FixedCols, Row));
      RepaintRow(Row);
    end
    else
    begin
      Col := FirstCellInRow(Row);
      SelectBaseCell;
      LeftCol := FixedColsVis;
    end;
    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);

    SelChange;

    Msg.Result := 0;
    Exit;
  end;

  if (Msg.CharCode = VK_END) and (FNavigation.HomeEndKey = heFirstLastCell)
    and not IsCtrl and not IsShift then
  begin
    Col := ColCount - 1;
    Row := RowCount - 1;
    SelectBaseCell;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);

    SelChange;
    Msg.Result := 0;
    Exit;
  end;


  if (Msg.CharCode = VK_END) and (FNavigation.HomeEndKey = heFirstLastRow)
    and not IsCtrl then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;

    if FFloatingFooter.Visible and (RowCount > 2) then
      Row := RowCount - 2
    else
      Row := RowCount - 1 - FixedFooters;

    if (FixedFooters > 0) and not FFloatingFooter.Visible then
    begin
      TopRow := RowCount - VisibleRowCount;
    end;

    SelectBaseCell;
    if not IsShift and MouseActions.DisjunctRowSelect then
    begin
      ClearRowSelectInt;
      SelectToRowSelect(False);
    end;

    if IsShift and MouseActions.DisjunctRowSelect then
    begin
      Selection := TGridRect(Rect(0,SelRow, ColCount -1, Row));
      SelectToRowSelect(false);
    end;

    if IsShift and not MouseActions.DisjunctRowSelect then
    begin
      Selection := TGridRect(Rect(0,SelRow, ColCount -1, Row));
    end;

    if FloatingFooter.Visible then // force toprow scroll
      TopRow := RowCount - VisibleRowCount;

    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);
    Msg.Result := 0;

    if (goRowSelect in Options) and FNavigation.KeepHorizScroll then
    begin
      StartUpdate;
      LeftCol := OldLeftCol;
      ResetUpdate;
    end;

    SelChange;

    Exit;
  end;

  if (Msg.CharCode = VK_END) and (FNavigation.HomeEndKey = heFirstLastColumn) and not
     (goRowSelect in Options) and not ISCtrl then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;

    if IsShift then
    begin
      Selection := TGridRect(Rect(Col, Row, ColCount - 1 - FixedRightCols, Row));
      RepaintRow(Row);
    end
    else
    begin
      Col := ColCount - 1;
      SelectBaseCell;
      LeftCol := ColCount - VisibleColCount;
    end;

    Msg.Result := 0;
    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);

    SelChange;
    Exit;
  end;

  if (Msg.CharCode = VK_RIGHT) and IsNode(Row) and IsMergedCell(Col,Row) then
  begin
    ExpandNode(RealRowIndex(Row));
  end;

  if (Msg.CharCode = VK_LEFT) and IsNode(Row) and IsMergedCell(Col,Row) then
  begin
    ContractNode(RealRowIndex(Row));
  end;

  if not Navigation.LeftRightRowSelect then
  begin
    if (Msg.CharCode = VK_LEFT) and (goRowSelect in Options)
      and not IsNode(Row) and (ColCount > VisibleColCount) then
    begin
      if (LeftCol > FixedCols) then
        LeftCol := LeftCol - 1;
      chw := Msg.CharCode;
      if Assigned(OnKeyDown) then
        OnKeyDown(self,chw,SS);
      Msg.Result := 0;
      Exit;
    end;

    if (Msg.CharCode = VK_RIGHT) and (goRowSelect in Options)
      and not IsNode(Row) and (ColCount > VisibleColCount) then
    begin
      if (LeftCol + VisibleColCount < ColCount) then
        LeftCol := LeftCol + 1;
      chw := Msg.CharCode;
      if Assigned(OnKeyDown) then
        OnKeyDown(self,chw,SS);
      Msg.Result := 0;
      Exit;
    end;
  end
  else
  begin
    if (Msg.CharCode = VK_LEFT) and (ssCtrl in SS) and (goRowSelect in Options)
      and not IsNode(Row) and (ColCount > VisibleColCount) and (LeftCol > FixedCols) then
    begin
      LeftCol := LeftCol - 1;
    end;

    if (Msg.CharCode = VK_RIGHT) and (ssCtrl in SS) and (goRowSelect in Options)
      and not IsNode(Row) and (ColCount > VisibleColCount) then
    begin
      if (LeftCol + VisibleColCount < ColCount) then
        LeftCol := LeftCol + 1;
    end;
  end;

  if (Msg.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) and $8000 = 0) and (goTabs in Options) then
  begin
    // if IsMergedCell(Col,Row) then
    // begin
    TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);

    if not EqualRect(TRect(FMoveSelection), TRect(Selection)) then
      SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);

    Exit;
    // end;
  end;

  if Navigation.SkipFixedCells then
  begin
    rs := (goRowSelect in Options);

    if UseRightToLeftAlignment then
    begin
      if (Msg.CharCode = VK_LEFT) and (Col < ColCount - FixedRightCols) and IsFixed(Col + 1,Row) then
      begin
        nc := Col;
        while (nc + 1 < ColCount - FixedRightCols) and IsFixed(nc + 1,Row) do
        begin
          inc(nc);
        end;
        if (nc + 1 < ColCount - FixedRightCols) and not IsFixed(nc + 1,Row) then
          Col := nc + 1;

        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);

        Msg.CharCode := 0;
      end;
    end
    else
    begin
      if (Msg.CharCode = VK_LEFT) and (Col > FixedCols) and IsFixed(Col - 1,Row) then
      begin
        nc := Col;
        while (nc - 1 >= FixedCols) and IsFixed(nc - 1,Row) do
        begin
          dec(nc);
        end;
        if (nc - 1 >= FixedCols) and not IsFixed(nc - 1,Row) then
          Col := nc - 1;

        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);

        Msg.CharCode := 0;
      end;
    end;

    if (Msg.CharCode = VK_UP) and (Row > FixedRows) and IsFixed(Col,Row - 1) then
    begin
      nr := Row;

      while (nr - 1 >= FixedRows) and IsFixed(Col,nr - 1) and not rs do
      begin
        dec(nr);
      end;

      if (nr - 1 >= FixedRows) and (rs or not IsFixed(Col,nr - 1)) then
        Row := nr - 1;

      chw := Msg.CharCode;
      if Assigned(OnKeyDown) then
        OnKeyDown(self,chw,SS);

      Msg.CharCode := 0;
    end;

    if UseRightToLeftAlignment then
    begin
      if (Msg.CharCode = VK_RIGHT) and (Col > FixedCols) and IsFixed(Col - 1,Row) then
      begin
        nc := Col;
        while (nc - 1 >= FixedCols) and IsFixed(nc - 1,Row) do
        begin
          dec(nc);
        end;
        if (nc - 1 >= FixedCols) and not IsFixed(nc - 1,Row) then
          Col := nc - 1;

        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);

        Msg.CharCode := 0;
      end;
    end
    else
    begin
      if (Msg.CharCode = VK_RIGHT) and (Col < ColCount - FixedRightCols) and IsFixed(Col + 1,Row) then
      begin
        nc := Col;
        while (nc + 1 < ColCount - FixedRightCols) and IsFixed(nc + 1,Row) do
        begin
          inc(nc);
        end;
        if (nc + 1 < ColCount - FixedRightCols) and not IsFixed(nc + 1,Row) then
          Col := nc + 1;

        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);

        Msg.CharCode := 0;
      end;
    end;

    if (Msg.CharCode = VK_DOWN) and (Row < RowCount - FixedFooters) and (IsFixed(Col,Row + 1) and (Row + 1 < RowCount)) then
    begin
      nr := Row;

      while (nr + 1 < RowCount - FixedFooters) and IsFixed(Col, nr + 1) and not rs do
      begin
        inc(nr);
      end;

      if (nr + 1 < RowCount - FixedFooters) and (rs or not IsFixed(Col,nr + 1)) then
        Row := nr + 1;

      chw := Msg.CharCode;
      if Assigned(OnKeyDown) then
        OnKeyDown(self,chw,SS);

      Msg.CharCode := 0;
    end;
  end;

  OnLastRow := (Row = RowCount - 1 - FixedFooters) or ((Row = RowCount - 2) and FloatingFooter.Visible);
  if DownChar and OnLastRow and Navigation.AppendOnArrowDown then
  begin
    AppendLastRow;
  end;

  if ((FMoveSelection.Top <> Selection.Top) or
     (FMoveSelection.Right <> Selection.Right) or
     (FMoveSelection.Bottom <> Selection.Bottom) or
     (FMoveSelection.Left <> Selection.Left)) and FSelectionRectangle then
  begin
    InvalidateGridrect(Selection);
    FMoveSelection := Selection;
  end;

  tr := TopRow;
  updflg := false;
  sfv := SearchFooter.Visible;

  if sfv then
  begin
    if (tr >= RowCount - VisibleRowCount) then
    begin
      if (Msg.CharCode = VK_DOWN) and (Row >= RowCount - 1) then
      begin
        ScrollToLastRow;

        Msg.Result := 1;
        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);
        Exit;
      end;

      if (Msg.CharCode = VK_RIGHT) and (Row >= RowCount - 1) and (Col = ColCount - 1) then
      begin
        Msg.Result := 1;
        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);
        Exit;
      end;
      if (Msg.CharCode = VK_LEFT) and (Row >= RowCount - 1) and (Col = FixedCols) then
      begin
        Msg.Result := 1;
        chw := Msg.CharCode;
        if Assigned(OnKeyDown) then
          OnKeyDown(self,chw,SS);
        Exit;
      end;

      if (Row >= RowCount - 1) and (Msg.CharCode in [VK_DOWN, VK_NEXT, VK_END, VK_LEFT, VK_RIGHT]) then
      begin
        BeginUpdate;
        updflg := true;
      end;

      if not updflg and not (Msg.CharCode in [VK_DOWN, VK_UP, VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_MENU, VK_SHIFT, VK_LEFT, VK_RIGHT]) then
      begin
        BeginUpdate;
        updflg := true;
      end;
    end;
  end;

  if hscrflg then
    BeginUpdate;

  inherited;

  if sfv then
  begin
    if (TopRow >= RowCount - VisibleRowCount) then
      if not (Msg.CharCode in [VK_DOWN, VK_UP, VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_MENU, VK_SHIFT, VK_LEFT, VK_RIGHT]) then
        TopRow := tr;

    if updflg then
      EndUpdate;
  end;


  if (Msg.CharCode in [VK_DOWN, VK_NEXT, VK_LEFT, VK_RIGHT, VK_END]) then
  begin
    if (SearchFooter.Visible) and (Row = RowCount -1) then
    begin
      CR := CellRect(Col,Row);
      while (CR.Bottom > ClientRect.Bottom - SearchPanel.Height + 2) and
        (Row <= RowCount - 1) do
      begin
        TopRow := TopRow + 1;
        CR := CellRect(Col,Row);
      end;
    end;
  end;

  if hscrflg then
  begin
    LeftCol := OldLeftCol;
    EndUpdate;
  end;

  if FMouseActions.DisjunctRowSelect and FMouseActions.RowSelectPersistent then
    RRow := RemapRowInv(Row)
  else
    RRow := Row;

  if (Msg.CharCode = VK_X) and
     FNavigation.AllowClipboardShortCuts and
     IsCtrl then
  begin
    Allow := True;
    GR := Selection;
    if Assigned(FOnClipboardCut) then
      FOnClipboardCut(self,Allow);
    if Allow then
    begin
      CutSelectionToClipboard;
      if Assigned(FOnClipboardCutDone) then
        FOnClipboardCutDone(self,GR);
    end;
    Exit;
  end;

  if (Msg.CharCode = VK_V) and
     FNavigation.AllowClipboardShortCuts and
     IsCtrl then
  begin
    Allow := True;
    if Assigned(FOnClipboardPaste) then FOnClipboardPaste(self,Allow);
    if Allow then PasteSelectionFromClipboard;
    Exit;
  end;

  if (msg.CharCode in [VK_INSERT,VK_C]) and
     FNavigation.AllowClipboardShortCuts and
     IsCtrl then
  begin
    Allow := True;
    GR := Selection;
    if Assigned(FOnClipboardCopy) then
      FOnClipboardCopy(Self,Allow);
    if Allow then
    begin
      CopySelectionToClipboard;
      if Assigned(FOnClipboardCopyDone) then
        FOnClipboardCopyDone(Self,GR);
    end;
    Exit;
  end;

  if (msg.CharCode = VK_INSERT) and
     FNavigation.AllowClipboardShortCuts and
     IsShift then
  begin
    Allow := True;
    if Assigned(FOnClipboardPaste) then
      FOnClipboardPaste(Self,Allow);
    if Allow then PasteSelectionFromClipboard;
    Exit;
  end;

  if (Msg.CharCode = VK_DELETE) and
     FNavigation.AllowClipboardShortCuts and
     IsShift then
  begin
    Allow := True;
    if Assigned(FOnClipboardCut) then
      FOnClipboardCut(Self,Allow);
    if Allow then
    begin
      CutSelectionToClipboard;
      if Assigned(FOnClipboardCutDone) then
        FOnClipboardCutDone(self,GR);
    end;
    Exit;
  end;

  if (Msg.CharCode = VK_INSERT) and
     FNavigation.AllowInsertRow and
     not IsCtrl and not IsShift and
     (GetKeystate(VK_MENU) and $8000 = 0) then
  begin
    Allow := True;

    QueryInsertRow(Row,Allow);
    if not Allow then Exit;

    RRow := RealRowIndex(Row);
    ORow := Row;
    flt := FilterActive;
    FilterActive := false;

    if RRow < RowCount then
      Row := RRow;

    if FNavigation.InsertPosition = pInsertAfter then
    begin
      if not (FixedRowAlways and (FixedRows = RowCount)) then
      begin
        if Row < RowCount then
        begin
          rr := RealRowIndex(Row + 1);
          DoInsertRow(rr);
          if ORow + 1 < RowCount then
            ORow := ORow + 1;
        end
        else
        begin
          rr := RealRowIndex(Row);
          DoInsertRow(rr);
          ORow := ORow;
        end;
      end
      else
      begin
        rr := RealRowIndex(Row);
        DoInsertRow(rr);
        ORow := 1;
      end;
    end
    else
    begin
      rr := RealRowIndex(Row);
      DoInsertRow(rr);
    end;

    if Assigned(FOnAutoInsertRow) then
      FOnAutoInsertRow(self,rr);

    Modified := true;

    FilterActive := flt;

    Row := ORow;

    CalcFooter(-1);
  end;

  if (msg.CharCode = VK_A) and IsCtrl then
  begin
    if (goRowSelect in Options) or (goRangeSelect in Options) then
    begin
      GR := TGridRect(Rect(FixedColsVis,FixedRows,
        ColCount - FixedRightCols - 1,RowCount - FixedFooters - 1));

      if MouseActions.DisjunctRowSelect then
      begin
        for i := FixedRows to RowCount - FixedFooters - 1 do
          RowSelect[i] := true;
      end;

      if MouseActions.DisjunctCellSelect then
      begin
        SelectCells(FixedCols, FixedRows, ColCount - FixedRightCols - 1, RowCount - FixedFooters - 1);
        Exit;
      end;

      UpdateOnSelection(GR);
      Selection := GR;

      // force cell correct for editing
      FocusCell(ColCount - FixedRightCols - 1,RowCount - FixedFooters - 1);
      R := CellRect(ColCount - FixedRightCols - 1,RowCount - FixedFooters - 1);
      MouseDown(mbLeft,[],R.Left + 2,R.Top + 2);
      MouseUp(mbLeft,[],R.Left + 2,R.Top + 2);
      FocusCell(ColCount - FixedRightCols - 1,RowCount - FixedFooters - 1);
      Selection := GR;
    end;
    Exit;
  end;


  if (Msg.CharCode in [VK_DOWN,VK_UP,VK_LEFT,VK_RIGHT,VK_HOME,VK_END,VK_PRIOR,VK_NEXT]) and
    MouseActions.DisjunctRowSelect then
  begin
    if not IsShift and not IsCtrl then
      ClearRowSelectInt;

    if IsShift then
      SelectToRowSelect(True)
    else
      RowSelect[RRow] := True;
  end;

  if (Msg.CharCode in [VK_DOWN,VK_UP,VK_LEFT,VK_RIGHT,VK_HOME,VK_END,VK_PRIOR,VK_NEXT]) and
    MouseActions.DisjunctColSelect then
  begin
    if not IsShift and not IsCtrl then
      ClearColSelect;

    if IsShift then
      SelectToColSelect(True)
    else
      ColSelect[Col] := True;
  end;

  if (Msg.CharCode = VK_SPACE) and
    MouseActions.DisjunctRowSelect then
  begin
    RowSelect[RRow] := not RowSelect[RRow];
  end;

  if (Msg.CharCode = VK_SPACE) and
    MouseActions.DisjunctColSelect then
  begin
    ColSelect[Col] := not ColSelect[Col];
  end;

  if (Msg.CharCode = VK_DELETE)
     and (FNavigation.AllowDeleteRow)
     and (GetKeystate(VK_MENU) and $8000 = 0) then
  begin
    if (RowCount - FixedFooters - FixedRows >= 1) or
       ((RowCount - FixedFooters - FixedRows = 1) and FixedRowAlways) then
    begin
      RRow := RealRowIndex(Row);
      flt := FilterActive;

      FilterActive := false;

      Allow := True;

      if Assigned(FOnCanDeleteRow) then
        FOnCanDeleteRow(self, RRow, Allow);

      if not Allow then Exit;

      DoDeleteRow(RRow);

      FilterActive := flt;

      if FloatingFooter.Visible and (Row = RowCount - 1) then
        Row := RowCount - 2;

      InitValidate(Col,Row);
      Modified := true;

      CalcFooter(-1);
    end;
  end;

  if (Msg.CharCode = VK_TAB) and (goTabs in Options) then
  begin

    if (FixedRightCols > 0) and (SelCol = ColCount + NumHiddenColumns - FixedRightCols - 1) then
    begin
      if SelRow = RowCount - FixedFooters - 1 then
        Row := FixedRows
      else
        if Row + 1 < RowCount then
          Row := Row + 1;

      Col := FixedColsVis;
    end;
  end;

  if (Msg.CharCode in [VK_F2, VK_RETURN]) then
  begin
    InitValidate(Col,Row);
    if HasHTMLControl(Cells[Col,Row]) then
      AdvanceHTMLEdit(Col,Row,'');

    if (Msg.CharCode = VK_F2) then
    begin
      DoF2Edit;
    end;
  end;

  SelChange;
end;

procedure TAdvStringGrid.WMRButtonDown(var Msg: TWMRButtonDown);
var
  x,y: longint;
  pt: TPoint;
  lc: Integer;
  CanSelect: boolean;
begin
  inherited;

  MouseToCell(Msg.xpos,Msg.ypos,x,y);

  if MouseActions.SelectOnRightClick and (x >= 0) and (y >= 0) and not IsFixed(x,y) then
  begin
    if not (MouseActions.DisjunctCellSelect and IsSelected(x,y)) then
    begin
      //if (goRangeSelect in Options) and not Assigned(OnRightClickCell) then
      //begin
      if not HasStaticEdit(x,y) then
      begin
        if not Assigned(OnRightClickCell) then
        begin
          MouseDown(mbLeft, [], Msg.Xpos, Msg.Ypos);
          MouseUp(mbLeft, [], Msg.Xpos, Msg.Ypos);
        end
        else
          FocusCell(x,y);
      end;

      if (x <> -1) and (y <> -1) then
      begin
        if (not IsSelected(x, y)) or (goRowSelect in Options) then
        begin
          lc := LeftCol;

          if Navigation.KeepHorizScroll then
            BeginUpdate;

          try
            if IsBaseCell(x,y) then
              MoveColRow(x,y,True,True)
            else
            begin
              pt := BaseCell(x,y);
              MoveColRow(pt.x,pt.y,True,True)
            end;

          finally
            if Navigation.KeepHorizScroll then
            begin
              LeftCol := lc;
              EndUpdate;
            end;
          end;
        end
        else
        begin
          CanSelect := true;
          if Assigned(OnSelectCell) then
            OnSelectCell(Self, x, y, CanSelect);
        end;
      end;

      if MouseActions.DisjunctRowSelect then
      begin
        if (GetKeystate(VK_CONTROL) and $8000 = $8000) or (MouseActions.DisjunctRowSelectNoCtrl) then
        begin
          RowSelect[y] := not RowSelect[y];
        end
        else
        begin
          if (RowSelectCount > 1) and Assigned(PopupMenu) Then
          begin
            if (not IsSelected(x, y)) then
            begin
              ClearRowSelectInt;
              RowSelect[y] := true;
            end;
          end
          else
          begin
            ClearRowSelectInt;
            RowSelect[y] := true;
          end;

  //        ClearRowSelectInt;
  //        RowSelect[y] := true;
        end;
      end;
    end;
  end;

  if Assigned(FOnRightClickCell) then
    FOnRightClickCell(Self,y,x);

  if (x < 0) or (y < 0) then
    Exit;

  if URLShow and URLEdit then
  begin
    if IsURL(Cells[RemapCol(x),y]) then
    begin
      Col := x;
      Row := y;
      ShowEditor;
    end;
  end;
end;

procedure TAdvStringGrid.WMLButtonDblClk(var Message: TWMLButtonDblClk);
var
  x,y,rx,ARow,ACol: Integer;
  r,cr: TRect;
  Allow: Boolean;
  BC: TPoint;
  rngsel,btn: boolean;
begin
  MouseToCell(Message.XPos,Message.YPos,x,y);

  if MouseActions.RangeSelectAndEdit and not HasStaticEdit(x,y) then
    FForceSel := true;

  if x = -1 then
  begin
    if not FixedRowAlways then
    begin
      x := ColCount - 1;
      y := 0;
    end
    else
    begin
      inherited;
      Exit;
    end;
  end;

  if (y < FixedRows) and (goColSizing in Options) and (MouseActions.AutoSizeColOnDblClick) then
  begin
    r := CellRect(x,y);

    if Abs(Message.XPos - r.Left) < 4 then
    begin
      FDblClk := True;
      if x - 1 >= FixedCols then
      begin
        Allow := True;
        if Assigned(OnColumnSize) then
          OnColumnSize(Self,x - 1,Allow);

        if Allow then
        begin
          AutoSizeCol(x - 1);
          if Assigned(FOnEndColumnSize) then
            FOnEndColumnSize(Self,x - 1);
        end;
        FForceSel := false;

        inherited;
        Exit;
      end;
    end;

    if Abs(Message.XPos - r.Right) < 4 then
    begin
      if x >= FixedCols then
      begin
        FDblClk := True;
        Allow := True;

        if Assigned(OnColumnSize) then
          OnColumnSize(Self,x,Allow);

        if Allow then
        begin
          AutoSizeCol(x);
          if Assigned(FOnEndColumnSize) then
            FOnEndColumnSize(Self,x);
        end;
        FForceSel := false;

        inherited;
        Exit;
      end;
    end;
  end;

  rx := RemapCol(x);
  btn := HasButton(rx,y);

  if btn then
  begin
    if PtInRect(ButtonRect(x,y),Point(Message.XPos,Message.YPos)) then
    begin
      Exit;
    end;
  end;

  if HasExpand(rx,y) then
  begin
    if PtInRect(ExpandRect(x,y),Point(Message.XPos,Message.YPos)) then
    begin
      Exit;
    end;
  end;

  inherited;

  if Assigned(FOnDblClickCell) then
  begin
    MouseToCell(Message.XPos,Message.YPos,ACol,ARow);
    FOnDblClickCell(Self,ARow,ACol);
  end;

  if HasStaticEdit(rx,y) and not btn then
  begin
    Exit;
  end;

  if MouseActions.EditOnDblClickOnly then
  begin
    rngsel := MouseActions.RangeSelectAndEdit;
    MouseActions.RangeSelectAndEdit := true;

    if IsEditable(rx,y) then
    begin
      Options := Options + [goEditing];
      FOldCol := x;
      FOldRow := y;
      ShowInplaceEdit;
    end;
    MouseActions.RangeSelectAndEdit := rngsel;
  end;

  if (x >= 0) and (y >= 0) then
  begin
    if FMouseActions.RangeSelectAndEdit and IsEditable(rx,y) and not MouseActions.EditOnDblClickOnly then
    begin
      //EditMode := false;
      Options := Options + [goEditing];
      BC := BaseCell(x,y);
      cr := CellRect(BC.X, BC.Y);
      OffsetRect(cr,4,4);
      MouseDown(mbleft,[],cr.left,cr.Top);
    end;
  end;

  FForceSel := false;

  if (y < FixedRows) and (MouseActions.FixedRowsEdit = fceDblClick) then
    StartFixedEdit(x,y)
  else
    if (x < FixedCols) and (MouseActions.FixedColsEdit = fceDblClick) then
      StartFixedEdit(x,y);
end;

procedure TAdvStringGrid.StartFixedEdit(x,y: Integer; FilterEdit: boolean = false);
var
  r: TRect;
  CanEdit: Boolean;
  rc: Integer;
  AEditor: TGridFixedCellEditor;
begin
  if EditTrans.Visible then
  begin
    if not ComboTrans.StopEdit then
      Exit;
  end;

  if ComboTrans.Visible then
  begin
    if not ComboTrans.StopEdit then
      Exit;
  end;

  CanEdit := true;

  if Assigned(OnCanEditCell) then
    OnCanEditCell(Self, y, x, CanEdit);

  if not CanEdit then
    Exit;

  FFixedColEdit := x;
  FFixedRowEdit := y;

  if x = 0 then
    AEditor := MouseActions.FixedColsEditor
  else
    AEditor := MouseActions.FixedRowsEditor;

  ComboTrans.Items.Assign(MouseActions.FixedComboValues);

  DoFixedCellEdit(x,y,AEditor,ComboTrans.Items);

  r := CellRect(x,y);
  rc := RealColIndex(x);
  InflateRect(r,-1,-1);
  r.Top := r.Top + 2;

  if FilterEdit then
  begin
    r.Left := r.Left + 19;
    AEditor := fceEdit;
    EditTrans.Color := FFilterEdit.Color;
  end;

  if AEditor = fceEdit then
  begin
    EditTrans.Left := r.Left;
    EditTrans.Width := r.Right - r.Left;
    EditTrans.Top := r.Top;
    EditTrans.Height := r.Bottom - r.Top;
    EditTrans.OnChange := FixedEditChange;

    EditTrans.Text := Cells[rc,y];
    EditTrans.Col := rc;
    EditTrans.Row := y;
    EditTrans.Visible := True;
    EditTrans.FilterEdit := FilterEdit;
    EditTrans.SetFocus;
  end
  else
  begin
    ComboTrans.Left := r.Left - 1;
    ComboTrans.Width := r.Right - r.Left + 1;
    ComboTrans.Top := r.Top - 1;
    ComboTrans.Height := r.Bottom - r.Top;

    if AEditor = fceComboEdit then
      ComboTrans.Style := csDropDown
    else
      ComboTrans.Style := csDropDownList;

    ComboTrans.DropDownCount := ControlLook.DropDownCount;

    ComboTrans.OnChange := FixedEditChange;
    ComboTrans.OnSelect := FixedComboSelect;
    ComboTrans.Text := Cells[rc,y];

    if AEditor = fceComboList then
    begin
      ComboTrans.ItemIndex := ComboTrans.Items.IndexOf(Cells[rc,y]);
    end;

    if Navigation.AutoComboDropSize then
      ComboTrans.SizeDropDownWidth;

    ComboTrans.Col := rc;
    ComboTrans.Row := y;
    ComboTrans.Visible := True;
    ComboTrans.SetFocus;
  end;


  {
  if EditTrans.Visible then
  begin
    if not EditTrans.StopEdit then
      Exit;
  end;

  CanEdit := true;
  if Assigned(OnCanEditCell) then
    OnCanEditCell(Self, y, x, CanEdit);

  if not CanEdit then
    Exit;

  FFixedColEdit := x;
  FFixedRowEdit := y;

  r := CellRect(x,y);
  rc := RealColIndex(x);
  InflateRect(r,-1,-1);
  }
end;

procedure TAdvStringGrid.ColumnMoved(FromIndex, ToIndex: longint);
var
  cw,i,ii,j: Integer;
  cv: Boolean;
  Rfi,Rti: Integer;
  s: string;

begin
  Rfi := RemapCol(FromIndex);
  Rti := RemapCol(ToIndex);

  {
  if (FColumnOrder.Count > FromIndex) and
     (FColumnOrder.Count > ToIndex) then
  begin
    ii := FColumnOrder.Items[FromIndex];
    FColumnOrder.Delete(FromIndex);
    FColumnOrder.Insert(ToIndex,ii);
  end;
  }

  if (FColumnOrder.Count > Rfi) and
     (FColumnOrder.Count > Rti) then
  begin
    ii := FColumnOrder.Items[Rfi];
    FColumnOrder.Delete(Rfi);
    FColumnOrder.Insert(Rti,ii);
  end;

  if FEnhRowColMove then
  begin
    cw := ColWidths[FromIndex];
    for i := FromIndex to ColCount - 2 do
      ColWidths[i] := ColWidths[i + 1];
    for i := ColCount - 1 downto ToIndex + 1 do
      ColWidths[i] := ColWidths[i - 1];
    ColWidths[ToIndex] := cw;

    if FSuppressColSizes.Count > 0 then
    begin
      cw := FSuppressColSizes[FromIndex];
      for i := FromIndex to ColCount - 2 do
        FSuppressColSizes[i] := FSuppressColSizes[i + 1];
      for i := ColCount - 1 downto ToIndex + 1 do
        FSuppressColSizes[i] := FSuppressColSizes[i - 1];
      FSuppressColSizes[ToIndex] := cw;
    end;

    if FNumHidden > 0 then
    begin
      cv := FVisibleCol[Rfi];

      for i := Rfi to ColCount + FNumHidden - 2 do
        FVisibleCol[i] := FVisibleCol[i + 1];

      for i := ColCount  + FNumHidden - 1 downto Rti + 1 do
        FVisibleCol[i] := FVisibleCol[i - 1];

      FVisibleCol[Rti] := cv;

      cw := FAllColWidths[Rfi];
      for i := Rfi to ColCount + FNumHidden - 2 do
        FAllColWidths[i] := FAllColWidths[i + 1];

      for i := ColCount + FNumHidden - 1 downto Rti + 1 do
        FAllColWidths[i] := FAllColWidths[i - 1];

      FAllColWidths[Rti] := cw;
    end;

    ColMoveflg := True;
  end;

  if FNumHidden > 0 then
  begin
    inherited ColumnMoved(Rfi,Rti);
  end
  else
    inherited ColumnMoved(FromIndex,ToIndex);

  if NumHiddenRows > 0 then
  begin
    for i := 1 to FGridItems.Count do
    begin
      with TGridItem(FGridItems.Items[i - 1]) do
      begin
        s := Items[Rfi];

        for j := Rfi to AllColCount - 2 do
          Items[j] := Items[j + 1];

        for j := AllColCount - 1 downto Rti + 1 do
          Items[j] := Items[j - 1];

        Items[Rti] := s;
      end;
    end;
  end;

  if Rfi = FSortSettings.Column then
    FSortSettings.Column := Rti
  else
  begin
    if (Rfi < FSortSettings.Column) and (Rti > FSortSettings.Column) then
      FSortSettings.Column := FSortSettings.Column - 1
    else
    begin
      if (Rfi > FSortSettings.Column) and (Rti <= FSortSettings.Column) then
        FSortSettings.Column := FSortSettings.Column + 1;
    end;
  end;

  {$WARNINGS OFF}
  if SortSettings.IndexShow then
  begin
    for i := 1 to SortIndexes.Count do
    begin
      ii := SortIndexes.Items[i - 1] and $FFFF;
      if ii = Rfi then
        SortIndexes.Items[i - 1] := SortIndexes.Items[i - 1] and $FFFF0000 or Rti
      else
      begin
        if (Rfi < ii) and (Rti > ii) then
        SortIndexes.Items[i - 1] := SortIndexes.Items[i - 1] and $FFFF0000 or (ii - 1)
        else
        begin
          if (Rfi > ii) and (Rti <= ii) then
            SortIndexes.Items[i - 1] := SortIndexes.Items[i - 1] and $FFFF0000 or (ii + 1);
        end;
      end;
    end;
  end;
  {$WARNINGS ON}

  if FromIndex = Col then
    Col := ToIndex
  else
    if (FromIndex < Col) and (ToIndex > Col) then
      Col := Col - 1
    else
    begin
      if (FromIndex > Col) and (ToIndex <= Col) then
        Col := Col + 1;
    end;

  if FloatingFooter.Visible then
    FFooterPanel.Repaint;

  if Assigned(SyncGrid.Grid) and not FSyncedMove then
  begin
    if SyncGrid.MoveColumn and (SyncGrid.Grid is TAdvStringgrid) then
    begin
      (SyncGrid.Grid as TAdvStringGrid).FSyncedMove := true;
      (SyncGrid.Grid as TAdvStringGrid).MoveColumn(FromIndex, ToIndex);
      (SyncGrid.Grid as TAdvStringGrid).FSyncedMove := false;
    end;
  end;
end;

procedure TAdvStringGrid.RowMoved(FromIndex, ToIndex: longint);
var
  rh: Integer;
  i: Integer;
  rm: TMovedEvent;

begin
  if (FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) and
    (ToIndex = RowCount - 1)) then
    Exit;

  rm := OnRowMoved;
  OnRowMoved := nil;

  inherited RowMoved(FromIndex,ToIndex);

  if FEnhRowColMove then
  begin
    rh := RowHeights[FromIndex];
    for i := FromIndex to RowCount - 2 do
       RowHeights[i] := RowHeights[i + 1];
    for i := RowCount - 1 downto ToIndex + 1 do
       RowHeights[i] := RowHeights[i - 1];
    RowHeights[ToIndex] := rh;

    ColMoveFlg := True;
  end;

  OnRowMoved := rm;

  if Assigned(OnRowMoved) then
    OnRowMoved(Self, FromIndex, ToIndex);

  if Assigned(SyncGrid.Grid) and not FSyncedMove then
  begin
    if SyncGrid.MoveRow and (SyncGrid.Grid is TAdvStringgrid) then
    begin
      (SyncGrid.Grid as TAdvStringGrid).FSyncedMove := true;
      (SyncGrid.Grid as TAdvStringGrid).MoveRow(FromIndex, ToIndex);
      (SyncGrid.Grid as TAdvStringGrid).FSyncedMove := false;
    end;
  end;

end;

procedure TAdvStringGrid.WMRButtonUp(var Msg:TWMLButtonUp);
begin
  // MouseUp stops colmove / rowmove on both left & right button up !!
  if ((Screen.Cursor = crDrag) or (Screen.Cursor = crNoDrop)) and
     (FGridstate in [gsColMoving,gsRowMoving]) and FEnhRowColMove then
  begin
    Msg.Result := 0;
  end
  else
    inherited;
end;

procedure TAdvStringGrid.WMLButtonUp(var Msg:TWMLButtonUp);
var
  x,y,cx,cy,displx,rx: Longint;
  idx,i,nw: Integer;
  doit,chk, WasMove: Boolean;
  r: TRect;
  gr: TGridRect;
  FIsSizing: Boolean;
  lc,offs: Integer;
  UndoSort, CanEdit: Boolean;
  allowdrop: boolean;
  idxsort,checkstate: boolean;
  bc: TPoint;
  noselchange: boolean;
  ismovingcolrow: boolean;
  isdir: boolean;
  dx,dy: integer;
  iGNS : Integer;
begin
  ColMoveFlg := False;
  ColSizeFlg := False;
  FMouseDown := False;
  FMouseKeepDown := False;
  FMouseSelectMode := msNormal;
  noselchange := false;

  if FScrollStart then
  begin
    FScrollStart := false;

    dy := Msg.YPos - ptdown.y;
    dx := Msg.XPos - ptdown.X;

    isdir := abs(dx) > abs(dy);

    if not isdir then
    begin
      if (Msg.YPos > ptdown.y) then
        FScrollDelta := -1
      else
        FScrollDelta := +1;

      if (GetTickCount - FTimeStart < 500) and (TopRow <> FTopDown) then
      begin
        FScrollSteps := 10;
        if not Assigned(FScrollTimer) then
          FScrollTimer := TTimer.Create(self);

        FScrollVert := true;
        FScrollEnd := true;
        FScrollTimer.Interval := 10;
        FScrollTimer.Enabled := true;
        FScrollTimer.OnTimer := ScrollTimerProc;
      end
      else
      begin
        if TopRow = FTopDown then
        begin
          MouseToCell(Msg.XPos, Msg.YPos, cx,cy);

          if (cy <> -1) and (cx <> -1) then
          begin
            if (goRowSelect in Options) then
            begin
            end
            else
            begin
              FocusCell(cx,cy);
              SelectCell(cx,cy);
            end;
          end;

          TopRow := FTopDown;

          CanEdit := true;
          GetCellReadOnly(cx,cy,CanEdit);

          // in case of not scrolling, still trigger checkbox & cell button clicks
          if HasCheckBox(cx,cy) and CanEdit then
          begin
            ToggleCheckBox(cx,cy);
            GetCheckBoxState(cx,cy,checkstate);
            DoCheckBoxClick(cx,cy,checkstate);
          end;
          if HasButton(cx,cy) and CanEdit then
            DoButtonClick(cx,cy);
        end;
      end;

      ptdown.Y := -1;
    end;

    if isdir then
    begin

      if (Msg.XPos > ptdown.x) then
        FScrollDelta := -1
      else
        FScrollDelta := +1;

      if (GetTickCount - FTimeStart < 500) and (LeftCol <> FLeftRight) then
      begin
        FScrollSteps := 10;
        if not Assigned(FScrollTimer) then
          FScrollTimer := TTimer.Create(self);

        FScrollVert := false;
        FScrollEnd := true;
        FScrollTimer.Interval := 10;
        FScrollTimer.Enabled := true;
        FScrollTimer.OnTimer := ScrollTimerProc;
      end
      else
      begin
        if LeftCol = FTopDown then
        begin
          MouseToCell(Msg.XPos, Msg.YPos, cx,cy);

          if (cy <> -1) and (cx <> -1) then
          begin
            FocusCell(cx,cy);
            SelectCell(cx,cy);
          end;

          LeftCol := Max(FixedCols, FLeftRight);

          CanEdit := true;
          GetCellReadOnly(cx,cy,CanEdit);

          // in case of not scrolling, still trigger checkbox & cell button clicks
          if HasCheckBox(cx,cy) and CanEdit then
          begin
            ToggleCheckBox(cx,cy);
            GetCheckBoxState(cx,cy,checkstate);
            DoCheckBoxClick(cx,cy,checkstate);
          end;
          if HasButton(cx,cy) and CanEdit then
            DoButtonClick(cx,cy);
        end;
      end;
    end;

    ptdown.X := -1;
    ptdown.Y := -1;

    ReleaseCapture;

    SetFocus;

    if ActiveRowShow then
    begin
      Invalidate;
    end;
  end;


  if FCtrlDown = True then
  begin
    FCtrlDown := False;
    InvalidateCell(FCtrlXY.X,FCtrlXY.Y);
  end;

  FMouseDownMove := False;

  if (Look = glListview) then
  begin
    RepaintRow(0);
    if FixedCols > 0 then
      RepaintCol(0);
  end;

  FMouseSelectStart := -1;

  if not (csDesigning in ComponentState) then
  begin
    ArwU.visible := False;
    ArwD.visible := False;
    ArwL.visible := False;
    ArwR.visible := False;
  end;

  if FSizingFixed then
  begin
    FSizeFixed := False;
    FSizingFixed := False;

    offs := 0;
    for i := 1 to FSizingFixedCol do
      offs := offs + ColWidths[i - 1];

    nw := Msg.XPos - offs;
    ColWidths[FSizingFixedCol] := nw;

    if Assigned(FOnEndColumnSize) then
      FOnEndColumnSize(Self,FSizingFixedCol);

    if Assigned(FOnUpdateColumnSize) then
    begin
      FOnUpdateColumnSize(Self, FSizingFixedCol, nw);
      if nw <> ColWidths[FSizingFixedCol] then
        ColWidths[FSizingFixedCol] := nw;
    end;
  end;

  if FSizingFixedR then
  begin
    FSizeFixedR := False;
    FSizingFixedR := False;

    offs := 0;
    for i := 1 to FSizingFixedRow do
      offs := offs + RowHeights[i - 1];

    nw := Msg.YPos - offs;
    RowHeights[FSizingFixedRow] := nw;

    if Assigned(FOnEndRowSize) then
      FOnEndRowSize(Self,FSizingFixedRow);
  end;


  if FFixedCellPushed then
  begin
    DrawEdge(Canvas.Handle,FPushedFixedCell, BDR_RAISEDINNER,BF_RIGHT or BF_BOTTOM);
    DrawEdge(Canvas.Handle,FPushedFixedCell, BDR_RAISEDINNER,BF_LEFT or BF_TOP);
    FFixedCellPushed := False;
  end;

  MouseToCell(Msg.XPos,Msg.YPos,x,y);
  displx := x;

  if (FPushedCellButton.x <> -1) {and (x > -1) and (y > -1)} then
  begin
    Canedit := (goEditing in Options);

    bc := Point(x,y);
    rx := RemapCol(x);

    if (x > -1) and (y > -1) then
    begin
      if not ControlLook.NoDisabledButtonLook then
        CanEdit := IsEditableInt(rx,y);
      bc := BaseCell(x,y);
    end;

    if CanEdit or ControlLook.NoDisabledButtonLook or HasExpand(bc.X, bc.Y) or
      (FPushedCellButton.x < FixedCols) or (FPushedCellButton.y < FixedRows) then
    begin
      if not IsNode(FPushedCellButton.y) then
        PushButton(FPushedCellButton.x,FPushedCellButton.y,False);

      if (x > -1) and (y > -1) then
      begin
        bc := BaseCell(x,y);
        if (PtInRect(ButtonRect(bc.x,bc.y),Point(Msg.XPos,Msg.YPos)) or
         (FixedAsButtons and (FPushedCellButton.x < FixedCols) or (FPushedCellButton.y < FixedRows))) then
           DoButtonClick(FPushedCellButton.x,FPushedCellButton.y);

        if HasExpand(bc.X, bc.Y) then
        begin
          if (PtInRect(ExpandRect(bc.x,bc.y),Point(Msg.XPos,Msg.YPos)) or
           (FixedAsButtons and (FPushedCellButton.x < FixedCols) or (FPushedCellButton.y < FixedRows))) then
             DoExpandClick(FPushedCellButton.x,FPushedCellButton.y,ToggleExpand(FPushedCellButton.x,FPushedCellButton.y));
        end;
      end;
    end;

    FPushedCellButton := Point(-1,-1);
    ReleaseCapture;
  end;

  if ((csDesigning in ComponentState) or FHintShowSizing) and FScrollHintShow then
  begin
    if Assigned(FScrollHintWnd) then
      FScrollHintWnd.ReleaseHandle;
    FScrollHintShow := False;
  end;


  ismovingcolrow := ((Screen.Cursor = crDrag) or (Screen.Cursor = crNoDrop)) and
     (FGridstate in [gsColMoving,gsRowMoving]) and FEnhRowColMove;

  if (x <> -1) and (y <> -1) and not ismovingcolrow then
  begin
    if HasButton(x,y) then
    begin
      if PtInRect(ButtonRect(x,y),Point(Msg.XPos,Msg.YPos)) then
        Exit;
    end;

    if HasExpand(x,y) then
    begin
      if PtInRect(ExpandRect(x,y),Point(Msg.XPos,Msg.YPos)) then
        Exit;
    end;
  end;

  FIsSizing := False;

  if (y < FixedRows) and (x >= 0) and (goColSizing in Options) then
  begin
    FIsSizing := (GetCursor = Screen.Cursors[crHSplit]);
  end;

  if Assigned(OnClick) and FDoOnClick and not FIsSizing and (((y < FixedRows) or (x < FixedCols)) {or (not (goEditing in Options))}) then
  begin
    OnClick(Self);
  end;

  FDoOnClick := false;

  if (FGridState = gsSelecting) or Dragging then
  begin
    FGridState := gsNormal;
    Click;
  end;

  if FSelectionClick then
  begin
    FSelectionClick := False;

    if (y >= FixedRows) and (x >= FixedCols) then
    begin
      //+++ 2.6.0.3: handle disjunct row selection while ole drag&drop is active
      if MouseActions.DisjunctRowSelect and DragDropSettings.OleDropSource and
        (GetKeyState(VK_CONTROL) and $8000 <> $8000) then
      begin
        ClearRowSelectInt;
      end;

      if MouseActions.DisjunctRowSelect and DragDropSettings.OleDropSource and
        ((GetKeyState(VK_CONTROL) and $8000 = $8000) or MouseActions.DisjunctRowSelectNoCtrl) then
      begin
        RowSelect[y] := not RowSelect[y];

        if Assigned(OnMouseUp) then
          OnMouseUp(Self, mbLeft, [ssCtrl], x,y);
        Exit;
      end;
      //--- 2.6.0.3

      if goRowSelect in Options then
      begin
        gr.Top := y;
        gr.Left := FixedCols;
        gr.Bottom := y;
        gr.Right := ColCount - 1;
      end
      else
      begin
        gr.Top := y;
        gr.Left := x;
        gr.Bottom := y;
        gr.Right := x;
      end;

      if Assigned(FRowIndicator) and (FixedCols > 0) then
        RepaintCell(0,Row);

      Selection := gr;

      if Assigned(FRowIndicator) and (FixedCols > 0) then
        RepaintCell(0,Row);
    end;
  end;

//  if FMouseActions.DisjunctRowSelect and (x = -1) and (y = -1) then
//  begin
//    SelectToRowSelect(false);
//  end;

  if FMouseActions.DisjunctRowSelect and (x >=0) and not (IsNode(y) and (x = 0)) {and not (Abs(y) < FixedRows)} then
  begin
    if (GetKeyState(VK_CONTROL) and $8000 = $8000) or
       (GetKeyState(VK_SHIFT) and $8000 = $8000) then
      FDisSelection := TGridRect(Rect(-1,-1,-1,-1));

    if not ((x = 0) and FMouseActions.HotmailRowSelect) and not IsFixed(x,y) then
    begin
      FDisSelection := TGridRect(Rect(-1,-1,-1,-1));
      SelectToRowSelect(False);
    end;

    if ( y >= FixedRows) and (y < RowCount - FFixedFooters) then
    begin
      if FDeselectState then
      begin
        if FMouseActions.RowSelectPersistent then
          RowSelect[RemapRowInv(y)] := False
        else
          RowSelect[y] := False;
        noselchange := true;
      end;

      if MouseActions.HotmailRowSelect then
        RepaintCell(0,0);
    end;
    FDeselectState := False;
  end;

  if (IsNode(y) and (Grouping.AutoSelectGroup)) and (x > 0) and not GetNodeState(y) then
  begin
    iGNS := GetNodeSpan(y);
    if FMouseActions.DisjunctRowSelect then
    begin
      for i := 1 to iGNS - 1 do
        RowSelect[RemapRowInv(y + i)] := true;
    end
    else
    begin
      Selection := TGridRect(Rect(FixedCols,y,ColCount - 1,y + iGNS - 1));
    end;
  end;

  if (FMouseActions.DisjunctColSelect) then
  begin
    SelectToColSelect(False);
    if ( x >= FixedCols) and (x < ColCount - FFixedRightCols) then
    begin
      if FDeselectState then
        ColSelect[x] := False;
    end;
    FDeselectState := False;
  end;

// if fEnhRowColMove and ((x=0) or (y=0)) then LockWindowUpdate(self.Handle);

  WasMove := False;

  if ismovingcolrow then
  begin

    MoveButton.Enabled := False;
    MoveButton.Visible := False;

    if Assigned(MoveForm) then
    begin
      FreeAndNil(MoveForm);
    end;

    DoEndBlockFocus;

    allowdrop := Screen.Cursor <> crNoDrop;

    Screen.Cursor := crDefault;

    if allowdrop then
    begin
      if (FGridState = gsColMoving) and (MoveCell >= 0) and
         (x >= FixedCols) and (MoveCell <> x) then
        MoveColumn(MoveCell,x);

      if (FGridState = gsRowMoving) and (MoveCell >= 0) and
         (y >= FixedRows) and (MoveCell <> y) then
        MoveRow(MoveCell,y);
    end
    else
    begin
      if (FGridState = gsColMoving) and (MoveCell >= 0) then
        RepaintRow(0);
      if (FGridState = gsRowMoving) and (MoveCell >= 0) then
        RepaintCol(0);
    end;

    if FGridState in [gsRowMoving,gsColMoving] then
      KillTimer(Handle,1);

    FGridState := gsNormal;
    WasMove := True;
  end;

  inherited;

  {$IFDEF DELPHI2010_LVL}
  if ((x < FixedCols) or (y < FixedRows)) and (x >= 0) and (y >= 0) then
  begin
    if not FIsSizing and Assigned(OnFixedCellClick) then
      OnFixedCellClick(Self,x,y);
  end;
  {$ENDIF}

  if noselchange then
    FSelChange := false;


  if (FGridState = gsSelecting) then
  begin
    FGridState := gsNormal;
  end;

  if FMouseResize then
  begin
    if Assigned(OnSelectionResize) then
      OnSelectionResize(Self,FDropSelection, Selection);

    if Navigation.AllowSmartClipboard then
    begin
      FEditDisable := True;
      PasteSelectionFromClipboard;
      FEditDisable := False;
    end;

    FMouseResize := False;

    if Assigned(OnSelectionResized) then
      OnSelectionResized(Self,FDropSelection, Selection);
  end;

  if Colmoveflg or Colsizeflg or (x < 0) or (y < 0) then
    Exit;

  x := RemapCol(x);

  if HasCheckBox(x,y) then
  begin
    GetCheckBoxState(x,y,chk);
    if Assigned(FOnCheckBoxMouseUp) then
      FOnCheckBoxMouseUp(Self,x,y,Chk);
  end;

  if IsRadio(x,y) then
  begin
    GetRadioIdx(x,y,idx);
    if Assigned(FOnRadioMouseUp) then
      FOnRadioMouseUp(Self,x,y,idx);
  end;

  if ((x < FixedCols) and (y < FixedRows) and not FSortSettings.FixedCols) then
    Exit;

  // Handle here if it is a sortable Column
  Doit := True;

  if FDblClk then
  begin
    FDblClk := False;
    Exit;
  end;

  r := CellRect(displx,y);

  if (y < FixedRows) and (goColSizing in Options) then
  begin
    if (Abs(Msg.xpos - r.Left) < 4)
      or (Abs(Msg.xpos - r.Right) < 4) then Exit;
  end;
  
  MouseToCell(clickposx,clickposy,cx,cy);

  if ControlLook.FixedDropDownButton and CanShowFixedDropDown(X) and (Msg.Xpos > r.Right - 16) then
    Exit;

  if ((Msg.Xpos > r.Right - 16) and GetFilter(x)) then
    Exit;

  if (y = FSortSettings.Row) and (cy = FSortSettings.Row) and
     (FixedRows > 0) and not IsInCheckBox(x,y,Msg.XPos,Msg.YPos) and
     FSortSettings.Show and not WasMove and
     (RowCount > 2) then
  begin
     if IsIgnoredColumn(x) then  // preset to false in case it is in the ignored column list
       Doit := false;

     DoCanSort(x,DoIt);
  end;

  if (y = FSortSettings.Row) and (cy = FSortSettings.Row) and
     (FixedRows > 0) and not IsInCheckBox(x,y,Msg.XPos,Msg.YPos) and
     FSortSettings.Show and
     (RowCount > 2) and
     Doit and not WasMove then
  begin
    HideInplaceEdit;

    if FSortRowXRef.Count <> RowCount then
      InitSortXRef;

    UndoSort := False;

    if FSortSettings.AutoColumnMerge then
      UndoColumnMerge;

    if FSortSettings.IndexShow then
    begin
      if FSortSettings.IndexSortKey = ikShift then
        idxsort := (GetKeyState(VK_SHIFT) and $8000 = $8000)
      else
        idxsort := (GetKeyState(VK_CONTROL) and $8000 = $8000);

      if idxsort then
      begin
        if SortIndexes.FindIndex(x)=-1 then SortIndexes.AddIndex(x,not Boolean(Ord(FSortSettings.InitSortDirection))) else
          SortIndexes.ToggleIndex(x);
      end
      else
      begin
        if (SortIndexes.Count=1) and (SortIndexes.FindIndex(x) <> -1) then
          SortIndexes.ToggleIndex(x)
        else
        begin
          SortIndexes.Clear;
          SortIndexes.AddIndex(x,not Boolean(Ord(FSortSettings.InitSortDirection)));
        end;
      end;

      lc := LeftCol;

      if Navigation.KeepHorizScroll and (goRowSelect in Options) then
        BeginUpdate;

      try
        SortTime := GetTickCount;

        if FNumNodes > 0 then
          QSortGroupIndexed
        else
          QSortIndexed;

        if SortIndexes.Count > 0 then
          FSortSettings.FSortColumn := SortIndexes[0]
        else
          FSortSettings.FSortColumn := -1;

        SortTime := GetTickcount - SortTime;

      finally
        if Navigation.KeepHorizScroll and (goRowSelect in Options) then
        begin
          LeftCol := lc;
          EndUpdate;
        end;
      end;
    end
    else
    begin
      if x = FSortSettings.Column then
      begin
          if (FSortSettings.Direction <> FSortSettings.InitSortDirection) and (FSortSettings.UndoSort) then
          UndoSort := true;

        if FSortSettings.Direction = sdAscending then
          FSortSettings.Direction := sdDescending
        else
          FSortSettings.Direction := sdAscending;
      end
      else
      begin
        FSortSettings.Direction := FSortSettings.InitSortDirection;
        FSortSettings.Column := x;
      end;
      SortTime := GetTickCount;

      lc := LeftCol;

      try
        if Navigation.KeepHorizScroll and (goRowSelect in Options) then
          BeginUpdate;

        if (FNumNodes > 0) then
          QSortgroup
        else
        begin
          if UndoSort then
          begin
            QUnSort;
            FSortSettings.Column := -1;
          end
          else
            QSort;
        end;

      finally
        if Navigation.KeepHorizScroll and (goRowSelect in Options) then
        begin
          LeftCol := lc;
          EndUpdate;
        end;
      end;

      SortTime := GetTickCount - SortTime;
    end;

    if FSortSettings.AutoColumnMerge then
      ApplyColumnMerge;


    if FControlList.Count > 0 then
      CellControlsUpdate(true);

    DoClickSort(FSortSettings.Column);
  end
  else
  begin
    if not DoIt then
    begin
      RepaintCell(x,FSortSettings.Row);
    end;
  end;
end;

procedure TAdvStringGrid.HandleRadioClick(ACol,ARow,Xpos,Ypos: Integer);
var
  cg: TCellGraphic;
  ofs1,ofs2,i,RCol,th: Integer;
  s: string;
  sl: TStrings;
  BC: TPoint;
  RadioSize: Integer;

begin
  GetCellColor(ACol,ARow,[],Canvas.Brush,Canvas.Font);

  BC := BaseCell(ACol,ARow);
  ACol := BC.X;
  ARow := BC.Y;

  cg := GetCellGraphic(ACol,ARow);

  RCol := RemapColInv(ACol);

  if not IsFixed(ACol,ARow) then
  begin
    Col := RCol;
    Row := ARow;
  end;  

  ofs1 := 0;
  ofs2 := 0;

  if ControlLook.ControlStyle in [csClassic,csFlat] then
    RadioSize := ControlLook.RadioSize
  else
    RadioSize := 16;

  sl := TStringList(cg.CellBitmap);

  if cg.CellBoolean and Assigned(sl) then
  begin
    for i := 1 to sl.Count do
    begin
      s := sl.Strings[i - 1];

      ofs2 := ofs2 + Canvas.TextWidth(s) + RadioSize;

      if (xpos < ofs2) and (xpos > ofs1) then
      begin
        if cg.CellIndex = -1 then
          Cells[RCol,ARow] := s
        else
          cg.CellIndex := i - 1;

        Cells[RCol,ARow] := s;

        SetRadioIdx(RCol,ARow,i - 1);

        if Assigned(FOnRadioClick) then
          FOnRadioClick(self,RCol,ARow,i - 1);

        Break;
      end;
      ofs1 := ofs2;
    end;
  end
  else
  begin
    th := Max(RadioSize,Canvas.TextHeight('gh'));
    for i := 1 to sl.Count do
    begin
      ofs2 := ofs2 + th;
      s := sl.Strings[i - 1];

     if (ypos < ofs2) and (ypos > ofs1) then
       begin
         if cg.CellIndex = -1 then
           Cells[RCol,ARow] := s
         else
           cg.CellIndex := i - 1;

        Cells[RCol,ARow] := s;

        SetRadioIdx(RCol,ARow,i - 1);

        if Assigned(FOnRadioClick) then
          FOnRadioClick(self,RCol,ARow,i - 1);

        Break;
      end;
      ofs1 := ofs2;
    end;
  end;
end;

procedure TAdvStringGrid.UpdateSelectionRect(var GR: TGridRect);
begin

end;

procedure TAdvStringGrid.WMLButtonDown(var Msg:TWMLButtonDown);
var
  x,y,rx,ry,ml,hl,lc,ox,oy,scrl: Integer;
  ClickRect, r, hr,cr: TRect;
  CID,CV,CT: string;
  s,Anchor,Stripped,FocusAnchor,AnchorHint: string;
  canedit,chk: Boolean;
  xsize,ysize: Integer;
  Handle,FixCellClick: Boolean;
  ctt: TTextType;
  cpt: TPoint;
  FOldAlwaysEdit,ClickInSelect: Boolean;
  OldLeftCol,OldTopRow,ORow,OCol: Integer;
  OldSel,PrevSel: TGridRect;
  LastCellClicked, Allow: Boolean;
  GR: TGridRect;
  SS: TShiftState;
  ForceSelect, CanChange: boolean;
  noderow: boolean;
  comboincell: boolean;
  israd: boolean;
  yremap: integer;
  ratevalue: double;
  FImages: TCustomImageList;
  i,offs: integer;
  cp: TPoint;
  clr1,clr2,clr3: TColor;
  ha: TAlignment;
  va: TVAlignment;
  ww: boolean;
  gd: TCellGradientDirection;
  st: TGridDrawState;

begin
  FDoOnClick := True;
  FMouseDownMove := True;
  FMouseKeepDown := True;
  FSpinUpClick := False;
  FSpinDnClick := False;
  ForceSelect := False;
  MouseToCell(Msg.XPos,Msg.YPos,X,Y);

  PrevSel := Selection;
  FOrigSelection := Selection;

  cp := Point(Msg.XPos,Msg.YPos);

  if SelectionResizer and SelectionRectangle and (X <> -1) and (Y <> -1) then
  begin
    r := CellRect(Selection.Right,Selection.Bottom);

    r.Top := r.Bottom - Round(6 * FDPIScale);

    if BiDiMode = bdLeftToRight then
      r.Left := R.Right - Round(6 * FDPIScale)
    else
      r.Left := R.Left + Round(6 * FDPIScale);

    if PtInRect(r,Point(msg.xpos,msg.ypos)) then
    begin
      FGridState := gsSelecting;

      FDropSelection := Selection;
      CopySelectionToClipboard;
      FMouseResize := True;
      OldSel := Selection;
      ORow := Row;
      OCol := Col;
      if not (goEditing in Options) and not MouseActions.RangeSelectAndEdit then
        inherited;
      Selection := OldSel;
      Col := OCol;
      Row := ORow;
      MouseMove([],Msg.Xpos,Msg.YPos);

      Msg.Result := 1;
      Exit;
    end;
  end;

  SS := [];
  if GetKeystate(VK_CONTROL) and $8000 = $8000 then
    SS := [ssCtrl];
  if GetKeystate(VK_SHIFT) and $8000 = $8000 then
    SS := [ssShift];
  if GetKeystate(VK_MENU) and $8000 = $8000 then
    SS := [ssAlt];

  if FMouseActions.TouchScroll and not EditMode and ((X <> Col) or (Y <> Row)) and (Y >= FixedRows) and not (ssShift in SS) then
  begin
    DoClickCell(Y,X);
    FTimeStart := GetTickCount;
    ptdown := cp;
    FTopDown := TopRow;
    FLeftRight := LeftCol;
    FScrollStart := true;
    msg.Result := 1;
    FScrollSteps := 0;

    if (goRowSelect in Options) then
    begin

      if (ssCtrl in SS) then
      begin
        RowSelect[Y] := not RowSelect[Y];
      end
      else
      begin
        ClearRowSelect;
        Row := Y;
      end;
    end;

    SetCapture(Self.Handle);
    Exit;
  end;

  if (goEditing in Options) and (MouseActions.RangeSelectAndEdit) and not (PtInRect(TRect(Selection),Point(X,Y))) then
  begin
    Options := Options - [goEditing];
  end;

  allow := true;

  if Assigned(OnCanClickCell) then
    OnCanClickCell(self, y,x, allow);

  if not Allow then
    Exit;

  ox := x;
  oy := y;

  if FCellSelectorMode then
  begin
    CellSelect(X,Y);
    Exit;
  end;

  if (FMouseSelectMode = msResize) then
  begin
    FDropSelection := Selection;
    CopySelectionToClipboard;
    FMouseResize := True;
    ORow := Row;
    OCol := Col;
    OldSel := Selection;
    if not (goEditing in Options) then
      inherited;
    Selection := OldSel;
    Col := OCol;
    Row := ORow;
    MouseMove([],Msg.Xpos,Msg.YPos);
    Exit;
  end;

  if FMouseActions.DisjunctCellSelect and not (ssCtrl in SS) and (x >= 0) and (y >=0) and not IsFixed(X,Y) then
  begin
    FSelectedCells.Clear;
    Invalidate;
  end;

  Searchinc := '';
  FMoveColind := -1;
  FMoveRowind := -1;
  FSelectionClick := False;
  FPushedCellButton := Point(-1,-1);

  OldLeftCol := LeftCol;
  OldTopRow := TopRow;
  FOldTopRow := TopRow;
  FOldKeepLeftCol := LeftCol;

  if y = 0 then
    MouseToCell(Msg.XPos - 5,Msg.YPos,ColClicked,RowClicked)
  else
    if x = 0 then
      MouseToCell(Msg.XPos,Msg.YPos - 4,ColClicked,RowClicked)
    else
      MouseToCell(Msg.XPos - 5,Msg.YPos - 4,ColClicked,RowClicked);

  if (Look = glListView) then
  begin
    if (FHotFixedCell.X <> -1) and (FHotFixedCell.Y <> -1) and
     ((FHotFixedCell.X < FixedCols) or (FHotFixedCell.Y < FixedRows)) then
    begin
      RepaintCell(FHotFixedCell.X,FHotFixedCell.Y);
    end;
  end;

  if (ColClicked >= 0) and (RowClicked >= 0) then
  begin
    ColClickedSize := ColWidths[ColClicked];
    RowClickedSize := RowHeights[RowClicked];
  end;

  ClickPosx := Msg.XPos;
  ClickPosy := Msg.YPos;

  FixCellClick := ((Y < FixedRows) or (X < FixedCols)) and (X >= 0) and (Y >= 0);

  if (X <> -1) and (Y <> -1) then
  begin
    rx := RealColIndex(x);
    cpt := BaseCell(rx,y);
    x := DisplColIndex(cpt.x);
    y := cpt.y;
    ClickRect := CellRect(x,y)
  end
  else
  begin
    HideInplaceEdit;
    if not FixedRowAlways then
      inherited;
    Exit;
  end;

  if FixedRowAlways and (FFixedRowsMin = RowCount) and (Y = FFixedRowsMin - 1) then
  begin
  //  inherited;
  //  Exit;
  end;

  if FMouseActions.CaretPositioning then
    LButFlg := True;

  if FSizeFixed then
  begin
    FSizingFixed := True;
    FSizeFixedX := Msg.XPos;
    DrawSizingLine(FSizeFixedX);

    offs := 0;

    for i := 1 to FixedCols do
    begin
      if (Abs(ColWidths[i - 1] + Offs - Msg.XPos) < 3) and (FixedCols > 0) and
          (X >= 0) and (Y >= 0) and not (csDesigning in ComponentState) then
      begin
        FSizingFixedCol := i - 1;
      end;
      Offs := Offs + ColWidths[i - 1] + 1;
    end;

    Exit;
  end;

  if FSizeFixedR then
  begin
    FSizingFixedR := True;
    FSizeFixedY := Msg.YPos;
    DrawSizingLineR(FSizeFixedY);

    offs := 0;

    for i := 1 to FixedRows do
    begin
      if (Abs(RowHeights[i - 1] + Offs - Msg.YPos) < 3) and (FixedRows > 0) and
          (X >= 0) and (Y >= 0) and not (csDesigning in ComponentState) then
      begin
        FSizingFixedRow := i - 1;
      end;
      Offs := Offs + RowHeights[i - 1] + 1;
    end;

    Exit;
  end;

  if FixCellClick or IsFixed(x,y) then
    HideInplaceEdit;

  FixCellClick := IsFixed(x,y) and not FixCellClick;

  noderow := false;
  if (x >= 0) and (y >= 0) then
    noderow := IsNode(y);

  if (x >= 0) and (y >= 0) then
  begin
    if ((y < FixedRows) or (x < FixedCols) or FixCellClick) then
    if (FFixedAsButtons and (goFixedVertLine in Options) and (goFixedHorzLine in Options) and Ctl3D) and
      (not noderow or (noderow and not InNodeRect(y,Msg.XPos))) then
    begin
      FPushedFixedCell := CellRect(x,y);
      FPushedCellButton := Point(x,y);
      FFixedCellPushed := True;
      DrawEdge(Canvas.Handle,FPushedFixedCell, BDR_SUNKENINNER,BF_RIGHT or BF_BOTTOM);
      DrawEdge(Canvas.Handle,FPushedFixedCell, BDR_SUNKENINNER,BF_LEFT or BF_TOP);
      noderow := false;
    end;
  end;

  rx := RemapCol(x);

  if not (csDesigning in ComponentState) and (x >= 0) and (y >= 0) then
  begin
    if ControlLook.SpinButtonsAlwaysVisible and HasSpinEdit(x,y) then
    begin
      r := CellRect(x,y);

      if (Msg.XPos > r.Right - 18) then
      begin
        if Msg.YPos > r.Top + ((r.Bottom - r.Top) div 2) then
          FSpinDnClick := true
        else
          FSpinUpClick := true;
      end;
    end;

    if (y < FixedRows) and (x = 0) and noderow and InNodeRect(y,Msg.XPos) and MouseActions.NodeAllExpandContract then
    begin
      if (GraphicObjects[0,y] as TCellGraphic).CellBoolean then
        ExpandAll
      else
        ContractAll;

      (GraphicObjects[0,y] as TCellGraphic).CellBoolean := not (GraphicObjects[0,y] as TCellGraphic).CellBoolean;
    end;

    if (y >= FixedRows) and (x = 0) then
      if noderow and InNodeRect(y,Msg.XPos) then
      begin
        if Assigned(OnMouseDown) then
          OnMouseDown(Self, mbLeft, SS, Msg.XPos, Msg.YPos);

        DoClickCell(Y,X);

        yremap := RemapRowInv(y);
        Allow := True;

        if not (GraphicObjects[0,y] as TCellGraphic).CellBoolean then
        begin

          if Assigned(FOnBeforeContractNode) then
            FOnBeforeContractNode(Self,y,yremap,Allow);

          if Allow then
          begin
            ContractNode(RemapRowInv(y));
            if Assigned(FOnContractNode) then
              FOnContractNode(self,y,yremap);
          end;
        end
        else
        begin
          if Assigned(FOnBeforeExpandNode) then
            FOnBeforeExpandNode(Self,y,yremap,Allow);

          if Allow then
          begin
            ExpandNode(RemapRowinv(y));
            if Assigned(FOnExpandNode) then
              FOnExpandNode(self,y,yremap);
          end;
        end;

        if MouseActions.MoveRowOnNodeClick then
          Row := y;

        Exit;
      end;

//    if (y >= FixedRows) and (x >= FixedCols) then
      if IsRadio(rx,y) and (IsEditable(rx,y) or (ControlLook.RadioAlwaysActive)) then
      begin
        HideInplaceEdit;
        HandleRadioClick(rx,y,Msg.XPos - ClickRect.Left,Msg.YPos - ClickRect.Top);
        SetFocus;
        Exit;
      end;

    if (x = 0) and (y >= FixedRows) and (FNumNodes > 0) and not
      (MouseActions.RowSelect or (goRowSizing in Options)) and not HasButton(rx,y) and not HasRating(rx,y) then
    begin
      if Assigned(OnMouseDown) then
        OnMouseDown(Self, mbLEFT,SS ,msg.XPos, msg.YPos);

      DoClickCell(Y,X);
      Exit;
    end;

    if (IsSelected(x,y) or
       ((y < FixedRows) and not FEnhRowColMove)) and
       {not (goEditing in Options) and} not HasButton(rx,y) and not HasCheckBox(rx, y) and
       FDragDropSettings.FOleDropSource
       and not ( (MouseActions.ColSelect or MouseActions.AllSelect) and (y < FixedRows) or (x < FixedCols)) then
    begin
      if not (((msg.xpos - ClickRect.Left < 4) or (ClickRect.Right - msg.xpos < 4)) and (goColsizing in Options)) then
      begin
        SetFocus;
        if Assigned(OnMouseDown) then
          OnMouseDown(Self, mbLEFT, SS ,msg.XPos, msg.YPos);

        FSelectionClick := True;

        DoClickCell(Y,X);
        Exit;
      end;
    end;
  end;

  if HasRating(rx,y) and IsEditable(rx,y) then
  begin
    HideInplaceEdit;
    R := CellRect(x,y);
    ratevalue := trunc((Msg.XPos - R.Left)/9) / 2;

    if DoRatingChange(rx, y, ratevalue) then
    begin
      Floats[rx,y] := ratevalue;
      RepaintCell(x,y);
    end;
    Exit;
  end;

  if HasButton(rx,y) then
  begin
    HideInplaceEdit;

    if not IsFixed(rx,y) then
    begin
      FForceSel := true;
      SelectCell(x,y);
      FForceSel := false;
    end;

    //move from here
    //Selection := TGridRect(Rect(x,y,x,y));

    if PtInRect(ButtonRect(x,y),Point(Msg.XPos,Msg.YPos)) then
    begin
      PushButton(x,y,True);

      FPushedCellButton := Point(x,y);
      SetCapture(Self.Handle);

      DoClickCell(Y,X);
      //if (goEditing in Options) then
      //  Options := Options - [goEditing];
      Exit;
    end;
  end;

  if HasExpand(rx,y) then
  begin
    HideInplaceEdit;

    if not IsFixed(rx,y) then
    begin
      FForceSel := true;
      SelectCell(x,y);
      FForceSel := false;
    end;

    if PtInRect(ExpandRect(x,y),Point(Msg.XPos,Msg.YPos)) then
    begin
      PushButton(x,y,True);

      FPushedCellButton := Point(x,y);

      DoClickCell(Y,X);

      SetCapture(Self.Handle);
      Exit;
    end;
  end;

  comboincell := false;

  if (x >= FixedCols) and
     (y >= FixedRows) and ControlLook.DropDownAlwaysVisible then
    begin
      comboincell := HasCombo(rx,y);
    end;


  if IsMergedCell(X,Y) and not IsFixed(X,Y) and not Assigned(OnMouseDown) and not comboincell then
  begin
    if BidiMode = bdRightToLeft then
    begin
      cp := BaseCell(ox,oy);
      for i := 1 to ox - cp.X do
        msg.XPos := msg.XPos + ColWidths[cp.X + i - 1];
      msg.YPos := ClickRect.Top + 2;
    end
    else
    begin
      msg.XPos := ClickRect.Left + 2;
      msg.YPos := ClickRect.Top + 2;
    end;
  end;

  if (x >= ColCount) or (y >= RowCount) or (x < 0) or (y < 0) then
  begin
    inherited;
    Exit;
  end;

  if (ColClicked <> -1) and (RowClicked <> -1) then
    r := CellRect(ColClicked,RowClicked)
  else
    r := Rect(0,0,0,0);

  ClickPosdx := -r.Right + ClickPosx;
  ClickPosdy := -r.Bottom + ClickPosy;

  // if ctrl-pressed / shift pressed
  if (FMouseActions.DisjunctRowSelect) and (y >= FixedRows) and
    not ((x = 0) and (FMouseActions.HotmailRowSelect or FMouseActions.RowSelect)) then
  begin
    if (GetKeystate(VK_SHIFT) and $8000 = $8000)  then
    begin
      inherited;
      Selection := TGridRect(Rect(x,y,PrevSel.Left, PrevSel.Top));
      Exit;
    end;

    if (GetKeystate(VK_CONTROL) and $8000 = $8000) or MouseActions.DisjunctRowSelectNoCtrl then
    begin
      if FMouseActions.RowSelectPersistent then
      begin
        if RowSelect[RemapRowInv(y)] then FDeselectState := True
      end
      else
      begin
        if RowSelect[y] then FDeselectState := True
      end;
    end
    else
    begin
      FMouseDown := True;
      if (GetKeystate(VK_MENU) and $8000 = 0) then
        ClearRowSelectInt;
    end;
  end;

  if (FMouseActions.DisjunctColSelect) and (x >= FixedCols) then
  begin
    if GetKeystate(VK_CONTROL) and $8000 = $8000 then
    begin
      if ColSelect[x] then FDeselectState := True;
    end
    else
    begin
      FMouseDown := True;
      ClearColSelect;
    end;
  end;

  s := Cells[rx,y];
  ctt := TextType(s,FEnableHTML);

  if URLShow or (ctt = ttHTML) then
  begin
    Anchor := '';
    if (ctt <> ttHTML) and IsURL(s) {$IFDEF CUSTOMIZED} or (pos('*',s) = 1) {$ENDIF} then
    begin
      Anchor := s;
    end
    else
      if ctt = ttHTML then
      begin
        if HasScrollBar(x,y) then
        begin
          scrl := GetScrollPosition(x,y);
          r.Right := r.Right - GetSystemMetrics(SM_CXVSCROLL);
        end
        else
          scrl := 0;

        r.Right := r.Right - FXYOffset.X;
        r.Left := r.Left + 1 + FXYOffset.X;
        r.Top := r.Top + 1 + FXYOffset.Y;
        r.Bottom := r.Bottom + scrl;

        if HasCheckBox(rx,y) then
          r.Left := r.Left + ControlLook.CheckSize;

        FImages := GetCellImageList(x,y);

        st := [];
        GetVisualProperties(x,y,st,false,false,false,Canvas.Brush, clr1, clr2, clr3, Canvas.Font,ha,va,ww,gd);

        if not HTMLDrawEx(Canvas,s,r,FImages,cp.x,cp.Y + scrl,-1,0,1,
                          True,False,False,False,False,False,not EnhTextSize,False,'',
                          0.0,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
                          XSize,YSize,ml,hl,hr,CR,CID,CV,CT,FImageCache,FContainer,self.Handle,BidiMode) then
          Anchor := '';
      end;

    if Anchor <> '' then
    begin
      Handle := True;

      CanEdit := ((goEditing in Options) or FEditDisable) and not ReadOnly[ox,oy];

      FCtrlDownId := CID;

      if (CID <> '') then
      begin
        //CanEdit := true;
        DoCanEditCell(ox,oy, CanEdit);
      end;

      if (CID <> '') and CanEdit then
      begin
        if FCtrlEditing then
        begin
          ControlExit(Self);
          s := Cells[rx,y];
        end;

        if CT = 'BUTTON' then
        begin
          FCtrlXY := Point(rx,y);
          FCtrlDown := True;
          RepaintCell(rx,y);
        end;

        if CT = 'CHECK' then
        begin
          if CV = 'TRUE' then
            SetControlValue(s,CID,'FALSE')
          else
            SetControlValue(s,CID,'TRUE');
          Cells[rx,y] := s;
        end;

        if CT = 'RADIO' then
        begin
          s := ClearRadioControls(s);
          SetControlValue(s,CID,'TRUE');
          Cells[rx,y] := s;
        end;

        if Assigned(FOnControlClick) then
          FOnControlClick(Self,y,x,CID,CT,CV);

        ControlEnter(S, CT, CID, CV, CR, x,rx,y);
        Handle := false;
      end
      else
      begin
        if Assigned(FOnAnchorClick) then
          FOnAnchorClick(Self,y,x,Anchor,Handle);
      end;

      if Handle then
        if  Pos('CELL://',Uppercase(Anchor)) > 0 then
        begin
          if NameToCell(Copy(Anchor,8,Length(Anchor)),cpt) then
          begin
            Row := cpt.y;
            Col := cpt.x;
            ScrollInView(cpt.x,cpt.y);
          end;
        end
        else
          ShellExecute(Application.Handle,'open',PChar(Anchor), nil, nil, SW_NORMAL);
        Exit;
    end;

    if (ctt = ttHTML) and (pos('<CONTROL',uppercase(s)) > 0) then
    begin
      DoClickCell(OY,OX);
      HideInplaceEdit;
      Selection := TGridRect(Rect(x,y,x,y));
      Exit;
    end;
  end;

  MoveCell := -1;

  if (x < FixedCols) and (y < FixedRows) and
     (FMouseActions.AllSelect) and
     (goRangeSelect in Options) and
     (FMouseSelectMode = msAll) then
  begin
    ORow := Selection.Top;
    OCol := Selection.Left;

    SetFocus; // make sure inplace editors are hidden

    // fix for TDBAdvGrid selection handling

    ExportNotification(esExportStart, -1);
    ExportNotification(esExportNewRow, RowCount - 1);
    ExportNotification(esExportFail, -1);

    HideSelection;

    GR := TGridRect(Rect(FixedCols,FixedRows,ColCount - 1,RowCount - 1));
    UpdateSelectionRect(GR);
    Selection := GR;
    FSelHidden := False;
    DoExit;   // force validatecell call
    if ActiveCellShow then
    begin
      UpdateActiveCells(OCol,ORow,x,y);
    end;
  end;

  if (x < FixedCols) and (y >= FixedRows) and
     (FMouseActions.RowSelect) and
     //(goRowSelect in Options) and
     (FMouseSelectMode = msRow) then
  begin
    ORow := Selection.Top;
    OCol := Selection.Left;

    if EditMode then
      SetFocus; // make sure inplace editors are hidden

    if MouseActions.DisjunctRowSelect and (GetKeystate(VK_CONTROL) and $8000 = $8000) then
    begin
      RowSelect[y] := not RowSelect[y];
    end
    else
    begin
      if MouseActions.DisjunctRowSelect and (GetKeystate(VK_CONTROL) and $8000 = 0) then
        ClearRowSelectInt;

      if FIsDBVersion then
      begin
        lc := LeftCol;
        Row := y;
        LeftCol := lc;
        Selection := TGridRect(Rect(FixedCols,y,ColCount - 1, y));
      end
      else
      begin
        HideSelection;

        if FMouseActions.DisjunctCellSelect then
          FSelectedCells.Clear;

        if GetKeystate(VK_SHIFT) and $8000 = $8000 then
        begin
          Selection := TGridRect(Rect(FixedCols,y,ColCount - 1, ORow));
        end
        else
        begin
          CanChange := true;
          if (y <> Row) and Assigned(FOnRowChanging) then
            FOnRowChanging(Self,ORow,y,Canchange);

          if CanChange then
            Selection := TGridRect(Rect(FixedCols,y,ColCount - 1, y));
        end;
      end;

      FSelHidden := False;
      DoExit;   // force validatecell call
      FMouseSelectStart := y;
    end;

    if ActiveCellShow then
      UpdateActiveCells(OCol,ORow,x,y);
    if not RowIndicator.Empty then
      Repaintcol(0);
  end;

  if (x >= FixedCols) and (y < FixedRows) and
     (FMouseActions.ColSelect) and
     (goRangeSelect in Options) and
     (FMouseSelectMode = msColumn) then
  begin
    OldSel := Selection; 

    ORow := Selection.Top;
    OCol := Selection.Left;

    SetFocus; //make sure inplace editors are hidden
    HideSelection;

    if FMouseActions.DisjunctCellSelect then
      FSelectedCells.Clear;

    if GetKeystate(VK_SHIFT) and $8000 = $8000 then
    begin
      if( x < OldSel.Left ) then begin
        Selection := TGridRect( Rect( x, FixedRows, OldSel.Right, RowCount - 1 ) );
      end
      else
      begin
        Selection := TGridRect(Rect(OCol,FixedRows,x,RowCount - 1));
      end;
    end
    else
      Selection := TGridRect(Rect(x,FixedRows,x,RowCount - 1));

    FSelHidden := False;
    DoExit;   //force validatecell call
    FMouseSelectStart := x;
    if ActiveCellShow then
      UpdateActiveCells(OCol,ORow,x,y);
  end;

  if (x >= FixedCols) and (y < FixedRows) then
    MoveCell := x;

  if (x < FixedCols) and (y >= FixedRows) then
    MoveCell := y;

  r := CellRect(x,y);

  MoveOfsx := Msg.xpos - r.Left;
  MoveOfsy := Msg.ypos - r.Top;

  CanEdit := (goEditing in Options) or (MouseActions.RangeSelectAndEdit);

  GetCellReadOnly(rx,y,CanEdit);

  israd := HasRadioButton(rx,y);

  if (x < ColCount) and (y < RowCount) and
     //(((x >= FixedCols) and
     (CanEdit or ControlLook.CheckAlwaysActive or ((x = 0) and MouseActions.HotMailRowSelect)) and
     ((y >= FixedRows) or (MouseActions.CheckAllCheck and not MouseActions.HotMailRowSelect) or (y < FixedRows)) and
     //( (x = 0) and (MouseActions.HotmailRowSelect))) and
     (HasCheckBox(rx,y) or israd) and IsInCheckBox(rx,y,Msg.XPos,Msg.YPos) then
  begin
    // hide any other possible active inplace editors

    if (goRowSelect in Options) and FNavigation.KeepHorizScroll then
      BeginUpdate;

    HideInplaceEdit;
    SetFocus;
    ry := RealRowIndex(y);

    if israd then
    begin
      ToggleRadioButton(rx,y,True);
      if Assigned(FOnRadioButtonClick) then
        FOnRadioButtonClick(Self, rx, y);
    end
    else
      ToggleCheck(rx,y,True);

    if ShowModified.Enabled then
    begin
      RowModified[y] := true;
      RepaintCell(0,y);
    end;

    if (x = 0) and (MouseActions.HotmailRowSelect) then
    begin
      Selection := TGridRect(Rect(FixedCols,y,ColCount -1, y));

      RowSelect[ry] := not RowSelect[ry];

      if (ry <> y) then
        RepaintCell(0,y);

      if (y = Row) and not RowSelect[ry] then
      begin
        HideSelection;
        FSelHidden := false;
      end;
    end;

    GetCheckBoxState(rx,ry,chk);

    // move focus to checkbox cell
    if not Navigation.AlwaysEdit and (y >= FixedRows) and (x >= FixedCols) then
      MoveColRow(x,y,True,True);

    DoCheckBoxClick(x,y,chk);

    if FHideFocusRect then
    begin
      RepaintCell(x,y);
    end;

    if (y < FixedRows) and (MouseActions.CheckAllCheck and MouseActions.HotmailRowSelect) then
    begin
      for i := FixedRows to RowCount - 1 do
      begin
        ry := RealRowIndex(i);
        RowSelect[ry] := chk;
      end;
      Invalidate;
    end;

    if (y < FixedRows) and (MouseActions.CheckAllCheck and not MouseActions.HotmailRowSelect) then
    begin
      rx := RealColIndex(x);
      for i := FixedRows to RowCount - 1 do
      begin
        //ry := RealRowIndex(i);
        SetCheckBoxState(rx,i,chk);
      end;
      Invalidate;
    end;

    if Assigned(OnMouseDown) then
      OnMouseDown(Self,mbLeft,KeyboardStateToShiftState,msg.XPos,msg.Ypos);

    Click;

    if (goRowSelect in Options) and FNavigation.KeepHorizScroll then
    begin
      LeftCol := OldLeftCol;
      EndUpdate;
    end;

    Exit;
  end;

  if (x >= FixedCols) and
     (y >= FixedRows) and ControlLook.DropDownAlwaysVisible then
  begin
    if HasEditBtn(rx,y) then
    begin
      if PtInrect(Rect(r.Right - ControlLook.DropDownButtonWidth - 2, r.Top, r.Right - 2, r.Bottom), Point(msg.XPos, msg.YPos)) then
      begin
        HideInplaceEdit;
        Col := X;
        Row := Y;
        ShowInplaceEdit;
        if Assigned(OnEllipsClick) then
        begin
          s := Cells[X,Y]; //BtnEdit.Text;
          OnEllipsClick(Self, X, Y, s);
          if (s <> BtnEdit.Text) and EditMode then
          begin
            BtnEdit.Text := s;
          end
          else
            Cells[X,Y] := s;
        end;
      end;
    end;
  end;

  if (x >= FixedCols) and
     (y >= FixedRows) and
     (CanEdit or (FMouseActions.EditOnDblClickOnly and comboincell)) and
     (FMouseActions.DirectEdit or (ControlLook.DropDownAlwaysVisible and comboincell)) then
  begin
    if (FMouseActions.EditOnDblClickOnly and comboincell) then
      FEditActive := false;

    HideInplaceEdit;
    SetFocus;
  end;

  r := CellRect(X,Y);
  ClickInSelect := PtInRect(r,Point(Msg.XPos,Msg.YPos));

  r.Left := BaseCell(X,Y).X;
  r.Top := BaseCell(X,Y).Y;
  r.Right := r.Left;
  r.Bottom := r.Top;

  ClickInSelect := ClickInSelect and EqualRect(TRect(Selection),r);

  if not ClickInSelect and MouseActions.RangeSelectAndEdit and not IsFixed(x,y) and not CanEdit then
  begin
    ForceSelect := true;
    Options := Options - [goEditing];
  end;

  FOldAlwaysEdit := FNavigation.AlwaysEdit;

  if FixCellClick then
  begin
    if  not ((y = RowCount - 1) and (FloatingFooter.Visible) and (FloatingFooter.FooterStyle = fsFixedLastRow)) then
    DoClickCell(Y,X);
    Exit;
  end;

  LastCellClicked := (Y = TopRow + VisibleRowCount) or (X = LeftCol + VisibleColCount) or ((X = LeftCol) and (LeftCol > FixedCols));

  if (goRowSelect in Options) and FNavigation.KeepHorizScroll then
    BeginUpdate;

  try
    if not FSelHidden then
    begin
      FNavigation.AlwaysEdit := False;
      inherited;
      FNavigation.AlwaysEdit := FOldAlwaysEdit;
    end;

    // block selecting state on partially visible clicked last row
    if (FGridState = gsSelecting) and LastCellClicked and FMouseActions.NoAutoRangeScroll then
    begin
      FGridState := gsnormal;
    end;

    if (TopRow <> OldTopRow) and FMouseActions.NoScrollOnPartialRow then
    begin
      TopRow := OldTopRow + FMouseActions.PartialScrollDelta;
      // stop further mouse processing
      SendMessage(self.Handle, WM_LBUTTONUP, 0,0);
    end;

    if (LeftCol <> OldLeftCol) and FMouseActions.NoScrollOnPartialCol then
    begin
      LeftCol := OldLeftCol + FMouseActions.PartialScrollDelta;
      // stop further mouse processing
      SendMessage(self.Handle, WM_LBUTTONUP, 0,0);
    end;

  finally
    if (goRowSelect in Options) and FNavigation.KeepHorizScroll then
    begin
      //StartUpdate;
      LeftCol := OldLeftCol;
      EndUpdate;
    end;
  end;

  if not (((msg.xpos - ClickRect.Left < 4) or (ClickRect.Right - msg.xpos < 4)) and (goColsizing in Options)) or (Y >= FixedRows) then
  begin
    DoClickCell(Y,X);
  end;

  if Assigned(FOnCellValidate) then
  begin
    FEntered := False;
    InitValidate(Col,Row);
  end;

  if IsMergedCell(X,Y) and not IsFixed(X,Y) then
  begin
    // merged cell selection changed to manipulate of Msg.X, Msg.Y
    (*
    CanChange := true;

    if (r.Left <> Col) or (r.Top <> Row) then
    begin
      if Assigned(OnCellChanging) then
        OnCellChanging(self, Row, Col, r.Top, r.Left, CanChange);
    end;

    if not CanChange then
      Exit;

    CanSelect := true;

    if (r.Left <> Col) or (r.Top <> Row) then
      if Assigned(OnSelectCell) then
        OnSelectCell(Self, r.Left, r.Top, CanSelect);

    if not (goRowSelect in Options) and CanSelect then
      Selection := TGridRect(Rect(r.Left,r.Top,r.Right,r.Bottom));
    *)
    if (ClickInSelect or MouseActions.DirectEdit) and CanEdit then
      ShowInplaceEdit;
  end;

  r := CellRect(x,y);

  if (Msg.XPos - R.Left) < 4 then
    Exit;

  if (R.Right - Msg.XPos) < 4 then
    Exit;

  if (x >= FixedCols) and
     (y >= FixedRows) and
     (CanEdit or (FMouseActions.EditOnDblClickOnly and comboincell)) and
     (FMouseActions.DirectEdit or (ControlLook.DropDownAlwaysVisible and CanEdit and comboincell)) and not HasStaticEdit(rx,y) then
     begin
       if FMouseActions.EditOnDblClickOnly and comboincell and not (goEditing in Options) then
       begin
         Options := Options + [goEditing];
         SetFocus;
       end;

       CanChange := true;

       if (x <> Col) and Assigned(FOnColChanging) then
         FOnColChanging(Self,Col,x,Canchange);
       if (y <> Row) and Assigned(FOnRowChanging) then
         FOnRowChanging(Self,Row,y,Canchange);

       if ((x <> Col) or (y <> Row)) and Assigned(FOnCellChanging) then
         FOnCellChanging(Self,Row,Col,y,x,CanChange);

       if CanChange then
       begin
         if IsBaseCell(ox,oy) then
         begin
           Selection := TGridRect(Rect(ox,oy,ox,oy));
           Initvalidate(ox,oy);
           ShowEditor;
         end
         else
         begin
           Selection := TGridRect(Rect(x,y,x,y));
           Initvalidate(x,y);
           ShowEditor;
         end;
       end;
     end;

//  FMouseActions.RangeSelectAndEdit := true;

  if ForceSelect then
  begin
    FGridState := gsSelecting;
  end;

end;

procedure TAdvStringGrid.ControlComboSelect(Sender: TObject);
begin
  if Assigned(FOnControlComboSelect) then
    FOnControlComboSelect(Self,FCtrlXY.Y, FCtrlXY.X, (Sender as TCustomComboBox).ItemIndex, FCtrlID, (Sender as TCustomComboBox).Items[(Sender as TCustomComboBox).ItemIndex]);
end;

procedure TAdvStringGrid.ControlEnter(S,CT,CID,CV: string; CR: TRect; X,RX,Y: Integer);
var
  ComboEdit: Boolean;
  DropHeight: Integer;
begin
  if (CT = 'EDIT') or (CT = 'PASSWORD') or (CT = 'MASK') then
  begin
    FCtrlXY := Point(rx,y);
    FCtrlID := CID;
    FCtrlType := CT;


    FCtrlEditing := True;
    FEditControl.Width := 0;

    if (CT = 'PASSWORD') then
      FEditControl.PasswordChar := '*'
    else
      FEditControl.PasswordChar := #0;

    if (CT = 'MASK') then
      FEditControl.EditMask := GetControlProp(s,CID)
    else
      FEditControl.EditMask := '';

    FEditControl.OnExit := ControlExit;
    FEditControl.Text := CV;
    FEditControl.BorderStyle := bsNone;
    FEditControl.Left := CR.Left + 1;
    FEditControl.Width := CR.Right - CR.Left - 4;
    FEditControl.Top := CR.Top + 8;
    FEditControl.Height := 14;
    FEditControl.MaxLength := GetControlMaxLen(s,CID);
    FEditControl.Parent := Self;
    FEditControl.Visible := True;

    BringWindowToTop(FEditControl.Handle);
    FEditControl.SetFocus;
  end;

  if CT = 'COMBO' then
  begin
    FCtrlXY := Point(rx,y);
    FCtrlID := CID;
    FCtrlType := CT;

    FCtrlEditing := True;

    FComboControl.IsWinXP := FIsWinXP;
    FComboControl.Width := 0;

    ComboEdit := True;
    DropHeight := 8;

    FComboControl.Flat := false;
    FComboControl.Left := CR.Left - 1;
    FComboControl.Width := CR.Right - CR.Left;
    FComboControl.Top := CR.Top + 4;

    {$IFDEF DELPHI7_LVL}
    FComboControl.OnSelect := ControlComboSelect;
    {$ENDIF}

    FComboControl.Parent := Self;

    if Assigned(FOnControlComboList) then
      FOnControlComboList(Self,y,x,CID,CT,CV,TStringList(FComboControl.Items),ComboEdit,DropHeight);

    if ComboEdit then
      FComboControl.Style := csDropDown
    else
      FComboControl.Style := csDropDownList;

    if FComboControl.Items.IndexOf(CV) <> -1 then
      FComboControl.ItemIndex := FComboControl.Items.IndexOf(CV);

    FComboControl.Text := CV;
    FComboControl.DropDownCount := DropHeight;

    FComboControl.OnExit := ControlExit;

    FComboControl.Height := FComboControl.ItemHeight * (DropHeight + 2);
    FComboControl.MaxLength := GetControlMaxLen(s,CID);

    FComboControl.Visible := True;
    FComboControl.DroppedDown := True;
    FComboControl.SetFocus;
    // BringWindowToTop(FComboControl.Handle);
  end;
end;

procedure TAdvStringGrid.ControlExit(Sender: TObject);
var
  s,CV:string;
begin
  if not FCtrlEditing then
    Exit;

  FCtrlEditing := false;

  if (FCtrlType = 'EDIT') or (FCtrlType = 'PASSWORD') or (FCtrlType = 'MASK') then
  begin
    s := Cells[FCtrlXY.X,FCtrlXY.Y];
    CV := FEditControl.Text;
    SetControlValue(s,FCtrlID,CV);
    Cells[FCtrlXY.X,FCtrlXY.Y] := s;
    FEditControl.Visible := False;
  end;

  if FCtrlType = 'COMBO' then
  begin
    s := Cells[FCtrlXY.X,FCtrlXY.Y];
    CV := FComboControl.Text;
    SetControlValue(s,FCtrlID,CV);
    Cells[FCtrlXY.X,FCtrlXY.Y] := s;
    FComboControl.Visible := False;
  end;

  if Assigned(FOnControlEditDone) then
    FonControlEditDone(Self,FCtrlXY.Y,FCtrlXY.X,FCtrlID,FCtrlType,CV);

  FCtrlType := '';
end;


function TAdvStringGrid.Compare(Col,ARow1,ARow2: Integer;sd: TSortDirection): Integer;
var
  AStyle: TSortStyle;
  r1,r2: Double;
  code1,code2: Integer;
  dt1,dt2: TDateTime;
  res,sp: Integer;
  s1,s2: string;
  Prefix,Suffix: string;
  cs1,cs2: Boolean;
  {$IFDEF TMSUNICODE}
  ws1,ws2: widestring;
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
  pws1,pws2: array[0..1023] of WideChar;
  {$ENDIF}

begin
  Inc(Compares);

  if FSortSettings.AutoFormat then
    aStyle := ssAutomatic
  else
  begin
    if FSortSettings.IgnoreCase then
      aStyle := ssAlphaNoCase
    else
      aStyle := FSortSettings.DefaultFormat;
  end;

  Prefix := '';
  Suffix := '';

  GetColFormat(Col,AStyle,Prefix,Suffix);

  res := 1;

  if not SortSettings.SortOnVirtualCells then
  begin
    s1 := GridCells[Col,ARow1];
    s2 := GridCells[Col,ARow2];
  end
  else
  begin
    s1 := Cells[Col,ARow1];
    s2 := Cells[Col,ARow2];
  end;

  if AStyle = ssAutomatic then
  begin
    if (CellTypes[Col,ARow1] in [ctCheckBox, ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox]) then
      aStyle := ssCheckBox
    else
    begin
      if (IsType(s1) in [AdvUtil.atNumeric,AdvUtil.atFloat,AdvUtil.atScientific]) then
        aStyle := ssNumeric
      else
      begin
        if FSortSettings.IgnoreCase then
          aStyle := ssAlphaNoCase
        else
          aStyle := ssAlphabetic;
          
        code1 := pos(DateSeparator,s1);
        if (code1 > 1) and (Length(s1) > code1) and (code1 < 4) then
        begin
          if (CheckNum(s1[code1 - 1]) and CheckNum(s1[code1 + 1])) and (pos(DateSeparator, s2) > 0) then
          begin
            {$IFDEF DELPHI7_LVL}
            if (pos(TimeSeparator,s1) > 0) then
              aStyle := ssDateTime
            else
            {$ENDIF}
              aStyle := ssDate
          end;
        end
        else
        begin
          {$IFDEF DELPHI7_LVL}
          code1 := pos(TimeSeparator,s1);
          if (code1 > 1) and (Length(s1) > code1) and (code1 < 4) then
          begin
            if (CheckNum(s1[code1 - 1]) and CheckNum(s1[code1 + 1])) and (pos(TimeSeparator, s2) > 0) then
              aStyle := ssTime;
          end
          {$ENDIF}
        end;
      end;
    end;
  end;

  if (AStyle in [ssAlphaNumeric, ssAlphaNumericNoCase]) then
  begin
    if (IsType(s1) in [AdvUtil.atNumeric,AdvUtil.atFloat,AdvUtil.atScientific]) and
       (IsType(s2) in [AdvUtil.atNumeric,AdvUtil.atFloat,AdvUtil.atScientific]) then
      AStyle := ssNumeric
    else
    begin
      if AStyle = ssAlphaNumeric then
        AStyle := ssAlphabetic
      else
        AStyle := ssAlphaNoCase;
    end;
  end;

  case aStyle of
  ssAlphabetic,ssAlphaCase:
  begin
    (*
    CompareString(LOCALE_USER_DEFAULT, 0 , PWideChar(Cells[Col,ARow1]), length(Cells[Col,ARow1]),
      PWideChar(Cells[Col,ARow2]), length(Cells[Col,ARow2]));

    if res = CSTR_LESS_THAN then res := -1;
    if res = CSTR_EQUAL then res := 0;
    if res = CSTR_GREATER_THAN then res := 1;
    *)

    if (s1 > s2) then
      res := 1
    else
      if (s1 = s2) then
        res := 0
      else
        res := -1;
  end;

  ssNatural:
  begin
  {$IFDEF DELPHI_UNICODE}
    res := StrCmpLogicalW(PWideChar(s1),PWideChar(s2));
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
    StringToWideChar(s1,pws1,SizeOf(pws1));
    StringToWideChar(s2,pws2,SizeOf(pws2));
    res := StrCmpLogicalW(pws1,pws2);
  {$ENDIF}
  end;

  {$IFDEF TMSUNICODE}
  ssUnicode:
  begin
    ws1 := WideCells[Col,ARow1];
    ws2 := WideCells[Col,ARow2];

    res := CompareStringW(LOCALE_USER_DEFAULT ,NORM_IGNORECASE,PWideChar(ws1),Length(ws1),
      PWideChar(ws2),Length(ws2));
    if res = CSTR_LESS_THAN then res := -1;
    if res = CSTR_EQUAL then res := 0;
    if res = CSTR_GREATER_THAN then res := 1;

  end;
  {$ENDIF}
  ssHTML:
  begin
    s1 := StrippedCells[Col,ARow1];
    s2 := StrippedCells[Col,ARow2];

    if s1 > s2 then
      res := 1
    else
     if s1 = s2 then
       res := 0
     else
       res := -1;
  end;
  ssImages:
  begin
    if GetCellImageIdx(Col,ARow1)>GetCellImageIdx(Col,ARow2) then
      res := 1
    else
      if GetCellImageIdx(Col,ARow1) = GetCellImageIdx(Col,ARow2) then
        res := 0
      else
        res := -1;
  end;
  ssCheckBox:
  begin
    GetCheckBoxState(Col,ARow1,cs1);
    GetCheckBoxState(Col,ARow2,cs2);
    if cs1 and not cs2 then
      res := 1
    else
      if cs1 = cs2 then
        res := 0
      else
        res := -1;
  end;
  ssAlphaNoCase:
  begin
    s1 := UpperCase(s1);
    s2 := UpperCase(s2);

    if s1 > s2 then
      res := 1
    else
      if s1 = s2 then
        res := 0
      else
        res := -1;
  end;
  ssAnsiAlphaCase:
  begin
    res := AnsiCompareStr(s1,s2);
    if res > 0 then
      res := 1
    else
      if res < 0 then
        res := -1;
  end;
  ssAnsiAlphaNoCase:
  begin
    res := AnsiCompareText(s1,s2);
    if res > 0 then
      res := 1
    else
      if res < 0 then
        res := -1;
  end;
  ssNumeric,ssFinancial:
  begin
    if Suffix <> '' then
    begin
     if VarPos(Suffix,s1,sp) > 0 then
       Delete(s1,sp,Length(Suffix));
     if VarPos(Suffix,s2,sp) > 0 then
       Delete(s2,sp,Length(Suffix));
    end;

    if Prefix <> '' then
    begin
      if VarPos(Prefix,s1,sp) > 0 then
        Delete(s1,sp,Length(Prefix));
      if VarPos(Prefix,s2,sp) > 0 then
        Delete(s2,sp,Length(Prefix));
    end;

    if AStyle = ssFinancial then
    begin
      {delete the thousandseparator}
      while VarPos(ThousandSeparator,s1,sp) > 0 do
        Delete(s1,sp,1);
      while VarPos(ThousandSeparator,s2,sp) > 0 do
        Delete(s2,sp,1);
    end;

    if DecimalSeparator <> '.' then
    begin
      if Varpos(Decimalseparator,s1,sp) > 0 then
        s1[sp] := '.';
      if VarPos(DecimalSeparator,s2,sp) > 0 then
        s2[sp] := '.';
    end;

    try
      Val(s1,r1,code1);
    except
      r1 := 0;
    end;

    try
      Val(s2,r2,code2);
    except
      r2 := 0;
    end;

    if code1 <> 0 then
    begin
      if Cells[Col,ARow1] = '' then
      begin
        r1 := 0;
        code1 := 0;
      end;
    end;

    if code2 <> 0 then
    begin
      if Cells[Col,ARow2] = '' then
      begin
        r2 := 0;
        code2 := 0;
      end;
    end;

    if (code1 <> 0) and (code2 <> 0) then
      res := 0
    else
    begin
      if r1 > r2 then
        res := 1
      else
       if r1 = r2 then
         res := 0
       else
         res := -1;
    end;
  end;

  ssCustom:
  begin
    res := 0;
    if Assigned(FCustomCompare) then
      FCustomCompare(Self,s1,s2,res);
  end;

  ssRaw:
  begin
    res := 0;
    if Assigned(FRawCompare) then
      FRawCompare(self,Col,ARow1,ARow2,res);
  end;

  {$IFDEF DELPHI7_LVL}
  ssTime:
  begin
    try
      dt1 := StrToTime(s1);
    except
      dt1 := 0;
    end;
    try                                   
      dt2 := StrToTime(s2);
    except
      dt2 := 0;
    end;    
    if dt1 > dt2 then
      res := 1
    else
      if dt1 = dt2 then
        res := 0
      else
       res := -1;
  end;
  ssDateTime:
  begin
    dt1 := 0;
    dt2 := 0;

    if (s1 <> '') then
    begin
      try
        dt1 := StrToDateTime(s1);
      except
        dt1 := 0;
      end;
    end;

    if (s2 <> '') then
    begin
      try
        dt2 := StrToDateTime(s2);
      except
        dt2 := 0;
      end;
    end;

    if dt1 > dt2 then
      res := 1
    else
      if dt1 = dt2 then
        res := 0
      else
       res := -1;
  end;

  {$ENDIF}

  ssDate,ssShortdateUS,ssShortDateEU:
  begin
    dt1 := 0;
    dt2 := 0;

    case aStyle of
    ssDate:
    begin
      try
        if s1 = '' then
          dt1 := 0
        else
          dt1 := StrToDatetime(s1);
      except
        dt1 := 0;
      end;
      try
        if s2 = '' then
          dt2 := 0
        else
          dt2 := StrToDatetime(s2);
      except
        dt2 := 0;
      end;

    end;
    ssShortDateUS:
    begin
      try
        dt1 := StrToShortDateUS(s1);
      except
        dt1 := 0;
      end;
      try
        dt2 := StrToShortDateUS(s2);
      except
        dt2 := 0;
      end;
    end;
    ssShortDateEU:
    begin
      try
        dt1 := StrToShortDateEU(s1);
      except
        dt1 := 0;
      end;
      try
        dt2 := StrToShortDateEU(s2);
      except
        dt2 := 0;
      end;
    end;
    end;

    if dt1 > dt2 then
      res := 1
    else
      if dt1 = dt2 then
        res := 0
      else
       res := -1;
    end;
  end;

  if FSortSettings.IgnoreBlanks then
  begin
//    case FSortSettings.Direction of
    case sd of
    sdAscending:
      begin
        if (s1 = '') and (s2 <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := -1
          else
            res := +1;

        if (s2 = '') and (s1 <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := +1
          else
            res := -1;

      end;
    sdDescending:
      begin
        if (s1 = '') and (s2 <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := +1
          else
            res := -1;

        if (s2 = '') and (s1 <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := -1
          else
            res := +1;

      end;
    end;
  end;

  Compare := res;
end;

function TAdvStringGrid.CompareLine(Col,ARow1,ARow2: Integer): Integer;
var
  res: Integer;
begin
  if IsIgnoredColumn(Col) then
    res := 0
  else
    res := Compare(Col,ARow1,ARow2,SortSettings.Direction);

  if (res = 0) and FSortSettings.Full then
  begin
    if Col <= ColCount - 2 then
    begin
      Inc(Col);
      res := CompareLine(Col,ARow1,ARow2);
    end;
  end;

  CompareLine := res;
end;

function TAdvStringGrid.CompareLineIndexed(Colidx,ARow1,ARow2: Integer): Integer;
var
  res: Integer;
  idx: Integer;
  sd: TSortDirection;
begin
  idx := FSortIndexes.Items[Colidx] and $7FFFFFFF;

  if (FSortIndexes.Items[Colidx] and $80000000 = $80000000) then
    sd := sdDescending
  else
    sd := sdAscending;

  if IsIgnoredColumn(idx) then
    res := 0
  else
    res := Compare(idx,ARow1,ARow2, sd);

  if (res = 0) and FSortSettings.Full then
  begin
    if (Colidx < FSortIndexes.Count - 1) then
    begin
      Inc(Colidx);
      res := CompareLineIndexed(Colidx,ARow1,ARow2);
    end;
  end
  else
  begin
    if (FSortIndexes.Items[Colidx] and $80000000 = $80000000) then
    begin
      res := res * -1;
    end;
  end;

  CompareLineIndexed := res;
end;


function TAdvStringGrid.ColumnType(Col: integer): TColumnType;
var
  typ1,typ2: AdvUtil.TAutoType;
  cb1,cb2: boolean;
begin
  Result := ctAlpha;

  typ1 := IsType(Cells[Col,FixedRows]);
  typ2 := IsType(Cells[Col,FixedRows + 1]);

  cb1 := HasCheckBox(Col,FixedRows);
  cb2 := HasCheckBox(Col,FixedRows + 1);

  if typ1 = typ2 then
  begin
    case typ1 of
    AdvUtil.atNumeric: Result := ctNumeric;
    AdvUtil.atFloat: Result := ctFloat;
    AdvUtil.atString: Result := ctAlpha;
    AdvUtil.atDate: Result := ctDate;
    AdvUtil.atTime: Result := ctTime;
    end;
  end;

  if (cb1 = cb2) and cb1 then
    Result := ctBoolean;
end;


function TAdvStringGrid.SortLine(Col,ARow1,ARow2: Integer): Boolean;
var
  res: Integer;
begin
  Result := False;

  res := Compare(Col,ARow1,ARow2, SortSettings.Direction);

  if res = SortDir then
  begin
    SortSwapRows(ARow1,ARow2);
    Result := True;
  end
  else
    if res = 0 then
    begin
      if Col < ColCount - 1 + NumHiddenColumns then
      begin
        Inc(Col);
        Result := SortLine(Col,ARow1,ARow2);
      end;
    end
    else
      Result := False;
end;

procedure TAdvStringGrid.SortByColumn(Col: Integer);
begin
  if RowCount < 2 then
    Exit;

  SortSettings.Column := Col;
  QSort;
end;

procedure TAdvStringGrid.QuickSortRows(Col,Left,Right: Integer);
var
  i,j,k,m,sr: Integer;

begin
  if FSortSettings.Direction = sdAscending then
    SortDir := 1
  else
    SortDir := -1;

  i := Left;
  j := Right;
  m := (Left + Right) shr 1;

  if Assigned(OnGetDisplText) or FVirtualCells then
  begin
    for k := 0 to ColCount - 1 do
    begin
      if not SortSettings.SortOnVirtualCells then
        GridCells[k, RowCount - 2] := GridCells[k,m]
      else
        Cells[k, RowCount - 2] := Cells[k,m];

      GridObjects[k, RowCount - 2] := GridObjects[k,m];
    end;
  end
  else
    Rows[RowCount - 2] := Rows[m];

  if SortSettings.SortOnVirtualCells and Assigned(OnGetDisplText) and Assigned(OnRawCompare) then
    sr := m
  else
    sr := RowCount - 2;

  repeat
    while (CompareLine(Col,sr,i) = SortDir) and (i < Right) do Inc(i);
    while (CompareLine(Col,j,sr) = SortDir) and (j > Left) do Dec(j);

    if i <= j then
    begin
      if i <> j then
      begin
        if CompareLine(Col,i,j) <> 0 then
          SortSwapRows(i,j);
      end;
      Inc(i);
      Dec(j);
    end;
  until i > j;

  if Left < j then
    QuickSortRows(Col,Left,j);
  if i < Right then
    QuickSortRows(Col,i,Right);
end;

procedure TAdvStringGrid.QuickSortRowsRef(Col,Left,Right: Integer);
var
  i,j,m,n,mid: Integer;

begin
  i := Left;
  j := Right;
  m := (Left + Right) div 2;
  mid := FUnSortRowXRef[m];

  repeat
    while (FUnSortRowXRef.Items[i] < mid) and (i < Right) do Inc(i);
    while (FUnSortRowXRef.Items[j] > mid) and (j > Left) do Dec(j);

    if i <= j then
    begin
      if i <> j then
      begin
        if FUnSortRowXRef.Items[j] <> FUnSortRowXRef.Items[i] then
        begin
          SortSwapRows(i,j);
          n := FUnSortRowXRef.Items[i];
          FUnSortRowXRef.Items[i] := FUnSortRowXRef.Items[j];
          FUnSortRowXRef.Items[j] := n;
        end;
      end;
      Inc(i);
      Dec(j);
    end;
  until i > j;

  if Left < j then
    QuickSortRowsRef(Col,Left,j);
  if i < Right then
    QuickSortRowsRef(Col,i,Right);
end;



procedure TAdvStringGrid.QuickSort(Col,Left,Right: Integer);
var
  cw,cc: Integer;
begin
  RowCount := RowCount + 3;

  //necessary to save this due to Delphi 1,2,3 bug in TStringGrid!
  cc := ColCount - 1;
  cw := ColWidths[cc];

  ColCount := ColCount + NumHiddenColumns;

  QuickSortRows(Col,left,right);
  FNilObjects := True;
  ClearRows(RowCount - 2,2);
  FNilObjects := False;

  ColCount := ColCount - NumHiddenColumns;
  ColWidths[cc] := cw;
  RowCount := RowCount - 3;
end;

procedure TAdvStringGrid.QuickSortRowsIndexed(Col,Left,Right: Integer);
var
  i,j,k,m: Integer;
begin
  if FSortSettings.Direction = sdAscending then
    SortDir := 1
  else
    SortDir := -1;

  i := Left;
  j := Right;
  m := (Left + Right) shr 1;

  if Assigned(OnGetDisplText) or FVirtualCells then
  begin
    for k := 0 to ColCount - 1 do
    begin
      if not SortSettings.SortOnVirtualCells then
        GridCells[k, RowCount - 2] := GridCells[k,m]
      else
        Cells[k, RowCount - 2] := Cells[k, m];
      GridObjects[k, RowCount - 2] := GridObjects[k, m];
    end;
  end
  else
    Rows[RowCount - 2] := Rows[m];

  repeat
    while (CompareLineIndexed(Col,RowCount - 2,i) = 1) and (i < Right) do Inc(i);
    while (CompareLineIndexed(Col,j,RowCount - 2) = 1) and (j > Left) do Dec(j);
    if i <= j then
    begin
      if i <> j then
        SortSwapRows(i,j);
      Inc(i);
      Dec(j);
    end;
  until i > j;

  if Left < j then
    QuicksortRowsIndexed(Col,Left,j);
  if i < Right then
    QuickSortRowsIndexed(Col,i,Right);
end;


procedure TAdvStringGrid.QuickSortIndexed(Left,Right: Integer);
var
  cw,cc: Integer;

begin
  RowCount := RowCount + 3;
  //necessary to save this due to Delphi 1,2,3 bug in TStringGrid!
  cc := ColCount - 1;
  cw := ColWidths[cc];

  ColCount := ColCount + NumHiddenColumns;

  QuickSortRowsIndexed(0, Left, Right);

  FNilObjects := true;
  ClearRows(RowCount - 2,2);
  FNilObjects := false;

  ColCount := ColCount - NumHiddenColumns;
  ColWidths[cc] := cw;
  RowCount := RowCount - 3;
end;


procedure TAdvStringGrid.QUnSort;
var
  i,cc,cw: Integer;
  FCols: TStringList;

begin
  cc := 0;
  cw := 0;

  FUnSortRowXRef.Clear;

  for i := 1 to FSortRowXRef.Count do
    FUnSortRowXRef.Add(FSortRowXRef.Items[i - 1]);

  FCols := nil;
  if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
  begin
    FCols := TStringList.Create;
    FCols.Assign(self.Cols[0]);
  end;

  BeginUpdate;

  try
    cc := ColCount - 1;
    cw := ColWidths[cc];
    ColCount := ColCount + NumHiddenColumns;
    QuickSortRowsRef(0,0,RowCount - 1);

    if SortSettings.IndexShow then
      SortIndexes.Clear;

  finally
    ColCount := ColCount - NumHiddenColumns;
    ColWidths[cc] := cw;
    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(FCols);
      FCols.Free;
    end;
    EndUpdate;
  end;
end;


procedure TAdvStringGrid.QSortGroupIndexed;
begin
  QSortGroupInt(true);
end;

procedure TAdvStringGrid.QSortGroup;
begin
  QSortGroupInt(false);
end;

procedure TAdvStringGrid.QSortGroupInt(Indexed: boolean);
var
  i,r1,r2: Integer;
  cw,cc,cr: Integer;
  FCols: TStringList;
  lvl, nlvl,mr: integer;
  tr: Integer;
  clrflg,cto: boolean;
begin
  if FSortRowXRef.Count <> RowCount then
    InitSortXRef;

  FCols := nil;

  if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
  begin
    FCols := TStringList.Create;
    FCols.Assign(self.Cols[0]);
  end;

  tr := TopRow;
  cto := ClearTextOnly;
  ClearTextOnly := false;

  BeginUpdate;

  mr := FMaxRowCount;

  try
    clrflg := FMaxRowCount - NumHiddenRows > RowCount;

    RowCount := RowCount + 3;

    if clrflg then
      ClearRows(RowCount - 3,3 - FFixedFooters);

    NormalRowCount := RowCount - 3;

    //necessary to save this due to Delphi 1,2,3 bug in TStringGrid!
    cc := ColCount - 1;
    cw := ColWidths[cc];

    ColCount := ColCount + NumHiddenColumns;

    // store currently selected row
    SortRow := Row;
    cr := Row;

    if FNavigation.MoveRowOnSort then
      Row := RowCount - 3;

    // determine max. node deepness
    lvl := 0;

    for i := FixedRows to RowCount - FixedFooters - 3 do
    begin
      if IsNode(i) then
      begin
        nlvl := GetNodeLevel(i);
        if nlvl > lvl then
          lvl := nlvl;
      end;
    end;

    for i := FixedRows to RowCount - FixedFooters - 3 do
    begin
      if IsNode(i) and not GetNodeState(i) and (GetNodeLevel(i) = lvl)  then
      begin
        r1 := i + 1;
        r2 := i + GetNodeSpan(i);
        if r2 - r1 > 1 then
          if Indexed then
            QuickSortIndexed(r1,r2 -1 )
          else
            QuickSortRows(FSortSettings.Column,r1,r2 -1 );
      end;
    end;

    //set all added Rows back to Nil}
    FNilObjects := True;
    ClearRows(RowCount - 3,3 - FixedFooters);
    FNilObjects := False;

    // restore row
    if FNavigation.MoveRowOnSort then
    begin
      Row := SortRow;
      FOldRowSel := -1;
    end
    else
      Row := cr;

    ColCount := ColCount - NumHiddenColumns;
    ColWidths[cc] := cw;
  finally
    RowCount := RowCount - 3;
    FMaxRowCount := mr;

    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(FCols);
      FCols.Free;
    end;

    if FNavigation.KeepScrollOnSort then
      TopRow := tr;

    ClearTextOnly := cto;

    EndUpdate;
  end;
end;

procedure TAdvStringGrid.Sort(Column: integer; Direction: TSortDirection = sdAscending);
begin
  SortSettings.Column := Column;
  SortSettings.Direction := Direction;
  QSort;
  if FControlList.Count > 0 then
    CellControlsUpdate(true);
end;

procedure TAdvStringGrid.QSort;
var
  cw,cc,cr,mr: Integer;
  enterstate: Boolean;
  FCols: TStringList;
  tr,iff: Integer;
  ff,clrflg,cto: boolean;

begin
  if FSortSettings.Column < 0 then
    Exit;

  if FSortRowXRef.Count <> RowCount then
    InitSortXRef;

  //clear previous sort indexes if QSortIndexed was executed before
  SortIndexes.Clear;

  FCols := nil;
  if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
  begin
    FCols := TStringList.Create;
    FCols.Assign(self.Cols[0]);
  end;

  tr := TopRow;
  cto := ClearTextOnly;
  ClearTextOnly := false;

  BeginUpdate;

  // exclude floating footer
  ff := FloatingFooter.Visible;
  iff := FixedFooters;
  FloatingFooter.Visible := false;

  mr := FMaxRowCount;
  cr := Row;

  try
    clrflg := FMaxRowCount - NumHiddenRows > RowCount;
    RowCount := RowCount + 3;

    if clrflg then
    begin
      FNilObjects := true;
      ClearRows(RowCount - 3,3 - FFixedFooters);
      FNilObjects := false;
    end;

    NormalRowCount := RowCount - 3;

    //necessary to save this due to Delphi 1,2,3 bug in TStringGrid!
    cc := ColCount - 1;
    cw := ColWidths[cc];

    ColCount := ColCount + NumHiddenColumns;
    SortRow := Row;

    if FNavigation.MoveRowOnSort and not MouseActions.DisjunctRowSelect then
      Row := RowCount - 4;

    QuickSortRows(FSortSettings.Column,FixedRows,(RowCount - 1) - 3 - iff);

    FNilObjects := True;
    FBlockCellChange := True;
    try
      ClearRows(RowCount - 3,3 - FFixedFooters);
    finally
      FBlockCellChange := False;
      FNilObjects := False;
    end;

    Enterstate := FEntered;
    FEntered := False;

    if not MouseActions.DisjunctRowSelect then
    begin
      if FNavigation.MoveRowOnSort then
      begin
        Row := SortRow;
        FOldRowSel := -1;
      end
      else
      begin
        if (cr >= FixedRows) and (cr < RowCount - 1 - FixedFooters) then
          Row := cr;
      end;
    end;

    FEntered := Enterstate;

    ColCount := ColCount - NumHiddenColumns;
    ColWidths[cc] := cw;

  finally
    RowCount := RowCount - 3;
    FMaxRowCount := mr;

    if Assigned(FOnRowChanged) and not Navigation.MoveRowOnSort then
      FOnRowChanged(Self,cr,Row);

    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(fCols);
      FCols.Free;
    end;

    if FNavigation.KeepScrollOnSort then
      TopRow := tr;

    FloatingFooter.Visible := ff;
    FixedFooters := iff;
    ClearTextOnly := cto;

    EndUpdate;

    if ff then
      FFooterPanel.Repaint;

    if SearchFooter.Visible then
    begin
      if SearchPanel.Visible then
        SearchPanel.Repaint;
    end;

  end;
end;

procedure TAdvStringGrid.QSortIndexed;
var
  cw,cc,cr,mr: Integer;
  enterstate: Boolean;
  FCols: TStringList;
  tr,iff: integer;
  clrflg,ff: boolean;

begin
  if FSortRowXRef.Count <> RowCount then
    InitSortXRef;

  if SortIndexes.Count = 0 then
    raise EAdvGridError.Create('No indexes specified for indexed sort');

  FCols := nil;
  if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
  begin
    FCols := TStringList.Create;
    FCols.Assign(self.Cols[0]);
  end;

  tr := TopRow;

  BeginUpdate;

  // exclude floating footer
  ff := FloatingFooter.Visible;
  iff := FixedFooters;
  FloatingFooter.Visible := false;
  mr := FMaxRowCount;

  try
    clrflg := FMaxRowCount - NumHiddenRows > RowCount;

    RowCount := RowCount + 3;

    if clrflg then
    begin
      FNilObjects := true;
      ClearRows(RowCount - 3,3 - FFixedFooters);
      FNilObjects := false;
    end;

    NormalRowCount := RowCount - 3;

    //necessary to save this due to Delphi 3 bug in TStringGrid!
    cc := ColCount - 1;
    cw := ColWidths[cc];

    ColCount := ColCount + NumHiddenColumns;
    SortRow := Row;
    cr := Row;

    if FNavigation.MoveRowOnSort then
      Row := RowCount - 3;

    QuickSortRowsIndexed(0,FixedRows,(RowCount - 1) - 3 - iff);

    FNilObjects := True;
    ClearRows(RowCount - 3,3 - FFixedFooters);
    FNilObjects := False;

    EnterState := FEntered;
    FEntered := False;

    if FNavigation.MoveRowOnSort then
    begin
      Row := SortRow;
      FOldRowSel := -1;
    end
    else
      Row := cr;

//    Row := SortRow;

    FEntered := EnterState;

    ColCount := ColCount - NumHiddenColumns;
    ColWidths[cc] := cw;
  finally
    RowCount := RowCount - 3;
    FMaxRowCount := mr;
    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(fCols);
      FCols.Free;
    end;

    if FNavigation.KeepScrollOnSort then
      TopRow := tr;

    FloatingFooter.Visible := ff;
    FixedFooters := iff;

    EndUpdate;

    if ff then
      FFooterPanel.Repaint;
  end;
end;

procedure TAdvStringGrid.InitSortXRef;
var
  i: Integer;
begin
  FSortRowXRef.Clear;
  for i := 0 to RowCount - 1 do
  begin
    FSortRowXRef.Add(i);
  end;
end;

procedure TAdvStringGrid.RemoveRowList(RowList: TIntList);
var
  i,j,k: integer;
  il: TIntList;
begin
  il := TIntList.Create(-1,-1);

  // save row heights
  for i := 1 to RowCount do
    il.Add(RowHeights[i - 1]);

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  j := 0;
  k := 0;
  for i := 0 to RowCount - 1 do
  begin
    // found a row to hide
    if (k < RowList.Count) and (i = RowList.Items[k]) then
    begin
      inc(k);
    end
    else
    begin
      if (i <> j) then
      begin
        Rows[j].Assign(Rows[i]);
        RowHeights[j] := il.Items[i];
      end;
      inc(j);
    end;
  end;

  RowCount := RowCount - RowList.Count;

  il.Free;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  CellControlsUpdate;
end;


procedure TAdvStringGrid.RemoveRowsEx(RowIndex, RCount : Integer);
var
  i,j,cw,cr: Integer;
  tr: Integer;

begin
  cw := ColWidths[ColCount - 1];
  cr := Row;
  tr := TopRow;

  BeginUpdate;

  try
    ColCount := ColCount + FNumHidden;

    // Move all rows down
    for i := RowIndex to RowCount - 1 do
    begin
      if (i + RCount < RowCount) then
        Rows[i] := Rows[i + RCount];
    end;

    for i := 1 to RCount do
    begin
      // v3.0 change ----
      //DeleteRow(RowIndex);
      if FMouseActions.DisjunctRowSelect and (FRowSelect.Count > RowIndex) then
      begin
         FRowSelect.Delete(RowIndex);
      end;
    end;

    // v3.0 change ++++
    RowCount := RowCount - RCount;

    FMaxRowCount := FMaxRowCount - RCount;


  //  for i := RowIndex to RowCount - 1 do
  //    RowHeights[i] := RowHeights[i + RCount];
  //  RowCount := RowCount - RCount;

    ColCount := ColCount - FNumHidden;
    ColWidths[ColCount-1] := cw;

    if cr < RowCount then
    begin
      Row := cr;
      TopRow := tr;
    end
    else
    begin
      if FixedRows < RowCount then
      begin
        Row := FixedRows;
        TopRow := FixedRows;
      end;
    end;

  finally
    EndUpdate;
  end;  

  for j := 1 to FGriditems.Count do
  begin
    if (FGriditems.Items[j - 1] as TGridItem).Idx > RowIndex + RCount - 1 then
      (FGriditems.Items[j - 1] as TGridItem).Idx := (FGriditems.Items[j - 1] as TGridItem).Idx - 1;
  end;

  CellsChanged(Rect(0,RowIndex,ColCount-1,RowIndex + RCount));
end;

procedure TAdvStringGrid.RemoveCheckedRows(CheckBoxColumn: integer; RemoveChecked: boolean=true);
var
  i: integer;
begin
  i := RowCount - 1;

  BeginUpdate;

  while (i >= FixedRows) do
  begin
    if IsChecked(CheckBoxColumn,i) XOR (not RemoveChecked) then
      RemoveRows(i,1);
    dec(i);
  end;

  EndUpdate;
end;

procedure TAdvStringGrid.RemoveRows(RowIndex, RCount : Integer);
var
  i: Integer;
  cc,cw,cr: Integer;
  tr: Integer;
  enterstate, fv: Boolean;
  ff: Integer;
  RRIndex: Integer;
  ci: TControlItem;
  djrs: boolean;
  FHideLast: boolean;

begin
  // Nothing to do ...
  if (RowIndex > RowCount) or (RCount <= 0) then
    Exit;

  for i := 1 to FControlList.Count do
  begin
    ci := FControlList.Control[i - 1];
    if (ci.Y >= RealRowIndex(RowIndex + RCount)) then
      ci.Y := ci.Y - RCount;
  end;

  ClearPropRect(0,RowIndex,ColCount - 1 + FNumHidden,RowIndex + RCount - 1);

  // necessary to save this due to Delphi 1,2,3 bug in TStringGrid!
  cc := ColCount - 1;
  cw := ColWidths[cc];

  // turn off the Entered state as a Row delete will reset cell focus}
  Enterstate := FEntered;
  FEntered := False;

  if (RowCount > FixedRows) and (ColCount > FixedCols) then
    SelectCell(Limit(Col,FixedCols,ColCount-1),Limit(Row,FixedRows,RowCount-1));

  BeginUpdate;

  if FFilterActive then
  begin
    RRIndex := RealRowIndex(RowIndex);

    FilterActive := false;

    RemoveRows(RRIndex, RCount);

    FilterActive := true;
    EndUpdate;
    Exit;
  end;

  FHideLast := HideLastRow;

  try
    ColCount := ColCount + FNumHidden;

    tr := TopRow;
    cr := Row;

    fv := FloatingFooter.Visible;
    ff := FixedFooters;

    FloatingFooter.Visible := false;

    if NumHiddenRows > 0 then
    begin
      RRIndex := RealRowIndex(RowIndex);
      for i := 1 to FGriditems.Count do
      begin
        if (FGriditems.Items[i - 1] as TGridItem).Idx > RRIndex then
        begin
          (FGriditems.Items[i - 1] as TGridItem).Idx :=
            (FGriditems.Items[i - 1] as TGridItem).Idx - RCount;
        end;
      end;
    end;

    for i := 1 to RCount do
    begin
      if ShowModified.Enabled then
      begin
        if FModifiedRows.Count > RowIndex then
          FModifiedRows.Delete(RowIndex);
      end;

      if FUseEnabledRows then
      begin
        if FEnabledRows.Count > RowIndex then
          FEnabledRows.Delete(RowIndex);
      end;

      if FMouseActions.DisjunctRowSelect and (FRowSelect.Count > RowIndex) then
      begin
        FRowSelect.Delete(RowIndex);
        RowSelect[RowIndex + i - 1] := False;
      end;
    end;

    // Move all rows down
    for i := RowIndex to RowCount - 1 do
    begin
      if (i + RCount < RowCount) then
      begin
        Rows[i] := Rows[i + RCount];
        RowHeights[i] := RowHeights[i + RCount];
      end
      else
        NilRow(i);
    end;

    for i := RowCount to RowCount + RCount do
    begin
      NilRow(i);
    end;

    // Decrease rows in one time
    RowCount := RowCount - RCount;

    djrs := MouseActions.DisjunctRowSelect;
    MouseActions.DisjunctRowSelect := false;

    // Make sure selection is valid when ColCount changes
    if (Row >= RowCount) and (RowCount - 1 >= FixedRows) then
      Row := RowCount - 1;

    ColCount := ColCount - FNumHidden;

    FMaxRowCount := FMaxRowCount - RCount;

    if cr < RowCount - FFixedFooters then
    begin
      if not MouseActions.DisjunctRowSelect then
        Row := cr;
      TopRow := tr;
    end
    else
    begin
      if RowCount - FFixedFooters > FixedRows then
        Row := RowCount - FFixedFooters - 1
      else
        HideSelection;

      FSelHidden := False;
    end;

    MouseActions.DisjunctRowSelect := djrs;

    ColWidths[cc] := cw;
    FloatingFooter.Visible := fv;
    FFixedFooters := ff;
  finally

    HideLastRow := FHideLast;
    EndUpdate;
  end;

  FEntered := EnterState;
  {
  if FMouseActions.DisjunctRowSelect then
  begin
    FSelectedRows.Clear;
    for i := 0 to RowCount - 1 do
    begin
      if RowSelect[i] then
        FSelectedRows.Add(i);
    end;
  end;
  }
  CellsChanged(Rect(0,RowIndex,ColCount-1,RowIndex + RCount));

  if (TopRow >= RowCount - VisibleRowCount - 1 + FixedRows - 1 ) and (RowCount - VisibleRowCount - 1 > 0) then
    TopRow := RowCount - VisibleRowCount - 1 +  FixedRows - 1;

  if FControlList.Count > 0 then
    CellControlsUpdate;

  if SearchFooter.Visible then
    SearchPanel.Repaint;
end;

procedure TAdvStringGrid.RemoveRowsInternal(RowIndex, RCount : Integer);
begin
  ClearPropRect(0,RowIndex,ColCount - 1,RowIndex + RCount - 1);
  IRemoveRows(RowIndex,RCount,true);
end;

procedure TAdvStringGrid.IRemoveRows(RowIndex, RCount : Integer; flg: Boolean);
var
  i: Integer;
  cc,cw,cr: Integer;
  tr: Integer;
  enterstate: Boolean;
  il: TIntList;
  vf: Boolean;
  RRIndex: Integer;
  rs: Boolean;
  ff: Integer;
  ds: boolean;
  bCCUCall: boolean;

begin
  if RowIndex >= RowCount then
    Exit;

  if (FControlList.Count > 0) and flg then
  begin
    i := FControlList.Count - 1;
    while (i >= 0) do
    begin
      if (FControlList.Control[i].Y >= RowIndex) and (FControlList.Control[i].Y < RowIndex + RCount) then
      begin
        FControlList.Control[i].Control.Visible := false;
        FControlList.Delete(i);
      end;
      dec(i);
    end;
  end;

  ff := -1;
  if FixedFooters > 0 then
  begin
    ff := FFixedFooters;
    FFixedFooters := 0;
  end;

  vf := FloatingFooter.Visible;

  if vf then
  begin
    BeginUpdate;
    FloatingFooter.Visible := false;
  end;

  ds := MouseActions.DisjunctRowSelect;
  MouseActions.DisjunctRowSelectDirect := false;

  try
    //necessary to save this due to Delphi 1,2,3 bug in TStringGrid!
    cc := ColCount - 1;
    cw := ColWidths[cc];

    //turn off the Entered state as a Row delete will reset cell focus}
    Enterstate := FEntered;
    FEntered := False;

    bCCUCall := ccuCall;
    ccuCall := False;
    try
      BeginUpdate;
      ColCount := ColCount + FNumHidden;

      tr := TopRow;
      cr := Row;

      rs := goRowSelect in Options;

      if rs and (FixedRows < RowCount - 1) then
        Options := Options - [goRowSelect];

      if (FNumNodes > 0) and (Row < RowCount) then
        Col := FixedCols;

      il := TIntList.Create(0,0);

      for i := 1 to RowCount do
        il.Add(RowHeights[i - 1]);

      if flg then
      begin
        if NumHiddenRows > 0 then
        begin
          RRIndex := RealRowIndex(RowIndex);
          for i := 1 to FGriditems.Count do
          begin
            if (FGriditems.Items[i - 1] as TGridItem).Idx > RRIndex then
              (FGriditems.Items[i - 1] as TGridItem).Idx :=
                (FGriditems.Items[i - 1] as TGridItem).Idx - RCount;
          end;
        end;
      end;

      for i := 1 to RCount do
      begin
        DeleteRow(RowIndex);
        il.Delete(RowIndex);
        if FMouseActions.DisjunctRowSelect and (FRowSelect.Count > RowIndex) and
          not FMouseActions.RowSelectPersistent then
            FRowSelect.Delete(RowIndex);
      end;

      if cr < RowCount - FFixedFooters then
      begin
        Row := cr;
        TopRow := tr;
      end
      else
      begin
        if RowCount - FFixedFooters > FixedRows then
        begin
          Row := RowCount - FFixedFooters - 1;
          if (Row >= RowCount) then // new row selection was not possible, ie. for fixed merged cells
            HideSelection;
        end
        else
          HideSelection;

        // no need to keep this set from here: v2.4.0.5
        FSelHidden := False;
      end;

      for i := 1 to RowCount do
        RowHeights[i - 1] := il.Items[i - 1];

      il.Free;

    finally
      ccuCall := bCCUCall;
      ColCount := ColCount - FNumHidden;
      ColWidths[cc] := cw;
      EndUpdate;
    end;

    FEntered := EnterState;

    CellsChanged(Rect(0,RowIndex,ColCount-1,RowIndex + RCount));

    if TopRow >= RowCount - 1 then
      TopRow := RowCount - 1;

    if (Row >= RowCount) and (FixedRows < RowCount) then // new row selection was not possible, ie. for fixed merged cells
    begin
      FForceSel := true;

      FocusCell(FixedCols,FixedRows);
      //Row := FixedRows;
      if (RowCount > FixedRows) and rs then
        Options := Options + [goRowSelect];
      FForceSel := false;
      HideSelection;
      FSelHidden := false;
    end
    else
      if rs and (FixedRows < RowCount) then
        Options := Options + [goRowSelect];

  finally
    MouseActions.DisjunctRowSelectDirect := ds;
    if vf then
    begin
      FloatingFooter.Visible := vf;
      EndUpdate;
    end;
  end;

  if (FControlList.Count > 0)  then
  begin
    (*
    i := FControlList.Count - 1;

    while (i >= 0) do
    begin
      if FControlList.Control[i].Y >= RealRowIndex(RowIndex) then
        FControlList.Control[i].Y := FControlList.Control[i].Y - RCount;
      dec(i);
    end;
    *)
    CellControlsUpdate;
  end;


  if ff <> -1 then
  begin
    FFixedFooters := ff;
  end;
end;

procedure TAdvStringGrid.RemoveDuplicates(ACol: Integer; DoCase: Boolean);
var
  sl: TStringList;
  i: Integer;
  il: TIntList;
begin
  ACol := RemapCol(ACol);
  sl := TStringList.Create;
  il := TIntList.Create(-1,-1);
  sl.Sorted := true;

  BeginUpdate;
  try
    i := FixedRows;

    while i < RowCount - FixedFooters do
    begin
      if sl.IndexOf(Cells[ACol,i]) = -1 then
      begin
        if DoCase then
          sl.Add(Cells[ACol,i])
        else
          sl.Add(UpperCase(Cells[ACol,i]));
      end
      else
        il.Add(i);

      Inc(i);
    end;
    RemoveRowList(il);
  finally
    EndUpdate;
    sl.Free;
    il.Free;
  end;
end;

procedure TAdvStringGrid.RemoveSelectedCols;
var
  i: Integer;
  ss,se: Integer;

begin
  if not MouseActions.DisjunctColSelect then
  begin
    ss := Selection.Left;
    se := Selection.Right;
    if (se < ss) then
    begin
      ss := Selection.Right;
      se := Selection.Left;
    end;
    RemoveCols(ss, se - ss + 1);
  end
  else
  begin
    for i := ColCount - 1 downto FixedCols do
    begin
      if ColSelect[i] then
      begin
        RemoveCols(i, 1);
        FColSelect.Delete(i);
      end;
    end;
  end;
end;

procedure TAdvStringGrid.RemoveUnSelectedCols;
var
  i: Integer;
  ss,se: Integer;

begin
  if not MouseActions.DisjunctColSelect then
  begin
    ss := Selection.Left;
    se := Selection.Right;
    if (se < ss) then
    begin
      ss := Selection.Right;
      se := Selection.Left;
    end;

    RemoveCols(se + 1, ColCount - 1 - se + 1);
    RemoveCols(FixedCols, ss - FixedCols);
  end
  else
  begin
    for i := ColCount - 1 downto FixedCols do
    begin
      if not ColSelect[i] then
      begin
        RemoveCols(i, 1);
        FColSelect.Delete(i);
      end;
    end;
  end;
  ClearColSelect;
end;


procedure TAdvStringGrid.RemoveSelectedRows;
var
  i,j,k,c: Integer;
  ss,se: Integer;
  il: TIntList;
begin
  BeginUpdate;

  try
    //i := FixedRows;

    if not MouseActions.DisjunctRowSelect then
    begin
      ss := Selection.Top;
      se := Selection.Bottom;
      if (se < ss) then
      begin
        ss := Selection.Bottom;
        se := Selection.Top;
      end;

      for i := se downto ss do
        RemoveRowsInternal(i,1);
        
      EndUpdate;
      Exit;
    end;

    i := RowCount - FixedFooters - 1;

    il := TIntList.Create(-1,-1);

    while i >= FixedRows do
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      if RowSelect[j] then
        il.Add(j);

      dec(i);
    end;

    // from last row to first
    i := RowCount - FixedFooters - 1;

    c := 1;
    k := i + 1;

    while i >= FixedRows do
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      if il.IndexOf(Pointer(j)) <> -1 then
      begin
        if (k - 1 = i) then
        begin
          k := i;
          inc(c);
        end
        else
        begin
          RemoveRowsInternal(i,c);
          k := i;
          c := 1;
        end;
      end
      else
      begin
        if c > 1 then
          RemoveRowsInternal(k,c - 1);
        c := 1;
        k := i;
      end;

      dec(i);
    end;

    if (c > 1) then
      RemoveRowsInternal(FixedRows,c - 1);

    il.Free;

    ClearRowSelectInt;
  finally
    EndUpdate;
  end;
end;

procedure TAdvStringGrid.RemoveUnSelectedRows;
var
  i: Integer;
begin
  BeginUpdate;
  try
    i := RowCount - FixedFooters - 1;
    while i >= FixedRows do
    begin
      if not RowSelect[i] then
        RemoveRowsInternal(i,1);
      Dec(i);
    end;
  finally
    EndUpdate;
  end;

  if not FMouseActions.RowSelectPersistent then
    ClearRowSelectInt
  else
    SelectRows(FixedRows, RowCount - FixedRows);
end;


procedure TAdvStringGrid.HideSelectedRows;
var
  i,j,k: Integer;
  il: TIntList;

begin
  if FMouseActions.DisjunctRowSelect then
  begin
    i := RowCount - 1;
    BeginUpdate;

    try
      while i >= FixedRows do
      begin
        if FMouseActions.RowSelectPersistent then
          k := RemapRowInv(i)
        else
          k := i;

        if RowSelect[k] then
        begin
          j := RealRowIndex(i);
          HideRows(j,j);
        end;

        Dec(i);
      end;
    finally
      EndUpdate;
    end;
  end
  else
  begin
    i := RowCount - 1;
    BeginUpdate;

    il := TIntList.Create(-1,-1);
    try
      while i >= FixedRows do
      begin
        if FMouseActions.RowSelectPersistent then
          k := RemapRowInv(i)
        else
          k := i;

        if RowSelect[k] then
        begin
          //j := RealRowIndex(i);
          il.Add(k);
        end;

        Dec(i);
      end;

      HideRowList(il);
    finally
      EndUpdate;
      il.Free;
    end;
  end;

end;

procedure TAdvStringGrid.HideUnSelectedRows;
var
  i,j,k: Integer;
begin
  i := FixedRows;
  BeginUpdate;
  try
    while i < RowCount do
    begin
      if FMouseActions.RowSelectPersistent then
        k := RemapRowInv(i)
      else
        k := i;

      if not RowSelect[k] then
      begin
        j := RealRowIndex(i);
        HideRows(j,j);
      end
      else
        Inc(i);
    end;
  finally
    EndUpdate;
  end;
end;


procedure TAdvStringGrid.TrimRect(ACol1,ARow1,ACol2,ARow2: Integer);
var
  i,j,rc: Integer;
begin
  for j := ARow1 to ARow2 do
  begin
    for i := ACol1 to ACol2 do
    begin
      if not SaveHiddenCells then
        rc := i
      else
        rc := RemapCol(i);


      Cells[rc,j] := SysUtils.Trim(Cells[rc,j]);
    end;
  end;
end;

procedure TAdvStringGrid.TrimColumn(ACol: Integer);
begin
  TrimRect(ACol,0,ACol,RowCount - 1);
end;

procedure TAdvStringGrid.TrimRow(ARow: Integer);
begin
  TrimRect(0,ARow,ColCount - 1,ARow);
end;

procedure TAdvStringGrid.TrimAll;
begin
  TrimRect(0,0,ColCount-1,RowCount-1);
end;

procedure TAdvStringGrid.ColorRect(ACol1,ARow1,ACol2,ARow2: Integer; AColor: TColor);
var
  i,j: Integer;
begin
  for j := ARow1 to ARow2 do
    for i := ACol1 to ACol2 do
      Colors[i,j] := AColor;
end;

procedure TAdvStringGrid.ClearRect(ACol1,ARow1,ACol2,ARow2: Integer);
var
  i,j: Integer;
  rc: Integer;
begin

  for j := ARow1 to ARow2 do
  begin
    for i := ACol1 to ACol2 do
    begin
      if not SaveHiddenCells then
        rc := i
      else
        rc := RemapCol(i);

      if FOwnsObjects and Assigned(Objects[rc,j]) then
        Objects[rc,j].Free;

      if not FClearTextOnly then
      begin
        if HasCellProperties(rc,j) then
        begin
          if FNilObjects then
          begin
            NilCell(rc,j);
          end
          else
          begin
            FreeCellGraphic(rc,j);
            CellProperties[rc,j] := nil;
          end;
        end;
      end;

      if not (csDestroying in ComponentState) then
      begin
        if Cells[rc,j] <> '' then
        begin
          Cells[rc,j] := '';
          if rc <> i then
            RepaintCell(i,j);
        end;
      end;
    end;
  end;

  if not FSaveHiddenCells and (NumHiddenColumns > 0) then
    Invalidate;

  if (ACol2 >= ColCount - 1) and (ARow2 >= RowCount - 1) and (ACol1 = 0) and (ARow1 = 0) then
    FHasCellProps := false;

  if not (csDestroying in ComponentState) and not FBlockCellChange then
  begin
    CellsChanged(Rect(RemapCol(ACol1),ARow1,RemapCol(ACol2),ARow2));
  end;
end;

procedure TAdvStringGrid.ClearRows(RowIndex,RCount: Integer);
begin
  if (RowCount > 0) and (ColCount > 0) and (RCount > 0) then
    ClearRect(0,RowIndex,ColCount - 1 + FNumHidden,RowIndex + RCount - 1);
end;

procedure TAdvStringGrid.ClearNormalCols(ColIndex, CCount: Integer);
begin
  if (RowCount > 0) and (ColCount > 0) and (CCount > 0) then
    ClearRect(ColIndex,FixedRows,ColIndex + CCount - 1,RowCount - 1 - FixedFooters);
end;

procedure TAdvStringGrid.ClearNormalRows(RowIndex, RCount: Integer);
begin
  if (RowCount > 0) and (ColCount > 0) and (RCount > 0) then
    ClearRect(FixedCols,RowIndex,ColCount - 1 + FNumHidden - FixedRightCols,RowIndex + RCount - 1);
end;


procedure TAdvStringGrid.AddColumn;
begin
  InsertCols(ColCount,1);
end;

procedure TAdvStringGrid.AddRow;
begin
  if FloatingFooter.Visible then
  begin
    InsertRows(RowCount - 1,1);
    if FloatingFooter.FooterStyle = fsFixedLastRow then
      ClearRows(RowCount - 2, 1);
  end
  else
  begin
    InsertRows(RowCount,1);
    ClearRows(RowCount - 1, 1);
  end;
end;

procedure TAdvStringGrid.InsertRows(RowIndex,RCount: Integer; UpdateCellControls: boolean = true);
begin
  InsertRowsEx(RowIndex,RCount,UpdateCellControls);
end;

procedure TAdvStringGrid.InsertRowsEx(RowIndex, RCount: Integer; UpdateCellControls: boolean = true);
var
  i,j: Integer;
  cw,cc: Integer;
begin
  cc := ColCount - 1;
  cw := ColWidths[cc];

  if (FSelHidden) or (Col >= ColCount) or (Row >= RowCount) then
    UnHideSelection;

  ColCount := ColCount + FNumHidden;
  RowCount := RowCount + RCount;

  j := 1;
  if FloatingFooter.Visible then
    j := 2;

  for i := RowCount - j downto (RowIndex + Rcount) do
  begin
    Rows[i] := Rows[i - RCount];
    RowHeights[i] := RowHeights[i - RCount];
  end;

  for i := RowIndex to RowIndex + RCount - 1 do
    RowHeights[i] := DefaultRowHeight;

  for i := 0 to RCount - 1 do
  begin
    NilRow(RowIndex + i);
  end;

  ColCount := ColCount - FNumHidden;

  if ShowModified.Enabled then
  begin
    for i := 0 to RCount - 1 do
      if FModifiedRows.Count > RowIndex then
      begin
        FModifiedRows.Insert(RowIndex,0);
      end;
  end;

  if FUseEnabledRows then
  begin
    for i := 0 to RCount - 1 do
      if FEnabledRows.Count > RowIndex then
        FEnabledRows.Insert(RowIndex,0);
  end;

  ColWidths[cc] := cw;

  if (FControlList.Count > 0) and UpdateCellControls then
  begin
    for i := 0 to FControlList.Count - 1 do
    begin
      if FControlList.Control[i].Y >= RealRowIndex(RowIndex) then
        FControlList.Control[i].Y := FControlList.Control[i].Y + RCount;
    end;
    CellControlsUpdate;
  end;

  if not (csDestroying in ComponentState) then
    CellsChanged(Rect(0,RowIndex,ColCount - 1,RowIndex + RCount));
end;

procedure TAdvStringGrid.ClearCols(ColIndex,CCount: Integer);
begin
  if (RowCount>0) and (ColCount>0) and (CCount>0) then
    ClearRect(ColIndex,0,ColIndex+CCount-1,RowCount-1);
end;

procedure TAdvStringGrid.RemoveCols(ColIndex,CCount: Integer);
var
  i: Integer;
begin
  if ColIndex + CCount >  ColCount + FNumHidden then
    CCount := ColCount + FNumHidden - ColIndex;

  ClearCols(ColIndex,CCount);

  ColCount := ColCount + FNumHidden;

  for i := ColIndex to ColCount - 1 do
  begin
    Cols[i] := Cols[i + CCount];
    ColWidths[i] := ColWidths[i + CCount];
    FVisibleCol[i] := FVisibleCol[i + CCount];
  end;

  ColCount := ColCount - FNumHidden;

  ColCount := ColCount - CCount;
  CellsChanged(Rect(ColIndex,0,ColIndex + CCount, RowCount - 1));
end;

procedure TAdvStringGrid.InsertCols(ColIndex,CCount: Integer);
var
  i: Integer;
begin
  ColCount := ColCount + CCount;

  for i := ColCount - 1 + FNumHidden downto ColIndex + CCount do
  begin
    Cols[i] := Cols[i - CCount];
    if i < ColCount then
      ColWidths[i] := ColWidths[i - CCount];
    FVisibleCol[i] := FVisibleCol[i - CCount];
  end;

  for i := ColIndex to ColIndex + CCount - 1 do
  begin
    if i < ColCount then
    begin
      ColWidths[i] := DefaultColWidth;
      FVisibleCol[i] := True;
    end;
  end;

  for i := 0 to CCount - 1 do
    NilCol(ColIndex + i)
end;

procedure TAdvStringGrid.SplitColumnCells(ColIndex: Integer);
var
  i,j: Integer;
begin
  i := 0;
  while i < RowCount - 1 - FixedFooters do
  begin
    j := i;
    if IsYMergedCell(ColIndex,i) then
    begin
      j := i + CellSpan(ColIndex,i).Y + 1;
      SplitCells(ColIndex,i);
    end
    else
      inc(j);
    i := j;
  end;
end;

procedure TAdvStringGrid.MergeColumnCells(ColIndex: Integer; MainMerge: Boolean);
var
  i,j,k: Integer;
begin
  j := 1;
  k := FixedRows;

  for i := FixedRows + 1 to RowCount - 1 - FixedFooters do
  begin
    if (Cells[ColIndex,i] = Cells[ColIndex,i - 1]) and
       (MainMerge or RowSpanIdentical(i,i - 1)) then
      inc(j)
    else
    begin
      if j > 1 then
        MergeCells(ColIndex,k,1,j);
      k := i;
      j := 1;
    end;
  end;

  if j > 1 then
    MergeCells(ColIndex,k,1,j);
end;

procedure TAdvStringGrid.SplitAllCells;
var
  i,j: Integer;

begin
  for i := 1 to RowCount do
    for j := 1 to ColCount do
    begin
      if IsMergedCell(j - 1, i - 1) then
        SplitCells(j - 1,i - 1);
    end;
end;

procedure TAdvStringGrid.SplitRowCells(RowIndex: Integer);
var
  i,j: Integer;
begin
  i := 0;
  while i < ColCount - 1 - FixedRightCols do
  begin
    j := i;
    if IsMergedCell(i,RowIndex) then
    begin
      if CellSpan(i,RowIndex).X<0 then
        inc(j)
      else
      begin
        j := i + CellSpan(i,RowIndex).X + 1;
        SplitCells(i,RowIndex);
      end;  
    end
    else
      inc(j);
      
    i := j;
  end;
end;

procedure TAdvStringGrid.MergeRowCells(RowIndex: Integer; MainMerge: Boolean);
var
  i,j,k: Integer;
begin
  j := 0;
  k := FixedCols;
  for i := FixedCols + 1 to ColCount - 1 - FixedRightCols do
  begin
    if (Cells[i,RowIndex] = Cells[i - 1,RowIndex]) and
       (MainMerge or ColSpanIdentical(i,i - 1)) then
      inc(j)
    else
    begin
      MergeCells(k,RowIndex,j + 1,1);
      k := i;
      j := 0;
    end;
  end;
  if j >= 1 then
    MergeCells(k,RowIndex,j + 1,1);
end;

procedure TAdvStringGrid.MergeCols(ColIndex1, ColIndex2 : Integer; Separator : string = ' ');
var
  i: Integer;
  s:string;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    s := Cells[ColIndex1,i] + Separator + Cells[ColIndex2,i];
    Cells[ColIndex1,i] := SysUtils.Trim(s);
  end;
  RemoveCols(ColIndex2,1);
end;

procedure TAdvStringGrid.ClearNormalCells;
begin
  if (FixedCols = 0) and (FNumNodes > 0) then
    RemoveAllNodes;

  if (RowCount > 0) and (ColCount > 0) then
  begin
    ClearRect(FixedCols,FixedRows,ColCount - 1 + FNumHidden - FixedRightCols,RowCount - 1 - FixedFooters);
  end;  
end;

procedure TAdvStringGrid.ClearSelection;
var
  i: Integer;
  b: boolean;
begin
  if FMouseActions.DisjunctRowSelect then
  begin
    for i := FixedRows to RowCount - 1 do
    begin
      if FMouseActions.RowSelectPersistent then
      begin
        if RowSelect[RemapRowInv(i)] then
          ClearRows(i,1);
      end
      else
      begin
        if RowSelect[i] then
          ClearRows(i,1);
      end;
    end;
  end
  else
  begin
    b := SaveHiddenCells;
    SaveHiddenCells := true;
    if FMouseActions.DisjunctColSelect then
    begin
      for i := FixedCols to ColCount - 1 do
      begin
        if ColSelect[i] then
          ClearCols(i,1);
      end;
    end
    else
    begin
      ClearRect(Selection.Left,Selection.Top,Selection.Right,Selection.Bottom);
    end;
    SaveHiddenCells := b;
  end;
end;

procedure TAdvStringGrid.Clear;
begin
  if HasNodes then
    ExpandAll;

  if not (csDestroying in ComponentState) then
    if (FNumNodes > 0) then
      RemoveAllNodes;

  if (RowCount > 0) and (ColCount > 0) then
    ClearRect(0,0,ColCount - 1 + FNumHidden,RowCount - 1);

  SearchInc := '';
  if FNumHidden > 0 then
    Invalidate;
end;

procedure TAdvStringGrid.ClearAll;
var
  j: integer;
begin
  if (csDestroying in ComponentState) then
    Exit;

  if (FNumNodes > 0) then
  begin
    ExpandAll;
    RemoveAllNodes;
  end;

  if (RowCount > 0) and (ColCount > 0) then
    ClearRect(0,0,FMaxColCount - 1,FMaxRowCount - 1);

  SearchInc := '';

  for j := 1 to FGriditems.Count do
  begin
    (FGriditems.Items[j - 1] as TGridItem).Items.Clear;
   end;
  if FNumHidden > 0 then
    Invalidate;
end;


function TAdvStringGrid.IsWideCell(ACol,ARow: Integer): Boolean;
begin
  Result := pos('|\',Cells[ACol,ARow]) = 1;
end;

function TAdvStringGrid.IsCell(SubStr: String; var ACol, ARow: Integer): Boolean;
var
  i,j: Integer;
begin
  for i := 0 to RowCount - 1 do
  begin
    for j := 0 to ColCount - 1 do
    begin
      if Rows[i].Strings[j] = SubStr then
      begin
        ARow := i;
        ACol := j;
        Result := True;
        Exit;
      end;
    end;
  end;
  Result := False;
end;

procedure TAdvStringGrid.LoadFromBinFile(FileName: string);
var
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    ms.LoadFromFile(FileName);
    LoadFromBinStream(ms);
  finally
    ms.Free;
  end;
end;


procedure TAdvStringGrid.LoadAtPointFromBinStream(Point: TPoint; Stream: TStream);
var
  cpio: TGridCellIO;
  cgio: TGridGraphicIO;
  gpio: TGridPropIO;
  giio: TGridIconIO;
  gbio: TGridBMPIO;
  gtio: TGridPicIO;
  gfio: TGridFilePicIO;
  gsio: TGridSLIO;
  pio: TGridCellPropIO;
  cg: TCellGraphic;
  sl: TStringList;
  il: TIntList;
  i: Integer;
  bmp: TBitmap;
  ico: TIcon;
  pic: TPicture;
  fpic: TFilePicture;
  FirstCell: Boolean;
  DeltaX,DeltaY: Integer;
  c,r,oldr: Integer;
  nprogr,oprogr: smallint;

begin
  gpio := TGridPropIO.Create(Self);
  cpio := TGridCellIO.Create(Self);
  cgio := TGridGraphicIO.Create(Self);
  gbio := TGridBMPIO.Create(Self);
  giio := TGridIconIO.Create(Self);
  gtio := TGridPicIO.Create(Self);
  gfio := TGridFilePicIO.Create(Self);
  gsio := TGridSLIO.Create(Self);
  pio := TGridCellPropIO.Create(Self);


  Stream.ReadComponent(gpio);
  gpio.Name := '';

  if (gpio.FullGrid) then
  begin
    Clear;

    RowCount := gpio.RowCount;
    ColCount := gpio.ColCount;

    sl := TStringList.Create;
    sl.CommaText := gpio.ColWidths;
    for i := 1 to ColCount do
      ColWidths[i - 1] := StrToInt(sl.Strings[i - 1]);

    sl.CommaText := gpio.RowHeights;
    for i := 1 to RowCount do
      RowHeights[i - 1] := StrToInt(sl.Strings[i - 1]);

    sl.Free;
  end;

  FirstCell := True;
  DeltaX := 0;
  DeltaY := 0;
  oldr := -1;
  oprogr := -1;

  while Stream.Position < Stream.Size - 1 do
  begin
    Stream.ReadComponent(cpio);
    cpio.Name := '';

    if FirstCell and not gpio.FullGrid then
    begin
      DeltaX := cpio.Col;
      DeltaY := cpio.Row;
      FirstCell := False;
    end;

    c := Point.X + cpio.Col - DeltaX;
    r := Point.Y + cpio.Row - DeltaY;

    Cells[c,r] := cpio.Cell;

    if (r <> oldr) then
    begin
      oldr := r;
      nprogr := Round((r)/(Max(1,Rowcount))*100);
      if nprogr <> oprogr then
      begin
        if Assigned(FOnFileProgress) then
          FOnFileProgress(Self,nprogr);

        oprogr := nprogr;
      end;
    end;

    if cpio.HasProp then
    begin
      pio.CellProperties.Assign(CellProperties[c,r]);

      Stream.ReadComponent(pio);
      pio.Name := '';
      pio.CellProperties.OwnerCol := c;
      pio.CellProperties.OwnerRow := r;
      CellProperties[c,r].Assign(pio.CellProperties);

      if pio.HasGraphic then
      begin
        cgio.CellGraphic.CellText := '';
        Stream.ReadComponent(cgio);

        cgio.Name := '';
        cg := CreateCellGraphic(c,r);
        cg.Assign(cgio.CellGraphic);
        if (cg.CellType = ctComment) then
        begin
          cg.CellType := ctNone;
          cg.CellComment := cg.CellText;
          cg.CommentColor := TColor(cg.CellIndex);
          cg.CellText := '';
        end;

        // it is guaranteed to be created, otherwise not saved
        case cg.CellType of
        ctBitmap,ctBitButton:
          begin
            Stream.ReadComponent(gbio);
            gbio.Name := '';
            bmp := TBitmap.Create;
            bmp.Assign(gbio.Bitmap);
            cg.CellBitmap := bmp;
          end;
        ctIcon:
          begin
            Stream.ReadComponent(giio);
            giio.Name := '';
            ico := TIcon.Create;
            ico.Assign(giio.Icon);
            cg.CellIcon := ico;
          end;
        ctPicture:
          begin
            Stream.ReadComponent(gtio);
            gtio.Name := '';
            pic := TPicture.Create;
            pic.Assign(gtio.Picture);
            cg.CellBitmap := TBitmap(pic);
          end;
        ctFilePicture:
          begin
            Stream.ReadComponent(gfio);
            gfio.Name := '';
            fpic := TFilePicture.Create;
            fpic.Assign(gfio.Picture);
            cg.CellBitmap := TBitmap(fpic);
          end;
        ctRadio:
          begin
            Stream.ReadComponent(gsio);
            gsio.Name := '';
            sl := TStringList.Create;
            sl.Assign(gsio.Strings);
            cg.CellBitmap := TBitmap(sl);
          end;
        ctImages:
          begin
            Stream.ReadComponent(gsio);
            gsio.Name := '';
            il := TIntList.Create(c,r);
            il.StrValue := gsio.Strings.CommaText;
            cg.CellBitmap := TBitmap(il);
          end;
        end;
      end;

    end;

    cpio.Cell := '';
  end;

  pio.Free;
  gsio.Free;
  gfio.Free;
  gtio.Free;
  giio.Free;
  gbio.Free;
  gpio.Free;
  cpio.Free;
  cgio.Free;
end;

procedure TAdvStringGrid.SaveToBinFile(FileName: string);
var
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  SaveToBinStream(ms);
  ms.SaveToFile(FileName);
  ms.Free;
end;

procedure TAdvStringGrid.SaveRectToBinStream(Rect: TRect; Stream: TStream; SaveHidden: boolean = false);
var
  i,j,rc: Integer;
  cpio: TGridCellIO;
  cgio: TGridGraphicIO;
  gpio: TGridPropIO;
  gbio: TGridBMPIO;
  giio: TGridIconIO;
  gtio: TGridPicIO;
  gfio: TGridFilePicIO;
  gsio: TGridSLIO;
  pio: TGridCellPropIO;
  nprogr,oprogr: Integer;
  cg: TCellGraphic;
begin
  // helper objects
  cpio := TGridCellIO.Create(Self);
  cgio := TGridGraphicIO.Create(Self);
  gpio:= TGridPropIO.Create(Self);
  gbio := TGridBMPIO.Create(Self);
  giio := TGridIconIO.Create(Self);
  gtio := TGridPicIO.Create(Self);
  gfio := TGridFilePicIO.Create(Self);
  gsio := TGridSLIO.Create(Self);
  pio := TGridCellPropIO.Create(Self);


  gpio.RowCount := Rect.Bottom - Rect.Top + 1;

  if SaveHidden then
  begin
    gpio.ColCount := Rect.Right - Rect.Left + 1 + FNumHidden;
    Rect.Right := Rect.Right + FNumHidden;
  end
  else
    gpio.ColCount := Rect.Right - Rect.Left + 1;

  if SaveFixedCells then
    gpio.FullGrid := (gpio.RowCount = RowCount) and (gpio.ColCount = ColCount)
  else
    gpio.FullGrid := (gpio.RowCount = RowCount - FixedRows) and (gpio.ColCount = ColCount - FixedCols);

  gpio.ID := Integer(Handle);

  for i := Rect.Left to Rect.Right do
   if i > Rect.Left then
     gpio.ColWidths := gpio.ColWidths + ',' + IntToStr(ColWidths[i])
   else
     gpio.ColWidths := IntToStr(ColWidths[i]);

  for i := Rect.Top to Rect.Bottom do
   if i > Rect.Top then
     gpio.RowHeights := gpio.RowHeights + ',' + IntToStr(RowHeights[i])
   else
     gpio.RowHeights := IntToStr(RowHeights[i]);

  Stream.WriteComponent(gpio);

  oprogr := -1;

  // need simpler object for cells with text only

  ExportNotification(esExportStart, Rect.Top);

  for j := Rect.Top to Rect.Bottom do
  begin
    ExportNotification(esExportNextRow, j);

    for i := Rect.Left to Rect.Right do
    begin
      if SaveHidden then
        rc := i
      else
        rc := RemapCol(i);

      cpio.Col := i;
      cpio.Row := j;
      cpio.Cell := Cells[rc,j];
      cpio.HasProp := HasCellProperties(rc,j);

      Stream.WriteComponent(cpio);

      if cpio.HasProp then
      begin
        pio.CellProperties.Assign(CellProperties[rc,j]);

        pio.HasGraphic := (CellTypes[rc,j] <> ctEmpty);

        if not FInWorkbook then
          pio.HasGraphic := pio.HasGraphic and
            (not ((CellTypes[rc,j] in [ctBitmap,ctBitButton,ctPicture,ctFilePicture,ctImages,ctRadio,ctIcon])
             and CellGraphics[rc,j].CellCreated));

        Stream.WriteComponent(pio);

        if pio.HasGraphic then
        begin
          cgio.CellGraphic.CellText := '';

          cg := CellGraphics[rc,j];

          cgio.CellGraphic.Assign(cg);

          if (cg.CellComment <> '') then
          begin
            cgio.CellGraphic.CellType := ctComment;
            cgio.CellGraphic.CellText := cg.CellComment;
            cgio.CellGraphic.CellIndex := integer(cg.CommentColor);
          end;

          Stream.WriteComponent(cgio);

          case CellTypes[rc,j] of
          ctBitmap,ctBitButton:
            begin
              gbio.Bitmap.Assign(CellGraphics[rc,j].CellBitmap);
              Stream.WriteComponent(gbio);
            end;
          ctIcon:
            begin
              giio.Icon.Assign(CellGraphics[rc,j].CellIcon);
              Stream.WriteComponent(giio);
            end;
          ctPicture:
            begin
              gtio.Picture.Assign(TPicture(CellGraphics[rc,j].CellBitmap));
              Stream.WriteComponent(gtio);
            end;
          ctFilePicture:
            begin
              gfio.Picture.Assign(TFilePicture(CellGraphics[rc,j].CellBitmap));
              Stream.WriteComponent(gfio);
            end;
          ctRadio:
            begin
              gsio.Strings.Assign(TStringList(CellGraphics[rc,j].CellBitmap));
              Stream.WriteComponent(gsio);
            end;
          ctImages:
            begin
              gsio.Strings.CommaText := TIntList(CellGraphics[rc,j].CellBitmap).StrValue;
              Stream.WriteComponent(gsio);
            end;
          end;
        end;
      end;
    end;

    if Assigned(FOnFileProgress) then
    begin
      nprogr := Round((j)/(Max(1,Rect.Bottom - Rect.Top))*100);
      if nprogr <> oprogr then
        FOnFileProgress(self,nprogr);
      oprogr := nprogr;
    end;

  end;

  ExportNotification(esExportDone, -1);

  pio.Free;
  gsio.Free;
  gfio.Free;
  giio.Free;
  gpio.Free;
  cpio.Free;
  cgio.Free;
  gbio.Free;
end;

procedure TAdvStringGrid.LoadFromBinStream(Stream: TStream);
var
  i: Integer;
begin
  LoadAtPointFromBinStream(Point(0,0),Stream);
  // synchronize nodes when used ...
  FNumNodes := 0;
  for i := FixedRows to RowCount - 1 do
  begin
    if CellTypes[0,i] = ctNode then
      inc(FNumNodes);
  end;
  if FNumNodes > 0 then
    RepaintCol(0);

end;

procedure TAdvStringGrid.SaveToBinStream(Stream: TStream);
var
  r: TRect;
begin
  r := Rect(SaveStartCol,SaveStartRow,SaveEndCol,SaveEndRow);
  SaveRectToBinStream(r, Stream, SaveHiddenCells);
end;

{$IFDEF DELPHI_UNICODE}
procedure TAdvStringGrid.SaveToFile(FileName: String; Unicode: boolean = true);
{$ENDIF}
{$IFNDEF DELPHI_UNICODE}
procedure TAdvStringGrid.SaveToFile(FileName: String);
{$ENDIF}
var
  //f: TextFile;
  i,j,n: Integer;
  ss,CellText: string;
  nprogr,oprogr: Integer;
  sl: TStringList;
begin
  sl := TStringList.Create;

  oprogr := -1;

  if FSaveHiddenCells then
    n := FNumHidden
  else
    n := 0;

  ss := IntToStr(SaveColCount+n) + ',' + IntToStr(SaveRowCount);

  sl.Add(ss);

  for i := SaveStartCol to SaveEndCol + n do
  begin
    ss := 'cw '+IntToStr(i) + ',' + IntToStr(ColWidths[i]);
    sl.Add(ss);
  end;

  ExportNotification(esExportStart, SaveStartRow);

  for i := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNextRow, i);
    for j := SaveStartCol to SaveEndCol + n do
    begin
      CellText := SaveCell(j,i);
      if CellText <> '' then
      begin
        ss := IntToStr(j) + ',' + IntToStr(i) + ',' + lftofile(CellText);

        sl.Add(ss);
      end;
    end;

    if Assigned(FOnFileProgress) then
    begin
      nprogr := Round(i/(Min(1,SaveRowCount-1))*100);
      if nprogr <> oprogr then
        FOnFileProgress(self,nprogr);
      oprogr := nprogr;
    end;
  end;
  ExportNotification(esExportDone, -1);

  {$IFDEF DELPHI_UNICODE}
  if Unicode then
    sl.SaveToFile(FileName, TEncoding.Unicode)
  else
    sl.SaveToFile(FileName);
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
  sl.SaveToFile(FileName);
  {$ENDIF}
  sl.Free;

  (*
  AssignFile(f, FileName);
  {$i-}
  Rewrite(f);
  {$i+}
  if IOResult <> 0 then
    raise EAdvGridError.Create('Cannot Create ' + FileName);

  oprogr := -1;

  if FSaveHiddenCells then
    n := FNumHidden
  else
    n := 0;

  ss := IntToStr(SaveColCount+n) + ',' + IntToStr(SaveRowCount);
  Writeln(f,ss);

  for i := SaveStartCol to SaveEndCol + n do
  begin
    ss := 'cw '+IntToStr(i) + ',' + IntToStr(ColWidths[i]);
    WriteLn(f,ss);
  end;

  ExportNotification(esExportStart, -1);

  for i := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNewRow, i);
    for j := SaveStartCol to SaveEndCol + n do
    begin
      CellText := SaveCell(j,i);
      if CellText <> '' then
      begin
        ss := IntToStr(j) + ',' + IntToStr(i) + ',' + lftofile(CellText);
        Writeln(f,ss);
      end;
    end;

    if Assigned(FOnFileProgress) then
    begin
      nprogr := Round(i/(Min(1,SaveRowCount-1))*100);
      if nprogr <> oprogr then
        FOnFileProgress(self,nprogr);
      oprogr := nprogr;
    end;
  end;
  ExportNotification(esExportDone, -1);
  CloseFile(f);
  *)
end;

procedure TAdvStringGrid.LoadFromFile(FileName: String);
var
  X,Y,CW: Integer;
  ss,ss1:string;
  //f:TextFile;
  strtCol,strtRow: Integer;
  nprogr,oprogr: Integer;
  seppos: Integer;
  sl: TFileStringList;

  function MStrToInt(s:string): Integer;
  var
    code,i: Integer;
  begin
    val(s,i,code);
    Result := i;
  end;

begin
  sl := TFileStringList.Create;

  sl.LoadFromFile(FileName);

  oprogr := -1;
  StrtCol := FixedCols;
  StrtRow := FixedRows;

  if FSaveFixedCells or FSaveFixedCols then
    StrtCol := 0;

  if FSaveFixedCells or FSaveFixedRows then
    StrtRow := 0;

  sl.ReadLn(ss);

  if ss <> '' then
  begin
    ss1 := Copy(ss,1,CharPos(',',ss) - 1);
    ColCount := MStrToInt(ss1) + StrtCol;
    ss1 := Copy(ss,CharPos(',',ss) + 1,Length(ss));
    RowCount := MStrToInt(ss1) + StrtRow;
  end;

  if (ColCount = 0) or (RowCount = 0) then
  begin
    sl.Free;
    raise EAdvGridError.Create('File contains no data or corrupt file '+FileName);
  end;

  while not sl.Eof do
  begin
    sl.Readln(ss);

    if Pos('cw',ss)=1 then {parse cw i,Width }
    begin
      seppos := CharPos(',',ss);
      ss1 := Copy(ss,4,seppos - 4);
      ss := Copy(ss,seppos + 1,255);
      CW := MStrToInt(ss1);
      if (cw >= 0) and (cw < ColCount) then
        ColWidths[cw] := mstrtoint(ss);
    end
    else
    begin
      ss1 := GetToken(ss,',');
      X := mStrToInt(ss1);
      ss1 := GetToken(ss,',');
      Y := mStrToInt(ss1);

      if (X < ColCount) and (Y < RowCount) then
      begin
        LoadCell(X,Y,FileToLF(ss,FMultiLineCells));
      end;

      if Assigned(FOnFileProgress) then
      begin
        nprogr := Round(y / (RowCount - 1) * 100);
        if nprogr <> oprogr then
          FOnFileProgress(self,nprogr);
        oprogr := nprogr;
      end;
      Application.ProcessMessages;
    end;
  end;

  sl.Free;
  CellsChanged(Rect(0,0,ColCount,RowCount));
  CellsLoaded;

(*
  AssignFile(f, FileName);
  {$i-}
  Reset(f);
  {$i+}
  if IOResult <> 0 then
    raise EAdvGridError.Create('Cannot open file ' + FileName);

  oprogr := -1;
  StrtCol := FixedCols;
  StrtRow := FixedRows;

  if FSaveFixedCells then
  begin
    StrtCol := 0;
    strtRow := 0;
  end;

  Readln(f,ss);
  if ss <> '' then
  begin
    ss1 := Copy(ss,1,CharPos(',',ss) - 1);
    ColCount := MStrToInt(ss1) + StrtCol;
    ss1 := Copy(ss,CharPos(',',ss) + 1,Length(ss));
    RowCount := MStrToInt(ss1) + StrtRow;
  end;

  if (ColCount = 0) or (RowCount = 0) then
  begin
    Closefile(f);
    raise EAdvGridError.Create('File contains no data or corrupt file '+FileName);
  end;

  while not Eof(f) do
  begin
    Readln(f, ss);

    if Pos('cw',ss)=1 then {parse cw i,Width }
    begin
      seppos := CharPos(',',ss);
      ss1 := Copy(ss,4,seppos - 4);
      ss := Copy(ss,seppos + 1,255);
      CW := MStrToInt(ss1);
      if (cw >= 0) and (cw < ColCount) then
        ColWidths[cw] := mstrtoint(ss);
    end
    else
    begin
      ss1 := GetToken(ss,',');
      X := mStrToInt(ss1);
      ss1 := GetToken(ss,',');
      Y := mStrToInt(ss1);

      if (X < ColCount) and (Y < RowCount) then
      begin
        LoadCell(X,Y,FileToLF(ss,FMultiLineCells));
      end;

      if Assigned(FOnFileProgress) then
      begin
        nprogr := Round(y / (RowCount - 1) * 100);
        if nprogr <> oprogr then
          FOnFileProgress(self,nprogr);
        oprogr := nprogr;
      end;
      Application.ProcessMessages;
    end;
  end;
  CloseFile(f);
  CellsChanged(Rect(0,0,ColCount,RowCount));
  CellsLoaded;
*)
end;

{$IFDEF ISDELPHI}
function TAdvStringGrid.CellToReal(ACol, ARow: Integer): Real;
var
  i:Real;
  Code: Integer;
  s:string;
begin
  Result := 0.0;
  if (Cells[ACol,ARow] <> '') then
  begin
    s := RemoveSeps(Cells[ACol, ARow]);
    Val(s, i, Code);
    if Code <> 0 then
      raise EAdvGridError.Create('Error at position: ' +
        IntToStr(Code) + ' in Cell [' + IntToStr(ACol) + ', ' +
        IntToStr(ARow) + '].')
    else
      Result := i;
  end;
end;
{$ENDIF}

{$IFDEF DELPHI_UNICODE}
procedure TAdvStringGrid.SaveToASCII(FileName: String; Unicode: boolean = true);
begin
  SaveToASCIIInt(FileName, false, Unicode);
end;

procedure TAdvStringGrid.AppendToASCII(FileName: String; Unicode: boolean = true);
begin
  SaveToASCIIInt(FileName, true, Unicode);
end;
{$ENDIF}

{$IFNDEF DELPHI_UNICODE}
procedure TAdvStringGrid.SaveToASCII(FileName: String);
begin
  SaveToASCIIInt(FileName, false, false);
end;

procedure TAdvStringGrid.AppendToASCII(FileName: String);
begin
  SaveToASCIIInt(FileName, true, false);
end;
{$ENDIF}


procedure TAdvStringGrid.SaveToASCIIInt(FileName: String; AppendFile: boolean; Unicode: boolean);
var
  sc,z,n: Integer;
  CellText,CellStr,str,alistr,remainingstr:string;
  i,rc: Integer;
  MultiLineList: TStringlist;
  //OutputFile:TextFile;
  anotherlinepos: Integer;
  blanksfiller: String;
  blankscount,NeededLines: Integer;
  AlignValue:TAlignment;
  Colchars:array of byte;
  OldCursor: TCursor;
  StrtCol, StrtRow: integer;
  sl: TFileStringList;

begin
  OldCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;

  SetLength(ColChars, AllColCount);
  (*
  AssignFile(OutputFile,FileName);

  if AppendFile then
  begin
    {$I-}
    Append(OutputFile);
    {$I+}
    if (ioResult <> 0) then
    begin
      {$i-}
      Rewrite(OutputFile);
      {$i+}
      if ( ioResult<> 0) then
        EAdvGridError.Create('Cannot create file '+FileName);
    end;
  end
  else
  begin
    {$i-}
    Rewrite(OutputFile);
    {$i+}
    if ( ioResult<> 0) then
      EAdvGridError.Create('Cannot create file '+FileName);
  end;
  *)

  sl := TFileStringList.Create;

  if AppendFile then
    if FileExists(FileName) then
      sl.LoadFromFile(FileName);


  if FSaveHiddenCells then
    n := FNumHidden
  else
    n := 0;

  StrtCol := FixedCols;
  StrtRow := FixedRows;

  if FSaveFixedCells or FSaveFixedCols then
    StrtCol := 0;

  if FSaveFixedCells or FSaveFixedRows then
    StrtRow := 0;

  ColCount := ColCount + n;

  for i := StrtCol to ColCount - 1 do
  begin
    if SaveHiddenCells then
      rc := i
    else
      rc := RemapCol(i);

    Colchars[rc] := MaxCharsInCol(rc);
  end;

  try
    ExportNotification(esExportStart, StrtRow);

    MultiLineList := TStringlist.Create;
    for z := StrtRow to RowCount - 1 do
    begin
      ExportNotification(esExportNextRow, z);
      str := '';
      for sc := StrtCol to ColCount - 1 do
      begin
        if SaveHiddenCells then
          rc := sc
        else
          rc := RemapCol(sc);

        CellText := SaveCell(rc,z);

        if (Pos(#13#10, CellText) > 0) and MultiLineCells then
        begin
          CellStr := Copy(CellText,0, Pos(#13#10, CellText) - 1);
          remainingstr := copy(CellText, Pos(#13#10, CellText)+2, Length(CellText));
          NeededLines := 0;
          repeat
            inc(NeededLines);
            blanksfiller := '';
            blankscount := 0;

            if (MultiLineList.Count < NeededLines) then  {we haven't already added a new line for an earlier Colunn}
              MultiLineList.Add('');

            {nr of spaces before cell text}
            for i := 0 to rc - 1 do
              BlanksCount := BlanksCount + ColChars[i] + 1;

            {add to line sufficient blanks}
            for i := 0 to (blankscount - Length(MultiLineList[NeededLines-1])-1) do
              BlanksFiller := BlanksFiller + ' ';

            MultiLineList[NeededLines - 1] := MultiLineList[NeededLines - 1] + BlanksFiller;

            AnotherLinePos := Pos(#13#10, remainingstr);

            if AnotherLinePos > 0 then
            begin
              alistr := Copy(remainingstr, 0, AnotherLinePos - 1);
              remainingstr := Copy(remainingstr,pos(#13#10,remainingstr)+2,Length(remainingstr));
            end
            else
            begin
              alistr := remainingstr;
            end;

            AlignValue := GetCellAlignment(rc,z).Alignment;

            case AlignValue of
            taRightJustify:while (Length(alistr)<Colchars[rc]) do alistr := ' '+alistr;
            taCenter:while (Length(alistr)<Colchars[rc]) do alistr := ' '+alistr+' ';
            end;
            MultiLineList[NeededLines-1] := MultiLineList[NeededLines-1]+alistr;

          until anotherlinepos = 0;
        end
        else
          cellstr := CellText;

        if Pos(#13#10,CellStr) > 0 then
          CellStr := Copy(CellStr,0,pos(#13#10,CellStr)-1);

        AlignValue := GetCellAlignment(rc,z).Alignment;
        case AlignValue of
        taRightJustify:while (Length(cellstr) < Colchars[rc]) do cellstr := ' ' + cellstr;
        taCenter:while (Length(cellstr) < Colchars[rc]) do cellstr := ' ' + cellstr+' ';
        end;

        blanksfiller := '';
        blankscount := Colchars[rc];
        for i := 0 to (blankscount - Length(cellstr)) do
          blanksfiller := blanksfiller + ' ';

        str := str + cellstr + blanksfiller;
      end;  {Column}

      sl.Writeln(Str);
      for i := 0 to MultiLineList.Count-1 do
        sl.Writeln(MultiLineList[i]);     {finally, add the extra lines for this Row}
      MultiLineList.Clear;

    end;    {Row}
    MultiLineList.Free;
  finally
    ColCount := ColCount - n;
    ExportNotification(esExportDone, -1);

    {$IFDEF DELPHI_UNICODE}
    if Unicode then
      sl.SaveToFile(FileName, FEncoding)
    else
      sl.SaveToFile(FileName);
    {$ENDIF}

    {$IFNDEF DELPHI_UNICODE}
    sl.SaveToFile(FileName);
    {$ENDIF}
    
    sl.Free;
    Screen.Cursor := OldCursor;
  end;
end;

procedure TAdvStringGrid.SaveToHTML(Filename:string; Show: boolean = false; Unicode: boolean = true);
begin
  OutputToHTML(Filename, False, Show, Unicode);
end;

procedure TAdvStringGrid.AppendToHTML(Filename:string; Show: boolean = false; Unicode: boolean = true);
begin
  OutputToHTML(Filename, True, Show, Unicode);
end;

function TAdvStringGrid.SaveToHTMLString(dir:string): string;
var
  i,j,mc,mr,ri: Integer;
  s,al,av,afs,afe,ass,ase,tablestyle: string;
  VAlignValue: TVAlignment;
  slist: TStringlist;
  AlignValue: TAlignment;
  TopRow: Integer;
  strtCol,strtRow: Integer;
  wraptxt,colwtxt,CellText,SpanTxt: string;
  DoneColW: Boolean;
  Span:TPoint;
  AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  AState: TGridDrawState;
  HAlign: TAlignment;
  VAlign: TVAlignment;
  WW: Boolean;
  GD: TCellGradientDirection;
  cssval: string;
  cssidx: integer;
  CSSList: TStringList;
  res: string;
  Pic: TCellGraphic;
  ImgLstBmp: TBitmap;
  images_counter:integer;
  htmlhdr: string;
  summ: string;
  imgidx,err: integer;
  il: TIntList;

  function HTMLAddImage(Pic: TGraphic;counter:integer;dir:string): string;
  var
    JPic: TJPEGImage;
    BPic: TBitmap;
    fname:string;
  begin
    if not DirectoryExists(dir + HTMLSettings.ImageFolder) then
      if not CreateDir(dir + HTMLSettings.ImageFolder) then
        raise Exception.Create('Cannot create ' + dir + 'images');

    fname := dir + HTMLsettings.ImageFolder + '/' + HTMLSettings.ImageBaseName + inttostr(counter) + '.jpg';

    if not (Pic is TJPEGImage) then
    begin //Convert the image
      JPic := TJPEGImage.Create;
      try
        BPic := TBitmap.Create; //we can't assign a metafile to a jpeg, so the temporary bitmap.
        try
          BPic.Width := Pic.Width;
          BPic.Height := Pic.Height;
          BPic.Canvas.Draw(0, 0, Pic);
          JPic.Assign(BPic);
        finally
          FreeAndNil(BPic);
        end;

        JPic.SaveTofile(fname);
      finally
        FreeAndNil(JPic);
      end; //finally
    end
    else
      Pic.SaveTofile(fname);

    Result := fname;
  end;

  function MakeHREF(s:string):string;
  begin
   Result := s;
   if not URLshow then Exit;
   if (pos('://',s) > 0) and (pos('</',s) = 0) then
   begin
   if not URLFull then
      Result := '<a href=' + s + '>' + copy(s,pos('://',s)+3,255) + '</a>'
     else
      Result := '<a href=' + s + '>' + s + '</a>';
    end;

   if (pos('mailto:',s) > 0) and (pos('</',s) = 0) then
    begin
     if not URLFull then
      Result := '<a href=' + s + '>' + copy(s,pos('mailto:',s) + 7,255)+'</a>'
     else
      Result := '<a href=' + s + '>' + s + '</a>';
    end;
  end;

  procedure AppendStr(var s: string; newstr: string);
  begin
    if s = '' then
      s := newstr
    else
      s := s + ';' + newstr;
  end;

  function CSS(AFont: TFont; AColor: TColor; AHAlign: TAlignment; VAlign: TVAlignment): string;
  var
    res: string;
  begin
    res := '';

    if (AColor <> $7fffffff) and FHTMLSettings.SaveColor then
      AppendStr(res,'background-color: #'+ HTMLColor(ColorToRGB(AColor))+'');

    if (AFont.Color <> $7fffffff) and FHTMLSettings.SaveColor then
      AppendStr(res,'color: #'+ HTMLColor(ColorToRGB(AFont.Color))+'');

    AppendStr(res,'font-size:'+IntTostr(AFont.Size)+'pt');

    if fsItalic in AFont.Style then
      AppendStr(res,'font-style: italic');

    if fsBold in AFont.Style then
      AppendStr(res,'font-weight: bold');

    AppendStr(res,'font-family: '+AFont.Name+'');

    case AHAlign of
    taCenter: AppendStr(res,'text-align: center');
    taRightJustify: AppendStr(res,'text-align: right');
    end;

    case VAlign of
    vtaTop: AppendStr(res,'vertical-align: top');
    vtaCenter: AppendStr(res,'vertical-align: middle');
    vtaBottom: AppendStr(res,'vertical-align: bottom');
    end;

    Result := res;
  end;

  function ExportImg(ACol,ARow: integer; lst: TStringList; celltext: string; Pic: TCellGraphic): string;
  var
    image: string;
    k: integer;
    FImages: TCustomImageList;
  begin
    if Assigned(Pic) then
      case Pic.Celltype of
      ctDataImage:
        begin
          FImages := GetCellImageList(ACol,ARow);
          val(celltext,imgidx,err);
          s := '';
          if Assigned(FImages) and (err = 0) and (imgidx >= 0) and (imgidx < GridImages.Count) then
          begin
            ImgLstBmp := TBitmap.Create;
            FImages.GetBitmap(imgidx, ImgLstBmp);
            image := '<img src= "file://' + HTMLAddImage(ImgLstBmp,images_counter,dir)+'">';
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' + s + image + '</td>');
            ImgLstBmp.Free;
            inc(images_counter);
          end
          else
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');

        end;
      ctImages:
        begin
          FImages := GetCellImageList(ACol,ARow);
          if Assigned(FImages) then
          begin
            il := TIntList(pic.FCellBitmap);

            if Assigned(il) then
            begin
              image := '';
              for k := 0 to il.Count - 1 do
              begin
                ImgLstBmp := TBitmap.Create;
                FImages.GetBitmap(il.Items[k], ImgLstBmp);
                image := image + '<img src= "file://' + HTMLAddImage(ImgLstBmp,images_counter,dir)+'">';
                ImgLstBmp.Free;
                inc(images_counter);
              end;

            end;
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' + image + s + '</td>');
          end;

        end;
      ctImageList:
        begin
          FImages := GetCellImageList(ACol,ARow);
          if Assigned(FImages) and (pic.FCellIndex >= 0) and (pic.FCellIndex < GridImages.Count) then
          begin
            ImgLstBmp := TBitmap.Create;
            FImages.GetBitmap(pic.FCellIndex, ImgLstBmp);
            image := '<img src= "file://' + HTMLAddImage(ImgLstBmp,images_counter,dir)+'">';
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' + image + s + '</td>');
            ImgLstBmp.Free;
            inc(images_counter);
          end
          else
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</TD>');
        end;
      ctPicture, ctInterface:
        begin
          if (Pic.CellBitmap <> nil) then
          begin
            image := '<img src= "file://' + HTMLAddImage(TPicture(Pic.CellBitmap).Graphic,images_counter,dir)+'">';
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' + s + image + '</td>');
            inc(images_counter);
          end
          else
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
        end;
      ctBitmap:
        begin
          if (Pic.CellBitmap <> nil) then
          begin
            image := '<img src= "file://'+HTMLAddImage(Pic.CellBitmap,images_counter,dir) + '">';
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+image+'</td>');
            inc(images_counter);
          end
          else
            lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
        end;
      ctNode:
        begin
          lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>+' +s+'</td>');
        end;
      else
        lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
      end
      else
        lst.Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
  end;

begin
  StrtCol := FixedCols;
  StrtRow := FixedRows;

  if FSaveFixedCells or FSaveFixedCols then
    StrtCol := 0;

  if FSaveFixedCells or FSaveFixedRows then
    StrtRow := 0;

  SList := TStringlist.Create;
  SList.Sorted := False;

  CSSList := TStringList.Create;

  DoneColW := False;

  htmlhdr := '';

  if FHTMLSettings.XHTML then
  begin
    htmlhdr := htmlhdr + '<?xml version="1.0" encoding="utf-8"?>'#13#10
    +'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'#13#10
    +'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'#13#10
    +'<HTML xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'#13#10;
  end;

  htmlhdr := htmlhdr + FHTMLSettings.HeaderText;

  if FHTMLSettings.PrefixTag <> '' then
    htmlhdr := htmlhdr + FHTMLSettings.PrefixTag;

  if FHTMLSettings.TableStyle <> '' then
    TableStyle := ' ' + FHTMLSettings.TableStyle + ' '
  else
    TableStyle := '';

  if FHTMLSettings.Summary <> '' then
    summ := 'summary="' + HTMLSettings.Summary + '" '
  else
    summ := '';

  SList.Add('<table border="'+IntToStr(FHTMLSettings.BorderSize)+'" '+
      'cellspacing="'+IntToStr(FHTMLSettings.CellSpacing)+'" ' +
      'cellpadding="'+IntToStr(FHTMLSettings.CellPadding)+'" ' +
      summ +
      TableStyle +
      ' width="' + IntToStr(FHTMLSettings.Width) + '%">');  // begin the table

  TopRow := StrtRow;

  if (FixedRows > 0) and (FSaveFixedCells or FSaveFixedRows) then
  begin
    SList.Add('<tr>');
    DoneColW := True;

    for i := StrtCol to ColCount - 1 do
    begin
      if IsBaseCellEx(i,0,mc,mr) then
      begin
        Span := CellSpan(i,0);

        SpanTxt := '';

        if Span.X > 0 then
          SpanTxt := ' colspan="' + IntToStr(Span.X + 1) + '"';

        if Span.Y > 0 then
          SpanTxt := SpanTxt + ' rowspan="' + IntToStr(Span.Y + 1) + '"';

        ri := RemapCol(i);

        CellText := SaveCell(ri,0);

        s := HTMLLineBreaks(CellText);
        s := MakeHREF(s);

        //if s = '' then
        //  s := '<BR>';
        if s = '' then
          s := '&nbsp;';

        {
        al := '';
        ac := '';
        afs := '';
        afe := '';
        av := '';

        AlignValue := GetCellAlignment(i,0).Alignment;

        if (s <> '') and (AlignValue <> taLeftJustify) then
        begin
          if AlignValue = taRightJustify then
            al := ' align="right"';
          if AlignValue=taCenter then
            al := ' align="center"';
        end;

        VAlignValue := GetCellAlignment(i,0).VAlignment;
        if (s <> '') and (VAlignValue <> vtaCenter) then
        begin
          if VAlignValue = vtaTop then
            av := ' valign="top"';
          if VAlignValue = vtaBottom then
            av := ' valign="bottom"';
        end;
        }

        if FHTMLSettings.ColWidths.Count > i then
          colwtxt := ' width=' + IntToStr(FHTMLSettings.ColWidths.Items[i])+'px'
        else
          colwtxt := '';

        Canvas.Font.Color := $7fffffff;
        Canvas.Font.Style := [];

        GetVisualProperties(i,0,AState,False,False,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlign,VAlign,WW,GD);

        {
        afs := '';
        afe := '';
        if (Canvas.Font.Color <> $7fffffff) and FHTMLSettings.SaveColor then
        begin
          afs := '<font color="#'+HTMLColor(dword(ColorToRGB(Canvas.Font.Color))) + '">';
          afe := '</font>';
        end;

        ass := '';
        ase := '';
        if FHTMLSettings.SaveFonts then
        begin
          if (fsBold in Canvas.Font.Style) then
          begin
            ass := ass + '<b>';
            ase := ase + '</b>';
          end;
          if (fsItalic in Canvas.Font.Style) then
          begin
            ass := ass + '<i>';
            ase := '</i>' + ase;
          end;
          if (fsUnderline in Canvas.Font.Style) then
          begin
            ass := ass + '<u>';
            ase := '</u>' + ase;
          end;
        end;
        }

        if WW then
          WrapTxt := ''
        else
          WrapTxt := ' nowrap="nowrap"';

        cssval := CSS(Canvas.Font, FixedColor, HAlign, VAlign);

        cssidx := CSSList.IndexOf(cssval);
        if cssidx = -1 then
          cssidx := CSSList.Add(cssval);

        if FHTMLSettings.ExportImages then
          Pic := CellGraphics[ri, 0]
        else
          Pic := nil;

        ExportImg(i, 0, SList, celltext, pic);
      end;
    end;
    SList.Add('</tr>');
    TopRow := 1;
  end;

  ExportNotification(esExportStart, TopRow);

  images_counter := 1;

  for i := TopRow to RowCount - 1 do
  begin
    ExportNotification(esExportNextRow, i);
    SList.Add('<tr>');

    for j := StrtCol to ColCount - 1 do
    begin
      if IsBaseCellEx(j,i,mc,mr) then
      begin
        Span := CellSpan(j,i);

        SpanTxt := '';

        if Span.X > 0 then
          SpanTxt := ' colspan="' + IntToStr(Span.X + 1) + '"';

        if Span.Y > 0 then
          SpanTxt := SpanTxt + ' rowspan="' + IntToStr(Span.Y + 1) + '"';

        ri := RemapCol(j);
        CellText := SaveCell(ri,i);
        s := CellText;

        if HTMLSettings.ConvertSpecialChars then
          s := FixMarkup(s);

        if HTMLSettings.NonBreakingText then
          s := FixNonBreaking(s);

        s := HTMLLineBreaks(s);
        s := MakeHREF(s);

        al := '';
        afs := '';
        afe := '';
        ass := '';
        ase := '';
        AlignValue := GetCellAlignment(j,i).Alignment;

        if (AlignValue <> taLeftJustify) and (s <> '') then
        begin
          if AlignValue = taRightJustify then
            al := ' align="right"';

          if AlignValue=taCenter then
            al := ' align="center"';
        end;

        VAlignValue := GetCellAlignment(j,0).VAlignment;
        if (s <> '') and (VAlignValue <> vtaCenter) then
        begin
          if VAlignValue = vtaTop then
            av := ' valign="top"';
          if VAlignValue = vtaBottom then
            av := ' valign="bottom"';
        end;


        //if (i < FixedRows) or (j < FixedCols) then
        //begin
        //  ac := ' bgcolor="#' + HTMLColor(ColorToRGB(FixedColor)) + '"';
        //end
        //else
        //  Canvas.Brush.Color := $7fffffff;

        Canvas.Brush.Color := $7fffffff;
        Canvas.Font.Color := $7fffffff;
        Canvas.Font.Style := [];

        GetVisualProperties(j, i, AState, False, False, True, Canvas.Brush,
          AColorTo, AMirrorColor, AMirrorColorTo, Canvas.Font, HAlign, VAlign, WW, GD);

        if IsFixed(j,i) then
          Canvas.Brush.Color := FixedColor;

        cssval := CSS(Canvas.Font, Canvas.Brush.Color, HAlign, VAlign);

        cssidx := CSSList.IndexOf(cssval);
        if cssidx = -1 then
          cssidx := CSSList.Add(cssval);

        if (FHTMLSettings.ColWidths.Count > j - strtcol) and not DoneColW then
          colwtxt := ' width=' + IntToStr(FHTMLSettings.ColWidths.Items[j - strtcol ])+'px'
        else
          colwtxt := '';

        //if Trim(s) = '' then
        //  if HTMLSettings.XHTML then
        //    s := '<BR/>'
        //  else
        //    s := '<BR>';

        if SysUtils.Trim(s) = '' then
          s := '&nbsp;';

        //Add('<td' + spantxt + wraptxt + al + av + ac + colwtxt + '>'+ afs + ass + s + ase + afe + '</td>');

        if WW then
          WrapTxt := ''
        else
          WrapTxt := ' nowrap="nowrap"';

        //Export Images

        if FHTMLSettings.ExportImages then
          Pic := CellGraphics[ri, i]
        else
          Pic := nil;
        ExportImg(j,i,SList, celltext, pic);
      end;
    end;

    SList.Add('</tr>');
  end;

  ExportNotification(esExportDone, -1);

  SList.Add('</table>');
  if FHTMLSettings.SuffixTag <> '' then
    SList.Add(FHTMLSettings.SuffixTag);

  if HTMLSettings.FooterText <> '' then
    SList.Add(FHTMLSettings.FooterText);

  if FHTMLSettings.XHTML then
    SList.Add('</HTML>');

  res := '<style>'#13#10;

  for cssidx := 0 to CSSList.Count - 1 do
  begin
    res := res + '.c'+inttostr(cssidx)+' {'+csslist[cssidx]+'}'#13#10;
  end;
  res := res + '</style>'#13#10;

  Result := htmlhdr + res + SList.Text;
  SList.Free;
  CSSList.Free;
end;

procedure TAdvStringGrid.OutputToHTML(Filename:string; AppendMode: Boolean; Show: boolean = false; Unicode: boolean = true);
var
  dir:string;
  i: integer;
  hdrsl, sl: TStringList;

begin
  sl := TStringList.Create;

  if AppendMode then
  try
    sl.LoadFromFile(FileName);
  except
  end;

  if FHTMLSettings.HeaderFile <> '' then
  begin
    hdrsl := TStringList.Create;
    try
      hdrsl.LoadFromFile(FHTMLSettings.HeaderFile);
      sl.AddStrings(hdrsl);
    finally
      hdrsl.Free;
    end;
  end;

  dir := ExtractFilePath(filename);

  for i := 1 to length(dir) do
  begin
    if dir[i] = '\' then
      dir[i] := '/';
  end;

  sl.Add(SaveToHTMLString(dir));

  if FHTMLSettings.FooterFile <> '' then
  begin
    hdrsl := TStringList.Create;
    try
      hdrsl.LoadFromFile(FHTMLSettings.FooterFile);
      sl.AddStrings(hdrsl);
    finally
      hdrsl.Free;
    end;
  end;

  try
    {$IFDEF DELPHI_UNICODE}
    if Unicode then
      sl.SaveToFile(FileName, FEncoding)
    else
       sl.SaveToFile(FileName, TEncoding.ASCII);
    {$ENDIF}

    {$IFNDEF DELPHI_UNICODE}
    sl.SaveToFile(FileName);
    {$ENDIF}
  finally
    sl.Free;
  end;


  if FHTMLSettings.AutoPreview or Show then
    ShellExecute(Application.Handle,'open',PChar(FileName),nil,nil,SW_NORMAL);
end;

procedure TAdvStringGrid.LoadFromXML(FileName: string; LevelToRow: boolean = false; LoadFieldDescr:boolean = true);
var
  Doc: Variant;
  i, Fc, Fr, c, r, mc, mr, l: Integer;
  s: string;

  procedure LoadChildNodes(aNode: Variant);
  var
    a, j: Integer;
    RowAlreadyAdded: Boolean;
  begin
    RowAlreadyAdded := False;

    if (VarType(aNode.Attributes) = varDispatch) then
    begin
      if Assigned(IDispatch(aNode.Attributes)) then
      begin
        for a := 0 to aNode.Attributes.Length - 1 do
        begin
          if ColCount <= c + fc then
            ColCount := c + fc + 1;

          if RowCount <= r + fr then
            RowCount := r + fr + 1;

          if (Cells[c + fc, 0] = '') and (SaveFixedCells or SaveFixedRows) then
            LoadCell(c + fc, 0, aNode.attributes.item[a].nodeName);

          s := aNode.attributes.item[a].Text;

          s := StringReplace(s,'$amp;','&',[rfReplaceAll]);
          s := StringReplace(s,'&gt;','>',[rfReplaceAll]);
          s := StringReplace(s,'&lt;','<',[rfReplaceAll]);
          s := StringReplace(s,'&quot;','"',[rfReplaceAll]);

          LoadCell(c + fc, r + fr, s);

          if c + fc > mc then
            mc := c + fc;

          if r + fr > mr then
            mr := r + fr;

          inc(c);
        end;

        if LevelToRow and (aNode.Attributes.length >= 1) then
        begin
          inc(r);
          c := l;
          RowAlreadyAdded := True;
        end;

      end;
    end;

    if (aNode.ChildNodes.Length <= 1) {and (aNode.nodeType = 3)} then
    begin
      if aNode.ChildNodes.Length = 1 then   // FF: Elements like <Accounts attributes... />
      begin
        if ColCount <= c +  fc then
          ColCount := c + fc + 1;
        if RowCount <= r + fr then
          RowCount := r + fr + 1;


        if (Cells[c + fc, 0] = '') and (SaveFixedCells or SaveFixedRows) and LoadFieldDescr then
        begin
          LoadCell(c + fc, 0, aNode.nodeName);
        end;

        if aNode.childNodes.Length = 1 then
        begin
          s := aNode.Text;

          s := StringReplace(s,'$amp;','&',[rfReplaceAll]);
          s := StringReplace(s,'&gt;','>',[rfReplaceAll]);
          s := StringReplace(s,'&lt;','<',[rfReplaceAll]);
          s := StringReplace(s,'&quot;','"',[rfReplaceAll]);

          if QuoteEmptyCells then
          begin
            if s = '""' then
              s := '';
          end;

          LoadCell(c + fc, r + fr, s);

          if c + fc > mc then
            mc := c + fc;

          if r + fr > mr then
            mr := r + fr;

        end;
        inc(c);
      end
      else
      begin
        // empty node
        LoadCell(c + fc, r + fr, '');
        inc(c);
      end;
    end
    else  // if Node has childs
    begin
      if LevelToRow and not RowAlreadyAdded then
      begin
        inc(r);
        c := 0;
      end;

      inc(l);

      for j:= 0 to aNode.ChildNodes.Length - 1 do
      begin
        LoadChildNodes(aNode.childNodes.Item[j]);
      end;
    end;
  end;

begin

  if not FileExists(FileName) then
  begin
    raise Exception.Create('XML file not found');
    Exit;
  end;

  try
    Doc := CreateOleObject('Microsoft.XMLDOM');
  except
    raise Exception.Create('XMLDOM server component not found');
    Exit;
  end;

  try
    Doc.load(FileName);
  except
    raise;
    Exit;
  end;

  if Doc.ParseError.errorCode <> 0 then
  begin
    raise Exception.Create('XMLDOM Parsing error '+InttoStr(Doc.parseError.errorCode)+' on line '+inttostr(Doc.parseError.line));
    Exit;
  end;

  fc := SaveStartCol;

  if (SaveFixedCells or SaveFixedRows) and not LoadFieldDescr then
    fr := 0
  else
    fr := FixedRows;

  mc := fc;
  mr := fr;

  r := 0;
  try
    for i := 0 to Doc.DocumentElement.ChildNodes.Length - 1 do
    begin
      c := 0;
      l := 1;

      if LevelToRow and (Doc.DocumentElement.ChildNodes.Item[i].Attributes.Length < 1) and (i = 0) then
        r := -1;      // avoid empty row at the top

      LoadChildNodes(Doc.DocumentElement.ChildNodes.Item[i]);
      if not LevelToRow then
        inc(r);
    end;

    ColCount := mc + 1;
    RowCount := mr + 1;
  finally
    //Doc._Release;
  end;
  CellsLoaded;
end;

procedure TAdvStringGrid.SaveToJSON(FileName: string; RecordDescr: string; FieldDescr: TStrings);
var
  sl: TStringList;
  i,j: integer;
  s,nc,cv: string;
  useflds: boolean;

begin
  sl := TStringList.Create;

  useflds := Assigned(FieldDescr) and (FieldDescr.Count >= SaveEndCol - SaveStartCol);

  try
    for i := SaveStartRow to SaveEndRow do
    begin
      s := '';

      for j := SaveStartCol to SaveEndCol do
      begin
        cv := SaveCell(j,i);
        cv := StringReplace(cv,'"','\"',[rfReplaceAll]);

        if useflds then
          nc := '{"' +  FieldDescr[j - SaveStartCol] + '":"' + cv +'"}'
        else
          nc := '"' + cv + '"';

        if j = SaveStartCol then
          s := nc
        else
          s := s + ',' + nc;
      end;

      if RecordDescr <> '' then
        s := '{"' + RecordDescr + '":[' + s + ']}'
      else
        s := '[' + s + ']';

      if sl.Count = 0 then
        sl.Add('{"grid":[' + s)
      else
        sl.Add(','+ s);
    end;

    sl.Add(']}');
    sl.SaveToFile(FileName);
  finally
    sl.Free;
  end;
end;

procedure TAdvStringGrid.SaveToXML(FileName: string; ListDescr, RecordDescr:string;FieldDescr: TStrings; ExportEmptyCells: boolean=false);
var
  i,j: Integer;
  f: TextFile;
  s: string;
  cr, n: Integer;
  nprogr,oprogr: integer;

begin
  Assignfile(f,filename);
  {$i-}
  Rewrite(f);
  {$i+}
  if IOResult <> 0 then
    raise EAdvGridError.Create('Cannot Create file '+FileName);

  writeln(f,'<?xml version="1.0" encoding="'+ FXMLEncoding +'" ?>');
  writeln(f,'<' + ListDescr + '>');

  ExportNotification(esExportStart, SaveStartRow);

  (* Saves data column-wise
  for i := SaveStartCol to SaveEndCol do
  begin
    ExportNotification(esExportNewRow, i);

    if Assigned(FieldDescr) and (i - SaveStartCol < FieldDescr.Count) then
            writeln(f,"<" + FieldDescr.Strings[i - SaveStartCol]+">")
          else
            writeln(f,"<FIELD" + IntToStr(i - SaveStartRow)+">");

    for j := SaveStartRow to SaveEndRow do
    begin
      cr := RemapCol(j);

      if IsBaseCell(cr,i) then
      begin
        s := SaveCell(i,cr);

        if (s <> "") or ExportEmptyCells then
        begin
          if QuoteEmptyCells and (s="") then
          begin
            s:= """";
          end;
          write(f,"<"+RecordDescr+">");


          s := StringReplace(s,"&","$amp;",[rfReplaceAll]);
          s := StringReplace(s,">","&gt;",[rfReplaceAll]);
          s := StringReplace(s,"<","&lt;",[rfReplaceAll]);
          s := StringReplace(s,""","&quot;",[rfReplaceAll]);

          write(f,s);

          writeln(f,"</" + RecordDescr + ">");

        end;
      end;
    end;
      if Assigned(FieldDescr) and (i - SaveStartRow< FieldDescr.Count) then
            writeln(f,"</" + FieldDescr.Strings[i - SaveStartRow]+">")
          else
            writeln(f,"</FIELD" + IntToStr(i - SaveStartRow)+">");
  end;
  *)

  oprogr := -1;

  if FSaveHiddenCells then
    n := FNumHidden
  else
    n := 0;

  for i := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNextRow, i);

    writeln(f,'<'+RecordDescr+'>');
    for j := SaveStartCol to SaveEndCol + n do
    begin
      if FSaveHiddenCells then
        cr := j
      else
        cr := RemapCol(j);

      if IsBaseCell(cr,i) then
      begin
        s := SaveCell(cr,i);

        if (s <> '') or ExportEmptyCells then
        begin
          if QuoteEmptyCells and (s='') then
          begin
            s:= '""';
          end;

          if Assigned(FieldDescr) and (cr - SaveStartCol < FieldDescr.Count) then
            write(f,'<' + FieldDescr.Strings[cr - SaveStartCol]+'>')
          else
            write(f,'<FIELD' + IntToStr(cr - SaveStartCol)+'>');

          s := StringReplace(s,'&','$amp;',[rfReplaceAll]);
          s := StringReplace(s,'>','&gt;',[rfReplaceAll]);
          s := StringReplace(s,'<','&lt;',[rfReplaceAll]);
          s := StringReplace(s,'"','&quot;',[rfReplaceAll]);

          write(f,s);

          if Assigned(FieldDescr) and (cr - SaveStartCol< FieldDescr.Count) then
            writeln(f,'</' + FieldDescr.Strings[cr - SaveStartCol]+'>')
          else
            writeln(f,'</FIELD' + IntToStr(cr - SaveStartCol)+'>');
        end;
      end;
    end;
    writeln(f,'</' + RecordDescr + '>');

    if Assigned(FOnFileProgress) then
    begin
      nprogr := Round((i)/(Max(1,SaveEndRow - SaveStartRow))*100);
      if nprogr <> oprogr then
        FOnFileProgress(self,nprogr);
      oprogr := nprogr;
    end;

  end;

  writeln(f,'</' + ListDescr + '>');

  ExportNotification(esExportDone, -1);
  CloseFile(f);
end;

procedure TAdvStringGrid.CopyBinFunc(gd: TGridRect);
var
  ms: TMemoryStream;
  Data: THandle;
  DataPtr: Pointer;
begin
  ms := TMemoryStream.Create;

  Clipboard.Open;

  try
    SaveRectToBinStream(TRect(gd),ms);

    Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, ms.Size);
    try
      DataPtr := GlobalLock(Data);
      try
        Move(ms.Memory^, DataPtr^, ms.Size);
        SetClipboardData(CF_GRIDCELLS, Data);
      finally
        GlobalUnlock(Data);
      end;
    except
      GlobalFree(Data);
      raise;
    end;
  finally
    ms.Free;
    Clipboard.Close;
  end;
end;

procedure TAdvStringGrid.CopyRTFFunc(ACol,ARow: Integer);
var
  s: string;
  GHandle: THandle;
  Gptr: PChar;

  cf_rtf: word;
begin
  s := Cells[ACol,ARow];
  if Pos('{\',s) = 0 then
    Exit;

  GHandle := GlobalAlloc(gmem_MoveAble,Length(s));
  if GHandle = 0 then
    Exit;

  GPtr := GlobalLock(GHandle);
  if GPtr = nil then
  begin
    GlobalFree(GHandle);
    Exit;
  end;

  StrCopy(gptr,'');
  StrCat(gptr,PChar(s));

  GlobalUnlock(GHandle);

  if not OpenClipBoard(Handle) then
    GlobalFree(GHandle)
  else
  begin
    cf_rtf := RegisterClipboardformat('Rich Text Format');
    SetClipBoardData(cf_rtf,GHandle);
    CloseClipBoard;
  end;
end;

procedure TAdvStringGrid.SetSelectionAsText(const Value: string);
var
  Content,endofRow: PChar;
  cr: PChar;
  ct,line:string;
  s,z,tabpos,mr,mc: Integer;
  gr:TGridRect;
  Allow: Boolean;
  ws: widestring;
  ll: Integer;
  nc: boolean;

begin
  z := Selection.Top;
  s := Selection.Left;

  Content := PChar(Value);
  EndOfRow := StrScan(Content,#0);

  gr.Top := z;
  gr.Left := s;
  gr.Right := s;
  gr.Bottom := z;

  mr := z;
  mc := s;

  repeat
    cr := StrScan(Content,#13);
    if cr = nil then
      cr := EndOfRow;
    Line := Copy(StrPas(Content),1,cr - Content);

    while (VarPos(#9,Line,TabPos) > 0) do
    begin
      ct := Copy(line,1,TabPos - 1);

      if (Pos(#10,ct) > 0) then
      begin
        if FExcelClipboardFormat or (1 > 0) then
        begin
          if Pos('"',ct)=1 then Delete(ct,1,1);
          if Pos('"',ct) = Length(ct) then
            Delete(ct,Length(ct),1);

          CSVToLineFeeds(ct);
        end;
      end;

      if (s <= ColCount) and (z <= RowCount) then
        begin
          Allow := True;

          if pos('|\',ct) = 1 then
          begin
            ws := DecodeWideStr(ct);
            ct := EncodeWideStr(ws);
          end;

          if Allow then
          begin
            GridCells[s,z] := ct;

            if s > mc then
              mc := s;
            if z > mr then
              mr := z;
          end;
        end;

      Delete(line,1,tabpos);
      inc(s);
      if (s > ColCount) then
        ColCount := s;
      if s > gr.Right then
        gr.Right := s;
    end;

    nc := false;

    if (s <= ColCount) and (z <= RowCount) then
    begin
      if (cr <> EndOfRow) or (Line <> '') then
      begin
        Allow := True;
        nc := true;

        if (Pos(#10,Line) > 0) then
        begin
          if Pos('"',Line)=1 then Delete(Line,1,1);
          if Pos('"',Line) = Length(Line) then
            Delete(Line,Length(Line),1);
          CSVToLineFeeds(Line);
        end;

        if pos('|\',ct) = 1 then
        begin
          ws := DecodeWideStr(Line);
          Line := EncodeWideStr(ws);
        end;

        if Allow then
        begin
          if (s <= ColCount) and (z <= RowCount) then
            GridCells[s,z] := Line;

          if s > mc then
            mc := s;
          if z > mr then
            mr := z;
        end;
      end;
    end;

    if nc then
      Inc(s);

    if (s > ColCount) then
      ColCount := s;

    if s > gr.Right then
      gr.Right := s;

    Content := cr + 1;

    if Content^ = #10 then
    begin
      Content := cr + 2;
    end;

    s := Selection.Left;

    if (Content^ <> #0) then
      Inc(z);

    if FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) then
      ll := RowCount - 1
    else
      ll := RowCount;

    if (z = ll) and
       (cr <> EndOfRow) and (Content^ <> #0) then
       begin
         RowCount := RowCount + 1;
       end;

    if z > gr.Bottom then
      gr.Bottom := z;

  until cr = EndOfRow;

  gr.Bottom := mr;
  gr.Right := mc;

  gr.Left := RemapCol(gr.Left);
  gr.Right := RemapCol(gr.Right);

  CellsChanged(TRect(gr));
end;


function TAdvStringGrid.GetSelectionAsText: string;
begin
  Result := CopyFuncStr(Selection,false);
end;

function TAdvStringGrid.CopyFuncStr(gd: TGridRect; DoDisjunct: Boolean): string;
var
  s,z,rc,zr: Integer;
  len: Integer;
  buffer,ptr: PChar;
  ct: string;
  es: TGridExportState;

begin
  Result := '';

  FClipTopLeft := Point(gd.Left,gd.Top);

  len := 1;

  ExportNotification(esExportStart, -1);

  if (gd.Top <= FixedRows) and (gd.Bottom >= RowCount - 1 - FixedFooters) then
    es := esExportNewRow
  else
    es := esExportSelRow;

  for z := gd.Top to gd.Bottom do
  begin
    ExportNotification(es, z);

    if FMouseActions.RowSelectPersistent then
      zr := RemapRowInv(z)
    else
      zr := z;

    if not (MouseActions.DisjunctRowSelect) or RowSelect[zr] or not DoDisjunct or
      MouseActions.DisjunctColSelect then
    begin
      for s := gd.Left to gd.Right do
      begin
        if not (MouseActions.DisjunctColSelect) or ColSelect[s] or not DoDisjunct then
        begin
          rc := RemapCol(s);
          ct := SaveCell(rc,z);

          if pos(#13,ct) > 0 then
            ct := '"' + CRToLF(ct) + '"';

          if not FNavigation.CopyHTMLTagsToClipboard and
            ((Pos('</',ct) > 0) or (Pos('<B',ct) > 0) or (Pos('<I',ct) > 0)) then
          begin
            ct := StrippedCells[rc,z];
          end
          else
          if Pos('{\',ct) > 0 then
          begin
            CellToRich(rc,z,RichEdit);
            ct := RichEdit.Text;
          end;
          if (LinesInText(ct,FMultiLineCells) > 1) and
             FExcelClipboardformat then LineFeedsToCSV(ct);

          len := len + Length(ct) + 1; //tab
        end;
      end;
      if gd.Top < gd.Bottom then
        len := len + 1;
    end;
  end;

  {$IFDEF DELPHI_UNICODE}
  len := len * 2;
  {$ENDIF}

  GetMem(Buffer,len);
  Buffer^ := #0;
  ptr := Buffer;

  try
    //fill buffer
    for z := gd.Top to gd.Bottom do
    begin
      ExportNotification(esExportNewRow, z);

      if FMouseActions.RowSelectPersistent then
        zr := RemapRowInv(z)
      else
        zr := z;

      if not (MouseActions.DisjunctRowSelect) or RowSelect[zr] or not DoDisjunct or
        MouseActions.DisjunctColSelect then
      begin
        for s := gd.Left to gd.Right do
        begin
          if not (MouseActions.DisjunctColSelect) or ColSelect[s] or not DoDisjunct then
          begin
            rc := RemapCol(s);
            ct := SaveCell(rc,z);

            if pos('|\',ct) = 1 then
              ct := DecodeWideStr(ct);

            if (Pos(#13,ct) > 0) then
            begin
              ct := '"' + CRToLF(ct) + '"';
            end;

            if not FNavigation.CopyHTMLTagsToClipboard and (Pos('</',ct) > 0) then
              ct := StrippedCells[rc,z]
            else
            if Pos('{\',ct) > 0 then
            begin
               CellToRich(rc,z,RichEdit);
               ct := RichEdit.Text;
            end;

            if (LinesInText(ct,FMultiLineCells)>1) and FExcelClipboardFormat then
              LineFeedsToCSV(ct);

             if s < gd.Right then
               ptr := StrEnd(StrPCopy(ptr,ct + #9))
             else
               ptr := StrEnd(StrPCopy(ptr,ct ));
          end;
        end;

//        ptr^ := #0;
//        Dec(ptr);

        if gd.Top < gd.Bottom then
        begin
          ptr := StrEnd(StrPCopy(ptr,#13#10));
        end;
      end;
    end;
  finally

    ptr^ := #0;

    Result := strpas(buffer);

    FreeMem(buffer,len);

    ExportNotification(esExportDone, -1);
  end;
end;

procedure TAdvStringGrid.CopyFunc(gd: TGridRect; DoDisjunct: Boolean);
var
  ct: string;

begin
  ct := CopyFuncStr(gd,DoDisjunct);

  {$IFDEF DELPHI_UNICODE}
  Clipboard.AsText := ct;
  {$ENDIF}

  {$IFNDEF DELPHI_UNICODE}
  ClipBoard.SetTextBuf(PChar(ct));
  {$ENDIF}

  if FNavigation.AllowRTFClipboard then
    CopyRTFFunc(gd.Left,gd.Top);

  if FNavigation.AllowFmtClipboard then
    CopyBinFunc(gd);
end;

procedure TAdvStringGrid.CopySelectionToClipboard;
var
  gd: TGridRect;
begin
  CorrectSelection;

  if MouseActions.DisjunctRowSelect then
  begin
    if Navigation.AllowFmtClipboard then
      CopyFunc(Selection,False)
    else
    begin
      gd.Top := GetSaveStartRow;
      gd.Left := FixedCols;
      gd.Bottom := GetSaveEndRow;
      gd.Right := ColCount - 1 - FixedRightCols;
      CopyFunc(gd,True);
    end;
  end
  else
  begin
    if MouseActions.DisjunctColSelect then
    begin
      if Navigation.AllowFmtClipboard then
        CopyFunc(Selection,False)
      else
      begin
        gd.Top := GetSaveStartRow;
        gd.Left := GetSaveStartCol;
        gd.Bottom := GetSaveEndRow;
        gd.Right := GetSaveEndCol;
        CopyFunc(gd,True);
      end;
    end
    else
      CopyFunc(Selection,False);
  end;

  FClipLastOp := coCopy;
end;

procedure TAdvStringGrid.CopyToClipBoardAsHTML;
var
  Data: THandle;
  DataPtr: Pointer;
  CF_HTML: word;
  s: string;
  {$IFNDEF DELPHI_UNICODE}
  sa: ansistring;
  {$ENDIF}
  {$IFDEF DELPHI_UNICODE}
  sa: utf8string;
  {$ENDIF}

begin
  s := SaveToHTMLString('');

  MakeFragment(s);

  {$IFNDEF DELPHI_UNICODE}
  sa := AnsiString(s);
  {$ENDIF}

  {$IFDEF DELPHI_UNICODE}
  sa := UTF8String(s);
  {$ENDIF}

  CF_HTML := RegisterClipboardFormat('HTML Format');

  Data := GlobalAlloc(GMEM_MOVEABLE, Length(sa));
  try
    // Obtain a pointer to the first byte of the allocated memory
    DataPtr := GlobalLock(Data);
    try
      // Move the data in Rec to the memory block
      Move(sa[1], DataPtr^, Length(sa));

      Clipboard.Open;
      try
        ClipBoard.SetAsHandle(CF_HTML, Data);
        ClipBoard.AsText := string(sa);
      finally
        Clipboard.Close;
      end;
    finally
      // Unlock the globally allocated memory
      GlobalUnlock(Data);
    end;
  except
    // A call to GlobalFree is required only if an exception occurs.
    //  Otherwise, the clipboard takes over managing any allocated
    //  memory to it.
    GlobalFree(Data);
    raise;
  end;
end;


procedure TAdvStringGrid.CopyToClipboard;
var
  gd: TGridRect;
begin
  gd.Top := GetSaveStartRow;
  gd.Left := GetSaveStartCol;
  gd.Bottom := GetSaveEndRow;
  gd.Right := GetSaveEndCol;
  CopyFunc(gd,False);
  FClipLastOp := coCopy;
end;

procedure TAdvStringGrid.CutToClipboard;
var
  s,z,rz: Integer;
  gd: TGridRect;
begin
  gd.Top := GetSaveStartRow;
  gd.Left := GetSaveStartCol;
  gd.Bottom := GetSaveEndRow;
  gd.Right := GetSaveEndCol;
  CopyFunc(gd,False);

  for z := gd.Left to gd.Right do
  begin
    rz := RemapCol(z);
    for s := gd.Top to gd.Bottom  do
      if (IsEditable(rz,s) or (Navigation.AllowClipboardAlways)) then
        Cells[s,z] := '';
  end;

  if ShowModified.Enabled then
  begin
    for s := gd.Top to gd.Bottom  do
      RowModified[s] := true;
  end;

  if (Navigation.ClipboardCutAction = caRemove) and (goRowSelect in Options) then
  begin
    RemoveRows(gd.Top, gd.Bottom - gd.Top + 1);
  end;

  FClipLastOp := coCut;
end;

procedure TAdvStringGrid.CutSelectionToClipboard;
var
  s,z,rc,zr: Integer;
  sel: TRect;
  rl: TIntList;
begin
  sel := TRect(Selection);
  CopySelectionToClipboard;

  if MouseActions.DisjunctRowSelect then
  begin
    for z := FixedRows to RowCount - 1 do
    begin
      if FMouseActions.RowSelectPersistent then
        zr := RemapRowInv(z)
      else
        zr := z;
      if RowSelect[zr] then
      begin
        ClearRows(z,1);
        if ShowModified.Enabled then
          RowModified[z] := true;
      end;
    end;
  end
  else
  begin
    if MouseActions.DisjunctColSelect then
    begin
      for z := FixedCols to ColCount - 1 do
        if ColSelect[z] then ClearCols(z,1);
    end
    else
      with Selection do
      begin
        if Assigned(UndoRedo) then
          UndoRedo.StartSequence;

        for s := Left to Right do
        begin
          rc := RealColIndex(s);
          for z := Top to Bottom do
            if IsEditable(rc,z) or Navigation.AllowClipboardAlways then
            begin
              if Assigned(UndoRedo) then
                UndoRedo.RegisterChange(rc,z,Cells[rc,z],'');
              Cells[rc,z] := '';
            end;
        end;

        if ShowModified.Enabled then
        begin
          for z := Top to Bottom  do
            RowModified[z] := true;
        end;

        if Assigned(UndoRedo) then
          UndoRedo.StopSequence;

        if Navigation.AllowFmtClipboard then
          ClearPropRect(Left,Top,Right,Bottom);
      end;
  end;

  FClipLastOp := coCut;

  if Assigned(OnCellsChanged) then
    OnCellsChanged(Self, sel);


  if (Navigation.ClipboardCutAction = caRemove) and (goRowSelect in Options) then
  begin
    if MouseActions.DisjunctRowSelect then
    begin
      rl := TIntList.Create(-1,-1);
      try
        for z := FixedRows to RowCount - 1 do
        begin
          if RowSelect[z] then
            rl.Add(z);
        end;
        ClearRowSelectInt;
        RemoveRowList(rl);
      finally
        rl.Free;
      end;


    end
    else
      RemoveRows(Selection.Top, Selection.Bottom - Selection.Top + 1);
  end;


  if NumHiddenColumns > 0 then
    Invalidate;
end;

procedure TAdvStringGrid.CellSelect(c,r: Integer);
begin

end;

procedure TAdvStringGrid.SetCellSelectMode(const Value: Boolean);
begin

end;


procedure TAdvStringGrid.CorrectSelection;
var
  sr: TGridRect;
  pt, sz: TPoint;
  flg: Boolean;
begin
  sr := Selection;

  flg := false;

  if IsMergedCell(Selection.Left, Selection.Top) then
  begin
    pt := BaseCell(Selection.Left, Selection.Top);
    if pt.X < sr.Left then
      sr.Left := pt.X;

    if pt.Y < sr.Top then
      sr.Top := pt.Y;
    flg := True;
  end;

  if IsMergedCell(Selection.Right, Selection.Bottom) then
  begin
    pt := BaseCell(Selection.Right, Selection.Bottom);
    sz := CellSpan(pt.X,pt.Y);

    if pt.X + sz.X > sr.Right then
      sr.Right := pt.X + sz.X;

    if pt.Y + sz.Y > sr.Bottom then
      sr.Bottom := pt.Y + sz.Y;
    flg := True;
  end;

  if flg then
    Selection := sr;
end;

procedure TAdvStringGrid.PasteSelectionFromClipboard;
var
  i,j,k,rc,rcs: Integer;
  s1,s2: string;
  dt1,dt2,dtv: TDateTime;
  f1,f2,fv: Double;
  i1,i2,c,iv,err1,err2: Integer;
  da1,da2,mo1,mo2,ye1,ye2,dmo,dye,dda: Word;
  Allow: Boolean;
  pc: string;
  selsize: Integer;
  cstate: boolean;
  pcols,prows: integer;
  os: TGridRect;
  sell: integer;
begin
  ImportNotification(isImportStart,-1);

  FPasteAll := false;

  CorrectSelection;

  if (goRowSelect in Options) then
    i := PasteFunc(FixedCols,Selection.Top,pcols,prows)
  else
    i := PasteFunc(Selection.Left,Selection.Top,pcols,prows);

  if not FNavigation.AllowSmartClipboard then
  begin
    os := TGridRect(Rect(Selection.Left, Selection.Top, Selection.Left + pcols, Selection.Top + prows));
    DoClipboardPasteDone(os);
    CellsLoaded;
    Exit;
  end;

  selsize := (Selection.Bottom - Selection.Top + 1) * (Selection.Right - Selection.Left + 1);

  // selection size is less or equal to copy size -> no smart clipboard
  if (selsize <= i) then
    Exit;

  PasteStart;

  if ((i = 1) or (selsize = i - 1))  and
     ((Selection.Left <> Selection.Right) or
      (Selection.Top <> Selection.Bottom)) then
  begin
    for j := Selection.Left to Selection.Right do
    begin
      rc := RemapCol(j);
      for k := Selection.Top to Selection.Bottom do
        if IsEditable(rc,k) or Navigation.AllowClipboardAlways then
        begin
          Allow := true;
          rcs := RemapCol(Selection.Left);
          pc := Cells[rcs,Selection.Top];

          if HasCheckBox(rcs,Selection.Top) then
          begin
            GetCheckBoxState(rcs,Selection.Top,cstate);
            if cstate then
              pc := CheckTrue
            else
              pc := CheckFalse;
          end;

          if Assigned(OnClipboardBeforePasteCell) and
             not ((j = Selection.Left) and (k = Selection.Top)) then
            OnClipboardBeforePasteCell(Self,j,k,pc,Allow);

          if Allow then
            PasteInCell(j,k,pc);

//            Cells[j,k] := pc;

          PasteNotify(FClipTopLeft, TGridRect(Rect(j,k,j,k)), coCopy);

          if Assigned(OnClipboardAfterPasteCell) and
             not ((j = Selection.Left) and (k = Selection.Top)) then
            OnClipboardAfterPasteCell(Self,j,k,pc);
        end;
    end;
  end;

  PasteDone;

  // copy to single column / single row
  if (i > 1) and
     ((Selection.Left = Selection.Right) or
      (Selection.Top = Selection.Bottom)) then
  begin
    sell := RemapCol(Selection.Left);
    s1 := Cells[sell,Selection.Top];
    if (Selection.Left = Selection.Right) then
      s2 := Cells[sell,Selection.Top + 1];
    if (Selection.Top = Selection.Bottom) then
      s2 := Cells[RemapCol(selection.Left + 1),Selection.Top];

    // try dates
    if (IsDateStr(s1) or (Pos(TimeSeparator,s1) > 0)) and
       (IsDateStr(s2) or (pos(TimeSeparator,s2) > 0)) then
    begin
      try
        dt1 := StrToDateTime(s1);
        dt2 := StrToDateTime(s2);

        dtv := dt2 - dt1;

        DecodeDate(dt1,ye1,mo1,da1);
        DecodeDate(dt2,ye2,mo2,da2);

        dmo := mo2 - mo1;
        dye := ye2 - ye1;
        dda := da2 - da1;

        for j := Selection.Left to Selection.Right do
        begin
          rc := RemapCol(j);
          for k := Selection.Top to Selection.Bottom do
          begin
            if IsEditable(rc,k) then
            begin
              if Pos(DateSeparator,s1) > 0 then
                pc := DateToStr(dt1)
              else
                pc := TimeToStr(dt1);

              Allow := true;

              if Assigned(OnClipboardBeforePasteCell) and
                 not ((j = Selection.Left) and (k = Selection.Top)) then
                OnClipboardBeforePasteCell(Self,j,k,pc,Allow);

              if Allow then
                PasteInCell(j,k,pc);

              PasteNotify(FClipTopLeft, TGridRect(Rect(j,k,j,k)), coCopy);

              if Assigned(OnClipboardAfterPasteCell) and
                 not ((j = Selection.Left) and (k = Selection.Top)) then
                OnClipboardAfterPasteCell(Self,j,k,pc);
            end;
            dt1 := GetNextDate(dt1,dye,dmo,dda,dtv);
          end;
        end;
        except
        end;
        CellsChanged(TRect(Selection));
        Exit;
      end;

    // try floats
    if (Pos(DecimalSeparator,s1) > 0) or (Pos(DecimalSeparator,s2) > 0) then
    begin
      try
        f1 := StrToFloat(s1);
        f2 := StrToFloat(s2);
        fv := f2 - f1;
        for j := Selection.Left to Selection.Right do
        begin
          rc := RemapCol(j);
          for k := Selection.Top to Selection.Bottom do
          begin
            if IsEditable(rc,k) then
            begin
              Allow := True;

              pc := Format(FloatFormat,[f1]);

              if Assigned(OnClipboardBeforePasteCell) and
                 not ((j = Selection.Left) and (k = Selection.Top)) then
                OnClipboardBeforePasteCell(Self,j,k,pc,Allow);

              if Allow then
              begin
                PasteInCell(j,k,pc);

                PasteNotify(FClipTopLeft, TGridRect(Rect(j,k,j,k)), coCopy);

                if Assigned(OnClipboardAfterPasteCell) and
                   not ((j = Selection.Left) and (k = Selection.Top)) then
                  OnClipboardAfterPasteCell(Self,j,k,pc);
               end;
            end;
            f1 := f1 + fv;
          end;
        end;
      except
      end;

      CellsChanged(TRect(Selection));
      Exit;
    end;

    // try integer
    Val(s1,i1,err1);
    val(s2,i2,err2);

    if (err1 = 0) and (err2 = 0) then
    begin
      iv := i2 - i1;
      for j := Selection.Left to Selection.Right do
      begin
        rc := RemapCol(j);
        for k := Selection.Top to Selection.Bottom do
        begin

          if IsEditable(rc,k) then
          begin
            Allow := true;
            pc := IntToStr(i1);

            if Assigned(OnClipboardBeforePasteCell) and
               not ((j = Selection.Left) and (k = Selection.Top)) then
              OnClipboardBeforePasteCell(Self,j,k,pc,Allow);

            if Allow then
            begin
              PasteInCell(j,k,pc);

              PasteNotify(FClipTopLeft, TGridRect(Rect(j,k,j,k)), coCopy);

              if Assigned(OnClipboardAfterPasteCell) and
                 not ((j = Selection.Left) and (k = Selection.Top)) then
                OnClipboardAfterPasteCell(Self,j,k,pc);
            end;

          end;
          i1 := i1 + iv;
        end;
      end;
      CellsChanged(TRect(Selection));
      Exit;
    end;

    // normal text repeat
    if Selection.Left = Selection.Right then
    begin
      for k := Selection.Top + i - 1 to Selection.Bottom do
      begin
        if IsEditable(RemapCol(Selection.Left),k) then
        begin
          Allow := true;
          pc := Cells[Selection.Left,k - i + 1];

          if Assigned(OnClipboardBeforePasteCell) and
             not (k = Selection.Top)  then
            OnClipboardBeforePasteCell(Self,Selection.Left,k,pc,Allow);

          if Allow then
          begin
            PasteInCell(Selection.Left,k, pc);

            if Assigned(OnClipboardAfterPasteCell) and
               not (k = Selection.Top)  then
              OnClipboardAfterPasteCell(Self,Selection.Left,k,pc);
          end;
        end;
      end;
      PasteNotify(Point(Selection.Left, Selection.Top), TGridRect(Rect(Selection.Left,Selection.Top + i - 1,Selection.Left,Selection.Bottom)),coCopy);
    end;

    if Selection.Top = Selection.Bottom then
    begin
      for k := Selection.Left + i - 1 to Selection.Right do
      begin
        if IsEditable(RemapCol(k),Selection.Top) then
        begin
          Allow := true;
          pc := Cells[k - i + 1,Selection.Top];

          if Assigned(OnClipboardBeforePasteCell) and
             not (k = Selection.Left)  then
            OnClipboardBeforePasteCell(Self,k,Selection.Top,pc,Allow);

          if Allow then
          begin
            PasteInCell(k,Selection.Top,pc);
            if Assigned(OnClipboardAfterPasteCell) and
               not (k = Selection.Left)  then
              OnClipboardAfterPasteCell(Self,k,Selection.Top,pc);
          end;
        end;
      end;
      PasteNotify(Point(Selection.Left, Selection.Top), TGridRect(Rect(Selection.Left + i - 1,Selection.Top,Selection.Right,Selection.Bottom)),coCopy);
    end;
  end;

  if (Selection.Bottom > Selection.Top) and (Selection.Left <> Selection.Right) and (prows = 1) then
  begin
    i1 := Selection.Top + 1;
    i2 := Selection.Bottom;
    c := Selection.Left;
    os := Selection;
    for i := i1 to i2 do
    begin
      Row := i;
      PasteFunc(c,i,pcols,prows)
    end;
    Selection := os;
  end;

  if (Selection.Bottom <> Selection.Top) and (Selection.Right > Selection.Left) and (pcols = 1) then
  begin
    i1 := Selection.Left + 1;
    i2 := Selection.Right;
    c := Selection.Top;
    os := Selection;
    for i := i1 to i2 do
    begin
      Col := i;
      PasteFunc(i,c,pcols,prows)
    end;
    Selection := os;
  end;

  ImportNotification(isImportDone,-1);

  CellsChanged(TRect(Selection));

  DoClipboardPasteDone(Selection);

  CellsLoaded;
end;

procedure TAdvStringGrid.PasteFromClipboard;
var
  pcols,prows: integer;
  r: TRect;
begin
  ImportNotification(isImportStart,-1);
  FPasteAll := true;
  PasteFunc(SaveStartCol,SaveStartRow,pcols,prows);
  ImportNotification(isImportDone,-1);
  r := Rect(SaveStartCol,SaveStartRow,SaveStartCol + pcols, SaveStartRow + prows);
  DoClipboardPasteDone(TGridRect(R));
  CellsLoaded;
end;


function TAdvStringGrid.PasteSize(p:PChar):TPoint;
var
  Content,endofRow,cr:PChar;
  Rows,Cols,c: Integer;
  tabpos: Integer;
  line: string;


begin
  Content := p;
  EndOfRow := StrScan(Content,#0);

  Rows := 0;
  Cols := 0;

  repeat
    cr := StrScan(Content,#13);

    if cr = nil then
      cr := EndofRow;

    if (cr = Content) then // extra line feed detected at end
      dec(Rows);

    Line := Copy(strpas(Content),1,cr - Content);
    c := 1;
    while (varpos(#9,line,tabpos)>0) do
    begin
      Inc(c);
      Delete(line,1,tabpos);
    end;

    if c > Cols then
      Cols := c;

    Content := cr + 1;
    if Content^ = #10 then
      Content := cr + 2;

    if cr <> EndOfRow then
      Inc(Rows);

  until cr = EndOfRow;

//  if (Cols > 0) and (Rows = 0) then
//    Rows := 1;

  Result.x := Cols;
  Result.y := Rows;

end;


procedure TAdvStringGrid.PasteInCell(ACol,ARow: Integer; Value: string);
var
  rc: Integer;
begin
  if SaveHiddenCells then
    rc := ACol
  else
    rc := RemapCol(ACol);

  if Assigned(UndoRedo) then
  begin
    UndoRedo.RegisterChange(rc,ARow,Cells[rc,ARow],Value);
  end;

  if HasCheckBox(rc,ARow) and not HasDataCheckBox(rc,ARow) then
  begin
    SetCheckBoxStateInt(rc,ARow, Value = CheckTrue)
  end
  else
  begin
    Cells[rc,ARow] := Value;
  end;

  // take hidden cells into account
  if rc <> ACol then
    RepaintCell(ACol,ARow);
end;

function TAdvStringGrid.PasteText(ACol,ARow: Integer;p:PChar;var Cols,Rows: integer): Integer;
var
  Content,endofRow: PChar;
  cr: PChar;
  hc: integer;
  ct,line:string;
  s,z,tabpos,mr,mc: Integer;
  numcells: Integer;
  gr:TGridRect;
  Allow: Boolean;
  ws: widestring;
  ll: Integer;
  nc,didpaste: boolean;

begin
  Result := 0;
  didpaste := false;

  if (ACol < 0) or (ARow < 0) then
    Exit;

  if not ((goEditing in Options) or
    (Navigation.AllowClipboardAlways) or (MouseActions.RangeSelectAndEdit)) then
     Exit;

  hc := 0;
  if SaveHiddenCells then
    hc := NumHiddenColumns;

  z := ARow;
  s := ACol;

  Content := p;
  EndOfRow := StrScan(Content,#0);

  NumCells := 0;
  gr.Top := ARow;
  gr.Left := ACol;
  gr.Right := ACol;
  gr.Bottom := ARow;

  mr := ARow;
  mc := ACol;

  if Assigned(UndoRedo) then
    UndoRedo.StartSequence;

  Cols := 0;
  Rows := 0;

  repeat
    cr := StrScan(Content,#13);
    if cr = nil then
      cr := EndOfRow;

    Line := Copy(StrPas(Content),1,cr - Content);

    //if Length(Line) > 0 then
      inc(Rows);

    if FPasteAll then
      ImportNotification(isImportNewRow,z)
    else
      ImportNotification(isImportSelRow,z);

    if (Length(Line) > 0) and (Navigation.ClipboardPasteAction = paInsert) then
      InsertRows(z,1);

    if pos(#9,Line) > 0 then
      Cols := 1;
    while (VarPos(#9,Line,TabPos) > 0) do
    begin
      inc(Cols);
      ct := Copy(line,1,TabPos - 1);

      if (Pos(#10,ct) > 0) then
      begin
        if FExcelClipboardFormat or (1 > 0) then
        begin
          if Pos('"',ct)=1 then Delete(ct,1,1);
          if Pos('"',ct) = Length(ct) then
            Delete(ct,Length(ct),1);

          CSVToLineFeeds(ct);
        end;
      end;

      if (s <= ColCount + hc) and (z <= RowCount) then
        if (IsEditable(RemapCol(s),z) or (Navigation.AllowClipboardAlways)) then
        begin
          Allow := True;

          if pos('|\',ct) = 1 then
          begin
            ws := DecodeWideStr(ct);

            if Assigned(FOnClipboardBeforePasteWideCell) then
              FOnClipboardBeforePasteWideCell(Self,s,z,ws,Allow);

            ct := EncodeWideStr(ws);
          end
          else
          begin
            if Assigned(FOnClipboardBeforePasteCell) then
              FOnClipboardBeforePasteCell(Self,s,z,ct,Allow);
          end;

          if Allow then
          begin
            didpaste := true;

            PasteInCell(s,z,ct);

            if s > mc then
              mc := s;
            if z > mr then
              mr := z;

            if pos('|\',ct) = 1 then
            begin
              if Assigned(FOnClipboardAfterPasteWideCell) then
                FOnClipboardAfterPasteWideCell(Self,s,z,ws)
            end
            else
              if Assigned(FOnClipboardAfterPasteCell) then
                FOnClipboardAfterPasteCell(Self,s,z,ct);
          end;
        end;

      Inc(NumCells);
      Delete(line,1,tabpos);
      inc(s);
      if (s > ColCount + hc) and Navigation.AllowClipboardColGrow then
        ColCount := s - hc;
      if s > gr.Right then
        gr.Right := s;
    end;

    nc := false;

    if (s <= ColCount + hc) and (z <= RowCount) then
    begin
      if (IsEditable(RemapCol(s),z) or Navigation.AllowClipboardAlways) then
      begin
        if (cr <> EndOfRow) or (Line <> '') then
        begin
          Allow := True;
          nc := true;

          if (Pos(#10,Line) > 0) then
          begin
            if Pos('"',Line)=1 then Delete(Line,1,1);
            if Pos('"',Line) = Length(Line) then
              Delete(Line,Length(Line),1);
            CSVToLineFeeds(Line);
          end;

          if pos('|\',ct) = 1 then
          begin
            ws := DecodeWideStr(Line);

            if Assigned(FOnClipboardBeforePasteWideCell) then
              FOnClipboardBeforePasteWideCell(Self,s,z,ws,Allow);

            Line := EncodeWideStr(ws);
          end
          else
          begin
            if Assigned(FOnClipboardBeforePasteCell) then
              FOnClipboardBeforePasteCell(Self,s,z,Line,Allow);
          end;

          if Allow then
          begin
            if (s <= ColCount) and (z <= RowCount) then
            begin
              didpaste := true;
              PasteInCell(s,z,Line);
            end;

            if s > mc then
              mc := s;
            if z > mr then
              mr := z;

            if (s <= ColCount) and (z <= RowCount) then
              if Assigned(FOnClipboardAfterPasteCell) then
                FOnClipboardAfterPasteCell(Self,s,z,Line);

          end;
        end;
      end;
    end;

    Inc(NumCells);
    if nc then
      Inc(s);

    if (s > ColCount + hc) and Navigation.AllowClipboardColGrow then
      ColCount := s - hc;

    if s > gr.Right then
      gr.Right := s;

    Content := cr + 1;

    if Content^ = #10 then
    begin
      Content := cr + 2;
    end;

    s := ACol;

    if (Content^ <> #0) then
      Inc(z);

    if FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) then
      ll := RowCount - 1
    else
      ll := RowCount;

    if (z = ll) and
       (cr <> EndOfRow) and (Content^ <> #0) and
       Navigation.AllowClipboardRowGRow then
       begin
         RowCount := RowCount + 1;
       end;

    if z > gr.Bottom then
      gr.Bottom := z;

  until cr = EndOfRow;

  dec(Rows);

  if Assigned(UndoRedo) then
    UndoRedo.StopSequence;

  gr.Bottom := mr;
  gr.Right := mc;

  PasteNotify(FClipTopLeft,gr,FClipLastOp);

  gr.Left := RemapCol(gr.Left);
  gr.Right := RemapCol(gr.Right);

  if didpaste then
    CellsChanged(TRect(gr));

  Result := NumCells;
end;

procedure TAdvStringGrid.PasteNotify(orig:TPoint;gr:TGridRect;lastop:TClipOperation);
var
  i: integer;
begin
  if ShowModified.Enabled then
  begin
    for i := gr.Top to gr.Bottom do
      RowModified[i] := true;
  end;
end;

procedure TAdvStringGrid.PasteStart;
begin

end;

procedure TAdvStringGrid.PasteDone;
begin

end;

function TAdvStringGrid.DoAllowFmtPaste: boolean;
begin
  Result := FNavigation.AllowFmtClipboard;
end;

function TAdvStringGrid.PasteFunc(ACol,ARow: Integer;var Cols,Rows: integer): Integer;
var
  {$IFDEF DELPHI_UNICODE}
  ContentStr: string;
  {$ENDIF}
  Content: PChar;
  DataPtr: Pointer;
  s: string;
  Data: THandle;
  cf_rtf,cf_gridcells: Integer;
  MemStream: TMemoryStream;
  Clipboard: TClipboard;
  gr:TGridRect;
  gpio: TGridPropIO;

begin
  Result := 0;
  Clipboard := TClipboard.Create;

  if DoAllowFmtPaste then
  begin
    OpenClipboard(Handle);
    cf_gridcells := RegisterClipboardformat('TAdvStringGrid Cells');
    CloseClipboard;

    if Clipboard.HasFormat(cf_gridcells) then
    begin
      // this is the preferred format ??
      Clipboard.Open;
      PasteStart;
      Data := 0;

      try
        Data := GetClipboardData(CF_GRIDCELLS);
        if Data = 0 then
          Exit;

        DataPtr := GlobalLock(Data);
        if DataPtr = nil then
        begin
          Clipboard.Close;
          Clipboard.Free;
          Exit;
        end;

        MemStream := TMemoryStream.Create;
        try
          MemStream.WriteBuffer(DataPtr^, GlobalSize(Data));
          MemStream.Position := 0;

          if Navigation.AllowClipboardRowGrow or
             Navigation.AllowClipboardColGrow or
             (Navigation.ClipboardPasteAction = paInsert) then
          begin
            gpio := TGridPropIO.Create(self);
            MemStream.ReadComponent(gpio);

            if (ACol + gpio.ColCount >= ColCount) and Navigation.AllowClipboardColGrow then
              ColCount := ACol + gpio.ColCount;

            if (ARow + gpio.RowCount >= RowCount) and Navigation.AllowClipboardRowGrow then
              RowCount := ARow + gpio.RowCount;

            Cols := ColCount;
            Rows := RowCount;

            if Navigation.ClipboardPasteAction = paInsert then
            begin
              InsertRows(ARow, gpio.RowCount);
            end;

            gpio.Free;

            MemStream.Position := 0;
          end;

          LoadAtPointFromBinStream(Point(ACol,ARow),MemStream);

          MemStream.Position := 0;

          gpio := TGridPropIO.Create(self);
          MemStream.ReadComponent(gpio);
          gr.Left := ACol;
          gr.Top := ARow;
          gr.Right := gr.Left + gpio.ColCount - 1;
          gr.Bottom := gr.Top + gpio.RowCount - 1;

          if gpio.ID = Integer(Handle) then
            PasteNotify(FClipTopLeft,gr,FClipLastOp)
          else
            PasteNotify(Point(-1,-1),gr,FClipLastOp);

          Result := gpio.ColCount * gpio.RowCount;

          gpio.Free;

        finally
          MemStream.Free;
        end;

      finally
        GlobalUnlock(Data);
      end;

      Clipboard.Close;
      Clipboard.Free;
      PasteDone;
      Exit;
    end;
  end;

  if FNavigation.AllowRTFClipboard then
  begin
    OpenClipboard(Handle);
    cf_rtf := RegisterClipboardformat('Rich Text Format');
    CloseClipboard;
    if Clipboard.HasFormat(cf_rtf) then
    begin
      Clipboard.Open;
      Data := GetClipboardData(CF_RTF);
      try
        if Data <> 0 then
          Content := PChar(GlobalLock(Data))
        else
          Content := nil
      finally
        if Data <> 0 then
          GlobalUnlock(Data);
        ClipBoard.Close;
      end;
      if Content = nil then Exit;

      s := '';
      while Content^ <> #0 do
      begin
        s := s + Content^;
        Content := Content + 1;
      end;
      if IsEditable(RemapCol(ACol),ARow) then
        PasteInCell(ACol, ARow, s);

      Cols := 1;
      Rows := 1;
      Clipboard.Free;
      Exit;
     end;
  end;

  if not Clipboard.HasFormat(CF_TEXT) then
  begin
    Clipboard.Free;
    Exit;
  end;

  Clipboard.Open;
  Data := GetClipboardData(CF_TEXT);
  try
    {$IFDEF DELPHI_UNICODE}
    ContentStr := Clipboard.AsText;
    if ContentStr <> '' then
      Result := PasteText(ACol,ARow,PChar(ContentStr),Cols,Rows);
    {$ENDIF}

    {$IFNDEF DELPHI_UNICODE}
    if Data <> 0 then
      Content := PChar(GlobalLock(Data))
    else
      Content := nil;
    if Content <> nil then
      Result := PasteText(ACol,ARow,Content,Cols,Rows);
    {$ENDIF}

  finally
    if Data <> 0 then
      GlobalUnlock(Data);

    ClipBoard.Close;
    Clipboard.Free;
  end;
end;

function TAdvStringGrid.GetXLSSheets(FileName: string): TStringList;
var
  FExcel: variant;
  FWorkBook: variant;
  FWorkSheets: variant;
  FWorkSheet: variant;
  i: Integer;
  OldCursor : TCursor;

begin
  OldCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  
  try
    FExcel := CreateOleObject('excel.application');
  except
    Screen.Cursor := OldCursor;
    raise EAdvGridError.Create('Excel OLE server not found');
    Exit;
  end;

  try
    FWorkBook := FExcel.WorkBooks.Open(FileName);
    FWorkSheets := FWorkBook.WorkSheets;

    Result := TStringList.Create;

    for i :=1 to FWorkSheets.Count do
    begin
      FWorkSheet := fworksheets.item[i];
      Result.Add(FWorkSheet.Name);
    end;

    FWorkbook.Saved := true;

  finally
    FExcel.Quit;
    FExcel := UnAssigned;
    Screen.Cursor := OldCursor;
  end;
end;


procedure TAdvStringGrid.LoadFromXLS(filename:string);
begin
  LoadXLS(filename,'');
end;

procedure TAdvStringGrid.LoadFromXLSSheet(filename,sheetname:string);
begin
  LoadXLS(filename,sheetname);
end;

procedure TAdvStringGrid.LoadXLS(Filename,sheetname:string);
var
  FExcel: Variant;
  FWorkbook: Variant;
  FWorksheet: Variant;
  FCell: Variant;
  FArray: Variant;
  s,z: Integer;
  rangestr:string;
  startstr,endstr:string;
  code: Integer;
  sr,er,sc,ec: Integer;
  strtCol,strtRow: Integer;
  ulc: Boolean;
  FOldFixedCols,FOldFixedRows: Integer;
  OldCursor: TCursor;
  singlecell:boolean;
begin
  OldCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;

  try
    FExcel := CreateOleObject('excel.application');
  except
    Screen.Cursor := OldCursor;
    raise EAdvGridError.Create('Excel OLE server not found');
    Exit;
  end;

  try
    //FExcel.visible:=True;
    FWorkBook := FExcel.WorkBooks.Open(FileName);

    if SheetName = '' then
      FWorkSheet := FWorkBook.ActiveSheet
    else
    begin
      FWorkSheet:=unAssigned;

      for s := 1 to FWorkbook.Sheets.Count do
        if FWorkBook.Sheets[s].Name = SheetName then
          FWorkSheet := FWorkBook.Sheets[s];

      if VarIsEmpty(FWorksheet) then
      begin
        Screen.Cursor := OldCursor;
        raise EAdvGridError.Create('Excel worksheet '+sheetname+' not found');
        Exit;
      end;
    end;

    FWorkSheet.UsedRange;

    rangestr := FWorkSheet.UsedRange.Address;

    {$IFDEF TMSDEBUG}
    DbgStr('Excel used range',rangestr);
    {$ENDIF}

    //decode here how many cells are required, $A$1:$D$8 for example

    startstr := '';
    endstr := '';

    sc := -1;
    ec := -1;
    singlecell := Pos(':',rangestr) = 0;

    if not singlecell then
    begin
      startstr := Copy(rangestr,1,pos(':',rangestr)-1);
      endstr := Copy(rangestr,pos(':',rangestr)+1,255);


      ulc := not (Pos('$',startstr) > 0);

      if pos('$',startstr) = 1 then
        Delete(startstr,1,1);

      if pos('$',endstr) = 1 then
        Delete(endstr,1,1);


      if pos('$',startstr) > 0 then
        Val(copy(startstr,pos('$',startstr)+1,255),sr,code)
      else
        Val(startstr,sr,code);

      if code <> 0 then
        sr := -1;

      if pos('$',endstr) > 0 then
        Val(copy(endstr,pos('$',endstr)+1,255),er,code)
      else
        Val(endstr,er,code);

      if code <> 0 then
        er := -1;

      // now decode the Columns
      if ulc then
      begin
        sc := 1;
        ec := 256;
      end
      else
      begin
        if pos('$',startstr) > 0 then
          startstr := Copy(startstr,1,pos('$',startstr)-1);

        if pos('$',endstr) > 0 then
          endstr := Copy(endstr,1,pos('$',endstr) - 1);

        if startstr <> '' then
          sc := ord(startstr[1]) - 64;

        if Length(startstr)>1 then
          sc := sc * 26 + ord(startstr[2]) - 64;

        if endstr<>'' then
          ec := ord(endstr[1]) - 64;
        if Length(endstr)>1 then
          ec := ec * 26 + ord(endstr[2]) - 64;
      end;
    end
    else
    begin
      if Pos('$',rangestr) > 0 then
      begin
        Delete(rangestr,1,1);

        if pos('$',rangestr) > 0 then
          Val(copy(rangestr,pos('$',rangestr)+1,255),sr,code)
        else
          Val(rangestr,sr,code);

        rangestr := Copy(rangestr,1,pos('$',rangestr)-1);
        if rangestr <> '' then
          sc := ord(rangestr[1]) - 64;
        if Length(rangestr)>1 then
          sc := sc * 26 + ord(rangestr[2]) - 64;

        ec := sc;
        er := sr;
      end
      else
      begin
        sc := 1;
        sr := 1;
        ec := 1;
        er := 1;
      end;
    end;

    {$IFDEF TMSDEBUG}
    DbgMsg('Rows from '+inttostr(sr)+' to '+inttostr(er));
    DbgMsg('Cols from '+inttostr(sc)+' to '+inttostr(ec));
    {$ENDIF}

    FOldFixedCols := FixedCols;
    FOldFixedRows := FixedRows;

    if (ec < 0) or (er < 0) or (sc < 0) or (sr < 0) then
    begin
      sc := 1;
      sr := 1;
      er := FWorkSheet.UsedRange.Rows.Count;
      ec := FWorkSheet.UsedRange.Columns.Count;
    end;

    if (sr <> -1) and (er <> -1) and (sc <> -1) and (ec <> -1) then
    begin
      ColCount := ec - sc + 1;
      RowCount := er - sr + 1;
    end;

    //farray := VarArrayCreate([1,1 + ec - sc,1,1 + er - sr],varVariant);
    //rangestr:='A1:';

    rangestr := Chr(ord('A') - 1 + sc) + IntToStr(sr)+':';

    if (ColCount > 26) then
    begin
      rangestr := rangestr + chr(ord('A') - 1 + ((ec - sc) div 26));
      rangestr := rangestr + chr(ord('A') + ((ec - sc) mod 26));
    end
    else
      rangestr := rangestr + Chr(ord('A') - 1 + ec);

    rangestr := rangestr + IntToStr(er);

    if FSaveFixedCells or FSaveFixedCols then
      strtCol := 0
    else
    begin
      StrtCol := FOldFixedCols;
      ColCount := ColCount + FOldFixedCols;
    end;

    if FSaveFixedCells or FSaveFixedRows then
      strtRow := 0
    else
    begin
      StrtRow := FOldFixedRows;
      RowCount := RowCount + FOldFixedRows;
    end;

    if ColCount > FOldFixedCols then
      FixedCols := FOldFixedCols;
    if RowCount  >FOldFixedRows then
      FixedRows := FOldFixedRows;

    if not singlecell then
    begin
      FArray := FWorkSheet.Range[RangeStr].Value;

      for s := 1 to RowCount - StrtRow do
      begin
        for z := 1 to ColCount - StrtCol do
        begin
          try
            FCell := FArray[s,z];

            if VarIsClear(FCell) then
              FCell := EmptyStr;

            if not (VarType(FCell) in [varEmpty,varDispatch,varError]) then
              LoadCell(z - 1 + StrtCol,s - 1 + StrtRow,FCell);
          except
            raise Exception.Create('Incorrect XLS file');
          end;
        end;
      end;
    end
    else
    begin
      try
        rangestr := FWorkSheet.Rows.Cells[sr,sc];
        LoadCell(StrtCol,StrtRow,rangestr);
      except
        raise Exception.Create('Incorrect XLS file');
      end;
    end;

    FWorkBook.Close(SaveChanges:=False);

  finally
    FExcel.Quit;
    FExcel := UnAssigned;
    Screen.Cursor := OldCursor;
    CellsChanged(Rect(0,0,ColCount,RowCount));
    CellsLoaded;
  end;
end;

procedure TAdvStringGrid.LoadFromMDBTable(Filename, Table: string);
begin
  LoadFromMDBSQL(Filename,'SELECT * FROM ' + Table);
end;

procedure TAdvStringGrid.LoadFromMDBSQL(Filename, SQL: string);
var
  ObjConnC, ObjRSC: variant;
  DSN: string;
  i,j,k: Integer;
begin
  ObjConnC := CreateOleObject('ADODB.Connection');
  DSN := 'Driver={Microsoft Access Driver (*.mdb)};DBQ='+Filename;

  ObjConnC.Open(DSN);
  ObjRSC := CreateOleObject('ADODB.RecordSet');
  ObjRSC.ActiveConnection := ObjConnC;
  ObjRSC.Open(SQL);

  i := ObjRSC.Fields.Count;

  ColCount := FixedCols + i;

  if FixedRows > 0 then
    for j := 1 to i do
    begin
      Cells[FixedCols + j - 1, FixedRows - 1] := ObjRSC.Fields[j - 1].Name;
    end;

  if ObjRSC.RecordCount > 0 then
  begin
    RowCount := FixedRows + ObjRSC.RecordCount;
  end;

  k := FixedRows;

  while (ObjRSC.Eof = False) do
  begin
    for j := 1 to i do
    begin
      if ObjRSC.Fields[j - 1].ActualSize > 0 then
        LoadCell(FixedCols + j - 1, k,ObjRSC.Fields[j - 1].Value)
      else
        LoadCell(FixedCols + j - 1, k,'');
    end;
    ObjRSC.MoveNext;
    inc(k);
    if k > RowCount then
      RowCount := RowCount + 1;
  end;
  ObjRSC.Close;
  ObjConnC.Close;
end;


procedure TAdvStringGrid.AppendToDOC(filename, bookmark:string);
begin
  SaveToDOCInt(filename, bookmark, false, true);
end;

procedure TAdvStringGrid.SaveToDOC(filename:string; CreateNewDocument: boolean = true);
begin
  SaveToDOCInt(filename,'', CreateNewDocument, false);
end;

procedure TAdvStringGrid.ChangeScale(M, D: Integer);
{$IFDEF DELPHIXE9_LVL}
var
  cw: TIntList;
  i: integer;
{$ENDIF}
begin
{$IFDEF DELPHIXE9_LVL}
  // workaround for bug introduced in Delphi 10 with persisting column widths
  cw := TIntList.Create(-1,-1);

  for i := 0 to ColCount - 1 do
    cw.Add(ColWidths[i]);
{$ENDIF}

  inherited;

{$IFDEF DELPHIXE9_LVL}
  for i := 0 to ColCount - 1 do
    ColWidths[i] := cw.Items[i];

  cw.Free;

  RowHeights[0] := FixedRowHeight;

{$ENDIF}

  if not (csDesigning in ComponentState) then
  begin
    if M <> D then
    begin
      FixedFont.Size      := MulDiv(FixedFont.Size, M, D);
      ActiveCellFont.Size := MulDiv(ActiveCellFont.Size, M, D);
    end;
  end;
end;

procedure TAdvStringGrid.SaveToDOCInt(filename, bookmark:string; CreateNewDocument, Append: boolean);
var
  fword: Variant;
  fdoc: Variant;
  ftable: Variant;
  frng: Variant;
  fcell: Variant;
  s,z: Integer;
  OldCursor: TCursor;
  FActive: Boolean;
begin
  OldCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  FActive := false;

  // try to find running Word OLE server
  try
    FWord := GetActiveOleObject('word.application');
    FActive := true;
  except
    try
      FWord := CreateOLEObject('word.application');
    except
      Screen.Cursor := OldCursor;
      raise EAdvGridError.Create('Word OLE server not found');
      Exit;
    end;
  end;

  try
    if Append then
      FDoc  := FWord.Documents.Open(filename)
    else
    begin

      if CreateNewDocument or (FWord.Documents.Count = 0) then
        FDoc := FWord.Documents.Add
      else
        FDoc := FWord.ActiveDocument;
    end;

    FDoc.ShowSpellingErrors := False;

    FRng := FWord.Selection;
    FRng.TypeText(Caption);
    FRng.TypeParaGraph;

    if Append then
    begin
      if (bookmark = '') then
      begin
        FDoc.Paragraphs.Add;
        FWord.Selection.Goto(what := wdGotoLine, which := wdGotoLast);
        FRng := FDoc.Range(start:=FWord.Selection.End,end:=FWord.Selection.End);
      end
      else
      begin
        if FDoc.Bookmarks.Exists(bookmark) then
          FRng := FDoc.Goto(what:=wdGotoBookmark,name:=bookmark)
        else
        begin
          FDoc.Paragraphs.Add;        
          FWord.Selection.Goto(what := wdGotoLine, which := wdGotoLast);
          FRng := FDoc.Range(start:=FWord.Selection.End,end:=FWord.Selection.End);
        end;
      end;
    end
    else
      FRng := FDoc.Range(start:=0,end:=0);

    FTable := FDoc.Tables.Add(frng,numRows:=RowCount,numColumns:=ColCount);

    ExportNotification(esExportStart, 0);

    for s := 1 to RowCount do
    begin
      ExportNotification(esExportNextRow, s);
      for z := 1 to ColCount do
      begin
        FCell := FTable.Cell(Row:=s,Column:=z);
        FCell.Range.InsertAfter(SaveCell(RemapCol(z-1),s-1));
        case GetCellAlignment(z-1,s-1).Alignment of
        taRightJustify:FCell.Range.ParagraphFormat.Alignment := wdAlignParagraphRight;
        taCenter:FCell.Range.ParagraphFormat.Alignment := wdAlignParagraphCenter;
        end;
        {
        .Bold = True
        .ParagraphFormat.Alignment = wdAlignParagraphCenter
        .Font.Name = "Arial"
        }
      end;
    end;

    ExportNotification(esExportDone, -1);

    FDoc.SaveAs(FileName);
  finally
    if not FActive then
      FWord.Quit;

    FWord := Unassigned;
    Screen.Cursor := OldCursor;
  end;
end;

{ TAdvGridPopup }

procedure TAdvGridPopup.Hide;
begin
  FVisible := false;
end;

procedure TAdvGridPopup.Show(PT: TPoint);
begin
  FVisible := true;
end;

{ TCellGraphic }

procedure TCellGraphic.Assign(Source: TPersistent);
begin
  if (Source is TBaseCellGraphic) then
  begin
    inherited Assign(Source);
  end;

  if (Source is TCellGraphic) then
  begin
    FCommentColor := (Source as TCellGraphic).CommentColor;
    FCellComment := (Source as TCellGraphic).CellComment;
  end;
end;

procedure TAdvStringGrid.SaveToXLS(FileName: string; CreateNewSheet: boolean = true);
begin
  SaveXLS(FileName,'',CreateNewSheet);
end;

procedure TAdvStringGrid.SaveToXLSSheet(FileName,SheetName: string);
begin
  SaveXLS(FileName,SheetName,true);
end;

procedure TAdvStringGrid.SaveXLS(FileName,SheetName: string; CreateNewSheet: boolean);
var
  FExcel: Variant;
  FWorkbook: Variant;
  FWorksheet: Variant;
  FArray: Variant;
  s,z: Integer;
  RangeStr: string;
  StrtCol,StrtRow: Integer;
  newbook: Boolean;
  OldCursor: TCursor;
  nRow: Integer;
  FActive: boolean;
begin
  OldCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  FActive := false;

  try
    FExcel := GetActiveOleObject('excel.application');
    FActive := true;
  except
    try
      FExcel := CreateOleObject('excel.application');
    except
      Screen.cursor := OldCursor;
      raise EAdvGridError.Create('Excel OLE server not found');
      Exit;
    end;
  end;

  newbook := True;
  nRow := 1;

  if SheetName = '' then
  begin
    if (FExcel.WorkBooks.Count = 0) or CreateNewSheet then
    begin
      FWorkBook := FExcel.WorkBooks.Add;
      //FWorkSheet := FWorkBook.WorkSheets.Add;
      FWorkSheet := FWorkBook.Sheets[1];
    end
    else
    begin
      // only when using active sheet, start save on active row
      FWorkBook := FExcel.ActiveWorkBook;
      FWorkSheet := FWorkbook.ActiveSheet;
      nRow := FExcel.ActiveCell.Row;
    end;
  end
  else
  begin
    newbook := False;
    try
      if FileExists(FileName) then
        FWorkBook := FExcel.WorkBooks.Open(Filename)
      else
      begin
        FWorkBook := FExcel.WorkBooks.Add;
        newbook := true;
      end;
    except
      try
        if VarIsEmpty(FWorkBook) then
          FWorkBook := FExcel.WorkBooks.Add;
        newbook := true;
      except
        Screen.Cursor := OldCursor;
        Exit;
      end;
    end;

    FWorkSheet := unAssigned;
    for s := 1 to FWorkbook.Sheets.Count do
      if (FWorkBook.Sheets[s].Name = sheetname) then
        FWorkSheet := FWorkBook.Sheets[s];

    if VarIsEmpty(FWorksheet) then
     begin

       FWorkSheet := FWorkBook.WorkSheets.Add;
       FWorkSheet.Name := sheetname;
     end;
  end;

  StrtCol := SaveStartCol;
  StrtRow := SaveStartRow;

  FArray := VarArrayCreate([0,RowCount - 1 - StrtRow,0, ColCount - 1 - StrtCol],VarVariant);

  ExportNotification(esExportStart, StrtRow);

  for s := StrtRow to RowCount - 1 do
  begin

    ExportNotification(esExportNextRow,s);

    for z := StrtCol to ColCount - 1 do
    begin
      FArray[s - StrtRow,z - StrtCol] := LineFeedsToXLS(SaveCell(RemapCol(z),s));
    end;
  end;

  ExportNotification(esExportDone,-1);

  RangeStr := 'A' + IntToStr(nRow) + ':';

  if (ColCount - StrtCol) > 26 then
  begin
    if (ColCount - StrtCol) mod 26 = 0 then
    begin
      RangeStr := RangeStr + Chr(Ord('A') - 2 + ((ColCount - StrtCol) div 26));
      RangeStr := RangeStr + 'Z';
    end
    else
    begin
      RangeStr := RangeStr + Chr(Ord('A') - 1 + ((ColCount - StrtCol) div 26));
      RangeStr := RangeStr + Chr(Ord('A') - 1 + ((ColCount - StrtCol) mod 26));
    end;
  end
  else
    RangeStr := RangeStr + Chr(Ord('A') - 1 + (ColCount - StrtCol));

  RangeStr := RangeStr + IntToStr(RowCount - StrtRow);

  FWorkSheet.Range[rangestr].Value := FArray;

  //FWorkSheet.Columns['A:' + LastCol].EntireColumn.AutoFit;

  try
    if newbook then
      FWorkbook.SaveAs(filename)
    else
      FWorkbook.Save;
  except
  end;    

  if not FActive then
    FExcel.Quit;

  FExcel := unAssigned;

  Screen.Cursor := OldCursor;
end;

procedure TAdvStringGrid.OutputToCSV(FileName:String;appendmode: Boolean; Unicode: boolean);
var
  z,s,n,rs: Integer;
  oprogr,nprogr: Integer;
  CellText: String;
  Delim: Char;
  dblquotes: Boolean;
  sl: TFileStringList;

begin
  oprogr := -1;

  if FSaveHiddenCells then
    n := FNumHidden
  else
    n := 0;

  if FDelimiter = #0 then
    Delim := ','
  else
    Delim := FDelimiter;

  sl := TFileStringList.Create;
  if AppendMode then
    sl.LoadFromFile(FileName);

  ExportNotification(esExportStart, SaveStartRow);

  for z := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNextRow, z);

    for s := SaveStartCol to SaveEndCol + n do
    begin
      if s > SaveStartCol then
        sl.write(Delim);

      if FSaveHiddenCells then
        rs := s
      else
        rs := RemapCol(s);

      CellText := SaveCell(rs,z);
      CellText := CSVQuotes(CellText);

      if FOemConvert then
        StringToOem(CellText);

      dblquotes := false;

      if ((FAlwaysQuotes) or ((Pos(Delim,CellText) = 0) and (Pos('"',CellText) > 0))) then
      begin
        CellText := '"' + CellText + '"';
        dblquotes := true;
      end;

      if CellText = '' then
      begin
        if JavaCSV then
          CellText := '^'
        else
          if QuoteEmptyCells then
            CellText := '""';
      end;

      if (Pos(Delim,CellText) > 0) or (LinesInText(CellText,true) > 1) then
      begin
        if JavaCSV then
          LinefeedstoJava(CellText)
        else
        begin
          if MultiLineCells then
          begin
            CellText := '"' + CellText + '"'
          end
          else
            if not dblquotes then
              LinefeedsToCSV(CellText)
            else
              LinefeedsToCSVNQ(CellText);
        end;
      end;
      sl.Write(CellText);
    end;
    sl.Writeln('');

    if Assigned(FOnFileProgress) then
    begin
      nprogr := Round(z/(RowCount-1)*100);
      if nprogr <> oprogr then
        FOnFileProgress(self,nprogr);
      oprogr := nprogr;
    end;
  end;

  ExportNotification(esExportDone, -1);

  {$IFDEF DELPHI_UNICODE}
  if Unicode then
    sl.SaveToFile(FileName, FEncoding)
  else
    sl.SaveToFile(FileName);
  {$ENDIF}

  {$IFNDEF DELPHI_UNICODE}
  sl.SaveToFile(FileName);
  {$ENDIF}

  sl.Free;
end;

{$IFDEF DELPHI_UNICODE}
procedure TAdvStringGrid.SaveToCSV(FileName:String; Unicode: boolean = true);
begin
  OutputToCSV(FileName,False,Unicode);
end;

procedure TAdvStringGrid.AppendToCSV(FileName:String; Unicode: boolean = true);
begin
  OutputToCSV(FileName,True,Unicode);
end;

{$ENDIF}

{$IFNDEF DELPHI_UNICODE}
procedure TAdvStringGrid.SaveToCSV(FileName:String);
begin
  OutputToCSV(FileName,False,False);
end;

procedure TAdvStringGrid.AppendToCSV(FileName:String);
begin
  OutputToCSV(FileName,True,False);
end;
{$ENDIF}

procedure TAdvStringGrid.InputFromCSV(Filename:string;insertmode: Boolean;MaxRows: integer);
var
  fs: TFileStream;
begin
  // avoid error when Excel already has the CSV file open
  fs := TFileStream.Create(FileName, fmShareDenyNone, 0);
  try
    if fs.Size > 0 then
      InputFromCSVStream(fs, insertmode, MaxRows);
  finally
    fs.Free;
  end;
end;

procedure TAdvStringGrid.InputFromCSVStream(AStream: TStream; insertmode: Boolean;MaxRows: integer);
var
  buffer,celltext: string;
  s,z: Integer;
  strtCol,strtRow: Integer;
  c1,c2,cm: Integer;
  OldDelimiter: Char;
  linecount,linepos: Integer;
  delimiterpos,quotepos: Integer;
  oprogr,nprogr: Smallint;
  lr: TStringList;
  NewRows: integer;
  sl: TFileStringList;
  sh: integer;
  hasquote: boolean;

begin
  StrtCol := SaveStartCol;
  StrtRow := SaveStartRow;

  sl := TFileStringList.Create;
  sl.LoadFromStream(AStream);

  if sl.Eof then
  begin
    raise Exception.Create('File is empty');
    sl.Free;
    Exit;
  end;

  // handle multiline cells
  s := 0;
  while s < sl.Count - 2 do
  begin
    z := NumCharDel('"',Delimiter,sl.Strings[s]);
    while odd(z) and (s < sl.Count - 2) do
    begin
      z := z + NumCharDel('"',Delimiter,sl.Strings[s + 1]);
      sl.Strings[s] := sl.Strings[s] + #13#10 + sl.Strings[s + 1];
      sl.Delete(s + 1);
    end;
    inc(s);
  end;

  z := StrtRow;

  lr := TStringList.Create;

  if InsertMode then
  begin
    z := RowCount;
    if FloatingFooter.Visible then
    begin
      lr.Assign(Rows[RowCount - 1]);
      NilRow(RowCount - 1);
      dec(z);
    end;
  end;

  OldDelimiter := FDelimiter;

  // do intelligent estimate of the separator
  if (FDelimiter = #0) then
  begin
    CellText := '';

    sl.ReadLn(buffer);

    if not sl.Eof then sl.ReadLn(CellText);
    sl.Reset;

    cm := 0;
    for s := 1 to 10 do
    begin
      c1 := NumSingleChar(CSVSeparators[s],Buffer);
      c2 := NumSingleChar(CSVSeparators[s],Celltext);
      if (c1 = c2) and (c1 > cm) then
      begin
        FDelimiter := CSVSeparators[s];
        cm := c1;
      end;
    end;

    if cm = 0 then
      for s := 1 to 10 do
      begin
        c1 := NumChar(CSVSeparators[s],Buffer);
        c2 := NumChar(CSVSeparators[s],Celltext);
        if (c1 = c2) and (c1 > cm) then
        begin
          FDelimiter := CSVSeparators[s];
          cm := c1;
        end;
      end;

    // if no matching delimiter count found on line1 & line2, take maximum
    if cm = 0 then
      for s := 1 to 10 do
      begin
        c1 := NumChar(CSVSeparators[s],Buffer);
        c2 := NumChar(CSVSeparators[s],Celltext);
        if (c1 > cm) or (c2 > cm) then
        begin
          FDelimiter := CSVSeparators[s];
          cm := Max(c1,c2);
        end;
      end;
  end;

  LineCount := 0;

  if Assigned(FOnFileProgress) then
  begin
    sl.Reset;
    if not FLoadFirstRow then
      sl.ReadLn(buffer);

    while not sl.Eof do
    begin
      sl.ReadLn(buffer);
      Inc(LineCount);
    end;

    if InsertMode then
      RowCount := RowCount + sl.Count
    else
      Rowcount := StrtRow + sl.Count + FixedFooters;
  end;

  sl.Reset;

  oprogr := -1;
  LinePos := 0;

  if not FLoadFirstRow then
    sl.ReadLn(buffer);

  NewRows := 0;

  if SaveHiddenCells then
    sh := NumHiddenColumns
  else
    sh := 0;  

  while (not sl.Eof) and ((MaxRows <= 0) or (NewRows < MaxRows)) do
  begin
    sl.ReadLn(buffer);

    inc(NewRows);

    if FOemConvert then
      OemToString(Buffer);

    s := StrtCol;

    if z >= RowCount - FixedFooters then
    begin
      RowCount := z + 1000;
    end;

    while VarCharPos(FDelimiter,Buffer,DelimiterPos) > 0 do
    begin

      while (Length(Buffer) > 1) and (Buffer[1] = ' ') do
      begin
        delete(Buffer,1,1);
        dec(DelimiterPos);
      end;

      hasquote := Buffer[1] = '"';
      if hasquote then
      begin
        Delete(buffer,1,1);   //delete first quote from buffer

        if SinglePos('"',Buffer,QuotePos) > 0 then  //search for next single quote
        begin
          CellText := Copy(buffer,1,QuotePos - 1);
          CellText := DoubleToSingleChar('"',CellText);
          Delete(buffer,1,QuotePos);
        end
        else
          CellText := '';
        VarCharPos(FDelimiter,buffer,DelimiterPos);
      end
      else
      begin
        CellText := Copy(buffer,1,DelimiterPos - 1);
      end;

      if JavaCSV then
        JavaToLineFeeds(CellText)
      else
        CSVToLineFeeds(CellText);

      LoadCell(s,z,CellText);

      Delete(buffer,1,DelimiterPos);

      Inc(s);
      if (s >= ColCount + sh) then
      begin
        ColCount := s - sh;
      end;
    end;

    // remaining part
    if Length(Buffer) > 0 then
    begin
      while (Length(Buffer) > 1) and (Buffer[1] = ' ') do
      begin
        delete(Buffer,1,1);
      end;

      hasquote := Buffer[1] = '"';
      if hasquote then
        Delete(buffer,1,1);

      if Length(Buffer) > 0 then
      begin
        if hasquote and (Buffer[Length(Buffer)] = '"') then
          Delete(Buffer,Length(Buffer),1);
      end;
      if hasquote then
        CellText := DoubleToSingleChar('"',Buffer)
      else
        CellText := Buffer;

      if JavaCSV then
        JavaToLineFeeds(CellText)
      else
        CSVToLineFeeds(CellText);

      LoadCell(s,z,CellText);
      Inc(s);

      if (s > ColCount + sh) then
      begin
        ColCount := s - sh;
      end;
    end;

    Inc(z);

    if Assigned(FOnFileProgress) then
    begin
      Inc(LinePos);
      if (LineCount > 0) then
      begin
        nprogr := Round(LinePos / LineCount * 100);
        if nprogr <> oprogr then
          FOnFileProgress(Self,nprogr);
      end
      else
        nprogr := 100;
      oprogr := nprogr;
    end;
  end;

  sl.Free;

  RowCount := z + FixedFooters;

  FMaxRowCount := RowCount;

  if FloatingFooter.Visible then
    Rows[RowCount - 1].Assign(lr);

  lr.Free;

  FDelimiter := OldDelimiter;
  CellsChanged(Rect(0,0,ColCount,RowCount));
  CellsLoaded;
end;

procedure TAdvStringGrid.LoadFromCSVStream(AStream:TStream; MaxRows: integer = -1);
begin
  InputFromCSVStream(AStream, false, MaxRows);
end;


{$IFDEF DELPHI_UNICODE}
procedure TAdvStringGrid.LoadFromCSV(FileName: String; AEncoding: TEncoding; MaxRows: integer = -1);
var
  sl: TStringList;
  ms: TMemoryStream;
begin
  sl := TStringList.Create;
  try
    sl.LoadFromFile(FileName, AEncoding);

    ms := TMemoryStream.Create;
    sl.SaveToStream(ms);
    ms.Position := 0;
    try
      LoadFromCSVStream(ms, MaxRows);
    finally
      ms.Free;
    end;
  finally
    sl.Free;
  end;
end;
{$ENDIF}


procedure TAdvStringGrid.LoadFromCSV(Filename:string; MaxRows: integer = -1);
begin
  InputFromCSV(Filename,False,MaxRows);
end;

procedure TAdvStringGrid.InsertFromCSV(Filename:string; MaxRows: integer = -1);
begin
  InputFromCSV(FileName,True,MaxRows);
end;

procedure TAdvStringGrid.SavetoStream(Stream: TStream);
var
  ss,CellText: string;
  i,j: Integer;

  procedure Writestring(s:string);
  var
    buf:PChar;
    c: array[0..1] of char;
    l,len: integer;

  begin
    l := length(s) * sizeof(char);
    len := l + sizeof(char);

    GetMem(buf,len);

    Move(s[1],buf^,l);
    //StrPLCopy(buf,s,l);

    Stream.Writebuffer(buf^,l);

    c[0] := #13;
    c[1] := #10;

    Stream.Writebuffer(c,2 * sizeof(char));
    FreeMem(buf);
  end;

begin
  ss := IntToStr(SaveColCount) + ',' + IntToStr(SaveRowCount);
  WriteString(ss);

  //save column Widths
  for i := 1 to ColCount do
    WriteString('cw '+IntToStr(i-1) + ',' + IntToStr(ColWidths[i - 1]));

  ExportNotification(esExportStart, SaveStartRow);

  //save cell contents
  for i := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNextRow, i);
    for j := SaveStartCol to SaveEndCol do
    begin
      CellText := SaveCell(j,i);

      if CellText <> '' then
      begin
        ss := IntToStr(j - SaveStartCol) + ',' + IntToStr(i - SaveStartRow) + ',' + LFToFile(CellText);
        Writestring(ss);
      end;
    end;
  end;

  ExportNotification(esExportDone, -1);
end;

procedure TAdvStringGrid.SaveToFixed(FileName:string;positions: TIntList);
var
  f: TextFile;
  c,r,m,n,nh,rc: Integer;
  s,su: string;

begin
  Assignfile(f,FileName);
  {$i-}
  ReWrite(f);
  {$i+}
  if IOResult <> 0 then
    raise EAdvGridError.Create('Cannot Create file '+FileName);

  if SaveHiddenCells then
    nh := FNumHidden
  else
    nh := 0;

  ColCount := ColCount + nh;

  for c := SaveStartCol to SaveEndCol do
    if Positions.Count - 1 < c - SaveStartCol then Positions.Add(MaxCharsInCol(c) + 1);

  ExportNotification(esExportStart, SaveStartRow);

  for r := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNextRow, r);
    s := '';
    for c := SaveStartCol to SaveEndCol do
    begin
      if SaveHiddenCells then
        rc := c
      else
        rc := RemapCol(c);

      su := SaveCell(rc,r);
      n := Length(su);

      if n > Positions.Items[c - SaveStartCol] then
        su := Copy(su,1,Positions.Items[c - SaveStartCol])
      else
        for m := 1 to Positions.Items[c - SaveStartCol] - n do
          su := su + ' ';

      s := s + su;
    end;
    WriteLn(f,s);
  end;
  ExportNotification(esExportDone, -1);
  CloseFile(f);

  ColCount := ColCount - nh;
end;

function compareInts(Item1 : Pointer; Item2 : Pointer) : Integer;
begin
  // We start by viewing the object pointers as TCustomer objects

  if Integer(item1) > Integer(Item2) then
    Result := 1
  else
    if Integer(item1) = Integer(Item2) then
      Result := 0
    else
      Result := -1;
end;


procedure TAdvStringGrid.LoadFromFixed(filename:string; positions:TIntList; DoTrim: boolean = true; MaxRows: integer = -1);
var
  f: TextFile;
  s,sub: string;
  c,r,i: Integer;
  rc: integer;
begin
  AssignFile(f, FileName);
  {$i-}
  Reset(f);
  {$i+}
  if IOResult <> 0 then
    raise EAdvGridError.Create('File ' + FileName + ' not found');

  ColCount := FixedCols + Positions.Count - 1;

  positions.Sort(@compareInts);

  r := SaveStartRow;

  rc := 1;

  while not Eof(f) do
  begin
    ReadLn(f,s);
    c := SaveStartCol;

    for i := 2 to Positions.Count do
    begin
      sub := Copy(s,Positions.Items[i-2],Positions.Items[i-1] - Positions.Items[i-2]);
      if DoTrim then
        LoadCell(c,r,SysUtils.Trim(sub))
      else
        LoadCell(c,r,sub);
      Inc(c);
    end;

    Inc(r);

    Inc(rc);

    if (MaxRows <> -1) then
      if rc > MaxRows then
        break;
      

    if (r >= RowCount) and not Eof(f) then
      RowCount := r + 1;
  end;

  CloseFile(f);
  CellsChanged(Rect(0,0,ColCount,RowCount));
  CellsLoaded;
end;

procedure TAdvStringGrid.LoadFromStream(stream:tStream);
var
  X,Y,LP: Integer;
  ss,ss1: string;

  function ReadString(var s:string): Integer;
  var
    c: char;
  begin
    c := '0';
    s := '';
    while (Stream.Position < Stream.Size) and (c <> #13) do
    begin
      Stream.Read(c,sizeof(char));
      if (c <> #13) then s := s + c;
    end;

    Stream.Read(c,sizeof(char));
    Result := Length(s);
  end;

begin
  {Allow to put other data before Grid's data in the stream}
  {stream.position:=0;}

  if (Stream.Position < Stream.Size) then
  begin
    if (Readstring(ss) > 0) then
    begin
      ss1 := Copy(ss,1,Pos(',',ss) - 1);
      ColCount := StrToInt(ss1) + SaveStartCol;
      ss1 := Copy(ss,Pos(',',ss) + 1,Length(ss));
      RowCount := StrToInt(ss1) + SaveStartRow;
    end;
  end;

  while (Stream.Position < Stream.Size) do
  begin
    LP := Stream.Position;

    ReadString(ss);
    if Pos('cw',ss) = 1 then
    begin
      Delete(ss,1,3);
      ss1 := GetToken(ss,',');
      X := StrToInt(ss1);
      Y := StrToInt(ss);
      ColWidths[X]:=Y;
    end
    else
    begin
      ss1 := GetToken(ss,',');
      if (ss1 = '') then // irregular data was found
      begin
        Stream.Position := LP;
        Break;
      end;
      X := StrToInt(ss1);
      ss1 := GetToken(ss,',');
      if (ss1 = '') then // irregular data was found
      begin
        Stream.Position := LP;
        Break;
      end;
      Y := StrToInt(ss1);
      LoadCell(X+SaveStartCol,Y+SaveStartRow,FileToLF(ss,FMultiLineCells));
    end;
  end;

  CellsChanged(Rect(0,0,ColCount,RowCount));
  CellsLoaded;
end;

function TAdvStringGrid.ColumnCustomCalc(ACol,FromRow,ToRow: Integer):Double;
begin
  Result := 0;
  if Assigned(OnColumnCalc) then
    OnColumnCalc(Self, ACol, FromRow, ToRow, Result);
end;

function TAdvStringGrid.ColumnCustomCalcGrp(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
begin
  Result := 0;
  if Assigned(OnGroupCalc) then
    OnGroupCalc(Self, ACol, FromRow, ToRow, Result);
end;

function TAdvStringGrid.ColumnCount(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
begin
  if (FromRow <> -1) and (ToRow <> -1) then
    Result := FromRow - ToRow
  else
    Result := RowCount - FixedRows - FixedFooters;
end;

function TAdvStringGrid.ColumnSum(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
var
  i,di: Integer;
  sum: Double;
  doh: Boolean;
  cnt: boolean;
  lh: TIntList;
begin
  if (FromRow = -1) or (ToRow = -1) then
  begin
    FromRow := FixedRows;
    ToRow := RowCount - 1 - FFixedFooters;
  end;

  sum := 0;

  if FloatingFooter.Visible then
    doh := ToRow > RowCount - 1
  else
    doh := ToRow > RowCount;

  ExportNotification(esExportStart, FromRow);

  lh := nil;
  for i := FromRow to ToRow do
  begin

    if doh then
      di := DisplRowIndex(i)
    else
      di := i;

    (*
    cnt := not (IsNode(di) and not IsHiddenRow(i) and (GroupColumn <> -1))
        and
           not (IsSummary(di) and not IsHiddenRow(i) and (GroupColumn <> -1));
    *)

    cnt := not (((IsNode(di) or IsSummary(di))) and (not IsHiddenRow(i,lh)) and (GroupColumn <> -1));

    if cnt and IsBaseCell(ACol, di) then
    begin
      ExportNotification(esExportNextRow, i);
      try
        if doh then
          Sum := Sum + AllFloats[ACol,i]
        else
          Sum := Sum + Floats[ACol,i];
      except
      end;
    end;
  end;

  if (lh <> nil) then FreeAndNil(lh);
  ExportNotification(esExportDone, -1);
  Result := sum;
end;

function TAdvStringGrid.ColumnAvg(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
begin
  if (FromRow = -1) or (ToRow = -1) then
  begin
    FromRow := FixedRows;
    ToRow := RowCount - 1 - FFixedFooters;
  end;

  if (ToRow - FromRow + 1) > 0 then
    Result := ColumnSum(ACol,FromRow,ToRow)/(ToRow - FromRow + 1)
  else
    Result := 0;
end;

function TAdvStringGrid.ColumnMin(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
var
  m: Double;
  i,di: Integer;
  doh: Boolean;
  cnt: boolean;
  lh: TIntList;
begin
  if (FromRow = -1) or (ToRow = -1) then
  begin
    FromRow := FixedRows;
    ToRow := RowCount - 1 - FFixedFooters;
  end;

  if FloatingFooter.Visible then
    doh := ToRow > RowCount - 1
  else
    doh := ToRow > RowCount;

  m := Floats[ACol,fromRow];

  ExportNotification(esExportStart, FromRow);

  lh := nil;
  for i := FromRow to ToRow do
  begin
    if doh then
      di := DisplRowIndex(i)
    else
      di := i;

    (*
    cnt := not (IsNode(di) and not IsHiddenRow(i) and (GroupColumn <> -1))
        and
           not (IsSummary(di) and not IsHiddenRow(i) and (GroupColumn <> -1));
    *)
    cnt := not (((IsNode(di) or IsSummary(di))) and (not IsHiddenRow(i,lh)) and (GroupColumn <> -1));

    if cnt and IsBaseCell(ACol, di) then
    begin
      ExportNotification(esExportNextRow, i);
      try
        if doh then
        begin
          if m > AllFloats[ACol,i] then
            m := AllFloats[ACol,i];
        end
        else
        begin
          if m > Floats[ACol,i] then
            m := Floats[ACol,i];
        end;
      except
      end;
    end;
  end;

  if (lh <> nil) then FreeAndNil (lh);
  ExportNotification(esExportDone, -1);
  Result := m;
end;

function TAdvStringGrid.ColumnMax(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
var
  m: Double;
  i,di: Integer;
  doh: Boolean;
  cnt: Boolean;
  lh: TIntList;
begin
  if (FromRow = -1) or (ToRow = -1) then
  begin
    FromRow := FixedRows;
    ToRow := RowCount - 1 - FFixedFooters;
  end;

  if FloatingFooter.Visible then
    doh := ToRow > RowCount - 1
  else
    doh := ToRow > RowCount;

  lh := nil;

  ExportNotification(esExportStart, FromRow);
  m := Floats[ACol,fromRow];
  for i := FromRow to ToRow do
  begin
    if doh then
      di := DisplRowIndex(i)
    else
      di := i;

    (*
    cnt := not (IsNode(di) and not IsHiddenRow(i) and (GroupColumn <> -1))
        and
           not (IsSummary(di) and not IsHiddenRow(i) and (GroupColumn <> -1));
    *)
    cnt := not (((IsNode(di) or IsSummary(di))) and (not IsHiddenRow(i,lh)) and (GroupColumn <> -1));

    if cnt and IsBaseCell(ACol, di) then
    begin
      ExportNotification(esExportNextRow, i);
      try
        if doh then
        begin
          if m < AllFloats[ACol,i] then
            m := AllFloats[ACol,i];
        end
        else
        begin
          if m < Floats[ACol,i] then
            m := Floats[ACol,i];
        end;
      except
      end;
    end;
  end;
  if (lh <> nil) then FreeAndNil (lh);
  ExportNotification(esExportDone, -1);
  Result := m;
end;

function TAdvStringGrid.ColumnStdDev(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
var
  m,d: double;
  i: integer;
begin
  if (FromRow = -1) or (ToRow = -1) then
  begin
    FromRow := FixedRows;
    ToRow := RowCount - 1 - FFixedFooters;
  end;

  m := ColumnAvg(ACol, FromRow, ToRow);

  ExportNotification(esExportStart, FromRow);

  d := 0;

  for i := fromRow to toRow do
  begin
    d := d + sqr(Floats[ACol,i] - m);
  end;

  Result := sqrt(d / (ToRow - FromRow + 1));

  ExportNotification(esExportDone, -1);
end;

function TAdvStringGrid.ColumnDistinct(ACol: integer; FromRow: integer = -1; ToRow: Integer = -1): Double;
var
  sl: TStringList;
  i: integer;
begin
  if (FromRow = -1) or (ToRow = -1) then
  begin
    FromRow := FixedRows;
    ToRow := RowCount - 1 - FFixedFooters;
  end;


  ExportNotification(esExportStart, FromRow);

  sl := TStringList.Create;

  try
    sl.Duplicates := dupIgnore;
    sl.Sorted := true;
    {$IFDEF DELPHI7_LVL}
    sl.CaseSensitive := false;
    {$ENDIF}

    for i := FromRow to ToRow do
    begin
      ExportNotification(esExportNextRow, i);
      sl.Add(Cells[ACol,i]);
    end;
    Result := sl.Count;

  finally
    ExportNotification(esExportDone, -1);
    sl.Free;
  end;
end;

function TAdvStringGrid.RowSum(ARow,FromCol,ToCol: Integer):Double;
var
  i: Integer;
  sum: Double;
begin
  sum := 0.0;
  for i := FromCol to ToCol do
  begin
    try
      if IsBaseCell(i, ARow) then
        sum := sum + Floats[i,ARow];
    except
    end;
  end;
  RowSum := sum;
end;

function TAdvStringGrid.RowAvg(ARow,FromCol,ToCol: Integer):Double;
begin
  Result := RowSum(ARow,FromCol,ToCol) / (ToCol - FromCol + 1);
end;

function TAdvStringGrid.RowMin(ARow,FromCol,ToCol: Integer):Double;
var
  m: Double;
  i: Integer;
begin
  m := Floats[FromCol,ARow];
  for i := FromCol to ToCol do
  begin
    try
      if IsBaseCell(i, ARow) then
        if m > Floats[i,ARow] then
          m := Floats[i,ARow];
    except
    end;
  end;      
  Result := m;
end;

function TAdvStringGrid.RowMax(ARow,fromCol,toCol: Integer):double;
var
  m: Double;
  i: Integer;
begin
  m := Floats[fromCol,ARow];
  for i := FromCol to ToCol do
  begin
    try
      if IsBaseCell(i, ARow) then
        if m < Floats[i,ARow] then
          m := Floats[i,ARow];
    except
    end;
  end;
  Result := m;
end;


function TAdvStringGrid.RectCalc(GR: TGridRect; CalcType: TCalcType): double;
var
  sr: TGridRect;
  i,j,t: integer;
  cv,v: double;
begin
  sr := GR;

  if sr.Left > sr.Right then
  begin
    t := sr.Right;
    sr.Right := sr.Left;
    sr.Left := t;
  end;

  if sr.Top > sr.Bottom then
  begin
    t := sr.Bottom;
    sr.Bottom := sr.Top;
    sr.Top := t;
  end;

  v := 0;
  t := 0;

  if CalcType in [ctMin,ctMax] then
    v := AllFloats[sr.Left, sr.Top];

  for i := sr.Left to sr.Right do
  begin
    for j := sr.Top to sr.Bottom do
    begin
      inc(t);
      cv := AllFloats[i,j];
      case CalcType of
      ctSum, ctAvg: v := v + cv;
      ctMin: if cv < v then v := cv;
      ctMax: if cv > v then v := cv;
      end;
    end;
  end;

  if CalcType = ctAvg then
  begin
    if t > 0 then
      v := v / t;
  end;

  Result := v;
end;


function TAdvStringGrid.RectSum(GR: TGridRect): Double;
begin
  Result := RectCalc(GR, ctSum);
end;

function TAdvStringGrid.RectAvg(GR: TGridRect): Double;
begin
  Result := RectCalc(GR, ctAvg);
end;

function TAdvStringGrid.RectMin(GR: TGridRect): Double;
begin
  Result := RectCalc(GR, ctMin);
end;

function TAdvStringGrid.RectMax(GR: TGridRect): Double;
begin
  Result := RectCalc(GR, ctMax);
end;

function TAdvStringGrid.SelectionSum: Double;
begin
  Result := RectSum(Selection);
end;

function TAdvStringGrid.SelectionAvg: Double;
begin
  Result := RectAvg(Selection);
end;

function TAdvStringGrid.SelectionMin: Double;
begin
  Result := RectMin(Selection);
end;

function TAdvStringGrid.SelectionMax: Double;
begin
  Result := RectMax(Selection);
end;

procedure TAdvStringGrid.SelectCells(FromCol,FromRow,ToCol,ToRow: integer);
var
  i,j: integer;
begin
  if MouseActions.DisjunctCellSelect then
  begin
    ClearSelectedCells;
    for i := FromCol to ToCol do
    begin
      for j := FromRow to ToRow do
        SelectedCells[i,j] := true;
    end;
  end
  else
  if (FromCol = ToCol) and (FromRow = ToRow) and (Col >= 0) and (Row >= 0) and (Col < ColCount - 1) and (Row < RowCount - 1) then
  begin
    Col := ToCol;
    Row := ToRow;
  end
  else
    Selection := TGridRect(Rect(FromCol,FromRow, ToCol, ToRow));
end;

function TAdvStringGrid.SelectedText:string;
var
  s,z,zr: Integer;
  ct,ts: string;
  gr: TGridRect;

begin
  ts := '';
  gr := Selection;

  if {(goRowSelect in Options) and} (FDragDropSettings.FOleEntireRows) then
  begin
    gr.Left := 0;
    gr.Right := ColCount - 1;
  end;

  if SaveHiddenCells then
    gr.Right := gr.Right + NumHiddenColumns;

  if FMouseActions.DisjunctRowSelect then
  begin
    for z := FixedRows to RowCount - 1 do
    begin

      if FMouseActions.RowSelectPersistent then
        zr := RemapRowInv(z)
      else
        zr := z;

      if RowSelect[zr] then
       begin
         for s := gr.Left to gr.Right do
         begin
           if SaveHiddenCells then
             ct := Cells[s,z]
           else
             ct := Cells[RemapCol(s),z];

           if Pos('{\',ct) > 0 then
           begin
             CellToRich(s,z,RichEdit);
             ct := RichEdit.Text;
           end;
           if (LinesInText(ct,fMultiLineCells) > 1) and
              FExcelClipboardformat then LineFeedsToCSV(ct);
           if s <> gr.Right then
             ts := ts + ct + #9
           else
             ts := ts + ct;
         end;
         //if z <> gr.Bottom then
           ts := ts + #13#10;
       end;
     end;
   end
  else
  for z := gr.Top to gr.Bottom do
  begin
    for s := gr.Left to gr.Right do
    begin
      if SaveHiddenCells then
        ct := Cells[s,z]
      else
        ct := Cells[RemapCol(s),z];

      //ct := Cells[RemapCol(s),z];

      if Pos('{\',ct) > 0 then
      begin
        CellToRich(s,z,RichEdit);
        ct := RichEdit.Text;
      end;

      if (LinesInText(ct, FMultiLineCells) > 1) and
         FExcelClipboardformat then LineFeedsToCSV(ct);

      if s <> gr.Right then
        ts := ts + ct + #9
      else
        ts := ts + ct;
    end;
    if z <> gr.Bottom then
      ts := ts + #13#10;
  end;

  Result := ts;
end;

function TAdvStringGrid.IsSelected(ACol,ARow: Integer): Boolean;
var
  rr: Integer;
begin
  Result := False;
  if (ARow < FixedRows) or (ACol < FixedCols) then
    Exit;

  if FMouseActions.DisjunctCellSelect then
  begin
    Result := FSelectedCells.IndexOf(Pointer(MakeLong(ACol,ARow))) <> -1;
  end
  else
  begin
    if FMouseActions.DisjunctRowSelect then
    begin
      if FMouseActions.RowSelectPersistent then
        rr := RemapRowInv(ARow)
      else
        rr := ARow;
      Result := RowSelect[rr];
    end
    else
    begin
      if FMouseActions.DisjunctColSelect then
        Result := ColSelect[ACol]
      else
        Result := (ACol >= Selection.Left) and
                  (ACol <= Selection.Right) and
                  (ARow >= Selection.Top) and
                  (ARow <= Selection.Bottom);
    end;
  end;
end;

procedure TAdvStringGrid.AutoNumberCol(const ACol: Integer);
var
  r: Integer;
begin
  if RowCount > 0 then
  for r := FixedRows + FAutoNumberStart to RowCount -1 - FFixedFooters do
    if FAutoNumberDirection = sdAscending then
      Ints[ACol,r] := r - FixedRows + 1 + FAutoNumberOffset
    else
      Ints[ACol,RowCount -1 - FFixedFooters - r + FixedRows] := r - FixedRows + 1 + FAutoNumberOffset;
end;

procedure TAdvStringGrid.AutoNumberRow(const ARow: Integer);
var
  c: Integer;
begin
  if ColCount > 0 then
  for c := FixedCols + FAutoNumberStart  to ColCount -1 - FFixedRightCols do
    if FAutoNumberDirection = sdAscending then
      Ints[c,ARow] := c - FixedCols + 1 + FAutoNumberOffset
    else
      Ints[ColCount -1 - FFixedRightCols - c + FixedCols,ARow] := c - FixedCols + 1 + FAutoNumberOffset;
end;


procedure TAdvStringGrid.AutoSizeCells(const DoFixedCells: Boolean; const PaddingX,PaddingY: Integer);
var
  i,j,x,y,SCol: Integer;
  TextSize: TSize;
  pt: TPoint;
  ow,nw,oh,nh,lh: Integer;

begin
  if DoFixedCells then
  begin
    x := 0;
    y := 0;

  end
  else
  begin
    x := FixedCols;
    y := FixedRows;
  end;

  BeginUpdate;
  try
    for i := x to ColCount - 1 do
    begin
      SCol := RemapCol(i);

      if SizeGrowOnly then
        ow := ColWidths[i]
      else
        ow := 0;

      lh := 0;

      for j := y to RowCount - 1 do
      begin
        if SizeGrowOnly then
          oh := RowHeights[j]
        else
          oh := lh;

        if (i < FixedCols) or (j < FixedRows) then
          Canvas.Font.Assign(FixedFont)
        else
          Canvas.Font.Assign(Font);

        GetCellColor(i,j,[],Canvas.Brush,Canvas.Font);

        pt := CellGraphicSize[i,j];

        TextSize := GetCellTextSize(SCol,j,False);

        TextSize.cx := TextSize.cx + pt.x + paddingx + XYOffset.X;
        TextSize.cy := TextSize.cy + pt.y + paddingy + XYOffset.Y;

        if not IsXMergedCell(i,j) then
        begin
          if (TextSize.cx > ow) then
          begin
            nw := CheckLimits(TextSize.cx,MinColWidth,MaxColWidth);
            if nw > ow then
            begin
              ColWidths[i] := nw;
              ow := nw;
            end;
          end;
        end;

        if not IsYMergedCell(i,j) then
        begin
          if (TextSize.cy > oh) then
          begin
            nh := CheckLimits(TextSize.cy,MinRowHeight,MaxRowHeight);
            if nh > oh then
            begin
              RowHeights[j] := nh;
              lh := nh;
            end;
          end;
        end;
      end;
    end;

  finally
    EndUpdate;
  end;
end;

procedure TAdvStringGrid.AutoGrowColumns(const DoFixedCols: Boolean; const Padding: Integer = 4);
var
  sz: boolean;
begin
  sz := SizeGrowOnly;
  SizeGrowOnly := true;
  AutoSizeColumns(DoFixedCols,Padding);
  SizeGrowOnly := sz;
end;

procedure TAdvStringGrid.AutoSizeColumns(const DoFixedCols: Boolean; const Padding: Integer = 4);
var
  i,j,k: Integer;
begin
  if DoFixedCols then
  begin
    j := 0;
    k := ColCount - 1;
  end
  else
  begin
    j := FixedCols;
    k := ColCount - FixedRightCols - 1;
  end;

  for i := j to k do
  begin
    AutoSizeCol(i);
    if Padding <> 0 then
      ColWidths[i] := CheckLimits(ColWidths[i] + Padding, MinColWidth, MaxColWidth);
  end;
end;

procedure TAdvStringGrid.SizeToWidth(const ACol: Integer;IncOnly: Boolean);
var
  MaxWidth, TextW, NewW, i: Integer;
  cg: TCellGraphic;
  RCol: Integer;
  sr,er:integer;
begin
  MaxWidth := 0;

  RCol := RemapCol(ACol);

  case ColumnSize.Rows of
  arNormal:
    begin
      sr := FixedRows;
      er := RowCount - FixedFooters;
    end;
  arFixed:
    begin
      sr := 0;
      er := FixedRows;
    end
  else
    begin
      sr := 0;
      er := RowCount - 1;
    end;
  end;

  for i := sr to er do
  begin
    if not IsXMergedCell(ACol,i) then
    begin
      (*
      // init font
      if (ACol < FixedCols) or (i < FixedRows) then
        Canvas.Font.Assign(FixedFont)
      else
        Canvas.Font.Assign(Font);

      // get cell font
      GetCellColor(RCol,i,[],Canvas.Brush,Canvas.Font);

      // apply zoom factor
      Canvas.Font.Size := Canvas.Font.Size + FZoomFactor;
      *)

      TextW := CellGraphicSize[RCol,i].x + GetCellTextSizeInt(ACol,RCol,i,true,WordWrap).cx;

      if (ACol = 0) and IsNode(i) then
      begin
        TextW := TextW + 16;
      end;

      if (ControlLook.DropDownAlwaysVisible) then
      begin
        if HasCombo(ACol,i) then
          TextW := TextW + Round(ControlLook.DropDownButtonWidth * FDPIScale);
      end;

      if FilterDropDownAuto and (i = FilterDropDownRow) then
      begin
        if GetFilter(ACol) then
          TextW := TextW + 12;
      end;

      if ShouldDrawSortIndicator(ACol,i) and (SortSettings.Column = ACol) then
      begin
        TextW := TextW + 10;
      end;

      cg := GetCellGraphic(RCol,i);

      if Assigned(cg) then
        if (cg.FCellHAlign = haFull) then
          TextW := CellGraphicSize[RCol,i].x - (FXYOffset.X + 2 * (GridLineWidth + 1)) ;

      if TextW > MaxWidth then
        MaxWidth := TextW;
    end;
  end;

  // Allow 2 pixel spacing at begin & end
  NewW := MaxWidth + XOffsetSize + 2 * (GridLineWidth + 1);

  if (IncOnly and (NewW > ColWidths[ACol])) or
     not IncOnly then
  begin
    UpdateAutoColSize(ACol,NewW);
    ColWidths[ACol] := CheckLimits(NewW,MinColWidth,MaxColWidth);
  end;
end;

procedure TAdvStringGrid.SizeToHeight(const ARow: Integer;IncOnly: Boolean; Padding: integer = 0);
var
  cg: TCellGraphic;
  MaxHeight, TextH, NewH, i,ri: Integer;
  NoScroll: Boolean;
  ts,gs: integer;
begin
  MaxHeight := 0;

  for i := 0 to ColCount - 1 do
  begin
    if not IsYMergedCell(i,ARow) and not IsIgnoredColumn(RemapCol(i)) then
    begin
      if (ARow < FixedRows) or (i < FixedCols) then
        Canvas.Font.Assign(FixedFont)
      else
        Canvas.Font.Assign(Font);

      GetCellColor(i,ARow,[],Canvas.Brush,Canvas.Font);

      if Canvas.Font.Size + FZoomFactor <> 0 then
        Canvas.Font.Size := Canvas.Font.Size + FZoomFactor
      else
        Canvas.Font.Size := 1;

      ri := RemapCol(i);

      ts := GetCellTextSizeInt(i,ri,ARow,false,WordWrap).cy;

      gs := GetCellGraphicSizeEx(ri,ARow,Padding).y;

      cg := GetCellGraphic(ri,ARow);

      if Assigned(cg) then
      begin
        if (cg.CellVAlign = vaFull) then
          if (ts = 0) then
            gs := DefaultRowHeight
          else
            gs := 0;

        if (cg.CellType in [ctVirtCheckBox, ctDataCheckBox]) then
        begin
          if (gs > 0) then
            ts := 0;
        end;
      end;

      TextH := ts + gs;

      // When merged, do not take the content of "invisible" cells into account for the height
      if IsMergedCell(i, ARow) then
      begin
        if not IsBaseCell(i,ARow) then
          TextH := 0;
      end;

      if Assigned(cg) then
      begin
        //if (cg.FCellVAlign = vaFull) or (NoImageAndText) then
        //  TextH := CellGraphicSize[i,ARow].y - (XYOffset.Y + 2 * (GridLineWidth + 1)) ;

        if cg.CellType in [ctDataCheckBox, ctCheckbox, ctVirtCheckBox, ctRadioButton] then
          TextH := DefaultRowHeight;
      end;

      if TextH > MaxHeight then
        MaxHeight := TextH;
    end;
  end;

  NewH := MaxHeight + YOffsetSize + 2 * (GridLineWidth);

  if XYOffsetTopLeftOnly then
    NewH := NewH + 2;

  NoScroll := (VisibleRowCount = RowCount) and EditMode and SizeWhileTyping.Height;

  if (IncOnly and (NewH > RowHeights[ARow])) or
     not IncOnly then
  begin
    // UpdateAutoRowSize(ARow,NewH);
    RowHeights[ARow] := CheckLimits(NewH,MinRowHeight, MaxRowHeight);
  end;

  if (VisibleRowCount <> RowCount) and NoScroll then
  begin
    ShowInplaceEdit;
    NormalEdit.SelStart := length(NormalEdit.Text);
  end;
end;

procedure TAdvStringGrid.AutoGrowCol(const ACol: Integer; const Padding: Integer = 0);
var
  sz: boolean;
begin
  sz := SizeGrowOnly;
  SizeGrowOnly := true;
  AutoSizeCol(ACol,Padding);
  SizeGrowOnly := sz;
end;

procedure TAdvStringGrid.AutoSizeCol(const ACol: Integer; const Padding: Integer = 0);
var
  i,ni,nw,lvl: integer;
begin
  if (ACol = 0) and HasNodes then
  begin
    ni := 0;
    nw := 0;
    case CellNode.NodeType of
    cnFlat,cnXP: nw := 4;
    cnLeaf: nw := 8;
    cn3D: nw := 6;
    cnGlyph: if not CellNode.ExpandGlyph.Empty then
        nw := CellNode.ExpandGlyph.Width div 2;
    end;

    for i := 0 to Rowcount - 1 do
    begin
      lvl := GetNodeLevel(i);

      lvl := lvl * CellNode.NodeIndent + nw;
      if lvl > ni then
        ni := lvl;
    end;

    ColWidths[ACol] := ni;
  end;

  SizetoWidth(ACol,SizeGrowOnly);

  if Padding <> 0 then
     ColWidths[ACol] := CheckLimits(ColWidths[ACol] + Padding, MinColWidth, MaxColWidth);
end;

procedure TAdvStringGrid.SizeToCols;
var
  i,tot: integer;
begin
  tot := 0;
  for i := 0 to ColCount - 1 do
  begin
    tot := tot + ColWidths[i];
  end;

  ClientWidth := tot;
end;

procedure TAdvStringGrid.SizeToRows;
var
  i,tot: integer;
begin
  tot := 0;
  for i := 0 to RowCount - 1 do
  begin
    tot := tot + RowHeights[i];
  end;

  ClientHeight := tot;
end;

procedure TAdvStringGrid.SizeToCells;
var
  sb: TScrollStyle;
begin
  sb := ScrollBars;

  ScrollBars := ssNone;
  SizeToCols;
  SizeToRows;

  ScrollBars := sb;
end;


procedure TAdvStringGrid.AutoSizeRows(const DoFixedRows: Boolean; const Padding: Integer = 0);
var
  i,j: Integer;
begin
  if RowCount = 0 then
    Exit;

  if DoFixedRows then
    j := 0
  else
    j := FixedRows;

  ExportNotification(esExportStart, j);

  for i := j to RowCount - 1 do
  begin
    ExportNotification(esExportNextRow, i);

    if Wordwrap then
    begin
      AutoSizeRow(i);
      if Padding <> 0 then
        RowHeights[i] := CheckLimits(RowHeights[i] + Padding, MinRowHeight, MaxRowHeight);
    end
    else
    begin
      SizeToLines(i,MaxLinesInRow(i),Padding)
    end;  
  end;

  UpdateScrollbars(true);

  ExportNotification(esExportDone, -1);
end;

procedure TAdvStringGrid.SizeToLines(const ARow,Lines,padding: Integer);
var
  th, nh: Integer;
  cv: string;
  DCREct: TRect;

begin
  GetCellColor(FixedCols,ARow,[],Canvas.Brush,Canvas.Font);
  cv := 'gh';
  DCRect := Rect(0,0,4096,20);
  th := DrawTextEx(Canvas.Handle,PChar(cv),Length(cv), DCRect, DT_SINGLELINE or DT_CALCRECT, nil) + 2;
  nh := CheckLimits(Padding + (th * Lines),MinRowHeight,MaxRowHeight);
  RowHeights[ARow] := nh + XYOffset.Y;
end;

procedure TAdvStringGrid.AutoSizeRow(const ARow: Integer; const Padding: Integer = 0);
begin
  SizeToHeight(ARow,SizeGrowOnly,Padding);

  if (Padding <> 0) then
    RowHeights[ARow] := CheckLimits(RowHeights[ARow] + Padding, MinRowHeight, MaxRowHeight);
end;

procedure TAdvStringGrid.AutoFitColumns(const DoFixedCells: boolean = true);
var
  ratio: real;
  CurrW: integer;
  ScrlW: integer;
  ColW: integer;
  BrdrW: integer;
  LineW: integer;
  UseW,RemW,ShareW: integer;
  i, Largest: integer;
  StartCol,EndCol: integer;
  AvailWidth: integer;

begin
  if (ScrollBarAlways <> saVert) and ((ScrollBars = ssNone) or (VisibleRowCount + FixedRows >= RowCount)) then
    ScrlW := 0
  else
    ScrlW := GetSystemMetrics(SM_CXVSCROLL);

  if BorderStyle = bsSingle then
  begin
    if Ctl3D then // border is sunken (vertical border is 2 pixels wide)
      BrdrW := 4
    else // border is one-dimensional (vertical border is one pixel wide)
      BrdrW := 2;
  end
  else
    BrdrW := 0;

  if DoFixedCells then
  begin
    StartCol := 0;
    EndCol := ColCount - 1;
    AvailWidth := Width;
  end
  else
  begin
    StartCol := FixedCols;
    EndCol := ColCount - 1 - FixedRightCols;

    AvailWidth := Width;
    for i := 0 to StartCol - 1 do
    begin
      AvailWidth := AvailWidth - ColWidths[i];
    end;

    for i := EndCol + 1 to ColCount - 1 do
    begin
      AvailWidth := AvailWidth - ColWidths[i];
    end;
  end;

  LineW := 0;

  if (goVertLine in Options) then
    LineW := LineW + ((ColCount - (FixedCols + FixedRightCols)) * GridLineWidth);

  if (goFixedVertLine in Options) and DoFixedCells then
    LineW := LineW + FixedCols + FixedRightCols;

  if ColCount > 1 then
  begin
    ColW := 0;
    for i := StartCol to EndCol do
      ColW := ColW + ColWidths[i];

    UseW := AvailWidth - (ScrlW + BrdrW + LineW);

    if ColW = AvailWidth - (ScrlW + BrdrW) then
      Exit;

    ratio := UseW / ColW;

    CurrW := 0;
    if ColCount > 2 then
    begin
      for i := StartCol to EndCol do
        CurrW := CurrW + Round(ColWidths[i] * ratio);

      ratio := CurrW / ColW;
      for i := StartCol to EndCol do
        ColWidths[i] := Round(ColWidths[i] * ratio);
    end
    else
    begin
      for i := StartCol to EndCol do
        CurrW := CurrW + Round(ColWidths[i] * ratio);

      ratio := CurrW / ColW;

      for i := StartCol to EndCol do
        ColWidths[i] := Round(ColWidths[i] * ratio);
    end;
  end
  else
    ColWidths[0] := Width - (ScrlW + 5);

  // Now check the sizing and adjust to make it fill the grid
  ColW := 0;
  for i := StartCol to EndCol do
    ColW := ColW + ColWidths[i];

  RemW := AvailWidth - (ColW + ScrlW + BrdrW);

  if (RemW > EndCol - StartCol + 1) and (EndCol - StartCol > 0) then
  begin
    ShareW := RemW div (EndCol - StartCol + 1);
    RemW := RemW - (ShareW * (EndCol - StartCol + 1));
    for i := StartCol to EndCol do
    begin
      ColWidths[i] := ColWidths[i] + ShareW;
    end;
  end;

  // find the biggest column and dump the remainder into that
  Largest := 0;
  for i := StartCol + 1 to EndCol do
  begin
    if ColWidths[i] > ColWidths[Largest] then
      Largest := i;
  end;

  ColWidths[Largest] := ColWidths[Largest] + RemW;
end;


procedure TAdvStringGrid.SwapColumns(ACol1, ACol2: Integer);
var
  cw,i: Integer;
begin
  ColCount := ColCount + 1 + FNumHidden;
  Cols[ColCount - 1] := Cols[ACol1];
  Cols[ACol1] := Cols[ACol2];
  Cols[ACol2] := Cols[ColCount - 1];

  FNilObjects := true;
  ClearCols(ColCount - 1, 1);
  FNilObjects := false;

  ColCount := ColCount - 1 - FNumHidden;
  cw := ColWidths[ACol1];
  ColWidths[ACol1] := ColWidths[ACol2];
  ColWidths[ACol2] := cw;
  if FSortSettings.Column = ACol1 then
    FSortSettings.Column := ACol2
  else
    if FSortSettings.Column = ACol2 then
      FSortSettings.Column := ACol1;

  if (FControlList.Count > 0) then
  begin
    for i := 0 to FControlList.Count - 1 do
    begin
      if FControlList.Control[i].X = ACol1 then
        FControlList.Control[i].X := ACol2
      else
        if FControlList.Control[i].X = ACol2 then
          FControlList.Control[i].X := ACol1;
    end;
    CellControlsUpdate;
  end;
end;

procedure TAdvStringGrid.SwapRows(ARow1, ARow2: Integer);
var
 rh,i: Integer;
begin
  RowCount := RowCount + 1;
  Rows[RowCount - 1] := Rows[ARow1];
  Rows[ARow1] := Rows[ARow2];
  Rows[ARow2] := Rows[RowCount - 1];

  FNilObjects := True;
  ClearRows(RowCount-1,1);
  FNilObjects := False;

  RowCount := RowCount - 1;
  rh := RowHeights[ARow1];
  RowHeights[ARow1] := RowHeights[ARow2];
  RowHeights[ARow2] := rh;

  if (FControlList.Count > 0) then
  begin
    for i := 0 to FControlList.Count - 1 do
    begin
      if FControlList.Control[i].Y = ARow1 then
        FControlList.Control[i].Y := ARow2
      else
        if FControlList.Control[i].Y = ARow2 then
          FControlList.Control[i].Y := ARow1;
    end;
    CellControlsUpdate;
  end;
end;

procedure TAdvStringGrid.SortSwapRows(ARow1, ARow2: Integer);
var
  h1,h2: Integer;
  rs: Boolean;
  s: string;
  o: TObject;
  rri1,rri2: integer;
begin
  inc(Swaps);

  if (FSortRowXRef.Count >= ARow1) and (FSortRowXRef.Count >= ARow2) then
  begin
    h1 := FSortRowXRef.Items[ARow1];
    FSortRowXRef.Items[ARow1] := FSortRowXRef.Items[ARow2];
    FSortRowXRef.Items[ARow2] := h1;
  end;

  if FUseEnabledRows then
  begin
    rs := RowEnabled[ARow1];
    RowEnabled[ARow1] := RowEnabled[ARow2];
    RowEnabled[ARow2] := rs;
  end;

  if FSortSettings.SingleColumn then
  begin
    s := Cells[FSortSettings.Column, ARow1];
    o := GridObjects[FSortSettings.Column, ARow1];
    Cells[FSortSettings.Column, ARow1] := Cells[FSortSettings.Column, ARow2];
    GridObjects[FSortSettings.Column, ARow1] := GridObjects[FSortSettings.Column, ARow2];
    Cells[FSortSettings.Column, ARow2] := s;
    GridObjects[FSortSettings.Column, ARow2] := o;
    Exit;
  end;

  h1 := RowHeights[ARow1];
  h2 := RowHeights[ARow2];

  SortList.Assign(Rows[ARow1]);
  Rows[ARow1] := Rows[ARow2];
  Rows[ARow2].Assign(SortList);

  if h1 <> h2 then
  begin
    RowHeights[ARow1] := h2;
    RowHeights[ARow2] := h1;
  end;

  if FMouseActions.DisjunctRowSelect and FNavigation.MoveRowOnSort then
  begin
    if NumHiddenRows > 0 then
    begin
      rri1 := RealRowIndex(ARow1);
      rri2 := RealRowIndex(ARow2);
      rs := RowSelect[rri1];
      RowSelect[rri1] := RowSelect[rri2];
      RowSelect[rri2] := rs;
    end
    else
    begin
      rs := RowSelect[ARow1];
      RowSelect[ARow1] := RowSelect[ARow2];
      RowSelect[ARow2] := rs;
    end;
  end;

  if ShowModified.Enabled then
  begin
    rs := RowModified[ARow1];
    RowModified[ARow1] := RowModified[ARow2];
    RowModified[ARow2] := rs;
  end;

  if ARow1 = SortRow then
    SortRow := ARow2
  else
    if ARow2=SortRow then
      SortRow := ARow1;
end;

procedure TAdvStringGrid.SetPreviewPage(Value: Integer);
begin
  FPrintPageFrom := Value;
  FPrintPageTo := Value;
end;

procedure TAdvStringGrid.PrintPreview(Canvas:TCanvas;DisplayRect:TRect);
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrivatePrintPreviewRect(Canvas, DisplayRect, gr, False);
end;

procedure TAdvStringGrid.PrintPreviewRect(Canvas:TCanvas; DisplayRect:TRect; Gridrect:TGridRect);
begin
  PrivatePrintPreviewRect(Canvas, DisplayRect, GridRect, False);
end;

procedure TAdvStringGrid.PrintPreviewSelection(Canvas:TCanvas; DisplayRect:TRect);
begin
  PrivatePrintPreviewRect(Canvas, DisplayRect, Selection, False);
end;

procedure TAdvStringGrid.PrintPreviewSelectedRows(Canvas: TCanvas; DisplayRect:TRect);
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrivatePrintPreviewRect(Canvas, DisplayRect, gr, True);
end;

procedure TAdvStringGrid.PrintPreviewSelectedCols(Canvas: TCanvas; DisplayRect:TRect);
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrivatePrintPreviewRect(Canvas, DisplayRect, gr, True);
end;

procedure TAdvStringGrid.PrivatePrintPreviewRect(Canvas:TCanvas; Displayrect: TRect; Gridrect: TGridRect; SelRows: Boolean);
var
  i: Integer;
  mm: Integer;
  FPrintPageFrom, FPrintPageTo: integer;

begin
  ExportNotification(esExportStart,-1);
  FPrintRect := Gridrect;

  try
    mm := GetMapMode(Canvas.Handle);
    SetMapMode(Canvas.Handle,mm_lometric); {everything in 0.1mm}
    PrevRect := DisplayRect;
    if not FFastPrint then
    begin
      i := BuildPages(Canvas,prCalcPreview,-1,SelRows);
      FPrintPageNum := i;
    end
    else
      i := 1;

    FPrintPageFrom := 1;
    FPrintPageTo := i;

    FIsPrintPreview := true;

    if Assigned(FOnPrintStart) then
      FOnPrintStart(Self,i,FPrintPageFrom,FPrintPageTo);

    if (FPrintPageFrom > 0) and (FPrintPageTo > 0) and (FPrintPageTo >= FPrintPageFrom) then
    begin
      Prevrect := DisplayRect;
      BuildPages(Canvas,prPreview,i,SelRows);
      SetMapMode(Canvas.Handle,mm);
    end;
  finally
    ExportNotification(esExportDone,-1);
    FIsPrintPreview := false;
  end;
end;

procedure TAdvStringGrid.Print;
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrivatePrintRect(gr,False);
end;

procedure TAdvStringGrid.PrintSelection;
begin
  PrivatePrintRect(Selection,False);
end;

procedure TAdvStringGrid.PrintRect(Gridrect:TGridRect);
begin
  PrivatePrintRect(GridRect,False);
end;

procedure TAdvStringGrid.PrintSelectedRows;
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrivatePrintRect(gr,True);
end;

procedure TAdvStringGrid.PrintSelectedCols;
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrivatePrintRect(gr,True);
end;


procedure TAdvStringGrid.PrivatePrintRect(Gridrect:TGridRect;SelRows: Boolean);
var
  pages: Integer;
  mm: Integer;
  flg: boolean;
begin
  ExportNotification(esExportStart,-1);

  FPrintRect := Gridrect;

  if not Printer.Printing and not FPrintSettings.UseDefaultOrientation then
    Printer.Orientation := FPrintSettings.Orientation;

  PrevRect.Top := 0;
  PrevRect.Left := 0;
  PrevRect.Right := Round(254/GetDeviceCaps(Printer.Handle,LOGPIXELSX) * Printer.PageWidth);
  PrevRect.Bottom := Round(254/GetDeviceCaps(Printer.Handle,LOGPIXELSY) * Printer.PageHeight);

  // use printer canvas for calc
  Printer.Title := FPrintSettings.JobName;

  if not FFastPrint then
  begin
    mm := GetMapMode(Canvas.Handle);

    SetMapMode(Canvas.Handle, mm_lometric);

    pages := BuildPages(Canvas, prCalcPrint, -1, SelRows);

    SetMapMode(Canvas.Handle, mm);
  end
  else
    pages := MaxInt;

  FPrintPageFrom := 1;
  FPrintPageTo := pages;
  FPrintPageNum := pages;

  if Assigned(FOnPrintStart) then
  begin
    FOnPrintStart(Self,Pages,FPrintPageFrom,FPrintPageTo);

    if (FPrintPageFrom = 0) or (FPrintPageTo = 0) or (FPrintPageTo < FPrintPageFrom) then
      Exit;
  end;

  flg := Printer.Printing;
  if not flg then
    Printer.BeginDoc;

  mm := GetMapMode(Printer.Canvas.Handle);
  SetMapMode(Printer.Canvas.Handle, mm_lometric);

  Printer.Canvas.Brush.Color := clWhite;
  Printer.Canvas.Pen.Color := clWhite;
  Printer.Canvas.FillRect(PrevRect);

  FPrintPageNum := FPrintPageTo;

  try
    BuildPages(Printer.Canvas, prPrint, pages, SelRows);
  finally
    SetMapMode(Printer.Canvas.Handle,mm);
    if not flg then
      Printer.EndDoc;
  end;

  ExportNotification(esExportDone,-1);
end;


procedure TAdvStringGrid.PrintDraw(Canvas: TCanvas; DrawRect: TRect);
var
  gr: TGridRect;
begin
  gr.Top := 0;
  gr.Left := 0;
  gr.Bottom := RowCount - 1;
  gr.Right := ColCount - 1;
  PrintDrawRect(Canvas,DrawRect,gr);
end;

procedure TAdvStringGrid.PrintDrawRect(Canvas: TCanvas;DrawRect: TRect; GridRect: TGridRect);
var
  mm: Integer;
begin
  FPrintRect := GridRect;
  PrevRect := DrawRect;
  FPrintPageFrom := 1;
  FPrintPageTo := 1;
  FPrintPageNum := 1;
  mm := GetMapMode(Canvas.Handle);
  SetMapMode(Canvas.Handle,mm_lometric);
  BuildPages(Canvas,prPrint,1,False);
  SetMapMode(Canvas.Handle,mm);
end;


function TAdvStringGrid.YOffsetSize: integer;
begin
  if FXYOffsetTopLeftOnly then
    Result := FXYOffset.Y
  else
    Result := 2 * FXYOffset.Y;
end;

function TAdvStringGrid.XOffsetSize: integer;
begin
  if FXYOffsetTopLeftOnly then
    Result := FXYOffset.X
  else
    Result := 2 * FXYOffset.X;
end;

function TAdvStringGrid.MaxLinesInGrid: Integer;
var
  i,j,k: Integer;
begin
  Result := 1;
  if (ColCount <= 0) or (RowCount <= 0) then
    Exit;
  if not FMultiLineCells then
    Exit;

  for i := 0 to ColCount - 1 do
    for j := 0 to RowCount - 1 do
    begin
      k := LinesInText(Cells[RemapCol(i),j],fMultiLineCells);
      if k > Result then Result := k;
    end;
  MaxLinesInGrid := Result;  
end;

function TAdvStringGrid.MaxCharsInCol(ACol: Integer): Integer;
var
  i,k,rc: Integer;
  s,substr: string;

begin
  Result := 0;

  rc := ACol;

  for i := 0 to RowCount - 1 do
  begin
    s := SaveCell(rc,i);
    repeat
      substr := GetNextLine(s,FMultiLineCells);
      k := Length(substr);
      if k > Result then
        Result := k;
    until s = '';
  end;
end;

procedure PositionText(var ARect:TRect;hal:TAlignment;val:TVAlignment;AAngle,x1,x2,y1,y2: Integer);
var
  Q: byte;
begin
  Q := 4;
  if AAngle <= 90 then Q := 1
  else if AAngle <= 180 then Q := 2
  else if AAngle <= 270 then Q := 3;

  case Q of
  1:begin
      case hal of
      taLeftJustify:aRect.Left := aRect.Left;
      taRightJustify:aRect.Left := aRect.Right - x1 - x2;
      taCenter:aRect.Left := aRect.Left + ((aRect.Right - Arect.Left-x2-x1) div 2);
      end;
      case val of
      vtaTop:aRect.Top := aRect.Top + y1;
      vtaCenter:aRect.Top := arect.Top - ((-arect.Bottom + arect.Top + y2 + y1) div 2) + y1;
      vtaBottom:aRect.Top := aRect.Bottom - y2;
      end;
    end;
  2:begin
      case hal of
      taLeftJustify:aRect.Left := aRect.Left + x1;
      taRightJustify:aRect.Left := aRect.Right - x2;
      taCenter:aRect.Left := aRect.Right-((aRect.Right-Arect.Left+x2-x1) div 2);
      end;
      case val of
      vtaTop:aRect.Top := aRect.Top + y1 + y2;
      vtaCenter:aRect.Top := arect.Top - ((-arect.Bottom + arect.Top + y2 + y1) div 2) + y1 + y2;
      vtaBottom:aRect.Top := aRect.Bottom;
      end;
    end;
  3:begin
      case hal of
      taLeftJustify:aRect.Left := aRect.Left + x2 + x1;
      taRightJustify:aRect.Left := aRect.Right;
      taCenter:aRect.Left := aRect.Right - ((aRect.Right - Arect.Left - x2 - x1) div 2);
      end;
      case val of
      vtaTop:aRect.Top := aRect.Top + y2;
      vtaCenter:aRect.Top := arect.Top - ((-arect.Bottom + arect.Top + y2 + y1) div 2)+y2;
      vtaBottom:aRect.Top := aRect.Bottom - y1;
      end;
    end;
  4:begin
      case hal of
      taLeftJustify:aRect.Left := aRect.Left + x2;
      taRightJustify:aRect.Left := aRect.Right - x1;
      taCenter:aRect.Left := aRect.Left + ((aRect.Right - Arect.Left + x2 - x1) div 2);
      end;
      case val of
      vtaTop:aRect.Top := arect.Top;
      vtaCenter:aRect.Top := aRect.Top - ((-aRect.Bottom + Arect.Top + y2 + y1) div 2);
      vtaBottom:aRect.Top := aRect.Bottom - y2 - y1;
      end;
    end;
  end;
end;

procedure TAdvStringGrid.CalcTextPos(var ARect:TRect;var sz: TSize; AAngle: Integer;ATxt:String;hal: TAlignment; val:TVAlignment);
var
  hSaveFont: HFont;
  y1,y2: Integer;
  x1,x2: Integer;

begin
  sz.cx := 0;
  sz.cy := 0;
  hSaveFont := SelectObject(Canvas.Handle,Canvas.Font.Handle);
  GetTextExtentPoint32(Canvas.Handle,PChar(aTxt + 'w'),Length(aTxt),sz);
  SelectObject(Canvas.Handle,hSaveFont);
  InflateRect(ARect,-2,-2);

  x1 := Abs(Trunc(sz.cx * cos(AAngle*Pi/180)));
  x2 := Abs(Trunc(sz.cy * sin(AAngle*Pi/180)));

  y1 := Abs(Trunc(sz.cx * sin(AAngle*Pi/180)));
  y2 := Abs(Trunc(sz.cy * cos(AAngle*Pi/180)));

  PositionText(ARect,hal,val,AAngle,x1,x2,y1,y2);
end;


function TAdvStringGrid.MaxLinesInRow(ARow: Integer): Integer;
var
  i,k: Integer;
begin
  Result := 1;

  if (ColCount <= 0) or not FMultiLineCells then
    Exit;

  for i := 0 to ColCount - 1 do
  begin
    k := LinesInText(Cells[RemapCol(i),ARow],FMultiLineCells);
    if k > Result then
      Result := k;
  end;
end;

//--------------------------------------------------------------------
// Font mapping conversion routines : used round in previous version!
//--------------------------------------------------------------------
function TAdvStringGrid.MapFontHeight(pointsize: Integer): Integer;
begin
  MapFontHeight := -Trunc(pointsize*254/72*FontScaleFactor);
end;

function TAdvStringGrid.MapFontSize(Height: Integer): Integer;
begin
  MapFontSize := Trunc(Height*72/254);
end;

procedure AsgPrintBitmap(Canvas:  TCanvas; DestRect:  TRect;  Bitmap:  TBitmap);
var
  BitmapHeader:  pBitmapInfo;
  BitmapImage :  POINTER;
  HeaderSize  :  DWORD;
  ImageSize   :  DWORD;
begin
  GetDIBSizes(Bitmap.Handle, HeaderSize, ImageSize);
  GetMem(BitmapHeader, HeaderSize);
  GetMem(BitmapImage,  ImageSize);
  try
    GetDIB(Bitmap.Handle, Bitmap.Palette, BitmapHeader^, BitmapImage^);
    StretchDIBits(Canvas.Handle,
                  DestRect.Left, DestRect.Top,     // Destination Origin
                  DestRect.Right  - DestRect.Left, // Destination Width
                  DestRect.Bottom - DestRect.Top,  // Destination Height
                  0, 0,                            // Source Origin
                  Bitmap.Width, Bitmap.Height,     // Source Width & Height
                  BitmapImage,
                  TBitmapInfo(BitmapHeader^),
                  DIB_RGB_COLORS,
                  SRCCOPY)
  finally
    FreeMem(BitmapHeader);
    FreeMem(BitmapImage)
  end;
end;

procedure PrintBitmapRop(Canvas:  TCanvas; DesTRect:  TRect;  Bitmap:  TBitmap; rop:dword);
var
  BitmapHeader: PBitmapInfo;
  BitmapImage: Pointer;
  HeaderSize,ImageSize: DWord;

begin
  GetDIBSizes(Bitmap.Handle, HeaderSize, ImageSize);
  GetMem(BitmapHeader, HeaderSize);
  GetMem(BitmapImage,  ImageSize);
  try
    GetDIB(Bitmap.Handle, Bitmap.Palette, BitmapHeader^, BitmapImage^);
    StretchDIBits(Canvas.Handle,
                  DesTRect.Left, DesTRect.Top,     // Destination Origin
                  DesTRect.Right  - DesTRect.Left, // Destination Width
                  DesTRect.Bottom - DesTRect.Top,  // Destination Height
                  0, 0,                            // Source Origin
                  Bitmap.Width, Bitmap.Height,     // Source Width & Height
                  BitmapImage,
                  TBitmapInfo(BitmapHeader^),
                  DIB_RGB_ColORS,
                  ROP)
  finally
    FreeMem(BitmapHeader);
    FreeMem(BitmapImage)
  end;
end;

function AppendWithSpace(s1,s2: string): string;
begin
  if (s1 = '') then
  begin
    Result := s2;
    Exit;
  end;

  if (s2 = '') then
  begin
    Result := s1;
    Exit;
  end;

  Result := s1 + ' ' + s2
end;


//-----------------------------------------
// Routine to build the page on the Canvas
//-----------------------------------------
function TAdvStringGrid.BuildPages(ACanvas: TCanvas; PrintMethod: TPrintMethod; MaxPages: Integer; SelRows: Boolean): Integer;
var
  i,j,m,tw,th,pagnum,pagCol,pagRow: Integer;
  YPosPrint: Integer;
  LastRow: Integer;
  hfntsize,ffntsize: Integer;
  xsize,ysize: Integer;
  spacing: Integer;
  Indent,topIndent,footIndent: Integer;
  AlignValue: TAlignment;
  AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  fntvspace,fnthspace,fntlineHeight: word;
  OldFont,NewFont: TFont;
  OldBrush,NewBrush: TBrush;
  OldPen: TPen;
  TotalWidth: Integer;
  HeaderSize: Integer;
  FooterSize: Integer;
  StartCol,EndCol: Integer;
  SpaceForCols,SpaceForFixedCols: Integer;
  orgsize: Integer;
  repeatCols,multiCol,doprintrow: Boolean;
  forcednewpage: Boolean;
  Allowfittopage: Boolean;
  scalefactor: Double;
  angle: Integer;
  ResFactor,HTMLFactor: Double;
  prevendCol, hhsize: Integer;
  LFont: TLogFont;
  hOldFont,hNewFont: HFont;
  bmp: TBitmap;
  pic: TPicture;
  iconinfo: TIconinfo;
  hdc: THandle;
  cache_Row,cache_Height,hsz: Integer;
  Cancelled: Boolean;
  {$IFDEF TMSUNICODE}
  sz: TSize;
  {$ENDIF}
  es: TGridExportState;
  GD: TCellGradientDirection;
  rhi: integer;

  function IsSelRow(ARow: Integer): Boolean;
  var
    rr: Integer;
  begin
    Result := True;
    if not SelRows then
      Exit;

    if (ARow < FixedRows) and PrintSettings.FixedCellsAlways then
      Exit;

    if MouseActions.DisjunctRowSelect then
    begin
      if FMouseActions.RowSelectPersistent then
        rr := RemapRowInv(ARow)
      else
        rr := ARow;
      Result := RowSelect[rr];
    end
    else
      Result := (ARow >= Selection.Top) and (ARow <= Selection.Bottom);
  end;

  function IsSelCol(ACol: Integer): Boolean;
  begin
    Result := True;

    if not SelRows then
      Exit;

    if MouseActions.DisjunctRowSelect then
      Exit;

    if (ACol < FixedCols) and PrintSettings.FixedCellsAlways then
      Exit;

    if MouseActions.DisjunctColSelect then
      Result := ColSelect[ACol]
    else
      Result := (ACol >= Selection.Left) and (ACol <= Selection.Right);
  end;

  // Get x,y dimensions of Grid cell in Canvas mapmode
  function GetTextSize(Col,Row: Integer): TSize;
  var
    s,su,Anchor,Stripped,FocusAnchor,AnchorHint:string;
    MaxSize,newsize,numlines,OldSize,hl,ml: Integer;
    gt: TPoint;
    r,hr,cr: TRect;
    htmlsize: TPoint;
    ctt: TTextType;
    DrawStyle: DWord;
    HAlign: TAlignment;
    VAlign: TVAlignment;
    WW: Boolean;
    AState: TGridDrawState;
    CID,CV,CT: string;
    {$IFDEF TMSUNICODE}
    ws: widestring;
    {$ENDIF}
    cellww: boolean;
  begin
    if HasDataCell(Col,Row) then
      s := ''
    else
      s := GetFormattedCell(Col,Row);

    ctt := TextType(s,FEnableHTML);

    case ctt of
    ttFormula:
      begin
        s := CalcCell(Col,Row);
      end;
    ttRTF:
      begin
        CellToRich(Col,Row,RichEdit);
        s := RichEdit.Text;
      end;
    {$IFDEF TMSUNICODE}
    ttUnicode:
      begin
        FillChar(r,SizeOf(r),0);

        if PrintSettings.NoAutoSize then
          r.Right := Round((ColWidths[Col] + 4) * resfactor)
        else
          r.Right := $FFFF;

        r.Bottom := $FFFF;

        ws := WideCells[col,row];

        if WordWrap then
        begin
          sz.cy := -DrawTextExW(ACanvas.Handle,PWideChar(ws),Length(ws), r, DT_LEFT or DT_NOPREFIX or DT_WORDBREAK or DT_CALCRECT,nil);
          sz.cx := r.Right - r.Left;
        end
        else
          GetTextExtentPoint32W(ACanvas.Handle,PWideChar(ws),Length(ws),sz);

        s := ws;
        Result.cx := sz.cx;
        Result.cy := sz.cy;
        Exit;
      end;
    {$ENDIF}
    ttHTML:
      begin
        OldFont.Assign(ACanvas.Font);
        NewFont.Assign(ACanvas.Font);
        NewFont.Size := orgsize;

        FillChar(r,SizeOf(r),0);

        if PrintSettings.NoAutoSize then
          r.Right := Round((ColWidths[Col] + 4) * resfactor)
        else
          r.Right := $FFFF;

        r.Bottom := $FFFF;

        Oldsize := ACanvas.Font.Size;
        SetMapMode(ACanvas.Handle,MM_TEXT);
        ACanvas.Font.Size := Trunc(FPrintSettings.Font.Size {* ScaleFactor});

        HTMLDrawEx(ACanvas,s,r,GridImages,0,0,-1,0,1,False,True,False,True,True,False,not EnhTextSize,False,'',
                   ResFactor,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
                   Integer(htmlsize.x),Integer(htmlsize.y),hl,ml,hr,cr,CID,CT,CV,FImageCache,FContainer,self.Handle,BidiMode);

        // Correct it for the new mapping mode
        SetMapMode(ACanvas.Handle,MM_LOMETRIC);
        dptolp(ACanvas.Handle,htmlsize,1);

        ACanvas.Font.Size := Oldsize;

        Result.cx :=  htmlsize.x;
        Result.cy := -htmlsize.y - Round(fntvspace * ResFactor);
        Exit;
      end;
    end;

    OldFont.Assign(ACanvas.Font);
    NewFont.Assign(ACanvas.Font);
    NewFont.Size := orgsize;

    AState := [];

    GetVisualProperties(Col,Row,AState,True,False,False,OldBrush,AColorTo,AMirrorColor,AMirrorColorTo,NewFont,HAlign,VAlign,WW,GD);

    cellww := WordWrap;
    GetCellWordWrap(Col,Row,cellww);

    ACanvas.Font.Assign(NewFont);
    ACanvas.Font.Height := MapFontHeight(NewFont.Size);

    if IsRotated(Col,Row,angle) then
    begin
      GetObject(ACanvas.Font.Handle,SizeOf(LFont),Addr(LFont));
      LFont.lfEscapement := -Angle * 10;
      LFont.lfOrientation := -Angle * 10;
      hNewFont := CreateFontIndirect(LFont);
      hOldFont := SelectObject(ACanvas.Handle,hNewFont);
    end;

    maxsize := 0;
    numlines := 0;

    if FPrintSettings.PrintGraphics then
    begin
      gt := GetCellGraphicSizeEx(ACanvas,Col, Row,0, ResFactor);
      gt.x := Round(gt.x * ResFactor);
      gt.y := Round(gt.y * ResFactor);
    end
    else
      gt := Point(0,0);

    if s = '' then
      s := 'gh';

    if cellww and FPrintSettings.NoAutoSize and not IsRotated(Col,Row,Angle) then
    begin
      r.Top := 0;
      r.Left := 0;

      if IsXMergedCell(Col,Row) then
        r.Right := $FFFF
      else
        r.Right := MaxWidths[DisplColIndex(Col)];

      r.Bottom := 50;
      DrawStyle := DT_CALCRECT or DT_WORDBREAK or DT_NOPREFIX;
      DrawStyle := DrawTextBiDiModeFlags(DrawStyle);
      r.Bottom := DrawText(ACanvas.Handle,PChar(s),Length(s),r,DrawStyle);
      Result.cx := r.Right;
      Result.cy := -r.Bottom;
    end
    else
    begin
      repeat
        su := GetNextLine(s,FMultiLineCells or WordWrap);
        if FURLShow and not FURLFull then StripURLProtoCol(su);
        newsize := ACanvas.TextWidth(su) + gt.x;
        if (newsize > maxsize) then maxsize := newsize;
        inc(numlines);
      until (s = '');

      Result.cx := maxsize;
      Result.cy := numlines * ACanvas.TextHeight('gh');
    end;

    if IsRotated(Col,Row,angle) then
    begin
      Result.cx := Abs(Round(Result.cx * cos(Angle*Pi/180)))+
                   Abs(Round(Result.cy * sin(Angle*Pi/180)));

      Result.cy := Abs(Round(maxsize * sin(Angle*Pi/180)))+
                   Abs(Round(Result.cy * cos(Angle*Pi/180)));
      hNewFont := SelectObject(ACanvas.Handle,hOldFont);
      DeleteObject(hNewFont);
    end;

    if Result.cy < gt.y then
      Result.cy := gt.y;

    if Result.cx < gt.x then
      Result.cx := gt.x;

    ACanvas.Font.Assign(oldFont);

    if Assigned(FOnCustomCellSize) then
    begin
      FOnCustomCellSize(Self,ACanvas,Col,Row,TPoint(Result),True);
    end;
  end;

  //Calculate required Column Widths for all Columns
  procedure CalculateWidths;
  var
    i,j,k: Integer;
  begin
    for j := FPrintRect.Left to FPrintRect.Right do
      MaxWidths[j] := 0;

    if FPrintSettings.NoAutoSize then
      for j := FPrintRect.Left to FPrintRect.Right do
      begin
        if IsSelCol(j) then
          MaxWidths[j] := Round((ColWidths[j] + 4) * ResFactor);
      end
    else
    begin
      i := 0;
      while (i <= FPrintRect.Bottom) or
            (FPrintSettings.RepeatFixedRows and (i <= FixedRows)) do
      begin
        if (i < FPrintRect.Top) and ((not FPrintSettings.RepeatFixedRows) or
           (i >= FixedRows)) then
        begin
           i := FPrintRect.Top;
           Continue;
        end;
        for j := FPrintRect.Left to FPrintRect.Right do
        begin
          if IsSelCol(j) then
          begin
            k := RemapCol(j);
            if FPrintSettings.FUseFixedWidth then
              tw := FPrintSettings.FFixedWidth
            else
              tw := GetTextSize(k,i).cx;

            if (tw > MaxWidths[j]) and not IsXMergedCell(k,i) then
              MaxWidths[j] := tw;
          end;
        end;
        Inc(i);
      end;

      {
      for i := FPrintRect.Top to FPrintRect.Bottom do
      begin
        for j := FPrintRect.Left to FPrintRect.Right do
        begin
          if IsSelCol(j) then
          begin
            k := RemapCol(j);
            if FPrintSettings.FUseFixedWidth then
              tw := FPrintSettings.FFixedWidth
            else
              tw := GetTextSize(k,i).cx;

            if (tw > MaxWidths[j]) and not IsXMergedCell(k,i) then
              MaxWidths[j] := tw;
          end;
        end;
      end;
      }
    end;
  end;


  //Calculate required Row Height
  function GetRowHeight(ARow: Integer): Integer;
  var
    j,k,nh,mh: Integer;
  begin
    mh := 0;

    if ARow = Cache_Row then
    begin
      Result := Cache_Height;
      Exit;
    end;

    if FPrintSettings.NoAutoSizeRow then
    begin
      Result := Round((RowHeights[ARow]) * ResFactor) + 4 {- 4};
      Exit;
    end;

    if FPrintSettings.UseFixedHeight then
      Result := FPrintSettings.FixedHeight
    else
    begin
      nh := 0;
      for j := FPrintRect.Left to FPrintRect.Right do
      begin
        if not FPrintSettings.NoAutoSizeRow then
          FontScaleFactor := ScaleFactor
        else
          FontScaleFactor := 1;

        k := RemapCol(j);
        nh := GetTextSize(k,ARow).cy;

        if not IsYMergedCell(k,ARow) then
        begin
          if nh > mh then mh := nh;
        end;
      end;

      if mh = 0 then
        Result := nh
      else
        Result := mh;

      Result := Result + Result shr 3;

      if Assigned(FOnPrintSetRowHeight) then
      begin
        OnPrintSetRowHeight(Self,ARow,Result);
      end;
    end;

    cache_Row := ARow;
    cache_Height := Result;
  end;

  function GetPrinterOrientation: Integer;
  var
    Device : array[0..255] of char;
    Driver : array[0..255] of char;
    Port : array[0..255] of char;
    hDMode : THandle;
  begin
    Printer.GetPrinter(Device, Driver, Port, hDMode);
    Result := winspool.DeviceCapabilities(Device,Port,DC_ORIENTATION,Nil,Nil);
  end;

  // Routine to draw header & footer
  function BuildColumnsRow(ypos,Col1,Col2,ARow,hght: Integer): Integer;
  var
    c,k,d,cn,lit: Integer;
    th,thm,tb,ml,hl,i,di: Integer;
    s,su,cs,Anchor,Stripped,FocusAnchor,AnchorHint: string;
    tr,tp,rg,ir,hr,ctr: TRect;
    first: Integer;
    x1,x2,y1,y2: Integer;
    cg: TCellGraphic;
    borders: TCellBorders;
    DrawStyle: DWORD;
    checkstate: Boolean;
    mm,hxsize,hysize,OldSize: Integer;
    ctt: TTextType;
    oldCol: TColor;
    CSP: TPoint;
    CDIM: TPoint;
    CGS: TPoint;
    DFS: DWORD;
    AState: TGridDrawState;
    WW: Boolean;
    HAlign: TAlignment;
    VAlign: TVAlignment;
    CID,CV,CT: string;
    {$IFDEF TMSUNICODE}
    ws: widestring;
    {$ENDIF}
    io: TInterfacedPersistent;
    icg: ICellGraphic;
    bpw: integer;
    bpc: TColor;
    tro: TRect;
    rottext: boolean;
    cellww: boolean;
    fntsize: integer;

  label
    BorderDrawing;

  begin
    if not FPrintSettings.NoAutoSizeRow then
      FontScaleFactor := ScaleFactor
    else
      FontScaleFactor := 1;

    thm := GetRowHeight(ARow);

    //thm := thm + (thm shr 3);

    Result := thm + 2 * fntvspace + FPrintSettings.RowSpacing;

    if (PrintMethod in [prCalcPreview,prCalcPrint]) or
       (((pagnum + 1) < FPrintPageFrom) or ((pagnum + 1) > FPrintPageTo)) then
    begin
      Fontscalefactor := 1.0;
      Exit;
    end;

    for c := Col1 to Col2 do
    begin
      if not IsSelCol(c) then
        Continue;

      cn := RemapCol(c);

      CSP := CellExt(cn,ARow);

      CDIM.X := 0;

      for k := 0 to CSP.X   do
        CDIM.X := CDIM.X + MaxWidths[c + k] + Spacing;

      if PrintSettings.NoAutoSizeRow then
      begin
        CDIM.Y := 0;
        if CSP.Y = 0 then
          CDIM.Y := Result
        else
          for i := ARow to ARow + CSP.Y do
          begin
            di := Round((RowHeights[ARow]) * ResFactor) - 4;
            CDIM.Y := CDIM.Y + di +  2 * fntvspace + FPrintSettings.RowSpacing;
          end;
      end
      else
      begin
        CDIM.Y := Result;
        for i := ARow + 1 to ARow + CSP.Y do
        begin
          CDIM.Y := CDIM.Y + result;
        end;
        //CDIM.Y := (CSP.Y + 1) * Result; // take vertical cell merging into account
      end;

      tr.Left := Indents[c];
      tr.Right := tr.Left + CDIM.X;

      tr.Top := ypos;
      tr.Bottom := ypos - CDIM.Y;

      OldPen.Assign(ACanvas.Pen);
      borders := [];

      if (FPrintSettings.Borders in [pbSingle, pbDouble]) then
        borders := [cbLeft, cbRight, cbTop, cbBottom];

      if (FPrintSettings.Borders in [pbHorizontal,pbAroundHorizontal]) then
        borders := [cbTop, cbBottom];

      if (FPrintSettings.Borders in [pbVertical,pbAroundVertical]) then
        borders := [cbLeft, cbRight];

      ACanvas.Pen.Width := 1;
      ACanvas.Pen.Color := FPrintSettings.BorderColor;

      GetCellPrintBorder(cn,ARow,ACanvas.Pen,borders);

      bpw := ACanvas.Pen.Width;
      bpc := ACanvas.Pen.Color;

      if not IsBaseCell(cn,ARow) then
      begin
        goto BorderDrawing;
        // Continue;
        // do some extra border drawing here
      end;

      OldBrush.Assign(ACanvas.Brush);
      OldFont.Assign(ACanvas.Font);
      NewBrush.Assign(ACanvas.Brush);

      NewFont.Assign(ACanvas.Font); // Copy everything except size, which is mapped into mm_lometric
      NewFont.Size := OrgSize;
      NewBrush.Style := bsSolid;

      GetVisualProperties(cn,ARow,AState,True,False,False,NewBrush,AColorTo,AMirrorColor,AMirrorColorTo,NewFont,HAlign,VAlign,WW,GD);

      fntsize := NewFont.Size;

      ACanvas.Brush.Assign(NewBrush);
      ACanvas.Font.Assign(NewFont);
      ACanvas.Font.Height := MapFontHeight(NewFont.Size);

      SetTextColor(ACanvas.Handle,ColorToRGB(NewFont.Color));

      cellww := WordWrap;
      GetCellWordWrap(cn,ARow,cellww);

      if HasDataCell(cn,ARow) then
        cs := ''
      else
        cs := GetFormattedCell(cn,ARow);

      ctt := TextType(cs,FEnableHTML);

      if ctt = ttFormula then
        cs := CalcCell(cn,ARow);

      if IsPassword(cn,ARow) then
        StringToPassword(cs,PasswordChar);

      tro := tr;

      if not (cbLeft in Borders) then
        tr.Left := tr.Left + ACanvas.Pen.Width * 2;

      if not (cbTop in Borders) then
        tr.Top := tr.Top - ACanvas.Pen.Width * 2;

      // do background painting
      OldCol := ACanvas.Pen.Color;
      ACanvas.Pen.Color := ACanvas.Brush.Color;
      AdvUtil.DrawGradient(ACanvas, AColorTo, ACanvas.Brush.Color, 64, tr, false);

      tr := tro;

      ACanvas.Pen.Color := OldCol;

      AlignValue := GetCellAlignment(cn,ARow).Alignment;

      th := ACanvas.TextHeight('gh') + FPrintSettings.RowSpacing;
      th := th + (th shr 3);

      first := 0;
      s := cs;

      repeat
        su := GetNextLine(s,FMultiLineCells or WordWrap);
        tb := ACanvas.TextWidth(su);
        if tb > first then
          first := tb;
      until (s = '');

      tb := first;

      s := cs;

      Angle := 0;
      rottext := IsRotated(cn,ARow,angle);

      if rottext then
      begin
        GetObject(ACanvas.Font.Handle,SizeOf(LFont),Addr(LFont));
        if (PrintMethod = prPreview) or not PrinterDriverFix
           or (GetPrinterOrientation = 270) then
        begin
          LFont.lfEscapement := -Angle * 10;
          LFont.lfOrientation := -Angle * 10;
        end
        else
        begin
          LFont.lfEscapement := Angle * 10;
          LFont.lfOrientation := Angle * 10;
        end;

        hNewFont := CreateFontIndirect(LFont);
        hOldFont := SelectObject(ACanvas.Handle,hNewFont);
      end;

      x1 := Abs(Trunc(tb * cos(Angle * Pi/180)));
      x2 := Abs(Trunc(th * sin(Angle * Pi/180)));
      y1 := Abs(Trunc(tb * sin(Angle * Pi/180)));
      y2 := Abs(Trunc(th * cos(Angle * Pi/180)));
      th := y1 + y2;

      first := fntvspace;

      tr.Left := Indents[c];
      tr.Right := tr.Left + CDIM.X;

      tr.Top := ypos;
      tr.Bottom := ypos - CDIM.Y;

      cg := CellGraphics[cn,ARow];

      if (cg <> nil) and FPrintSettings.PrintGraphics then
      begin
        CGS := GetPrintGraphicSize(cn,ARow,CDIM.X,CDIM.Y,ResFactor);

        if not ((cg.CellType in [ctFilePicture,ctInterface,ctPicture,ctBitmap]) and (cg.CellAngle <> Integer(noStretch))) then
        begin
          CGS.X := Round(CGS.X * ResFactor);
          CGS.Y := Round(CGS.Y * ResFactor);
        end;

        // do not print actual cell text for a radiobutton cell
        if cg.CellType = ctRadio then
          s := '';

        case cg.CellHalign of
        haBeforeText:
          begin
            rg.Left := tr.Left + Round(ResFactor);
            rg.Right := rg.Left + CGS.X;
            tr.Left := rg.Right;
          end;
        haLeft:
          begin
            rg.Left := tr.Left + Round(ResFactor);
            rg.Right := rg.Left + CGS.X;
            tr.Left := rg.Right;
          end;
        haAfterText:
          begin
            rg.Right := tr.Right;
            rg.Left := rg.Right - CGS.X;
            tr.Right := rg.Left;
          end;
        haRight:
          begin
            rg.Right := tr.Right;
            rg.Left := rg.Right - CGS.X;
            tr.Right := rg.Left;
          end;
        haCenter:
          begin
            rg.Left := tr.Left + ((CDIM.X - CGS.X ) div 2);
            rg.Right := rg.Left + CGS.X;
          end;
        haFull:
          begin
            rg.Left := tr.Left;
            rg.Right := tr.Right;
          end;
        end;

        case cg.CellValign of
        vaTop:
          begin
            rg.Top := tr.Top;
            rg.Bottom := tr.Top - CGS.Y;
          end;
        vaCenter:
          begin
            rg.Top := tr.Top - ((CDIM.Y - CGS.Y) div 2);
            rg.Bottom := rg.Top - CGS.Y;
          end;
        vaBottom:
          begin
            rg.Top := tr.Bottom + CGS.Y;
            rg.Bottom := tr.Bottom;
          end;
        vaUnderText:
          begin
            rg.Top := tr.Bottom + CGS.Y;
            rg.Bottom := rg.Top - CGS.Y;
            tr.Bottom := rg.Top;
          end;
        vaAboveText:
          begin
            rg.Top := tr.Top;
            rg.Bottom := rg.Top - CGS.Y;
            tr.Top := rg.Bottom;
          end;
        vaFull:
          begin
            rg.Top := tr.Top;
            rg.Bottom := tr.Bottom;
          end;
        end;


        if (HAlign = taRightJustify) and
           (cg.CellType in [ctCheckbox, ctDataCheckbox,ctVirtCheckBox,ctRowCheckBox,ctRadioButton]) and (s = '')  then
        begin
          rg.Right := tr.Right;
          rg.Left := rg.Right - CGS.X;
          tr.Right := rg.Left;
        end;

        if (HAlign = taCenter) and
           (cg.CellType in [ctCheckbox, ctDataCheckbox,ctVirtCheckBox,ctRowCheckBox,ctRadioButton]) and (s = '') then
        begin
          rg.Left := Indents[c] + ((CDIM.X - CGS.X ) div 2);
          rg.Right := rg.Left + CGS.X;
        end;
      end;

      // draw text transparent
      ACanvas.Brush.Style := bsClear;

      case ctt of
      ttRTF:
        begin
          RTFPaint(cn,ARow,ACanvas,tr);
        end;
      ttHTML:
        begin
          lptodp(ACanvas.Handle,tr.Topleft,1);
          lptodp(ACanvas.Handle,tr.Bottomright,1);

          mm := GetMapMode(ACanvas.Handle);
          OldSize := ACanvas.Font.Size;
          SetMapMode(ACanvas.Handle,MM_TEXT);
          //Canvas.Font.Size := Trunc(FPrintSettings.Font.Size * ScaleFactor);
          ACanvas.Font.Size := Trunc(fntsize * ScaleFactor);

          tr.Right := tr.Right - fnthspace - Round(2 * ResFactor);
          //tr.Top := tr.Top - Round(fntvspace * ResFactor);

          tr.Bottom := tr.Bottom + Round(fntvspace * ResFactor);

          HTMLDrawEx(ACanvas,cs,tr,Gridimages,0,0,-1,0,1, False,False,True,False,True,False,not EnhTextSize,False,'',
                     HTMLFactor,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
                     hxsize,hysize,hl,ml,hr,ctr,CID,CT,CV, FImageCache, FContainer, Handle, BidiMode);

          SetMapMode(ACanvas.Handle,mm);
          ACanvas.Font.Size := Oldsize;
        end;
      {$IFDEF TMSUNICODE}
      ttUnicode:
        begin
          if tr.Right > XSize then
            tr.Right := Indents[EndCol + 1];

          ACanvas.TextRect(tr,tp.Left,tp.Top,'');

          tr.Left := tr.Left + Round(2 * ResFactor);

          ws := WideCells[cn,ARow];

          case AlignValue of
          taRightJustify: DrawStyle := DT_RIGHT or DT_NOPREFIX;
          taCenter: DrawStyle := DT_CENTER or DT_NOPREFIX;
          else
            DrawStyle := DT_LEFT or DT_NOPREFIX;
          end;

          if cellww then
            DrawStyle := DrawStyle or DT_WORDBREAK;

          if Win32Platform = VER_PLATFORM_WIN32_NT then
            DrawTextExW(ACanvas.Handle,PWideChar(ws),Length(ws), tr, DrawStyle,nil)
          else
            ExtTextOutW(ACanvas.Handle,tr.Left,tr.Top,ETO_CLIPPED,@tr,PWideChar(ws),Length(ws),nil);
        end
      {$ENDIF}
      else
        begin
          // wordwrap printing
          if cellww and FPrintSettings.NoAutoSize and not rottext then
          begin
            // Make sure the background is fully drawn in background color
            if tr.Right > XSize then
              tr.Right := Indents[EndCol + 1];

            ACanvas.TextRect(tr,tp.Left,tp.Top,'');

            tr.Left := tr.Left + Round(2 {* ResFactor});

            DrawStyle := DT_LEFT;

            tp := tr;
            case AlignValue of
            taLeftJustify:
              begin
                tp.Left := tr.Left + fnthspace;
                DrawStyle := DT_LEFT;
              end;
            taRightJustify:
              begin
                tp.Left := tr.Left;
                tp.Right := tr.Right - fnthspace;
                DrawStyle := DT_RIGHT;
              end;
            taCenter:
              begin
                tp.Left := tr.Left + fnthspace;
                tp.Right := tr.Right - fnthspace;
                DrawStyle := DT_CENTER;
              end;
            end;

            DrawStyle := DrawStyle or DT_WORDBREAK or DT_EDITCONTROL or DT_EXPANDTABS or DT_NOPREFIX;
            DrawStyle := DrawTextBiDiModeFlags(DrawStyle);
            DrawText(ACanvas.Handle,PChar(s),Length(s),tp,DrawStyle);
          end
          else
          begin
            lit := LinesInText(s,FMultiLineCells);

            if (lit = 1) or (Angle = 90) then
            begin
              tp := tr;
              tp.Bottom := tp.Top - Result - FPrintSettings.RowSpacing;

              if tr.Right > XSize then
                tr.Right := Indents[EndCol + 1];

              su := GetNextLine(s,FMultiLineCells);

              if URLShow and not URLFull then
                StripURLProtoCol(su);

              if (Angle <> 0) then
              begin
                if IsYMergedCell(cn,ARow) then
                  tp.Bottom := tp.Bottom - ((CellSpan(cn,ARow).Y) * (Result + FPrintSettings.RowSpacing));

                if IsXMergedCell(cn,ARow) then
                  tp.Right := Indents[ cn + CellSpan(cn,Row).X];

                InflateRect(tp, 0, fnthspace);

                PositionText(tp,AlignValue,VAlign,Angle,x1,x2,-y1,-y2);
              end;

              if EnhTextSize and PrintSettings.NoAutoSize then
              begin
                case AlignValue of
                taRightJustify: DrawStyle := DT_RIGHT or DT_END_ELLIPSIS or DT_SINGLELINE or DT_EDITCONTROL or DT_NOPREFIX;
                taCenter: DrawStyle := DT_CENTER or DT_END_ELLIPSIS or DT_SINGLELINE or DT_EDITCONTROL or DT_NOPREFIX;
                else
                  DrawStyle := DT_LEFT or DT_END_ELLIPSIS or DT_SINGLELINE or DT_EDITCONTROL or DT_NOPREFIX;
                end;

                if angle <> 0 then
                begin
                  ACanvas.TextRect(tr,tp.Left,tp.Top,su);
                end
                else
                begin
                  tr.Left := tr.Left + FXYOffset.X;
                  tr.Top := tp.Top + FXYOffset.Y;

                  DrawText(ACanvas.Handle,PChar(su),Length(su),tr,DrawStyle);
                end;
              end
              else
              begin
                if angle <> 0 then
                begin
                  //tp := tr;
                  ACanvas.TextRect(tr,tp.Left,tp.Top,su);

                  s := cs;

                  //print multiline text when angle is 90
                  if (Angle = 90) and (LinesInText(s, MultiLineCells or WordWrap) > 1) then
                  begin
                    su := GetNextLine(s,true);
                    su := GetNextLine(s,true);

                    th := ACanvas.TextHeight('gh');

                    while (su <> '') do
                    begin
                      tr.Left := tr.Left + th;
                      tr.Right := tr.Right + th;
                      tp.Left := tp.Left + th;

                      ACanvas.TextRect(tr,tp.Left,tp.Top,su);
                      su := GetNextLine(s,true);
                    end;
                  end;
                end
                else
                begin
                  DrawStyle := 0;

                  case AlignValue of
                  taLeftJustify:
                    begin
                      tp.Left := tr.Left + fnthspace;
                      DrawStyle := DT_LEFT or DT_SINGLELINE or DT_EDITCONTROL or DT_NOPREFIX;
                    end;
                  taRightJustify:
                    begin
                      tp.Left := tr.Left;
                      tp.Right := tr.Right - fnthspace;
                      DrawStyle := DT_RIGHT or DT_SINGLELINE or DT_EDITCONTROL or DT_NOPREFIX;
                    end;
                  taCenter:
                    begin
                      tp.Left := tr.Left + fnthspace;
                      tp.Right := tr.Right - fnthspace;
                      DrawStyle := DT_CENTER or DT_SINGLELINE or DT_EDITCONTROL or DT_NOPREFIX;
                    end;
                  end;

                  case Valign of
                  vtaCenter: DrawStyle := DrawStyle + DT_VCENTER;
                  vtaBottom: DrawStyle := DrawStyle + DT_BOTTOM;
                  end;

                  if IsYMergedCell(cn,ARow) then
                    tp.Bottom := tp.Bottom - ((CellSpan(cn,ARow).Y) * (Result + FPrintSettings.RowSpacing));

                  if IsXMergedCell(cn,ARow) then
                    tp.Right := Indents[ cn + CellSpan(cn,ARow).X + 1];

                  tp.Top := tp.Top - fntvspace;
                  DrawText(ACanvas.Handle,PChar(su),Length(su),tp,DrawStyle);
                end;
              end;
            end
            else
            begin
              case Valign of
              vtaTop:First := 0;
              vtaCenter:First := ((Result - ((th - FPrintSettings.RowSpacing) * lit)) div 2);
              vtaBottom:First := Result - ((th - FPrintSettings.RowSpacing) * lit);
              end;

              if IsMergedCell(cn,ARow) then
                First := 0;

              repeat
                tp := tr;
                su := GetNextLine(s,FMultiLineCells);

                if URLShow and not URLFull then StripURLProtoCol(su);
                case AlignValue of
                taLeftJustify:tp.Left := tp.Left + fnthspace;
                taRightJustify:tp.Left := tp.Right - fnthspace - ACanvas.TextWidth(su);
                taCenter:tp.Left := tp.Left+( (tp.Right - tp.Left - ACanvas.TextWidth(su)) div 2);
                end;

                ACanvas.TextRect(tr,tp.Left + FXYOffset.X,tr.Top - First - fntvspace,su);

                if first > 0 then
                begin
                  tr.Top := tr.Top - First;
                  first := 0;
                end;
                tr.Top := tr.Top - th + FPrintSettings.RowSpacing;
              until (s = '');
            end;
          end;
        end;
      end;

      ACanvas.Brush.Style := bsSolid;

      if (cg <> nil) and FPrintSettings.PrintGraphics then
      begin
        case cg.CellType of
        ctCheckbox,ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox:
          begin
            DFS := DFCS_BUTTONCHECK;
            if FControlLook.ControlStyle = csFlat then
              DFS := DFS or DFCS_FLAT;

            rg.Bottom := rg.Top + Round(CellGraphicSize[cn,ARow].y * ResFactor);

            OffsetRect(rg,0,Round(-XYOffset.Y * ResFactor));

            GetCheckBoxState(cn,ARow,checkstate);
            if checkstate then
              DrawFrameControl(ACanvas.Handle,rg,DFC_BUTTON, DFS or DFCS_CHECKED)
            else
              DrawFrameControl(ACanvas.Handle,rg,DFC_BUTTON, DFS);
          end;
        ctRadioButton:
          begin
            DFS := DFCS_BUTTONRADIO;
            if FControlLook.ControlStyle = csFlat then
              DFS := DFS or DFCS_FLAT;

            rg.Bottom := rg.Top + Round(CellGraphicSize[cn,ARow].y * ResFactor);

            OffsetRect(rg,0,Round(-XYOffset.Y * ResFactor));

            if IsRadioButtonChecked(cn, ARow) then
              DrawFrameControl(ACanvas.Handle,rg,DFC_BUTTON, DFS or DFCS_CHECKED)
            else
              DrawFrameControl(ACanvas.Handle,rg,DFC_BUTTON, DFS);
          end;

        ctRadio:
          begin
            rg.Bottom := rg.Top + Round(CellGraphicSize[cn,ARow].y * ResFactor);

            OffsetRect(rg,0,Round(-XYOffset.Y * ResFactor));

            DrawRadio(ACanvas, rg, GetRadioStrings(cn,ARow).Count,cg.CellIndex,cg.cellBoolean, false,
                      TStringList(cg.cellbitmap), false, cn, ARow, csClassic, ResFactor, true);
          end;
        ctButton,ctBitButton:
          begin
            rg.Bottom := rg.Top + Round(CellGraphicSize[cn,ARow].y * ResFactor);

            bmp := TBitmap.Create;
            bmp.Width := rg.Right - rg.Left;
            bmp.Height := rg.Bottom - rg.Top;

            DrawFrameControl(bmp.Canvas.Handle,Rect(0,0,bmp.Width,bmp.Height),DFC_BUTTON,DFCS_BUTTONPUSH);
            ACanvas.Draw(rg.left, rg.Top - bmp.Height, bmp);
            ACanvas.Brush.Style := bsClear;
            ACanvas.TextOut(rg.Left, rg.Top , cg.CellText);
            ACanvas.Brush.Style := bsSolid;
            bmp.Free;
          end;
        ctBitmap: AsgPrintBitmap(ACanvas,rg,cg.CellBitmap);
        ctNone:
          begin
            if (cg.CellComment <> '') and PrintSettings.PrintComments then
            begin
              // draw corner
              ACanvas.Brush.Color := clRed;
              ACanvas.Brush.Style := bsSolid;
              ACanvas.Polygon([Point(tr.Right- Round(8 * ResFactor),rg.Top), Point(tr.Right,rg.Top), Point(tr.Right, rg.Top-Round(8 * ResFactor))])
            end;
          end;
        ctNode:
          begin
            hxsize := Round(20);
            hysize := Round(20);

            ACanvas.Pen.Color := FCellNode.NodeColor;

            ACanvas.Rectangle(rg.Left + (rg.Right - rg.Left - hxSize) div 2,rg.Top - (rg.Top - rg.Bottom - hysize) div 2,rg.Left + (rg.Right - rg.Left - hxSize) div 2 + hxsize,rg.Top - (rg.Top - rg.Bottom - hysize) div 2 - hysize);

            if cg.CellBoolean then
            begin
              ACanvas.MoveTo(rg.Left + (rg.Right - rg.Left - hxSize) div 2, rg.Top - (rg.Top - rg.Bottom) div 2);
              ACanvas.LineTo(rg.Left + (rg.Right - rg.Left - hxSize) div 2 + hxsize - 2,rg.Top - (rg.Top - rg.Bottom) div 2);

              ACanvas.MoveTo(rg.Left + (rg.Right - rg.Left) div 2, rg.Top - (rg.Top - rg.Bottom - hysize) div 2);
              ACanvas.LineTo(rg.Left + (rg.Right - rg.Left) div 2, rg.Top - (rg.Top - rg.Bottom - hysize) div 2 - hysize + 2);
            end
            else
            begin
              ACanvas.MoveTo(rg.Left + (rg.Right - rg.Left - hxSize) div 2, rg.Top - (rg.Top - rg.Bottom) div 2);
              ACanvas.LineTo(rg.Left + (rg.Right - rg.Left - hxSize) div 2 + hxsize - 2,rg.Top - (rg.Top - rg.Bottom) div 2);
            end;

          end;
        ctInterface:
          begin
            io := TInterfacedPersistent(cg.CellBitmap);
            if io.GetInterface(ICellGraphic, icg) then
            begin
              bmp := TBitmap.Create;

              ml := icg.CellWidth;
              hl := icg.CellHeight;

              if (ml = 0) or (hl = 0) then
              begin

                if (ml = 0) then
                  ml := rg.Right - rg.Left;

                if (hl = 0) then
                  hl := rg.Bottom - rg.Top;
              end;

              if hl <  0 then
                hl := -hl;

              bmp.Width := ml;
              bmp.Height := hl;

              icg.Draw(bmp.Canvas, Rect(0,0, ml-1, hl - 1), cn, ARow, false, self);
              AsgPrintBitmap(ACanvas,rg,bmp);

              bmp.free;
            end;
          end;
        ctShape:
          begin
            OffsetRect(rg, 0, Round(-XYOffset.Y * ResFactor));
            DrawShape(ACanvas, rg.Right, rg.Top, rg.Right - rg.Left - 1, rg.Bottom - rg.Top - 1 + Round(4 * ResFactor), TCellShape(cg.CellAngle), TColor(cg.CellIndex), TColor(cg.CellBitmap));
          end;
        ctPicture:
          begin
            bmp := TBitmap.Create;
            bmp.PixelFormat := pf24bit;
            bmp.Width := TPicture(cg.CellBitmap).Graphic.Width;
            bmp.Height := TPicture(cg.CellBitmap).Graphic.Height;

            if AColorTo <> clNone then
              DrawGradient(bmp.Canvas,NewBrush.Color, AColorTo, 128, Rect(0,0,bmp.Width, bmp.Height),FBackground.Display = bdGradientHorz)
            else
              DrawGradient(bmp.Canvas,NewBrush.Color, NewBrush.Color, 128, Rect(0,0,bmp.Width, bmp.Height),FBackground.Display = bdGradientHorz);

            bmp.Canvas.Draw(0,0,TPicture(cg.CellBitmap).Graphic);
            ACanvas.StretchDraw(rg,bmp);
            bmp.free;
          end;
        ctFilePicture:
          begin
            if FileExists(TFilePicture(cg.CellBitmap).Filename) then
            begin
              pic := TPicture.Create;
              pic.LoadFromFile(TFilePicture(cg.CellBitmap).Filename);
              bmp := TBitmap.Create;
              bmp.PixelFormat := pf24bit;
              bmp.Width := pic.Graphic.Width;
              bmp.Height := pic.Graphic.Height;
              bmp.Canvas.Draw(0,0,pic.graphic);
              ACanvas.StretchDraw(rg,bmp);
              // AsgPrintBitmap(Canvas,rg,bmp);
              bmp.Free;
              pic.Free;
            end;
          end;
        ctIcon:
          begin
            GetIconInfo(cg.CellIcon.Handle,IconInfo);
            bmp := TBitmap.Create;
            bmp.Handle := Iconinfo.hbmmask;
            PrintBitmapRop(ACanvas,rg,bmp,SRCCOPY);
            bmp.Free;
            GetIconInfo(cg.CellIcon.Handle,IconInfo);
            bmp := TBitmap.Create;
            bmp.Handle := IconInfo.hbmColor;
            PrintBitmapROP(ACanvas,rg,bmp,SRCINVERT);
            bmp.Free;
          end;
        ctImageList:
          begin
            if Assigned(FGridImages) then
            begin
              bmp := TBitmap.Create;
              bmp.Width := FGridImages.Width;
              bmp.Height := FGridImages.Height;
              bmp.Canvas.Brush.Color := Canvas.Brush.Color;
              bmp.Canvas.Pen.Color := Canvas.Brush.Color;
              bmp.Canvas.Rectangle(0,0,bmp.Width,bmp.Height);
              FGridImages.Draw(bmp.Canvas,0,0,cg.CellIndex);
              AsgPrintBitmap(ACanvas,rg,bmp);
              bmp.free;
            end;
          end;
        ctDataImage:
          begin
            if Assigned(FGridImages) then
            begin
              bmp := TBitmap.Create;
              bmp.Width := FGridImages.Width;
              bmp.Height := FGridImages.Height;
              bmp.Canvas.Brush.Color := Canvas.Brush.Color;
              bmp.Canvas.Pen.Color := Canvas.Brush.Color;
              bmp.Canvas.Rectangle(0,0,bmp.Width,bmp.Height);
              FGridImages.Draw(bmp.Canvas,0,0,Ints[cn,ARow]);
              AsgPrintBitmap(ACanvas,rg,bmp);
              bmp.free;
            end;
          end;
        ctImages:
          begin
            if Assigned(FGridImages) then
            begin
              ir := rg;
              for d := 1 to CellImages[c,ARow].Count do
              begin
                bmp := TBitmap.Create;

                bmp.Width := FGridImages.Width;
                bmp.Height := FGridImages.Height;
                bmp.Canvas.Brush.Color := ACanvas.Brush.Color;
                bmp.Canvas.Pen.Color := ACanvas.Brush.Color;
                bmp.Canvas.Rectangle(0,0,bmp.Width,bmp.Height);
                FGridImages.Draw(bmp.Canvas,0,0,TIntList(cg.CellBitmap).Items[d - 1]);

                if cg.cellBoolean then
                begin
                  ir.Left := rg.Left + (d - 1) * Round(FGridimages.Width * ResFactor);
                  ir.Right := ir.Left + Round(FGridimages.Width*ResFactor);
                end
                else
                begin
                  ir.Top := rg.Top + (d - 1) * Round(FGridimages.Height * ResFactor);
                  ir.Bottom := ir.Top + Round(FGridimages.Height * ResFactor);
                end;

                AsgPrintBitmap(ACanvas,ir,bmp);
                bmp.Free;
              end;
            end;
          end;
        ctProgress:
          begin
            rg.Top := rg.Top - Round(2 * ResFactor);
            rg.Bottom := rg.Bottom + Round(4 * ResFactor);
            rg.Right := tr.Right;

            with cg do
              if CellBoolean then
                DrawProgressLin(ACanvas,rg,TColor(CellBitmap),TColor(CellIndex),
                  TColor(CellIcon),TColor(CellAngle),Ints[c,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor,true)
              else
                DrawProgressLin(ACanvas,rg,TColor(CellBitmap),TColor(CellBitmap) xor $FFFFFF,
                  TColor(CellIcon),TColor(CellIcon) xor $FFFFFF,Ints[c,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor, true);

            ACanvas.Pen.Color := clBlack;
          end;
        ctProgressPie:
          begin
            DrawProgressPie(ACanvas,rg,TColor(cg.CellBitmap),cg.CellAngle, true);
          end;
        end;

        if IsRotated(cn,ARow,angle) then
        begin
          hNewFont := SelectObject(ACanvas.Handle,hOldFont);
          DeleteObject(hNewFont);
        end;

        Canvas.Font.Assign(oldFont);
        Canvas.Brush.Assign(oldBrush);
      end;

      if Assigned(OnCustomCellDraw) then
      begin
        tr.Bottom := ypos - Result;
        tr.Top := ypos;

        lptodp(ACanvas.Handle,tr.TopLeft,1);
        lptodp(ACanvas.Handle,tr.BottomRight,1);

        mm := GetMapMode(ACanvas.Handle);
        OldSize := ACanvas.Font.Size;
        SetMapMode(ACanvas.Handle,MM_TEXT);
        ACanvas.Font.Size := FPrintSettings.Font.size;

        OnCustomCellDraw(Self,ACanvas,cn,ARow,[],tr,true);

        SetMapMode(ACanvas.Handle,mm);
        Canvas.Font.Size := Oldsize;
      end;

    BorderDrawing:

      ACanvas.Pen.Width := bpw;
      ACanvas.Pen.Color := bpc;

      if not IsBaseCell(cn, ARow) then
      begin
        if  CSP.X >= 0 then
          borders := borders - [cbLeft, cbRight];

        if  CSP.Y >= 0 then
          borders := borders - [cbTop, cbBottom];
      end;

      //if IsBaseCell(cn,ARow) and (FPrintSettings.Borders in [pbSingle,pbDouble]) then
      //  borders := borders + [cbLeft, cbTop];

      {
      if IsYMergedCell(cn,ARow) and not IsXMergedCell(cn,ARow) and not IsBaseCell(cn,ARow) then
      begin
        borders := borders - [cbTop,cbBottom];
      end;

      if IsXMergedCell(cn,ARow) and not IsYMergedCell(cn,ARow) and not IsBaseCell(cn,ARow) then
      begin
        borders := borders - [cbLeft,cbRight];
      end;
      }

      if IsYMergedCell(cn,ARow) and (CSP.Y = 0) then
        borders := borders - [cbTop];

      if IsXMergedCell(cn,ARow) and (CSP.X = 0) then
        borders := borders - [cbLeft];

      // adapt pen width for printout

      //if PrintMethod = prPreview then
        ACanvas.Pen.Width := ACanvas.Pen.Width;
      //else
      //  ACanvas.Pen.Width := round(ACanvas.Pen.Width * resfactor);

      tr.Left := Indents[c];
      tr.Right := tr.Left + CDIM.X;

      tr.Top := ypos;
      tr.Bottom := ypos - CDIM.Y;

      if tr.Bottom < YSize + FooterSize then
      begin
        tr.Bottom := ypos - Result;
        borders := borders - [cbBottom];
      end;

      if tr.Right > XSize then
      begin
        tr.Right := Indents[EndCol + 1];
      end;


      if (cbLeft in borders) then
      begin
        if (cn > Col1) then
        begin
          ACanvas.MoveTo(tr.Left - ACanvas.Pen.Width,tr.Top);
          ACanvas.LineTo(tr.Left - ACanvas.Pen.Width,tr.Bottom);
        end
        else
        begin
          ACanvas.MoveTo(tr.Left,tr.Top);
          ACanvas.LineTo(tr.Left,tr.Bottom);
        end;
      end;

      if (cbRight in borders) then
      begin
        ACanvas.MoveTo(tr.Right,tr.Top);
        ACanvas.LineTo(tr.Right,tr.Bottom);
        {
        if c = ColCount - 1 then
        begin
          Canvas.MoveTo(tr.Right,tr.Top);
          Canvas.LineTo(tr.Right,tr.Bottom);
        end
        else
        begin
          Canvas.MoveTo(tr.Right - Canvas.Pen.Width,tr.Top);
          Canvas.LineTo(tr.Right - Canvas.Pen.Width,tr.Bottom);
        end;
        }
      end;

      if (cbTop in borders) then
      begin
        ACanvas.MoveTo(tr.Left,tr.Top);
        ACanvas.LineTo(tr.Right,tr.Top);
      end;

      if (cbBottom in borders) then
      begin
        ACanvas.MoveTo(tr.Left,tr.Bottom);
        ACanvas.LineTo(tr.Right,tr.Bottom);
      end;

      ACanvas.Pen.Assign(OldPen);
    end;

    Fontscalefactor := 1.0;
  end;

   // Routine to draw header & footer
   function BuildHeader(sizeonly: boolean = false): Integer;
   var
     tl,tr,tc,bl,br,bc: string;
     i,j,ml,hl: Integer;
     HTMLHeader: string;
     HTMLTitle: Boolean;
     HTMLRect,hr,cr: TRect;
     HTMLMM: Integer;
     HTMLFontSize,HTMLXSize,HTMLYSize: Integer;
     Anchor,Stripped,FocusAnchor,AnchorHint: string;
     CID,CV,CT: string;

     function PagNumStr:string;
     begin
       if MultiCol then
       begin
         Result := IntToStr(PagRow+1) + '-' + IntToStr(PagCol);
         DoGetPrintPageNum(PagRow + 1, PagCol, Result);
       end
       else
       begin
         if (FPrintSettings.PageNumSep <> '') and (MaxPages > 1) then
           Result := IntToStr(PagNum + 1 + PrintSettings.PageNumberOffset) +
             FPrintSettings.PageNumSep + IntToStr(MaxPages + PrintSettings.MaxPagesOffset)
         else
           Result := IntToStr(PagNum + 1 + PrintSettings.PageNumberOffset);

         DoGetPrintPageNum(PagNum + 1, PagCol, Result);
       end;
     end;

   begin
     Result := 0;
     FontScaleFactor := ScaleFactor;

     if ((PagNum + 1) < FPrintPageFrom) or ((Pagnum + 1) > FPrintPageTo) then
       Exit;

     if (PrintMethod in [prCalcPreview,prCalcPrint]) then
       Exit;

     tl := '';
     tr := '';
     tc := '';
     bl := '';
     br := '';
     bc := '';
     HTMLHeader := '';
     HTMLTitle := True;

     with FPrintSettings do
     begin
       case FTime of
       ppTopLeft:tl := FormatDateTime('hh:nn',Now) + ' ' + tl;
       ppTopRight:tr := tr + ' ' + FormatDateTime('hh:nn',Now);
       ppTopCenter:tc := tc + ' ' + FormatDateTime('hh:nn',Now);
       ppBottomLeft:bl := FormatDateTime('hh:nn',Now) + ' ' + bl;
       ppBottomRight:br := br + ' ' + FormatDateTime('hh:nn',Now);
       ppBottomCenter:bc := bc + ' ' + FormatDateTime('hh:nn',Now);
       end;

       case FDate of
       ppTopLeft:tl := FormatDateTime(FDateFormat,Now) + ' ' + tl;
       ppTopRight:tr := tr + ' ' + FormatDateTime(FDateFormat,Now);
       ppTopCenter:tc := tc + ' ' + FormatDateTime(FDateFormat,Now);
       ppBottomLeft:bl := FormatDateTime(FDateFormat,Now) + ' ' + bl;
       ppBottomRight:br := br + ' ' + FormatDateTime(FDateFormat,Now);
       ppBottomCenter:bc := bc + ' ' + FormatDateTime(FDateFormat,Now);
       end;

       case FPageNr of
       ppTopLeft:tl := FPagePrefix+' '+PagNumStr+' '+FPageSuffix+' '+tl;
       ppTopRight:tr := tr+' '+FPagePrefix+' '+PagNumStr+' '+FPageSuffix;
       ppTopCenter:tc := tc+' '+FPagePrefix+' '+PagNumStr+' '+FPageSuffix;
       ppBottomLeft:bl := FPagePrefix+' '+PagNumStr+' '+FPageSuffix+' '+bl;
       ppBottomRight:br := br+' '+FPagePrefix+' '+PagNumStr+' '+FPageSuffix;
       ppBottomCenter:bc := bc+' '+FPagePrefix+' '+PagNumStr+' '+FPageSuffix;
       end;

       if FTitleText <> '' then
       begin
         case FTitle of
         ppTopLeft:tl := FTitleText + ' ' + tl;
         ppTopRight:tr := tr + ' ' + FTitleText;
         ppTopCenter:tc := tc + ' ' + FTitleText;
         ppBottomLeft:bl := FTitleText + ' ' + bl;
         ppBottomRight:br := br + ' ' + FTitleText;
         ppBottomCenter:bc := bc + ' ' + FTitleText;
         end;
       end
       else
       begin
         if TextType(FTitleLines.Text,FEnableHTML) = ttHTML then
         begin
           HTMLHeader := StringListToText(FTitleLines);
           HTMLTitle := FTitle in [ppTopLeft,ppTopCenter,ppTopRight];
         end
         else
           if FTitleLines.Count > 0 then
           begin
             case FTitle of
             ppTopLeft:tl := AppendWithSpace(FTitleLines.Strings[0],tl);
             ppTopRight:tr := AppendWithSpace(tr,FTitleLines.Strings[0]);
             ppTopCenter: tc := AppendWithSpace(tc,FTitleLines.Strings[0]);
             ppBottomLeft:bl := AppendWithSpace(FTitleLines.Strings[0],bl);
             ppBottomRight:br := AppendWithSpace(br,FTitleLines.Strings[0]);
             ppBottomCenter:bc := AppendWithSpace(bc,FTitleLines.Strings[0]);
           end;
         end;
       end;
     end;

     {$IFDEF FREEWARE}
     if PrintMethod = prPrint then GetFreeStr(cla,bc);
     {$ENDIF}

     OldFont.Assign(ACanvas.Font);
     OldBrush.Assign(ACanvas.Brush);
     ACanvas.Brush.Style := bsClear;
     ACanvas.Font.Assign(FPrintSettings.HeaderFont);

     ACanvas.Font.Height := MapFontHeight(FPrintSettings.HeaderFont.Size); {map into mm_lometric space}

     if tl <> '' then ACanvas.Textout(Indent,-Headersize,tl);
     if tr <> '' then ACanvas.Textout(xsize - ACanvas.TextWidth(tr) - 20 - FPrintSettings.RightSize ,-Headersize,tr);
     if tc <> '' then ACanvas.Textout((xsize - ACanvas.TextWidth(tc)) shr 1,-Headersize,tc);

     if (FPrintSettings.FTitle in [ppTopLeft,ppTopRight,ppTopCenter]) and
        (FPrintSettings.FTitleLines.Count > 1) and (HTMLHeader = '') then
     begin
       j := 0;
       for i := 2 to FPrintSettings.FTitleLines.Count do
       begin
         j := j + ACanvas.TextHeight('gh');
         tc := FPrintSettings.TitleLines[i - 1];
         case FPrintSettings.FTitle of
         ppTopLeft:ACanvas.Textout(Indent,-Headersize-j,tc);
         ppTopRight:ACanvas.Textout(xsize-ACanvas.TextWidth(tc)-20-FPrintSettings.RightSize ,-HeaderSize-j,tc);
         ppTopCenter:ACanvas.Textout((xsize-ACanvas.TextWidth(tc)) shr 1,-HeaderSize - j,tc);
         end;
       end;
       Result := j;
     end;

     if (HTMLHeader <> '') and HTMLTitle then
     begin
       // init font
       ACanvas.Font.Size := FPrintSettings.HeaderFont.Size;

       HTMLRect := Rect(0,0,xsize -20 -FPrintSettings.RightSize,1000);

       HTMLDrawEx(ACanvas,HTMLHeader,HTMLRect,Gridimages,0,0,-1,0,1, False,True,True,False,True,False,True,False,'',
                  HTMLFactor,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
                  HTMLXSize,HTMLYSize,ml,hl,hr,cr,CID,CV,CT,FImageCache,FContainer,Handle,BidiMode);

       // adapt to dpi
       Result := Round(HTMLYsize * 96 / GetDeviceCaps(ACanvas.Handle, LOGPIXELSY));

       if not sizeonly then
       begin
         HTMLRect := Rect(Indent, -HeaderSize, xsize -20 -FPrintSettings.RightSize, -HeaderSize - HTMLYSize);

         lptodp(ACanvas.Handle,HTMLRect.TopLeft,1);
         lptodp(ACanvas.Handle,HTMLRect.BottomRight,1);

         HTMLMM := GetMapMode(ACanvas.Handle);
         HTMLFontSize := ACanvas.Font.Size;
         SetMapMode(ACanvas.Handle,MM_TEXT);
         ACanvas.Font.Size := FPrintSettings.HeaderFont.Size;

         HTMLRect.Bottom := HTMLRect.Top + HTMLYSize;

         HTMLDrawEx(ACanvas,HTMLHeader,HTMLRect,Gridimages,0,0,-1,0,1, False,False,True,False,True,False,True,False,'',
                    HTMLFactor,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
                    HTMLXSize,HTMLYSize,ml,hl,hr,cr,CID,CV,CT,FImageCache,FContainer,Handle,BidiMode);

         SetMapMode(ACanvas.Handle,HTMLMM);
         ACanvas.Font.Size := HTMLFontSize;
       end;
     end;

     ACanvas.Font.Assign(FPrintSettings.FooterFont);
     ACanvas.Font.Height := MapFontHeight(ACanvas.Font.size); //map into mm_lometric space

     if bl <> '' then ACanvas.Textout(Indent,ysize + FFntSize+FntVSpace + Footersize,bl);
     if br <> '' then ACanvas.Textout(xsize-ACanvas.TextWidth(br)-20-FPrintSettings.RightSize ,ysize+ffntsize+fntvspace+footersize,br);
     if bc <> '' then ACanvas.Textout((xsize-ACanvas.TextWidth(bc)) shr 1,ysize+ffntsize+fntvspace+footersize,bc);

     if (FPrintSettings.FTitle in [ppBottomLeft,ppBottomRight,ppBottomCenter]) and
        (FPrintSettings.FTitleLines.Count > 1) and (HTMLHeader = '') then
     begin
       j := 0;
       for i := 2 to FPrintSettings.FTitleLines.Count do
       begin
         j := j + ACanvas.TextHeight('gh');
         tc := FPrintSettings.TitleLines[i - 1];
         case FPrintSettings.FTitle of
         ppBottomLeft:ACanvas.Textout(Indent,ysize + FFntSize + FntVSpace + FooterSize-j,tc);
         ppBottomRight:ACanvas.Textout(xsize- ACanvas.TextWidth(tc)- 20 - FPrintSettings.RightSize ,YSize + FFntSize + FntVSpace+footersize-j,tc);
         ppBottomCenter:ACanvas.Textout((xsize- ACanvas.TextWidth(tc)) shr 1,YSize + FFntSize + FntVSpace + Footersize-j,tc);
         end;
       end;
       Result := j;
     end;

     if (HTMLHeader <> '') and not HTMLTitle then
     begin
       HTMLRect := Rect(Indent, ysize + FPrintSettings.FooterSize, xsize, ysize );

       lptodp(ACanvas.Handle,HTMLRect.Topleft,1);
       lptodp(ACanvas.Handle,HTMLRect.Bottomright,1);

       HTMLMM := GetMapMode(ACanvas.Handle);
       HTMLFontSize := ACanvas.Font.Size;
       SetMapMode(ACanvas.Handle,MM_TEXT);
       ACanvas.Font.Size := FPrintSettings.HeaderFont.Size;

       HTMLDrawEx(ACanvas,HTMLHeader,HTMLRect,Gridimages,0,0,-1,0,1,False,False,True,False,True,False,True,False,'',
                  HTMLFactor,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,HTMLXSize,HTMLYSize,
                  hl,ml,hr,cr,CID,CT,CV,FImageCache,FContainer,Handle,BidiMode);

       Result := Round(HTMLYsize * 96/GetDeviceCaps(ACanvas.Handle, LOGPIXELSY));

       SetMapMode(ACanvas.Handle,HTMLMM);
       ACanvas.Font.Size := HTMLFontSize;
     end;

     ACanvas.Font.Assign(OldFont);
     ACanvas.Brush.Assign(OldBrush);
   end;

   procedure DrawBorderAround(StartCol,EndCol,yposprint: Integer);
   var
     k: Integer;
   begin
     if ((pagnum+1)<FPrintPageFrom) or ((pagnum+1)>FPrintPageTo) then Exit;
     if (PrintMethod in [prCalcPreview,prCalcPrint]) then Exit;

{     if ((PrintMethod=prPreview) and (pagnum<>PreviewPage)) or
         (PrintMethod in [prCalcPreview,prCalcPrint]) then Exit;}

     if (FPrintSettings.FBorders in [pbAround,pbAroundVertical,pbAroundHorizontal]) then
     begin
       if RepeatCols then
         k := 0
       else
         k := StartCol;

       ACanvas.MoveTo(Indents[k],-TopIndent - FPrintSettings.TitleSpacing);
       ACanvas.LineTo(Indents[EndCol + 1],-TopIndent - FPrintSettings.TitleSpacing);
       ACanvas.LineTo(Indents[EndCol + 1],yposprint +(fntvspace shr 1));
       ACanvas.LineTo(Indents[k],yposprint + (fntvspace shr 1));
       ACanvas.LineTo(Indents[k],-TopIndent - FPrintSettings.TitleSpacing);
     end;

     if (FPrintSettings.FBorders in [pbDouble,pbHorizontal,pbAroundHorizontal]) then
     begin
       if RepeatCols then
         ACanvas.MoveTo(Indents[0],yposprint+(fntvspace shr 1))
       else
         ACanvas.MoveTo(Indents[StartCol],yposprint+(fntvspace shr 1));

       ACanvas.LineTo(Indents[EndCol+1],yposprint+(fntvspace shr 1));
     end;

     if (FPrintSettings.FBorders in [pbDouble,pbVertical,pbAroundVertical]) then
     begin
       {draw here the vertical Columns too}
       if RepeatCols then
       begin
         for k := 0 to FixedCols - 1 do
         begin
           ACanvas.MoveTo(Indents[k],-topIndent-FPrintSettings.TitleSpacing);
           ACanvas.LineTo(Indents[k],yposprint+(fntvspace shr 1));
         end;
       end;
       {
       for k := StartCol to EndCol + 1 do
       begin
         Canvas.MoveTo(Indents[k],-TopIndent - FPrintSettings.TitleSpacing);
         Canvas.LineTo(Indents[k],yposprint+(fntvspace shr 1));
       end;
       }
     end;
   end;

   procedure StartNewPage;
   begin
     if ((PagNum + 2) < FPrintPageFrom) or ((PagNum + 2) > FPrintPageTo) then
       Exit;

     if (PrintMethod = prPrint) and (PagNum + 1 >= FPrintPageFrom) then
     begin
       //if FPrintPreview <> nil then
       //begin
       //  FPrintPreview.NewPage;
       //  Canvas := FPrintPreview.Canvas;
       //end
       //else
         Printer.NewPage;
     end;

     SetMapMode(ACanvas.Handle,MM_LOMETRIC);

     if (PrintMethod in [prPrint,prPreview]) then
     if Assigned(FOnPrintPage) then
     begin
       FOnPrintPage(Self,ACanvas,PagNum + 2,xsize,ysize);
     end;
   end;


begin
  SetMapMode(ACanvas.Handle,MM_TEXT);

  SetLength(Indents, AllColCount + 1);
  SetLength(MaxWidths, AllColCount + 1);

  try
    hdc := GetDC(Handle);
    HTMLFactor := GetDeviceCaps(ACanvas.Handle,LOGPIXELSX)/GetDeviceCaps(hdc,LOGPIXELSX);
    ReleaseDC(Handle,hdc);
  except
    HTMLFactor := 1.0;
  end;

  SetMapMode(ACanvas.Handle,MM_LOMETRIC);
  FontScalefactor := 1.0;

  newFont := TFont.Create;
  oldFont := TFont.Create;
  oldpen := TPen.Create;
  newBrush := TBrush.Create;
  oldBrush := TBrush.Create;

  ACanvas.Pen.Color := clBlack;
  ACanvas.Pen.style := FPrintSettings.BorderStyle;

  if FPrintSettings.Borders = pbDouble then
    ACanvas.Pen.Width := 10
  else
    ACanvas.Pen.Width := 2;

  ACanvas.Font.Assign(FPrintSettings.HeaderFont);
  ACanvas.Font.Height := MapFontHeight(ACanvas.Font.Size);

  hfntsize := ACanvas.TextHeight('gh');

  ACanvas.Font := FPrintSettings.FooterFont;
  ACanvas.Font.Height := MapFontHeight(ACanvas.Font.Size);
  ffntsize := ACanvas.TextHeight('gh');

  ACanvas.Font := FPrintSettings.Font;

  cache_Row := -1;

  orgsize := Canvas.Font.size;

  ACanvas.Font.Height := MapFontHeight(ACanvas.Font.size); {map into mm_lometric space}

  FntlineHeight := Canvas.TextHeight('gh');

  FntVSpace := fntlineHeight shr 3;
  FntHSpace := ACanvas.TextWidth('g') div 2; // adapt for multiline

  case PrintMethod of
  prPrint:
    begin
//      if FPrintPreview <> nil then
//      begin
//        dptolp(Canvas.Handle,prevrect.Topleft,1);
//        dptolp(Canvas.Handle,prevrect.Bottomright,1);
//        xsize := (prevrect.Right - prevrect.Left);
//        ysize := (prevrect.Bottom - prevrect.Top);
//      end
//      else
//      begin
        xsize := ACanvas.Cliprect.Right - Canvas.Cliprect.Left;
        ysize := ACanvas.Cliprect.Bottom;
//      end;
    end;
  prCalcPrint:
    begin
      xsize := prevrect.Right - prevrect.Left;
      ysize := -prevrect.Bottom - prevrect.Top;
    end;
  prPreview,prCalcPreview:
    begin
      dptolp(ACanvas.Handle,prevrect.Topleft,1);
      dptolp(ACanvas.Handle,prevrect.Bottomright,1);
      xsize := (prevrect.Right - prevrect.Left);
      ysize := (prevrect.Bottom - prevrect.Top);
    end;
  end;

//  ResFactor := GetDeviceCaps(ACanvas.Handle,LOGPIXELSX)/GetDeviceCaps(Canvas.Handle,LOGPIXELSX)*(254/GetDeviceCaps(Canvas.Handle,LOGPIXELSX));

  ResFactor := (254/GetDeviceCaps(Canvas.Handle,LOGPIXELSX));

  FPrintPageRect := Rect(0,0,xsize,ysize);

  Indent := FPrintSettings.FLeftSize;

  if FPrintSettings.FUseFixedWidth then
    Spacing := 0
  else
    Spacing := FPrintSettings.ColumnSpacing + 20; // min. 2mm space

  ScaleFactor := 1.0;

  CalculateWidths;

  // total space req. for Columns
  TotalWidth := 0;
  for j := FPrintRect.Left to FPrintRect.Right do
  begin
    if IsSelCol(j) then
      TotalWidth := TotalWidth + MaxWidths[j] + Spacing;
  end;

  if FPrintSettings.FFitToPage <> fpNever then
  begin
    tw := (FPrintRect.Right - FPrintRect.Left + 1) * Spacing;
    if TotalWidth - tw <> 0 then
      ScaleFactor := (XSize - FPrintSettings.FRightSize - FPrintSettings.FLeftSize - tw)/(TotalWidth - tw);

    if (ScaleFactor > 1.0) and (FPrintSettings.FFitToPage = fpShrink) then ScaleFactor := 1.0;
    if (ScaleFactor < 1.0) and (FPrintSettings.FFitToPage = fpGRow) then ScaleFactor := 1.0;

    if (ScaleFactor <> 1.0) and (FPrintSettings.FFitToPage = fpCustom) then
    begin
      AllowFitToPage := True;
      if Assigned(OnFitToPage) then
        OnFitToPage(Self,scalefactor,AllowFitToPage);
      if not AllowFitToPage then
        ScaleFactor := 1.0;
    end;

    if ScaleFactor <> 1.0 then
    begin
      for j := FPrintRect.Left to FPrintRect.Right do
        maxWidths[j] := Trunc(MaxWidths[j] * scalefactor);

      TotalWidth := 0;
      //recalculate total req. width
      for j := FPrintRect.Left to FPrintRect.Right do
      begin
        TotalWidth := TotalWidth + MaxWidths[j] + spacing;
      end;
    end;
  end;

  if Assigned(FOnPrintSetColumnWidth) then
  begin
    for j := FPrintRect.Left to FPrintRect.Right do
    begin
      FOnPrintSetColumnWidth(Self,j,MaxWidths[j]);
    end;

    TotalWidth := 0;
    for j := FPrintRect.Left to FPrintRect.Right do
    begin
      if IsSelCol(j) then
        TotalWidth := TotalWidth + MaxWidths[j] + Spacing;
    end;
  end;

  StartCol := FPrintRect.Left;
  EndCol := FPrintRect.Left;

  PagNum := 0; //page counter
  PagCol := 0;
  LastRow := -1;

  //calculate the size of the fixed Columns
  MultiCol := False;
  Cancelled := False;

  if (FPrintRect.Top <= FixedRows) and (FPrintRect.Bottom >= RowCount - 1 - FixedFooters) then
    es := esExportNewRow
  else
    es := esExportSelRow;

  while (EndCol <= FPrintRect.Right) and not Cancelled do
  begin
    // calculate new endCol here
    SpaceforFixedCols := 0;

    PrevEndCol := EndCol;

    PagRow := 0;
    Inc(PagCol);

    // added fixed spaceforCols here if repeatFixedCols is set

    //RepeatCols := (EndCol > FPrintRect.Left) and (FixedCols > 0) and
    //              (FPrintSettings.FRepeatFixedCols);

    RepeatCols := ((FixedCols > 0) and FPrintSettings.FRepeatFixedCols)
      and ( (EndCol > FPrintRect.Left) or (FixedCols < FPrintRect.Left) );

    if RepeatCols then
    begin
      for m := 0 to FixedCols - 1 do
        SpaceForFixedCols := SpaceForFixedCols + MaxWidths[m] + Spacing;
    end;

    SpaceForCols := SpaceForFixedCols;

    while (SpaceForCols <= XSize - FPrintSettings.FRightSize) and (EndCol <= FPrintRect.Right) do
    begin
      SpaceForCols := SpaceForCols + MaxWidths[EndCol] + Spacing;
      if SpaceForCols <= XSize - FPrintSettings.FRightSize then
        inc(EndCol);
    end;

    if not (SpaceforCols <= XSize - FPrintSettings.FRightSize) then
    begin
      SpaceForCols := SpaceForCols - MaxWidths[EndCol] - Spacing;
      Dec(EndCol);
    end;

    if EndCol <= PrevendCol then
      EndCol := PrevEndCol + 1;

    //space for Cols is the Width of the printout
    if EndCol > FPrintRect.Right then
      EndCol := FPrintRect.Right;

    MultiCol := MultiCol or (EndCol < FPrintRect.Right);

    FPrintPageWidth := SpaceForCols;

    if FPrintSettings.FCentered then
    begin
      Indents[StartCol] := 0;
      Indents[0] := 0;
    end
    else
    begin
      Indents[StartCol] := Indent;
      Indents[0] := Indent;
    end;

    for j := StartCol to EndCol do
    begin
      if IsSelCol(j) then
        Indents[j + 1] := Indents[j] + MaxWidths[j] + Spacing
      else
        Indents[j + 1] := Indents[j];
    end;

    FPrintColStart := StartCol;
    FPrintColEnd := EndCol;

    if RepeatCols then
    begin
      for m := 1 to FixedCols - 1 do
      begin
        Indents[m] := Indents[m - 1] + MaxWidths[m - 1] + Spacing;
      end;
    end;

    if (FPrintSettings.FCentered) and (SpaceForCols < XSize) then
    begin
      SpaceforCols := (XSize - SpaceForCols) shr 1;
      for j := StartCol to EndCol + 1 do
      begin
        Indents[j] := Indents[j] + SpaceForCols;
      end;

      //add centering space to repeated Columns
      if RepeatCols then
        for m := 0 to FixedCols do
        begin
          Indents[m] := Indents[m] + SpaceForCols;
        end;
    end;

    // add spacing if required for repeat fixed Columns}
    for j := StartCol to EndCol + 1 do
    begin
      Indents[j] := Indents[j] + SpaceForFixedCols;
    end;

    // fixed Columns
    j := 0;
    yposprint := -TopIndent;
    TopIndent := 0; //reserve a line for header

    HeaderSize := FPrintSettings.FHeaderSize;
    FooterSize := FPrintSettings.FFooterSize;

    if (FPrintSettings.FTime in [ppTopLeft,ppTopCenter,ppTopRight]) or
       (FPrintSettings.FDate in [ppTopLeft,ppTopCenter,ppTopRight]) or
       (FPrintSettings.FPageNr in [ppTopLeft,ppTopCenter,ppTopRight]) or
       (FPrintSettings.FTitle in [ppTopLeft,ppTopCenter,ppTopRight]) then
    begin
      TopIndent := hfntsize + fntvspace + HeaderSize;

      if (FPrintSettings.TitleLines.Count > 0) and (FPrintSettings.Title in [ppTopLeft,ppTopCenter,ppTopRight]) then
      begin
        hhsize := Round(BuildHeader(false));

        if hhsize <> 0 then
          TopIndent := TopIndent + hhsize + FPrintSettings.HeaderSize
        else
          TopIndent := TopIndent + hfntsize * (FPrintSettings.TitleLines.Count - 1);
      end;
    end
    else
    begin
      TopIndent := HeaderSize;
    end;

    if (FPrintSettings.FTime in [ppBottomLeft,ppBottomCenter,ppBottomRight]) or
       (FPrintSettings.FDate in [ppBottomLeft,ppBottomCenter,ppBottomRight]) or
       (FPrintSettings.FPageNr in [ppBottomLeft,ppBottomCenter,ppBottomRight]) or
       (FPrintSettings.FTitle in [ppBottomLeft,ppBottomCenter,ppBottomRight]) then
    begin
      FootIndent := 2 * (FFntSize + FntVSpace) + FooterSize;
      if (FPrintSettings.TitleLines.Count > 0) and (FPrintSettings.Title in [ppBottomLeft,ppBottomCenter,ppBottomRight]) then
        FootIndent := FootIndent + FFntsize * (FPrintSettings.TitleLines.Count - 1);
    end
    else
      FootIndent := 1 * (FFntSize + FntVSpace) + Footersize;

    i := FPrintRect.Top;

    if (PrintMethod in [prPrint,prPreview]) then
      if Assigned(FOnPrintPage) then
      begin
        FOnPrintPage(self,ACanvas,PagNum + 1,xsize,ysize);
      end;

    // print all Rows here

    while (i < FPrintRect.Bottom + 1) and not Cancelled do
    begin
      ExportNotification(es, i);

      //at start of page.. print header
      if j = 0 then
      begin
        YPosPrint := -TopIndent;
        BuildHeader;
        YPosPrint := YPosPrint - FPrintSettings.TitleSpacing;
      end;

      if (j = 0) and (i > 0) and
         ((PagNum > 0) or (FPrintRect.Top >= FixedRows)) and
         FPrintSettings.FRepeatFixedRows and (FixedRows > 0) then
      begin
        //here headers are reprinted
        for m := 0 to FixedRows - 1 do
        begin
          //if necessary, reprint fixed Columns
          if RepeatCols then
          begin
            BuildColumnsRow(yposprint,0,FixedCols - 1,m,0);
          end;

          //print Columns
          th := BuildColumnsRow(yposprint,startCol,endCol,m,0);
          YPosPrint := YPosPrint - th;
        end;
        inc(j);
      end;

      doprintrow := true;

      rhi := 0;

      if IsSelRow(i) then
      begin
        rhi := GetRowHeight(i);

        if rhi > YSize then
          rhi := YSize;

        if (YPosPrint - rhi >= YSize + FootIndent) then
        begin
          if RepeatCols then
            BuildColumnsRow(yposprint,0,FixedCols - 1,i,0);

          th := BuildColumnsRow(YPosPrint,StartCol,EndCol,i,0);
          YPosPrint := YPosPrint - th;
        end
        else
          doprintrow := false;
      end;

      if doprintrow then
      begin
        inc(i);
        if i < RowCount then
          rhi := GetRowHeight(i)
        else
          rhi := 0;
      end
      else
        Cancelled := true;

      inc(j);

      ForcedNewPage := False;

      // query to print new page after each row
      if Assigned(FOnPrintNewPage) then
      begin
        FOnPrintNewPage(Self,i,ForcedNewPage);
      end;

      //rhi := GetRowHeight(j);

      if ((i >= FPrintRect.Bottom + 1) or (YPosPrint - rhi < YSize + FootIndent))
         or ForcedNewPage then
      begin
        if (PrintMethod in [prPrint,prPreview]) then
        begin
          if Assigned(FOnPrintPageDone) then
            FOnPrintPageDone(Self, ACanvas, i, YPosPrint, PagNum + 1, XSize, YSize);

          if Assigned(FOnPrintCancel) then
            FOnPrintCancel(Self,PagNum + 1, Cancelled);
        end;
      end;

      if ((i < FPrintRect.Bottom + 1) and (YPosPrint - rhi < YSize + FootIndent))
         or ForcedNewPage then
      begin
        DrawBorderAround(StartCol,EndCol,YPosPrint);
        j := 0;
        LastRow := i;
        StartNewPage;

        if (PreviewPage < PagNum) and FastPrint then
          i := FPrintRect.Bottom + 1;

        inc(PagNum);
        inc(PagRow);

        // recalculate title & footer size after each page
        if (FPrintSettings.FTime in [ppTopLeft,ppTopCenter,ppTopRight]) or
           (FPrintSettings.FDate in [ppTopLeft,ppTopCenter,ppTopRight]) or
           (FPrintSettings.FPageNr in [ppTopLeft,ppTopCenter,ppTopRight]) or
           (FPrintSettings.FTitle in [ppTopLeft,ppTopCenter,ppTopRight]) then
        begin
          TopIndent := hfntsize + fntvspace + headersize;
          if (FPrintSettings.FTitleLines.Count > 0) and (FPrintSettings.FTitle in [ppTopLeft,ppTopCenter,ppTopRight]) then
            TopIndent := TopIndent + hfntsize * (FPrintSettings.FTitleLines.Count - 1);
        end
        else
          TopIndent := HeaderSize;

        if (FPrintSettings.FTime in [ppBottomLeft,ppBottomCenter,ppBottomRight]) or
           (FPrintSettings.FDate in [ppBottomLeft,ppBottomCenter,ppBottomRight]) or
           (FPrintSettings.FPageNr in [ppBottomLeft,ppBottomCenter,ppBottomRight]) or
           (FPrintSettings.FTitle in [ppBottomLeft,ppBottomCenter,ppBottomRight]) then
        begin
          FootIndent := 2*(FFntSize + FntVSpace) + FooterSize;
          if (FPrintSettings.FTitleLines.Count > 0) and (FPrintSettings.FTitle in [ppBottomLeft,ppBottomCenter,ppBottomRight]) then
            FootIndent := FootIndent+ffntsize*(FPrintSettings.FTitleLines.Count-1);
        end
        else
          FootIndent := 1*(FFntSize + FntVSpace) + Footersize;
      end;
    end;

    if (LastRow = -1) or (i <> LastRow) then
      DrawBorderAround(StartCol,EndCol,YPosPrint);

    StartCol := EndCol + 1;
    EndCol := StartCol;
    if EndCol <= FPrintRect.Right then
      StartNewPage;
    Inc(PagNum);
  end; //end of while EndCol < FPrintRect.Right

  // free temporary Font and Brush objects
  NewFont.Free;
  OldFont.Free;
  OldPen.Free;
  NewBrush.Free;
  OldBrush.Free;
  Result := PagNum;

  if Assigned(FOnPrintDone) then
    FOnPrintDone(Self);
end;


procedure TAdvStringGrid.InvalidateGridRect(r:TGridRect);
var
  gdr1,gdr2,gdr3:TRect;
begin
  gdr1 := CellRect(r.Left,r.Top);
  gdr2 := CellRect(r.Right,r.Bottom);
  UnionRect(gdr3,gdr1,gdr2);
  InvalidateRect(Handle,@gdr3,False);
end;

procedure TAdvStringGrid.ClearModifiedRows;
begin
  FModifiedRows.Clear;
  Invalidate;
end;

procedure TAdvStringGrid.ClearSelectedCells;
begin
  Selection := TGridRect(Rect(FixedCols,FixedRows,FixedCols,FixedRows));
  FSelectedCells.Clear;
  Invalidate;
end;

function TAdvStringGrid.GetSelectedCell(i: Integer): TGridCoord;
begin
  Result.X := Loword(integer(FSelectedCells.Items[i]));
  Result.Y := Hiword(integer(FSelectedCells.Items[i]));
end;

function TAdvStringGrid.GetSelectedCellsCount: Integer;
var
  i,j: Integer;
begin
  if not MouseActions.DisjunctCellSelect then
  begin
    FSelectedCells.Clear;

    if (Selection.Left <> Selection.Right) or
       (Selection.Top <> Selection.Bottom) then
    begin
      for i := Selection.Left to Selection.Right do
      begin
        for j := Selection.Top to Selection.Bottom do
        begin
          if FSelectedCells.IndexOf(Pointer(MakeLong(i,j))) = -1 then
            FSelectedCells.Add(MakeLong(i,j));
         end;
      end;
    end
    else
    begin
      if FSelectedCells.IndexOf(Pointer(MakeLong(Col,Row))) = -1 then
        FSelectedCells.Add(MakeLong(Col,Row));
    end;
  end;

  Result := FSelectedCells.Count;
end;

function TAdvStringGrid.GetSelectedCells(i, j: Integer): Boolean;
var
  xmi,xma: integer;
  ymi,yma: integer;
begin
  if MouseActions.DisjunctCellSelect then
  begin
    Result := FSelectedCells.IndexOf(Pointer(MakeLong(i,j))) <> -1;
  end
  else
  begin
    xmi := Selection.Left;
    xma := Selection.Right;
    if Selection.Left > Selection.Right then
    begin
      xma := Selection.Left;
      xmi := Selection.Right;
    end;
    ymi := Selection.Top;
    yma := Selection.Bottom;
    if Selection.Top > Selection.Bottom then
    begin
      yma := Selection.Top;
      ymi := Selection.Bottom;
    end;

    Result := (i >= xmi) and (i <= xma) and (j >= ymi) and (j <= yma);
  end;
end;

procedure TAdvStringGrid.SetSelectedCells(i, j: Integer; const Value: Boolean);
var
  k: Integer;
begin
  k := FSelectedCells.IndexOf(Pointer(makelong(i,j)));

  if (k = -1) and Value then
  begin
    FSelectedCells.Add(MakeLong(i,j));
    RepaintCell(i,j)
  end;

  if not Value and (k <> - 1) then
  begin
    FSelectedCells.Delete(k);
    RepaintCell(i,j);
  end;
end;

function TAdvStringGrid.GetSelectedColCount: integer;
var
  pt: TPoint;
begin
  if MouseActions.DisjunctColSelect then
    Result := FColSelect.Count
  else
  begin
    if IsMergedCell(Selection.Left, Selection.Top) then
    begin
      pt := CellSpan(Selection.Left, Selection.Top);
      if pt.x + Selection.Left > Selection.Right then
        Result := pt.x + 1
      else
        Result := Abs(Selection.Left - Selection.Right) + 1;
    end
    else
      if IsMergedCell(Selection.Right, Selection.Top) then
      begin
        pt := CellSpan(Selection.Left, Selection.Right);
        Result := Abs(Selection.Left - Selection.Right) + pt.x + 1;
      end
      else
        Result := Abs(Selection.Left - Selection.Right) + 1;
  end;

end;

function TAdvStringGrid.GetSelectedRowCount: integer;
var
  pt: TPoint;
  sel: TGridRect;
begin
  if MouseActions.DisjunctRowSelect then
    Result := FSelectedRows.Count
  else
  begin
    sel := Selection;
    if (sel.Bottom >= RowCount - FixedFooters) and (FloatingFooter.Visible = false) then
      sel.Bottom := RowCount - FixedFooters - 1;

    if IsMergedCell(sel.Left, sel.Top) then
    begin
      pt := CellSpan(sel.Left, sel.Top);
      if pt.y + sel.Top > sel.Bottom then
        Result := pt.y + 1
      else
        Result := Abs(sel.Top - sel.Bottom) + 1;
    end
    else
      if IsMergedCell(sel.Left, sel.Bottom) then
      begin
        pt := CellSpan(sel.Left, sel.Bottom);
        Result := Abs(sel.Top - sel.Bottom) + pt.y + 1;
      end
      else
        Result := Abs(sel.Top - sel.Bottom) + 1;
  end;
end;

function TAdvStringGrid.GetSelectedRow(i: Integer): Integer;
var
  ms,mx: integer;
begin
  if MouseActions.DisjunctRowSelect then
  begin
    if i < FSelectedRows.Count then
      Result := FSelectedRows[i]
    else
      Result := -1;
  end
  else
  begin
    ms := Min(Selection.Top, Selection.Bottom);
    mx := Max(Selection.Top, Selection.Bottom);

    if (ms + i <= mx) then
      Result := ms + i
    else
      Result := -1;
  end;
end;

procedure TAdvStringGrid.KeyDown(var Key: Word; Shift: TShiftState);
var
  r,c,nc: integer;
  snake: boolean;
  st,sb,sw: integer;
begin
  r := Row;
  c := Col;
  nc := -1;

  case Key of
  VK_LEFT:
    begin
      if BiDiMode = bdRightToLeft then
        nc := NextCol(c + 1)
      else
        nc := NextCol(c - 1);
    end;
  VK_RIGHT:
    begin
      if BiDiMode = bdRightToLeft then
        nc := NextCol(c - 1)
      else
        nc := NextCol(c + 1);
    end;
  end;

  FLastKeyCell := point(Col,Row);

  if (Key = VK_SHIFT) or (Key = VK_CONTROL) or (Key = VK_MENU) then
  begin
    if SearchFooter.Visible and (Row = RowCount - 1) then
    begin
      Key := 0;
      Exit;
    end;
  end;

  inherited;

  if (nc <> -1) and (nc <> Col) then
  begin
    Col := nc;
  end;

  snake := Navigation.CursorAdvance = caSnake;

  st := Selection.Top;
  sb := Selection.Bottom;

  if (st > sb) then
  begin
    sw := sb;
    sb := st;
    st := sw;
  end;

  if (ssCtrl in Shift) and (Key = VK_DOWN) and Navigation.CursorMoveRows and (sb < RowCount - 1) then
  begin
    r := Row;
    if st = sb then
    begin
      MoveRow(st, st + 1);
      Row := r + 1;
    end
    else
    begin
      MoveRows(st, st + 1, sb - st + 1);
      Selection := TGridRect(Rect(FixedCols, st + 1, ColCount - 1, sb + 1));
    end;
  end;

  if (ssCtrl in Shift) and (Key = VK_UP) and Navigation.CursorMoveRows and (st > FixedRows) then
  begin
    r := Row;
    if st = sb then
    begin
      MoveRow(st, st - 1);
      Row := r - 1;
    end
    else
    begin
      MoveRows(st, st - 1, sb - st + 1);
      Selection := TGridRect(Rect(FixedCols, st - 1, ColCount - 1, sb - 1));
    end;
  end;

  if Navigation.CursorAdvance <> caDefault then
  begin
    case Key of
    VK_LEFT:
      if FLastKeyCell.X = FixedCols then
      begin
        Col := ColCount - 1 - FixedRightCols;
        if snake then
          if Row > FixedRows then
            Row := Row - 1;
      end;
    VK_RIGHT:
      if FLastKeyCell.X  = ColCount - 1 then
      begin
        Col := FixedCols;
        if snake then
          if Row < RowCount - 1 - FixedFooters then
            Row := Row + 1;
      end;
    VK_UP:
      if FLastKeyCell.Y = FixedRows then
      begin
        Row := RowCount - 1 - FixedFooters;
        if snake then
          if Col > FixedCols then
            Col := Col - 1;
      end;
    VK_DOWN:
      if FLastKeyCell.Y = RowCount - 1 then
      begin
        Row := FixedRows;
        if snake then
          if Col < ColCount - 1 - FixedRightCols then
            Col := Col + 1;
      end;
    end;
  end;

  if FUseEnabledRows and Navigation.SkipDisabledRows and (r = Row) then
  begin
    case Key of
    VK_DOWN:
      begin
        if (r < RowCount - 1) then
        begin
          inc(r);
          while (r < RowCount - 1) and not RowEnabled[r] do
            inc(r);

          if (r <= RowCount - 1) and (RowEnabled[r]) then
            Row := r;
        end;
      end;
    VK_UP:
      begin
        if (r > FixedRows) then
        begin
          dec(r);
          while (r > FixedRows) and not RowEnabled[r] do
            dec(r);

          if (r >= FixedRows) and (RowEnabled[r]) then
            Row := r;
        end;
      end;
    end;
  end;

  if Assigned(SyncGrid.Grid) then
  begin
    if SyncGrid.SelectionColumn then
      SyncGrid.Grid.Col := Col;

    if SyncGrid.SelectionRow then
      SyncGrid.Grid.Row := Row;
  end;
end;

procedure TAdvStringGrid.MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);
var
  XSelection: TGridRect;
  c,r: Integer;
  cr: TRect;
  menu: TPopupMenu;
  pt: TPoint;
  keephighlighted: boolean;
  sz: integer;
begin
  XSelection := Selection;
  FFltrPopPressCol := -1;

  MouseToCell(x,y,c,r);

  if (MouseActions.RangeSelectAndEdit) and (Button = mbLeft) and not MouseActions.EditOnDblClickOnly then
  begin
    if (Col = c) and (Row = r) and not (goEditing in Options) and IsEditAble(RemapCol(c),r) then
    begin
      Options := Options + [goEditing];
      inherited;
      ShowInplaceEdit;
      Exit;
    end;

    if not ((Col = c) and (Row = r)) and (goEditing in Options) and (ssShift in Shift) then
    begin
      Options := Options - [goEditing];
      inherited;
      Exit;
    end;
  end;

  if (c <> -1) and (r <> -1) then
  begin
    CR := CellRect(c,r);
    sz := 0;

    if (goColSizing in Options) then
      sz := 2;

    if (X > CR.Right - 16) and (X < CR.Right - sz) and HoverFixedCell(c,r) and (ControlLook.FixedDropDownButton) then
    begin
      FDropDownDown := true;
      keephighlighted := false;

      if CanShowFixedDropDown(c) and (Assigned(FFixedDropDownMenu) or Assigned(FOnFixedDropDownClick)) then
      begin
        FNoMouseLeave := true;

        menu := FFixedDropDownMenu;
        if Assigned(Menu) then
          menu.Tag := c;

        if Assigned(FOnFixedDropDownClick) then
          FOnFixedDropDownClick(Self, c, r, menu, keephighlighted);

        if Assigned(Menu) then
        begin
          FMouseDownMove := false;
          FHoverFixedX := c;
          FHoverFixedY := r;
          RepaintCell(c,r);

          pt := ClientToScreen(point(CR.Right - 16, CR.Bottom));
          Menu.Popup(pt.X, pt.Y);

          FHoverFixedX := -1;
          FHoverFixedY := -1;
          RepaintCell(c,r);
        end;

        FNoMouseLeave := keephighlighted;
        Exit;
      end;
    end;

    if HoverFixedCell(c,r) and (ControlLook.FixedGradientDownFrom <> clNone) and (r = FixedRows - 1) then
      RepaintCell(c,r);
  end;
  {
  if (c >= 0) and (r >= 0) and ((c < FixedCols) or (r < FFixedRowsMin)) then
  begin
    if HasFilterEdit(c,r) then
    begin
      CR := CellRect(c,r);
      InflateRect(CR,-4,-4);
      CR.Left := CR.Left + 18;
      if PtInRect(CR, point(x,y)) then
        StartFixedEdit(c,r, true);
      Exit;
    end;
  end;
  }

  // if selected cell is hidden, ensure selection
  if (Col >= ColCount) or (Row >= RowCount) and (c >= 0) and (r >= 0) then
    FocusCell(c,r);

  FEditStart := true;

  inherited;

  FEditStart := false;

  if (ssShift in Shift) and (SelectionRectangle) then
  begin
    RepaintRect(TRect(Selection));
  end;

//  if not EqualRect(TRect(XSelection), TRect(Selection)) then
//  begin
//    SelectionChanged(Selection.Left, Selection.Top,Selection.Right, Selection.Bottom);
//  end;

  if (c >= 0) and (r >= 0) and ((c < FixedCols) or (r < FFixedRowsMin)) then
  begin
    if HasFilterEdit(c,r) then
    begin
      CR := CellRect(c,r);

      if (X > CR.Left) and (Y < CR.Top + 16) and (X < CR.Left + 16) then
        FFltrPopPressCol := c;

      InflateRect(CR,-4,-4);
      CR.Left := CR.Left + 18;


      if PtInRect(CR, point(x,y)) then
        StartFixedEdit(c,r, true);
      Exit;
    end;

    if (MouseActions.FixedRowsEdit = fceLeftClick) and (Button = mbLeft) and (r < FFixedRowsMin) then
    begin
      if (goColSizing in Options) then
      begin
        CR := CellRect(c,r);
        InflateRect(CR,-4,-4);
        if PtInRect(CR, point(x,y)) then
          StartFixedEdit(c,r);
      end
      else
        StartFixedEdit(c,r);
      Exit;
    end;

    if (MouseActions.FixedColsEdit = fceLeftClick) and (Button = mbLeft) and (c < FixedCols) then
    begin
      if (goRowSizing in Options) then
      begin
        CR := CellRect(c,r);
        InflateRect(CR,-4,-4);
        if PtInRect(CR, point(x,y)) then
          StartFixedEdit(c,r);
      end
      else
        StartFixedEdit(c,r);
      Exit;
    end;

    if (MouseActions.FixedRowsEdit = fceLeftClick) and (Button = mbRight) and (r < FixedRows) then
    begin
      StartFixedEdit(c,r);
      Exit;
    end;

    if (MouseActions.FixedColsEdit = fceLeftClick) and (Button = mbRight) and (c < FixedCols) then
    begin
      StartFixedEdit(c,r);
      Exit;
    end;
  end;

  if Assigned(SyncGrid.Grid) then
  begin
    if SyncGrid.SelectionColumn and (FUpdateCount = 0) then
      SyncGrid.Grid.Col := Col;

    if SyncGrid.SelectionRow then
      SyncGrid.Grid.Row := Row;
  end;
end;

procedure TAdvStringGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  r,c,i,j,k,tw,mw: Integer;
  XSelection: TGridRect;
  pt: TPoint;
  CanSelect: Boolean;
  DoSelChange: Boolean;
  RC, VP: integer;
  CR: TRect;
  s: string;
  LC: TRect;
  Allow: boolean;
  mh,nh: integer;
  sl: TStringList;
  isSizing: boolean;
begin
  if (csDesigning in ComponentState) then
  begin
    inherited;
    HandleDesignChoice(X,Y);
    Exit;
  end;

  DoSelChange := false;

  if not EqualRect(TRect(FOrigSelection), TRect(Selection)) and ((Button = mbLeft) or ((Button = mbRight) and MouseActions.SelectOnRightClick)) then
  begin
    DoSelChange := true;
  end;

  XSelection := Selection;

  MouseToCell(X,Y,C,R);
  RC := RealColIndex(C);

  IsSizing := FGridState = gsColSizing;

  if HasFilterEdit(C,R) and not IsSizing then
  begin
    CR := CellRect(C,R);
    if (X > CR.Left) and (Y < CR.Top + 16) and (X < CR.Left + 16) and (FFltrPopPressCol = c) then
    begin
      pt := Point(Cr.Left, cr.Bottom);
      pt := ClientToScreen(pt);

      FFltrPopup.Tag := RC;

      for i := 0 to FFltrPopup.Items.Count - 1 do
      begin
        if i < FilterEdit.TypeNames.Count then
          FFltrPopup.Items[i].Caption := FilterEdit.TypeNames[i];
      end;

      FFltrPopup.Popup(pt.x, pt.y);
      Exit;
    end;
  end;

  if (R = FilterDropDownRow) and (RC <> FilterColumn) and not IsSizing then
  begin
    CR := CellRect(C,R);

    if (X > CR.Right - 16) and (Y < CR.Top + 19) and
       (X < CR.Right - 3) and GetFilter(RC) then
    begin
      FilterColumn := RC;

      if FFilterDropDownCheck then
      begin
        DropCheckList.Color := FilterDropDown.Color;
        DropCheckList.Font.Assign(FilterDropDown.Font);
        DropCheckList.Canvas.Font.Assign(FilterDropDown.Font);
        DropCheckList.Items.Clear;
      end
      else
      begin
        DropList.Color := FilterDropDown.Color;
        DropList.Font.Assign(FilterDropDown.Font);
        DropList.Canvas.Font.Assign(FilterDropDown.Font);
        DropList.Items.Clear;
      end;

      mw := 0;

      for I := 1 to FFilterList.Count do
      begin
        VP := Pos(#9, FFilterList.Strings[I - 1]);
        if VP > 0 then
          s := Copy(FFilterList.Strings[I - 1],1,VP - 1)
        else
          s := FFilterList.Strings[I - 1];

        if FFilterDropDownCheck then
        begin
          DropCheckList.Items.Add(s);

          sl := TStringList.Create;

          for j := 0 to  Filter.Count - 1 do
          begin
            if pos(' ',s) <> 0 then
              s := '"'+s+'"';

            if (Filter.Items[j].Column = FilterColumn) then
            begin
              sl.Clear;

              SplitString('|',Filter.Items[j].FriendlyName,sl);

              for k := 0 to sl.Count - 1 do
              begin
                if pos(' ', sl[k]) <> 0 then
                  sl[k] := '"' + sl[k] + '"';
              end;

              if (sl.IndexOf(s) <> -1) then
              //if (Filter.Items[j].Condition = s) and  then
                DropCheckList.Checked[DropCheckList.Items.Count - 1] := true;
            end;
          end;

          sl.Free;

          tw := DropCheckList.Canvas.TextWidth(s) + 24;
        end
        else
        begin
          DropList.Items.Add(s);
          tw := DropList.Canvas.TextWidth(s) + 8;
        end;

        if tw > mw then
          mw := tw;

        if I = 1 then
        begin
          if not FFilterDropDownCheck then
            DropList.ItemIndex := 0;
        end;
      end;

      // do AutoSize
      if FilterDropDown.AutoSize then
      begin
        mh := Height - RowHeights[0];
        if VisibleColCount < ColCount then
          mh := mh - GetSystemMetrics(SM_CYHSCROLL);

        if FFilterDropDownCheck then
        begin
          nh := DropCheckList.ItemHeight * DropCheckList.Items.Count + 2 * GetSystemMetrics(SM_CYEDGE);
          DropCheckList.Height := Min(mh , nh);

          if nh > mh then
            mw := mw + GetSystemMetrics(SM_CXVSCROLL);

          DropCheckList.Width := mw + 2 * GetSystemMetrics(SM_CXEDGE);
        end
        else
        begin
          nh := DropList.ItemHeight * DropList.Items.Count + 2 * GetSystemMetrics(SM_CYEDGE);
          DropList.Height := Min(mh, nh);

          if nh > mh then
            mw := mw + GetSystemMetrics(SM_CXVSCROLL);

          DropList.Width := mw + 2 * GetSystemMetrics(SM_CXEDGE);
        end;
      end
      else
      begin
        if FFilterDropDownCheck then
        begin
          DropCheckList.Width := FilterDropDown.Width;
          DropCheckList.Height := FilterDropDown.Height;
        end
        else
        begin
          DropList.Width := FilterDropDown.Width;
          DropList.Height := FilterDropDown.Height;
        end;
      end;

      if FFilterDropDownCheck then
      begin
        DropCheckList.Top := cr.Top + 16;
        DropCheckList.Left := cr.Right - 16;
      end
      else
      begin
        DropList.Top := cr.Top + 16;
        DropList.Left := cr.Right - 16;
      end;

      if FilterDropDown.ColumnWidth then
      begin
        if FFilterDropDownCheck then
        begin
          DropCheckList.Width := CR.Right - CR.Left;
          DropCheckList.Left := CR.Left;
        end
        else
        begin
          DropList.Width := CR.Right - CR.Left;
          DropList.Left := CR.Left;
        end;
      end;

      // Prevent cropping of droplist
      LC := CellRect(C,0);

      Allow := true;
      DoFilterShow(C,Allow);

      if Allow then
      begin
        // Check if the right side of the droplist exceeds the right side of the grid
        //if ( DropList.Left + DropList.Width ) > Width then
        if FFilterDropDownCheck then
        begin
          if (DropCheckList.Left + DropCheckList.Width > Width) then
          begin
            DropCheckList.Left := LC.Right - DropCheckList.Width;
            if DropCheckList.Left < 0 then
              DropCheckList.Left := 0;
          end;

          DropCheckList.Parent := Self;
          DropCheckList.Visible := True;
          DropCheckList.SetFocus;
        end
        else
        begin
          if (DropList.Left + DropList.Width > Width) then
          begin
            DropList.Left := LC.Right - DropList.Width;
            if DropList.Left < 0 then
              DropList.Left := 0;
          end;

          DropList.Parent := Self;
          DropList.Visible := True;
          DropList.SetFocus;
        end;
      end;
    end
    else
    begin
      if DropList.Visible then
      begin
        DropList.Visible := false;
        DoFilterClose(FilterColumn);
      end;
      if DropCheckList.Visible then
      begin
        DropCheckList.Visible := false;
        DoFilterClose(FilterColumn);
      end;
      FilterColumn := -1;
    end;
  end
  else
  begin
    if DropList.Visible then
    begin
      DropList.Visible := false;
      DoFilterClose(FilterColumn);
    end;
    if DropCheckList.Visible then
    begin
      DropCheckList.Visible := false;
      DoFilterClose(FilterColumn);
    end;
    FilterColumn := -1;
  end;

  FDropDownDown := false;

  if (x > Width) and (FGridState = gsColSizing) then
  begin
    FGridState := gsNormal;
    Exit;
  end;

  if (y > Height) and (FGridState = gsRowSizing) then
  begin
    FGridState := gsNormal;
    Exit;
  end;

  if MouseActions.DisjunctCellSelect and (Button = mbLeft) and (c > -1) and (r > -1) then
  begin
    pt := BaseCell(c,r);

    if not IsFixed(pt.x,pt.y) then
    begin
      CanSelect := true;

      if Assigned(OnSelectCell) then
        OnSelectCell(Self, pt.X, pt.Y, CanSelect);

       if not CanSelect then
         Exit;

      if ssShift in Shift then
      begin
        FSelectedCells.Add(MakeLong(c,r));
        DoSelChange := true;
      end
      else
        if (ssCtrl in Shift) then
        begin
          i := FSelectedCells.IndexOf(Pointer(makelong(pt.x,pt.y)));
          if i = -1 then
            FSelectedCells.Add(MakeLong(pt.x,pt.y))
          else
            FSelectedCells.Delete(i);

          DoSelChange := true;
        end
        else
          begin
            // delete previous selections
            for i := 1 to FSelectedCells.Count do
              RepaintCell(loword(FSelectedCells.Items[i - 1]),hiword(FSelectedCells.Items[i - 1]));

            FSelectedCells.Clear;
            FSelectedCells.Add(MakeLong(pt.x,pt.y));
            DoSelChange := true;
          end;
    end
    else
    begin
      if MouseActions.DisjunctCellSelect and not (ssCtrl in Shift) and not IsFixed(C,R) then
      begin
        FSelectedCells.Clear;
        DoSelChange := true;
        Repaint;
      end;
    end;

    if (Selection.Left <> Selection.Right) or
       (Selection.Top <> Selection.Bottom) then
    begin
      for i := Selection.Left to Selection.Right do
      begin
        for j := Selection.Top to Selection.Bottom do
        begin
          if not ((i = pt.x) and (j = pt.y)) and not IsSelected(i,j) then
            FSelectedCells.Add(MakeLong(i,j));
        end;
      end;

      for i := 1 to FSelectedCells.Count do
        RepaintCell(loword(FSelectedCells.Items[i - 1]),hiword(FSelectedCells.Items[i - 1]));
    end;

    RepaintCell(c,r);
  end;

  if DoSelChange then
    SelectionChanged(XSelection.Left, XSelection.Top,XSelection.Right, XSelection.Bottom);

  if ((FGridState = gsColMoving) and (Button = mbRight)) then
    Exit
  else
    inherited;

  if HoverFixedCell(c,r) and (ControlLook.FixedGradientDownFrom <> clNone) and (r = FixedRows - 1) then
    RepaintCell(c,r);

//  if not (FGridState = gsNormal) then
//    inherited;

  if not EqualRect(TRect(XSelection), TRect(Selection)) then
  begin
    SelectionChanged(Selection.Left, Selection.Top,Selection.Right, Selection.Bottom);
  end;
end;

procedure TAdvStringGrid.CMMouseEnter(var Msg: TMessage);
begin
  inherited;

  if MouseActions.AutoFocus then
    if not (GetFocus = Handle) then SetFocus;
end;

procedure TAdvStringGrid.CMMouseLeave(var Msg: TMessage);
var
  hx,hy: Integer;
  p: TPoint;
  r: TRect;
begin
  inherited;

  if Assigned(PopupToolBar) and PopupToolBar.Visible and not EditMode then
  begin
    GetCursorPos(p);
    if not PopupToolbar.MouseInPopup(p) then
      PopupToolBar.Hide;
  end;

  FMouseSelectMode := msNormal;

  FSizeFixed := false;
  FSizeFixedR := false;

  if not FNoMouseLeave and (FHoverFixedCells <> hfNone) and ((FHoverFixedX <> -1) or (FHoverFixedY <> -1)) then
  begin
    hx := FHoverFixedX;
    hy := FHoverFixedY;
    FHoverFixedX := -1;
    FHoverFixedY := -1;
    RepaintCell(hx,hy);
  end;

  if (Look = glListView) then
  begin
    if (FHotFixedCell.X <> -1) and (FHotFixedCell.Y <> -1) and
     ((FHotFixedCell.X < FixedCols) or (FHotFixedCell.Y < FixedRows)) then
    begin
      RepaintCell(FHotFixedCell.X,FHotFixedCell.Y);
    end;
  end;

  if FHoverRow and (FHoverRowIdx <> -1) then
  begin
    hy := FHoverRowIdx;
    FHoverRowIdx := -1;
    RepaintRow(hy);
  end;

  if HoverButtons.Enabled then
  begin
    GetCursorPos(p);
    GetWindowRect(FButtonForm.Handle, R);
    if not PtInRect(R, p) then
      ShowWindow(FButtonForm.Handle, SW_HIDE);
  end;
end;

{$IFDEF DELPHIXE2_LVL}
procedure TAdvStringGrid.CMStyleChanged(var Message: TMessage);
begin
  InitVCLStyle(true);
end;
{$ENDIF}

procedure TAdvStringGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  ACol,ARow: longint;
  mrg,i,ff,wi: Integer;
  nondef: Boolean;
  s,Anchor,Stripped,FocusAnchor,AnchorHint: string;
  r,hr,cr: TRect;
  pt: TPoint;
  xsize,ysize,ml,hl,scrl: Integer;
  ctt: TTextType;
  Allow: Boolean;
  dwEffects: Integer;
  DropSource: TGridDropSource;
  CID,CV,CT: string;
  OldSel,XSelection: TGridRect;
  cc,rc,offs,offsy: Integer;
  SmartResize: boolean;
  irsel,allowmoving: Boolean;
  gr: TGridRect;
  sp: TScrollProp;
  ms: TMemoryStream;
  hovold: TPoint;
  clr1,clr2,clr3: TColor;
  st: TGridDrawState;
  gd: TCellGradientDirection;
  ha: TAlignment;
  va: TVAlignment;
  ww: boolean;
  dx,dy: integer;
  spb: TAsgSpeedButton;
  cond: boolean;
  isdir: boolean;

  function IsLeftPressed: boolean;
  var
    fResult: integer;
  begin
     fResult := GetSystemMetrics(SM_SWAPBUTTON);
     if fResult = 0 then
       Result := (GetAsyncKeyState(VK_LBUTTON) and $8000) <> 0
     else
       Result := (GetAsyncKeyState(VK_RBUTTON) and $8000) <> 0;
  end;

begin
  if FMouseDownMove and FMouseActions.RangeSelectAndEdit and (goEditing in Options) and not EditMode then
  begin
    Options := Options - [goEditing];
  end;

  dx := 0;
  dy := 0;
  if FScrollStart and (ptdown.y <> -1) then
  begin
    dy := ptdown.y - y;
  end;

  if FScrollStart and (ptdown.x <> -1) then
  begin
    dx := ptdown.x - x;
  end;

  isdir := abs(dx) > abs(dy);

  if FScrollStart and (ptdown.y <> -1) and not isdir and (RowCount > VisibleRowCount + FixedRows) then
  begin
    dy := ptdown.y - y;
    TopRow := FTopDown + dy div defaultrowheight;
  end;

  if FScrollStart and (ptdown.x <> -1) and isdir and (ColCount > VisibleColCount + FixedCols) then
  begin
    dx := ptdown.x - x;
    LeftCol := Max(FixedCols, (FLeftRight + dx div DefaultColWidth));
  end;

  NonDef := False;
  irsel := False;

  XSelection := Selection;
  OldSel := Selection;

  if SelectionRectangle then
  begin
    if (gsSelecting = FGridState) then
    begin
      if not EqualRect(TRect(Selection),TRect(FSizeSelection)) then
      begin
        //Invalidate;
        FSizeSelection := Selection;
      end;
    end;
  end;

  MouseToCell(X,Y,ACol,ARow);

  if Assigned(PopupToolBar) and (PopupToolBarMode <> tbNone) then
  begin

    if PopupToolBarMode = tbActiveCell then
    begin

      if (ACol = Col) and (ARow = Row) and not PopupToolBar.Visible then
      begin
        FToolBarPopupCell.X := ACol;
        FToolBarPopupCell.Y := ARow;
        r := CellRect(ACol,ARow);
        PopupToolBar.Grid := Self;
        PopupToolBar.GridCell := FToolBarPopupCell;
        PopupToolBar.Show(ClientToScreen(Point(r.Left,r.Top - 44)));
      end;

      if ((ACol <> Col) or (ARow <> Row)) and Assigned(PopupToolBar) and PopupToolBar.Visible then
      begin
        PopupToolBar.Hide;
      end;
    end;

    if (PopupToolBarMode in [tbHoverCell, tbHoverNormalCell]) then
    begin

      if ((ACol <> FToolBarPopupCell.X) or (ARow <> FToolBarPopupCell.Y)) and not PopupToolBar.Visible then
      begin
        if not IsFixed(ACol,ARow) or (PopupToolbarMode = tbHoverCell) then
        begin
          FToolBarPopupCell.X := ACol;
          FToolBarPopupCell.Y := ARow;
          r := CellRect(ACol,ARow);

          PopupToolBar.Grid := Self;
          PopupToolBar.GridCell := FToolBarPopupCell;
          PopupToolBar.Show(ClientToScreen(Point(r.Left,r.Top - 44)));
        end;
      end;

      if ((ACol <> FToolBarPopupCell.X) or (ARow <> FToolBarPopupCell.Y)) and PopupToolBar.Visible then
      begin
        PopupToolBar.Hide;
      end;
    end;
  end;

  if not (csDesigning in ComponentState) then
  begin
    if (ACol >= 0) and (ARow >= 0) then
    begin
      if (ARow <> FHoverRowIdx) and FHoverRow then
      begin
        i := FHoverRowIdx;
        FHoverRowIdx := ARow;
        RepaintRow(FHoverRowIdx);
        if (i >= 0) and (i < RowCount) then
          RepaintRow(i);
      end;

      if HasScrollbar(ACol,ARow) then
      begin
        FScrollCol := ACol;
        FScrollRow := ARow;
        R := CellRect(ACol,ARow);
        FScrollBar.Position := GetScrollPosition(ACol,ARow);
        sp := GetScrollProp(ACol,ARow);

        if (sp.PageSize < sp.Range) and
           (
           (FScrollBar.Top <> R.Top + GridLineWidth) or
           (FScrollBar.Left <> R.Right - FScrollBar.Width - GridLineWidth) or
           (FScrollBar.Visible = false)
           ) then
        begin
          FScrollBar.PageSize := sp.PageSize;
          FScrollBar.Min := 0;
          FScrollBar.Max := sp.Range;
          FScrollBar.Width := 17;
          FScrollBar.Top := R.Top + GridLineWidth;
          FScrollBar.Left := R.Right - FScrollBar.Width - GridLineWidth;
          FScrollBar.Height := R.Bottom - R.Top - 2 * GridLineWidth;
          FScrollBar.Position := GetScrollPosition(ACol,ARow);
          FScrollBar.Visible := true;
        end;
        //CellControlsUpdate;
      end
      else
        FScrollBar.Visible := false;

      cond := (HoverButtons.Rows = hrAll) or (ARow >= FixedRows);

      if HoverButtons.Enabled and (HoverButtons.Buttons.Count > 0) and cond then
      begin
        FHoverButtonRow := ARow;

        if HoverButtons.MoveActiveRow then
          Row := ARow;

        wi := 0;

        if (FButtonForm.ControlCount = 0) then
        begin
          for i := 0 to HoverButtons.Buttons.Count - 1 do
          begin
            spb := TAsgSpeedButton.Create(FButtonForm);
            spb.Images := GridImages;
            spb.ImageIndex := HoverButtons.Buttons[i].ImageIndex;
            spb.Picture.Assign(HoverButtons.Buttons[i].Picture);
            spb.Hint := HoverButtons.Buttons[i].Hint;
            spb.ShowHint := spb.Hint <> '';
            spb.Flat := HoverButtons.Buttons[i].Flat;
            spb.Enabled := HoverButtons.Buttons[i].Enabled;
            spb.Caption := HoverButtons.Buttons[i].Caption;
            spb.Parent := FButtonForm;
            spb.Left := wi;
            spb.Tag := i;
            spb.Top := 0;
            spb.OnClick := HoverButtonClick;

            if HoverButtons.Buttons[i].Width > 0 then
              spb.Width := HoverButtons.Buttons[i].Width;

            wi := wi + spb.Width;
          end;
        end;

        if wi > 0 then
          FButtonForm.Width := wi;

        r := CellRect(HoverButtons.Column, ARow);

        case HoverButtons.Position of
        hbRightFromColumnRight: pt := Point(r.Right,r.Top);
        hbLeftFromColumnRight: pt := Point(r.Right,r.Top);
        hbRightFromColumnLeft: pt := Point(r.Left,r.Top);
        hbLeftFromColumnLeft: pt := Point(r.Left,r.Top);
        end;

        pt := ClientToScreen(pt);

        case HoverButtons.Position of
        hbLeftFromColumnRight, hbLeftFromColumnLeft: pt.X := pt.X - FButtonForm.Width;
        end;

        SetWindowPos(FButtonForm.Handle, HWND_TOPMOST, pt.x, pt.y, FButtonForm.Width, FButtonForm.Height,
          SWP_NOACTIVATE);
        ShowWindow(FButtonForm.Handle, SW_SHOWNOACTIVATE);
      end
      else
        if HoverButtons.Enabled and not cond then
          ShowWindow(FButtonForm.Handle, SW_HIDE);

    end
    else
    begin
      if HoverButtons.Enabled then
        ShowWindow(FButtonForm.Handle, SW_HIDE);
    end;
  end;

  if (FHoverFixedCells <> hfNone) and not FNoMouseLeave then
  begin
    xsize := FHoverFixedX;
    ysize := FHoverFixedY;
    FHoverFixedX := ACol;
    FHoverFixedY := ARow;

    if ((ysize <= FixedRows) and (ysize >= 0)) or
       ((xsize <= FixedCols) and (xsize >= 0)) then
      if (xsize <> FHoverFixedX) or (ysize <> FHoverFixedY) then
        RepaintCell(xsize,ysize);

    if ((FHoverFixedY <= FixedRows) and (FHoverFixedY >= 0)) or
       ((FHoverFixedX <= FixedCols) and (FHoverFixedX >= 0)) then
      if (xsize <> FHoverFixedX) or (ysize <> FHoverFixedY) then
        RepaintCell(FHoverFixedX, FHoverFixedY);
  end;

  if (Look = glListView) then
  begin
    if (FHotFixedCell.X <> ACol) or (FHotFixedCell.Y <> ARow) then
    begin
      if (FHotFixedCell.X <> -1) and (FHotFixedCell.Y <> -1) and
       ((FHotFixedCell.X < FixedCols) or (FHotFixedCell.Y < FixedRows)) then
      begin
        RepaintCell(FHotFixedCell.X,FHotFixedCell.Y);
      end;

      FHotFixedCell.X := ACol;
      FHotFixedCell.Y := ARow;

      if (FHotFixedCell.X <> -1) and (FHotFixedCell.Y <> -1) and
         ((ACol < FixedCols) or (ARow < FixedRows)) then
      begin
        RepaintCell(FHotFixedCell.X,FHotFixedCell.Y);
      end;
    end;
  end;

  if HasButton(ACol,ARow) and PtInRect(ButtonRect(ACol,ARow),Point(X,Y)) then
  begin
    if (FHoverButton.X <> ACol) or (FHoverButton.Y <> ARow) then
    begin
      if (FHoverButton.X <> -1) and (FHoverButton.Y <> -1) then
        RepaintCell(FHoverButton.X, FHoverButton.Y);

      FHoverButton := Point(ACol,ARow);
      RepaintCell(FHoverButton.X, FHoverButton.Y);
    end;
  end
  else
  begin
    if HasExpand(ACol,ARow) and PtInRect(ExpandRect(ACol,ARow),Point(X,Y)) then
    begin
      if (FHoverButton.X <> ACol) or (FHoverButton.Y <> ARow) then
      begin
        if (FHoverButton.X <> -1) and (FHoverButton.Y <> -1) then
          RepaintCell(FHoverButton.X, FHoverButton.Y);

        FHoverButton := Point(ACol,ARow);
        RepaintCell(FHoverButton.X, FHoverButton.Y);
      end;
    end
    else
    begin
      if (FHoverButton.X <> -1) and (FHoverButton.Y <> -1) then
        RepaintCell(FHoverButton.X, FHoverButton.Y);
      FHoverButton := Point(-1,-1);
    end;
  end;

  if (FMouseSelectStart <> - 1) and
     (MouseActions.RowSelect) and
     (FMouseSelectMode = msRow) then
  begin
    if (ARow >= FixedRows) and (ARow <= RowCount - FixedFooters) then
    begin
      if (ARow > FMouseSelectStart) then
        Selection := TGridRect(Rect(FixedCols,FMouseSelectStart,ColCount - 1, Max(FixedRows,ARow)))
      else
        Selection := TGridRect(Rect(FixedCols,Max(FixedRows,ARow),ColCount - 1, FMouseSelectStart));

      if SelectionRectangle then
      begin
        if not EqualRect(TRect(Selection),TRect(FSizeSelection)) then
          RepaintRect(Rect(LeftCol, Selection.Top, LeftCol + VisibleColCount, Selection.Bottom));
        FSizeSelection := Selection;
      end;
    end;

    if (Y > Height - 4) then
      TopRow := TopRow + 1;

    if (FixedRows > 0) and (RowCount > 0) and (Y < RowHeights[0]) and (TopRow > FixedRows) then
    begin
      TopRow := TopRow - 1;
      irsel := true;
    end;
  end;

  if (FMouseSelectStart <> - 1) and
     (MouseActions.ColSelect) and
     (FMouseSelectMode = msColumn) then
  begin
    if ACol > FMouseSelectStart then
      Selection := TGridRect(Rect(FMouseSelectStart,FixedRows,Max(FixedCols,ACol),RowCount - 1))
    else
      Selection := TGridRect(Rect(Max(FixedCols,ACol),FixedRows,FMouseSelectStart,RowCount - 1));

    if SelectionRectangle then
    begin
      if not EqualRect(TRect(Selection),TRect(FSizeSelection)) then
        RepaintRect(Rect(Selection.Left, TopRow, Selection.Right, TopRow + VisibleRowCount));
      FSizeSelection := Selection;
    end;
  end;

  FSizeFixed := False;

  Offs := 0;

  for i := 1 to FixedCols do
  begin
    if (Abs(ColWidths[i - 1] + Offs - X) < 3) and (FixedCols > 0) and
        (ACol >= 0) and (ARow >= 0) and not (csDesigning in ComponentState) then
    begin
      FSizeFixed := FMouseActions.SizeFixedCol;
    end;
    Offs := Offs + ColWidths[i - 1] + 1;
  end;

  if FSizingFixed then
  begin
    DrawSizingLine(FSizeFixedX);
    FSizeFixedX := X;
    DrawSizingLine(FSizeFixedX);
  end;

  FSizeFixedR := False;

  Offsy := 0;
  for i := 1 to FixedRows do
  begin
    if (Abs(RowHeights[i - 1] + Offsy - Y) < 3) and (FixedRows > 0) and
        (ACol >= 0) and (ARow >= 0) and not (csDesigning in ComponentState) then
    begin
      FSizeFixedR := FMouseActions.SizeFixedRow;
    end;
    Offsy := Offsy + RowHeights[i - 1] + 1;
  end;


  if FSizingFixedR then
  begin
    DrawSizingLineR(FSizeFixedY);
    FSizeFixedY := Y;
    DrawSizingLineR(FSizeFixedY);
  end;

  SmartResize := false;

  if SelectionResizer and SelectionRectangle then
  begin
    r := CellRect(Selection.Right,Selection.Bottom);

    if (ACol >= FixedCols) and
       (ARow >= FixedRows) and ControlLook.DropDownAlwaysVisible and HasCombo(RealColIndex(ACol),ARow) then
      begin
        r.Right := r.Right - Round(ControlLook.DropDownButtonWidth * FDPIScale);
      end;

    r.Top := r.Bottom - Round(6 * FDPIScale);

    if BidiMode = bdLeftToRight then
      r.Left := R.Right - Round(6 * FDPIScale)
    else
      r.Right := R.Left + Round(6 * FDPIScale);

    if PtInRect(r,Point(x,y)) then
    begin
      SmartResize := true;
    end;
  end;

  if FSelectionClick and (ACol >= 0) and (ARow >= 0) and
     IsLeftPressed and ((Abs(ClickPosX - X) > 3) or (Abs(ClickPosY - Y) > 3)) and
     FDragDropSettings.FOleDropSource and not (FGridState = gsColsizing) and not SmartResize  then
  begin
    FSelectionClick := False;
    Allow := True;
    ACol := RemapCol(ACol);

    if FDragDropSettings.OleColumnsOnly and (ARow >= FixedRows) then
      Allow := false
    else
     if Assigned(FOnOleDrag) then
        FOnOleDrag(self,ARow,ACol,Cells[ACol,ARow],Allow);

    if Allow then
    begin
      DropSource := TGridDropSource.Create(self);
      if Assigned(FOnOleDragStart) then
        FOnOleDragStart(Self,ARow,ACol);

      pt := ClientToScreen(point(x,y));

      DoStartBlockFocus;

      if DragDropSettings.ShowCells then
      begin
        if not Assigned(MoveForm) then
        begin
          ShowSelection := false;

          if FDragDropSettings.OleColumnDragDrop then
          begin
            gr := TGridRect(Rect(ACol,0,ACol,VisibleRowCount));
          end
          else
            gr := TGridRect(Rect(Max(LeftCol,Selection.Left),Max(TopRow,Selection.Top),
              Min(Selection.Right,LeftCol + VisibleColCount - 1 {- FixedCols}),Min(Selection.Bottom,TopRow + VisibleRowCount - 1{- FixedRows})));

          MoveForm := SelectionToForm(gr);
          ShowSelection := true;
          SetWindowPos(MoveForm.Handle,HWND_TOPMOST,0,0,0,0,SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
        end;

        if Assigned(MoveForm) then
        begin
          if BiDiMode = bdRightToLeft then
            MoveForm.Left := pt.X - MoveForm.Width + ColWidths[0]
          else
            MoveForm.Left := pt.X;

          MoveForm.Top := pt.Y;
        end;
      end;

      if (ARow < FixedRows) and (ACol >= 0) and DragDropSettings.OleColumnDragDrop then
      begin
        if not DragDropSettings.ShowCells then
        begin
          MoveButton.Left := pt.x;
          MoveButton.Top := pt.y;
          MoveButton.Width := ColWidths[ACol];
          MoveButton.Height := RowHeights[0];
          MoveButton.Caption := Cells[ACol,ARow];
          MoveButton.Visible := True;
          SetWindowPos(MoveButton.Handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
        end;

        if not (StartColDoDragDrop(DropSource,ACol,DROPEFFECT_COPY or DROPEFFECT_MOVE,dwEffects) = DRAGDROP_S_CANCEL) then
        begin
          // do a full Column d&d here
          if Assigned(FOnOleDragStop) then
            FOnOleDragStop(Self,dwEffects);
        end;

       MoveButton.Visible := False;
       ArwD.Visible := False;
       ArwU.Visible := False;
      end
     else
      begin
        FDropSelection := Selection;

        if Navigation.AllowFmtClipboard then
        begin
          ms := TMemoryStream.Create;
          SaveRectToBinStream(TRect(Selection),ms);
        end
        else
          ms := nil;

        if not (StartTextDoDragDrop(DropSource,SelectedText,Cells[ACol,ARow], ms, DROPEFFECT_COPY or DROPEFFECT_MOVE,dwEffects) = DRAGDROP_S_CANCEL) then
        begin
          if not FDragDropSettings.OleCopyAlways then
          begin
            if dwEffects = DROPEFFECT_MOVE then
              if FDragDropSettings.FOleRemoveRows and (goRowSelect in Options) then
              begin
                if FMouseActions.DisjunctRowSelect then
                  RemoveSelectedRows
                else
                  RemoveRowsInternal(FDropSelection.Top,FDropSelection.Bottom - FDropSelection.Top + 1);
              end
              else
              begin
                if not DragDropSettings.OleCopyAlways then
                begin
                  if FMouseActions.DisjunctRowSelect then
                    ClearSelection
                  else
                    ClearRect(FDropSelection.Left,FDropSelection.Top,FDropSelection.Right,FDropSelection.Bottom);
                end;
              end;
          end;

          if Assigned(FOnOleDragStop) then
            FOnOleDragStop(self,dwEffects);
        end;

        if Assigned(ms) then
          ms.Free;

       end
     end
    else
      if FGridState = gsNormal then
        FGridState := gsSelecting;
  end;

  if not (csDesigning in Componentstate) then
  begin
    if FGridState = gsColSizing then
      Colsized := True;

    if FGridState = gsRowSizing then
      RowSized := True;

    if FGridState = gsColMoving then
    begin
      Allow := True;
      if Assigned(FOnColumnMove) then
        FOnColumnMove(Self,MoveCell,Allow);
      if not Allow then
      begin
        FGridState := gsNormal;
      end;
    end;

    if FGridState = gsRowMoving then
    begin
      Allow := True;
      if Assigned(FOnRowMove) then
        FOnRowMove(Self,MoveCell,Allow);
      if not Allow then
      begin
        FGridState := gsNormal;
      end;
    end;

    if (FGridState in [gsColMoving,gsRowMoving]) and (RowCount > 1) and
       ( (clickposx <> x) or (clickposy <> y)) and FEnhRowColMove and not FSizingFixed and not FSizingFixedR then
    begin
      allowmoving := true;

      DoStartBlockFocus;

      if (FGridState = gsColMoving) and (MoveCell >= FixedCols) and (ARow >= 0) then
      begin
        if not Assigned(MoveForm) and DragDropSettings.ShowCells then
        begin
          MoveForm := SelectionToForm(TGridRect(Rect(MoveCell,0,MoveCell,TopRow + VisibleRowCount - FixedRows)));
          SetWindowPos(MoveForm.Handle,HWND_TOPMOST,0,0,0,0,SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
        end;

        MoveButton.Caption := Cells[RemapCol(MoveCell),0];
        MoveButton.Width := ColWidths[MoveCell];
        MoveButton.Height := RowHeights[ARow];
        MoveButton.Invalidate;
      end;

      if (FGridState = gsRowMoving) and (MoveCell >= FixedRows) and (ACol >= 0) then
      begin
        if not Assigned(MoveForm) and DragDropSettings.ShowCells then
        begin
          MoveForm := SelectionToForm(TGridRect(Rect(0, MoveCell, LeftCol + VisibleColCount - FixedCols, MoveCell)));
          SetWindowPos(MoveForm.Handle,HWND_TOPMOST,0,0,0,0,SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
        end;
        MoveButton.Caption := Cells[0,MoveCell];
        MoveButton.Height := RowHeights[MoveCell];
        MoveButton.Width := ColWidths[ACol];
        MoveButton.Invalidate;
      end;

      pt := ClientToScreen(point(x - moveofsx,y - moveofsy));

      if not DragDropSettings.ShowCells then
      begin
        MoveButton.Left := pt.x;
        MoveButton.Top := pt.y;
      end
      else
      begin
        if Assigned(MoveForm) then
        begin
          if BiDiMode = bdRightToLeft then
            MoveForm.Left := pt.X - MoveForm.Width + ColWidths[0]
          else
            MoveForm.Left := pt.x;

          MoveForm.Top := pt.y;
        end
        else
        begin
          FGridState := gsNormal;
          allowmoving := False;
        end; // if Assigned(MoveForm) then
      end;

      if FGridState = gsColMoving then
      begin
        if (FMoveColInd >= FixedCols) and (FMoveColInd >= 0) and (ACol >= 0) then
        begin
          r := CellRect(FMoveColInd,0);
          r.Topleft := ClientToScreen(r.Topleft);
          r.Bottomright := ClientToScreen(r.Bottomright);

          if FMoveColInd < movecell then
          begin
            ArwU.Top := r.Bottom;
            ArwU.Left := r.Left - 5;
            ArwD.Top := r.Top - 8;
            ArwD.Left := r.Left - 5;
          end
          else
          begin
            ArwU.Top := r.Bottom;
            ArwU.Left := r.Left - 5 + ColWidths[FMoveColInd];
            ArwD.Top := r.Top - 8;
            ArwD.Left := r.Left - 5 + ColWidths[FMoveColInd];
          end;
        end;
        ArwD.Visible := (FMoveColind >= FixedCols) and (FMoveColInd - LeftCol < VisibleColCount);
        ArwU.Visible := (FMoveColind >= FixedCols) and (FMoveColInd - LeftCol < VisibleColCount);

        FMoveColInd := ACol;
        FMoveRowInd := 0;

        if Assigned(FOnColumnMoving) then
          FOnColumnMoving(Self, FMoveColInd, allowmoving);
      end;

      if FGridState = gsRowMoving then
      begin
        if not ((FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow)) and
           (FMoveRowInd = RowCount - 1)) then

        if (FMoveRowInd >= FixedRows) and (FMoveRowInd - TopRow < VisibleRowCount) and (ARow >= 0) then
        begin
          r := CellRect(0,FMoveRowInd);
          r.Topleft := ClientToScreen(r.Topleft);
          r.Bottomright := ClientToScreen(r.Bottomright);

          if FMoveRowInd < movecell then
          begin
            ArwL.Top := r.Top - 5;
            ArwL.Left := r.Left - 10;
            ArwR.Top := r.Top - 5;
            ArwR.Left := r.Right;
          end
          else
          begin
            ArwL.Top := r.Top - 5 + RowHeights[FMoveRowInd];
            ArwL.Left := r.Left - 10;
            ArwR.Top := r.Top - 5 + RowHeights[FMoveRowInd];
            ArwR.Left := r.Right;
          end;
        end;
        ArwR.Visible :=(FMoveRowInd >= FixedRows) and (FMoveRowInd - TopRow < VisibleRowCount) ;
        ArwL.Visible :=(FMoveRowInd >= FixedRows) and (FMoveRowInd - TopRow < VisibleRowCount) ;
        FMoveColInd := 0;
        FMoveRowInd := ARow;

        if Assigned(FOnRowMoving) then
          FOnRowMoving(Self, FMoveRowInd, allowmoving);
      end;

      if (FGridState = gsColMoving) and (VisibleColCount < ColCount) then
      begin
        mrg := 0;
        for i := 1 to FixedCols do
          mrg := mrg + ColWidths[i - 1];
        if (x < mrg) and (LeftCol > FixedCols) then
        begin
          LeftCol := LeftCol - 1;
          Repaint;
        end;
        if (x > Width) and (LeftCol + VisibleColCount < ColCount) then
        begin
          LeftCol := LeftCol + 1;
          Repaint;
        end;
      end;

      if (FGridState = gsRowMoving) and (VisibleRowCount < RowCount) then
      begin
        mrg := 0;
        for i := 1 to FixedRows do
          mrg := mrg + RowHeights[i-1];
        if (y < mrg) and (TopRow > FixedRows) then
        begin
          TopRow := TopRow - 1;
          Repaint;
        end;
        if (y > Height) and (TopRow + VisibleRowCount < RowCount) then
        begin
          TopRow := TopRow + 1;
          Repaint;
        end;
      end;

      if not MoveButton.Visible then
      begin
        MoveButton.Visible := not DragDropSettings.ShowCells;
        Windows.SetFocus(Parent.Handle);
      end;

      if not MoveButton.Enabled then
        MoveButton.Enabled := True;

      if not allowmoving then
        Screen.Cursor := crNoDrop
      else
        Screen.Cursor := crDrag;

      if (not allowmoving) and (FGridState = gsNormal) then 
        Screen.Cursor := FOldCursor;
      //if Screen.Cursor <> crDrag then
      //  Screen.Cursor := crDrag;
    end;

    FMouseSelectMode := msNormal;

    if SmartResize then
      FMouseSelectMode := msResize;

    if (ARow < FixedRows) and
       (ARow >= 0) and (ACol >= 0) and
       (ACol < self.FixedCols) and
       (FMouseActions.AllSelect) then
    begin
      NonDef := True;
      Invokedchange := True;
      FMouseSelectMode := msAll;
    end;

    if (ARow < self.FixedRows) and
       (ARow >= 0) and (ACol >= 0) and
       (ACol >= FixedCols) and
       (FMouseActions.ColSelect) and not InSizeZone(x,y) then
    begin
      Nondef := True;
      Invokedchange := True;
      FMouseSelectMode := msColumn;
    end;

    if FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) then
      ff := 2
    else
      ff := 1;

    if (ACol < FixedCols) and
       (ARow >= 0) and (ACol >= 0) and (ARow <= RowCount - ff) and
       ((ARow >= FixedRows) or (irsel)) and
       (FMouseActions.RowSelect) and not InSizeZone(x,y) and not InNodeRect(ARow,x) then
    begin
      NonDef := True;
      InvokedChange := True;
      FMouseSelectMode := msRow;
    end;
  end;

  MouseToCell(x,y,ACol,ARow);

  if (ACol < ColCount) and (ARow < RowCount) and
     (ACol >= 0) and (ARow >= 0) then
    begin
      s := Cells[RemapCol(ACol),ARow];
      ctt := TextType(s,FEnableHTML);

      if URLShow and (ctt <> ttHTML) {$IFDEF CUSTOMIZED} or (pos('*',s)=1) {$ENDIF} then
      begin
        if IsURL(s) {$IFDEF CUSTOMIZED}  or (pos('*',s)=1) {$ENDIF}  then
        begin
          NonDef := True;
          InvokedChange := True;
          if Cursor <> crURLcursor then
            inherited Cursor := crURLcursor;
        end;
      end;

      if ctt = ttHTML then
      begin
        r := CellRect(ACol,ARow);
        r.Left := r.Left + 1 + FXYOffset.X;
        r.Top := r.Top + 1 + FXYOffset.Y;
        r.right := r.Right - FXYOffset.X;

        if HasCheckBox(ACol,ARow) then
          r.Left := r.Left + ControlLook.CheckSize;

        if HasScrollBar(ACol,ARow) then
        begin
          scrl := GetScrollPosition(ACol,ARow);
          r.Right := r.Right - GetSystemMetrics(SM_CXVSCROLL);
          r.Bottom := r.Bottom + scrl;
        end
        else
          scrl := 0;

        if IsFixed(ACol,ARow) then
          Canvas.Font.Assign(FixedFont)
        else
          Canvas.Font.Assign(Font);

        st := [];
        GetVisualProperties(ACol,ARow,st,false,false,false,Canvas.Brush, clr1, clr2, clr3, Canvas.Font,ha,va,ww,gd);

        if not HTMLDrawEx(Canvas,s,r,GridImages,x,y + scrl,-1,0,1,True,False,False,True,True,False,not EnhTextSize,False,'',
                          0.0,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,xsize,ysize,
                          ml,hl,hr,cr,CID,CV,CT,FImageCache,FContainer,self.Handle,BidiMode) then
          Anchor := '';

        if FURLUnderlineOnHover then
        begin
          if (((FHoverCell.X <> ACol) or (FHoverCell.Y <> ARow)) and (FHoverCell.X >= 0) and (FHoverCell.Y >= 0)) or
            (FHoverLink <> -1) then
          begin
            hovold := FHoverCell;
            FHoverCell := Point(ACol,ARow);
            RepaintCell(hovold.X, hovold.Y);
          end;

          if ((FHoverCell.X <> ACol) or (FHoverCell.Y <> ARow) or (FHoverLink <> -1)) or (FHoverLink <> hl)  then
          begin
            FHoverCell := Point(ACol,ARow);
            FHoverLink := hl;
            RepaintCell(ACol, ARow);
          end;

        end;

        if (Anchor <> '') or (AnchorHint <> '') then
        begin
          if Assigned(FOnAnchorHint) then
          begin
            if (AnchorHint <> '') then
              FOnAnchorHint(Self, ARow, ACol, AnchorHint)
            else
              FOnAnchorHint(Self, ARow, ACol, Anchor)
          end;

          if (AnchorHint <> FLastAnchorHint) and (FLastAnchorHint <> '') and (Anchor <> FAnchor) then
          begin
            FLastAnchorHint := AnchorHint;
            Application.CancelHint;
          end;

          NonDef := True;
          InvokedChange := True;
          if Cursor <> crURLcursor then
            inherited Cursor := crURLcursor;

          if Anchor <> FAnchor then
          begin
            if Assigned(FOnAnchorEnter) then
              FOnAnchorEnter(self,ARow,ACol,Anchor);
            FAnchor := Anchor;
          end;
        end
        else
        begin
          if FAnchor <> '' then
          begin
            if Assigned(FOnAnchorExit) then
              FOnAnchorExit(Self,ARow,ACol,Anchor);
            FAnchor := Anchor;
          end;
        end;
      end
      else
      begin
        if FURLUnderLineOnHover then
        begin
          if (((FHoverCell.X <> ACol) or (FHoverCell.Y <> ARow)) and (FHoverCell.X >= 0) and (FHoverCell.Y >= 0)) or
            (FHoverLink <> -1) then
          begin
            FHoverlink := -1;
            RepaintCell(FHoverCell.X, FHoverCell.Y);
            FHoverCell := Point(-1,-1);
          end;
        end;
      end;
   end;


  if not NonDef and (Cursor <> FOldCursor) then
  begin
    InvokedChange := True;
    Cursor := FOldCursor;
  end;

  if (FLastHintPos.x >= 0) and (FLastHintPos.y >= 0) then
  begin
    MouseToCell(x,y,ACol,ARow);
    IsBaseCellEx(ACol,ARow,ACol,ARow);
    if (ACol <> FLastHintPos.x) or (ARow <> FLastHintPos.y) then
    begin
      Application.CancelHint;
      FLastHintPos := Point(-1,-1);
    end;
  end;

  if (FLastBalloonPos.X >= -1) and (FLastBalloonPos.Y >= -1) and (Balloon.Enable) then
  begin
    MouseToCell(x,y,ACol,ARow);
    IsBaseCellEx(ACol,ARow,ACol,ARow);
    if (ACol <> FLastBalloonPos.x) or (ARow <> FLastBalloonPos.y) then
    begin
      SendMessage(FHToolTip, TTM_POP, 0, 0);
      FLastBalloonPos := Point(-1,-1);
    end;
  end;

  if (gsSelecting = FGridState) and FSelectionRectangle and
     ((FMoveSelection.Top <> Selection.Top) or
     (FMoveSelection.Right <> Selection.Right) or
     (FMoveSelection.Bottom <> Selection.Bottom) or
     (FMoveSelection.Left <> Selection.Left)) then
  begin //old selection and new selection ?
    InvalidateGridrect(Selection);
    FMoveselection := Selection;
  end;

  // 2.6.0.1
  //if (RowCount = 1) or (ColCount = FixedCols) then
  //  FGridState := gsNormal;

  inherited MouseMove(Shift, X, Y);

  //+++2.6.0.3
  if Navigation.KeepHorizScroll and FMouseKeepDown and not (FGridState = gsColMoving) then
  begin
    StartUpdate;
    LeftCol := FOldKeepLeftCol;
    ResetUpdate;
  end;
  //---2.6.0.3

  if ((FGridState = gsColSizing) or FSizingFixed) and Assigned(OnColumnSizing)  then
  begin
    if FSizingFixed then
    begin
      OnColumnSizing(Self, 0, FSizeFixedX);
    end
    else
    begin
      r := CellRect(ColClicked,ARow);
      OnColumnSizing(Self, ColClicked, x - r.Left - ClickPosDx);
    end;
  end;

  if ((FGridState = gsRowSizing) or FSizingFixedR) and Assigned(OnRowSizing)  then
  begin
    if FSizingFixedR then
    begin
      OnRowSizing(Self, 0, FSizeFixedY);
    end
    else
    begin
      OnRowSizing(Self, RowClicked, y - r.Top - ClickPosDy);
    end;
  end;


  if ((csDesigning in ComponentState) or FHintShowSizing) and
    ((FGridState = gsColSizing) or (FGridState = gsRowSizing) or FSizingFixed or FSizingFixedR)  then
  begin
    if FSizingFixed then
    begin
      r := CellRect(0,0);
      s := 'cw=<b>'+inttostr(FSizeFixedX)+'</b>';
      pt.x := r.Left;
      pt.y := r.Top;
    end
    else
    if FSizingFixedR then
    begin
      r := CellRect(0,0);
      s := 'rh=<b>'+inttostr(FSizeFixedY)+'</b>';
      pt.x := r.Left;
      pt.y := r.Top;
    end
    else
    begin
      cc := ColClicked;
      rc := RowClicked;

      if FGridState = gsColSizing then
      begin
        if cc = -1 then
        begin
          cc := ColCount - 1;
          rc := 0;
        end;
        r := CellRect(cc,rc);
        s := 'cw=<b>'+inttostr(x - r.Left - ClickPosDx)+'</b>';
        pt.x := r.Left;
        pt.y := r.Top;
      end;

      if FGridState = gsRowSizing then
      begin
        if rc = -1 then
        begin
          rc := RowCount - 1;
          cc := 0;
        end;
        r := CellRect(cc,rc);
        s := 'rh=<b>'+inttostr(y - r.Top - ClickPosDy)+'</b>';
        pt.x := r.Left;
        pt.y := r.Top;
      end;
    end;

    pt := ClientToScreen(pt);

    if Assigned(FScrollHintWnd) then
    begin
      r := FScrollHintWnd.CalcHintRect(200,s,Nil);
      FScrollHintWnd.Caption := s;
      FScrollHintWnd.Color := self.HintColor;

      r.Left := r.Left + pt.x;
      r.Right := r.Right + pt.x;
      r.Top := r.Top + pt.y;
      r.Bottom := r.Bottom + pt.y;

      FScrollHintWnd.ActivateHint(r,s);
      FScrollHintShow := True;
    end;
  end;


  if FEnhRowColMove then
  begin
    Update;
  end;

  if not EqualRect(TRect(XSelection), TRect(Selection)) then
  begin
    SelectionChanged(Selection.Left, Selection.Top,Selection.Right, Selection.Bottom);
  end;
end;

(* deprecated, replaced by Anchors
procedure TAdvStringGrid.GridResize(Sender: TObject);
var
  nx,ny: Integer;
begin
  if csDesigning in ComponentState then Exit;
  if csDestroying in ComponentState then Exit;

  if (Sender is TForm) and FSizeWithForm then
  begin
    nx := (Sender as TForm).Width;
    ny := (Sender as TForm).Height;

    if (self.Width + nx - prevsizex > 0) and (self.Height + ny - prevsizey > 0) then
    begin
      self.Width := self.Width + nx - prevsizex;
      self.Height := self.Height + ny - prevsizey;
      prevsizex := nx;
      prevsizey := ny;
    end;
  end;

  if ResizeAssigned then
  begin
    try
      FOnResize(Sender);
    except
    end;
  end;

  StretchColumn(FColumnSize.StretchColumn);
end;
*)

procedure TAdvStringGrid.ShowHintProc(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo);
var
  Col,Row,RCol: Integer;
  HintPos: TRect;
  Anchor,Stripped,FocusAnchor,AnchorHint:string;
  XSize,YSize: Integer;
  hl,ml,cellw,cellh: Integer;
  hr,cr: TRect;
  CID,CV,CT: string;
  csize: TSize;
  ctt: TTextType;
  ws: widestring;
  EHTS: boolean;

begin
  MouseToCell(HintInfo.CursorPos.x,HintInfo.CursorPos.y,Col,Row);

  if ControlLook.HintMaxWidth > 0 then
    HintInfo.HintMaxWidth := ControlLook.HintMaxWidth;

  WideHintFontName := Font.Name;

  if (Col >= 0) and (Row >= 0) then
  begin
    IsBaseCellEx(Col,Row,Col,Row);
    FLastHintPos := Point(Col,Row);

    HintPos := CellRect(Col,Row);
    cellw := HintPos.Right - HintPos.Left;
    cellh := HintPos.Bottom - HintPos.Top;

    RCol := RemapCol(Col);

    if IsComment(RCol,Row,HintStr) then
    begin
      HintInfo.HintPos.x := HintPos.Right;
      HintInfo.HintPos.y := HintPos.Top;
    end
    else
    begin
      HintInfo.HintPos.x := HintInfo.CursorPos.x; //HintPos.Left;
      HintInfo.HintPos.y := HintPos.Bottom + 6;
    end;

    if (TextType(Cells[RCol,Row],FEnableHTML) = ttHTML) and FAnchorHint then
    begin
      if not HTMLDrawEx(Canvas,Cells[RCol,Row],HintPos,GridImages,HintInfo.CursorPos.x,HintInfo.CursorPos.y,-1,0,1,True,False,False,True,True,False,not EnhTextSize,False,'',
                          0.0,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,xsize,ysize,
                          ml,hl,hr,cr,CID,CT,CV,FImageCache,FContainer,self.Handle,BidiMode) then
        Anchor := '';

      if (Anchor <> '') then
      begin
        if AnchorHint = '' then
          AnchorHint := Anchor;

        if Assigned(FOnAnchorHint) then
          FOnAnchorHint(self,Row,RCol,AnchorHint);

        FLastAnchorHint := AnchorHint;

        HintStr := AnchorHint;
        HintInfo.HintPos.x := HintInfo.CursorPos.x + 8;
        HintInfo.HintPos.y := HintInfo.CursorPos.y - 16;
      end;
    end;


    if FHintShowCells and
       (Col >= FixedCols) and
       (Row >= FixedRows) and
       (Col < ColCount - FixedRightCols) and
       (Row < RowCount - FixedFooters) then
    begin
      HintInfo.HintPos.y := HintPos.Top;

      ctt := TextType(Cells[RCol,Row],FEnableHTML);
      if ctt = ttUnicode then
        HintStr := WideCells[RCol,Row] // convert back to ansi string
      else
        if HTMLHint then
          HintStr := Cells[RCol,Row]
        else
          HintStr := StrippedCells[RCol,Row];
    end;

    EHTS := FEnhTextSize;

    FEnhTextSize := false;

    csize := GetCellTextSize(RCol,Row,true);

    FEnhTextSize := EHTS;

    if FHintShowLargeText and
       //((csize.cx > ColWidths[Col]) or (csize.cy > RowHeights[Row])) then
       ((csize.cx > cellw) or (csize.cy > cellh)) then
    begin
      if FHintShowLargeTextPos = hpCell then
      begin
        HintInfo.HintPos.y := HintPos.Top;
        HintInfo.HintPos.X := CellRect(Col,Row).Left;
      end;

      ctt := TextType(Cells[RCol,Row],FEnableHTML);
      if ctt = ttUnicode then
        HintStr := Cells[RCol,Row]
      else
        if HTMLHint or (ctt <> ttHTML) then
          HintStr := Cells[RCol,Row]
        else
          HintStr := StrippedCells[RCol,Row];
    end;

    if not (FloatingFooter.Visible and (Row = RowCount - 1)) then
      GetCellHint(Col,Row,HintStr, ws);

    if (TextType(HintStr, true) in [ttUnicode, ttHTML]) and UseInternalHintClass then
    begin
      HintInfo.HintWindowClass := THTMLHintWindow;
      {$IFDEF DELPHI_UNICODE}
      HintInfo.HintData := Self;
      {$ENDIF}
    end;

    HintInfo.HintPos := ClientToScreen(HintInfo.HintPos);
  end;
  HintInfo.HintColor := FHintColor;
end;

procedure TAdvStringGrid.SetEditText(ACol, ARow: longint; const Value: string);
var
  pt: TPoint;
begin
  pt := Point(ACol,ARow);
  if not IsBaseCell(ACol, ARow) then
    pt := BaseCell(ACol, ARow);

  pt.X := RemapCol(pt.X);
  inherited SetEditText(pt.X,pt.Y,Value);
end;

function TAdvStringGrid.GetEditText(ACol, ARow: Longint): string;
var
  AlignValue: TAlignment;
  pt: TPoint;
begin
  FNoEditChange := true;
  ACol := RemapCol(ACol);

  if InplaceEditor <> nil then
  begin
    AlignValue := GetCellAlignment(ACol,ARow).Alignment;
    TAdvInplaceEdit(InplaceEditor).VAlign := (AlignValue = taRightJustify);
  end;

  pt := Point(ACol,ARow);

  if not IsBaseCell(ACol, ARow) then
  begin
    pt := BaseCell(ACol,ARow);
  end;

  //if Navigation.AlwaysEdit and not Navigation.AllowCtrlEnter then
  //  Result := FEditText
  //else
  Result := inherited GetEditText(pt.X,pt.Y);

  if not FEditWithTags then
    Result := HTMLStrip(Result);
end;

procedure TAdvStringGrid.CellToRich(Col,Row: Integer;RichEditor: TRichedit);
var
  MemoryStream: TStringStream;
  RtfText: string;
begin
  RtfText := Cells[Col,Row];

  if RtfText <> '' then
  begin
    MemoryStream := TStringStream.Create('');
    try
      MemoryStream.WriteString(RtfText);
      MemoryStream.Position := 0;
      RichEditor.Lines.LoadFromStream(MemoryStream);
    finally
      MemoryStream.Free;
    end;
  end
  else
    RichEditor.Clear;
end;

procedure TAdvStringGrid.RichToCell(Col,Row: Integer; RichEditor: TRichEdit);
begin
  Cells[Col,Row] := RichToString(RichEditor);
end;

function TAdvStringGrid.RichToString(RichEditor: TRichEdit): string;
var
  MemoryStream: TStringStream;
begin
  if (csDestroying in ComponentState) then
    Exit;

  MemoryStream := TStringStream.Create('');
  try
    RichEditor.Lines.SaveToStream(MemoryStream);
    Result := MemoryStream.DataString;
  finally
    MemoryStream.Free;
  end;
end;


procedure TAdvStringGrid.SetIntegralHeight(const Value: Boolean);
begin
  FIntegralHeight := Value;
  SetBounds(Left,Top,Width,Height);
end;

procedure TAdvStringGrid.CalcSizingState(X, Y: Integer; var State: TGridState;
  var Index: Integer; var SizingPos, SizingOfs: Integer;
  var FixedInfo: TGridDrawInfo);
var
  cx,cy: Integer;
  Allow: Boolean;
begin
  inherited;
  MouseToCell(x - 6,y,cx,cy);
  if (cy < FixedRows) and (cx >= 0) then
  begin
    Allow := True;
    if Assigned(FOnColumnSize) then
    begin
      FOnColumnSize(self,cx,Allow);
      if not Allow then
      begin
        State := gsNormal;
        FSizeFixed := false;
      end;
    end;
  end;

  MouseToCell(x,y - 6,cx,cy);
  if cx < FixedCols then
  begin
    Allow := True;
    if Assigned(FOnRowSize) then
    begin
      FOnRowSize(self,cy,Allow);
      if not Allow then
      begin
        State := gsNormal;
      end;
    end;
  end;

end;

function TAdvStringGrid.HiddenRow(j: Integer): TStrings;
var
  i: Integer;
begin
  Result := nil;
  for i := 1 to FGridItems.Count do
  begin
    if (FGridItems.Items[i - 1] as TGridItem).Idx = j then
    begin
      Result := (FGridItems.Items[i - 1] as TGridItem).Items;
      break;
    end;
  end;
end;

function TAdvStringGrid.GetStrippedCell(i,j: Integer):string;
begin
  Result := HTMLStrip(Cells[i,j]);
end;

procedure TAdvStringGrid.SetUseHTMLHints(const Value: Boolean);
begin
  FUseHTMLHints := Value;

  if Value then
    HintWindowClass := THTMLHintWindow
  else
    HintWindowClass := THintWindow;  
end;


function TAdvStringGrid.GetCurrentCell:string;
var
  pt: TPoint;
begin
  if FVirtualEdit then
    Result := GetCurrentDisplCell
  else
  begin
    if IsBasecell(RealCol, Row) then
      Result := GridCells[RealCol,Row]
    else
    begin
      pt := BaseCell(RealCol, Row);
      Result := GridCells[pt.x, pt.y];
    end;
  end;
end;

function TAdvStringGrid.GetCurrentDisplCell:string;
var
  pt: TPoint;
begin
  if IsBasecell(RealCol, Row) then
    Result := Cells[RealCol,Row]
  else
  begin
    pt := BaseCell(RealCol, Row);
    Result := Cells[pt.x, pt.y];
  end;
end;

function TAdvStringGrid.GetCurrentEditor: TEditorType;
begin
  Result := EditControl;
end;

procedure TAdvStringGrid.CellTextChange(ACol, ARow: integer);
var
  sz: TSize;
  sp: TScrollProp;
begin
  if HasAutoRangeScrollBar(ACol, ARow) then
  begin
    sz := GetCellTextSize(ACol,ARow,true,true);

    sp.PageSize := RowHeights[ARow];
    sp.Range := sz.cy - RowHeights[ARow] + RowHeights[ARow];

    SetScrollProp(ACol,ARow,sp);
  end;
end;

function TAdvStringGrid.GetEditCell(i,j: integer): string;
begin
  Result := GridCells[i,j];
end;

procedure TAdvStringGrid.SetEditCell(const AValue:string);
var
  pt: TPoint;
begin
  // 3.3.1.3
  if IsBasecell(RealCol, Row) then
    SetEditText(Col,Row, AValue)
  else
  begin
    pt := BaseCell(RealCol, Row);
    SetEditText(pt.x, pt.y, AValue);
  end;
end;

procedure TAdvStringGrid.SetCurrentCell(const AValue:string);
var
  pt: TPoint;
begin
  if IsBasecell(RealCol, Row) then
    Cells[RealCol,Row] := AValue
  else
  begin
    pt := BaseCell(RealCol, Row);
    Cells[pt.x, pt.y] := AValue;
  end;

//  Result := GridCells[RealCol,Row]
//  Cells[RealCol,Row] := AValue;
end;

function TAdvStringGrid.GetCellsEx(i,j: Integer): string;
var
  st: TStrings;
begin
  if (i < 0) or (j < 0) then
  begin
    Result := '';
    Exit;
  end;

  if IsHiddenRow(j) then
  begin
    st := HiddenRow(j);

    while i >= st.Count do
      st.Add('');

    Result := st.Strings[i];
    GetDisplText(i,j,Result);
  end
  else
  begin
    j := RemapRow(j);
    Result := Cells[i,j];
  end;
end;

function TAdvStringGrid.GetGridCellsEx(i,j: Integer):string;
begin
  if IsHiddenRow(j) then
  begin
    Result := HiddenRow(j).Strings[i];
  end
  else
  begin
    j := RemapRow(j);
    Result := GridCells[i,j];
  end;
end;


function TAdvStringGrid.GetWideCellsEx(i,j: Integer): widestring;
begin
{$IFDEF TMSUNICODE}
  Result := DecodeWideStr(AllCells[i,j]);
{$ELSE}
  Result := AllCells[i,j];
{$ENDIF}
end;


function TAdvStringGrid.GetAllColWidths(i: Integer): Integer;
begin
  if not IsHiddenColumn(i) then
  begin
    Result := ColWidths[RemapColInv(i)];
  end
  else
    Result := FAllColWidths[i];
end;

procedure TAdvStringGrid.SetAllColWidths(i: Integer; const Value: Integer);
begin
  FAllColWidths[i] := Value;

  if not IsHiddenColumn(i) then
  begin
    ColWidths[RemapColInv(i)] := Value;
  end;
end;

function TAdvStringGrid.GetCursorEx: TCursor;
begin
  Result := inherited Cursor;
end;

procedure TAdvStringGrid.SetCursorEx(const Value: TCursor);
begin
  inherited Cursor := Value;
  FOldCursor := Value;
end;

function TAdvStringGrid.SortedRowIndex(ARow: Integer): Integer;
begin
  Result := ARow;
  if FSortRowXRef.Count > ARow then
    Result := FSortRowXRef.Items[ARow];
  Result := RemapRowInv(Result);
end;

function TAdvStringGrid.UnsortedRowIndex(ARow: Integer): Integer;
var
  k: Integer;
begin
  Result := ARow;
  if FSortRowXRef.Count > 0 then
  begin
    for k := 0 to FSortRowXRef.Count - 1 do
    begin
      if FSortRowXRef.Items[k] = ARow then
        Break;
    end;
    Result := k;
  end;  
end;

function TAdvStringGrid.GetUnSortedCell(i, j: Integer): string;
var
  k: Integer;
begin
  k := j;
  if FSortRowXRef.Count >= j then
  for k := 0 to FSortRowXRef.Count - 1 do
  begin
    if FSortRowXRef.Items[k ] = j then
      Break;
  end;
  Result := Cells[i,k];
end;

procedure TAdvStringGrid.SetUnSortedCell(i, j: Integer; const Value: string);
var
  k: Integer;
begin
  k := j;
  if FSortRowXRef.Count >= j then
  for k := 0 to FSortRowXRef.Count - 1 do
  begin
    if FSortRowXRef.Items[k ] = j then
      Break;
  end;

  Cells[i,k] := Value;
end;

procedure TAdvStringGrid.SetCellsEx(i,j: Integer;Value:string);
var
  rc: Integer;
  sl: TStrings;
begin
  if IsHiddenRow(j) then
  begin
    sl := HiddenRow(j);

    while sl.Count <= i do
      sl.Add('');

    sl.Strings[i] := Value
  end
  else
  begin
    j := RemapRow(j);
    Cells[i,j] := Value;
    rc := RemapColInv(i);
    if rc <> i then
    begin
      RepaintCell(rc,j);
    end;
  end;
end;

procedure TAdvStringGrid.SetGridCellsEx(i,j: Integer;Value:string);
var
  rc: Integer;
begin
  if IsHiddenRow(j) then
    HiddenRow(j).Strings[i] := Value
  else
  begin
    j := RemapRow(j);
    GridCells[i,j] := Value;
    rc := RemapColInv(i);
    if rc <> i then
    begin
      RepaintCell(rc,j);
    end;
  end;
end;

procedure TAdvStringGrid.SetWideCellsEx(i,j: Integer;Value:widestring);
begin
{$IFDEF TMSUNICODE}
  AllCells[i,j] := EncodeWideStr(Value);
{$ELSE}
  AllCells[i,j] := Value;
{$ENDIF}
end;

function TAdvStringGrid.GetAllGraphicsObject(i,j: integer): TObject;
var
  k: integer;
begin
  if IsHiddenRow(j) then
  begin
    Result := HiddenRow(j).Objects[i]
  end
  else
  begin
    k := RemapRow(j);
    //k := j;
    Result := GridObjects[i,k];
  end;
end;

function TAdvStringGrid.GetObjectsEx(i,j: Integer):TObject;
var
  CO: TObject;
begin
  if IsHiddenRow(j) then
  begin
    CO := HiddenRow(j).Objects[i];
    if CO is TCellProperties then
      Result := TObject(TCellProperties(CO).CellObject)
    else
      Result := CO;
  end
  else
  begin
    j := RemapRow(j);
    Result := Objects[i,j];
  end;
end;

function TAdvStringGrid.GetOriginalCells(i, j: Integer): string;
var
  c: integer;
begin
  Result := '';
  c := ColumnPosition(i);
  if (c <> -1) then
    Result := Cells[c,j]
  else
    Result := Cells[i,j];
end;

procedure TAdvStringGrid.SetObjectsEx(i,j: Integer; AObject: TObject);
var
  CO: TObject;
  cp: TCellProperties;
begin
  if IsHiddenRow(j) then
  begin
    CO := HiddenRow(j).Objects[i];

    if Assigned(CO) and (CO is TCellProperties) then
      (CO as TCellProperties).CellObject := TIObjType(AObject)
    else
    begin
      cp := CreateCellProperties(i,j);
      cp.CellObject := TIObjType(AObject);
      HiddenRow(j).Objects[i] := cp;
    end;
  end
  else
  begin
    j := RemapRow(j);
    Objects[i,j] := AObject;
  end;
end;

procedure TAdvStringGrid.SetOriginalCells(i, j: Integer; const Value: string);
var
  c: integer;
begin
  c := ColumnPosition(i);
  if (c <> -1) then
    Cells[c,j] := Value
  else
    Cells[i,j] := Value;
end;

function TAdvStringGrid.GetCellControls(i,j: Integer): TControl;
begin
  Result := nil;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].Control;
end;

procedure TAdvStringGrid.SetCellChecker(const Value: TAdvStringGridCheck);
begin
  FCellChecker := Value;
  FCellChecker.Grid := Self;
end;

procedure TAdvStringGrid.SetCellControls(i,j: Integer;AControl: TControl);
var
  r: TRect;
  ci: Integer;
begin
  if AControl = nil then
  begin
    if Assigned(CellProperties[i,j].Control) then
    begin
      ci := FControlList.ControlIndex(i,j);
      if ci <> -1 then
        FControlList.RemoveControl(ci);
    end;
    CellProperties[i,j].Control := nil;
    Exit;
  end;

  ci := FControlList.ControlIndex(i,j);

  if ci <> -1 then
    FControlList.RemoveControl(ci);

  if (AControl = nil) and (CellProperties[i,j].Control <> nil) then
  begin
    if (FNumCellControls > 0) then
      dec(FNumCellControls);
  end;

  if (AControl <> nil) and (CellProperties[i,j].Control = nil) then
  begin
    inc(FNumCellControls);
  end;

  FControlList.AddControl(i,realrowindex(j),AControl);

  CellProperties[i,j].Control := AControl;
  r := CellRect(i,j);
  AControl.Parent := Self;
//  AControl.SetBounds(r.Left,r.Top,r.Right - r.Left - 1,r.Bottom - r.Top - 1);

  AControl.SetBounds(r.Left - CELLCONTROLOFFSET,r.Top - CELLCONTROLOFFSET,r.Right - r.Left - 1 + 2*CELLCONTROLOFFSET,r.Bottom - r.Top - 1 + 2*CELLCONTROLOFFSET);
end;

procedure TAdvStringGrid.SetCellFont(i, j: Integer; const Value: TFont);
var
  cp: TCellProperties;
begin
  cp := CellProperties[i,j];
  cp.FontName := Value.Name;
  cp.FontSize := Value.Size;
  cp.FontStyle := Value.Style;
  cp.FontColor := Value.Color;

  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetColors(i,j: Integer;AColor: TColor);
begin
  CellProperties[i,j].BrushColor := AColor;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetRowColor(i: Integer;AColor: TColor);
var
  j: Integer;
begin
  if AColor = clNone then
  begin
    for j := FixedCols to AllColCount - 1 do
    begin
      if GetCellEmpty(j,i) and (Objects[j,i] = nil) and not IsMergedCell(j,i) then
        ClearPropCell(j,i)
      else
        CellProperties[j,i].BrushColor := clNone;
    end;
  end
  else
  begin
    for j := FixedCols to AllColCount - 1 do
    begin
      CellProperties[j,i].BrushColor := AColor;
    end;
  end;
  RepaintRow(i);
end;

procedure TAdvStringGrid.SetRowColorTo(i: Integer;AColor: TColor);
var
  j: Integer;
begin
  if AColor = clNone then
  begin
    for j := FixedCols to AllColCount - 1 do
      ClearPropCell(j,i);
  end
  else
  begin
    for j := FixedCols to AllColCount - 1 do
      CellProperties[j,i].BrushColorTo := AColor;
  end;
  RepaintRow(i);
end;


procedure TAdvStringGrid.SetRowFontColor(i: Integer;AColor: TColor);
var
  j: Integer;
begin
  if AColor = clNone then
  begin
    for j := FixedCols to AllColCount - 1 do
    begin
      if Colors[j,i] = clNone then
        ClearPropCell(j,i);
    end;
  end
  else
  begin
    for j := FixedCols to AllColCount - 1 do
      CellProperties[j,i].FontColor := AColor;
  end;
  RepaintRow(i);
end;


function TAdvStringGrid.GetColors(i,j: Integer): TColor;
begin
  Result := clNone;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].BrushColor;
end;

procedure TAdvStringGrid.SetColorsTo(i,j: Integer;AColor: TColor);
begin
  CellProperties[i,j].BrushColorTo := AColor;
  RepaintCell(DisplColIndex(i),j);
end;

function TAdvStringGrid.GetColorsTo(i,j: Integer): TColor;
begin
  Result := clNone;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].BrushColorTo;
end;

procedure TAdvStringGrid.SetGradientDir(i,j: Integer;ADirection: TCellGradientDirection);
begin
  CellProperties[i,j].GradientDirection := ADirection;
  RepaintCell(DisplColIndex(i),j);
end;

function TAdvStringGrid.GetGradientDir(i,j: Integer): TCellGradientDirection;
begin
  Result := GradientVertical;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].GradientDirection;
end;

function TAdvStringGrid.GetReadCell(i, j: Integer): string;
begin
  Result := Cells[RealColIndex(i), j];
end;

function TAdvStringGrid.GetReadOnly(i,j: Integer): Boolean;
begin
  Result := false;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].ReadOnly;
end;

procedure TAdvStringGrid.SetReadOnly(i,j: Integer;AValue: Boolean);
begin
  CellProperties[i,j].ReadOnly := AValue;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetRealCell(i, j: Integer; const Value: string);
begin
  Cells[RealColIndex(i),j] := Value;
end;

function TAdvStringGrid.GetWordWraps(i,j: Integer): Boolean;
begin
  Result := CellProperties[i,j].WordWrap;
end;

procedure TAdvStringGrid.SetWordWraps(i,j: Integer;AValue: Boolean);
begin
  CellProperties[i,j].WordWrap := AValue;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

function TAdvStringGrid.GetFontColors(i, j: Integer): TColor;
begin
  Result := clNone;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontColor;
end;

procedure TAdvStringGrid.SetFocusHelper(const Value: TFocusHelper);
begin
  FFocusHelper.Assign(Value);
end;

procedure TAdvStringGrid.SetFontColors(i, j: Integer; const Value: TColor);
begin
  CellProperties[i,j].FontColor := Value;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

function TAdvStringGrid.GetFontStyles(i, j: Integer): TFontStyles;
begin
  Result := [];
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontStyle;
end;

procedure TAdvStringGrid.SetFontStyles(i, j: Integer;
  const Value: TFontStyles);
begin
  CellProperties[i,j].FontStyle := Value;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetFormatType(const Value: TFormatType);
begin
  if (FFormatType <> Value) then
  begin
    FFormatType := Value;
    Invalidate;
  end;
end;

function TAdvStringGrid.GetFontNames(i, j: Integer): string;
begin
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontName
  else
    Result := Font.Name;
end;

function TAdvStringGrid.GetFontSizes(i, j: Integer): Integer;
begin
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontSize
  else
    Result := Font.Size;
end;

procedure TAdvStringGrid.SetFontNames(i, j: Integer; const Value: string);
begin
  CellProperties[i,j].FontName := Value;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetFontSizes(i, j: Integer;
  const Value: Integer);
begin
  CellProperties[i,j].FontSize := Value;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

function TAdvStringGrid.GetLinesInCell(i, j: Integer): Integer;
begin
  Result := LinesInText(Cells[i,j],true);
end;

function TAdvStringGrid.GetAlignments(i, j: Integer): TAlignment;
begin
  Result := taLeftJustify;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].Alignment;
end;

procedure TAdvStringGrid.SetAlignments(i, j: Integer;
  const Value: TAlignment);
begin
  CellProperties[i,j].Alignment := Value;
  if FUpdateCount = 0 then
    RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetTMSGradFrom(const Value: TColor);
begin
  FTMSGradFrom := ColorToRGB(Value);
  Invalidate;
end;

procedure TAdvStringGrid.SetTMSGradTo(const Value: TColor);
begin
  FTMSGradTo := ColorToRGB(Value);
  Invalidate;
end;

procedure TAdvStringGrid.SetTMSGradMirrorFrom(const Value: TColor);
begin
  FTMSGradMirrorFrom := ColorToRGB(Value);
  Invalidate;
end;

procedure TAdvStringGrid.SetTMSGradMirrorTo(const Value: TColor);
begin
  FTMSGradMirrorTo := ColorToRGB(Value);
  Invalidate;
end;

function TAdvStringGrid.GetAllColCount: Integer;
begin
  Result := ColCount + NumHiddenColumns;
end;

function TAdvStringGrid.GetAllRowCount: Integer;
begin
  Result := RowCount + NumHiddenRows;
end;

function TAdvStringGrid.GetLastCol: Integer;
begin
  Result := ColCount - 1;
end;

function TAdvStringGrid.GetLastRow: Integer;
begin
  Result := RowCount - 1;
end;

procedure TAdvStringGrid.Zoom(x: Integer);
var
  i: Integer;
begin
  if FZoomFactor + x > 20 then
    Exit;

  if FZoomFactor + x < -20 then
    Exit;

  FScrollLock := true;

  FZoomFactor := FZoomFactor + x;

  BeginUpdate;

  for i := 0 to ColCount - 1 do
  begin
    if ColWidths[i] > 0 then
      if ColWidths[i] + x > 0 then
        ColWidths[i] := ColWidths[i] + x;
  end;

  for i := 0 to RowCount - 1 do
  begin
    if RowHeights[i] > 0 then
      if RowHeights[i] + x > 0 then
        RowHeights[i] := RowHeights[i] + x;
  end;

  FScrollLock := false;

  EndUpdate;

  if ScrollProportional and not (ScrollType = ssMetro) then
  begin
    UpdateVScroller;
    UpdateHScroller;
  end;
end;

procedure TAdvStringGrid.DrawIntelliFocusPoint;
var
  FocusBmp,TmpBmp: TBitmap;
  arect,brect: TRect;

begin
  FocusBmp := TBitmap.Create;

  case FIntelliPan of
  ipBoth:FocusBmp.LoadFromResourceName(hinstance,'INTLI1');
  ipHorizontal:FocusBmp.LoadFromResourceName(hinstance,'INTLI2');
  ipVertical:FocusBmp.LoadFromResourceName(hinstance,'INTLI3');
  end;

  ARect := Rect(0,0,FocusBmp.Width,FocusBmp.Height);
  with wheelpanpos do
    BRect := Rect(x,y,x + FocusBmp.Width,y + FocusBmp.Height);

  BRect := Rect(0,0,FocusBmp.Width,FocusBmp.Height);

  TmpBmp := TBitmap.Create;

  try
    TmpBmp.Height := FocusBmp.Height;
    TmpBmp.Width := FocusBmp.Width;
    TmpBmp.Canvas.Brush.Color := clWhite;
    TmpBmp.Canvas.BrushCopy(ARect,FocusBmp,BRect,FocusBmp.Canvas.Pixels[0,0]);

    with wheelpanpos do
      ARect := Rect(x,y,x + focusbmp.Width,y+focusbmp.Height);

    Canvas.CopyRect(ARect,TmpBmp.Canvas,BRect);
  finally
    FocusBmp.free;
    TmpBmp.free;
  end;
end;

procedure TAdvStringGrid.EraseIntelliFocusPoint;
var
  r:TRect;
begin
  r := Rect(wheelpanpos.x,wheelpanpos.y,wheelpanpos.x + 32,wheelpanpos.y + 32);

  InvalidateRect(self.Handle,@r,False);
end;


procedure TAdvStringGrid.WndProc(var Message: TMessage);
var
  nr: Integer;
  pt: TPoint;
  xinc,yinc: Integer;
  cursid: Integer;
  lc,wi: Integer;
  CH: THandle;
  s:string;
  buf: array[0..255] of char;
  FOldSelection: TGridRect;
  delta: integer;
  Res: integer;
  SuppressMsg: Boolean;
  ShiftState: TShiftState;
  KeyState: TKeyboardState;
  Pos: TPoint;
  Handled, de: boolean;

begin
  SuppressMsg := false;

  if Message.Msg = WM_DESTROY then
  begin
    if not IsLibrary and not (csDesigning in ComponentState) and AutoThemeAdapt then
    begin
      ThemeNotifier(Self).UnRegisterWindow(Handle);
    end;

    {$IFDEF TMSUNICODE}
    if not (csDesigning in ComponentState) and Assigned(ComboUni) and not FIsWin7 then
      if Assigned(ComboUni.Items) then
         ComboUni.Items.Clear;
    {$ENDIF}
    if FOleDropTargetAssigned then
      RevokeDragDrop(self.Handle);
    KillTimer(Handle,FGridTimerID);

    if FocusHelper.Enabled then
    begin
      HideFocusHelper;
    end;
  end;

  if (csDestroying in ComponentState) then
  begin
    inherited;
    Exit;
  end;

  FOldSelection := Selection;

  if Message.Msg = WM_GRIDEDITSHOW then
    ShowInplaceEdit;

  if Message.Msg = WM_GRIDEDITDONE then
  begin
    (*
    if Assigned(PopupToolBar) and (PopupToolBarMode = tbEditedCell) and PopupToolBar.Visible then
      PopupToolBar.Hide;
    *)
    if Assigned(FOnEditCellDone) then
      FOnEditCellDone(Self, Message.WParam, Message.LParam);

    if MouseActions.EditOnDblClickOnly then
    begin
      HideInplaceEdit;
      EditMode := false;
      Options := Options - [goEditing];
    end;

    if not EditMode and FocusHelper.Enabled then
      HideFocusHelper;
  end;

  if Message.Msg = WM_CANCELMODE then // cancel enh. col/row moving operation
  begin
    if (Screen.Cursor = crDrag) and
       (FGridstate in [gsColMoving,gsRowMoving]) and FEnhRowColMove then
    begin
      Screen.Cursor := crDefault;

      MoveButton.Enabled := False;
      MoveButton.Visible := False;

      if FGridState in [gsRowMoving,gsColMoving] then
        KillTimer(Handle,1);
      FGridState := gsNormal;
    end;
  end;

  if (Message.Msg = WM_PAINT) and (FPaintCount = 0) and ScrollProportional and not (ScrollType = ssMetro) and not (csDesigning in ComponentState) then
  begin
    // very first paint, canvas handle exists, scrollbars can be properly initialized
    UpdateVSCroller;
    UpdateHScroller;
  end;

  if (Message.Msg = WM_SIZE) or
//   (Message.Msg = CM_INVALIDATE) or
     (Message.Msg = CM_UIACTIVATE) or
     (Message.Msg = WM_LBUTTONUP ) then
     begin
       if not (csDesigning in ComponentState) then
       begin
         UpdateVScroller;
         UpdateHScroller;
       end;
     end;

  if (Message.Msg = WM_THEMECHANGED) or (Message.Msg = WM_OFFICETHEMECHANGED) then
  begin
    if FAutoThemeAdapt then
      ThemeAdapt;
  end;

  if (Message.Msg = WM_NCPAINT) then
  begin
    inherited;
    if FUpdateCount > 0 then Exit;
    NCPaintProc;
    Message.Result := 0;
    Exit;
  end;

  // inplace edit control notification message forwarding
  if (Message.Msg = WM_COMMAND) and
     (Message.WParamHi = EN_CHANGE) then
  begin
    SendMessage(message.lParam,WM_COMMAND,message.wparam,message.lparam);

    if FShowEditProcess then
    begin
      // v3.2.2.9 : prevent disappearing of caret
      SendMessage(NormalEdit.Handle, WM_SETREDRAW, Integer(false),0);

      if not FEditStart and EditMode then
        case EditControl of
        edNormal,
        edNumeric,
        edPositiveNumeric,
        edFloat,
        edPositiveFloat,
        edCapital,
        edMixedCase,
        edPassword,
        edLowerCase,
        edUpperCase: SetEditText(Col,Row, NormalEdit.Text);

        edSpinEdit,
        edFloatSpinEdit,
        edTimeSpinEdit,
        edDateSpinEdit: SetEditText(Col,Row, SpinEdit.Text);

        edEditBtn,edMaskEditBtn,
        edNumericEditBtn,
        edFloatEditBtn: SetEditText(Col,Row, BtnEdit.Text);
        end;

      //if not FEditStart and EditMode then
      //  SetEditText(Col,Row, NormalEdit.Text);

      SendMessage(NormalEdit.Handle, WM_SETREDRAW, Integer(true),0);

      //FShowEditProcess := false;
      Exit;
    end;
  end;


  // inplace combobox control notification message forwarding
  if (Message.Msg = WM_COMMAND)then
  begin

    if DWORD(Message.lParam) <> DWORD(Handle) then
    begin
      //forward messages to child controls
      //if FControlList.HasHandle(message.lParam) then (always forward)
      SendMessage(message.lParam,WM_COMMAND,message.wparam,message.lparam);
    end;
  end;

  if (Message.Msg = WM_COMMAND) and
     ((Message.WParamHi = CBN_SELCHANGE) or (Message.WParamHi = CBN_EDITCHANGE)) then
  begin
    if  (Message.LParam = Integer(EditCombo.Handle)) and EditMode then
    begin
      nr := EditCombo.Itemindex;

      if Assigned(FOnComboChange) then
      begin
        if nr = -1 then
          FOnComboChange(Self,RealColIndex(Col),Row,nr,EditCombo.Text)
        else
          FOnComboChange(Self,RealColIndex(Col),Row,nr,EditCombo.Items[nr]);
      end;

      if Assigned(FOnComboObjectChange) then
      begin
        if nr = -1 then
          FOnComboObjectChange(Self,RealColIndex(Col),Row,nr,EditCombo.Text,nil)
        else
          FOnComboObjectChange(Self,RealColIndex(Col),Row,nr,EditCombo.Items[nr],EditCombo.Items.Objects[nr]);
      end;
    end;

    if Assigned(EditLink) then
    begin
      if (EditLink.GetEditControl <> nil) then
      begin
        CH := EditLink.GetEditControl.Handle;
        if (CH = THandle(Message.LParam)) then
        begin
          if Assigned(FOnComboChange) then
          begin
            nr := SendMessage(CH, CB_GETCURSEL,0,0);
            s := '';
            if  (nr <> -1) then
            begin
              SendMessage(CH, CB_GETLBTEXT, nr, LParam(@buf));
              s := strpas(buf);
            end;
            FOnComboChange(Self,Col,Row,nr,s);
          end;
        end;
      end;
    end;
  end;

  if (Message.Msg = WM_COMMAND) and
     (Message.WParamHi = CBN_CLOSEUP) and (Message.LParam = LParam(EditCombo.Handle)) then
  begin
    if MouseActions.DirectComboClose then
    begin
      EditCombo.Text := EditCombo.Items[EditCombo.ItemIndex];

      nr := EditCombo.ItemIndex;

      if Assigned(FOnComboChange) and (EditCombo.Text <> OriginalCellValue) then
      begin
        if nr = -1 then
          FOnComboChange(Self,RealColIndex(Col),Row,nr,EditCombo.Text)
        else
          FOnComboChange(Self,RealColIndex(Col),Row,nr,EditCombo.Items[nr]);
      end;

      if Assigned(FOnComboObjectChange) then
      begin
        if nr = -1 then
          FOnComboObjectChange(Self,RealColIndex(Col),Row,nr,EditCombo.Text,nil)
        else
          FOnComboObjectChange(Self,RealColIndex(Col),Row,nr,EditCombo.Items[nr],EditCombo.Items.Objects[nr]);
      end;

      // force that the editor always closes!
      EditControl := edComboEdit;
      EditMode := true;

      de := MouseActions.DirectEdit;
      MouseActions.DirectEdit := false;

      HideInplaceEdit;
      SetFocus;

      MouseActions.DirectEdit := de;
    end;

    DoComboCloseUp(Row, RealColIndex(Col));
  end;

  if (Message.Msg = WM_COMMAND) and
     (Message.WParamHi = CBN_DROPDOWN) and (Message.LParam = LParam(EditCombo.Handle)) then
  begin
    DoComboDropDown(Row,RealColIndex(Col));
  end;


  if (Message.Msg = WM_COMMAND) and
     (Message.wparamhi = CBN_EDITCHANGE) then
  begin
    if Assigned(FOnComboChange) then
    begin
      FOnComboChange(Self,Col,Row,-1,EditCombo.Text);
    end;
  end;

  if (message.msg = WM_TIMER) and (wheelmsg > 0) and wheelpan and (FIntelliPan <> ipNone) then
  begin
    GetCursorPos(pt);
    pt := ScreenToClient(pt);
    yinc := 0;
    xinc := 0;

    if pt.x < wheelpanpos.x - 5 then xinc := -1;
    if pt.x > wheelpanpos.x + 5 then xinc := 1;
    if pt.y < wheelpanpos.y - 5 then yinc := -1;
    if pt.y > wheelpanpos.y + 5 then yinc := 1;

    if FIntelliPan = ipHorizontal then yinc := 0;
    if FIntelliPan = ipVertical then xinc := 0;

    cursid := 8000;

    if (yinc = 0) and (xinc = 0) then cursid := 8000;
    if (yinc = 0) and (xinc > 0) then cursid := 8003;
    if (yinc = 0) and (xinc < 0) then cursid := 8002;
    if (yinc > 0) and (xinc = 0) then cursid := 8001;
    if (yinc < 0) and (xinc = 0) then cursid := 8004;
    if (yinc < 0) and (xinc < 0) then cursid := 8006;
    if (yinc < 0) and (xinc > 0) then cursid := 8005;
    if (yinc > 0) and (xinc < 0) then cursid := 8008;
    if (yinc > 0) and (xinc > 0) then cursid := 8007;

    if Row > RowCount - FixedFooters - 1 then
      Row := RowCount - 1 - FixedFooters;
    if Row < FixedRows then
      Row := FixedRows;
    if Col > ColCount - FixedRightCols - 1 then
      Col := ColCount - 1 - FixedCols;
    if Col < FixedCols then
      Col := FixedCols;

    if (MouseActions.WheelAction = waMoveSelection) then
    begin
      if (Col > FixedCols) and (xinc = -1) then
      begin
        if (Col + xinc < LeftCol) or (Col + xinc >= LeftCol + VisibleColCount) then
          EraseIntelliFocusPoint;

        if Col + xinc >= FixedCols then
          Col := Col + xinc;
      end;

      if (Col < ColCount - FixedRightCols - 1) and (xinc=1) then
      begin
        if (Col + xinc < LeftCol) or (Col + xinc >= LeftCol + VisibleColCount) then
          EraseIntelliFocusPoint;

        if (Col + xinc <= ColCount - 1) then
          Col := Col + xinc;
      end;

      if (Row > FixedRows)  and (yinc = -1) then
      begin
        if (Row + yinc < TopRow) or (Row + yinc >= TopRow + VisibleRowCount) then
          EraseIntelliFocusPoint;

        if Row + yinc >= 0 then
          Row := Row + yinc;
      end;

      if (Row < RowCount - FixedFooters-1) and (yinc = 1) then
      begin
        if (Row + yinc < TopRow) or (Row + yinc >= TopRow + VisibleRowCount) then
          EraseIntelliFocusPoint;

        if Row + yinc <= RowCount - 1 then
          Row := Row + yinc;
      end;
    end
    else
    begin
      if (LeftCol > FixedCols) and (xinc = -1) then
      begin
        EraseIntelliFocusPoint;

        if LeftCol + xinc >= FixedCols then
          LeftCol := LeftCol + xinc;
      end;

      if (LeftCol < ColCount - VisibleColCount) and (xinc=1) then
      begin
        EraseIntelliFocusPoint;

        if LeftCol + xinc <= ColCount - VisibleColCount then
          LeftCol := LeftCol + xinc;
      end;

      if (TopRow > FixedRows)  and (yinc = -1) then
      begin
        EraseIntelliFocusPoint;

        if TopRow + yinc >= FixedRows then
          TopRow := TopRow + yinc;
      end;

      if (TopRow < RowCount - VisibleRowCount) and (yinc = 1) then
      begin
        EraseIntelliFocusPoint;

        if TopRow + yinc <= RowCount - VisibleRowCount then
          TopRow := TopRow + yinc;
      end;

    end;

    if cursid = 8000 then
      SetCursor(FICursor)
    else
      SetCursor(LoadCursor(hinstance,makeintresource(cursid)));

    DrawIntelliFocusPoint;

    if not EqualRect(TRect(FOldSelection), TRect(Selection)) then
    begin
      SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);
    end;
  end;

  if (Message.msg = WM_MBUTTONDOWN) and (wheelmsg > 0) and
     not wheelpan and (FIntelliPan <> ipNone) and (RowCount > FixedRows) then
  begin
    FICursor := LoadCursor(hinstance,makeintresource(8000));
    prevcurs := SetCursor(FICursor);
    wheelpan := True;
    wheeltimer := SetTimer(self.Handle,999,10,Nil);
    wheelpanpos.x := loword(message.lparam);
    wheelpanpos.y := hiword(message.lparam);
    SetCapture(Self.Handle);
    ShowHint := False;
    DrawIntelliFocusPoint;
  end
  else
  if ((message.msg = WM_MBUTTONDOWN) and (wheelmsg > 0) and wheelpan) or
     ((message.msg = WM_LBUTTONDOWN) and (wheelmsg > 0) and wheelpan) or
     ((message.msg = WM_RBUTTONDOWN) and (wheelmsg > 0) and wheelpan) or
     ((message.msg = WM_KEYDOWN) and (wheelmsg > 0) and wheelpan) then
  begin
    ReleaseCapture;
    KillTimer(self.Handle,wheeltimer);
    SetCursor(prevcurs);
    Showhint := True;
    wheelpan := False;
    EraseIntelliFocusPoint;
  end;

  if (message.msg = wheelmsg) and (wheelmsg > 0) and not wheelpan and not (csDesigning in ComponentState) then //intellimouse event here
  begin
    Res := 0;
    SuppressMsg := true;
    FScrollBar.Visible := false;

    if MouseActions.WheelActive = waMouseOver then
    begin
      pos.x := message.lparam and $FFFF;
      pos.y := (message.lparam and $FFFF0000) shr 16;
      pos := ScreenToClient(pos);
      if not PtInRect(ClientRect,pos) then
        Exit;
    end;

    // allow for processing by the parent
    if Assigned(Parent) then
      with TMessage(Message) do
        Res := Parent.Perform(CM_MOUSEWHEEL, WParam, LParam);

    if Res = 0 then
    begin
      if (GetKeystate(VK_CONTROL) and $8000 = $8000) and FIntelliZoom then
      begin  //zoom
        if integer(message.wparam) < 0 then
          Zoom(-wheelscrl)
        else
          Zoom(+wheelscrl);

        DoIntelliZoom;
        //AutoSizeCells(true,4,4);
      end
      else
      if FEnableWheel then
      begin //normal scrolling
        if FixedRowAlways and (RowCount = 1) then
          Exit;

        nr := Row;

        if MouseActions.WheelIncrement > 0 then
          wi := MouseActions.WheelIncrement
        else
          wi := wheelscrl;

        if MouseActions.WheelAction = waMoveSelection then
        begin
          if (integer(message.wparam) < 0) then
            nr := Row + wi
          else
            nr := Row - wi;
        end
        else
        begin
          if (integer(message.wparam) < 0) then
          begin
            if (TopRow < RowCount - VisibleRowCount) and (TopRow + wi >= FixedRows) then
              TopRow := TopRow + wi;
          end
          else
          begin
            if TopRow - wi < FixedRows then
              wi := TopRow - FixedRows;

            if (TopRow > FixedRows) and (TopRow - wi >= FixedRows) then
              TopRow := TopRow - wi;
          end;
        end;

        if (nr < FixedRows) then
          nr := FixedRows;
        if nr > RowCount - FixedFooters - 1 then
          nr := RowCount - FixedFooters - 1;

        if (Col > ColCount - 1) and (Row > RowCount - 1) then
        begin
          FocusCell(ColCount - 1, RowCount - 1);
        end;

        if (Col > ColCount - 1) then
          Col := ColCount - 1;

        if Col < FixedCols then
          Col := FixedCols;

        lc := LeftCol;
        delta := 0;

        if (nr < RowCount) and (nr >= 0) then
        begin
          StartUpdate;

          if MouseActions.DisjunctRowSelect and (MouseActions.WheelAction <> waScroll) then
            ClearRowSelectInt;

          delta := nr - Row;

          if MouseActions.WheelAction <> waScroll then
          begin
            Row := nr;

            // couldn't set row
            wi := nr - Row;

            if (Row < nr) then
            begin
              while (nr < RowCount) and (Row <> nr) do
              begin
                nr := nr + wi;
                if nr < RowCount then
                  Row := nr;
              end;
            end
            else
              if (Row > nr) then
              begin
                while (nr >= FixedRows) and (Row <> nr) do
                begin
                  nr := nr + wi;
                  if nr >= FixedRows then
                    Row := nr;
                end;
              end;
          end;

          // what when selection is not accepted ...
          if (Row <> nr) then
          begin
            Row := Row + round((nr - Row) /2);

            if message.wparam > 0 then
            begin
              if TopRow > FixedRows then
                TopRow := TopRow - 1;
            end;
          end;

          if (goRowSelect in Options) and Navigation.KeepHorizScroll then
            LeftCol := lc;

          ResetUpdate;
        end;

        DirectWheelChange(delta, SuppressMsg);

        //if (MouseActions.WheelIncrement <> 0) or (MouseActions.DisjunctRowSelect) then
        //begin
          if SuppressMsg then
          begin
            Message.Result := 1;

            if MouseActions.DisjunctRowSelect then
            begin
              GetKeyboardState(KeyState);
              ShiftState := KeyboardStateToShiftState(KeyState);
              Handled := false;
              Pos := Point(Message.LParam and $FFFF, Message.LParam shr 16);
            end;

            if Assigned(OnMouseWheelDown) and (integer(message.wparam) < 0) then
              OnMouseWheelDown(Self, ShiftState, Pos, Handled);

            if Assigned(OnMouseWheelUp) and (integer(message.wparam) >= 0) then
              OnMouseWheelUp(Self, ShiftState, Pos, Handled);

            if FUseVCLStyles then
            begin
              // workaround for VCL style bug where scrollbar does not update
              nr := Row;
              inherited;
              if MouseActions.WheelIncrement > 0 then
                Row := nr;
            end;
          end;
        //end;

        if not EqualRect(TRect(FOldSelection), TRect(Selection)) then
        begin
          SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);
        end;

        if SearchFooter.Visible then
        begin
          if TopRow = RowCount - VisibleRowCount then
          begin
            ScrollToLastRow;
          end;
        end;
      end;

      {$IFNDEF DELPHI9_LVL}
      if (MouseActions.WheelIncrement <> 0) and SuppressMsg then
      begin
        Exit;
      end;
      {$ENDIF}

      {$IFDEF DELPHIXE2_LVL}
      //Exit;
      {$ENDIF}
    end;
  end;


  nr := Row;

  if not SuppressMsg then
    inherited;

  if (nr <> Row) and Assigned(SyncGrid) and (SyncGrid.SelectionRow) then
    Row := Row;
end;

procedure TAdvStringGrid.DirectWheelChange(delta: integer; var SuppressMsg: Boolean);
begin
  SuppressMsg := True;
end;


procedure TAdvStringGrid.DoHeaderButtonClick(Sender: TObject; ButtonIndex: integer);
begin
  if Assigned(OnDropDownHeaderButtonClick) then
  begin
    OnDropDownHeaderButtonClick(Self, Col, Row, ButtonIndex);
  end;
end;

procedure TAdvStringGrid.DoFooterButtonClick(Sender: TObject; ButtonIndex: integer);
begin
  if Assigned(OnDropDownFooterButtonClick) then
  begin
    OnDropDownFooterButtonClick(Self, Col, Row, ButtonIndex);
  end;
end;

procedure TAdvStringGrid.DoMemoChanged(Sender: TObject);
begin
  SetEditText(Col,Row, FEditMemo.MemoText.Text);
end;

function TAdvStringGrid.DoMouseWheelDown(Shift: TShiftState;
  MousePos: TPoint): Boolean;
var
  lc: Integer;
  de,em: Boolean;
begin
  if (Assigned(FDropCheckList) and FDropCheckList.Visible) or
     (Assigned(FDropList) and FDropList.Visible) then
  begin
    Exit;
  end;

  if (MouseActions.WheelAction = waScroll) or not FEnableWheel then
  begin
    Result := False;
    if Assigned(OnMouseWheelDown) then
      OnMouseWheelDown(Self, Shift, MousePos, Result);
    Exit;
  end;

  de := MouseActions.DirectEdit;
  MouseActions.DirectEdit := false;

  if (goRowSelect in Options) and Navigation.KeepHorizScroll then
  begin
    StartUpdate;
    lc := LeftCol;
    Result := inherited DoMouseWheelDown(Shift,MousePos);
    LeftCol := lc;
    ResetUpdate;
  end
  else
  begin
    em := EditMode;
    Result := inherited DoMouseWheelDown(Shift,MousePos);
    if em then
      SetFocus;
  end;

  MouseActions.DirectEdit := de;
end;

function TAdvStringGrid.DoMouseWheelUp(Shift: TShiftState;
  MousePos: TPoint): Boolean;
var
  lc: Integer;
  de,em: Boolean;
begin
  if (Assigned(FDropCheckList) and FDropCheckList.Visible) or
     (Assigned(FDropList) and FDropList.Visible) then
  begin
    Exit;
  end;

  if (MouseActions.WheelAction = waScroll) or not FEnableWheel then
  begin
    Result := False;
   if Assigned(OnMouseWheelUp) then
      OnMouseWheelUp(Self, Shift, MousePos, Result);
    Exit;
  end;

  de := MouseActions.DirectEdit;
  MouseActions.DirectEdit := false;

  if (goRowSelect in Options) and Navigation.KeepHorizScroll then
  begin
    StartUpdate;
    lc := LeftCol;
    Result := inherited DoMouseWheelUp(Shift,MousePos);
    LeftCol := lc;
    ResetUpdate;
  end
  else
  begin
    em := EditMode;

    if (Row < RowCount) and (Col < ColCount) then
      Result := inherited DoMouseWheelUp(Shift,MousePos)
    else
      Result := True;

    if em then
      SetFocus;
  end;

  MouseActions.DirectEdit := de;
end;

procedure TAdvStringGrid.Select;
begin
  SelectCell(Col,Row);
end;


procedure TAdvStringGrid.ForceMouseOnCell(Col,Row:integer);
var
  CR: TRect;
  pt: TPoint;
  md,mu: TMouseEvent;
begin
  CR := CellRect(Col,Row);
  pt.X := CR.Left + 2;
  pt.Y := CR.Top + 2;
  FForceSel := true;
  md := OnMouseDown;
  mu := OnMouseUp;
  OnMouseDown := nil;
  OnMouseUp := nil;
  inherited MouseDown(mbLeft,[],pt.X,pt.Y);
  inherited MouseUp(mbLeft,[],pt.X,pt.Y);
  OnMouseDown := md;
  OnMouseUp := mu;
  FForceSel := false;
end;

procedure TAdvStringGrid.ShowInplaceEdit;
var
  RCol: integer;
begin
  RCol := RemapCol(Col);
  if not HasStaticEdit(RCol,Row) then
  begin
    if Row < TopRow then
      TopRow := Row;
    if Col < LeftCol then
      LeftCol := Col;

    if not (goEditing in Options) and MouseActions.RangeSelectAndEdit then
    begin
      Options := Options + [goEditing];
    end;

    FEditText := Cells[Col,Row];
    ShowEditor;
  end;
end;

procedure TAdvStringGrid.HideInplaceEdit;
begin
  if EditMode then
  begin
    HideEditor;
    HideEditControl(Col,Row);
    EditMode := False;
    SelectCell(Col,Row);
    // SetFocus;
  end;
end;

procedure TAdvStringGrid.DoneEditing(ACol,ARow: integer);
begin
  if FocusHelper.Enabled then
    HideFocusHelper;

  if Assigned(FOnEditingDone) then
    FOnEditingDone(Self);

  if FocusHelper.Enabled then
    ShowFocusHelper(CellRect(Col,Row));

  HideInplaceEdit;
  //  EditMode := false;

  PostMessage(Handle, WM_GRIDEDITDONE,ACol,ARow);

  (*
  if SearchFooter.Visible then
  begin
    FSearchPanel.Invalidate;
    FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width + 1;
    FSearchPanel.FEdit.Width := FSearchPanel.FEdit.Width - 1;
  end;
  *)
end;

procedure TAdvStringGrid.DoneInplaceEdit(Key:word; Shift: TShiftState);
var
  FOldAlwaysEdit: Boolean;
begin
  FBlockFocus := True;

  FEditing := False;

  HideInplaceEdit;

  if Navigation.AppendOnArrowDown and (Key = VK_DOWN) and IsOnLastRow then
  begin
    AppendLastRow;
  end;

  if Key in [VK_DOWN,VK_UP,VK_LEFT,VK_RIGHT,VK_TAB] then
    Keydown(Key,shift);

  FOldAlwaysEdit := FNavigation.AlwaysEdit;
  FNavigation.AlwaysEdit := False;

  SetFocus;

  if (Key = VK_RETURN) then
    AdvanceEdit(Col,Row,false,True,True,False,False);

  FNavigation.AlwaysEdit := FOldAlwaysEdit;
  FBlockFocus := False;
end;

procedure TAdvStringGrid.CellControlsUpdate(rebuildlist: boolean = false);
var
  i,j: Integer;
  ctrl: TControl;
  r: TRect;
  ci: TControlItem;
  pt: TPoint;

begin
  if not HandleAllocated then
    Exit;

  if not ccuCall then
    Exit;
  if rebuildlist then
  begin
    FControlList.Clear;

    for i := 0 to ColCount - 1 do
      for j := 0 to RowCount - 1 do
      begin
        if HasCellProperties(i,j) then
        begin
          ctrl := CellProperties[i,j].Control;
          if Assigned(ctrl) then
            FControlList.AddControl(i,j,ctrl);
        end;
      end;
  end;

  if Assigned(FScrollBar) then
  if FScrollBar.Visible then
  begin
    if (Row >= TopRow) and (Col >= LeftCol) and
       (Col < LeftCol + VisibleColCount) and (Row < TopRow + VisibleRowCount) then
    begin
      r := CellRect(Col,Row);
      FScrollBar.Top := r.Top;
      FScrollBar.Left := r.Right - FScrollBar.Width;
      FScrollBar.Height := r.Bottom - r.Top;
    end
    else
    begin
      FScrollBar.Height := 0;
    end;
  end;

  if FNumCellControls = 0 then
    Exit;

  for i := 1 to FControlList.Count do
  begin
    ci := FControlList.Control[i - 1];

    // ci has the absolute cell index
    if IsHiddenRow(ci.Y) or IsHiddenColumn(ci.X) then
      ci.Control.Visible := false;

    pt.X := RemapCol(ci.X);
    pt.Y := RemapRow(ci.Y);

    if (pt.X < LeftCol) or (pt.X > LeftCol + VisibleColCount) or
       (pt.Y < TopRow) or (pt.Y > TopRow + VisibleRowCount) or
       IsHiddenRow(ci.Y) then
    begin
      //ctrl := CellControls[pt.X,pt.Y];
      if (pt.Y >= FixedRows) and (pt.X >= FixedCols) then
      begin
        ctrl := ci.Control;
        if Assigned(ctrl) then
        begin
          ctrl.Visible := false;
        end;
      end
      else
      begin
        ctrl := ci.Control;
        if Assigned(ctrl) then
        begin
          r := CellRect(pt.X,pt.Y);
          ctrl.SetBounds(r.Left - CELLCONTROLOFFSET,r.Top - CELLCONTROLOFFSET,r.Right - r.Left - 1 + 2*CELLCONTROLOFFSET,r.Bottom - r.Top - 1 + 2*CELLCONTROLOFFSET);
          ctrl.Visible := True;
        end;
      end;
    end
    else
    begin
      //ctrl := CellControls[pt.X,pt.Y];

      if (pt.Y >= FixedRows) and (pt.X >= FixedCols) then
      begin
        ctrl := ci.Control;
        if Assigned(ctrl) then
        begin
          r := CellRect(pt.X,pt.Y);
          ctrl.SetBounds(r.Left - CELLCONTROLOFFSET,r.Top - CELLCONTROLOFFSET,r.Right - r.Left - 1 + 2*CELLCONTROLOFFSET,r.Bottom - r.Top - 1 + 2*CELLCONTROLOFFSET);
          ctrl.Visible := True;
        end;
      end;
    end;
  end;

  for i := 1 to FControlList.Count do
  begin
    ci := FControlList.Control[i - 1];

    pt.X := RemapCol(ci.X);
    pt.Y := RemapRow(ci.Y);

    if (pt.X < LeftCol) or (pt.X > LeftCol + VisibleColCount) or
       (pt.Y < TopRow) or (pt.Y > TopRow + VisibleRowCount) then
    begin
    end
    else
    begin
      ctrl := CellControls[pt.X,pt.Y];
      if (pt.Y >= FixedRows) and (pt.X >= FixedCols) then
      begin
        if Assigned(ctrl) then
        begin
          if ctrl.Visible then
          begin
            ctrl.Invalidate;
            ctrl.Width := ctrl.Width + 1;
            ctrl.Width := ctrl.Width - 1;
          end;
        end;
      end;
    end;
  end;
end;

function TAdvStringGrid.CellNameList: TStringList;
begin
  Result := nil;
end;

procedure TAdvStringGrid.TopLeftChanged;
var
  fcr,tcr,lr: TRect;
begin
  // get previous background rectangle
  if not FBackground.Bitmap.Empty and (FBackground.Display = bdFixed) then
  begin
    MouseToCell(Left,Top,longint(fcr.Left),longint(fcr.Top));
    MouseToCell(Left + FBackground.Bitmap.Width,Top + FBackground.Bitmap.Height,longint(fcr.Right),longint(fcr.Bottom));
  end;

  offsetrect(fcr,- LeftCol + FOldLeftCol, - TopRow + FOldTopRow);

  if SearchFooter.Visible and (FOldTopRow < TopRow) then
  begin
    lr := CellRect(Col,Row);

    if (lr.Bottom < Height - SearchPanel.Height) and (lr.Bottom > Height - SearchPanel.Height) then
    begin
      TopRow := TopRow + 1;
    end;
  end;

  inherited TopLeftChanged;

  if SelectionRectangle then
  begin
    //RepaintRect(TRect(Selection));
    if (Selection.Top <> Selection.Bottom) then
      Invalidate;
  end;

  // get new background rectangle & repaint
  if (not FBackground.Bitmap.Empty and (FBackground.Display = bdFixed)) then
  begin
    MouseToCell(Left,Top,longint(tcr.Left),longint(tcr.Top));
    MouseToCell(Left + FBackground.Bitmap.Width,Top + FBackground.Bitmap.Height,longint(tcr.Right),longint(tcr.Bottom));
    RepaintRect(fcr);
    RepaintRect(tcr);
  end;

  if (not FBackground.Bitmap.Empty and (FBackground.Display = bdTile)) then
    Invalidate;

  if (Background.Display in [bdGradientHorz, bdGradientVert]) and (Background.ColorTo <> clNone) then
    Invalidate;

  if (EditMode) and not (EditControl in [edNormal,edValidChars,edLowerCase,edUppercase,edLowerCase,edCapital]) then
    HideInplaceEdit;

  UpdateVScrollBar;
  UpdateHScrollBar;
  UpdateFooter;

  CellControlsUpdate;

  FOldLeftCol := LeftCol;
  FOldTopRow := TopRow;

  if (csDesigning in ComponentState) then
    Invalidate;

  if Assigned(SyncGrid.Grid) then
  begin
    if SyncGrid.ScrollVertical then
      SyncGrid.Grid.TopRow := TopRow;

    if SyncGrid.ScrollHorizontal then
      SyncGrid.Grid.LeftCol := LeftCol;
  end;

  if FocusHelper.Enabled then
  begin
    if (Col >= LeftCol) and (Row >= TopRow) and
     (Col < LeftCol + VisibleColCount) and
     (Row < TopRow + VisibleRowCount) and EditorMode then
    begin
      FocusGrid := Self;
      ShowFocusHelper(CellRect(Col,Row));
    end;
  end;

  if Assigned(vscrlctrl) then
    vscrlctrl.Invalidate;
  if Assigned(hscrlctrl) then
    hscrlctrl.Invalidate;
end;

function TAdvStringGrid.EllipsClick(s:string):string;
var
  c: Integer;
begin
  c := RemapCol(Col);
  Result := s;
  if Assigned(OnEllipsClick) then
  begin
    OnEllipsClick(self,c,Row,s);
    Result := s;
  end;
end;

function TAdvStringGrid.GetDateTimePicker:TGridDatePicker;
begin
  Result := TGridDatePicker(EditDate);
end;

procedure TAdvStringGrid.KeyUp(var Key: Word; Shift: TShiftState);
var
  pt: TPoint;
  CanSelect: Boolean;
  i,j,swp: integer;
  gr,oldgr: TGridRect;
begin
  if Key in [VK_LEFT,VK_RIGHT,VK_DOWN,VK_UP,VK_UP,VK_END,VK_PRIOR,VK_NEXT,VK_INSERT,VK_DELETE] then
    SearchInc := '';

  oldgr := Selection;

  if oldgr.Left > oldgr.Right  then
  begin
    swp := oldgr.Left;
    oldgr.Left := oldgr.Right;
    oldgr.Right := swp;
  end;

  if oldgr.Top > oldgr.Bottom  then
  begin
    swp := oldgr.Top;
    oldgr.Top := oldgr.Bottom;
    oldgr.Bottom := swp;
  end;

  inherited;

  if FNavigation.AlwaysEdit then
  begin
    if (Key in [VK_LEFT,VK_RIGHT,VK_DOWN,VK_UP]) and not HasStaticEdit(RealCol,Row) then
      ShowInplaceEdit;

    if (Key = VK_TAB) and (goTabs in Options) and not HasStaticEdit(RealCol,Row) then
      ShowInplaceEdit;
  end;

  if not EqualRect(TRect(FMoveSelection), TRect(Selection)) then
    if (Key in [VK_LEFT,VK_RIGHT,VK_DOWN,VK_UP, VK_TAB]) then
    begin
      SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);
    end;

  if FMouseActions.DisjunctCellSelect and (ssShift in Shift) and not (goEditing in Options) then
  begin
    for i := oldgr.Left to oldgr.Right do
      for j := oldgr.Top to oldgr.Bottom do
      begin
        swp := FSelectedCells.IndexOf(TObject(makelong(i,j)));
        if swp <> -1 then
          FSelectedCells.Delete(swp);
      end;

    gr := Selection;

    if gr.Left > gr.Right  then
    begin
      swp := gr.Left;
      gr.Left := gr.Right;
      gr.Right := swp;
    end;

    if gr.Top > gr.Bottom  then
    begin
      swp := gr.Top;
      gr.Top := gr.Bottom;
      gr.Bottom := swp;
    end;

    for i := gr.Left to gr.Right do
      for j := gr.Top to gr.Bottom do
      begin
        if not ((i = Col) and (j = Row)) then
        begin
          FSelectedCells.Add(makelong(i,j));
        end;
      end;
  end;

  if FMouseActions.DisjunctCellSelect and (Key = VK_SPACE) and not (goEditing in Options) then
  begin
    pt := BaseCell(Col,Row);

    if not IsFixed(pt.x,pt.y) then
    begin
      CanSelect := true;

      if Assigned(OnSelectCell) then
        OnSelectCell(Self, pt.X, pt.Y, CanSelect);

      if not CanSelect then
        Exit;

      if ssCtrl in Shift then
      begin
        i := FSelectedCells.IndexOf(Pointer(makelong(pt.x,pt.y)));
        if i = -1 then
          FSelectedCells.Add(MakeLong(pt.x,pt.y))
        else
          FSelectedCells.Delete(i);
      end
      else
      begin
        // delete previous selections
        for i := 1 to FSelectedCells.Count do
          RepaintCell(loword(FSelectedCells.Items[i - 1]), hiword(FSelectedCells.Items[i - 1]));
        FSelectedCells.Clear;
        FSelectedCells.Add(MakeLong(pt.x,pt.y));
      end;
    end;

    if (Selection.Left <> Selection.Right) or
       (Selection.Top <> Selection.Bottom) then
    begin
      for i := Selection.Left to Selection.Right do
      begin
        for j := Selection.Top to Selection.Bottom do
        begin
          if not ((i = pt.x) and (j = pt.y)) then
            FSelectedCells.Add(MakeLong(i,j));
        end;
      end;
      for i := 1 to FSelectedCells.Count do
        RepaintCell(loword(FSelectedCells.Items[i - 1]),hiword(FSelectedCells.Items[i - 1]));
    end;

    RepaintCell(Col,Row);
  end;
end;

function TAdvStringGrid.GetVersionNr: Integer;
begin
  Result := MakeLong(MakeWord(BLD_VER,REL_VER),MakeWord(MIN_VER,MAJ_VER));
end;

function TAdvStringGrid.GetVersionString:string;
var
  vn: Integer;
begin
  vn := GetVersionNr;
  Result := IntToStr(Hi(Hiword(vn)))+'.'+IntToStr(Lo(Hiword(vn)))+'.'+IntToStr(Hi(Loword(vn)))+'.'+IntToStr(Lo(Loword(vn)))+' '+DATE_VER;
end;

function TAdvStringGrid.SelectionToForm(ARect: TGridRect): TForm;
var
  bmp, finalbmp: TBitmap;
  cr1,cr2,ar:TRect;
  img: TImage;
  h: integer;
begin
  bmp := TBitmap.Create;
  bmp.Width := Width;
  bmp.Height := Height;
  PaintTo(bmp.Canvas,0,0);

  cr1 := GetCellRect(ARect.Left, ARect.Top);
  cr2 := GetCellRect(ARect.Right, ARect.Bottom);

  if cr1.Left > cr2.Left then
  begin
    ar := cr1;
    cr1 := cr2;
    cr2 := ar;
  end;

  if (cr1.Bottom > cr2.Bottom) then
  begin
    h := cr1.Bottom;
    cr1.Bottom := cr2.Bottom;
    cr2.Bottom := h;
    h := cr1.Top;
    cr1.Top := cr2.Top;
    cr2.Top := h;
  end;


  finalbmp := TBitmap.Create;
  finalbmp.Width := cr2.Right - cr1.Left + 1;
  finalbmp.Height := cr2.Bottom - cr1.Top + 1;

  finalbmp.Canvas.CopyRect(Rect(0,0,finalbmp.Width,finalbmp.Height), bmp.Canvas,
    Rect(cr1.Left + 1, cr1.Top + 1, cr2.Right + 2, cr2.Bottom + 2));

  if (ARect.Left = 0) and (FixedCols > 0) and (goFixedHorzLine in Options) then
  begin
    finalbmp.Canvas.Pen.Color := GridFixedLineColor;
    finalbmp.Canvas.MoveTo(0,0);
    finalbmp.Canvas.LineTo(0,finalbmp.Height);
  end;

  if (ARect.Top = 0) and (FixedRows > 0) and (goFixedVertLine in Options) then
  begin
    finalbmp.Canvas.Pen.Color := GridFixedLineColor;
    finalbmp.Canvas.MoveTo(0,0);
    finalbmp.Canvas.LineTo(finalbmp.Width,0);
  end;

  bmp.Free;

  Result := TNoActiveForm.CreateNew(Self);
  Result.BorderStyle := bsNone;
  Result.Width := finalbmp.Width;
  Result.Height := finalbmp.Height;
  Result.FormStyle := fsStayOnTop;

  img := TImage.Create(Result);
  img.Parent := Result;
  img.Align := alClient;

  img.Picture.Bitmap.Assign(finalbmp);

  Result.AlphaBlendValue := 192;
  Result.AlphaBlend := true;

  finalbmp.Free;
end;

procedure TAdvStringGrid.InitOrigColSizes;
var
  i: integer;
begin
  FOrigColSizes.Clear;

  for I := 0 to ColCount - 1 do
    FOrigColSizes.Add(ColWidths[I]);

  FOldSize := Width;
end;

procedure TAdvStringGrid.BalloonInit;

  procedure WindowBlend(hwnd:THandle;colorkey:TColor;alpha:byte;r:TRect);
  var
   dw: dword;
   blnd: _BLENDFUNCTION;
   dskdc: thandle;
   size,src: tpoint;
   hdc: thandle;
  begin
   hdc := GetDC(hwnd);
   dw := GetWindowLong(hwnd, GWL_EXSTYLE);
   SetWindowLong(hwnd, GWL_EXSTYLE,dw or WS_EX_LAYERED);
   DynaLink_SetLayeredWindowAttributes(hwnd,DWORD(colorkey),alpha,2);
   blnd.BlendOp := AC_SRC_OVER;
   blnd.BlendFlags := 0;
   blnd.SourceConstantAlpha := 0;
   blnd.AlphaFormat := 0;
   dskdc := GetDC(0);
   size := Point(r.right-r.left,r.bottom-r.top);
   src := Point(r.left,r.top);
   DynaLink_UpdateLayeredWindow(hwnd,dskdc,nil,@size,hdc,@src,dword(colorkey), blnd,ULW_ALPHA);
   ReleaseDC(0,dskdc);
   ReleaseDC(hwnd,hdc);
  end;

begin
  if Balloon.FInit then
    Exit;

  Balloon.FInit := true;

  CreateToolTip;
  AddToolTip(3,'AdvGrid','ToolTipText');
  if Balloon.InitialDelay <> -1 then
    SendMessage(fhtooltip,TTM_SETDELAYTIME, TTDT_INITIAL, Balloon.InitialDelay);

  if Balloon.ReshowDelay <> -1 then
    SendMessage(fhtooltip,TTM_SETDELAYTIME, TTDT_RESHOW, Balloon.ReshowDelay);

  if Balloon.AutoHideDelay <> -1 then
    SendMessage(fhtooltip,TTM_SETDELAYTIME, TTDT_AUTOPOP, Balloon.AutoHideDelay);

  if (Balloon.Transparency > 0) then
    WindowBlend(fhToolTip,0,255 - Balloon.Transparency,Rect(0,0,100,100));
end;

procedure TAdvStringGrid.BalloonDone;
begin
  if Balloon.FInit then
    DestroyToolTip;
  Balloon.FInit := false;
end;

procedure TAdvStringGrid.BalloonChange(Sender: TObject);
begin
  if not (csLoading in ComponentState) then
  begin
    if Balloon.Enable then
      BalloonInit
    else
      BalloonDone;
  end;
end;

procedure TAdvStringGrid.ModifiedChanged(Sender: TObject);
begin
  RepaintCol(0);
end;

procedure TAdvStringGrid.BandsChanged(Sender: TObject);
begin
  Invalidate;
end;

procedure TAdvStringGrid.SearchChanged(Sender: TObject);
begin
  if (csLoading in ComponentState) then
    Exit;
  if not Assigned(FSearchPanel) then
    Exit;

  if Assigned(FSearchPanel) and (FSearchPanel.FHiliteButton.Down and FSearchPanel.Visible and not FSearchFooter.Visible) or FSearchFooter.AlwaysHighLight then
  begin
    InvalidateGrid;
  end;

  FSearchPanel.Color := FSearchFooter.Color;
  FSearchPanel.ColorTo := FSearchFooter.ColorTo;
  FSearchPanel.Visible := FSearchFooter.Visible;

  FSearchPanel.FindNextCaption := FSearchFooter.FindNextCaption;
  FSearchPanel.FindPrevCaption := FSearchFooter.FindPrevCaption;
  FSearchPanel.MatchCaseCaption := FSearchFooter.MatchCaseCaption;
  FSearchPanel.FForwardButton.Caption := FSearchFooter.FindNextCaption;
  FSearchPanel.FBackwardButton.Caption := FSearchFooter.FindPrevCaption;
  FSearchPanel.FMatchCase.Caption := FSearchFooter.MatchCaseCaption;
  FSearchPanel.FHiliteButton.Caption := FSearchFooter.HighLightCaption;
  FSearchPanel.HighLightCaption := FSearchFooter.HighLightCaption;

  FSearchPanel.HintFindNext := FSearchFooter.HintFindNext;
  FSearchPanel.HintFindPrev := FSearchFooter.HintFindPrev;
  FSearchPanel.HintClose := FSearchFooter.HintClose;
  FSearchPanel.HintHighLight := FSearchFooter.HintHighLight;

  FSearchPanel.Font := FSearchFooter.Font;

  if ControlLook.ControlStyle = csFlat then
  begin
    FSearchPanel.FBackwardButton.Flat := true;
    FSearchPanel.FForwardButton.Flat := true;
    FSearchPanel.FHiliteButton.Flat := true;
  end;

  if (ControlLook.ControlStyle in [csWinXP,csTheme]) and not AutoThemeAdapt then
  begin
    FSearchPanel.FBackwardButton.AutoXPStyle := true;
    FSearchPanel.FForwardButton.AutoXPStyle := true;
    FSearchPanel.FHiliteButton.AutoXPStyle := true;
    FSearchPanel.FBackwardButton.Flat := false;
    FSearchPanel.FForwardButton.Flat := false;
    FSearchPanel.FHiliteButton.Flat := false;
  end;

  if ControlLook.ControlStyle = csClassic then
  begin
    FSearchPanel.FBackwardButton.AutoXPStyle := false;
    FSearchPanel.FForwardButton.AutoXPStyle := false;
    FSearchPanel.FHiliteButton.AutoXPStyle := false;
    FSearchPanel.FBackwardButton.Flat := false;
    FSearchPanel.FForwardButton.Flat := false;
    FSearchPanel.FHiliteButton.Flat := false;
  end;

  if AutoThemeAdapt then
  begin
    FSearchPanel.FBackwardButton.AutoThemeAdapt := true;
    FSearchPanel.FForwardButton.AutoThemeAdapt := true;
    FSearchPanel.FHiliteButton.AutoThemeAdapt := true;
    FSearchPanel.FBackwardButton.Flat := true;
    FSearchPanel.FForwardButton.Flat := true;
    FSearchPanel.FHiliteButton.Flat := true;
  end;

  FSearchPanel.FHiliteButton.Visible := FSearchFooter.ShowHighlight;
  FSearchPanel.FExitButton.Visible := FSearchFooter.ShowClose;
  FSearchPanel.FMatchCase.Visible := FSearchFooter.ShowMatchCase;
  FSearchPanel.FMatchCase.Transparent := true;
  FSearchPanel.FBackwardButton.Visible := FSearchFooter.ShowFindPrev;
  FSearchPanel.FForwardButton.Visible := FSearchFooter.ShowFindNext;

  FSearchPanel.FExitButton.Hint := FSearchPanel.HintClose;
  FSearchPanel.FExitButton.ShowHint := FSearchPanel.HintClose <> '';
  FSearchPanel.FForwardButton.Hint := FSearchPanel.HintFindNext;
  FSearchPanel.FForwardButton.ShowHint := FSearchPanel.HintFindNext <> '';
  FSearchPanel.FBackwardButton.Hint := FSearchPanel.HintFindPrev;
  FSearchPanel.FBackwardButton.ShowHint := FSearchPanel.HintFindPrev <> '';
  FSearchPanel.FHiliteButton.Hint := FSearchPanel.HintHighlight;
  FSearchPanel.FHiliteButton.ShowHint := FSearchPanel.HintHighlight <> '';

  if not FSearchPanel.FHiliteButton.Visible then
  begin
    FSearchPanel.FMatchCase.Left := 330;
    FSearchPanel.FMatchCase.Width := 200;
  end
  else
  begin
    FSearchPanel.FMatchCase.Left := 425;
    FSearchPanel.FMatchCase.Width := 200;
  end;

  if not FSearchPanel.FForwardButton.Visible then
    FSearchPanel.FForwardButton.Height := 0
  else
    FSearchPanel.FForwardButton.Height := 23;

  if not FSearchPanel.FBackwardButton.Visible then
    FSearchPanel.FBackwardButton.Height := 0
  else
    FSearchPanel.FBackwardButton.Height := 23;

  if not FSearchPanel.FHiliteButton.Visible then
    FSearchPanel.FHiliteButton.Height := 0
  else
    FSearchPanel.FHiliteButton.Height := 23;

  if not FSearchPanel.FMatchCase.Visible then
    FSearchPanel.FMatchCase.Height := 0
  else
    FSearchPanel.FMatchCase.Height := 18;

  if not FSearchFooter.Visible then
    FSearchPanel.Height := 0
  else
  begin
    FSearchPanel.Height := 32;
    FSearchPanel.Top := Height - 32;
  end;

  if SearchFooter.Visible then
  begin
    ScrollToLastRow;
  end;
end;

procedure TAdvStringGrid.CreateToolTip;
begin
  fhToolTip := CreateWindowEx(0, 'Tooltips_Class32', nil, TTS_ALWAYSTIP or TTS_BALLOON or TTS_NOPREFIX,
    Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT),Integer(CW_USEDEFAULT),
    Integer(CW_USEDEFAULT), Handle, 0, hInstance, nil);

  if fhToolTip <> 0 then
    SetWindowPos(fhToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
end;

procedure TAdvStringGrid.DestroyToolTip;
begin
  DestroyWindow(FHToolTip);
end;

procedure TAdvStringGrid.DestroyWnd;
begin
  inherited;
  if not (csDesigning in ComponentState) then
    BalloonDone;
end;

procedure TAdvStringGrid.AddToolTip(IconType: Integer; Text, Title: string);
var
  Item: THandle;
  Rect: TRect;
  ti: TToolInfo;
  buffer: array[0..255] of char;
begin
  Item := self.Handle;

  if (Item <> 0) AND (Windows.GetClientRect(Item, Rect)) then
  begin
    ti.cbSize := SizeOf(TToolInfo);

    ti.uFlags := TTF_SUBCLASS or TTF_IDISHWND ;
    ti.hInst := hInstance;

    ti.hwnd := Item;
    ti.Rect := Rect;
    ti.uId := Handle;

    ti.lpszText :=  LPSTR_TEXTCALLBACK;
    SendMessage(fhToolTip, TTM_ADDTOOL, 0, LParam(@ti));
    FillChar(buffer, sizeof(buffer), #0);
    lstrcpy(buffer, PChar(Title));
    if (IconType > 3) or (IconType < 0) then IconType := 0;
    SendMessage(fhToolTip, TTM_SETTITLE, IconType, LParam(@buffer));
  end;
end;

procedure TAdvStringGrid.SubclassProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_GETDLGCODE) and (goTabs in Options)  then
  begin
    msg.Result := msg.Result or DLGC_WANTCHARS or DLGC_WANTTAB or DLGC_WANTARROWS;
    Exit;
  end;

  FGridControlWndProc(Msg);
end;

procedure TAdvStringGrid.UnitChanged(Sender: TObject; NewUnit:string);
begin
  if Assigned(OnUnitChanged) then
    OnUnitChanged(Self, Col, Row, NewUnit);
end;

procedure TAdvStringGrid.OleColumnDragStart(ACol, AIndex: integer; AList: TCustomListbox);
begin
  FOleDragCol := ACol;
  FOleDragIndex := AIndex;
  FOleDragList := AList;
end;


{OLE Drag & Drop interface only supported in Delphi 4+}

constructor TGridDropSource.Create(AGrid: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AGrid;
end;

procedure TGridDropSource.CurrentEffect(dwEffect: Longint);
begin
  if dwEffect = DROPEFFECT_MOVE then
    FLastEffect := dwEffect;

  if dwEffect = DROPEFFECT_COPY then
    FLastEffect := dwEffect;
end;

procedure TGridDropSource.QueryDrag;
var
  pt: TPoint;
begin
  GetCursorPos(pt);

  if not FGrid.DragDropSettings.ShowCells then
  begin
    FGrid.MoveButton.Left := pt.x;
    FGrid.MoveButton.Top := pt.y - FGrid.MoveButton.Height;
  end
  else
  begin
    if Assigned(FGrid.MoveForm) then
    begin
      FGrid.MoveForm.Left := pt.x + 4;
      FGrid.MoveForm.Top := pt.y + 4;
    end;
  end;
end;

procedure TGridDropSource.DragDropStop;
begin
  inherited;

  if FGrid.DragDropSettings.ShowCells then
  begin
    if Assigned(FGrid.MoveForm) then
      FreeAndNil(FGrid.MoveForm);
  end;
end;

constructor TGridDropTarget.Create(AGrid: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AGrid;
end;

procedure TGridDropTarget.DropCol(pt: TPoint; Col: Integer);
var
  c,r,i,j,dc: Integer;
  ehcm: boolean;
begin
  FGrid.ScreenToCell(pt,c,r);

  if c < 0 then
    c := FGrid.ColCount;

  if dfCol in DropFormats then
  begin
    FGrid.ArwD.Visible := False;
    FGrid.ArwU.Visible := False;
    FGrid.MoveButton.Visible := False;
  end;

  if FGrid.FOleDragCol <> -1 then
  begin
    FGrid.FOleDragList.Items.Delete(FGrid.FOleDragIndex);
    j := 0;
    for i := 0 to FGrid.FColumnOrder.Count - 1 do
    begin
      if FGrid.FOleDragCol = FGrid.FColumnOrder[i]  then
      begin
        FGrid.UnhideColumn(i);
        j := i;
        break;
      end;
    end;

    if c >= 0 then
    begin
      ehcm := FGrid.EnhRowColMove;
      FGrid.EnhRowColMove := True;
      FGrid.MoveColumn(FGrid.DisplColIndex(j), c);
      FGrid.EnhRowColMove := ehcm;
    end;

    FGrid.FOleDragCol := -1;
  end
  else

  if FGrid.DragDropSettings.OleColumnReorder then
  begin
    if c > FGrid.ColCount - 1 then
      c := FGrid.ColCount - 1;
    dc := FGrid.DisplColIndex(Col);

    if (dc <> c) then
    begin
      ehcm := FGrid.EnhRowColMove;
      FGrid.EnhRowColMove := True;
      FGrid.MoveColumn(dc, c);
      FGrid.EnhRowColMove := ehcm;
    end;
  end;

  if Assigned(FGrid.OnOleDropCol) then
    FGrid.OnOleDropCol(FGrid,r,c,Col);
end;

procedure TGridDropTarget.DropStream(pt: TPoint; ms: TMemoryStream);
var
  r,c: integer;
begin
  ms.Position := 0;
  FGrid.ScreenToCell(pt,c,r);
  FGrid.LoadAtPointFromBinStream(Point(c,r),ms);
  FGrid.ArwL.Visible := False;
  FGrid.ArwD.Visible := False;
  FGrid.MoveButton.Visible := False;
  if Assigned(FGrid.FOnOleDropped) then
    FGrid.FOnOleDropped(FGrid,FGrid.Selection);
end;

procedure TGridDropTarget.DropText(pt: TPoint; s: string);
var
  c,r,tr,i: Integer;
  Allow: Boolean;
  gr: TGridRect;
  Size: TPoint;
  pcols,prows: integer;
  Rect: TRect;
  apnd: boolean;

begin
  FGrid.ScreenToCell(pt,c,r);
  apnd := false;

  if (r = -1) and not (dfCol in DropFormats) and
    FGrid.FDragDropSettings.FOleEntireRows and FGrid.FDragDropSettings.FOleAppendRows then
  begin
    // get rect of last row
    Rect := FGrid.CellRect(FGrid.LeftCol, FGrid.RowCount - 1);
    // allow to append row via drag & drop
    if Rect.Bottom <= pt.Y then
    begin
      apnd := true;
      c := FGrid.FixedCols;
      r := FGrid.RowCount - 1;
    end;
  end;

  // in case of dropping entire rows, force selection to leftmost column
  if not (dfCol in DropFormats) and FGrid.FDragDropSettings.FOleEntireRows then
  begin
    c := 0;
  end;

  Allow := True;

  Size := FGrid.PasteSize(PChar(s));

  if (goRowSelect in FGrid.Options) then
  begin
    if FGrid.FDragDropSettings.OleEntireRows then
      c := 0
    else
      c := FGrid.FixedCols;
  end;

  if Assigned(FGrid.FOnOleDrop) then
    FGrid.FOnOleDrop(FGrid,r,c,s,Allow);

  if Allow then
  begin
    gr := FGrid.FDropSelection;

    if (r <= gr.Top) and (FGrid.DragDropSettings.OLERemoveRows) then
    begin
      gr.Top := gr.Top + size.y + 1;
      gr.Bottom := gr.Bottom + size.y + 1;

      if FGrid.MouseActions.DisjunctRowSelect then
      begin
        for i := 1 to size.y + 1 do
          FGrid.FRowSelect.Insert(r,nil);
      end;
    end;

    FGrid.FDropSelection := gr;

    if (r = 0) and (FGrid.FixedRowAlways) and (FGrid.RowCount = 1) then
      Inc(r);

    if FGrid.FDragDropSettings.OleInsertRows then
    begin
      tr := FGrid.TopRow;
      if (tr > FGrid.FixedRows) then inc(tr);

      if apnd then
      begin
        FGrid.RowCount := FGrid.RowCount + size.y + 1;
        Inc(r);
      end
      else
        FGrid.InsertRows(r,size.y + 1);

      if (tr > 0) then
        FGrid.TopRow := tr;
    end;

    FGrid.PasteText(c, r, PChar(s), pcols, prows);

    if c < FGrid.FixedCols then
      c := FGrid.FixedCols;

    gr.Top := r;
    gr.Left := c;
    gr.Bottom := r + size.y;

    if goRowSelect in FGrid.Options then
      gr.Right := c + size.x - FGrid.FixedCols
    else
      gr.Right := c + size.x - 1;

    FGrid.Selection := gr;
  end;

  FGrid.ArwL.Visible := False;
  FGrid.ArwD.Visible := False;
  FGrid.MoveButton.Visible := False;

  if Assigned(FGrid.FOnOleDropped) then
    FGrid.FOnOleDropped(FGrid,gr);
end;

procedure TGridDropTarget.DragMouseMove(pt: TPoint; var Allow: Boolean; DropFormats: TDropFormats);
var
  c,r: Integer;
  Rect: TRect;
  apnd: boolean;
begin
  inherited;

  FGrid.ScreenToCell(pt,c,r);
  pt := FGrid.ScreenToClient(pt);
  apnd := false;

  if (r = -1) and not (dfCol in DropFormats) and
    FGrid.FDragDropSettings.FOleEntireRows and FGrid.FDragDropSettings.FOleAppendRows then
  begin
    // get rect of last row
    Rect := FGrid.CellRect(FGrid.LeftCol, FGrid.RowCount - 1);

    // allow to append row via drag & drop
    if Rect.Bottom <= pt.Y then
    begin
      apnd := true;
      c := FGrid.FixedCols;
      r := FGrid.RowCount - 1;
    end;
  end;

  Allow := (c >= 0) and (r >= 0);

  if Allow and not (dfCol in DropFormats) then
  begin
    if (r = 0) and (FGrid.TopRow > FGrid.FixedRows) then
    begin
      FGrid.TopRow := FGrid.TopRow - 1;
    end
    else
    if (pt.y < 8) and (FGrid.FixedRows = 0) and (FGrid.TopRow > 0) then
    begin
      FGrid.TopRow := FGrid.TopRow - 1;
    end
    else
    if r = FGrid.TopRow + FGrid.VisibleRowCount then
    begin
      FGrid.TopRow := FGrid.TopRow + 1;
    end;

    if ((FGrid.FTimerTicks mod 2) = 0) then
    begin
      FGrid.FTimerTicks := FGrid.FTimerTicks + 1;

      if (c = 0) and (FGrid.LeftCol > FGrid.FixedCols) then
      begin
        FGrid.LeftCol := FGrid.LeftCol - 1;
      end;

      if (c = FGrid.LeftCol + FGrid.VisibleColCount) then
      begin
        FGrid.LeftCol := FGrid.LeftCol + 1;
      end;
    end;
  end;

  if (dfCol in DropFormats) then
  begin
    if c < 0 then
    begin
      c := FGrid.ColCount;
      r := 0;
      Allow := true;
    end
    else
      if (r >= FGrid.FixedRows) or (c < FGrid.FixedCols) then
        Allow := False;
  end
  else
  begin
    if (r < FGrid.FixedRows) and
       not ((FGrid.RowCount = 1) and FGrid.FixedRowAlways) then
      Allow := False;
  end;

  Allow := Allow or (dfFile in DropFormats);

  Allow := Allow or (dfGridCells in DropFormats);

  if Assigned(FGrid.FOnOleDragOver) then
    FGrid.FOnOleDragOver(FGrid,r,c,Allow);

  Allow := Allow and (((r >= 0) and (c >= 0)) or (dfFile in DropFormats));

  if (dfCol in DropFormats) and Allow then
  begin
    FGrid.ArwD.Visible := True;
    FGrid.ArwU.Visible := True;

    Rect := FGrid.CellRect(c,r);
    pt := FGrid.ClientToScreen(Point(Rect.Left,Rect.Top));

    FGrid.ArwD.Top := pt.y - 8;
    FGrid.ArwD.Left := pt.x;

    pt := FGrid.ClientToScreen(Point(Rect.Left,Rect.Bottom));

    FGrid.ArwU.Top := pt.y;
    FGrid.ArwU.Left := pt.x;

    Exit;
  end
  else
  if Allow and (r >=0) and (c >= 0) then
  begin
    if (r = 0) and FGrid.FixedRowAlways then
    begin
      Inc(r);
      apnd := false;
    end;

    if FGrid.FDragDropSettings.FOleEntireRows then
      Rect := FGrid.CellRect(FGrid.FixedCols,r)
    else
      Rect := FGrid.CellRect(c,r);

    pt := FGrid.ClientToScreen(point(Rect.Left,Rect.Top));

    if apnd then
      pt.Y := pt.Y + FGrid.RowHeights[r];

    FGrid.ArwL.Visible := True;
    FGrid.ArwL.Top := pt.y;
    FGrid.ArwL.Left := pt.x - 10
  end
  else
  begin
   FGrid.ArwL.Visible := False;
   FGrid.ArwD.Visible := False;
   FGrid.ArwU.Visible := False;
  end;
end;

procedure TGridDropTarget.DragMouseLeave;
begin
  FGrid.ArwD.Visible := False;
  FGrid.ArwU.Visible := False;
  FGrid.ArwL.Visible := False;
end;

procedure TGridDropTarget.DropRTF(pt: TPoint; s: string);
var
  c,r: Integer;
  Allow: Boolean;
begin
  FGrid.ScreenToCell(pt,c,r);

  Allow := True;
  if Assigned(FGrid.FOnOleDrop) then
    FGrid.FOnOleDrop(FGrid,r,c,s,Allow);

  if Allow then
    FGrid.Cells[c,r] := s;

  FGrid.ArwL.Visible := False;
  FGrid.ArwD.Visible := False;
end;

procedure TGridDropTarget.DropURL(pt: TPoint; s: string);
var
  c,r: Integer;
  Allow: Boolean;
begin
  FGrid.ScreenToCell(pt,c,r);
  Allow := True;
  if Assigned(FGrid.FOnOleDropURL) then
    FGrid.FOnOleDropURL(FGrid,r,c,s,Allow);

  if Allow then
    FGrid.Cells[c,r] := s;

  FGrid.ArwL.Visible := False;
  FGrid.ArwD.Visible := False;
end;


procedure TGridDropTarget.DropFiles(pt:TPoint; Files:TStrings);
var
  Allow: Boolean;
  r,c: Integer;
begin
  if Files.Count = 1 then
  begin
    Allow := True;

    if Assigned(FGrid.OnOleDropFile) then
    begin
      FGrid.ScreenToCell(pt,c,r);
      FGrid.OnOleDropFile(FGrid,r,c,Files[0],Allow);
    end;

    if Allow then
    begin
      if Pos('.CSV',UpperCase(Files[0])) > 0 then
      begin
        if Assigned(FGrid.FOnOleDrop) then
          FGrid.FOnOleDrop(FGrid,-1,-1,Files[0],Allow);
        if Allow then
          FGrid.LoadFromCSV(files[0]);
      end;

      if Pos('.XLS',UpperCase(Files[0])) > 0 then
      begin
        if Assigned(FGrid.FOnOleDrop) then
          FGrid.FOnOleDrop(FGrid,-1,-1,Files[0],Allow);
        if Allow then
          FGrid.LoadFromXLS(Files[0]);
      end;
    end;
  end;

  FGrid.ArwL.Visible := False;
  FGrid.ArwD.Visible := False;
end;

procedure Initialize;
begin
  OleInitialize(Nil);
end;

{ TGridItem }
constructor TGridItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FItems := TStringList.Create;
end;

destructor TGridItem.Destroy;
begin
  FItems.Free;
  inherited Destroy;
end;

procedure TGridItem.SetHeight(const Value: Integer);
begin
  FHeight := Value;
end;

procedure TGridItem.SetIdx(const Value: Integer);
begin
  FIdx := Value;
end;

procedure TGridItem.SetItems(const Value: TStrings);
begin
  FItems := Value;
end;

{ TAdvRichEdit }

procedure TAdvRichEdit.SelNormal;
begin
  SelFormat(0);
end;

procedure TAdvRichEdit.SelSubscript;
begin
  SelFormat(-40);
end;

procedure TAdvRichEdit.SelSuperscript;
begin
  SelFormat(40);
end;

procedure TAdvRichEdit.SelFormat(Offset: Integer);
var
  Format: TCharFormat; { defined in Unit RichEdit }
begin
  FillChar( Format, SizeOf(Format), 0);
  with Format do
  begin
    cbSize := SizeOf(Format);
    dwMask := CFM_OFFSET;
    yOffset := Offset; { superscript by 40 twips, negative Values give subscripts}
  end;
  Perform( EM_SETCHARFORMAT, SCF_SELECTION, LParam(@Format));
end;

constructor TAdvRichEdit.Create(AOwner: TComponent);
begin
  inherited;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TAdvRichEdit.ReCreate;
begin
  ReCreateWnd;
end;

procedure TAdvRichEdit.WMGetDlgCode(var Msg: TWMGetDlgCode);
begin
  inherited;
  Msg.Result := Msg.Result or DLGC_WANTTAB;
end;

procedure TAdvRichEdit.WMKillFocus(var Msg: TMessage);
begin
  if FGrid.InvokedFocusChange then
    Exit;

  if integer(Msg.wparam) = Integer(FGrid.Handle) then
    FGrid.HideInplaceEdit;

  inherited;
end;


procedure TAdvRichEdit.CNNotify(var Msg: TWMNotify);
type
  PREQRESIZE = ^TREQRESIZE;
  TREQRESIZE = record
    NMHdr: TNMHdr;
    rc: TRect;
  end;
var
  ReqResize: PREQRESIZE;
  NewHeight: Integer;
//  NewWidth: Integer;
  R: TRect;
  VerInfo: TOSVersionInfo;
begin
  if Msg.NMHdr^.Code = EN_REQUESTRESIZE then
  begin
    ReqResize := PREQRESIZE(Msg.NMHdr);

    if not (csDesigning in ComponentState) then
    begin
      if FGrid.RichEdit.HandleAllocated then
      begin
        if Msg.NMHdr^.hwndFrom = FGrid.RichEdit.Handle then
        begin
          FGrid.RichEdit.FReqWidth := ReqResize^.rc.Right - ReqResize^.rc.Left;
          FGrid.RichEdit.FReqHeight := ReqResize^.rc.Bottom - ReqResize^.rc.Top;
        end;
      end;

      if not FGrid.InplaceRichEdit.HandleAllocated then
        Exit;

      ReqResize := PREQRESIZE(Msg.NMHdr);

      with ReqResize^ do
      begin
        if FGrid.SizeWhileTyping.Height and
           (Msg.NMHdr^.hwndFrom = FGrid.InplaceRichEdit.Handle)
           and not FGrid.InplaceRichEdit.FLocked then
        begin
          NewHeight := ReqResize^.rc.Bottom - ReqResize^.rc.Top + 5;
          // NewWidth := ReqResize^.rc.Right - ReqResize^.rc.Left;

          if NewHeight > FGrid.RowHeights[FGrid.Row] then
          begin
            R := FGrid.CellRect(FGrid.Col,FGrid.Row);
            if R.Top + NewHeight < FGrid.Height then
            begin
              Height := NewHeight + 4;

              VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
              GetVersionEx(verinfo);

              if (verinfo.dwPlatformId = VER_PLATFORM_WIN32_NT) then
              begin
                // do not do this on Win9x
                // r := Rect(2,2,NewWidth - 2,NewHeight - 2);
                // SendMessage(Handle,EM_SETRECT,0,Longint(@r));
              end;

              FGrid.RowHeights[FGrid.Row] := NewHeight + 5;

              if Assigned(FGrid.OnEndRowSize) then
                FGrid.OnEndRowSize(FGrid,FGrid.Row);
            end;
          end;

        end;

      end;
    end;
  end;
  inherited;
end;

procedure TAdvRichEdit.Lock;
begin
  FLocked := True;
end;

procedure TAdvRichEdit.Unlock;
begin
  FLocked := False;
end;

procedure TAdvRichEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if (Key = VK_TAB) and (goTabs in FGrid.Options) then
  begin
    FGrid.SetFocus;
    FGrid.KeyDown(Key,Shift);
    FGrid.ShowInplaceEdit;
  end;

  if (Key in [VK_UP,VK_DOWN]) and not FGrid.WordWrap
     and not FGrid.MultiLineCells then
  begin
    FGrid.SetFocus;
    FGrid.KeyDown(Key,Shift);
  end;
end;

function TAdvRichEdit.IsSelSubscript: Boolean;
var
  Format: TCharFormat; { defined in Unit RichEdit }
begin
  FillChar( Format, SizeOf(Format), 0);
  with Format do
  begin
    cbSize := SizeOf(Format);
    dwMask := CFM_OFFSET;
  end;
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,LParam(@Format));
  Result := Format.yOffset = -40;
end;

function TAdvRichEdit.IsSelNormal: Boolean;
var
  Format: TCharFormat; { defined in Unit RichEdit }
begin
  FillChar( Format, SizeOf(Format), 0);
  with Format do
  begin
    cbSize := SizeOf(Format);
    dwMask := CFM_OFFSET;
  end;
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,LParam(@Format));
  Result := Format.yOffset = 0;
end;

function TAdvRichEdit.IsSelSuperscript: Boolean;
var
  Format: TCharFormat; { defined in Unit RichEdit }
begin
  FillChar( Format, SizeOf(Format), 0);
  with Format do
  begin
    cbSize := SizeOf(Format);
    dwMask := CFM_OFFSET;
  end;
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,LParam(@Format));
  Result := Format.yOffset = 40;
end;

{ TFilter }

function TFilter.Add: TFilterData;
begin
  Result := TFilterData(inherited Add);
  if Count = 1 then
    Result.Operation := foNone
  else
    Result.Operation := foAND;
end;

constructor TFilter.Create(AOwner: TAdvStringGrid);
begin
  inherited Create(TFilterData);
  FOwner := AOwner;
end;

function TFilter.GetColFilter(Col: Integer): TFilterData;
var
  i: Integer;
begin
  for i := 1 to Count do
  begin
    if Items[i - 1].Column = Col then
    begin
      Result := Items[i - 1];
      Exit;
    end;
  end;
  Result := Add;
  Result.Column := Col;
end;

function TFilter.GetItem(Index: Integer): TFilterData;
begin
  Result := TFilterData(inherited GetItem(Index));
end;

function TFilter.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TFilter.RemoveColumnFilter(Col: integer);
var
  i: integer;
begin
  i := Count;

  while i > 0 do
  begin
    dec(i);
    if Items[i].Column = Col then
      Delete(i);
  end;
  if Assigned(FOwner) then
  begin
    FOwner.RepaintCell(Col,0);
  end;
end;


function TFilter.HasFilterType(Col: integer): TFilterType;
var
  i: Integer;
begin
  Result := ftContains;

  for i := 1 to Count do
  begin
    if Items[i - 1].Column = Col then
    begin
      Result := Items[i - 1].FilterType;
      Break;
    end;
  end;
end;

function TFilter.HasFilter(Col: integer): Boolean;
var
  i: Integer;
begin
  Result := false;

  for i := 1 to Count do
  begin
    if Items[i - 1].Column = Col then
    begin
      Result := true;
      Break;
    end;
  end;
end;

function TFilter.HasOtherFilter(Col: integer): Boolean;
var
  i: Integer;
begin
  Result := false;

  for i := 1 to Count do
  begin
    if Items[i - 1].Column <> Col then
    begin
      Result := true;
      Break;
    end;
  end;
end;


function TFilter.Insert(index: Integer): TFilterData;
begin
  Result := TFilterData(inherited Add);
end;

procedure TFilter.SetItem(Index: Integer; Value: TFilterData);
begin
  inherited SetItem(Index, Value);
end;

procedure TFilter.Update(Item: TCollectionItem);
begin
  inherited;
  if Assigned(FOwner) then
    FOwner.RepaintRow(0);
end;

{ TBackGround }

procedure TBackGround.Assign(Source: TPersistent);
begin
  if (Source is TBackGround) then
  begin
    FTop := (Source as TBackground).Top;
    FLeft := (Source as TBackground).Left;
    FDisplay := (Source as TBackground).Display;
    FBitmap.Assign((Source as TBackground).Bitmap);
    FBackgroundCells := (Source as TBackground).Cells;
    FColor := (Source as TBackground).Color;
    FColorTo := (Source as TBackground).ColorTo;
  end;
end;

constructor TBackGround.Create(AGrid: TAdvStringGrid);
begin
  FGrid := AGrid;
  inherited Create;
  FBitmap := TBitmap.Create;
  FColor := clWindow;
  FColorTo := clBtnFace;
end;

destructor TBackGround.Destroy;
begin
  FBitmap.Free;
  inherited Destroy;
end;

procedure TBackGround.SetBitmap(Value: TBitmap);
begin
  FBitmap.Assign(Value);
  FGrid.Invalidate;
end;

procedure TBackGround.SetLeft(Value: Integer);
begin
  FLeft := Value;
  FGrid.Invalidate;
end;

procedure TBackGround.SetTop(Value: Integer);
begin
  FTop := Value;
  FGrid.Invalidate;
end;

procedure TBackGround.SetDisplay(Value: TBackgroundDisplay);
begin
  FDisplay := Value;
  FGrid.Invalidate;
end;

procedure TBackGround.SetBackGroundCells(const Value: TBackgroundCells);
begin
  FBackgroundCells := Value;
  FGrid.Invalidate;
end;

procedure TBackGround.SetColor(const Value: TColor);
begin
  FColor := Value;
  FGrid.Invalidate;
end;

procedure TBackGround.SetColorTo(const Value: TColor);
begin
  FColorTo := Value;
  FGrid.Invalidate;  
end;

{ TEditLink }

constructor TEditLink.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FForcedExit := False;
  FPopupLeft := -1;
  FPopupTop := -1;
  FWantHTML := false;
  FKeepFocus := false;
end;

procedure TEditLink.CreateEditor;
begin
  // virtual implementation
end;

destructor TEditLink.Destroy;
begin
  inherited Destroy;
end;

procedure TEditLink.DestroyEditor;
begin
  // virtual implementation
end;

procedure TEditLink.EditExit(Sender: TObject);
begin
  HideEditor;
  if (EditStyle = esPopup) and Assigned(FPopupForm) then
  begin
    DestroyEditor;
    FPopupForm.Hide;
  end;
end;

procedure TEditLink.EditKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  Allow: Boolean;
  s:string;
begin
  Allow := (Key in [VK_LEFT, VK_RIGHT, VK_DOWN, VK_UP, VK_PRIOR, VK_NEXT,
                   VK_END, VK_UP, VK_RETURN, VK_ESCAPE, VK_TAB]) {or (ssAlt in Shift)};

  if FWantKeyUpDown and (Key in [VK_UP,VK_DOWN]) then Allow := False;
  if FWantKeyLeftRight and (Key in [VK_LEFT,VK_RIGHT]) then Allow := False;
  if FWantKeyHomeEnd and (Key in [VK_HOME,VK_END]) then Allow := False;
  if FWantKeyPriorNext and (Key in [VK_PRIOR,VK_NEXT]) then Allow := False;
  if FWantKeyReturn and (Key in [VK_RETURN]) then Allow := False;
  if FWantKeyEscape and (Key in [VK_ESCAPE]) then Allow := False;
  if FWantTabs and (Key in [VK_TAB]) then Allow := False;

  if Allow then
    with FOwner do
    begin

      if (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then
      begin
        s := GetEditorValue;
        CurrentCell := s;

        if not ValidateCell(s) then
        begin
          SetEditorValue(CurrentCell);
          Key := 0;
          FNoAutoAdvance := true;
          Repaint;
          Exit;
        end;

        SetEditorValue(CurrentCell);
      end;

      if (Key = VK_TAB) then
      begin
        if Navigation.TabToNextAtEnd then
        begin
          FForcedExit := True;
          SetFocus;
          FForcedExit := False;
          HideEditControl(Col,Row);

          if TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000) and not HasStaticEdit(Col,Row) then
          begin
            PostMessage(Handle, WM_GRIDEDITSHOW, 0, 0);
            //PostMessage(Handle, WM_KEYDOWN, VK_F2, 0);
            Key := 0;
            Exit;
          end;
        end;
        Key := 0;
      end;

      if Key = VK_ESCAPE then
      begin
        s := OriginalCellValue;
        SetEditorValue(OriginalCellValue);
      end;

      s := GetEditorValue;
      FForcedExit := True;
      SetFocus;
      FForcedExit := False;

      HideEditControl(Col,Row);

      if EditStyle = esPopup then
      begin
        EditExit(Self);
        SetCellValue(s);
      end;

      EditMode := False;
      SelectCell(Col,Row);

      if (Key = VK_RETURN) and FLastValidation then
      begin
        FLastValidation := true;
        AdvanceEdit(Col,Row,False,True,not (ssShift in Shift),False,True);
        Key := 0;
        Exit;
      end
      else
      begin
        if not FLastValidation then
        begin
          FLastValidation := true;
          ShowEditControl(Col,Row);
          Exit;
        end;
      end;

      FLastValidation := true;

      if (Key = VK_ESCAPE) then
      begin
        Key := 0;
        Exit;
      end;

      if Key in [VK_DOWN,VK_UP,VK_TAB,VK_LEFT,VK_RIGHT] then
        KeyDown(Key,Shift);

      GetEditControl.Enabled := false;
      FForcedExit := True;
      SetFocus;
      FForcedExit := False;

      if (goTabs in Options) and (Key = VK_TAB) then
      begin
        if not HasStaticEdit(Col,Row) then
          PostMessage(Handle, WM_KEYDOWN, VK_F2, 0);
      end;
    end
  else
    inherited;
end;

procedure TEditLink.FormExit(Sender: TObject);
var
  s:string;
begin
  s := GetEditorValue;
  //necessary patch for hidden cells
  if Assigned(FOwner.NormalEdit) then
    FOwner.NormalEdit.Text := s;

  if not FForcedExit then
  begin
    EditExit(Sender);
    FOwner.InvokedFocusChange := true;
  end
  else
    SetCellValue(s);
end;

function TEditLink.GetCellValue: string;
begin
  Result := FOwner.Cells[FOwner.RemapCol(FOwner.Col),FOwner.Row];
end;

function TEditLink.GetEditControl: TWinControl;
begin
  Result := Nil;
end;

function TEditLink.GetEditorValue: string;
begin
  Result := '';
end;

function TEditLink.GetParent: TWinControl;
begin
  if EditStyle = esPopup then
    Result := FPopupForm
  else
    Result := FOwner;
end;

procedure TEditLink.RestoreWinProc;
var
  WinControl: TWinControl;
begin
  WinControl := GetEditControl;

  if Assigned(WinControl) and (EditStyle = esInplace) then
  begin
    WinControl.WindowProc := FOwner.FGridControlWndProc;
    FSubclassed := false;

    if WinControl.HandleAllocated then
    begin
      ShowWindow(WinControl.Handle, SW_HIDE);
      // SendMessage(WinControl.Handle,WM_CLOSE,0,0);
    end;
  end;
end;

procedure TEditLink.HideEditor;
begin
  SetCellValue(GetEditorValue);
  FOwner.HideInplaceEdit;
  RestoreWinProc;
end;

procedure TEditLink.SetCellValue(s: string);
begin
  FOwner.UpdateEditingCell(FOwner.RemapCol(FOwner.Col),FOwner.Row,s);
end;

procedure TEditLink.SetEditorValue(s: string);
begin
  // virtual implementation
end;

procedure TEditLink.SetFocus(Value: Boolean);
var
  ec: TWinControl;
begin
  ec := GetEditControl;

  if Value then
  begin
    if not ec.Visible then
      ec.Visible := true;
    if not ec.Enabled then
      ec.Enabled := true;
  end;

  if (EditStyle = esInplace) and not (FSubClassed) then
  begin
    FOwner.FGridControlWndProc := ec.WindowProc;
    ec.WindowProc := FOwner.SubClassProc;
    FSubClassed := true;
  end;

  if Value then
    ec.SetFocus
  else
    FOwner.SetFocus;
end;

procedure TEditLink.SetProperties;
begin
  // virtual implementation
end;

procedure TEditLink.SetCellProps(AColor: TColor; AFont: TFont);
begin
  // virtual implementation
end;

procedure TEditLink.SetRect(r: TRect);
begin
  SetWindowPos(GetEditControl.Handle,0,r.Left,r.Top,
    r.Right-r.Left-FOwner.GridLineWidth,r.Bottom-r.Top-FOwner.GridLineWidth, SWP_NOZORDER);
end;

procedure TEditLink.SetVisible(Value: Boolean);
var
  wi: TWinControl;
begin
  wi := GetEditControl;
  if Assigned(wi) then
    wi.Visible := Value;
end;

{ TGridChangeNotifier}

procedure TGridChangeNotifier.CellsChanged(R:TRect);
begin
end;

{ TFilterData }

procedure TFilterData.BuildCondition(s: string);
begin
  if Pos(' ',s) > 0 then
    s := '"' + s + '"';

  case FilterType of
  ftEqual: Condition := s;
  ftStartsWith: Condition := s + '*';
  ftEndsWith: Condition := '*' + s;
  ftContains: Condition := '*' + s + '*';
  ftNotContains: Condition := '!*' + s + '*';
  ftNotEqual: Condition := '!' + s;
  ftLargerThan: Condition := '>' + s;
  ftSmallerThan: Condition := '<' + s;
  end;
end;

constructor TFilterData.Create(ACollection: TCollection);
begin
  inherited;
  FCaseSensitive := True;
  FMethod := fmExpression;
  FEnabled := true;
end;

procedure TFilterData.Assign(Source: TPersistent);
var
  ASrcFilterData: TFilterData;
begin
  ASrcFilterData := Source as TFilterData;
  if Assigned(ASrcFilterData) then
  begin
    FColumn  := ASrcFilterData.Column;
    FCondition := ASrcFilterData.Condition;
    FCaseSensitive := ASrcFilterData.CaseSensitive;
    FData := ASrcFilterData.Data;
    FPrefix := ASrcFilterData.Prefix;
    FSuffix := ASrcFilterData.Suffix;
    FOperation := ASrcFilterData.Operation;
    FRemoveAccented := ASrcFilterData.RemoveAccented;
  end;
end;

constructor THTMLHintWindow.Create(AOwner: TComponent);
begin
  inherited;
  FImages := nil;
  FPictureContainer := nil;
end;

procedure THTMLHintWindow.CreateParams(var Params: TCreateParams);
const
  CS_DROPSHADOW = $00020000;

begin
  inherited CreateParams(Params);
  Params.Style := Params.Style - WS_BORDER;

  if (Win32Platform = VER_PLATFORM_WIN32_NT) and
     ((Win32MajorVersion > 5) or
      ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) then
    Params.WindowClass.Style := Params.WindowClass.Style or CS_DROPSHADOW;
end;

procedure THTMLHintWindow.Paint;
var
  DC: HDC;
  R, rd, hr,cr: TRect;
  Brush, SaveBrush: HBRUSH;
  Anchor,Stripped,FocusAnchor,AnchorHint:string;
  XSize,YSize,ml,hl:integer;
  CID,CV,CT: string;

  procedure DCFrame3D(var R: TRect; const TopLeftColor, BottomRightColor: TColor);
  var
    Pen, SavePen: HPEN;
    P: array[0..2] of TPoint;
  begin
    Pen := CreatePen(PS_SOLID, 1, ColorToRGB(TopLeftColor));
    SavePen := SelectObject(DC, Pen);
    P[0] := Point(R.Left, R.Bottom-2);
    P[1] := Point(R.Left, R.Top);
    P[2] := Point(R.Right-1, R.Top);
    PolyLine(DC, P, 3);
    SelectObject(DC, SavePen);
    DeleteObject(Pen);

    Pen := CreatePen(PS_SOLID, 1, ColorToRGB(BottomRightColor));
    SavePen := SelectObject(DC, Pen);
    P[0] := Point(R.Left, R.Bottom-1);
    P[1] := Point(R.Right-1, R.Bottom-1);
    P[2] := Point(R.Right-1, R.Top-1);
    PolyLine(DC, P, 3);
    SelectObject(DC, SavePen);
    DeleteObject(Pen);
  end;

begin
  DC := Canvas.Handle;
  R := ClientRect;
  RD := ClientRect;

  // Background
  Brush := CreateSolidBrush(ColorToRGB(Color));

  SaveBrush := SelectObject(DC, Brush);
  FillRect(DC, R, Brush);
  SelectObject(DC, SaveBrush);
  DeleteObject(Brush);

  // Border
  DCFrame3D(R, cl3DLight, cl3DDkShadow);

  // Caption
  RD.Left := R.Left + 4;
  RD.Top := R.Top + (R.Bottom - R.Top - FTextHeight) div 2;
  RD.Bottom := RD.Top + FTextHeight + 8;
  RD.Right := RD.Right - 4;
  Canvas.Brush.Color := Color;

  if TextType(Caption,true) = ttUnicode then
  begin
    Canvas.Font.Name := WideHintFontName;
    DrawTextExW(Canvas.Handle,PWideChar(WideCaption),Length(WideCaption),rd,DT_SINGLELINE or DT_LEFT or DT_NOPREFIX,nil);
   end
  else
    HTMLDrawEx(Canvas,Caption,rd,FImages,0,0,-1,0,1,False,False,False,False,False,
                 False,False,False,'',0.0,clBlue,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
                 XSize,YSize,hl,ml,hr,cr,CID,CV,CT,nil,FPictureContainer,self.Handle,BidiMode);
end;

procedure THTMLHintWindow.ActivateHint(Rect: TRect; const AHint: string);
var
  dx, dy : Integer;
  Pnt: TPoint;
  hr,cr: TRect;
  XSize,YSize,ml,hl: Integer;
  Anchor,Stripped,FocusAnchor,AnchorHint: string;
  CID,CV,CT: string;
  Monitor : TMonitor;
  ws: widestring;

begin
  Caption := AHint;
  dx := 16;
  dy := 4;

  // Calculate width and height
  Rect.Right := Rect.Left + 1024 - dx;

  if TextType(AHint,true) = ttUnicode then
  begin
    Canvas.Font.Name := WideHintFontName;
    ws := DecodeWideStr(AHint);
    YSize := DrawTextExW(Canvas.Handle,PWideChar(ws),Length(ws),Rect,DT_SINGLELINE or DT_CALCRECT or DT_LEFT or DT_NOPREFIX,nil);
    XSize := Rect.Right - Rect.Left;
    WideCaption := ws;
    dx := 8;
  end
  else
    HTMLDrawEx(Canvas,AHint,Rect,FImages,0,0,-1,0,1,False,True,False,False,False,
               False,True,False,'',0.0,clBlue,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,XSize,YSize,
               hl,ml,hr,cr,CID,CT,CV,nil,FPictureContainer,self.Handle,BidiMode);

  FTextWidth := XSize;
  Rect.Right := Rect.Left + FTextWidth + dx;

  FTextHeight := YSize;
  Rect.Bottom := Rect.Top + FTextHeight + dy;

  // Calculate position
  Pnt := Point(Rect.Left,Rect.Top);
  Rect.Left := Pnt.X;
  Rect.Top := Pnt.Y;
  Rect.Right := Rect.Right - Rect.Left + Pnt.X;
  Rect.Bottom := Rect.Bottom - Rect.Top + Pnt.Y;

  Monitor := Screen.MonitorFromPoint(Pnt);

  if Rect.Right - Monitor.Left > Monitor.Width then
  begin
    Rect.Left := Monitor.Left + Monitor.Width - Rect.Right + Rect.Left - 2;
    Rect.Right := Rect.Left + FTextWidth + dx;
  end;

  if Rect.Bottom - Monitor.Top > Monitor. Height then
  begin
    Rect.Bottom := Monitor.Top + Monitor. Height - 2;
    Rect.Top := Rect.Bottom - FTextHeight - dy;
  end;

{
    // Make sure the tooltip is completely visible
     if (Right > Screen.Width) and ((Screen.Width - Right + Left - 2) >= 0) then
    begin
      Left := Screen.Width - Right + Left -2;
      Right := Left + FTextWidth + dx;
    end;

    if (Bottom > Screen.Height) and ((Screen.Height - 2 - FTextHeight - dy) >= 0) then
    begin
      Bottom := Screen.Height - 2;
      Top := Bottom - FTextHeight - dy;
    end;
}

  BoundsRect := Rect;

  Pnt := ClientToScreen(Point(0, 0));
  SetWindowPos(Handle, HWND_TOPMOST, Pnt.X, Pnt.Y, 0, 0,
                 SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE);
  Invalidate;
end;

{$IFDEF DELPHI_UNICODE}
procedure THTMLHintWindow.ActivateHintData(Rect: TRect; const AHint: string; AData: TCustomData);
begin
  if (TObject(AData) is TAdvStringGrid) then
  begin
    FImages := TAdvStringGrid(AData).GridImages;
    FPictureContainer := TAdvStringGrid(AData).PictureContainer;
  end;
  inherited;
end;
{$ENDIF}

function THTMLHintWindow.CalcHintRect(MaxWidth: Integer;
  const AHint: string; AData: Pointer): TRect;
var
  ARect,hr,cr: TRect;
  XSize,YSize,ml,hl: Integer;
  Anchor,Stripped,FocusAnchor,AnchorHint: string;
  CID,CT,CV: string;
  ws: widestring;
begin
  FillChar(ARect,SizeOf(ARect),0);

  ARect.Right := ARect.Left + MaxWidth;

  if TextType(AHint,true) = ttUnicode then
  begin
    Canvas.Font.Name := WideHintFontName;
    ws := DecodeWideStr(AHint);
    YSize := DrawTextExW(Canvas.Handle,PWideChar(ws),Length(ws),ARect,DT_SINGLELINE or DT_CALCRECT or DT_LEFT or DT_NOPREFIX,nil);
    XSize := ARect.Right;
  end
  else
    HTMLDrawEx(Canvas,AHint,ARect,FImages,0,0,-1,0,1,False,True,False,False,False,False,
             True,False,'',0.0,clBlue,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,XSize,YSize,
             hl,ml,hr,cr,CID,CT,CV,nil,FPictureContainer,self.Handle,BidiMode);

  Result := Rect(0,0,XSize,YSize);
end;

procedure THTMLHintWindow.CMTextChanged(var Message: TMessage);
begin
  Invalidate;
end;


{ TSortSettings }

constructor TSortSettings.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AOwner;
  FSortFull := True;
  FSortAutoFormat := True;
  FSortUpGlyph := TBitmap.Create;
  FSortDownGlyph := TBitmap.Create;
  FIndexUpGlyph := TBitmap.Create;
  FIndexDownGlyph := TBitmap.Create;
  FSortIndexColor := clYellow;
  FAutoSortForGrouping := True;
  FVirtualCells := True;
  FHeaderColor := clNone;
  FHeaderColorTo := clNone;
  FHeaderMirrorColor := clNone;
  FHeaderMirrorColorTo := clNone;
  FIgnoreCase := False;
  FSortColumn := -1;
  FIndexSortKey := ikShift;
end;

destructor TSortSettings.Destroy;
begin
  FSortUpGlyph.Free;
  FSortDownGlyph.Free;
  FIndexUpGlyph.Free;
  FIndexDownGlyph.Free;
  inherited;
end;

procedure TSortSettings.Assign(Source: TPersistent);
begin
  if (Source is TSortSettings) then
  begin
    FAutoSortForGrouping := (Source as TSortSettings).AutoSortForGrouping;
    FAutoColumnMerge := (Source as TSortSettings).AutoColumnMerge;
    FDefaultFormat := (Source as TSortSettings).DefaultFormat;
    FSortColumn := (Source as TSortSettings).Column;
    FSortShow := (Source as TSortSettings).Show;
    FSortIndexShow := (Source as TSortSettings).IndexShow;
    FSortIndexColor := (Source as TSortSettings).IndexColor;
    FSortFull := (Source as TSortSettings).Full;
    FSortSingleColumn := (Source as TSortSettings).SingleColumn;
    FSortIgnoreBlanks := (Source as TSortSettings).IgnoreBlanks;
    FSortBlankPos := (Source as TSortSettings).BlankPos;
    FSortAutoFormat := (Source as TSortSettings).AutoFormat;
    FSortDirection := (Source as TSortSettings).Direction;
    FSortUpGlyph.Assign((Source as TSortSettings).UpGlyph);
    FSortDownGlyph.Assign((Source as TSortSettings).DownGlyph);
    FIndexUpGlyph.Assign((Source as TSortSettings).IndexUpGlyph);
    FIndexDownGlyph.Assign((Source as TSortSettings).IndexDownGlyph);
    FIndexSortKey := (Source as TSortSettings).IndexSortKey;
    FInitSortDirection := (Source as TSortSettings).InitSortDirection;
    FSortFixedCols := (Source as TSortSettings).FixedCols;
    FSortNormalCellsOnly := (Source as TSortSettings).NormalCellsOnly;
    FSortRow := (Source as TSortSettings).Row;
    FUndoSort := (Source as TSortSettings).UndoSort;
    FHeaderColor := (Source as TSortSettings).HeaderColor;
    FHeaderColorTo := (Source as TSortSettings).HeaderColorTo;
    FHeaderMirrorColor := (Source as TSortSettings).HeaderMirrorColor;
    FHeaderMirrorColorTo := (Source as TSortSettings).HeaderMirrorColorTo;
  end;
end;

function TSortSettings.SaveToString: string;
begin
  if IndexShow then
    Result := 'i;' + FGrid.SortIndexes.SaveToString
  else
  begin
    if Direction = sdAscending then
      Result := 'u' + IntToStr(Column)
    else
      Result := 'd' + IntToStr(Column); 
  end;  
end;

procedure TSortSettings.LoadFromString(const Value: string);
var
  v: string;
  err,c: integer;
begin
  if Value = '' then
    Exit;

  Show := true;
  v := Value;
  if Length(v) < 2 then
    raise Exception.Create('Invalid sort settings specifier');

  if pos('i;', v) > 0 then
  begin
    IndexShow := true;
    Delete(v,1,2);
    if Length(v) > 0 then
    begin
      FGrid.SortIndexes.LoadFromString(v);
      FGrid.QSortIndexed;
    end;
  end
  else
  begin
    IndexShow := false;
    if pos('u',v) > 0 then
      Direction := sdAscending
    else
      Direction := sdDescending;
    Delete(v,1,1);
    val(v, c, err);
    if err = 0 then
    begin
      Column := c;
      FGrid.QSort;
    end;
  end;
end;

procedure TSortSettings.Remove;
begin
  Column := -1;
  FGrid.SortIndexes.Clear;
  FGrid.RepaintRow(FGrid.FixedRows - 1);
end;

function TSortSettings.GetDownGlyph: TBitmap;
begin
  Result := FSortDownGlyph;
end;

function TSortSettings.GetUpGlyph: TBitmap;
begin
  Result := FSortUpGlyph;
end;

procedure TSortSettings.SetDownGlyph(const Value: TBitmap);
begin
  FSortDownGlyph.Assign(Value);
end;

procedure TSortSettings.SetHeaderColor(const Value: TColor);
begin
  if FHeaderColor <> Value then
  begin
    FHeaderColor := Value;
    if FGrid.FixedRows > 0 then
      FGrid.RepaintRow(FGrid.FixedRows - 1);
  end;
end;

procedure TSortSettings.SetHeaderColorTo(const Value: TColor);
begin
  if FHeaderColorTo <> Value then
  begin
    FHeaderColorTo := Value;
    if FGrid.FixedRows > 0 then
      FGrid.RepaintRow(FGrid.FixedRows - 1);
  end;
end;

procedure TSortSettings.SetHeaderMirrorColor(const Value: TColor);
begin
  if FHeaderMirrorColor <> Value then
  begin
    FHeaderMirrorColor := Value;
    if FGrid.FixedRows > 0 then
      FGrid.RepaintRow(FGrid.FixedRows - 1);
  end;
end;

procedure TSortSettings.SetHeaderMirrorColorTo(const Value: TColor);
begin
  if FHeaderMirrorColorTo <> Value then
  begin
    FHeaderMirrorColorTo := Value;
    if FGrid.FixedRows > 0 then
      FGrid.RepaintRow(FGrid.FixedRows - 1);
  end;
end;

procedure TSortSettings.SetIndexDownGlyph(const Value: TBitmap);
begin
  FIndexDownGlyph.Assign(Value);
end;

procedure TSortSettings.SetIndexUpGlyph(const Value: TBitmap);
begin
  FIndexUpGlyph.Assign(Value);
end;

procedure TSortSettings.SetSortRow(const Value: Integer);
begin
  if Value > FGrid.FixedRows then
    raise Exception.Create('Sort row should be smaller than number of fixed rows')
  else
    FSortRow := Value;
end;

procedure TSortSettings.SetUpGlyph(const Value: TBitmap);
begin
  FSortUpGlyph.Assign(Value);
end;

procedure TSortSettings.ToggleDirection;
begin
  if Direction = sdAscending then
    Direction := sdDescending
  else
    Direction := sdAscending;
end;

procedure TSortSettings.SetShow(const Value: Boolean);
begin
  if (Value <> FSortShow) then
  begin
    FSortShow := Value;
    FGrid.Invalidate;
  end;
end;

{ TControlLook }

constructor TControlLook.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AOwner;
  FCheckBoxSize := 15;
  FRadioSize := 10;
  FDropDownCount := 8;
  FCheckedGlyph := TBitmap.Create;
  FUnCheckedGlyph := TBitmap.Create;
  FRadioOnGlyph := TBitmap.Create;
  FRadioOffGlyph := TBitmap.Create;
  FProgressMarginX := 2;
  FProgressMarginY := 2;
  FControlStyle := csTheme;
  FFixedDropDownButton := false;
  FDropDownButtonWidth := 16;

  Init;
  FDropDownHeader := THeaderAppearance.Create(AOwner);
  FDropDownFooter := TFooterAppearance.Create(AOwner);
end;

procedure TControlLook.Init;
begin
  FColor := clBlack;
  FCommentColor := clRed;

  FProgressBorderColor := clGray;
  FFixedGradientFrom := clNone;
  FFixedGradientTo := clNone;
  FFixedGradientMirrorFrom := clNone;
  FFixedGradientMirrorTo := clNone;

  FFixedGradientHoverFrom := clWhite;
  FFixedGradientHoverTo := clGray;
  FixedGradientHoverMirrorFrom := clNone;
  FixedGradientHoverMirrorTo := clNone;
  FFixedGradientHoverBorder := clSilver;

  FFixedGradientDownFrom := clSilver;
  FFixedGradientDownTo := clGray;
  FixedGradientDownMirrorFrom := clNone;
  FixedGradientDownMirrorTo := clNone;
  FFixedGradientDownBorder := clGray;
end;

destructor TControlLook.Destroy;
begin
  FDropDownHeader.Free;
  FDropDownFooter.Free;
  FCheckedGlyph.Free;
  FUnCheckedGlyph.Free;
  FRadioOnGlyph.Free;
  FRadioOffGlyph.Free;
  inherited;
end;

procedure TControlLook.Assign(Source: TPersistent);
begin
  if (Source is TControlLook) then
  begin
    FButtonPrefix := (Source as TControlLook).ButtonPrefix;
    FCheckBoxSize := (Source as TControlLook).CheckSize;
    FRadioSize := (Source as TControlLook).RadioSize;
    FControlStyle := (Source as TControlLook).ControlStyle;
    FCheckedGlyph.Assign((Source as TControlLook).CheckedGlyph);
    FUnCheckedGlyph.Assign((Source as TControlLook).UnCheckedGlyph);
    FRadioOnGlyph.Assign((Source as TControlLook).RadioOnGlyph);
    FRadioOffGlyph.Assign((Source as TControlLook).RadioOffGlyph);
    FProgressMarginX := (Source as TControlLook).ProgressMarginX;
    FProgressMarginY := (Source as TControlLook).ProgressMarginY;
    FCommentColor := (Source as TControlLook).CommentColor;
    FColor := (Source as TControlLook).Color;
    FProgressBorderColor := (Source as TControlLook).ProgressBorderColor;
    FCheckAlwaysActive := (Source as TControlLook).CheckAlwaysActive;
    FRadioAlwaysActive := (Source as TControlLook).RadioAlwaysActive;
    FFixedGradientFrom := (Source as TControlLook).FixedGradientFrom;
    FFixedGradientTo := (Source as TControlLook).FixedGradientTo;
    FFixedGradientMirrorFrom := (Source as TControlLook).FixedGradientMirrorFrom;
    FFixedGradientMirrorTo := (Source as TControlLook).FixedGradientMirrorTo;

    FFixedGradientHoverFrom := (Source as TControlLook).FixedGradientHoverFrom;
    FFixedGradientHoverTo := (Source as TControlLook).FixedGradientHoverTo;
    FFixedGradientHoverMirrorFrom := (Source as TControlLook).FixedGradientHoverMirrorFrom;
    FFixedGradientHoverMirrorTo := (Source as TControlLook).FixedGradientHoverMirrorTo;
    FFixedGradientHoverBorder := (Source as TControlLook).FixedGradientHoverBorder;

    FFixedGradientDownFrom := (Source as TControlLook).FixedGradientDownFrom;
    FFixedGradientDownTo := (Source as TControlLook).FixedGradientDownTo;
    FFixedGradientDownMirrorFrom := (Source as TControlLook).FixedGradientDownMirrorFrom;
    FFixedGradientDownMirrorTo := (Source as TControlLook).FixedGradientDownMirrorTo;
    FFixedGradientDownBorder := (Source as TControlLook).FixedGradientDownBorder;
    FDropDownAlwaysVisible := (Source as TControlLook).DropDownAlwaysVisible;
    FSpinButtonsAlwaysVisible := (Source as TControlLook).SpinButtonsAlwaysVisible;
    FDropDownCount := (Source as TControlLook).DropDownCount;
    FDropDownFooter.Assign((Source as TControlLook).DropDownFooter);
    FDropDownHeader.Assign((Source as TControlLook).DropDownHeader);
    FHintMaxWidth := (Source as TControlLook).HintMaxWidth;
    FDropDownButtonWidth := (Source as TControlLook).DropDownButtonWidth;
  end;
end;



procedure TControlLook.SetCheckBoxSize(const Value: Integer);
begin
  FCheckBoxSize := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetCheckedGlyph(const Value: TBitmap);
begin
  FCheckedGlyph.Assign(Value);
  FGrid.Invalidate;
end;

procedure TControlLook.SetColor(const Value: TColor);
begin
  FColor := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetControlStyle(const Value: TControlStyle);
begin
  if (FControlStyle <> Value) then
  begin
    FControlStyle := Value;
    FGrid.Invalidate;
  end;
end;

procedure TControlLook.SetDropDownAlwaysVisible(const Value: Boolean);
begin
  if (FDropDownAlwaysVisible <> Value) then
  begin
    FDropDownAlwaysVisible := Value;
    FGrid.Invalidate;
  end;
end;

procedure TControlLook.SetDropDownButtonWidth(const Value: integer);
begin
  if (FDropDownButtonWidth <> Value) then
  begin
    FDropDownButtonWidth := Value;
    FGrid.Invalidate;
  end;
end;

procedure TControlLook.SetDropDownFooter(const Value: TFooterAppearance);
begin
  FDropDownFooter.Assign(Value);
end;

procedure TControlLook.SetDropDownHeader(const Value: THeaderAppearance);
begin
  FDropDownHeader.Assign(Value);
end;

procedure TControlLook.SetSpinButtonsAlwaysVisible(const Value: Boolean);
begin
  FSpinButtonsAlwaysVisible := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetCommentColor(const Value: TColor);
begin
  FCommentColor := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetFlatButton(const Value: Boolean);
begin
  FFlatButton := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetNoDisabledCheckRadioLook(const Value: Boolean);
begin
  FNoDisabledCheckRadioLook := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetNoDisabledButtonLook(const Value: Boolean);
begin
  FNoDisabledButtonLook := Value;
  FGrid.Invalidate;
end;


procedure TControlLook.SetProgressMarginX(const Value: Integer);
begin
  FProgressMarginX := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetProgressMarginY(const Value: Integer);
begin
  FProgressMarginY := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetProgressXP(const Value: Boolean);
begin
  FProgressXP := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetRadioOffGlyph(const Value: TBitmap);
begin
  FRadioOffGlyph.Assign(Value);
  FGrid.Invalidate;
end;

procedure TControlLook.SetRadioOnGlyph(const Value: TBitmap);
begin
  FRadioOnGlyph.Assign(Value);
  FGrid.Invalidate;
end;

procedure TControlLook.SetRadioSize(const Value: Integer);
begin
  FRadioSize := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetUnCheckedGlyph(const Value: TBitmap);
begin
  FUnCheckedGlyph.Assign(Value);
  FGrid.Invalidate;
end;

procedure TControlEdit.WMKeyDown(var Msg:TWMKeydown);
begin
  inherited;
end;

procedure TControlEdit.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  if (Msg.CharCode = VK_RETURN) then
  begin
    Msg.Result := 0;
    Exit;
  end;

  if (Msg.CharCode = VK_TAB) then
  begin
    Msg.Result := 1;
    Exit;
  end
  else
    inherited;
end;

procedure TControlEdit.KeyPress(var Key: Char);
var
  grd: TAdvStringGrid;
begin
  if (Parent is TAdvStringGrid) then
  begin
    grd := Parent as TAdvStringGrid;

    if Key = #13 then
    begin
      Key := #0;
      DoExit;
      grd.SetFocus;
      Exit;
    end;

    if Key = #9 then
    begin
      Key := #0;
      DoExit;

      if grd.Navigation.AdvanceAuto then
        grd.AdvanceEdit(grd.Col,grd.Row,true,false, true, false,true)
      else
        grd.AdvanceHTMLEdit(grd.Col,grd.Row,grd.FCtrlID);
      Exit;
    end;
  end;

  inherited;
end;

procedure TControlCombo.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  if (Msg.CharCode = VK_TAB) then
  begin
    Msg.Result := 1;
    Exit;
  end
  else
    inherited;
end;


procedure TControlCombo.KeyPress(var Key: Char);
begin
  if Key = #13 then
  begin
    Key := #0;
    DoExit;
    with (Parent as TAdvStringGrid) do SetFocus;
    Exit;
  end;

  if Key = #9 then
  begin
    Key := #0;
    DoExit;

    with (Parent as TAdvStringGrid) do
    begin
      if Navigation.AdvanceAuto then
        AdvanceEdit(Col,Row,true,false, true, false,true)
      else
        AdvanceHTMLEdit(Col,Row,FCtrlID);
    end;
    Exit;
  end;
  inherited;
end;


procedure TControlLook.SetFixedGradientFrom(const Value: TColor);
begin
  FFixedGradientFrom := Value;
  if Value <> clNone then
    FGrid.TMSGradientTo := Value
end;

procedure TControlLook.SetFixedGradientTo(const Value: TColor);
begin
  FFixedGradientTo := Value;
  if Value <> clNone then
    FGrid.TMSGradientFrom := Value
end;

procedure TControlLook.SetFixedGradientMirrorFrom(const Value: TColor);
begin
  FFixedGradientMirrorFrom := Value;
  FGrid.TMSGradientMirrorTo := Value
end;

procedure TControlLook.SetFixedGradientMirrorTo(const Value: TColor);
begin
  FFixedGradientMirrorTo := Value;
  FGrid.TMSGradientMirrorFrom := Value
end;

procedure TControlLook.SetFixedGradientHoverFrom(const Value: TColor);
begin
  FFixedGradientHoverFrom := Value;
  if Value <> clNone then
    FGrid.TMSGradientHoverTo := Value
end;

procedure TControlLook.SetFixedGradientHoverTo(const Value: TColor);
begin
  FFixedGradientHoverTo := Value;
  if Value <> clNone then
    FGrid.TMSGradientHoverFrom := Value
end;

procedure TControlLook.SetFixedGradientHoverMirrorFrom(const Value: TColor);
begin
  FFixedGradientHoverMirrorFrom := Value;
  FGrid.TMSGradientHoverMirrorTo := Value
end;

procedure TControlLook.SetFixedGradientHoverMirrorTo(const Value: TColor);
begin
  FFixedGradientHoverMirrorTo := Value;
  FGrid.TMSGradientHoverMirrorFrom := Value
end;

procedure TControlLook.SetFixedGradientHoverBorder(const Value: TColor);
begin
  FFixedGradientHoverBorder := Value;
  if Value <> clNone then
    FGrid.TMSGradientHoverBorder := Value
end;

procedure TControlLook.SetFixedGradientDownFrom(const Value: TColor);
begin
  FFixedGradientDownFrom := Value;
  if Value <> clNone then
    FGrid.TMSGradientDownTo := Value
end;

procedure TControlLook.SetFixedGradientDownTo(const Value: TColor);
begin
  FFixedGradientDownTo := Value;
  if Value <> clNone then
    FGrid.TMSGradientDownFrom := Value
end;

procedure TControlLook.SetFixedGradientDownMirrorFrom(const Value: TColor);
begin
  FFixedGradientDownMirrorFrom := Value;
  FGrid.TMSGradientDownMirrorTo := Value
end;

procedure TControlLook.SetFixedGradientDownMirrorTo(const Value: TColor);
begin
  FFixedGradientDownMirrorTo := Value;
  FGrid.TMSGradientDownMirrorFrom := Value
end;

procedure TControlLook.SetFixedGradientDownBorder(const Value: TColor);
begin
  FFixedGradientDownBorder := Value;
  if Value <> clNone then
    FGrid.TMSGradientDownBorder := Value
end;

{ TFooterPanel }

constructor TFooterPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
  FLastHintX := -1;
end;

procedure TFooterPanel.CreateWnd;
begin
  inherited;

  if FGrid.FloatingFooter.Visible then
    Height := FGrid.FloatingFooter.Height
  else
    Height := 0;

  if Assigned(FGrid.OnCreatedFloatingFooter) then
    FGrid.OnCreatedFloatingFooter(FGrid);
end;

function TFooterPanel.PaintCustomPaint: Integer;
var
  R: TRect;
  rtl: boolean;
begin
  R := ClientRect;
  rtl := FGrid.UseRightToLeftAlignment;

  if Assigned(FGrid.OnFooterPaint) then
    FGrid.OnFooterPaint(Self, FGrid.FloatingFooter.Column, Canvas, RTLCoord(rtl,R));

  Result := R.Right;
end;

function TFooterPanel.PaintColPreview: Integer;
var
  FW: Integer;
  r: TRect;
  OldColor: TColor;
  rtl: boolean;

begin
  FW := GridColWidths;

  rtl := FGrid.UseRightToLeftAlignment;

  R := ClientRect;

  if rtl then
    R.Left := R.Right - FW
  else
    R.Right := FW;

  Canvas.Brush.Color := FGrid.FloatingFooter.Color;
  Canvas.Pen.Width := 1;
  Canvas.Pen.Color := FGrid.FloatingFooter.Color;
  Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);

  Canvas.Pen.Color := clGray;
  Canvas.MoveTo(R.Left,R.Bottom);
  Canvas.LineTo(R.Right - 1,R.Bottom);
  Canvas.LineTo(R.Right - 1,R.Top);
  Canvas.Pen.Color := clWhite;
  Canvas.LineTo(R.Left,R.Top);
  Canvas.LineTo(R.Left,R.Bottom);

  if rtl then
  begin
    R.Left := 0;
    R.Right := FW;
  end;

  FGrid.FNoRTLOrientation := true;

  OldColor := FGrid.FSelectionTextColor;
  FGrid.FSelectionTextColor := clBlack;

  if Assigned(FGrid.OnFooterPaint) then
    FGrid.OnFooterPaint(Self, FGrid.FloatingFooter.Column, Canvas, RTLCoord(rtl,R))
  else
    FGrid.DrawGridCell(Canvas,FGrid.FloatingFooter.Column, FGrid.Row, RTLCoord(rtl,R), []);

  FGrid.FSelectionTextColor := OldColor;

  Canvas.Brush.Color := FGrid.Color;
  Canvas.Pen.Color := FGrid.Color;

  if rtl then
  begin
    R.Left := 0;
    R.Right := ClientRect.Right - FW;
  end
  else
  begin
    R.Left := FW;
    R.Right := ClientRect.Right;
  end;

  Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);

  FGrid.FNoRTLOrientation := false;

  Result := FW;
end;

function TFooterPanel.HTMLColReplace(s:string):string;
var
  beforetag,aftertag,fld:string;
  i,j,colidx,err:integer;
begin
  beforetag:='';
  while Pos('<#',s) > 0 do
  begin
    i := pos('<#',s);
    beforetag := beforetag + Copy(s,1,i-1); //part prior to the tag
    aftertag := Copy(s,i,length(s)); //part after the tag
    j := pos('>',aftertag);
    fld := Copy(aftertag,1,j-1);
    Delete(fld,1,2);
    Delete(s,1,i+j-1);

    val(fld,colidx,err);

    if err = 0 then
      beforetag := beforetag + FGrid.Cells[colidx,FGrid.Row];
  end;

  Result := beforetag + s;
end;


function TFooterPanel.PaintCustomPreview: Integer;
var
  FW: Integer;
  r: TRect;
  OldColor: TColor;
  s: string;
  Anchor,Stripped,FocusAnchor,AH: string;
  XSize,YSize,hl,ml: integer;
  hr,cr: TRect;
  CID,CV,CT: string;
  rtl: boolean;

begin
  FW := GridColWidths;

  rtl := FGrid.UseRightToLeftAlignment;

  R := ClientRect;

  if rtl then
    R.Left := R.Right - FW
  else
    R.Right := FW;

  Canvas.Brush.Color := FGrid.FloatingFooter.Color;
  Canvas.Pen.Width := 1;
  Canvas.Pen.Color :=  FGrid.FloatingFooter.Color;
  Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);

  Canvas.Pen.Color := clGray;
  Canvas.MoveTo(R.Left,R.Bottom);
  Canvas.LineTo(R.Right - 1,R.Bottom);
  Canvas.LineTo(R.Right - 1,R.Top);
  Canvas.Pen.Color := clWhite;
  Canvas.LineTo(R.Left,R.Top);
  Canvas.LineTo(R.Left,R.Bottom);

  OldColor := FGrid.FSelectionTextColor;
  FGrid.FSelectionTextColor := clBlack;

  if csDesigning in ComponentState then
  begin
    s := FGrid.FloatingFooter.CustomTemplate;
    DrawText(Canvas.Handle,PChar(s),Length(s),R,0);
  end
  else
  begin
    s := HTMLColReplace(FGrid.FloatingFooter.CustomTemplate);

    R.Top := R.Top + 2;
    with FGrid do
    HTMLDrawEx(self.Canvas,s,R,Gridimages,0,0,-1,0,1,False,False,False,False,False,False,not EnhTextSize,False,'',
      0.0,FURLColor,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AH,
      XSize,YSize,hl,ml,hr,cr,CID,CT,CV,FImageCache,FContainer,self.Handle,BidiMode);
    R.Top := R.Top - 2;
  end;

  FGrid.FSelectionTextColor := OldColor;

  Canvas.Brush.Color := FGrid.Color;
  Canvas.Pen.Color := FGrid.Color;

  if rtl then
  begin
    R.Left := 0;
    R.Right := ClientRect.Right - FW;
  end
  else
  begin
    R.Left := FW;
    R.Right := ClientRect.Right;
  end;
  
  Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);

  Result := FW;
end;

function TFooterPanel.RTLCoord(rtl: boolean; ARect: TRect): TRect;
var
  w: Integer;
begin
  w := ClientRect.Right;
  if rtl then
    Result := Rect(w - ARect.Left, ARect.Top, w - ARect.Right, ARect.Bottom)
  else
    Result := ARect;
end;

function TFooterPanel.PaintLastRow: integer;
var
  i, FW: Integer;
  r: TRect;
  lft: Integer;
  rtl: boolean;
  rc: integer;

begin
  FW := GridColWidths;

  rtl := FGrid.UseRightToLeftAlignment;
  lft := FGrid.LeftCol;

  R := ClientRect;

  if rtl then
    R.Left := R.Right - FW
  else
    R.Right := FW;

  Canvas.Brush.Color := FGrid.FloatingFooter.Color;
  Canvas.Pen.Color :=  FGrid.FloatingFooter.Color;
  Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);

  Canvas.Brush.Color := FGrid.Color;
  Canvas.Pen.Color := FGrid.Color;

  if rtl then
  begin
    R.Left := 0;
    R.Right := ClientRect.Right - FW;
  end
  else
  begin
    R.Left := FW;
    R.Right := ClientRect.Right;
  end;

  Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);

  if rtl then
    FW := ClientRect.Right
  else
    FW := 0;

  for i := 1 to FGrid.FixedCols do
  begin
    Canvas.Pen.Color := clWhite;

    Canvas.MoveTo(FW,R.Bottom);
    if (goFixedVertLine in FGrid.Options) and ((FGrid.Look in [glSoft,glXP,glVista,glTMS]) and not FGrid.Flat) then
      Canvas.LineTo(FW,R.Top);

    Canvas.MoveTo(FW,R.Top);

    if rtl then
      FW := FW - FGrid.ColWidths[i - 1]
    else
      FW := FW + FGrid.ColWidths[i - 1];


    Canvas.Pen.Color := FGrid.GridLineColor;
          
    if (goFixedHorzLine in FGrid.Options) {and ((FGrid.Look in [glSoft,glXP,glVista,glTMS]) and not FGrid.Flat)} then
      Canvas.LineTo(FW -1,R.Top);

    Canvas.MoveTo(FW -1,R.Top);

//    if FGrid.Look <> glVista then
//      Canvas.Pen.Color := clGray;

    if (goFixedVertLine in FGrid.Options) then
      Canvas.LineTo(FW - 1,R.Bottom);
  end;

  for i := lft to FGrid.ColCount - 1 do
  begin
    Canvas.Pen.Color := clWhite;

    Canvas.MoveTo(FW,R.Bottom);
    if (goFixedVertLine in FGrid.Options) and ((FGrid.Look in [glSoft,glXP,glVista,glTMS]) and not FGrid.Flat) then
      Canvas.LineTo(FW,R.Top);

    Canvas.MoveTo(FW,R.Top);

    if rtl then
      FW := FW - FGrid.ColWidths[i]
    else
      FW := FW + FGrid.ColWidths[i];

    Canvas.Pen.Color := FGrid.GridLineColor;

    if (goFixedHorzLine in FGrid.Options) {and ((FGrid.Look in [glSoft,glXP,glVista,glTMS]) and not FGrid.Flat)} then
      Canvas.LineTo(FW -1,R.Top);

    Canvas.MoveTo(FW -1,R.Top);

    if FGrid.Look <> glVista then
      Canvas.Pen.Color := clGray;

    if (goFixedVertLine in FGrid.Options) then
      Canvas.LineTo(FW - 1,R.Bottom);
  end;

  R := ClientRect;

  if (goFixedHorzLine in FGrid.Options) then
    R.Top := R.Top + 1;


  FGrid.FNoRTLOrientation := true;

  for i := 1 to FGrid.FixedCols do
  begin
    if FGrid.IsMergedCell(i - 1, FGrid.RowCount - 1) then
      R.Right := FGrid.CellRect(i - 1, FGrid.RowCount - 1).Right - 1
    else
      R.Right := R.Left + FGrid.ColWidths[i - 1] - 1;

//    if (goFixedHorzLine in FGrid.Options) then
//      R.Top := R.Top + 1;

    if (goFixedHorzLine in FGrid.Options) and ((FGrid.Look in [glSoft,glXP,glVista,glTMS]) and not FGrid.Flat) then
      R.Left := R.Left + 1;

    if FGrid.IsBaseCell(i - 1,FGrid.RowCount - 1) then
      FGrid.DrawGridCell(Canvas,i - 1, FGrid.RowCount - 1, RTLCoord(rtl,R), [gdFixed]);

    R.Left := R.Right + 1;
  end;

  for i := lft to FGrid.ColCount - 1 do
  begin
    rc := FGrid.RealColIndex(i);

    if FGrid.IsMergedCell(i, FGrid.RowCount - 1) then
      R.Right := FGrid.CellRect(i, FGrid.RowCount - 1).Right - 1
    else
      R.Right := R.Left + FGrid.ColWidths[i] - 1;

    if (goFixedHorzLine in FGrid.Options) and ((FGrid.Look in [glSoft,glXP,glVista,glTMS]) and not FGrid.Flat) then
      R.Left := R.Left + 1;

    if Assigned(FGrid.OnGetCellColor) then
    begin
      Canvas.Brush.Color := clNone;
      FGrid.OnGetCellColor(FGrid, FGrid.RowCount - 1, rc, [gdFixed], Canvas.Brush, Canvas.Font);

      if Canvas.Brush.Color <> clNone then
        Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);
    end;

    if FGrid.Colors[rc,FGrid.RowCount - 1] <> clNone then
    begin
      Canvas.Brush.Color := FGrid.Colors[rc,FGrid.RowCount - 1];
      Canvas.Rectangle(R.Left,R.Top,R.Right,R.Bottom);
    end;

    if FGrid.IsBaseCell(i,FGrid.RowCount - 1) then
    begin
      if Assigned(FGrid.OnFooterPaint) then
        FGrid.OnFooterPaint(Self, i, Canvas, RTLCoord(rtl,R))
      else
        FGrid.DrawGridCell(Canvas,i, FGrid.RowCount - 1, RTLCoord(rtl,R), [gdFixed]);
    end;

    R.Left := R.Right + 1;
  end;

  Result := R.Right;

  FGrid.FNoRTLOrientation := false;
end;

procedure TFooterPanel.Paint;
var
  w: integer;
begin
  BidiMode := FGrid.BidiMode;

  w := Width;

  case FGrid.FloatingFooter.FooterStyle of
  fsFixedLastRow: w := PaintLastRow;
  fsColumnPreview: w := PaintColPreview;
  fsCustomPreview: w := PaintCustomPreview;
  fsCustomPaint: w := PaintCustomPaint;
  end;

  if FGrid.FloatingFooter.BorderColor <> clNone then
  begin
    Canvas.Pen.Color := FGrid.FloatingFooter.BorderColor;
    Canvas.MoveTo(0,0);
    Canvas.LineTo(w,0);
  end;
end;

destructor TFooterPanel.Destroy;
begin
  inherited;
end;

function TFooterPanel.GridColWidths: integer;
var
  i,FW: integer;
begin
  FW := 0;

  for i := 1 to FGrid.FixedCols do
    FW := FW + FGrid.ColWidths[i - 1];

  for i := FGrid.LeftCol to FGrid.ColCount - 1 do
    FW := FW + FGrid.ColWidths[i];

  Result := FW;
end;

procedure TFooterPanel.CMHintShow(var Msg: TCMHintShow);
var
  CanShow: Boolean;
  hi: PHintInfo;
  i,dx: integer;
Begin
  CanShow := ShowHint;

  hi := Msg.HintInfo;

  i := 0;
  dx := 0;

  // measure distance of fixed cells
  while (hi.CursorPos.x > dx) and (i < FGrid.ColCount) and (i < FGrid.FixedCols) do
  begin
    dx := dx + FGrid.ColWidths[i];
    inc(i);
  end;

  // measure distance of fixed cells
  i := FGrid.LeftCol;
  while (hi.CursorPos.x > dx) and (i < FGrid.ColCount) do
  begin
    dx := dx + FGrid.ColWidths[i];
    inc(i);
  end;


  if (i = FGrid.ColCount) and (hi.CursorPos.x > dx) then
    i := -1;

  if Assigned(FGrid.OnGridHint) and (i > 0) then
  begin
    FGrid.OnGridHint(FGrid, FGrid.RowCount - 1, i - 1, hi.HintStr);
  end;

  if CanShow and (i > 0) then
    FLastHintX := i - 1
  else
    FLastHintX := -1;

  Msg.Result := Ord(Not CanShow);
end;

procedure TFooterPanel.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  i,dx: integer;
begin
  inherited;

  i := 0;
  dx := 0;

  while (X > dx) and (i < FGrid.ColCount) do
  begin
    dx := dx + FGrid.ColWidths[i];
    inc(i);
  end;

  if Assigned(FGrid.OnClick) then
    FGrid.OnClick(FGrid);

  FGrid.DoClickCell(FGrid.RowCount - 1,i);
end;

procedure TFooterPanel.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  i,dx: integer;
begin
  inherited;

  i := 0;
  dx := 0;

  while (X > dx) and (i < FGrid.ColCount) and (i < FGrid.FixedCols) do
  begin
    dx := dx + FGrid.ColWidths[i];
    inc(i);
  end;

  i := FGrid.LeftCol;
  while (X > dx) and (i < FGrid.ColCount) do
  begin
    dx := dx + FGrid.ColWidths[i];
    inc(i);
  end;


  if ShowHint and ((FLastHintX <> i - 1) and (FLastHintX >= 0)) then
  begin
    Application.CancelHint;
    FLastHintX := i - 1;
  end;
end;

procedure TFooterPanel.CMMouseLeave(var Msg: TMessage);
begin
  inherited;
  FLastHintX := -1;
end;

{ TFloatingFooter }

procedure TFloatingFooter.Assign(Source: TPersistent);
begin
  if (Source is TFloatingFooter) then
  begin
    FCalculateHiddenRows := (Source as TFloatingFooter).CalculateHiddenRows;
    FColor := (Source as TFloatingFooter).Color;
    FColumn := (Source as TFloatingFooter).Column;
    FCustomTemplate := (Source as TFloatingFooter).CustomTemplate;
    FFooterstyle := (Source as TFloatingFooter).FooterStyle;
    Visible := (Source as TFloatingFooter).Visible;
    FShowHint := (Source as TFloatingFooter).ShowHint;
  end;
end;

constructor TFloatingFooter.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AOwner;
  FColor := clBtnFace;
  FOnCalcFooter := nil;
  FBorderColor := clNone;
  FEnableCalculation := true;
  FCalculateHiddenRows := true;
  FDidInc := false;
end;

destructor TFloatingFooter.Destroy;
begin
  inherited;
end;

function TFloatingFooter.GetColumnCalc(c: Integer): TColumnCalcType;
begin
  Result := acNone;
  if FGrid.HasCellProperties(c,FGrid.RowCount - 1) then
    Result := FGrid.CellProperties[c,FGrid.RowCount -1].CalcType;
end;

procedure TFloatingFooter.Invalidate;
begin
  FGrid.FFooterPanel.Invalidate;
end;

procedure TFloatingFooter.SetColor(const Value: TColor);
begin
  FColor := Value;
  FGrid.FFooterPanel.Invalidate;
end;

procedure TFloatingFooter.SetColumn(const Value: Integer);
begin
  FColumn := Value;
  FGrid.FFooterPanel.Invalidate;
end;

procedure TFloatingFooter.SetColumnCalc(c: Integer;
  const Value: TColumnCalcType);
begin
  FGrid.CellProperties[c,FGrid.RowCount -1].CalcType := Value;
  FGrid.UpdateCell(c,FGrid.RowCount - 1);
end;

procedure TFloatingFooter.SetCustomTemplate(const Value: string);
begin
  FCustomTemplate := Value;
  FGrid.FFooterPanel.Invalidate;
end;

procedure TFloatingFooter.SetEnableCalculation(const Value: Boolean);
begin
  FEnableCalculation := Value;
end;

procedure TFloatingFooter.SetFooterStyle(const Value: TFooterStyle);
begin
  FFooterStyle := Value;

  if not (csDesigning in FGrid.ComponentState) then
  begin
    if ((FFooterStyle = fsFixedLastRow) or not FVisible) and (FDidInc) then
    begin
      FGrid.RowCount :=  FGrid.RowCount - 1;
      FDidInc := false;
    end
    else
    if (FFooterStyle <> fsFixedLastRow) and FVisible and not FDidInc then
    begin
      FGrid.RowCount :=  FGrid.RowCount + 1;
      FDidInc := true;
    end;
  end;

  FGrid.HideLastRow := Visible; // and (FFooterStyle = fsFixedLastRow);
  FGrid.Invalidate;
  FGrid.FFooterPanel.Invalidate;
end;

procedure TFloatingFooter.SetHeight(const Value: Integer);
begin
  FHeight := Value;

  if Assigned(FGrid.FFooterPanel) and (FHeight > 0) then
    FGrid.FFooterPanel.Height := Value - 1;
end;

procedure TFloatingFooter.SetShowHint(const Value: boolean);
begin
  FShowHint := Value;
  FGrid.FFooterPanel.ShowHint := Value;
end;

procedure TFloatingFooter.SetBorderColor(const Value: TColor);
begin
  if (FBorderColor <> Value) then
  begin
    FBorderColor := Value;
    FGrid.FFooterPanel.Invalidate;
  end;
end;

procedure TFloatingFooter.SetVisible(const Value: Boolean);
begin
  if (FVisible <> Value) then
  begin
    FVisible := Value;

    if Value then
      FGrid.FFooterPanel.Height := FHeight - 1
    else
      FGrid.FFooterPanel.Height := 0;

    FGrid.FFooterPanel.Visible := Value;

    if FGrid.FFooterPanel.Visible and (FFooterStyle = fsFixedLastRow) then
      FGrid.FixedFooters := 1
    else
      FGrid.FixedFooters := 0;

    if not (csDesigning in FGrid.ComponentState) then
    begin
      if ((FFooterStyle = fsFixedLastRow) or not FVisible) and (FDidInc) then
      begin
        FGrid.RowCount :=  FGrid.RowCount - 1;
        FDidInc := false;
      end
      else
      if (FFooterStyle <> fsFixedLastRow) and FVisible and not FDidInc then
      begin
        FGrid.RowCount :=  FGrid.RowCount + 1;
        FDidInc := true;
      end;
    end;

    if not (csDesigning in FGrid.ComponentState) and (FGrid.FixedRows > 0) then
      FGrid.FixedrowAlways := true;

    FGrid.HideLastRow := (FFooterStyle = fsFixedLastRow) and (FGrid.FFloatingFooter.Visible = true);
    FGrid.Invalidate;
  end;
end;

{ TGridCellIO }

constructor TGridCellIO.Create(AOwner: TComponent);
begin
  inherited;
end;

destructor TGridCellIO.Destroy;
begin
  inherited;
end;

{ TGridCellPropIO }

constructor TGridCellPropIO.Create(AOwner: TComponent);
begin
  inherited;
  FCellProperties := TCellProperties.Create(TBaseGrid(AOwner),0,0);
end;

destructor TGridCellPropIO.Destroy;
begin
  FCellProperties.Free;
  inherited;
end;


{ TGridGraphicIO }

constructor TGridGraphicIO.Create(AOwner: TComponent);
begin
  inherited;
  FCellGraphic := TBaseCellGraphic.Create;
end;

destructor TGridGraphicIO.Destroy;
begin
  FCellGraphic.Free;
  inherited;
end;

{ TGridBMPIO }

constructor TGridBMPIO.Create(AOwner: TComponent);
begin
  inherited;
  FBitmap := TBitmap.Create;
end;

destructor TGridBMPIO.Destroy;
begin
  FBitmap.Free;
  inherited;
end;

{ TGridIconIO }

constructor TGridIconIO.Create(AOwner: TComponent);
begin
  inherited;
  FIcon := TIcon.Create;
end;

destructor TGridIconIO.Destroy;
begin
  FIcon.Free;
  inherited;
end;

{ TGridPicIO }

constructor TGridPicIO.Create(AOwner: TComponent);
begin
  inherited;
  FPicture := TPicture.Create;
end;

destructor TGridPicIO.Destroy;
begin
  FPicture.Free;
  inherited;
end;

{ TGridFilePicIO }

constructor TGridFilePicIO.Create(AOwner: TComponent);
begin
  inherited;
  FPicture := TFilePicture.Create;
end;

destructor TGridFilePicIO.Destroy;
begin
  FPicture.Free;
  inherited;
end;

{ TGridSLIO }

constructor TGridSLIO.Create(AOwner: TComponent);
begin
  inherited;
  FStrings := TStringList.Create;
end;

destructor TGridSLIO.Destroy;
begin
  FStrings.Free;
  inherited;
end;

function TAdvStringGrid.ColumnByHeader(AValue: string): integer;
var
  i: integer;
begin
  result := -1;
  for i := 0 to TotalColCount - 1 do
  begin
    if AllCells[i,0] = AValue then
    begin
      result := i;
      break;
    end;
  end;
end;

function TAdvStringGrid.ColumnPosition(ACol: integer): integer;
var
  i: integer;
begin
  Result := ACol;

  if FColumnOrder.Count = 0 then
    Exit;

  for i := 1 to ColCount + FNumHidden do
  begin
    if ACol = FColumnOrder.Items[i - 1] then
    begin
      Result := i - 1;
      break;
    end;
  end;

  if GroupColumn <> -1 then
  begin
    if ACol >= GroupColumn then
    begin
      Result := Result - 1;
    end;
  end;
end;

function TAdvStringGrid.ColumnAtPosition(ACol: integer): integer;
begin
  Result := ACol;
  if FColumnOrder.Count = 0 then
  begin
    SetColumnOrder;
    if FColumnOrder.Count = 0 then
      Exit;
  end;

  Result := FColumnOrder.Items[ACol];

  if GroupColumn <> -1 then
  begin
    if Result >= GroupColumn then
      Result := Result + 1;
  end;
end;

procedure TAdvStringGrid.ResetColumnOrder;
var
  i: Integer;
  rst: Boolean;
begin
  UnHideColumnsAll;
  if FColumnOrder.Count = 0 then
  begin
    SetColumnOrder;
    Exit;
  end;

  rst := False;
  while not rst do
  begin
    rst := True;
    for i := 1 to ColCount do
    begin
      if i - 1 > FColumnOrder.Items[i - 1] then
      begin
        rst := False;
        MoveColumn(i - 1,FColumnOrder.Items[i - 1]);
      end;
    end;
  end;
end;

procedure TAdvStringGrid.SetColumnOrder;
var
  i: Integer;
begin
  FColumnOrder.Clear;
  for i := 1 to ColCount do
    FColumnOrder.Add(i - 1);

  FSuppressColSizes.Clear;

  for I := 0 to ColCount - 1 do
    FSuppressColSizes.Add(ColWidths[I]);
end;

function TAdvStringGrid.GetWideCells(i, j: Integer): widestring;
begin
  {$IFDEF DELPHI_UNICODE}
  Result := Cells[i,j];
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
  Result := DecodeWideStr(Cells[i,j]);
  {$ENDIF}
end;

procedure TAdvStringGrid.SetWideCells(i, j: Integer;
  const Value: widestring);
begin
  {$IFDEF DELPHI_UNICODE}
  Cells[i,j] := Value;
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
  GridCells[i,j] := EncodeWideStr(Value);
  {$ENDIF}
end;

{ TGridTransCombo }

constructor TGridTransCombo.Create(AOwner: TComponent);
begin
  inherited;
  FGrid := TAdvStringGrid(AOwner);
  Visible := False;

end;

procedure TGridTransCombo.DoExit;
begin
  inherited;
  StopEdit;
end;

function TGridTransCombo.GetDropWidth: integer;
begin
  Result := SendMessage(Handle,CB_GETDROPPEDWIDTH,0,0);
end;

procedure TGridTransCombo.KeyPress(var Key: Char);
begin
  if Key = #13 then
    Key := #0;
  inherited;
end;

procedure TGridTransCombo.SetDropWidth(const Value: integer);
begin
  SendMessage(Handle,CB_SETDROPPEDWIDTH,Value,0);
end;

procedure TGridTransCombo.SizeDropDownWidth;
var
  i,tw,nw: Integer;
  HasScroll: Boolean;
  sz: TSize;
  ws: widestring;
begin
  tw := Width;

  HasScroll := Items.Count > DropDownCount;

  for i := 1 to Items.Count do
  begin
    ws := Self.Items[i - 1];
    GetTextExtentPoint32W(FGrid.Canvas.Handle,PWideChar(ws),Length(ws),sz);
    nw := sz.cx;

//    nw := FGrid.Canvas.TextWidth(Self.Items[i - 1]);

    if HasScroll then
    begin
      if nw > tw - 25 then
        tw := nw + 25;
    end
    else
    begin
      if nw > tw - 5 then
        tw := nw + 8;
    end;
  end;

  SendMessage(Handle,CB_SETDROPPEDWIDTH,tw,0);
end;

function TGridTransCombo.StopEdit: Boolean;
var
  Valid: Boolean;
  value: string;
begin
  Result := True;

  if Assigned(FGrid) then
  begin
    Value := self.Text;
    Valid := true;

    if Assigned(FGrid.OnCellValidate) then
      FGrid.OnCellValidate(FGrid, Col, Row, Value, Valid);

    if Valid then
    begin
      if Assigned(FGrid.OnEditingDone) then
        FGrid.OnEditingDone(FGrid);

      FGrid.Cells[Col,Row] := Value;
    end
    else
    begin
      Result := False;
      FGrid.Col := Col;
      FGrid.Row := Row;
      SetFocus;
      Exit;
    end;
  end;

  Visible := False;
end;


{ TGridTransEdit }

constructor TGridTransEdit.Create(AOwner: TComponent);
begin
  inherited;
  FGrid := TAdvStringGrid(AOwner);
  Visible := False;
end;

function TGridTransEdit.StopEdit: Boolean;
var
  Valid: Boolean;
  value: string;
begin
  Result := True;

  if Assigned(FGrid) then
  begin
    Value := self.Text;
    Valid := true;

    if Assigned(FGrid.OnCellValidate) then
      FGrid.OnCellValidate(FGrid, Col, Row, Value, Valid);

    if Valid then
    begin
      if Assigned(FGrid.OnEditingDone) then
        FGrid.OnEditingDone(FGrid);

      FGrid.Cells[Col,Row] := Value;

      if FilterEdit then
        FGrid.DoFilterEditDone(Col, ftNone);
    end
    else
    begin
      Result := False;
      FGrid.Col := Col;
      FGrid.Row := Row;
      SetFocus;
      Exit;
    end;
  end;

  Visible := False;
end;

procedure TGridTransEdit.DoExit;
begin
  inherited;
  StopEdit;
end;


procedure TGridTransEdit.Keypress(var Key: Char);
begin
  if Key = #13 then
  begin
    Key := #0;
    StopEdit;
  end;
  inherited;
end;

{ TGrouping }

procedure TGrouping.Assign(Source: TPersistent);
begin
  if (Source is TGrouping) then
  begin
    FGroupCountFormat := (Source as TGrouping).GroupCountFormat;
    FHeaderColor := (Source as TGrouping).HeaderColor;
    FHeaderColorTo := (Source as TGrouping).HeaderColorTo;
    FHeaderTextColor := (Source as TGrouping).HeaderTextColor;
    FHeaderUnderLine := (Source as TGrouping).HeaderUnderline;

    FMergeHeader := (Source as TGrouping).MergeHeader;
    FMergeSummary := (Source as TGrouping).MergeSummary;

    FShowGroupCount := (Source as TGrouping).ShowGroupCount;
    FSummaryColor := (Source as TGrouping).SummaryColor;
    FSummaryColorTo := (Source as TGrouping).SummaryColorTo;
    FSummaryTextColor := (Source as TGrouping).SummaryTextColor;
    FSummaryLine := (Source as TGrouping).SummaryLine;
    FAutoCheckGroup := (Source as TGrouping).AutoCheckGroup;
    FAutoSelectGroup := (Source as TGrouping).AutoSelectGroup;
  end;
end;

constructor TGrouping.Create;
begin
  inherited;

  FHeaderColor := clNone;
  FHeaderColorTo := clNone;
  FHeaderTextColor := clNone;
  FHeaderUnderline := false;
  FHeaderLineWidth := 2;
  FHeaderLineColor := clBlue;

  FSummaryColor := clNone;
  FSummaryColorTo := clNone;
  FSummaryTextColor := clNone;
  FSummaryLine := false;
  FSummaryLineColor := clBlue;
  FSummaryLineWidth := 2;
end;


{ TDragDropSettings }


constructor TDragDropSettings.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AOwner;
  FOleDropTarget := False;
  FOleAcceptFiles := True;
  FOleAcceptText := True;
  FOleAcceptURLs := True;
  FOleAppendRows := False;
  FShowCells := True;
end;

destructor TDragDropSettings.Destroy;
begin
  inherited;
end;

procedure TDragDropSettings.Assign(Source: TPersistent);
begin
  if (Source is TDragDropSettings) then
  begin
    FShowCells := (Source as TDragDropSettings).ShowCells;
    FOleAcceptFiles := (Source as TDragDropSettings).OleAcceptFiles;
    FOleAcceptText := (Source as TDragDropSettings).OleAcceptText;
    FOleAcceptURLs := (Source as TDragDropSettings).OleAcceptURLs;
    FOleCopyAlways := (Source as TDragDropSettings).OleCopyAlways;
    FOleDropTarget := (Source as TDragDropSettings).OleDropTarget;
    FOleDropSource := (Source as TDragDropSettings).OleDropSource;
    FOleEntireRows := (Source as TDragDropSettings).OleEntireRows;
    FOleInsertRows := (Source as TDragDropSettings).OleInsertRows;
    FOleRemoveRows := (Source as TDragDropSettings).OleRemoveRows;
    FOleAppendRows := (Source as TDragDropSettings).OleAppendRows;
    FOleDropRTF := (Source as TDragDropSettings).OleDropRTF;
    FOleColumnDragDrop := (Source as TDragDropSettings).OleColumnDragDrop;
    FOleColumnsOnly := (Source as TDragDropSettings).OleColumnsOnly;
    FOleColumnReorder := (Source as TDragDropSettings).OleColumnReorder;
  end;
end;

procedure TDragDropSettings.SetOleDropRTF(const Value: Boolean);
begin
  SetRTFAware(Value);
  FOleDropRTF := Value;
end;

procedure TDragDropSettings.SetOleDropTarget(const Value: Boolean);
begin
  FOleDropTarget := Value;

  if not (csDesigning in FGrid.ComponentState) then
  begin
    if FOleDropTarget then
    begin
      FGrid.FGridDropTarget := TGridDropTarget.Create(FGrid);
      FGrid.FOleDropTargetAssigned := RegisterDragDrop(FGrid.Handle, FGrid.FGridDropTarget ) = s_OK;
    end
    else
      if FGrid.FOleDropTargetAssigned then RevokeDragDrop(FGrid.Handle);
  end;
end;


procedure TDragDropSettings.SetShowCells(const Value: boolean);
begin
  FShowCells := Value;
end;

{ TBalloonSettings }

procedure TBalloonSettings.Assign(Source: TPersistent);
begin
  if (Source is TBalloonSettings) then
  begin
    FTextColor := (Source as TBalloonSettings).TextColor;
    FBackgroundColor := (Source as TBalloonSettings).BackgroundColor;
    FInitialDelay := (Source as TBalloonSettings).InitialDelay;
    FAutoHideDelay := (Source as TBalloonSettings).AutoHideDelay;
    FReshowDelay := (Source as TBalloonSettings).ReshowDelay;
    FEnable := (Source as TBalloonSettings).Enable;
  end;
end;

constructor TBalloonSettings.Create;
begin
  inherited Create;
  FTextColor := clNone;
  FBackgroundColor := clNone;
  FInitialDelay := -1;
  FAutoHideDelay := -1;
  FReshowDelay := -1;
  FEnable := False;
end;

procedure TBalloonSettings.SetEnable(const Value: Boolean);
begin
  if (FEnable <> Value) then
  begin
    FEnable := Value;
    if Assigned(FOnEnableChange) then
      FOnEnableChange(self);
  end;
end;


{ TShowModified }

procedure TShowModified.Assign(Source: TPersistent);
begin
  if (Source is TShowModified) then
  begin
    FColor := (Source as TShowModified).Color;
    FEnabled := (Source as TShowModified).Enabled;
  end;
end;

constructor TShowModified.Create;
begin
  inherited;
  FColor := clYellow;
  FEnabled := False;
end;

procedure TShowModified.SetColor(const Value: TColor);
begin
  FColor := Value;
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

{ TRetEdit }

procedure TRetEdit.WMKeyDown(var Msg:TWMKeydown);
begin
  if (Msg.CharCode = VK_RETURN) then
  begin
    if (GetKeyState(VK_CONTROL) and $8000 = $8000) then
    begin
      if Assigned(OnCtrlReturn) then
        FOnCtrlReturn(Self);
    end
    else
      if Assigned(FOnReturn) then
        FOnReturn(Self);
    Exit;
  end;

  inherited;
end;

procedure TRetEdit.WMChar(var Msg: TWMChar);
var
  ch: char;
begin
  if Msg.CharCode in [Ord(#13),Ord(#10)] then
  begin
    ch := Chr(Msg.CharCode);
    if Assigned(OnKeyPress) then
      OnKeyPress(self, ch);
    Msg.Result :=0
  end
  else
    inherited;
end;

procedure TRetEdit.CreateParams(var Params:TCreateParams);
begin
  inherited;
  Params.Style :=  Params.Style + ES_MULTILINE;
end;

{ TSearchPanel }

procedure TSearchPanel.BackwardClick(Sender: TObject);
begin
  if Assigned(FOnBackwardClick) then
    FOnBackwardClick(Self);
end;

procedure TSearchPanel.ExitClick(Sender: TObject);
begin
  if Assigned(FOnExitClick) then
    FOnExitClick(Self);
end;

procedure TSearchPanel.HighlightClick(Sender: TObject);
begin
  if Assigned(FOnHighlightClick) then
    FOnHighlightClick(Self);
end;


procedure TSearchPanel.MatchCaseClick(Sender: TObject);
begin
  if Assigned(FOnMatchCaseClick) then
    FOnMatchCaseClick(Self);
end;

procedure TSearchPanel.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
end;

constructor TSearchPanel.Create(AOwner: TComponent);
begin
  inherited;
  FEdit := TRetEdit.Create(Self);
  FForwardButton := TAdvGridButton.Create(Self);
  FBackwardButton := TAdvGridButton.Create(Self);
  FExitButton := TAdvGridButton.Create(Self);
  FHiliteButton := TAdvGridButton.Create(Self);
  FMatchCase := TAdvCheckBox.Create(Self);
  FColorTo := clNone;
  FGrid := AOwner as TAdvStringGrid;
end;

procedure TSearchPanel.CreateWnd;
begin
  inherited;

  FEdit.Parent := Self;
  FEdit.Top := 6;
  FEdit.Width := 110;
  FEdit.Left := 25;
  FEdit.OnChange := EditChange;
  FEdit.OnReturn := EditReturn;
  FEdit.OnCtrlReturn := EditCtrlReturn;
  FEdit.OnKeyDown := EditKeyDown;

  if UseRightToLeftAlignment then
    FEdit.Left := Width - FEdit.Width - FEdit.Left;

  FForwardButton.Parent := self;

  FForwardButton.Top := 5;
  FForwardButton.Left := 140;
  FForwardButton.Height := 23;
  FForwardButton.Width := 90;
  FForwardButton.Hint := FHintFindNext;
  FForwardButton.ShowHint := FHintFindNext <> '';
  FForwardButton.Caption := FindNextCaption;
  FForwardButton.OnClick := ForwardClick;
  FForwardButton.Glyph.LoadFromResourceName(hinstance,'ASGARDOWN');
  FForwardButton.GlyphDisabled.LoadFromResourceName(hinstance,'ASGARDOWND');
  FForwardButton.Enabled := false;
  FForwardButton.ParentFont := true;

  if UseRightToLeftAlignment then
    FForwardButton.Left := Width - FForwardButton.Width - FForwardButton.Left;

  FBackwardButton.Parent := self;
  FBackwardButton.Left := 235;
  FBackwardButton.Top := 5;
  FBackwardButton.Height := 23;
  FBackwardButton.Width := 90;
  FBackwardButton.Hint := FHintFindPrev;
  FBackwardButton.ShowHint := FHintFindPrev <> '';
  FBackwardButton.Caption := FindPrevCaption;
  FBackwardButton.OnClick := BackwardClick;
  FBackwardButton.Glyph.LoadFromResourceName(hinstance,'ASGARUP');
  FBackwardButton.GlyphDisabled.LoadFromResourceName(hinstance,'ASGARUPD');
  FBackwardButton.Enabled := false;
  FBackwardButton.ParentFont := true;

  if UseRightToLeftAlignment then
    FBackwardButton.Left := Width - FBackwardButton.Width - FBackwardButton.Left;

  FExitButton.ParentFont := false;
  FExitButton.Parent := self;
  FExitButton.Left := 5;
  FExitButton.Top := 7;
  FExitButton.Width := 14;
  FExitButton.Height := 14;
  FExitButton.Hint := FHintClose;
  FExitButton.ShowHint := FHintClose <> '';
  FExitButton.Glyph.LoadFromResourceName(hinstance,'ASGCLOSE');
  FExitButton.GlyphHot.LoadFromResourceName(hinstance,'ASGCLOSEH');
  FExitButton.GlyphDown.LoadFromResourceName(hinstance,'ASGCLOSED');
  FExitButton.OnClick := ExitClick;
  FExitButton.ParentFont := true;
  FExitButton.Caption := '';

  if UseRightToLeftAlignment then
    FExitButton.Left := Width - FExitButton.Width - FExitButton.Left;

  FHiliteButton.Parent := self;
  FHiliteButton.Top := 5;
  FHiliteButton.Left := 330;
  FHiliteButton.Width := 90;
  FHiliteButton.Height := 23;
  FHiliteButton.Hint := FHintHighlight;
  FHiliteButton.ShowHint := FHintHighlight <> '';
  FHiliteButton.Font.Style := [];
  FHiliteButton.Enabled := false;
  FHiliteButton.Caption := HighLightCaption;
  FHiliteButton.ParentFont := true;

  FHiliteButton.Style := AdvObj.tasCheck;
  FHiliteButton.OnClick := HighLightClick;
  FHiliteButton.Glyph.LoadFromResourceName(hinstance,'ASGHI');
  FHiliteButton.GlyphDisabled.LoadFromResourceName(hinstance,'ASGHID');

  if UseRightToLeftAlignment then
    FHiliteButton.Left := Width - FHiliteButton.Width - FHiliteButton.Left;

  FMatchCase.Parent := Self;
  FMatchCase.Top := 8;

  if FHiliteButton.Visible then
    FMatchCase.Left := 425
  else
    FMatchCase.Left := 330;

  FMatchCase.Caption := MatchCaseCaption;
  FMatchCase.OnClick := MatchCaseClick;

  if Assigned(FGrid.OnCreatedSearchFooter) then
    FGrid.OnCreatedSearchFooter(FGrid);
end;

destructor TSearchPanel.Destroy;
begin
  inherited;
end;

procedure TSearchPanel.EditReturn(Sender: TObject);
begin
  ForwardClick(Sender);
end;

procedure TSearchPanel.EditCtrlReturn(Sender: TObject);
begin
  BackwardClick(Sender);
end;


procedure TSearchPanel.EditChange(Sender: TObject);
begin
  FForwardButton.Enabled := FEdit.Text <> '';
  FBackwardButton.Enabled := FEdit.Text <> '';
  FHiliteButton.Enabled := FEdit.Text <> '';
  if Assigned(FOnEditChange) then
    FOnEditChange(Self);
end;

procedure TSearchPanel.ForwardClick(Sender: TObject);
begin
  if Assigned(FOnForwardClick) then
    FOnForwardClick(Self);
end;

procedure TSearchPanel.Paint;
begin
  inherited;
  Canvas.Brush.Color := Color;
  Canvas.Pen.Color := Color;

  if (ColorTo <> clNone) then
    DrawGradient(Canvas, Color, ColorTo, 32, ClientRect,false)
  else
    Canvas.Rectangle(ClientRect.Left, ClientRect.Top, ClientRect.Right, ClientRect.Bottom);

  Canvas.Pen.Color := FGrid.GridLineColor;
  Canvas.MoveTo(0,0);
  Canvas.LineTo(Width,0);
end;

procedure TSearchPanel.SetColorTo(const Value: TColor);
begin
  FColorTo := Value;
  Invalidate;
end;

{ TDragScrollDelays }

procedure TDragScrollDelays.Assign(Source: TPersistent);
begin
  if (Source is TDragScrollDelays) then
  begin
    FInitialDelay := (Source as TDragScrollDelays).InitialDelay;
    FRepeatDelay := (Source as TDragScrollDelays).RepeatDelay;
  end;
end;

{ TDragScrollMargins }

procedure TDragScrollMargins.Assign(Source: TPersistent);
begin
  if (Source is TDragScrollMargins) then
  begin
    FTopMargin  := (Source as TDragScrollMargins).TopMargin;
    FBottomMargin := (Source as TDragScrollMargins).BottomMargin;
    FLeftMargin := (Source as TDragScrollMargins).LeftMargin;
    FRightMargin := (Source as TDragScrollMargins).RightMargin;
  end;
end;

{ TDragScrollOptions }

procedure TDragScrollOptions.Assign(Source: TPersistent);
begin
  if (Source is TDragScrollOptions) then
  begin
    FMargins.Assign((Source as TDragScrollOptions).Margins);
    FDelays.Assign((Source as TDragScrollOptions).Delays);
    FActive := (Source as TDragScrollOptions).Active;
  end;
end;

constructor TDragScrollOptions.Create;
begin
  inherited;
  FActive := False;
  FDelays := TDragScrollDelays.Create;
  FDelays.InitialDelay := 1000;
  FDelays.RepeatDelay := 250;
  FMargins := TDragScrollMargins.Create;
  FMargins.TopMargin := 50;
  FMargins.BottomMargin := 50;
  FMargins.LeftMargin := 50;
  FMargins.RightMargin := 50;
end;

destructor TDragScrollOptions.Destroy;
begin
  FDelays.free;
  FMargins.free;
  inherited;
end;


procedure TGridProgressAppearance.Assign(Source: TPersistent);
begin
  if Source is TGridProgressAppearance then
  begin
    FUnCompleteFontColor := TGridProgressAppearance(Source).UnCompleteFontColor;
    FCompleteColor := TGridProgressAppearance(Source).CompleteColor;
    FUnCompleteColor := TGridProgressAppearance(Source).UnCompleteColor;
    FCompleteFontColor := TGridProgressAppearance(Source).CompleteFontColor;
    FStacked := TGridProgressAppearance(Source).Stacked;
    FShowPercentage := TGridProgressAppearance(Source).ShowPercentage;
    FShowBorder := TGridProgressAppearance(Source).ShowBorder;
    FCompletionSmooth := TGridProgressAppearance(Source).CompletionSmooth;
    FShowGradient := TGridProgressAppearance(Source).ShowGradient;
    FLevel2Perc := TGridProgressAppearance(Source).Level2Perc;
    FLevel1Perc := TGridProgressAppearance(Source).Level1Perc;
    FSteps := TGridProgressAppearance(Source).Steps;
    FLevel3Color := TGridProgressAppearance(Source).Level3Color;
    FLevel1Color := TGridProgressAppearance(Source).Level1Color;
    FLevel0Color := TGridProgressAppearance(Source).Level0Color;
    FLevel3ColorTo := TGridProgressAppearance(Source).Level3ColorTo;
    FLevel2ColorTo := TGridProgressAppearance(Source).Level2ColorTo;
    FLevel0ColorTo := TGridProgressAppearance(Source).Level0ColorTo;
    FLevel1ColorTo := TGridProgressAppearance(Source).Level1ColorTo;
    FBorderColor := TGridProgressAppearance(Source).BorderColor;
    FLevel2Color := TGridProgressAppearance(Source).Level2Color;
    FStyle := TGridProgressAppearance(Source).Style;
    Changed;
  end;
end;



//------------------------------------------------------------------------------

procedure TGridProgressAppearance.Changed;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

//------------------------------------------------------------------------------

constructor TGridProgressAppearance.Create;
begin
  inherited;

  FCompleteColor := clRed;
  FCompleteFontColor := clBlue;
  FUnCompleteColor := clNone;
  FUnCompleteFontColor := clWindowText;

  FLevel0Color := clLime;
  FLevel0ColorTo := $00E1FFE1;
  FLevel1Color := clYellow;
  FLevel1ColorTo := $00CAFFFF;
  FLevel2Color := $0053A9FF;
  FLevel2ColorTo := $00A8D3FF;
  FLevel3Color := clRed;
  FLevel3ColorTo := $00CACAFF;

  FLevel1Perc := 70;
  FLevel2Perc := 90;

  FBorderColor := clBlack;
  FShowBorder := false;
  FStacked := false;
  FShowPercentage := true;
  FCompletionSmooth := true;
  FShowGradient := true;
  FSteps := 11;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetBorderColor(const Value: TColor);
begin
  if FBorderColor <> Value then
  begin
    FBorderColor := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetCompleteColor(const Value: TColor);
begin
  if FCompleteColor <> Value then
  begin
    FCompleteColor := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetCompleteFontColor(const Value: TColor);
begin
  if FCompleteFontColor <> Value then
  begin
    FCompleteFontColor := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetCompletionSmooth(const Value: Boolean);
begin
  if FCompletionSmooth <> Value then
  begin
    FCompletionSmooth := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel0Color(const Value: TColor);
begin
  if FLevel0Color <> Value then
  begin
    FLevel0Color := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel0ColorTo(const Value: TColor);
begin
  if FLevel0ColorTo <> Value then
  begin
    FLevel0ColorTo := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel1Color(const Value: TColor);
begin
  if FLevel1Color <> Value then
  begin
    FLevel1Color := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel1ColorTo(const Value: TColor);
begin
  if FLevel1ColorTo <> Value then
  begin
    FLevel1ColorTo := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel1Perc(const Value: Integer);
begin
  if FLevel1Perc <> Value then
  begin
    FLevel1Perc := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel2Color(const Value: TColor);
begin
  if FLevel2Color <> Value then
  begin
    FLevel2Color := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel2ColorTo(const Value: TColor);
begin
  if FLevel2ColorTo <> Value then
  begin
    FLevel2ColorTo := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel2Perc(const Value: Integer);
begin
  if FLevel2Perc <> Value then
  begin
    FLevel2Perc := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel3Color(const Value: TColor);
begin
  if FLevel3Color <> Value then
  begin
    FLevel3Color := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetLevel3ColorTo(const Value: TColor);
begin
  if FLevel3ColorTo <> Value then
  begin
    FLevel3ColorTo := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetShowBorder(const Value: Boolean);
begin
  if FShowBorder <> Value then
  begin
    FShowBorder := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetShowGradient(const Value: Boolean);
begin
  if FShowGradient <> Value then
  begin
    FShowGradient := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetShowPercentage(const Value: Boolean);
begin
  if FShowPercentage <> Value then
  begin
    FShowPercentage := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetStacked(const Value: Boolean);
begin
  if FStacked <> Value then
  begin
    FStacked := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetSteps(const Value: Integer);
begin
  if FSteps <> Value then
  begin
    FSteps := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetStyle(const Value: TProgressStyle);
begin
  if FStyle <> Value then
  begin
    FStyle := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetUnCompleteColor(const Value: TColor);
begin
  if FUnCompleteColor <> Value then
  begin
    FUnCompleteColor := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

procedure TGridProgressAppearance.SetUnCompleteFontColor(const Value: TColor);
begin
  if FUnCompleteFontColor <> Value then
  begin
    FUnCompleteFontColor := Value;
    Changed;
  end;
end;

//------------------------------------------------------------------------------

{ TFilterDropDown }

constructor TFilterDropDown.Create;
begin
  inherited;
  FFont := TFont.Create;
  FWidth := 150;
  FHeight := 150;
  FCaseSensitive := False;
  FSorted := true;
  FColumnWidth := False;
  FColor := clWindow;
  FAutoSize := false;
  FGlyph := TBitmap.Create;
  FGlyph.OnChange := GlyphChanged;
  FGlyphActive := TBitmap.Create;
  FGlyphActive.OnChange := GlyphChanged;
end;

//------------------------------------------------------------------------------

destructor TFilterDropDown.Destroy;
begin
  FGlyph.Free;
  FGlyphActive.Free;
  FFont.Free;
  inherited;
end;

procedure TFilterDropDown.GlyphChanged(Sender: TObject);
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

//------------------------------------------------------------------------------

procedure TFilterDropDown.SetFont(const Value: TFont);
begin
  FFont.Assign(Value);
end;

procedure TFilterDropDown.SetGlyph(const Value: TBitmap);
begin
  FGlyph.Assign(Value);
end;

procedure TFilterDropDown.SetGlyphActive(const Value: TBitmap);
begin
  FGlyphActive.Assign(Value);
end;

//------------------------------------------------------------------------------

procedure TFilterDropDown.Assign(Source: TPersistent);
begin
  if (Source is TFilterDropdown) then
  begin
    FCaseSensitive := (Source as TFilterDropdown).CaseSensitive;
    FColor := (Source as TFilterDropdown).Color;
    FColumnWidth := (Source as TFilterDropDown).ColumnWidth;
    FFont.Assign((Source as TFilterDropDown).Font);
    FHeight := (Source as TFilterDropDown).Height;
    FWidth := (Source as TFilterDropDown).Width;
    FGlyph.Assign((Source as TFilterDropDown).Glyph);
    FGlyphActive.Assign((Source as TFilterDropDown).GlyphActive);
    FTextChecked := (Source as TFilterDropDown).TextChecked;
    FTextUnchecked := (Source as TFilterDropDown).TextUnchecked;
  end;
end;

//------------------------------------------------------------------------------

{ TFilterEdit }

procedure TFilterEdit.Assign(Source: TPersistent);
begin
  if (Source is TFilterEdit) then
  begin
    FEnabled := (Source as TFilterEdit).Enabled;
    FRow := (Source as TFilterEdit).Row;
    FColor := (Source as TFilterEdit).Color;
    FColumns := (Source as TFilterEdit).Columns;
    FTypeNames.Assign((Source as TFilterEdit).TypeNames);
    FCaseSensitive := (Source as TFilterEdit).CaseSensitive;
  end;
end;

constructor TFilterEdit.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FOwner := AOwner;
  FCaseSensitive := true;
  FColor := clWhite;
  FColumns := fdNormal;
  FTypeNames := TStringlist.Create;
  FTypeNames.Add('Starts with');
  FTypeNames.Add('Ends with');
  FTypeNames.Add('Contains');
  FTypeNames.Add('Not contains');
  FTypeNames.Add('Equal');
  FTypeNames.Add('Not equal');
  FTypeNames.Add('Larger than');
  FTypeNames.Add('Smaller than');
  FTypeNames.Add('Clear');
end;

destructor TFilterEdit.Destroy;
begin
  FTypeNames.Free;
  inherited;
end;

procedure TFilterEdit.SetColor(const Value: TColor);
begin
  if (FColor <> Value) then
  begin
    FColor := Value;
    FOwner.Invalidate;
  end;
end;

procedure TFilterEdit.SetColumns(const Value: TFilterDropDownColumns);
begin
  if (FColumns <> Value) then
  begin
    FColumns := Value;
    FOwner.Invalidate;
  end;
end;

procedure TFilterEdit.SetEnabled(const Value: boolean);
begin
  if (FEnabled <> Value) then
  begin
    FEnabled := Value;
    FOwner.Invalidate;
    FOwner.FilterActive := false;
    FOwner.Filter.Clear;
    FOwner.ClearRect(0,Row,FOwner.ColCount - 1,Row);
  end;
end;

procedure TFilterEdit.SetRow(const Value: integer);
begin
  if (FRow <> Value) then
  begin
    FRow := Value;
    FOwner.Invalidate;
  end;
end;


procedure TFilterEdit.SetTypeNames(const Value: TStringList);
begin
  FTypeNames.Assign(Value);
end;

{ FDropList }

procedure TDropList.WndProc(var Msg: TMessage);
var
  pt: TPoint;
begin
  // end display of listbox when clicked outside listbox
  if msg.msg = CM_CANCELMODE then
  begin
    GetCursorPos(pt);
    pt := ScreenToClient(pt);
    if not PtInRect(Rect(0,-20,Width,Height),pt) then
    begin
      (Parent as TAdvStringGrid).DoFilterClose((Parent as TAdvStringGrid).FilterColumn);
      (Parent as TAdvStringGrid).FilterColumn := -1;
      Visible := false;
    end;
  end;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TDropList.KeyPress(var Key: Char);
begin
  inherited;
  if Key = #13 then
  begin
    Visible := False;
    if Assigned(FOnSelect) then
      FOnSelect(Self,ItemIndex);
  end;
end;

//------------------------------------------------------------------------------

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

  Visible := False;
  if Assigned(FOnSelect) then
    FOnSelect(Self,ItemIndex);
end;


{ FDropList }

procedure TDropCheckList.WndProc(var Msg: TMessage);
var
  pt: TPoint;
begin
  // end display of listbox when clicked outside listbox
  if msg.msg = CM_CANCELMODE then
  begin
    GetCursorPos(pt);
    pt := ScreenToClient(pt);
    if not PtInRect(Rect(0,0,Width,Height),pt) then
    begin
      (Parent as TAdvStringGrid).DoFilterClose((Parent as TAdvStringGrid).FilterColumn);
      (Parent as TAdvStringGrid).FilterColumn := -1;
      Visible := false;
    end;
  end;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TDropCheckList.KeyPress(var Key: Char);
begin
  inherited;
  {
  if Key = #13 then
  begin
    Visible := False;
    if Assigned(FOnSelect) then
      FOnSelect(Self,ItemIndex);
  end;
  }
end;

//------------------------------------------------------------------------------

procedure TDropCheckList.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;
  {
  Visible := False;
  if Assigned(FOnSelect) then
    FOnSelect(Self,ItemIndex);
  }
end;

procedure TDropCheckList.ClickCheck;
begin
  if Assigned(FOnSelect) then
    FOnSelect(Self,ItemIndex);
end;

//------------------------------------------------------------------------------

{ TNoActiveForm }

procedure TNoActiveForm.WMActivate(var Message: TWMActivate);
begin
  inherited;
  message.Result := 1;
end;

procedure TNoActiveForm.WMMouseActivate(var msg: TWMMouseActivate);
begin
  inherited;
  msg.result := MA_NOACTIVATE;
end;

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

  with Params do
  begin
    Style := WS_POPUP;
    if not FEnabled then
      Style := Style or WS_DISABLED or WS_BORDER;
    WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  end;
end;

//------------------------------------------------------------------------------


{ TScrollControl }

constructor TScrollControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FColor := clSilver;
  FScrollWidth := 4;
  FDirection := sdVertical;
end;

function TScrollControl.Grid: TAdvStringGrid;
begin
  Result := nil;
  if Assigned(Parent) and (Parent is TAdvStringGrid) then
    Result := (Parent as TAdvStringGrid);
end;

procedure TScrollControl.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  grd: TAdvStringGrid;
  delta,nr: integer;

begin
  inherited;
  grd := Grid;
  if Assigned(grd) and FDownOnScroller then
  begin
    if Direction = sdVertical then
    begin
      delta := Y - FDownPos;
      nr := FDownRow + Round(delta / (Height - grd.RowHeights[0]) * grd.RowCount);
      grd.TopRow := Max(grd.FixedRows, Min(nr, grd.RowCount - grd.VisibleRowCount));
    end
    else
    begin
      delta := X - FDownPos;
      nr := FDownRow + Round(delta / (Width - grd.ColWidths[0]) * grd.ColCount);
      grd.LeftCol := Max(grd.FixedCols, Min(nr, grd.ColCount - grd.VisibleColCount));
    end;
  end;
end;

procedure TScrollControl.MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);
var
  grd: TAdvStringGrid;
  APos,ASize: integer;
begin
  inherited;

  grd := Grid;
  if Assigned(grd) then
  begin
    GetScrollPos(APos, ASize);

    if Direction = sdVertical then
    begin
      if (Y >= APos) and (Y <= APos + ASize) then
      begin
        FDownOnScroller := true;
        FDownPos := Y;
        FDownRow := grd.TopRow;
      end
      else
      begin
        if Y < APos then
          grd.TopRow := Max(grd.FixedRows, grd.TopRow - grd.VisibleRowCount)
        else
          grd.TopRow := Min(grd.TopRow + grd.VisibleRowCount, grd.RowCount - grd.VisibleRowCount);
      end;
    end
    else
    begin
      if (X >= APos) and (X <= APos + ASize) then
      begin
        FDownOnScroller := true;
        FDownPos := X;
        FDownRow := grd.LeftCol;
      end
      else
      begin
        if X < APos then
          grd.LeftCol := Max(grd.FixedCols, grd.LeftCol - grd.VisibleColCount)
        else
          grd.LeftCol := Min(grd.LeftCol + grd.VisibleColCount, grd.ColCount - grd.VisibleColCount);
      end;
    end;
  end;
end;

procedure TScrollControl.MouseUp(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);
begin
  inherited;
  FDownOnScroller := false;
end;

function TScrollControl.GetScrollSize: integer;
var
  i: integer;
  grd: TAdvStringGrid;
begin
  Result := 0;

  grd := Grid;

  if Assigned(grd) then
  begin
    if FDirection = sdVertical then
    begin
      Result := Height;
      for i := 1 to grd.FixedRows do
        Result := Result - grd.RowHeights[i - 1];

      for i := 1 to grd.FixedFooters do
        Result := Result - grd.RowHeights[grd.RowCount - i];
    end
    else
    begin
      Result := Width;

      for i := 1 to grd.FixedCols do
        Result := Result - grd.ColWidths[i - 1];

      for i := 1 to grd.FixedFooters do
        Result := Result - grd.ColWidths[grd.ColCount - i];
    end;
  end;
end;

function TScrollControl.GetScrollOffset: integer;
var
  grd: TAdvStringGrid;
  i: integer;
begin
  grd := Grid;

  Result := 0;

  if Assigned(grd) then
  begin
    if FDirection = sdVertical then
    begin
      for i := 1 to grd.FixedRows do
        Result := Result + grd.RowHeights[i - 1];
    end
    else
    begin
      for i := 1 to grd.FixedCols do
        Result := Result + grd.ColWidths[i - 1];
    end;
  end;
end;

procedure TScrollControl.GetScrollPos(var APos,ASize: integer);
var
  grd: TAdvStringGrid;
  sz: integer;
  perc,stop: double;
begin
  APos := 0;
  ASize := 0;

  grd := Grid;

  if Assigned(grd) then
  begin
    sz := GetScrollSize;

    if FDirection = sdVertical then
    begin
      perc := grd.VisibleRowCount / Max(1,grd.RowCount);
      stop := (grd.TopRow - grd.FixedRows) / Max(1,grd.RowCount - grd.FixedRows);
    end
    else
    begin
      perc := grd.VisibleColCount / Max(1,grd.ColCount);
      stop := (grd.LeftCol - grd.FixedCols) / Max(1,grd.ColCount - grd.FixedCols);
    end;

    APos := round(stop * sz) + GetScrollOffset;
    ASize := round(perc * sz);

    if ASize < 20 then
      ASize := 20;

    if FDirection = sdVertical then
    begin
      if APos + ASize > Height then
        APos := Height - ASize;
    end
    else
    begin
      if APos + ASize > Width then
        APos := Width - ASize;
    end;
  end;
end;

procedure TScrollControl.Paint;
var
  grd: TAdvStringGrid;
  hght,vstop: integer;
begin
  grd := Grid;

  if Assigned(grd) then
  begin
    GetScrollPos(vstop,hght);

    Canvas.Pen.Color := FColor;
    Canvas.Brush.Color := Canvas.Pen.Color;

    if FDirection = sdVertical then
    begin
      if grd.VisibleRowCount < grd.RowCount - grd.FixedRows then
        Canvas.Rectangle(0,vstop,FScrollWidth,vstop + hght)
    end
    else
    begin
      if grd.VisibleColCount < grd.ColCount - grd.FixedCols then
        Canvas.Rectangle(vstop, 0, vstop + hght, FScrollWidth);
    end;
  end;
end;

procedure TScrollControl.SetColor(const AValue: TColor);
begin
  if (AValue <> FColor) then
  begin
    FColor := AValue;
    Invalidate;
  end;
end;

procedure TScrollControl.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
//  Message.Result := 1;
  inherited;
end;

procedure TScrollControl.WMPaint(var Message: TWMPaint);
var
  DC, MemDC: HDC;
  MemBitmap, OldBitmap: HBITMAP;
  PS: TPaintStruct;
  {$IFNDEF DELPHI_UNICODE}
  dbl: boolean;
  {$ENDIF}
  p: TPoint;
  i: integer;
begin
  if Assigned(Parent) then
  begin
    DC := Message.DC;
    if DC <> 0 then
    begin
      {$IFNDEF DELPHI_UNICODE}
      dbl := Parent.DoubleBuffered;
      Parent.DoubleBuffered := false;
      {$ENDIF}
      i := SaveDC(DC);
      p := ClientOrigin;
      Windows.ScreenToClient(Parent.Handle, p);
      p.x := -p.x;
      p.y := -p.y;
      MoveWindowOrg(DC, p.x, p.y);
      SendMessage(Parent.Handle, WM_ERASEBKGND, DC, 0);
      SendMessage(Parent.Handle, WM_PAINT, DC, 0);
      //if (Parent is TAdvStringGrid) then
      //  (Parent as TAdvStringGrid).PaintCtrls(DC, nil);
      RestoreDC(DC, i);
      {$IFNDEF DELPHI_UNICODE}
      Parent.DoubleBuffered := dbl;
      {$ENDIF}
    end;
  end;

  if not FDoubleBuffered or (Message.DC <> 0) then
  begin
    if not (csCustomPaint in ControlState) and (ControlCount = 0) then
      inherited
    else
      PaintHandler(Message);
  end
  else
  begin
    DC := GetDC(0);
    MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
    ReleaseDC(0, DC);
    MemDC := CreateCompatibleDC(0);
    OldBitmap := SelectObject(MemDC, MemBitmap);
    try
      DC := BeginPaint(Handle, PS);
      Perform(WM_ERASEBKGND, MemDC, MemDC);
      Message.DC := MemDC;
      WMPaint(Message);
      Message.DC := 0;
      BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY);
      EndPaint(Handle, PS);
    finally
      SelectObject(MemDC, OldBitmap);
      DeleteDC(MemDC);
      DeleteObject(MemBitmap);
    end;
  end;
end;

{ TColorSetting }

procedure TColorSetting.Assign(Source: TPersistent);
begin
  if (Source is TColorSetting) then
  begin
    FTextColor := (Source as TColorSetting).TextColor;
    FBkgColor := (Source as TColorSetting).BkgColor;
  end;
end;

procedure TColorSetting.Changed;
begin
  if Assigned(OnChange) then
    OnChange(Self);
end;

constructor TColorSetting.Create;
begin
  inherited;
  FTextColor := clNone;
  FBkgColor := clNone;
end;

procedure TColorSetting.SetBkgColor(const Value: TColor);
begin
  if (FBkgColor <> Value) then
  begin
    FBkgColor := Value;
    Changed;
  end;
end;

procedure TColorSetting.SetTextColor(const Value: TColor);
begin
  if (FTextColor <> Value) then
  begin
    FTextColor := Value;
    Changed;
  end;
end;


{ TAutoColor }

procedure TAutoColor.Assign(Source: TPersistent);
begin
  if (Source is TAutoColor) then
  begin
    FNegativeNumber.Assign((Source as TAutoColor).NegativeNumber);
    FPositiveNumber.Assign((Source as TAutoColor).PositiveNumber);
  end;
end;

procedure TAutoColor.Changed;
begin
  if Assigned(OnChange) then
    OnChange(Self);
end;

function TAutoColor.ColorsDefined: boolean;
begin
  Result := (NegativeNumber.TextColor <> clNone) or
            (NegativeNumber.BkgColor <> clNone) or
            (PositiveNumber.TextColor <> clNone) or
            (PositiveNumber.BkgColor <> clNone);
end;

constructor TAutoColor.Create;
begin
  inherited;
  FNegativeNumber := TColorSetting.Create;
  FNegativeNumber.OnChange := ValueChanged;

  FPositiveNumber := TColorSetting.Create;
  FPositiveNumber.OnChange := ValueChanged;
end;

destructor TAutoColor.Destroy;
begin
  FNegativeNumber.Free;
  FPositiveNumber.Free;
  inherited;
end;

procedure TAutoColor.SetNegativeNumber(const Value: TColorSetting);
begin
  FNegativeNumber.Assign(Value);
end;

procedure TAutoColor.SetPositiveNumber(const Value: TColorSetting);
begin
  FPositiveNumber.Assign(Value);
end;

procedure TAutoColor.ValueChanged(Sender: TObject);
begin
  Changed;
end;

{ THeaderDragButton }

procedure THeaderDragButton.CreateParams(var Params: TCreateParams);
begin
  inherited;
  with Params do
  begin
    Style := WS_POPUP or WS_BORDER;
    WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  end;
  Color := clBtnFace;
end;

procedure THeaderDragButton.Paint;
var
  r: TRect;
  v, a, fa, ah: string;
  xs, ys, ml, hl: Integer;
  cid, cv, ct: string;
  cr, hr: TRect;
begin
  r := GetClientRect;

  if Assigned(FGrid) then
    FGrid.PaintCellExt(Canvas, 0, 0, r, []);

  SetBkMode(Canvas.handle,TRANSPARENT);

  if Pos('</',FCaption) > 0 then
  begin
    HTMLDrawEx(Canvas,FCaption, r, FGrid.GridImages, 2, 2, -1, -1, 2, false, false, false, false, false, false, false, false, '', 1.0, clBlue, clNone, clNone,
      clGray, v, a, fa, ah, xs, ys, hl, ml, hr, cr, cid, cv, ct, nil, nil, Handle)
  end
  else
    DrawTextEx(Canvas.handle,pchar(FCaption),Length(fCaption),r,DT_CENTER or DT_VCENTER or DT_END_ELLIPSIS or DT_SINGLELINE,nil);
end;



{ THoverButtonsCollectionItem }

procedure THoverButtonsCollectionItem.Assign(Source: TPersistent);
begin
  if (Source is THoverButtonsCollectionItem) then
  begin
    FTag := (Source as THoverButtonsCollectionItem).Tag;
    FFlat := (Source as THoverButtonsCollectionItem).Flat;
    FEnabled := (Source as THoverButtonsCollectionItem).Enabled;
    FCaption := (Source as THoverButtonsCollectionItem).Caption;
    FHint := (Source as THoverButtonsCollectionItem).Hint;
    FPicture.Assign((Source as THoverButtonsCollectionItem).Picture);
    FWidth := (Source as THoverButtonsCollectionItem).Width;
  end;
end;

constructor THoverButtonsCollectionItem.Create(Collection: TCollection);
begin
  inherited;
  FPicture := TPicture.Create;
  FEnabled := true;
  FFlat := false;
  FTag := 0;
end;

destructor THoverButtonsCollectionItem.Destroy;
begin
  FPicture.Free;
  inherited;
end;

procedure THoverButtonsCollectionItem.SetPicture(const Value: TPicture);
begin
  FPicture.Assign(Value);
end;

{ THoverButtonsCollection }

function THoverButtonsCollection.Add: THoverButtonsCollectionItem;
begin
  Result := THoverButtonsCollectionItem(inherited Add);
end;

constructor THoverButtonsCollection.Create(AOwner: TPersistent);
begin
  inherited Create(AOwner, THoverButtonsCollectionItem);
end;

function THoverButtonsCollection.GetItems(
  Index: integer): THoverButtonsCollectionItem;
begin
  Result := THoverButtonsCollectionItem(inherited Items[Index]);
end;

function THoverButtonsCollection.Insert(
  Index: integer): THoverButtonsCollectionItem;
begin
  Result := THoverButtonsCollectionItem(inherited Insert(Index));
end;

procedure THoverButtonsCollection.SetItems(Index: integer;
  const Value: THoverButtonsCollectionItem);
begin
  inherited Items[Index] := Value;
end;

{ THoverButtons }

procedure THoverButtons.Assign(Source: TPersistent);
begin
  if (Source is THoverButtons) then
  begin
    FEnabled := (Source as THoverButtons).Enabled;
    FButtons.Assign((Source as THoverButtons).Buttons);
    FColumn := (Source as THoverButtons).Column;
    FPosition := (Source as THoverButtons).Position;
    FRows := (Source as THoverButtons).Rows;
    FMoveActiveRow := (Source as THoverButtons).MoveActiveRow;
  end;
end;

constructor THoverButtons.Create(AOwner: TPersistent);
begin
  inherited Create;
  FOwner := AOwner;
  FRows := hrNormal;
  FButtons := THoverButtonsCollection.Create(Self);
  FMoveActiveRow := true;
end;

destructor THoverButtons.Destroy;
begin
  FButtons.Free;
  inherited;
end;

function THoverButtons.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure THoverButtons.SetButtons(const Value: THoverButtonsCollection);
begin
  FButtons.Assign(Value);
end;


initialization
{$IFNDEF TMSDISABLEOLE}
  Initialize;
{$ENDIF}
  FocusGrid := nil;

  if MsgHook = 0 then
    MsgHook := SetWindowsHookEx(WH_CALLWNDPROC, @MsgHookProc, 0, GetCurrentThreadID);


  {$IFDEF ISDELPHI}
  try
    RegisterClass(TAdvStringGrid);

    RegisterClass(TDropList);
    RegisterClass(TArrowWindow);
    RegisterClass(TGridCombo);
    RegisterClass(TGridSpin);
    RegisterClass(TGridTransEdit);
    RegisterClass(TGridTransCombo);
    RegisterClass(TGridCheckBox);
    RegisterClass(TGridEditBtn);
    RegisterClass(TGridDateTimePicker);
    RegisterClass(TGridUnitEditBtn);
    RegisterClass(TGridTrackBarDropDown);
    RegisterClass(TGridMemoDropDown);
    RegisterClass(TGridCalculatorDropDown);
    RegisterClass(TGridTimePickerDropDown);
    RegisterClass(TGridDetailPickerDropDown);
    RegisterClass(TGridGridDropDown);
    RegisterClass(TGridColorDropDown);
    RegisterClass(TGridImageDropDown);
    RegisterClass(TGridButton);
    RegisterClass(TGridDatePicker);
    RegisterClass(THeaderDragButton);
    RegisterClass(TControlEdit);
    RegisterClass(TControlCombo);
    RegisterClass(TScrollBar);
    RegisterClass(TAdvRichEdit);
    RegisterClass(TFooterPanel);
    RegisterClass(TSearchPanel);
  except
  end;
  {$ENDIF}

  ComCtrlOk := GetfileVersion(comctrl) >= $00040046;

  CF_GRIDCELLS := RegisterClipboardFormat('TAdvStringGrid Cells');
  WM_GRIDEDITDONE := RegisterWindowMessage('GridEditDone');
  WM_GRIDEDITSHOW := RegisterWindowMessage('GridEditShow');
  WM_EDITPROP := RegisterWindowMessage('GridEditProp');
  WM_DTPSHIFTFOCUS := RegisterWindowMessage('DTPShiftFocus');

finalization
{$IFNDEF TMSDISABLEOLE}
  OleUninitialize;
{$ENDIF}
  if MsgHook <> 0 then
  begin
    UnhookWindowsHookEx(MsgHook);
  end;
  MsgHook := 0;

end.
