{***************************************************************************}
{ TAdvStringGrid component                                                  }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 1996-2008                                          }
{            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.                                      }
{***************************************************************************}

// revision history                        
// 2.8.4.1 : changed LoadFromStream to allow loading multiple grids from same stream
//         : improved drag & drop handling from readonly drag&drop sources
// 2.8.4.2 : change in .Paint procedure for inplace editor painting with TDBAdvGrid
// 2.8.5.0 : support for masked & password HTML form controls
//         : improved MouseActions.RowSelect handling with scrolling
//         : improved PasteSelectionFromClipboard procedure
//         : improved drag&drop with Internet Explorer
//         : improved HTML forms handling with tab key navigation
//         : option to do column calculations in floating footer taking hidden rows in account or not
//         : built-in datetime and time sort format support
// 2.8.5.1 : Improved tab handling of custom inplace edit controls
// 2.8.6.0 : OnGetDisplWideText event added
// 2.8.7.0 : Improvements in SaveToDoc, SaveToXLS
// 2.8.7.1 : Improved readonly cell handling with merged cells
// 2.8.7.2 : Improved column sizing with column stretching enabled in scrolled grid
// 2.8.7.3 : Fixed Navigation.AppendOnArrowDown with floating footer visible
// 2.8.7.4 : Fixed RemoveRows() combined with use of CellControls
//         : Fixed RangeSelectAndEdit issue with hidden columns and F2 handling
//         : Fixed issue with original cell value restore upon ESC
// 2.8.7.5 : Fixed Ctrl-A select all with disjunct row selection mode
// 2.8.8.0 : Added MouseActions.WheelIncrement property
//           Added MouseActions.WheelAction property
// 2.8.8.1 : Fixed issue with RemoveRows() causing TopRow to become negative
//           Fix for flicker during painting with FixedRightCols > 0
//           Fix for AlwaysEdit mode with edButton inplace editor type
//           Fix for cell validation & floating footer recalculation
//           Fix for keydown event in combination with floating footer
// 2.8.8.2 : Fix for unicode cells hint
//         : Added functions TotalRowCount, TotalColCount
// 2.8.8.3 : Fix for printing issue
// 2.8.8.4 : Fix for mousewheel scrolling
// 2.8.8.5 : Improvements for unicode formulas in TAdvSpreadGrid
// 2.8.8.6 : Improvements for unicode formulas in TAdvSpreadGrid
// 2.8.8.7 : Fix for Unicode stream persistence

// v3.0    : see what's new file for details about enhancements
// 3.0.0.1 : Changed Abort handling in print routine
//         : Fixed issue with goRowSelect range select and checkboxes
// 3.0.0.2 : Fixed issue with SelectionTextColor for fixed right columns
//         : Fixed issue with column & row moving in small grids
// 3.0.0.3 : Improved balloon hint handling
//         : Fixed issue with virtual cell editing
//         : Fixed issue with wordwrap initialization for individual cells
//         : Fixed issue with AutoNumAlign
//         : Added SearchFooter.AutoSearch property
//         : Fixed issue with incorrect OnExit event during inplace editing
//         : Fixed issue with hidden columns & unicode editing
//         : Fixed memory leak issue with RowColor[] property
//         : Fix in LoadFromXML for XML files with data only in attributes
// 3.0.0.4 : Fix Alignment property handling
// 3.0.0.5 : Fix text in node cell issue
// 3.0.0.6 : Fix in BidiMode RightToLeft footer paint
//         : Improved HTML control editing
//         : Fix in parent node find function
// 3.0.0.7 : Improvement with indent for drawing text in cells with nodes
// 3.0.0.8 : Fixed issue with progressbar printing
//         : Fixed issue with background display on grids with FixedCols = 0
//         : Fixed clipboard event sequence inconsistency
//         : Fixed issue with OLE drag & drop + disjunct row selection in same grid
//         : Fixed issue with SelectionTextColor in combination with hidden columns
//         : SaveToAscii, SaveToFixed use SaveHiddenCells property now
// 3.0.0.9 : Improved SelectOnRightClick with merged cells
// 3.1.0.0 : New DragScrollOptions property
//         : New horiz. scrolling during OLE drag & drop
//         : Fixed issue with SaveToDoc()
//         : SubGroup improvement
//         : Improvement with DirectEdit & readonly cells & clipboard handling
//         : New OnCanClickCell event
//         : New TAdvGridRTFIO component for rich text export
//         : Fix for DirectEdit mode editing with merged cells
// 3.1.1.0 : New: OnDateTimeChange event added
//         : Fixed issue with rich edit inplace editing & size while typing
//         : Improved dropdown button for combobox appearance
//         : Fixed issue with printing with hidden columns, fixed col = 0,
// 3.1.1.1 : Fixed issue with row remove & fixed merged rows
//         : Fixed issue with SelectOnRightClick & disjunct row selection
// 3.1.1.2 : Fixed issue with node contract & fixed merged rows
//         : Improved DragScrollOptions.Active -> default property value
// 3.2.0.0 : New: ControlLook.CheckAlwaysActive, ControlLook.RadioAlwaysActive added
//         : New: edUniMemo inplace editor
//         : SearchFooter.SearchActiveColumnOnly added
//         : SearchFooter.SearchColumn property added
// 3.2.0.1 : Fix in LoadFromXML
//         : Fix in edUnitEditBtn inplace editor with ESC key
// 3.2.0.2 : Fix for paste in normal cell editor
//         : Fix for scroll on visible inplace editor issue
// 3.2.0.3 : Fix for merged cell editing
// 3.2.0.4 : Fix for paste in standard inplace editor
// 3.2.0.5 : Fix for use of OnGetEditText with normal inplace editor
//         : Fix issue with fixed cells for grouping & hidden columns
//         : Fix for autosizecolumns with float formatted cells
//         : Fix for OnExit event call with auto advance editbtn editor
//         : Fix for floatingfooter background color synchronisation
//         : Fix issue with OnPrintSetRowHeight default height
//         : Fix node tree drawing issue on last row of grid
// 3.3.0.0 : New: OnEditChange event triggered for non default inplace editor types edComboEdit, edSpinEdit, edEditBtn
//         : New: CSV pager component
//         : Fixed: issue with RemoveCols for grid with hidden columns
//         : Fixed: issue with cell validation & arrow keys
// 3.3.0.1 : Fixed: issue with UnSort
// 3.3.0.2 : Property AllWideCells[] added
//         : Improved sort mode ssAlphaNumericNoCase
//         : SetTheme public function added
// 3.3.0.3 : Fixed issue with tabbed editing with merged cells
//         : Fixed issue with scrollinview on last row
//         : Fixed issue with editing in partially visible merged cells
// 3.3.0.4 : Fixed issue with RowIndicator transparent drawing
//         : Removed limitation to set BtnEdit.ButtonWidth smaller than 15
//         : Improvement in LoadFromXLS
//         : Fixed issue with fixedfooters & grouping
// 3.3.0.5 : Fix for clipped progress bar drawing
// 3.3.1.0 : Added events OnSaveCell, OnLoadCell
//         : Fixed issue with EditLink on multiple form instances
//         : Fixed issue with SelectOnRightClick for click on fixed cells
// 3.3.1.1 : Improved node drawing
//         : Fixed issue with loading from XML & special characters
//         : Fixed small painting issue with active cells
//         : Fixed ShowModified applies for checkbox modifications too now
//         : Improved OnGetFloatFormat event for decimal number formatting
//         : Improved ScrollProportional behaviour during wheel zoom
//         : Fixed issue with goTabs for fixed cells inside grid
// 3.3.1.2 : Fixed issue with ActiveCellShow and zero fixed columns and/or rows
//         : Improved tab handling with fixed & readonly columns
// 3.3.1.3 : Fix for paste handling in edit control in grid with hidden columns
// 3.3.2.0 : Filter support added for ignoring logic symbols between quotes
//         : Fixed issue with selection of cells after paste of cell block
//         : New: SearchFooter.Font property
//         : Improved: editing/cell selection with SearchFooter visible
//         : Fixed: issue with EditorEnabled & backspace key in inplace spin edit
// 3.3.2.1 : Improved floating point detection method
// 3.3.2.2 : Improved AutoSizeRow with virtual checkboxes
// 3.3.2.3 : Improved fixed column sizing cursor behaviour
// 3.3.2.3 : Improved Tab handling for readonly grids
//         : Fixed issue with column stretching and proportional scrollbars
// 3.3.2.4 : Fixed issue with OnComboChange for Unicode combobox inplace editor
//         : Fixed issue with AutoSizeRow with Unicode cells
// 3.3.2.5 : Fixed issue with date inplace editor height for large cells
//         : Improved : LoadFromXML uses now LoadCell virtual proc.
//         : Fixed issue with column index in combochange events for hidden columns
//         : Fixed issue for very small row heights with PrintSettings.NoAutoSizeRows = true
//         : Fixed issue with custom checkbox control painting for Bidi RightToLeft mode
//         : Improved : auto tab advance in scenarios with custom fixed, readonly cells
// 3.3.2.6 : Fixed : caret display issue for normal inplace editors
//         : Fixed : issue with ShowSelection = false and disjunct row select during mousedown
//         : Fixed : issue with checkbox click with grid with goRowSelect = true
// 3.3.2.7 : Fixed : CellsLoaded called after LoadFromXML
//         : Fixed : issue with column stretch, horiz. prop. scrollbar
//         : Fixed : KeepHorizScroll with SelectOnRightClick issue
//         : Fixed : issue with RemoveSelectedRows in non disjunct row selection mode
//         : Fixed : issue with PreciseCheckBoxCheck & hidden columns
// 3.3.2.8 : Fixed : issue with MemoEditLink memo positioning in Delphi 2005 or higher
//         : Fixed : issue with ScrollInView for grid without fixed rows
//         : Fixed : issue with KeepHorizScroll and Indexed sorting
//         : Fixed : issue with unicode inplace editing with arrow keys
//         : Fixed : issue with coordinate in OnCanEditCell for F2 key when hidden columns are used
// 3.3.2.9 : Fixed : fix for TAdvColumnGrid AdvanceOnEnter with hidden columns
//         : Fixed : issue with SizeWhileTyping
//         : Fixed : OnSetEditText invoking from normal inplace editor
//         : Fixed : CursorWalkEditor behaviour
//         : Fixed : cell property initialization when grid.Bands is used
//         : Fixed : issue with grid.EditBtn.OnKeyDown
//         : Fixed : issue with disjunctrowselect & editing for keyboard selection

// 3.4.0.0 : New : AddCheckBoxColumn, RemoveCheckBoxColumn procedures added
//         : New : property Gradients[col,row] to set gradient direction
//         : New : public property LoadFirstRow added to control loading first line with LoadFromCSV(), InsertFromCSV()
//         : New : method grid.SortSettings.Remove to immediately remove sort indicators
//         : New : OfficeHint property
//         : New : Office 2007 Luna & Obsidian styles added
//         : New : AddAdvProgress, RemoveAdvProgress & grid.ProgressAppearance for adding sophisticated progress bars in grid
//         : New : SelectedRowCount, SelectedRow[i]: boolean;
//         : Improved : keyboard scroll behaviour with SearchFooter visible
//         : Improved : ActiveCellShow is automatically updated when programmatically changing Selection
//         : Improved : RowModified is persisted when grid is sorted
//         : Improved : cleanup of cell objects in case RowCount,ColCount changes programmatically
//         : Improved : disjunct cell keyboard interface : ctrl - space + space to select
//         : Improved : MouseActions.RangeSelectAndEdit  behaviour
// 3.4.0.1 : Fixed : issue with cell controls on fixed rows, fixed cols
//         : Fixed : issue with Navigation.AllowCtrlEnter = false
//         : Fixed : issue with virtual cells & AllCells[] access
// 3.4.0.2 : Fixed : issue with gradient selection colors and gradient cell colors
//         : Fixed : issue in function RowAvg()
// 3.4.0.3 : Fixed : issue with OnBeforeClipboardPasteCell
//         : Fixed : issue with painting for merged group headers
//         : Improved : grid.Invalidate now also automatically invalidates the floating footer
//         : Fixed : issue with reparenting with inplace editor
//         : Fixed : issue with AppendToDoc
//         : Fixed : issue with inplace combobox in classic Windows style for BidiMode bdRightToLeft
// 3.4.0.4 : Fixed : issue with OnGetDisplWideText
//         : Fixed : print column width calculation with use of OnGetFloatFormat
//         : Improved : node position for painting
//         : Improved : group summary handling
// 3.4.0.5 : Fixed : parameter order in OnGetWordWrap
//         : Fixed : issue with OnEllipsClick for edButton editor type
// 3.4.0.6 : Fixed : issue with insert/remove rows and ShowModified
// 3.4.0.7 : Fixed : issue with editing when AlwaysEdit = true & AllowCtrlEnter = false
//         : Fixed : issue with goTabs and tab advance with readonly cells
//         : Fixed : issue with Navigation.TabToNextAtEnd
//         : Fixed : issue when application active window changes when inplace editor is active
// 3.4.1.0 : New : support for printing radiobuttons added
// 3.4.1.1 : Fixed : issue with RemoveSelectedRows and disjunct selection + persistent row selection
// 3.4.2.0 : New : Events OnGetEditWideText, OnSetEditWideText added
// 3.4.2.1 : Fixed : hide of spin edit with blank text
// 3.4.2.2 : Fixed : issue with disjunct column selection & hidden columns
//         : Improved : handling KeepHorizScroll
//         : Improved : single select selection behaviour with merged cells
// 3.4.3.0 : New : UpdateEditMode method added to fix issue with programmatically changing goEditing while grid has focus
// 3.4.4.0 : New : OnRowDisjunctSelected event added
//         : Fixed : issue with scrolling with SearchFooter visible
// 3.4.4.1 : Fixed : issue with Navigation.AllowCtrlEnter = false
// 3.4.5.0 : New : property AllGridCells[] added to get real grid cell value of hidden & visible cells
// 3.4.5.1 : Fixed : issue with OnGetCellPrintBorder and right-side borders
//         : Fixed : issue with MouseActions.RangeSelectAndEdit = true for non editable grids
//         : Fixed : issue with column moving & visible floating footer
//         : Improved : drag & drop interface for disjunct selected rows
//         : Fixed : Issue with SaveRectToBinStream
// 3.4.6.0 : New : property FloatingFooter.BorderColor added
// 3.4.6.1 : Fixed : issue with DirectEdit & Merged cells
// 3.4.6.2 : Fixed : issue with AdvanceOnEnter, checkboxes and OnCanEdit event
//         : Fixed : issue with KeepHorizScroll, FixedFooters, goRowSelect mode
//         : Improved : performance of RemoveRows
//         : Fixed : issue with AlwaysEdit = true and readonly cells
//         : Fixed : issue with CursorWalkEditor & cell merging & static edits
//         : Improved : drawing speed
//         : Fixed : issue with unicode editing
//         : Fixed : issue with GroupCalc for grid with contracted nodes
//         : Fixed : issue with copy & paste for float cells
// 3.4.6.3 : Fixed : issue with disjunctrowselect
// 3.4.7.0 : New : Office2007 Silver style support added
// 3.4.7.1 : Fixed : issue with SaveFixedCells & SaveToAscii
// 3.4.7.2 : Fixed : issue with dbl click & MouseActions.RangeSelectAndEdit = true
// 3.4.8.0 : New : added support to sort cells with scientific notation, ie. X,YE+Z
// 3.4.8.1 : Fixed : background color issue with checkboxes on gradient grid
// 3.4.8.2 : Fixed : issue with RangeSelectAndEdit and popup menus
//         : Fixed : issue with client-alignment, stretchcolumn
// 3.4.8.3 : Improved : SmartClipboard resize with editing enabled
//         : Improved : scientific type detection
//         : Improved : AdvanceOnEnter, OnCellValidate behaviour with custom inplace editors
//         : Improved : fnAutoGoto search in disjunct row select mode
// 3.4.8.5 : New : filter based on cells with stripped HTML tags
//         : Fixed : issue with RemoveChildRow()
//         : Improved : AdvGridReplaceDialog shows modified rows when enabled
// 3.4.8.6 : Fixed : issue with Undo for data checkboxes
//         : Fixed : issue with combination of RangeSelectAndEdit, goColMoving = true, SelectionResizer
// 3.4.8.7 : Fixed : issue with goEditing
// 3.4.8.8 : Fixed : issue with center alignment & haBeforeText, haAfterText images
//         : Improved : added support for export grids with empty cells to XML
//         : Fixed : issue with InsertRows & CellControls
//         : Improved : behaviour of OnEditChange
// 3.4.8.9 : New : Select method added to programmatically perform select on the default cell
//         : Fixed : issue with shift column selection
// 3.4.8.10: Fixed : issue with scroll & searchfooter visible
//         : Fixed : issue with rangeselectandedit=true and mouse dbl click
//         : Fixed : issue with row sizing & nodes
//         : Fixed : small painting issue with nodes
//         : Fixed : issue with cell controls & grid resize
// 3.4.8.11: Fixed : issue with ActiveRowColor & unicode text
//         : Fixed : issue with HintShowSizing and multimonitor use
//         : Fixed : issue with goTabs & edUniMemo editor
// 3.4.8.12: Fixed : issue with OnClickCell with goColSizing enabled
// 3.4.8.13: Fixed : issue with column parameter for grid with hidden columns in OnCanEditCell
//         : Fixed : issue with CellControls use and hide/unhide rows
// 3.4.8.14: Improved : vertical scroll handling with floating footer

// 3.5.0.0 : New : methods ColumnStatesToString, StringToColumnStates
//         : New : methods ColumnPosition, ColumnAtPosition
//         : New : OnEllipsClick event triggered on F4 key in edEditBtn editor
//         : New : fcCalculated setting for filter data to filter in TAdvSpreadGrid on results
//         : New : OnEditCellDone event added
//         : New : Extra MaxRows parameter for functions LoadFromCSV, InsertFromCSV
//         : New : OnDatePickerCloseUp event added
//         : New : AutoFitColumns added
// 3.5.0.1 : Fixed : issue with hidden columns and tracking column moving
//         : Fixed : issue with OnEditCellDone with advance edit
//         : Improved : AutoFitColumns
// 3.5.1.0 : Improved : OnClick, OnClickCell events triggered for click on footerpanel
// 3.5.1.1 : Improved : index sort indicator drawing
//         : Fixed : issue with OnCanEdit and button in cell
// 3.5.2.0 : New : OnSearchEditChanged event added
//         : Fixed : issue with Tab on datepicker inplace edit
// 3.5.2.1 : Fixed : isues with tab key and OnCellValidate
// 3.5.2.2 : Fixed : issue with AllowFmtClipboard & AllowClipboardRowGrow,AllowClipboardColGrow
//         : Improved : sequence of OnRowMoved event triggering
//         : Fixed : issue with multicell text Paste in VCL.NET
// 3.5.2.3 : Fixed : issue with printing
//         : Improved : OnCellClick triggered when clicked on node cells outside node
// 3.5.3.0 : New : exposed MatchCase checkbox in search footer via Grid.SearchPanel.MatchCase
// 3.5.3.1 : Fixed : issue with unicode inplace editors
//         : Fixed : issue with calling BeginDrag from OnMouseMove
// 3.5.4.0 : New : property SortSettings.SortOnVirtualCells added
//         : New : TAdvGridUndoRedo.OnUndo, OnRedo events added
//         : New : TAdvGridFindDialog.OnCellFound event added
//         : New : C++Builder 2007 support
//         : Fixed : issue with OnGridHint with scrolled FloatingFooter
//         : Fixed : issue with subgrouping in special cases
//         : Fixed : issue with OnCellsChanged event for unicode inplace memo editing
//         : Fixed : issue with cell properties on floating footer row with no column calc
//         : Fixed : issue with OnClick in readonly grid
// 3.5.4.1 : Fixed : issue with esPopup external editor type
// 3.5.5.0 : New : Ctrl-F with searchfooter activated sets focus to search edit
// 3.5.5.1 : Fixed : issue with cellcontrols & swaprows, moverow, insertrow, removerow
// 3.5.6.0 : New : setting SelectionTextColor = clNone preserves font color for selected cells
//         : Fixed : issue with shortcut keys and setting AutoGotoWhenSorted
// 3.5.6.1 : Fixed : issue with OnRowChanging for tab handling with read-only cells
// 3.5.6.2 : Improved : behavior with use of grid.Navigation.AdvanceOnEnter
//         : Fixed : issue with destructor when OLE drag & drop is used
//         : Fixed : issue with combination DisjunctCellSelect & ColSelect/RowSelect
//         : Fixed : issue with accessing checkbox state in hidden rows

// 3.6.0.0 : New : RemovedCheckRows method added
//         : New : default parameter added in AddCheckBoxColumn
//         : New : function IsChecked added
//         : New : Undo/Redo support for multi cell copy & paste
//         : New : ShowMaximized property added in TAdvPreviewDialog

// 3.6.0.1 : Improved : small improvement for right arrow in mode grid.Navigation.CursorWalkEditor = true
//         : Fixed : issue with summary lines & floating footer calculations with hidden rows
// 3.6.0.2 : Fixed : issue with readonly cells and button in cell / checkbox in cell
//           Fixed : issue with removing cell controls with hidden rows

// 4.0.0.0 : New : GroupCustomCalc method & OnGroupCalc event added
//         : New : UnSelectRows, UnSelectCols method added
//         : New : SaveWithRTF public property added
//         : New : SearchFooter.SearchMatchStart property added
//         : New : GotoCell() method added
//         : New : OnColumnSizing, OnRowSizing events added
//         : New : MaxRows & DoTrim default parameter on LoadFromFixed added
//         : New : Hover/down complex gradients on fixed rows
//         : New : Fixed row dropdown menu
//         : New : Automatic Group count display with Group count format
//         : New : Grouping.AutoSelectGroup, to automatically select all rows in a group by clicking the group header
//         : New : OnCustomStrToDate event added
//         : New : global grid Modified property added
//         : New : OnColumnSizing, OnRowSizing events
//         : New : MaxComboLength property added
//         : New : with goTabs, AdvanceInsert = true & TabToNextAtEnd = false, row is inserted on tab at last cell
//         : New : OnSearchFooterClose event added
//         : New : MouseActions.DirectComboClose, MouseActions.DirectDateClose properties added
//         : New : SelectionMirrorColor/SelectionMirrorColorTo added for Vista style gradients on selected cells
//         : New : Internal atScientific type added for auto text alignment / formatting / sorting
//         : New : Navigation.CursorWalkAlwaysEdit property added
//         : New : Navigation.LeftRightRowSelect property added 
//         : New : fnSelectedCells option added for Find function
//         : New : edDateTimeEdit editor type added
//         : New : exposed hilight button in searchfooter via grid.SearchPanel.HiliteButton
//         : New : event OnSearchFooterAction added
//         : New : CSV import dialog
//         : New : support for parenthesis in filter spec
//         : New : translucent cell display during column or row moving
//         : New : translucent cell display during drag & drop
//         : New : support for Unicode hints
//         : New : support for MaxLen attribute for HTML cell forms
//         : New : support for masked & password editors for HTML cell forms
//         : New : fnIncludeHiddenRows in Find parameters option added to search in rows hidden by nodes
//         : New : IgnoreColumns property for AutoSizeRows, Sort, Find control
//         : New : OnFooterCalc event added for custom footer calculations
//         : Improved : float spinedit inplace editor behaviour with Page Up/Down keys
//         : Improved : OnGetEditorProp also called from normal inplace editor
//         : Improved : ColumnSize.SynchWithGrid behavior
//         : Improved : HTML control drawing with XP themes
//         : Improced : scope option to search in selected cells added in TAdvGridFindDialog, TAdvGridReplaceDialog
//         : Improved : perform auto scroll when dropped over first row during OLE drag & drop
//         : Improved : RowModified[] can be used also when visible modified row indication is disabled
//         : Improved : LoadFromFixed handles out of order column indexes
//         : Fixed : issue with tab edit for special combinations of fixed cells
//         : Fixed : issue with OnButtonClick for fixed cells and FixedAsButtons = true
//         : Fixed : issue with AutoNumAlign and thousand separators
//         : Fixed : issue with getting checkbox state for data checkboxes with hidden rows
//         : Fixed : issue with Title attribute case sensitivity in hyperlinks on HTML formatted text
//         : Fixed : issue with clicking on header checkbox & sorting
//         : Fixed : issue with AddAdvProgress and Min,Max different from 0,100
//         : Fixed : issue with SortOnVirtualCells & custom sorting

// 4.0.0.1 : Fixed : issue with aborting printing from OnPrintStart
//         : Fixed : issue with RemoveSelectedRows & fixed footers
//         : Fixed : issue with autosizing rich text
// 4.0.0.2 : Fixed : issue with very small grid height and cell selection
//         : Fixed : issue with repaint with FixedRows = 0
//         : Fixed : issue with OnMouseDown for cells with nodes
// 4.0.0.3 : Fixed : issue with Subgrouping on groups with 1 item in last subgroup
//         : Fixed : issue with tab, editing & merged cells
//         : Fixed : issue with checkbox, hidden column & Navigation.Always = true
//         : Improved : OnGetEditorProp event called for edComboList & edComboEdit editor types for
//         :            combobox initialization in case grid.ControlLook.DropDownAlwaysVisible = true
//         : Fixed : particular issue with Unicode combobox inplace editor
// 4.0.0.4 : Fixed : issue with GetParentRow() with collapsed nodes
//         : Fixed : issue with searchpanel & filtered grid
//         : Fixed : issue with tab key & rare combination of readonly & merged cells
//         : Improved : search footer FindNext/FindPrevious scroll in view on found cells
// 4.0.1.0 : New : Navigation.MoveScrollOnly property added to always only perform scrolling and no selection change
//         :       when pressing Up/Down/Next/Prior/Home/End
// 4.0.1.1 : Fixed : issue with loading CSV files with empty last column
//         : Fixed : issue with GroupShowCount
//         : Fixed : issue with panning and WheelAction = waScroll
// 4.0.2.0 : Improved : AdvGridFindDialog.Dialog & AdvGridReplaceDialog.Dialog exposed
// 4.0.3.0 : New : public property grid.XMLEncoding to specify code table for XLM export
//         : Fixed : issue with node collapsing & cell selection
// 4.0.3.1 : Fixed : issue with OLE drag & drop with ShowCells & FixedRows > 1
// 4.0.4.0 : New : OnWideEllipsClick event added
// 4.0.4.1 : Fixed : issue with Unicode hint
// 4.0.4.2 : Fixed : issue with Hilight function
// 4.0.5.0 : New : OnOleDropURL event added, DragDropSettings.OleAcceptURLs added
//         : Fixed : issue with using SearchFooter and rows higher than grid height
// 4.0.5.1 : Fixed : issue with AutoGotoWhenSorted and hiding sorting
//         : Fixed : issue with AdvanceInsert & FloatingFooter
// 4.0.5.2 : Fixed : issue with cell highlighting and hidden columns
//         : Fixed : issue with disjunct cell selection & fixed cells
// 4.0.5.3 : Fixed : issue with OnDblClick event in combination with FixedRowAlways = true
// 4.0.5.4 : Fixed : issue with MouseActions.NoScrollOnPartialRow = true
//         : Fixed : issue with SelectedRowCount & merged cells
//         : Fixed : issue with AutoInsertRows when nodes are used
//         : Fixed : issue with CursorWalkEditor = true
// 4.0.6.0 : New : MouseActions.EditOnDblClickOnly property added
// 4.0.6.1 : Fixed : issue with MouseActions.SelectOnRightClick and OnSelectCell event
//         : Fixed : issue with OnSelectionChanged
//         : Fixed : OnClick issue in combination with OnCanEdit event handler
// 4.0.6.2 : Fixed : issue with printing radiobuttons
//         : Fixed : small issue with goTabs & goEditing in grid.Options
//         : Fixed : issue with cell controls and deleting rows
// 4.0.6.3 : Fixed : issue with row delete / row insert in grid with nodes
//         : Fixed : issue with stretch column and always visible vert. scrollbar
//         : Fixed : issue with OnSelectionChanged & disjunct row selection
//         : Improved : auto adapt line width for printout resolution
//         : Fixed : small issue with disjunct cell selection
// 4.0.6.4 : Fixed : issue with loading empty comments to stream
//         : Improved : direct edit start with keyboard allowed when MouseActions.EditOnDblClick = true
//         : Improved : faster cleanup for virtual grids
// 4.0.6.5 : Fixed : issue with auto hiding horz. scrollbar
//         : Fixed : issue with cell validation , tab key and hidden columns
//         : Fixed : issue with MouseActions.EditOnDBlClickOnly = true
// 4.0.6.6 : Fixed : issue with combination of FixedAsButton & nodes
// 4.0.6.7 : Fixed : issue with starting editing with Return key
//         : Fixed : issue with changing RowCount while FloatingFooter is visible
// 4.0.6.8 : Fixed : small issue with AdvanceOnEnter and edEditBtn tyue
//         : Fixed : small issue with programmatically set checkboxes in grid with hidden rows
// 4.0.6.9 : Fixed : issue with validation and edComboList inplace editor
//         : Fixed : issue with ShowSelection =false and DisjunctCellSelection
//         : Fixed : memory leak issue when calling Clear* functions
//         : Fixed : issue with UnHilightInRow, UnMarkInRow for grid with hidden columns
//         : Fixed : issue with disjunct row selection and hidden rows
//         : Fixed : issue with row moving, bdRightToLeft mode & ShowCells = true
// 4.0.6.10: Fixed : issue with mousewheel in older Delphi versions
// 4.0.6.11: Fixed : issue with EditOnDblClickOnly and OnCanEdit event usage
//         : Improved : AddProgressFormatted supports integer & double progress values
// 4.0.6.12: Fixed : rare memory leak situation with hidden columns & removing rows in code
// 4.0.6.13: Improved : search footer painting issue when removing rows from grid
//         : Improved : OnAutoAddRow triggered when tab key pressed on last row with AdvanceInsert = true
//         : Fixed : issue with disjunct row unselection & hidden rows
//         : Fixed : issue with AllowFmtClipboard & empty grid cells
//         : Fixed : issue with RangeSelectAndEdit and Ctrl-A
//         : Fixed : issue with subgroup sorting
//         : Fixed : issue with ESC key handling on modal forms for specific editor types
//         : Fixed : issue with InsertChildRow 2nd default parameter InsertAt
// 4.0.7.0 : Improved : ChangeScale method implemented
// 4.0.7.1 : Improved : mouse sensitivity for clicks on nodes
//         : Improved : floating footer border drawing
//         : Fixed : issue with FloatingFooter and inserting rows
//         : Fixed : issue with RangeSelectAndEdit and use of OnCanEdit event
// 4.0.8.0 : New : property Navigation.KeepScrollOnSort added
//         : New : public function UpdateXYOffset() added
//         : New : HTML export with images export added 
//         : Improved : HTML output when prefix/suffix is used
// 4.0.8.1 : Fixed : issue with flat scrollbars & reparenting
//         : Fixed : issue with InsertChildNode()
//         : Fixed : issue with SortSettings.HeaderColor & hidden columns
//         : Fixed : issue with spin editor & grid.Navigation.AdvanceOnEnter = true  


{$I TMSDEFS.INC}

unit AdvGrid;

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

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


{$IFNDEF DELPHI_UNICODE}
{$IFDEF DELPHI5_LVL}
{$IFNDEF TMSDOTNET}
  {$DEFINE TMSUNICODE}
{$ENDIF}
{$ENDIF}
{$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, BaseGrid, Mask, AdvStyleIF
  {$IFNDEF TMSDOTNET} , OleCtnrs, AdvXPVS, jpeg {$ENDIF}
  {$IFDEF TMSDOTNET} , WinUtils, uxTheme, System.Runtime.InteropServices, System.Text {$ENDIF}
  {$IFNDEF DELPHI3_LVL} , OleAuto {$ENDIF}
  , ComObj, Winspool, ActiveX, ImgList, AsgDD
  {$IFDEF TMSUNICODE} , AsgUni {$ENDIF}
  {$IFDEF DELPHI6_LVL} , Variants {$ENDIF}
  {$IFDEF TMSDEBUG} , TMSUtil {$ENDIF}
  , AdvObj, AdvDateTimePicker
  {$IFDEF TMSGDIPLUS}
  , AdvHintInfo
  {$ENDIF}
  ;

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

  MAXCOLUMNS = 512;
  RTF_TWIPS = 1440;

  MAJ_VER = 4; // Major version nr.
  MIN_VER = 0; // Minor version nr.
  REL_VER = 8; // Release nr.
  BLD_VER = 1; // Build nr.
  DATE_VER = 'Oct, 2008'; // Month version

var
  CF_GRIDCELLS: Word;
  WM_GRIDEDITDONE: Word;

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

  TAdvStringGrid = 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);

  PBoolArray = ^TBoolarray;
  TBoolArray = array[0..MAXCOLUMNS] of Boolean;
  TWidthArray = array[0..MAXCOLUMNS] of SmallInt;

  TAdvGridStyle = (gsOffice2003Blue, gsOffice2003Silver, gsOffice2003Olive, gsOffice2003Classic, gsOffice2007Luna, gsOffice2007Obsidian, gsWindowsXP, gsWhidbey, gsCustom, gsOffice2007Silver,gsWindowsVista);

  EAdvGridError = class(Exception);

  TAsgVAlignment = Basegrid.TVAlignment;

  TGetEditorTypeEvent = procedure(Sender:TObject;ACol,ARow: Integer;
    var AEditor:TEditorType) of object;

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

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

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

  TCheckBoxClickEvent = procedure(Sender:TObject;ACol,ARow: Integer;
    State: Boolean) of object;

  TRadioClickEvent = procedure(Sender:TObject;ACol,ARow,AIdx: 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;

  TSpinClickEvent = procedure(Sender:TObject;ACol,ARow,
     AValue: Integer; UpDown: Boolean) 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;

  TSearchEditChangeEvent = procedure(Sender: TObject; Value: string; var DefaultSearch: boolean) of object;

  TSearchAction = (saFindFirst, saFindPrevious, saFindNext);

  TSearchFooterActionEvent = procedure(Sender: TObject; Value: string; ACol, ARow: integer; SearchAction: TSearchAction) 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;

  TSortStyle = (ssAutomatic, ssAlphabetic, ssNumeric, ssDate, ssAlphaNoCase,
    ssAlphaCase, ssShortDateEU, ssShortDateUS, ssCustom, ssFinancial, ssAnsiAlphaCase,
    ssAnsiAlphaNoCase, ssRaw, ssHTML, ssImages, ssCheckBox
    {$IFDEF TMSUNICODE}
    , ssUnicode
    {$ENDIF}
    {$IFDEF DELPHI7_LVL}
    , ssDateTime, ssTime
    {$ENDIF}
    , ssAlphaNumeric, ssAlphaNumericNoCase
    );

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

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

  TCellBorder = (cbTop,cbLeft,cbRight,cbBottom);

  TCellBorders = set of TCellBorder;

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

  TSortDirection = (sdAscending,sdDescending);

  TAdvanceDirection = (adLeftRight,adTopBottom);

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

  TInsertPosition = (pInsertBefore,pInsertAfter);

  TScrollType = (ssNormal,ssFlat,ssEncarta);

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

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

  TCanInsertRowEvent = procedure(Sender: TObject; ARow: Integer;
    var CanInsert: Boolean) of object;

  TAutoInsertRowEvent = procedure(Sender:TObject; ARow: Integer) of object;

  TCanAddRowEvent = procedure(Sender: TObject; var CanAdd: Boolean) of object;
  TAutoAddRowEvent = procedure(Sender:TObject; ARow: Integer) of object;

  TCanDeleteRowEvent = procedure(Sender: TObject; ARow: Integer;
    var CanDelete: Boolean) of object;

  TAutoDeleteRowEvent = procedure(Sender:TObject; ARow: Integer) of object;

  TAutoInsertColEvent = procedure(Sender:TObject; ACol: Integer) of object;

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

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

  TClickSortEvent = procedure(Sender:TObject; ACol: Integer) of object;

  TCanSortEvent = procedure(Sender:TObject; ACol: Integer; var DoSort: 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;
            
  TCustomCompareEvent = procedure(Sender:TObject; str1,str2:string;
    var Res: Integer) of object;

  TRawCompareEvent = procedure(Sender:TObject; ACol,Row1,Row2: Integer;
    var Res: Integer) of object;

  TGridFormatEvent = procedure(Sender : TObject; ACol: Integer;
    var AStyle:TSortStyle; var aPrefix,aSuffix:string) of object;

  TGridColorEvent = procedure(Sender: TObject; ARow, ACol: Integer;
    AState: TGridDrawState; ABrush: TBrush; AFont: TFont ) of object;

  TGridBorderEvent = procedure (Sender: TObject; ARow, ACol: Integer; APen: TPen;
    var Borders: TCellBorders) of object;

  TGridBorderPropEvent = procedure (Sender: TObject; ARow, ACol: Integer;
    LeftPen,TopPen,RightPen,BottomPen: TPen) of object;

  TGridAlignEvent = procedure (Sender: TObject; ARow, ACol: Integer;
    var HAlign: Classes.TAlignment;var VAlign: TAsgVAlignment) of object;

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

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

  {$IFDEF TMSGDIPLUS}
  TOfficeHintEvent = procedure(Sender: TObject; ACol, ARow: Integer; OfficeHint: TAdvHintInfo) of object;
  {$ENDIF}

  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;

  TScrollHintEvent = procedure (Sender:TObject; ARow: Integer;var hintstr:string) of object;

  TGridPrintPageEvent = procedure (Sender:TObject; Canvas: TCanvas; PageNr,PageXSize,PageYSize: Integer) 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;

  TOnResizeEvent = procedure (Sender:TObject) of object;

  TColumnSizeEvent = procedure (Sender:TObject; ACol: Integer; var Allow: Boolean) of object;

  TColumnSizingEvent = procedure (Sender:TObject; ACol, ColumnSize: Integer) of object;

  TRowSizingEvent = procedure (Sender:TObject; ARow, RowSize: Integer) of object;

  TRowSizeEvent = procedure (Sender:TObject; ARow: Integer; var Allow: Boolean) of object;

  TEndColumnSizeEvent = procedure (Sender:TObject; ACol: Integer) of object;

  TUpdateColumnSizeEvent = procedure (Sender:TObject; ACol: Integer; var AWidth: Integer) of object;

  TEndRowSizeEvent = procedure (Sender:TObject; ARow: Integer) of object;

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

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

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

  TCanClickCellEvent = procedure (Sender:TObject;ARow,ACol: Integer;var Allow: Boolean) 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;

  TAnchorClickEvent = procedure(Sender:TObject;ARow,ACol: Integer; Anchor:string; var AutoHandle: Boolean) of object;

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

  TAnchorEvent = procedure(Sender:TObject;ARow,ACol: Integer; Anchor:string) 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;

  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;

  TCustomCellDrawEvent = procedure(Sender: TObject; Canvas: TCanvas; ACol,ARow: Integer;
    AState: TGridDrawState; ARect: TRect; Printing: Boolean) 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;

  TBeforeCellPasteWideEvent = procedure(Sender: TObject; ACol,ARow: Integer;
    var Value: widestring; var Allow: Boolean) 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;

  TFloatFormatEvent = procedure(Sender: TObject; ACol,ARow: Integer;var IsFloat: Boolean;
    var FloatFormat: string) 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);

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

  TFindParams = set of TFindParameters;

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

  TSortBlankPosition = (blFirst,blLast);

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

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

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

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

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

  TGridBalloonEvent = procedure(Sender: TObject; ACol, ARow: Integer; var ATitle: string; var AText: string; var AIcon: Integer) 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;

  //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;


  {TCellGraphic}

  TCellGraphic = 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;
    {$IFDEF TMSDOTNET}
    FCellColor: TColor;
    FCellBKColor: TColor;
    FCellTextFGColor : TColor;
    FCellTextBKColor : TColor;
    FCellTextGraphic : TStrings;
    FCellFilePicture : TFilePicture;
    FCellPicture : TPicture;
    FCellList: TIntList;
    FCellStrings : TStrings;
    {$IFDEF DELPHI6_LVL}
    FCellInterface: TInterfacedPersistent;
    {$ENDIF}
    {$ENDIF}
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    {$IFDEF DELPHI6_LVL}
    procedure SetInterfacedCell(AObject: TInterfacedPersistent);
    {$ENDIF}    
    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);
    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 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;
    {$IFDEF TMSDOTNET}
    property CellColor: TColor read FCellColor write FCellColor;
    property CellBKColor: TColor read FCellBKColor write FCellBKColor;
    property CellTextBKColor: TColor read FCellTextBKColor write FCellTextBKColor;
    property CellTextFGColor: TColor read FCellTextFGColor write FCellTextFGColor;
    property CellTextGraphic : TStrings read FCellTextGraphic write FCellTextGraphic;
    property CellFilePicture : TFilePicture read FCellFilePicture write FCellFilePicture;
    property CellPicture : TPicture read FCellPicture write FCellPicture;
    property CellList: TIntList read FCellList write FCellList;
    property CellStrings: TStrings read FCellStrings write FCellStrings;
    {$IFDEF DELPHI6_LVL}
    property CellInterface: TInterfacedPersistent read FCellInterface write FCellInterface;
    {$ENDIF}
    {$ENDIF}
  end;

  {TBands}

  TBands = class(TPersistent)
  private
    FPrint: Boolean;
    FActive: Boolean;
    FTotalLength: Integer;
    FSecondaryLength: Integer;
    FPrimaryLength: Integer;
    FSecondaryColor: TColor;
    FPrimaryColor: TColor;
    FOwner:TAdvStringGrid;
    procedure SetActive(const Value: Boolean);
    procedure SetPrimaryColor(const Value: TColor);
    procedure SetPrimaryLength(const Value: Integer);
    procedure SetSecondaryColor(const Value: TColor);
    procedure SetSecondaryLength(const Value: Integer);
  public
    constructor Create(AOwner:TAdvStringGrid);
    procedure Assign(Source: TPersistent); override;
    property TotalLength: integer read FTotalLength;
  published
    property Active: Boolean read FActive write SetActive default False;
    property PrimaryColor: TColor read FPrimaryColor write SetPrimaryColor default clInfoBk;
    property PrimaryLength: Integer read FPrimaryLength write SetPrimaryLength default 1;
    property SecondaryColor: TColor read FSecondaryColor write SetSecondaryColor default clWindow;
    property SecondaryLength: Integer read FSecondaryLength write SetSecondaryLength default 1;
    property Print: Boolean read FPrint write FPrint default False;
  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;
    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);
  public
    constructor Create(AOwner: TAdvStringGrid);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    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 clNone;
    property FixedGradientHoverTo: TColor read FFixedGradientHoverFrom write SetFixedGradientHoverFrom default clNone;
    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 clNone;
    property FixedGradientDownFrom: TColor read FFixedGradientDownTo write SetFixedGradientDownTo default clNone;
    property FixedGradientDownTo: TColor read FFixedGradientDownFrom write SetFixedGradientDownFrom default clNone;
    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 clNone;
    property FixedDropDownButton: Boolean read FFixedDropDownButton write FFixedDropDownButton default False;
    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 csWinXP;
    property DropDownAlwaysVisible: Boolean read FDropDownAlwaysVisible write SetDropDownAlwaysVisible default False;
    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;

  TGridFixedCellEdit = (fceNone, fceDblClick, fceLeftClick, fceRightClick);

  TWheelAction = (waMoveSelection, waScroll);

  {TMouseActions}

  TMouseActions = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    FColSelect: Boolean;
    FRowSelect: Boolean;
    FAllSelect: Boolean;
    FDirectEdit: Boolean;
    FDirectComboDrop: Boolean;
    FDirectComboClose: Boolean;
    FDirectDateClose: Boolean;
    FDirectDateDrop: Boolean;
    FDisjunctRowSelect: Boolean;
    FDisjunctColSelect: Boolean;    
    FAllColumnSize: Boolean;
    FAllRowSize: Boolean;
    FCaretPositioning: Boolean;
    FSizeFixedCol: Boolean;
    FSizeFixedRow: Boolean;
    FDisjunctCellSelect: Boolean;
    FFixedRowsEdit: TGridFixedCellEdit;
    FFixedColsEdit: TGridFixedCellEdit;
    FHotmailRowSelect: Boolean;
    FRangeSelectAndEdit: Boolean;
    FNoAutoRangeScroll: Boolean;
    FPreciseCheckBoxCheck: Boolean;
    FCheckAllCheck: Boolean;
    FNodeAllExpandContract: Boolean;
    FMoveRowOnNodeClick: Boolean;
    FRowSelectPersistent: Boolean;
    FSelectOnRightClick: Boolean;
    FNoScrollOnPartialRow: Boolean;
    FWheelIncrement: Integer;
    FWheelAction: TWheelAction;
    FAutoSizeColOnDblClick: Boolean;
    FEditOnDblClickOnly: Boolean;
    FOnChange: TNotifyEvent;
    procedure SetDisjunctColSelect(const AValue: Boolean);
    procedure SetDisjunctRowSelect(const AValue: Boolean);
    procedure SetDisjunctCellSelect(const AValue: Boolean);
    procedure SetHotmailRowSelect(const AValue: Boolean);
    procedure SetEditOnDblClickOnly(const AValue: Boolean);
    procedure SetWheelAction(const Value: TWheelAction);
  protected
    procedure Changed;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property AllColumnSize: Boolean read FAllColumnSize write FAllColumnSize default False;
    property AllRowSize: Boolean read FAllRowSize write FAllRowSize default False;
    property AllSelect: Boolean read FAllSelect write FAllSelect default False;
    property AutoSizeColOnDblClick: Boolean read FAutoSizeColOnDblClick write FAutoSizeColOnDblClick default True;
    property CaretPositioning: Boolean read FCaretPositioning write FCaretPositioning default False;
    property CheckAllCheck: Boolean read FCheckAllCheck write FCheckAllCheck default False;
    property ColSelect: Boolean read FColSelect write FColSelect default False;
    property DirectComboClose: Boolean read FDirectComboClose write FDirectComboClose default False;
    property DirectComboDrop: Boolean read FDirectComboDrop write FDirectComboDrop default False;
    property DirectDateClose: Boolean read FDirectDateClose write FDirectDateClose default False;
    property DirectDateDrop: Boolean read FDirectDateDrop write FDirectDateDrop default False;
    property DirectEdit: Boolean read FDirectEdit write FDirectEdit default False;
    property DisjunctRowSelect: Boolean read FDisjunctRowSelect write SetDisjunctRowSelect default False;
    property DisjunctColSelect: Boolean read FDisjunctColSelect write SetDisjunctColSelect default False;
    property DisjunctCellSelect: Boolean read FDisjunctCellSelect write SetDisjunctCellSelect default False;
    property EditOnDblClickOnly: Boolean read FEditOnDblClickOnly write SetEditOnDblClickOnly default False;
    property FixedRowsEdit: TGridFixedCellEdit read FFixedRowsEdit write FFixedRowsEdit default fceNone;
    property FixedColsEdit: TGridFixedCellEdit read FFixedColsEdit write FFixedColsEdit default fceNone;
    property HotmailRowSelect: Boolean read FHotmailRowSelect write SetHotmailRowSelect default false;
    property MoveRowOnNodeClick: Boolean read FMoveRowOnNodeClick write FMoveRowOnNodeClick default False;
    property NoAutoRangeScroll: Boolean read FNoAutoRangeScroll write FNoAutoRangeScroll default False;
    property NodeAllExpandContract: Boolean read FNodeAllExpandContract write FNodeAllExpandContract default False;
    property NoScrollOnPartialRow: Boolean read FNoScrollOnPartialRow write FNoScrollOnPartialRow default False;
    property PreciseCheckBoxCheck: Boolean read FPreciseCheckBoxCheck write FPreciseCheckBoxCheck default False;
    property RangeSelectAndEdit: Boolean read FRangeSelectAndEdit write FRangeSelectAndEdit default False;
    property RowSelect: Boolean read FRowSelect write FRowSelect default False;
    property RowSelectPersistent: Boolean read FRowSelectPersistent write FRowSelectPersistent default False;
    property SelectOnRightClick: Boolean read FSelectOnRightClick write FSelectOnRightClick default False;
    property SizeFixedCol: Boolean read FSizeFixedCol write FSizeFixedCol default False;
    property SizeFixedRow: Boolean read FSizeFixedRow write FSizeFixedRow default False;    
    property WheelIncrement: Integer read FWheelIncrement write FWheelIncrement default 0;
    property WheelAction: TWheelAction read FWheelAction write SetWheelAction default waMoveSelection;
  end;

  TColumnSizeLocation = (clRegistry,clIniFile);

  {TColumnSize}

  TColumnSize = class(TPersistent)
  private
    Owner: TComponent;
    FSave: Boolean;
    FKey : string;
    FSection : string;
    FStretch: Boolean;
    FStretchColumn: Integer;
    FSynchWithGrid: Boolean;
    FLocation: TColumnSizeLocation;
    procedure SetStretch(Value: Boolean);
  public
    constructor Create(AOwner:TComponent);
    destructor Destroy; override;
  published
    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 StretchColumn: Integer read FStretchColumn write FStretchColumn default -1;
    property SynchWithGrid: Boolean read FSynchWithGrid write FSynchWithGrid default False;
    property Location: TColumnSizeLocation read FLocation write FLocation default clRegistry;
  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;
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
  published
    property AutoSelectGroup: boolean read FAutoSelectGroup write FAutoSelectGroup 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;

  THomeEndAction = (heFirstLastColumn,heFirstLastRow);

  { TNavigation }

  TNavigation = class(TPersistent)
  private
    FAllowInsertRow: Boolean;
    FAllowDeleteRow: Boolean;
    FAdvanceOnEnter: Boolean;
    FAdvanceInsert: Boolean;
    FAutoGotoWhenSorted: Boolean;
    FAutoGotoIncremental: Boolean;
    FAutoComboDropSize: Boolean;
    FAllowClipboardShortcuts: Boolean;
    FAllowRTFClipboard: Boolean;
    FAllowSmartClipboard: Boolean;
    FAllowClipboardAlways: Boolean;
    FAllowClipboardColGrow: Boolean;
    FAllowClipboardRowGrow: Boolean;
    FCopyHTMLTagsToClipboard: Boolean;
    FAdvanceDirection: TAdvanceDirection;
    FAdvanceAuto: Boolean;
    FCursorWalkEditor: Boolean;
    FCursorWalkAlwaysEdit: Boolean;
    FMoveRowOnSort: Boolean;
    FKeepScrollOnSort: Boolean;
    FImproveMaskSel: Boolean;
    FAlwaysEdit: Boolean;
    FInsertPosition:TInsertPosition;
    FLineFeedOnEnter: Boolean;
    FHomeEndKey: THomeEndAction;
    FKeepHorizScroll: Boolean;
    FAllowFMTClipboard: Boolean;
    FTabToNextAtEnd: Boolean;
    FEditSelectAll: Boolean;
    FTabAdvanceDirection: TAdvanceDirection;
    FSkipFixedCells: Boolean;
    FAllowCtrlEnter: Boolean;
    FAppendOnArrowDown: Boolean;
    FLeftRightRowSelect: Boolean;
    FMoveScrollOnly: Boolean;    
    FOnChange: TNotifyEvent;
    procedure SetAutoGoto(aValue: Boolean);
    procedure SetAdvanceDirection(const Value: TAdvanceDirection);
  protected
    procedure Changed;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property AllowInsertRow: Boolean read FAllowInsertRow write FAllowInsertRow default False;
    property AllowDeleteRow: Boolean read FAllowDeleteRow write FAllowDeleteRow default False;
    property AlwaysEdit: Boolean read FAlwaysEdit write FAlwaysEdit default False;
    property AdvanceOnEnter: Boolean read FAdvanceOnEnter write FAdvanceOnEnter default False;
    property AdvanceInsert: Boolean read FAdvanceInsert write FAdvanceInsert default False;
    property AutoGotoWhenSorted: Boolean read FAutoGotoWhenSorted write SetAutoGoto default False;
    property AutoGotoIncremental: Boolean read FAutoGotoIncremental write FAutoGotoIncremental default False;
    property AutoComboDropSize: Boolean read FAutoComboDropSize write FAutoComboDropSize default False;
    property AdvanceDirection: TAdvanceDirection read FAdvanceDirection write SetAdvanceDirection default adLeftRight;
    property AllowClipboardShortCuts: Boolean read FAllowClipboardShortcuts write FAllowClipboardShortcuts default False;
    property AllowCtrlEnter: Boolean read FAllowCtrlEnter write FAllowCtrlEnter default True;
    property AllowSmartClipboard: Boolean read FAllowSmartClipboard write FAllowSmartClipboard default False;
    property AllowRTFClipboard: Boolean read FAllowRTFClipboard write FAllowRTFClipboard default False;
    property AllowFmtClipboard: Boolean read FAllowFMTClipboard write FAllowFMTClipboard default False;
    property AllowClipboardAlways: Boolean read FAllowClipboardAlways write FAllowClipboardAlways default False;
    property AllowClipboardRowGrow: Boolean read FAllowClipboardRowGrow write FAllowClipboardRowGrow default True;
    property AllowClipboardColGrow: Boolean read FAllowClipboardColGrow write FAllowClipboardColGrow default True;
    property AdvanceAuto: Boolean read FAdvanceAuto write FAdvanceAuto default False;
    property AppendOnArrowDown: Boolean read FAppendOnArrowDown write FAppendOnArrowDown default False;
    property EditSelectAll: Boolean read FEditSelectAll write FEditSelectAll default True;
    property InsertPosition: TInsertPosition read FInsertPosition write FInsertPosition default pInsertBefore;
    property CursorWalkEditor: Boolean read FCursorWalkEditor write FCursorWalkEditor default False;
    property CursorWalkAlwaysEdit: Boolean read FCursorWalkAlwaysEdit write FCursorWalkAlwaysEdit default True;
    property MoveRowOnSort: Boolean read FMoveRowOnSort write FMoveRowOnSort default False;
    property KeepScrollOnSort: Boolean read FKeepScrollOnSort write FKeepScrollOnSort default False;
    property MoveScrollOnly: Boolean read FMoveScrollOnly write FMoveScrollOnly default False;
    property ImproveMaskSel: Boolean read FImproveMaskSel write FImproveMaskSel default False;
    property LeftRightRowSelect: Boolean read FLeftRightRowSelect write FLeftRightRowSelect default true;
    property CopyHTMLTagsToClipboard: Boolean read FCopyHTMLTagsToClipboard write FCopyHTMLTagsToClipboard default True;
    property KeepHorizScroll: Boolean read FKeepHorizScroll write FKeepHorizScroll default False;
    property LineFeedOnEnter: Boolean read FLineFeedOnEnter write FLineFeedOnEnter default False;
    property HomeEndKey: THomeEndAction read FHomeEndKey write FHomeEndKey default heFirstLastColumn;
    property SkipFixedCells: Boolean read FSkipFixedCells write FSkipFixedCells default True;
    property TabToNextAtEnd: Boolean read FTabToNextAtEnd write FTabToNextAtEnd default False;
    property TabAdvanceDirection: TAdvanceDirection read FTabAdvanceDirection write FTabAdvanceDirection default adLeftRight;
  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;
    FWidth: Integer;
    FColWidths: TIntList;
    FXHTML: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property ColWidths: TIntList read FColWidths;
  published
    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 SaveColor: Boolean read FSaveColor write FSaveColor default True;
    property SaveFonts: Boolean read FSaveFonts write FSaveFonts default True;
    property FooterFile: string read FFooterFile write FFooterFile;
    property HeaderFile: string read FHeaderFile write FHeaderFile;
    property TableStyle: string read FTableStyle write FTableStyle;
    property PrefixTag: string read FPrefixTag write FPrefixTag;
    property SuffixTag: string read FSuffixTag write FSuffixTag;
    property Width: Integer read FWidth write FWidth default 100;
    property XHTML: Boolean read FXHTML write FXHTML default False;
    property ConvertSpecialChars: Boolean read FConvertSpecialChars write FConvertSpecialChars default False;
    property AutoPreview: boolean read FAutoPreview write FAutoPreview default False;
    property NonBreakingText: Boolean read FNonBreakingText write FNonBreakingText default False;
  end;

  { TBalloonSettings }

  TBalloonSettings = class(TPersistent)
  private
    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;

  {$IFDEF TMSDOTNET}
  TWMNotifyTT = class(TWMNotify)
  protected
    function GetToolTipText: TToolTipText;
    procedure SetToolTipText(value: TToolTipText);
  public
    property ToolTipText: TToolTipText read GetToolTipText write SetToolTipText;
  end;
  {$ENDIF}


  {TPrintSettings}

  TPrintSettings = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    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;
    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;
  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 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);

  { 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;
    FHeaderColor: TColor;
    FHeaderColorTo: TColor;
    FHeaderMirrorColor: TColor;
    FHeaderMirrorColorTo: TColor;
    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;
  published
    property AutoSortForGrouping: Boolean read FAutoSortForGrouping write FAutoSortForGrouping default True;
    property AutoColumnMerge: Boolean read FAutoColumnMerge write FAutoColumnMerge default False;
    property Column: Integer read FSortColumn write FSortColumn default 0;
    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 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 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;
  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;
    {$IFNDEF TMSDOTNET}
    FTag: Integer;
    {$ENDIF}
    FAutoPopupWidth: Boolean;
    FPopupLeft: Integer;
    FPopupTop: Integer;
  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 EditCell:TPoint read FEditCell;
  published
    property AutoPopupWidth: Boolean read FAutoPopupWidth write FAutoPopupWidth;
    property EditStyle: TEditStyle read FEditStyle write FEditStyle;
    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;
    property PopupHeight: Integer read FPopupHeight write FPopupHeight;
    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;
    property WantKeyEscape: Boolean read FWantKeyEscape write FWantKeyEscape;
    {$IFNDEF TMSDOTNET}
    property Tag: Integer read FTag write FTag;
    {$ENDIF}
  end;

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

  {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;
    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;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
  end;

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

  {$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(TDateTimePicker)
  private
    FOldDropped: Boolean;
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
    {$IFNDEF TMSDOTNET}
    procedure WMNCPaint (var Message: TMessage); message WM_NCPAINT;
    {$ENDIF}
  protected
//    {$IFDEF TMSDOTNET}
    procedure WndProc(var Message: TMessage); override;
//    {$ENDIF}
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure DoExit; override;
  public
    FGrid: TAdvStringGrid;
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
    {$IFDEF DELPHI2006_LVL}
    property Text;
    {$ENDIF}
  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
    FSelKeyDown: integer;
    FGrid: TAdvStringGrid;
    procedure WMChar(var Msg:TWMChar); message WM_CHAR;
    procedure WMPaste(var Msg:TMessage); message WM_PASTE;
    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;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ReCreate;
  published
  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 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;
    Workmode: Boolean;
    FGrid: TAdvStringGrid;
    FColE,FRowE: integer;
    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;
  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;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DoChange;
  published
    property VAlign: Boolean read FVAlign write SetVAlign;
    property WordWrap: Boolean read FWordwrap write SetWordWrap;
    property LengthLimit: smallint read FLengthLimit write FLengthLimit;
    property PopupMenu;
  end;

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

  {TFilterData}

  TFilterData = class(TCollectionItem)
  private
    FColumn: SmallInt;
    FCondition: string;
    FCaseSensitive: Boolean;
    FSuffix: string;
    FPrefix: string;
    FOperation: TFilterOperation;
    FData: TFilterCells;
  public
    constructor Create(ACollection: TCollection); override;
    procedure Assign(Source: TPersistent); override;
  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 Prefix: string read FPrefix write FPrefix;
    property Suffix: string read FSuffix write FSuffix;
    property Operation: TFilterOperation read FOperation write FOperation;
  end;

  {TFilter}

  TFilter = class(TCollection)
  private
    FOwner: TAdvStringGrid;
    function GetItem(Index: Integer): TFilterData;
    procedure SetItem(Index: Integer; Value: TFilterData);
    function GetColFilter(Col: Integer): TFilterData;
  public
    constructor Create(AOwner: TAdvStringGrid);
    function Add: TFilterData;
    function Insert(index: Integer): TFilterData;
    property Items[Index: Integer]: TFilterData read GetItem write SetItem;
    property ColumnFilter[Col: Integer]: TFilterData read GetColFilter;
  protected
    {$IFDEF DELPHI3_LVL}
    function GetOwner: TPersistent; override;
    {$ELSE}
    function GetOwner: TPersistent;
    {$ENDIF}
  end;

  {TGridItem}

  TGridItem = class(TCollectionItem)
  private
    FIdx: Integer;
    FHeight: Integer;
    FItems: TStrings;
    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 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 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;
    FOleCopyAlways: Boolean;
    FOleColumnDragDrop: 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
    {$IFDEF DELPHI6_LVL}
    property ShowCells: boolean read FShowCells write SetShowCells default True;
    {$ENDIF}
    {$IFNDEF DELPHI6_LVL}
    property ShowCells: boolean read FShowCells write SetShowCells default False;
    {$ENDIF}
    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 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;
    property OleColumnDragDrop: Boolean read FOleColumnDragDrop write FOleColumnDragDrop default False;
  end;

  {$IFNDEF TMSDOTNET}
  TGridDropTarget = class(TASGDropTarget)
  private
    FGrid: TAdvStringGrid;
  public
    constructor Create(AGrid:TAdvStringGrid);
    procedure DropText(pt:TPoint;s:string); 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;
  {$ENDIF}

  {TGridChangeNotifier}

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

  {THTMLHintWindow}

  THTMLHintWindow = class(THintWindow)
  private
    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
    procedure ActivateHint(Rect: TRect; const AHint: string); override;
    {$IFNDEF TMSDOTNET}
    function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect; override;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TObject): TRect; override;
    {$ENDIF}
  published
  end;

  TRetEdit = class(TEdit)
  private
    FOnReturn: 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;
  end;

  { TSearchPanel }

  TSearchPanel = class(TPanel)
  private
    FEdit: TRetEdit;
    FExitButton: TAdvGridButton;
    FForwardButton: TAdvGridButton;
    FBackwardButton: TAdvGridButton;
    FHiliteButton: TAdvGridButton;
    FMatchCase: TCheckBox;
    FOnForwardClick: TNotifyEvent;
    FOnBackwardClick: TNotifyEvent;
    FOnEditChange: TNotifyEvent;
    FOnExitClick: TNotifyEvent;
    FOnHighLightClick: 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 EditChange(Sender: TObject);
    procedure EditReturn(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: TCheckBox 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 OnExitClick: TNotifyEvent read FOnExitClick write FOnExitClick;
  end;

  { TSearchFooter }

  TSearchFooter = class(TPersistent)
  private
    FShowFindPrev: boolean;
    FShowFindNext: boolean;
    FFindNextCaption: string;
    FFindPrevCaption: string;
    FColorTo: TColor;
    FColor: TColor;
    FOnChange: TNotifyEvent;
    FVisible: boolean;
    FAutoThemeAdapt: Boolean;
    FShowClose: Boolean;
    FShowHighLight: Boolean;
    FShowMatchCase: Boolean;
    FMatchCaseCaption: string;
    FHintClose: string;
    FHintFindPrev: string;
    FHintHighLight: string;
    FHintFindNext: string;
    FAutoSearch: Boolean;
    FLastSearch: string;
    FSearchColumn: Integer;
    FSearchActiveColumnOnly: Boolean;
    FSearchMatchStart: Boolean;
    FHighLightCaption: string;
    FFont: TFont;
    procedure SetColor(const Value: TColor);
    procedure SetColorTo(const Value: TColor);
    procedure SetFindNextCaption(const Value: string);
    procedure SetFindPrevCaption(const Value: string);
    procedure SetShowFindNext(const Value: boolean);
    procedure SetShowFindPrev(const Value: boolean);
    procedure SetVisible(const Value: boolean);
    procedure SetAutoThemeAdapt(const Value: boolean);
    procedure SetShowClose(const Value: Boolean);
    procedure SetShowHighLight(const Value: Boolean);
    procedure SetShowMatchCase(const Value: Boolean);
    procedure SetMatchCaseCaption(const Value: string);
    procedure SetHintClose(const Value: string);
    procedure SetHintFindNext(const Value: string);
    procedure SetHintFindPrev(const Value: string);
    procedure SetHintHighlight(const Value: string);
    procedure SetHighLightCaption(const Value: string);
    procedure SetFont(const Value: TFont);
  protected
    procedure Changed;
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property AutoThemeAdapt: Boolean read FAutoThemeAdapt write SetAutoThemeAdapt;
    property LastSearch: string read FLastSearch write FLastSearch;
  published
    property AutoSearch: Boolean read FAutoSearch write FAutoSearch default True;
    property Color: TColor read FColor write SetColor default clWhite;
    property ColorTo: TColor read FColorTo write SetColorTo default clBtnFace;
    property FindNextCaption: string read FFindNextCaption write SetFindNextCaption;
    property FindPrevCaption: string read FFindPrevCaption write SetFindPrevCaption;
    property Font: TFont read FFont write SetFont;
    property HighLightCaption: string read FHighLightCaption write SetHighLightCaption;
    property HintClose: string read FHintClose write SetHintClose;
    property HintFindNext: string read FHintFindNext write SetHintFindNext;
    property HintFindPrev: string read FHintFindPrev write SetHintFindPrev;
    property HintHighlight: string read FHintHighLight write SetHintHighlight;
    property MatchCaseCaption: string read FMatchCaseCaption write SetMatchCaseCaption;
    property SearchActiveColumnOnly: Boolean read FSearchActiveColumnOnly write FSearchActiveColumnOnly default False;
    property SearchColumn: Integer read FSearchColumn write FSearchColumn default -1;
    property SearchMatchStart: boolean read FSearchMatchStart write FSearchMatchStart default False;
    property ShowClose: Boolean read FShowClose write SetShowClose default true;
    property ShowFindNext: boolean read FShowFindNext write SetShowFindNext default true;
    property ShowFindPrev: boolean read FShowFindPrev write SetShowFindPrev default true;
    property ShowHighLight: Boolean read FShowHighLight write SetShowHighLight default true;
    property ShowMatchCase: Boolean read FShowMatchCase write SetShowMatchCase default true;
    property Visible: boolean read FVisible write SetVisible default false;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  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;
    procedure Paint; override;
    procedure CreateWnd; override;
    function RTLCoord(rtl: boolean; ARect: TRect): TRect;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property BorderWidth;
  end;

  TFooterStyle = (fsFixedLastRow, fsColumnPreview, fsCustomPreview);

  { TFloatingFooter }

  TFloatingFooter = class(TPersistent)
  private
    FGrid: TAdvStringGrid;
    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);

  {TAdvStringGrid}

  TAdvStringGrid = class(TBaseGrid, ITMSStyle)
  private
    {$IFDEF FREEWARE}
    cla:string;
    {$ENDIF}
    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;
    FMouseKeepDown: Boolean;
    FCtrlDown: Boolean;
    FMouseResize: Boolean;
    FMouseDownMove: Boolean;
    FLookupHistory : Boolean;
    FEnhRowColMove : Boolean;
    FSizeWithForm : Boolean;
    FMultilineCells : Boolean;
    FSortRowXRef: TIntList;
    FUnSortRowXRef: TIntList;
    FMergedColumns: TIntList;
    FSelectedCells: TIntList;
    FSelectedRows: TIntList;
    FModifiedRows: TIntList;
    FOnGetCellColor: TGridColorEvent;
    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;
    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;
    {$IFNDEF TMSDOTNET}
    FGridDropTarget: TGridDropTarget;
    {$ENDIF}
    FOnOleDropFile: TOleDropFileEvent;
    FOnOleDropURL: TOleDropURLEvent;
    FOnClickSort: TClickSortEvent;
    FOnCanSort: TCanSortEvent;
    FOnExpandNode: TNodeClickEvent;
    FOnContractNode: TNodeClickEvent;
    FOnBeforeExpandNode: TNodeAllowEvent;
    FOnBeforeContractNode: TNodeAllowEvent;
    FCustomCompare: TCustomCompareEvent;
    FRawCompare: TRawCompareEvent;
    FOnSearchEditChange: TSearchEditChangeEvent;
    FOnSearchFooterAction: TSearchFooterActionEvent;
    FOnSearchFooterClose: TNotifyEvent;
    FOnClipboardPaste: TClipboardEvent;
    FOnClipboardCut: TClipboardEvent;
    FOnClipboardCopy: TClipboardEvent;
    FOnClipboardBeforePasteCell: TBeforeCellPasteEvent;
    FOnClipboardBeforePasteWideCell: TBeforeCellPasteWideEvent;
    FOnResize: TOnResizeEvent;
    FOnPrintStart: TGridPrintStartEvent;
    FOnPrintCancel: TGridPrintCancelEvent;
    FOnPrintPage: TGridPrintPageEvent;
    FOnPrintNewPage: TGridPrintNewPageEvent;
    FOnPrintPageDone: TGridPrintPageDoneEvent;
    FOnPrintSetColumnWidth: TGridPrintColumnWidthEvent;
    FOnPrintSetRowHeight: TGridPrintRowHeightEvent;
    FDoFitToPage: TDoFitToPageEvent;
    FOnClickCell: TClickCellEvent;
    FOnRightClickCell: TClickCellEvent;
    FOnDblClickCell: TDblClickCellEvent;
    FOnCanEditCell: TCanEditCellEvent;
    FOnCanClickCell: TCanClickCellEvent;
    FOnIsFixedCell: TIsFixedCellEvent;
    FOnIsPasswordCell: TIsPasswordCellEvent;
    FOnAnchorClick: TAnchorClickEvent;
    FOnAnchorEnter: TAnchorEvent;
    FOnAnchorExit: TAnchorEvent;
    FOnAnchorHint: TAnchorHintEvent;
    FOnControlClick: TCellControlEvent;
    FOnControlEditDone: TCellControlEvent;
    FOnControlComboList: TCellComboControlEvent;
    FOnCellValidate: TCellValidateEvent;
    FOnCellValidateWide: TCellValidateWideEvent;
    FOnCellsChanged: TCellsChangedEvent;
    FOnFileProgress: TGridProgressEvent;
    FOnFilterProgress: TGridProgressEvent;
    FOnFixedDropDownClick: TFixedDropDownEvent;
    FOnRichEditSelectionChange: TNotifyEvent;
    FHintColor: TColor;
    FHintShowCells: Boolean;
    FHintShowLargeText: Boolean;
    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;
    //FPrecisePrintMeasure: Boolean;
    FHTMLSettings: THTMLSettings;
    FBands: TBands;
    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;
    FSelectionMirrorColor: TColor;
    FSelectionMirrorColorTo: TColor;
    FSelectionTextColor: TColor;
    FSelectionRectangle: Boolean;
    FSelectionRTFKeep: Boolean;
    FVAlignment: TVAlignment;
    FVAlign: DWORD;
    FURLShow: 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;
    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;
    FEnableHTML: Boolean;
    FEnableWheel: Boolean;
    FFlat: Boolean;
    FAnchorHint: Boolean;
    FSaveFixedCells: Boolean;
    FLoadFirstRow: Boolean;
    FSaveHiddenCells: 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;
    FOldSelection: TGridRect;
    FSizeSelection: TGridRect;
    FMoveSelection: TGridRect;
    FEntered: Boolean;
    FEditing: Boolean;
    FSpecialEditor: Boolean;
    FEditActive: Boolean;
    FValidating: Boolean;
    FFindBusy: Boolean;
    FComboIdx: Integer;
    SortDir: Integer;
    SortRow: Integer;
    SearchCell: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;
    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;
    MaxWidths: array[0..MAXCOLUMNS] of Integer;
    Indents: array[0..MAXCOLUMNS] of Integer;
    FOnGetEditorType: TGetEditorTypeEvent;
    FOnHasComboBox: THasComboEvent;
    FOnHasSpinEdit: THasSpinEditEvent;
    FOnGetEditorProp: TGetEditorPropEvent;
    FOnEllipsClick: TEllipsClickEvent;
    FOnButtonClick: TButtonClickEvent;
    FOnCheckBoxClick: TCheckBoxClickEvent;
    FOnCheckBoxMouseUp: TCheckBoxClickEvent;
    FOnRadioClick: TRadioClickEvent;
    FOnRadioMouseUp: TRadioClickEvent;
    FOnComboChange: TComboChangeEvent;
    FOnComboCloseUp: TClickCellEvent;
    FOnDatePickerCloseUp: 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;
    EditSpin: TGridSpin;
    EditTrans: TGridTransEdit;
    {$IFDEF TMSUNICODE}
    EditUni: TGridUniEdit;
    MemoUni: TGridUniMemo;
    ComboUni: TGridUniCombo;
    EditBtnUni: TGridUniEditBtn;
    {$ENDIF}
    EditCheck: TGridCheckbox;
    EditBtn: TGridEditBtn;
    UnitEditBtn: TGridUnitEditBtn;
    EditDate: TGridDatePicker;
    EditDateTime: TAdvDateTimePicker;
    GridButton: TGridButton;
    MoveButton: TPopupButton;
    MoveForm: TForm;
    EditControl: TEditorType;
    FGridItems: TCollection;
    FFilter: TFilter;
    FFilterActive: Boolean;
    FFilterFixedRows: Integer;
    FNotifierList: TList;
    FActiveCellShow: Boolean;
    FActiveCellFont: TFont;
    FXYOffset: TPoint;
    FOldSize: Integer;
    FOrigColSizes: TIntList;
    FSizeFixed: Boolean;
    FSizeFixedCol: Integer;
    FSizingFixed: Boolean;
    FSizeFixedRow: 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;
    FIsWinVista: Boolean;
    FIsComCtl6: Boolean;
    FClearTextOnly: Boolean;
    FOnEditingDone: TNotifyEvent;
    FOnEditChange: TEditChangeEvent;
    FOnEditCellDone: TEditCellDoneEvent;
    FOnUpdateColumnSize: TUpdateColumnSizeEvent;
    FHTMLHint: 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;
    FOnCustomCellSize: TCustomCellSizeEvent;
    FSelectionResizeEvent: TSelectionResizeEvent;
    FSelectionResizedEvent: TSelectionResizeEvent;
    {$IFDEF TMSUNICODE}
    FGetEditWideText: TGetEditWideTextEvent;
    FSetEditWideText: TSetEditWideTextEvent;
    FOnWideEllipsClick: TWideEllipsClickEvent;
    {$ENDIF}
    FOnGetWordWrap: TWordWrapEvent;
    FOnGroupCalc: 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;
    {$IFDEF TMSUNICODE}
    FUniLocale: LCID;
    FUniCmpFlgs: DWord;
    {$ENDIF}
    {$IFDEF FREEWARE}
    FFreewareCode: Integer;
    {$ENDIF}
    FGridControlWndProc: TWndMethod;
    FNumCellControls: Integer;
    FControlList: TControlList;
    FDisableSize: Boolean;
    FDefaultEditor: TEditorType;
    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;
    FDragScrollDirection: TDragScrollDirection;
    FOnDragScroll: TDragScrollEvent;
    FFindCol, FFindRow: integer;
    FNoImageAndText: boolean;
    FOnSaveCell: TCellSaveLoadEvent;
    FOnLoadCell: TCellSaveLoadEvent;
    FMaxRowCount: Integer;
    FMaxColCount: Integer;
    FProgressAppearance: TGridProgressAppearance;
    FOnCustomStrToDate: TCustomStrToDateEvent;
    {$IFDEF TMSGDIPLUS}
    FOnOfficeHint: TOfficeHintEvent;
    FOfficeHint: TAdvHintInfo;
    {$ENDIF}
    FScrollLock: Boolean;
    FPaintCount: integer;
    FEditText: string;
    FEditWideText: widestring;
    FNoEditChange: Boolean;
    FGridModified: boolean;
    FIgnoreColumns: TIntList;
    FXMLEncoding: string;
    procedure SetDragScrollOptions(Value: TDragScrollOptions);
    procedure NCPaintProc;
    {$IFNDEF TMSDOTNET}
    procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    procedure WMNotify(var Message: TWMNOTIFY); message WM_NOTIFY;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    procedure WMNotify(var Message: TWMNOTIFYTT); message WM_NOTIFY;
    {$ENDIF}
    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 CMCursorChanged(var Message: TMessage); message CM_CURSORCHANGED;
    procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
    {$IFDEF TMSDOTNET}
    procedure CMHintShow(var Msg: TCMHintShow); message CM_HINTSHOW;
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    procedure CMHintShow(var Msg: TMessage); message CM_HINTSHOW;
    {$ENDIF}
    procedure CMDialogChar(var Msg: TCMDialogChar); message CM_DIALOGCHAR;
    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);

    function IsPassword(ACol,ARow: Integer): Boolean;
    procedure HandleRadioClick(ACol,ARow,Xpos,Ypos: Integer);
    function HasStaticEdit(ACol,ARow: Integer): Boolean;
    procedure TabEdit(Dir: 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(Canvas: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 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 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;
    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): Integer;
    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);    
    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);
    function GetCellAlignment(ACol,ARow: Integer): TCellAlignment;
    procedure DrawIntelliFocusPoint;
    procedure EraseIntelliFocusPoint;
    procedure SetImages(Value:TCustomImageList);
    procedure SetURLShow(Value: Boolean);
    procedure SetURLColor(Value: TColor);
    procedure SetURLFull(Value: Boolean);
    procedure SetLook(Value: TGridLook);
    procedure CalcTextPos(var ARect:TRect;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 ApplyFilterOld;
    procedure ApplyFilter;
    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;
    {$IFNDEF TMSDOTNET}
    function PasteText(ACol,ARow: Integer;p:PChar): Integer;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    function PasteText(ACol,ARow: Integer;p:string): Integer;
    {$ENDIF}
    procedure InputFromCSV(FileName: string;insertmode: Boolean;MaxRows: integer);
    procedure OutputToCSV(FileName: string;appendmode: Boolean; unicode: Boolean);
    procedure OutputToHTML(FileName: string;appendmode: Boolean);
    procedure LoadXLS(filename,sheetname: string);
    procedure SaveXLS(filename,sheetname: string; CreateNewSheet: Boolean);
    {$IFDEF DELPHI3_LVL}
    function GetDateTimePicker:TDateTimePicker;
    procedure SetArrowColor(Value: TColor);
    function GetArrowColor: TColor;
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    function PasteSize(p:PChar):TPoint;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    function PasteSize(p:string):TPoint;
    {$ENDIF}
    procedure MarkCells(s,tag:string;DoCase: Boolean; FromCol,FromRow,ToCol,ToRow: Integer);
    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 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);
    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 GetAllRowCount: Integer;
    function GetWideCells(i, j: Integer): widestring;
    procedure SetWideCells(i, j: Integer; const Value: widestring);
    procedure StartFixedEdit(x,y: Integer);
    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);
    function GetVersion: 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 SetBalloonSettings(const Value: TBalloonSettings);

    procedure SearchEditChange(Sender: TObject);
    procedure SearchBackward(Sender: TObject);
    procedure SearchForward(Sender: TObject);
    procedure SearchExit(Sender: TObject);
    procedure SearchHighLight(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; 
  protected
    FClipTopLeft: TPoint;
    FClipLastOp: TClipOperation;
    FScrollHintWnd: THTMLHintWindow;
    FScrollHintShow: Boolean;
    FVirtualCells: Boolean;
    FCellCache: string;
    FNoRTLOrientation: Boolean;
    FIsGrouping: Boolean;
    procedure SubclassProc(var Msg: TMessage);
    procedure DoCalcFooter(ACol: Integer); virtual;
    procedure UpdateEditingCell(ACol,ARow: Integer; Value: string); virtual;
    procedure UpdateOnSelection(var GR: TGridRect); virtual;
    procedure PasteInCell(ACol,ARow: Integer; Value: string); virtual;
    function GetCurrentCell: string; virtual;
    procedure SetCurrentCell(const AValue: string); virtual;
    procedure SetEditCell(const AValue: string); virtual;
    procedure RestoreCache; virtual;
    procedure ThemeAdapt;
    function ToggleCheck(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;
    procedure GetDisplText(c,r: Integer; var Value: string); override;    
    procedure UpdateFooter;
    function GetCellType(ACol,ARow: Integer): TCellType; virtual;
    function GetCellGraphic(ACol,ARow: Integer): TCellGraphic; virtual;
    function GetCellGraphicSize(ACol,ARow: Integer): TPoint; 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 DrawWallPaperFixed(crect: TRect);
    procedure DrawWallPaperTile(crect: TRect);
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    function CreateEditor: TInplaceEdit; override;
    function CanEditShow: Boolean; override;
    procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
    function GetEditText(ACol, ARow: Longint): string; 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 DestroyWnd; override;
    procedure CreateWnd; 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);
    {$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 Click; override;
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure Paint; override;
    procedure PaintBackground;
    procedure SelectToRowSelect(IsShift: Boolean);
    function GetEditLimit: Integer; override;
    procedure ColWidthsChanged; override;
    procedure RowHeightsChanged; override;
    procedure InvalidateGridRect(r:TGridRect);
    procedure TopLeftChanged; override;
//    procedure CellControlsUpdate;
    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;
    function SaveCell(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 DoCanEditCell(ACol,ARow: Integer; var CanEdit: boolean); virtual;
    procedure DoSearchFooterAction(AValue: string; ACol, ARow: integer; ASearchAction: TSearchAction); 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 GetCellEditor(ACol,ARow: Integer;var AEditor:TEditorType); 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): Boolean; virtual;
    function HasSpinEdit(ACol,ARow: Integer): Boolean; virtual;
    function GetCheckTrue(ACol,ARow: Integer): string; virtual;
    function GetCheckFalse(ACol,ARow: Integer): string; virtual;
    function GetFilter(ACol: Integer): Boolean; virtual;
    function GetSaveStartCol: Integer;
    function GetSaveStartRow: Integer;
    function GetSaveEndCol: Integer;
    function GetSaveEndRow: Integer;
    function GetSaveRowCount: Integer;
    function GetSaveColCount: Integer;
    procedure RemoveRowsInternal(RowIndex, RCount: Integer); virtual;
    procedure StretchColumn(ACol: Integer);
    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;
    procedure QueryAddRow(var AllowAdd: Boolean); virtual;
    procedure QueryInsertRow(ARow: Integer; var AllowInsert: Boolean); virtual;
    procedure DirectWheelChange(delta: integer); virtual;
    {$IFDEF DELPHI5_LVL}
    function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    {$ENDIF}
    procedure UpdateVScroller;
    procedure UpdateHScroller;
    procedure DoAppendRow; virtual;
    procedure AddSummary(ARow: Integer);
    procedure IRemoveRows(RowIndex, RCount: Integer; flg: Boolean);
    procedure CorrectSelection;
    property CellSelectorMode: Boolean read FCellSelectorMode write FCellSelectorMode;
    procedure CellSelect(c,r: Integer); virtual;
    procedure SetCellSelectMode(const Value: Boolean); virtual;
    {$IFDEF TMSDOTNET}
    procedure Resize; override;
    {$ENDIF}
    procedure BalloonChange(Sender: TObject);
    procedure ModifiedChanged(Sender: TObject);
    procedure DatePickerCloseUp(Sender: TObject);
    procedure DateTimePickerChange(Sender: TObject);
    procedure SearchChanged(Sender: TObject);
    procedure UpdateSelectionRect(var GR: TGridRect); virtual;
    procedure OnMouseActionsChanged(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;
  public
    LButFlg: Boolean;
    Compares: Integer;
    Swaps: Integer;
    SortTime: DWord;
    Sortlist: TStringList;
    PrevSizeX,PrevSizeY: Integer;
    EditMode: Boolean;
    function GetCellTextSize(ACol,ARow: Integer;VS: Boolean = false): TSize;
    procedure ExportNotification(AState: TGridExportState; ARow: Integer); virtual;
    procedure ImportNotification(AState: TGridImportState; ARow: Integer); virtual;
    procedure CellControlsUpdate;
    procedure RegisterNotifier(ANotifier: TGridChangeNotifier);
    procedure UnRegisterNotifier(ANotifier: TGridChangeNotifier);
    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 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;
    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;

    procedure BalloonInit;
    procedure BalloonDone;

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

    procedure RemoveCheckedRows(CheckBoxColumn: integer; RemoveChecked: boolean=true);
    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;
    {$IFNDEF TMSDOTNET}
    procedure Resize; override;
    {$ENDIF}
    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 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;
    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 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;
    function NumHiddenRows: Integer;
    function TotalRowCount: Integer;
    function RealRowIndex(ARow: Integer): Integer;
    function RealColIndex(ACol: Integer): Integer;
    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 UnSortedRowIndex(ARow: Integer): Integer;
    function SortedRowIndex(ARow: Integer): Integer;
    function GetRealCol: Integer;
    function GetRealRow: Integer;
    function GetRowEx: Integer;
    procedure SetRowEx(const Value: Integer);
    procedure ScreenToCell(pt:TPoint; var ACol,ARow: Integer);
    procedure HideSelection;
    procedure UnHideSelection;
    procedure UpdateEditMode;
    procedure ScrollInView(ColIndex,RowIndex: Integer);
    procedure MoveRow(FromIndex, ToIndex: Integer);
    procedure MoveColumn(FromIndex, ToIndex: Integer);
    procedure SwapRows(ARow1,ARow2: Integer);
    procedure SortSwapRows(ARow1,ARow2: Integer); virtual;
    procedure ClearRect(ACol1,ARow1,ACol2,ARow2: Integer); virtual;
    procedure Clear;
    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 FocusCell(Col,Row: Integer);
    procedure GotoCell(Col,Row: Integer);
    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 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);
    procedure SaveToHTML(FileName: string; Show:boolean = false);
    function SaveToHTMLString(dir: string): string;
    procedure AppendToHTML(FileName: string);
    procedure SaveToXML(FileName: string; ListDescr, RecordDescr:string;FieldDescr:TStrings; ExportEmptyCells: boolean=false);
    procedure LoadFromXML(FileName: string; LevelToRow: boolean = false);
    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);
    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;
    procedure LoadColPositions;
    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;
    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);
    procedure SetComponentStyle(AStyle: TTMSStyle);
    procedure RandomFill(DoFixed: Boolean = false;Rnd: Integer = 100);
    procedure LinearFill(DoFixed: Boolean = false);
    procedure TextFill(DoFixed: Boolean; Txt: string);
    function HilightText(DoCase: Boolean; S,Text: string):string;
    function UnHilightText(S:string):string;
    procedure HilightInCell(DoCase: Boolean; Col,Row: Integer; HiText: string);
    procedure HilightInCol(DoFixed,DoCase: Boolean; Col: Integer; HiText: string);
    procedure HilightInRow(DoFixed,DoCase: Boolean; Row: Integer; HiText: string);
    procedure HilightInGrid(DoFixed,DoCase: Boolean; HiText: string);
    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);
    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;
    procedure AutoSizeCells(const DoFixedCells: Boolean; const PaddingX,PaddingY: Integer);
    procedure AutoSizeColumns(const DoFixedCols: Boolean; const Padding: Integer = 4);
    procedure AutoSizeCol(const ACol: Integer);
    procedure AutoSizeRows(const DoFixedRows: Boolean; const Padding: Integer = 0);
    procedure AutoSizeRow(const ARow: Integer);
    procedure StretchRightColumn;
    procedure AutoNumberCol(const ACol: Integer);
    procedure AutoNumberRow(const ARow: Integer);
    function IsSelected(ACol,ARow: Integer): Boolean;
    function SelectedText:string;
    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 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 MapFontHeight(pointsize: Integer): Integer;
    function MapFontSize(Height: Integer): Integer;
    {$IFDEF DELPHI6_LVL}
    procedure AddInterfacedCell(ACol,ARow: Integer; AObject: TInterfacedPersistent);
    procedure RemoveInterfacedCell(ACol,ARow: Integer);
    function GetInterfacedCell(ACol,ARow: Integer): TInterfacedPersistent;
    {$ENDIF}
    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 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 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;
    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 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);
    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);
//    procedure AddCheckBoxEx(ACol,ARow: Integer;State,Data: Boolean;HAlign: TCellHalign;VAlign: TCellVAlign);
    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;
    function IsChecked(ACol,ARow: integer): Boolean;
    function SetCheckBoxState(ACol,ARow: Integer;state: Boolean): Boolean;
    function ToggleCheckBox(ACol,ARow: Integer): Boolean;
    procedure CheckAll(ACol: Integer);
    procedure UnCheckAll(ACol: Integer);

    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 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;
    function ColumnSum(ACol,fromRow,toRow: Integer): Double;
    function ColumnAvg(ACol,fromRow,toRow: Integer): Double;
    function ColumnMin(ACol,fromRow,toRow: Integer): Double;
    function ColumnMax(ACol,fromRow,toRow: Integer): Double;
    function ColumnCustomCalc(ACol,fromRow,toRow: Integer): 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;
    procedure ResetFixedCellHighlight;
    procedure CalcFooter(ACol: Integer); virtual;
    procedure BeginUpdate;
    procedure EndUpdate;
    procedure StartUpdate;
    procedure ResetUpdate;
    property LockUpdate: Boolean read GetLockFlag write SetLockFlag;
    property CellTypes[ACol,ARow: Integer]:TCellType read GetCellType;
    property CellGraphics[ACol,ARow: Integer]:TCellGraphic read GetCellGraphic;
    property CellGraphicSize[ACol,ARow: Integer]:TPoint read GetCellGraphicSize;
    property CellImages[ACol,ARow: Integer]: TIntList read GetCellImages;
    property Ints[ACol,ARow: Integer]: Integer read GetInts write SetInts;
    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 ControlValues[ACol,ARow: Integer;ID: string]: string read GetCtrlVal write SetCtrlVal;
    property Delimiter:char read FDelimiter write FDelimiter;
    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 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 SortIndexes: TSortIndexList read FSortIndexes;
    property OriginalCellValue: string read FCellCache;
    property EditActive: Boolean read FEditActive;
    property NoImageAndText: Boolean read FNoImageAndText write FNoImageAndText;
    {$IFDEF DELPHI3_LVL}
    property DateTimePicker: TDateTimePicker read GetDateTimePicker;
    {$ENDIF}
    property Combobox: TGridCombo read EditCombo;
    property ClearTextOnly: Boolean read FClearTextOnly write FClearTextOnly;
    {$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 FRichEdit;
    property FooterCanvas: TCanvas read GetFooterCanvas;
    property InplaceRichEdit: TAdvRichEdit read FInplaceRichEdit;
    property IncrSearchText: string read SearchInc write SearchInc;
    property NormalEdit: TAdvInplaceEdit read GetInplaceEditor;
    property SearchPanel: TSearchPanel read FSearchPanel;
    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 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;
    property DisplCells[i,j: Integer]: string read GetFormattedCell;
    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 AllColWidths[i: Integer]: Integer read GetAllColWidths write SetAllColWidths;
    property AllColCount: Integer read GetAllColCount;
    property AllRowCount: Integer read GetAllRowCount;
    property Alignments[i,j: Integer]: TAlignment read GetAlignments write SetAlignments;
    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 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 CurrentCell:string read GetCurrentCell write SetCurrentCell;
    {$IFDEF DELPHI3_LVL}
    property ArrowColor: TColor read GetArrowColor write SetArrowColor;
    {$ENDIF}
    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 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 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 UseHTMLHints: Boolean read FUseHTMLHints write SetUseHTMLHints;
    property AutoNumberDirection: TSortDirection read FAutoNumberDirection write FAutoNumberDirection;
    property AutoNumberOffset: Integer read FAutoNumberOffset write FAutoNumberOffset;
    property AutoNumberStart: Integer read FAutoNumberStart write FAutoNumberStart;
    property OnPainted: TNotifyEvent read FOnPainted write FOnPainted;
    {$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}
  published
    property OnAutoAdvance: TAutoAdvanceEvent read FOnAutoAdvance
      write FOnAutoAdvance;
    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 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 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 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 OnPrintPageDone: TGridPrintPageDoneEvent read FOnPrintPageDone
      write FOnPrintPageDone;
    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 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 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 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 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 OnClipboardPaste:TClipboardEvent read FOnClipboardPaste
      write FOnClipboardPaste;
    property OnClipboardCopy:TClipboardEvent read FOnClipboardCopy
      write FOnClipboardCopy;
    property OnClipboardCut:TClipboardEvent read FOnClipboardCut
      write FOnClipboardCut;
    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 OnHasComboBox: THasComboEvent read FOnHasComboBox write FOnHasComboBox;
    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;
    {$IFDEF TMSUNICODE}
    property OnWideEllipsClick:TWideEllipsClickEvent read FOnWideEllipsClick
      write FOnWideEllipsClick;
    {$ENDIF}  
    property OnButtonClick:TButtonClickEvent read FOnButtonClick
      write FOnButtonClick;
    property OnCheckBoxClick:TCheckBoxClickEvent read FOnCheckBoxClick
      write FOnCheckBoxClick;
    property OnCheckBoxMouseUp:TCheckBoxClickEvent read FOnCheckBoxMouseUp
      write FOnCheckBoxMouseUp;
    property OnRadioClick:TRadioClickEvent read FOnRadioClick
      write FOnRadioClick;
    property OnRadioMouseUp:TRadioClickEvent read FOnRadioMouseUp
      write FOnRadioMouseUp;
    property OnDatePickerCloseUp: TClickCellEvent read FOnDatePickerCloseUp
      write FOnDatePickerCloseUp;  
    property OnComboChange:TComboChangeEvent read FOnComboChange
      write FOnComboChange;
    property OnComboCloseUp: TClickCellEvent read FOnComboCloseUp
      write FOnComboCloseUp;
    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 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 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 DragDropSettings: TDragDropSettings read FDragDropSettings write FDragDropSettings;
    {$IFDEF TMSGDIPLUS}
    property OfficeHint: TAdvHintInfo read FOfficeHint write SetOfficeHint;
    {$ENDIF}
    property HintColor: TColor read FHintColor write FHintColor default clInfoBk;
    {$IFDEF DELPHI3_LVL}
    property HintShowCells: Boolean read FHintShowCells write FHintShowCells default False;
    property HintShowLargeText: Boolean read FHintShowLargeText write FHintShowLargeText default False;
    property HintShowSizing: Boolean read FHintShowSizing write FHintShowSizing default False;
    property HTMLHint: Boolean read FHTMLHint write FHTMLHint default False;
    property OnScrollHint:TScrollHintEvent read FOnScrollHint write FOnScrollHint;
    {$ENDIF}
    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 OnSelectionResize: TSelectionResizeEvent read FSelectionResizeEvent write FSelectionResizeEvent;
    property OnSelectionResized: TSelectionResizeEvent read FSelectionResizedEvent write FSelectionResizedEvent;
    {$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 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 Balloon: TBalloonSettings read FBalloonSettings write SetBalloonSettings;
    property Bands:TBands read FBands write FBands;
    property BackGround:TBackground read FBackground write SetBackground;
    property CellNode: TCellNode read fCellNode write fCellNode;
    property CellChecker: TAdvStringGridCheck read FCellChecker write FCellChecker;
    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 DefaultEditor: TEditorType read FDefaultEditor write FDefaultEditor default edNormal;
    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 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 GridImages: TCustomImageList read FGridImages write SetImages;
    property Grouping: TGrouping read FGrouping write FGrouping;
    property HideFocusRect: Boolean read FHideFocusRect write FHideFocusRect default False;
    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 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 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 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 SizeWhileTyping: TSizeWhileTyping read FSizeWhileTyping write FSizeWhileTyping;
    property SizeWithForm: Boolean read FSizeWithForm write FSizeWithForm default False;
    property SortSettings: TSortSettings read FSortSettings write FSortSettings;
    property URLColor: TColor read FURLColor write SetURLColor default clBlue;
    property URLShow: Boolean read FURLShow write SetURLShow default False;
    property URLFull: Boolean read FURLFull write SetURLFull default False;
    property URLEdit: Boolean read FURLEdit write FURLEdit default False;
    property VAlignment: TVAlignment read FVAlignment write SetVAlignment default vtaTop;
    property Version: string read GetVersion write SetVersion stored false;
    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: TCellGraphic;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property CellGraphic: TCellGraphic 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;

implementation

{$IFDEF TMSDOTNET}
uses
  Types;
{$ENDIF}


const
  WM_THEMECHANGED = $031A;
  
  s_QuickConfig = 'Quick config';
  s_Gallery = 'Gallery';

  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}

  {$IFNDEF DELPHI6_LVL}
  WS_EX_LAYERED  = $00080000;
  {$EXTERNALSYM WS_EX_LAYERED}
  ULW_ALPHA      = $00000002;
  {$EXTERNALSYM ULW_ALPHA}
  {$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,'|','@','*','-','+','&');

var
  WideHintFontName: string;


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;

{$IFNDEF TMSDOTNET}
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;
{$ENDIF}

procedure TColumnSize.SetStretch(Value: Boolean);
begin
  FStretch := Value;
  if Assigned((Owner as TAdvStringGrid).Parent) then
    (Owner as TAdvStringGrid).StretchColumn(FStretchColumn);
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.DoExit;
begin
  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 <> #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 self.Value - self.Increment >= self.MinValue then
                self.Value := self.Value - self.Increment;
    sptFloat:if self.FloatValue - self.IncrementFloat >= self.MinFloatValue then
               self.FloatValue := self.FloatValue - self.IncrementFloat;
    end;
  VK_PRIOR:
    case SpinType of
    sptNormal:if self.Value - self.Increment <= self.MaxValue then
                self.Value := self.Value+self.increment;
    sptFloat:if self.FloatValue + self.IncrementFloat <= self.MaxFloatValue then
               self.FloatValue := self.FloatValue + self.IncrementFloat;
    end;
  VK_END:
    case SpinType of
    sptNormal:self.Value := self.MinValue;
    sptFloat:self.FloatValue := self.MinFloatValue;
    end;
  VK_HOME:
    case SpinType of
    sptNormal:self.Value := self.MaxValue;
    sptFloat:self.FloatValue := self.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;
      self.Text := FGrid.OriginalCellValue;

      case SpinType of
      sptNormal:
        begin
          val(self.Text, i, err);
          self.Value := i;
        end;
      sptFloat:
        begin
          val(self.Text, r, err);
          self.FloatValue := r;
        end;
      end;
    end;

    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.CurrentCell;
        self.SelStart := Length(self.Text);
        Repaint;
        Exit;
      end;
      //2.8.1
      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);


    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;
    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;

  {$IFNDEF TMSDOTNET}
  hwndEdit := FindWindowEx(Handle, 0,nil,nil);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  hwndEdit := FindWindowEx(Handle, 0,'','');
  {$ENDIF}

  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);
  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(FGrid.CurrentCell) <> -1 then
        ItemIndex := Items.IndexOf(FGrid.CurrentCell);
    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}


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 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
    if Assigned(FGrid.OnEditChange) then
      FGrid.OnEditChange(FGrid, FGrid.Col, FGrid.Row, Text);
end;

procedure TGridCombo.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
//  if (Char(Msg.CharCode) = #13) then Msg.Result := 1;
  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 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.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;

  {$IFNDEF TMSDOTNET}
  hwndEdit := FindWindowEx(Handle, 0,nil,nil);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  hwndEdit := FindWindowEx(Handle, 0,'','');
  {$ENDIF}

  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;
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(Self, FGrid.RealColIndex(FGrid.Col), FGrid.Row, ItemIndex, Text);
  end;
end;


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

procedure TGridCombo.KeyDown(var Key: Word; Shift: TShiftState);
var
  Condition: Boolean;
  ComboSelState: Boolean;
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]);

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

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

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

    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.CurrentCell;
        Self.SelStart := Length(Self.Text);
        Self.Repaint;
        Exit;
      end;

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

      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;

    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;

{ TGridDatePicker }

procedure TGridDatePicker.CNNotify(var Message: TWMNotify);
begin
  {$IFNDEF TMSDOTNET}
  with Message, NMHdr^ do
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  with Message, NMHdr do
  {$ENDIF}
  begin
    Result := 0;
    case code of
      DTN_CLOSEUP:FOldDropped := False;
      DTN_DROPDOWN:FOldDropped := True;
    end;
  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 (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

//{$IFDEF TMSDOTNET}
procedure TGridDatePicker.WndProc(var Message: TMessage);
var
  DC: HDC;
  arect: TRect;
  WindowBrush:hBrush;
begin
  inherited;
  
  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;
//{$ENDIF}

{$IFNDEF TMSDOTNET}
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;
{$ENDIF}

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

procedure TGridDatePicker.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridDatePicker.DoExit;
begin
  FGrid.HideInplaceEdit;
  inherited DoExit;
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 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 (goTabs in FGrid.Options) 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);
  end
  else
    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;
end;

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

procedure TGridEditBtn.ReCreate;
begin
  ReCreateWnd;
end;

procedure TGridEditBtn.WMPaste(var Msg:TMessage);
var
  {$IFNDEF DELPHI_UNICODE}
  Data: THandle;
  {$IFNDEF TMSDOTNET}
  Content: PChar;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Content: Integer;
  {$ENDIF}
  {$ENDIF}
  newstr: string;
  Allow: Boolean;

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
    {$IFNDEF TMSDOTNET}
    if Data <> 0 then
      Content := PChar(GlobalLock(Data))
    else
      Content := nil
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    if Data <> 0 then
      Content := Integer(GlobalLock(Data))
    else
      Content := 0;
    {$ENDIF}
  finally
    if Data <> 0 then
      GlobalUnlock(Data);
  ClipBoard.Close;
  end;

  {$IFNDEF TMSDOTNET}
  if Content = nil then
    Exit;
   Allow := True;
   NewStr := StrPas(Content);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  if Content <= 0 then
    Exit;

  Allow := True;
  NewStr := ClipBoard.AsText;
  {$ENDIF}

  {$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;

  inherited;
end;

procedure TGridEditBtn.WMChar(var Msg:TWMChar);
begin
  if (Msg.CharCode = ord(#13)) then
    Msg.Result :=0
  else
  case FGrid.EditControl of
  edEditBtn: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 Msg.CharCode in Float_Characters then
      begin
        {$IFNDEF TMSDOTNET}
        if ((Msg.CharCode = ord(DecimalSeparator)) and
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        if ((Msg.CharCode = ord(DecimalSeparator[1])) and
        {$ENDIF}
           ( (Pos(DecimalSeparator,self.Text) > 0) and (Pos(DecimalSeparator,self.SelText) = 0) )) then
          Exit;

        {$IFNDEF TMSDOTNET}
        if (Msg.CharCode = Ord(ThousandSeparator)) then
          Exit;
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        if (Msg.CharCode = Ord(ThousandSeparator[1])) then
          Exit;
        {$ENDIF}

        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 (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

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

  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
            FGrid.SetFocus;
            am := Navigation.AdvanceDirection;
            Navigation.AdvanceDirection := adLeftRight;
            AdvanceEdit(Col,Row,True,True,True,False, True);
            Navigation.AdvanceDirection := am;

            if Navigation.CursorWalkAlwaysEdit then
            begin
              {$IFDEF TMSDOTNET}
              FGrid.ShowInplaceEdit;
              {$ENDIF}
              {$IFNDEF TMSDOTNET}
              FGrid.ShowEditor;
              {$ENDIF}
            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;
          Navigation.AdvanceDirection := adLeftRight;
          AdvanceEdit(Col,Row,True,True,False,False, True);
          Navigation.AdvanceDirection := am;
          if Navigation.CursorWalkAlwaysEdit then
          begin
            {$IFDEF TMSDOTNET}
            FGrid.ShowInplaceEdit;
            {$ENDIF}
            {$IFNDEF TMSDOTNET}
            FGrid.ShowEditor;
            {$ENDIF}
          end;
        end;
      end;
    end;
  end;



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

end;

procedure TGridEditBtn.KeyDown(var Key: Word; Shift: TShiftState);
var
  s:string;
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);

  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);

    // 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.CurrentCell;
        SelStart := Length(Self.Text);
        Repaint;
        Exit;
      end;
      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 (goTabs in FGrid.Options) then
    begin
      FGrid.HideInplaceEdit;
      FGrid.SetFocus;
      FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
      Exit;
    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);
  end
  else
    inherited;
end;

{ TGridUnitEditBtn }

constructor TGridUnitEditBtn.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FGrid := AOwner as TAdvStringGrid;
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
    Msg.Result := 0
  else
    inherited;
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.Text;

      if not FGrid.ValidateCell(self.Text) then
      begin
        Self.Text := FGrid.CurrentCell;
        Exit;
      end;
      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 (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);
begin
  with (Parent as TAdvStringGrid) do
  begin
    Self.Caption := EllipsClick(Self.Caption);
    CurrentCell := self.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 TMouseActions.Create(AOwner: TComponent);
begin
  inherited Create;
  FGrid := AOwner as TAdvStringGrid;
  FAutoSizeColOnDblClick := True;
end;

destructor TMouseActions.Destroy;
begin
  inherited Destroy;
end;

procedure TMouseActions.SetHotmailRowSelect(const AValue: Boolean);
begin
  FHotmailRowSelect := AValue;
  FGrid.Invalidate;
end;

procedure TMouseActions.SetEditOnDblClickOnly(const AValue: Boolean);
begin
  FEditOnDblClickOnly := AValue;
  if AValue then // make sure to turn off normal editing
    FGrid.Options := FGrid.Options - [goEditing];
end;

procedure TMouseActions.SetDisjunctColSelect(const AValue: Boolean);
begin
  FDisjunctColSelect := AValue;

  if FDisjunctColSelect and (csDesigning in FGrid.ComponentState)  then
  begin
    FDisjunctRowSelect := False;
    FDisjunctCellSelect := False;
  end;

end;

procedure TMouseActions.SetDisjunctRowSelect(const AValue: Boolean);
begin
  FDisjunctRowSelect := AValue;

  if FDisjunctRowSelect and (csDesigning in FGrid.ComponentState) then
  begin
    FDisjunctColSelect := False;
    FDisjunctCellSelect := False;
  end;

end;

procedure TMouseActions.SetDisjunctCellSelect(const AValue: Boolean);
begin
  FDisjunctCellSelect := AValue;
  if FDisjunctCellSelect and (csDesigning in FGrid.ComponentState) then
  begin
    FDisjunctRowSelect := False;
    FDisjunctColSelect := False;
  end;
end;

procedure TMouseActions.Changed;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

procedure TMouseActions.SetWheelAction(const Value: TWheelAction);
begin
  if (FWheelAction <> Value) then
  begin
    FWheelAction := Value;
    Changed;
  end;
end;

constructor TCellGraphic.Create;
begin
  inherited Create;
  CellCreated := False;
  CellType := ctNone;
end;

destructor TCellGraphic.Destroy;
begin
  case CellType of
  {$IFNDEF TMSDOTNET}
  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;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  ctImages: CellList.Free;
  ctPicture: if CellCreated then CellPicture.Free;
  ctFilePicture: if CellCreated then CellFilePicture.Free;
  ctRadio: if CellCreated then CellStrings.Free;
  {$ENDIF}

  ctIcon: if CellCreated then CellIcon.Free;
  ctBitmap: if CellCreated then CellBitmap.Free;
  ctBitButton: if CellCreated then CellBitmap.Free;
  end;
  inherited Destroy;
end;

procedure TCellGraphic.Assign(Source: TPersistent);
begin
  FCellType := TCellGraphic(Source).CellType;
  FCellVAlign := TCellGraphic(Source).CellVAlign;
  FCellHAlign := TCellGraphic(Source).CellHAlign;
  FCellIndex := TCellGraphic(Source).CellIndex;
  FCellTransparent := TCellGraphic(Source).CellTransparent;
  FCellValue := TCellGraphic(Source).CellValue;
  FCellAngle := TCellGraphic(Source).CellAngle;
  FCellBoolean := TCellGraphic(Source).CellBoolean;
  FCellErrFrom := TCellGraphic(Source).CellErrFrom;
  FCellErrLen := TCellGraphic(Source).CellErrLen;
  FCellText := TCellGraphic(Source).CellText;
  FCellCreated := TCellGraphic(Source).CellCreated;

//  FCellBitmap: TBitmap read FCellBitmap write FCellBitmap;
//  FCellIcon: TIcon read FCellIcon write FCellIcon;
//  FCellCreated: Boolean read FCellCreated write FCellCreated;
end;

{$IFDEF DELPHI6_LVL}
procedure TCellGraphic.SetInterfacedCell(AObject:TInterfacedPersistent);
begin
  {$IFNDEF TMSDOTNET}
  CellBitmap := TBitmap(AObject);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  CellInterface := AObject;
  {$ENDIF}
  CellType := ctInterface;
end;
{$ENDIF}

procedure TCellGraphic.SetBitmap(ABmp:TBitmap;Transparent: Boolean;hal:TCellHAlign;val:TCellVAlign);
begin
  CellBitmap := ABmp;
  CellType := ctBitmap;
  CellHAlign := hal;
  CellVAlign := val;
  CellTransparent := Transparent;
end;

procedure TCellGraphic.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 TCellGraphic.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 TCellGraphic.SetPicture(APicture:TPicture; Transparent: Boolean;StretchMode:TStretchMode;padding: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctPicture;
  CellHAlign := hal;
  CellVAlign := val;
  {$IFDEF TMSDOTNET}
  CellPicture := APicture;
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  CellBitmap := TBitmap(APicture);
  {$ENDIF}
  CellTransparent := Transparent;
  CellAngle := Integer(StretchMode);
  CellIndex := padding;
end;

procedure TCellGraphic.SetFilePicture(APicture: TFilePicture; Transparent: Boolean;stretchmode:TStretchMode;padding: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctFilePicture;
  CellHAlign := hal;
  CellVAlign := val;
  {$IFDEF TMSDOTNET}
  CellFilePicture := APicture;
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  CellBitmap := TBitmap(APicture);
  {$ENDIF}
  CellTransparent := Transparent;
  CellAngle := Integer(StretchMode);
  CellIndex := padding;
end;

function TCellGraphic.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
    {$IFNDEF TMSDOTNET}
    ph := TPicture(CellBitmap).Height;
    pw := TPicture(CellBitmap).Width;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    ph := CellPicture.Height;
    pw := CellPicture.Width;
    {$ENDIF}
  end
  else
  begin
    {$IFNDEF TMSDOTNET}
    ph := TFilePicture(CellBitmap).Height;
    pw := TFilePicture(CellBitmap).Width;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    ph := CellFilePicture.Height;
    pw := CellFilePicture.Width;
    {$ENDIF}
  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 TCellGraphic.SetCheckBox(Value,Data,Flat: Boolean;hal:TCellHAlign;val:TCellVAlign);
begin
  if Data then
    CellType := ctDataCheckBox
  else
    CellType := ctCheckbox;

  CellBoolean := Value;
  CellHAlign := hal;
  CellVAlign := val;
  CellTransparent := Flat;
end;

procedure TCellGraphic.SetIcon(AIcon: TIcon;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctIcon;
  CellIcon := aicon;
  CellHAlign := hal;
  CellVAlign := val;
end;

procedure TCellGraphic.SetDataImage(idx: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctDataImage;
  CellIndex := idx;
  CellHAlign := hal;
  CellVAlign := val;
end;

procedure TCellGraphic.SetMultiImage(Col,Row,dir: Integer;hal:TCellHAlign;val:TCellVAlign;notifier:TImageChangeEvent);
{$IFDEF TMSDOTNET}
var
  il: TIntList;
{$ENDIF}
begin
  CellType := ctImages;
  CellHAlign := hal;
  CellVAlign := val;
  CellBoolean := dir = 0;
  {$IFDEF TMSDOTNET}
  il := TIntList.Create(Col,Row);
  CellList := il;
  il.OnChange := notifier;
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  CellBitmap := TBitmap(TIntList.Create(Col,Row));
  TIntList(CellBitmap).OnChange := notifier;
  {$ENDIF}
  CellCreated := True;
end;

procedure TCellGraphic.SetImageIdx(idx: Integer;hal:TCellHAlign;val:TCellVAlign);
begin
  CellType := ctImageList;
  CellIndex := idx;
  CellHAlign := hal;
  CellVAlign := val;
end;

procedure TCellGraphic.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;
end;

destructor TColumnSize.Destroy;
begin
  inherited Destroy;
end;

procedure TNavigation.Assign(Source: TPersistent);
begin
  if (Source is TNavigation) then
  begin
    FAllowInsertRow := (Source as TNavigation).AllowInsertRow;
    FAllowDeleteRow := (Source as TNavigation).AllowDeleteRow;
    FAlwaysEdit := (Source as TNavigation).AlwaysEdit;
    FAdvanceOnEnter := (Source as TNavigation).AdvanceOnEnter;
    FAdvanceInsert := (Source as TNavigation).AdvanceInsert;
    FAutoGotoWhenSorted := (Source as TNavigation).AutoGotoWhenSorted;
    FAutoGotoIncremental := (Source as TNavigation).AutoGotoIncremental;
    FAutoComboDropSize := (Source as TNavigation).AutoComboDropSize;
    FAdvanceDirection := (Source as TNavigation).AdvanceDirection;
    FAllowClipboardShortCuts := (Source as TNavigation).AllowClipboardShortcuts;
    FAllowCtrlEnter := (Source as TNavigation).AllowCtrlEnter;
    FAllowSmartClipboard := (Source as TNavigation).AllowSmartClipboard;
    FAllowRTFClipboard := (Source as TNavigation).AllowRTFClipboard;
    FAllowFmtClipboard := (Source as TNavigation).AllowFMTClipboard;
    FAllowClipboardAlways := (Source as TNavigation).AllowClipboardAlways;
    FAllowClipboardRowGrow := (Source as TNavigation).AllowClipboardRowGrow;
    FAllowClipboardColGrow := (Source as TNavigation).AllowClipboardColGrow;
    FAdvanceAuto := (Source as TNavigation).AdvanceAuto;
    FAppendOnArrowDown := (Source as TNavigation).AppendOnArrowDown;
    FEditSelectAll := (Source as TNavigation).EditSelectAll;
    FInsertPosition := (Source as TNavigation).InsertPosition;
    FCursorWalkEditor := (Source as TNavigation).CursorWalkEditor;
    FCursorWalkAlwaysEdit := (Source as TNavigation).CursorWalkAlwaysEdit;
    FMoveRowOnSort := (Source as TNavigation).MoveRowOnSort;
    FImproveMaskSel := (Source as TNavigation).ImproveMaskSel;
    FCopyHTMLTagsToClipboard := (Source as TNavigation).CopyHTMLTagsToClipboard;
    FKeepHorizScroll := (Source as TNavigation).KeepHorizScroll;
    FLineFeedOnEnter := (Source as TNavigation).LineFeedOnEnter;
    FHomeEndKey := (Source as TNavigation).HomeEndKey;
    FSkipFixedCells := (Source as TNavigation).SkipFixedCells;
    FTabToNextAtEnd := (Source as TNavigation).TabToNextAtEnd;
    FTabAdvanceDirection := (Source as TNavigation).AdvanceDirection;
    FLeftRightRowSelect := (Source as TNavigation).LeftRightRowSelect;
    FMoveScrollOnly := (Source as TNavigation).MoveScrollOnly;
  end;
end;

constructor TNavigation.Create;
begin
  inherited Create;
  FCopyHTMLTagsToClipboard := True;
  FAllowClipboardRowGrow := True;
  FAllowClipboardColGrow := True;
  FEditSelectAll := True;
  FSkipFixedCells := True;
  FAllowCtrlEnter := True;
  FCursorWalkAlwaysEdit := True;
  FLeftRightRowSelect := True;
end;

destructor TNavigation.Destroy;
begin
  inherited Destroy;
end;

procedure TNavigation.Changed;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

procedure TNavigation.SetAutoGoto(aValue: Boolean);
begin
  FAutoGotoWhenSorted:=aValue;
end;

procedure TNavigation.SetAdvanceDirection(const Value: TAdvanceDirection);
begin
  if (FAdvanceDirection <> Value) then
  begin
    FAdvanceDirection := Value;
    Changed;
  end;
end;

constructor THTMLSettings.Create;
begin
  inherited Create;
  FSaveColor := True;
  FSaveFonts := True;
  FBorderSize := 1;
  FCellSpacing := 0;
  FCellPadding := 0;
  FWidth := 100;
  FColWidths := TIntList.Create(0,0);
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;
    FHeaderFile := (Source as THTMLSettings).HeaderFile;
    FTableStyle := (Source as THTMLSettings).TableStyle;
    FPrefixTag := (Source as THTMLSettings).PrefixTag;
    FSuffixTag := (Source as THTMLSettings).SuffixTag;
    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;
  end;
end;

{ TPrintSettings }

constructor TPrintSettings.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AOwner;
  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;
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;
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;
  {$IFNDEF TMSDOTNET}
  Content: PChar;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Content: Integer;
  {$ENDIF}
  {$ENDIF}
  newstr: string;
  len: smallint;
  Newsl,Newss: 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;
    NewStr := ClipBoard.AsText;
  end;
  {$ENDIF}

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

  ClipBoard.Open;
  Data := GetClipBoardData(CF_TEXT);
  try
    {$IFNDEF TMSDOTNET}
    if Data <> 0 then
      Content := PChar(GlobalLock(Data))
    else
      Content := nil
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    if Data <> 0 then
      Content := Integer(GlobalLock(Data))
    else
      Content := 0;
    {$ENDIF}
  finally
    if Data <> 0 then
      GlobalUnlock(Data);
  ClipBoard.Close;
  end;

  {$IFNDEF TMSDOTNET}
  if Content = nil then
    Exit;

   Allow := True;
   NewStr := StrPas(Content);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  if Content <= 0 then
    Exit;

  Allow := True;
  NewStr := ClipBoard.AsText;
  {$ENDIF}

  {$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;

  NewStr := InsertString(NewStr);

  if (Length(NewStr) > FLengthLimit) and (FLengthLimit > 0) then
    Exit;

  case FGrid.EditControl of
  edNumeric,edPositiveNumeric:
    begin
      if IsType(Newstr) = atNumeric then
        self.Text := NewStr;
    end;
  edFloat:
    begin
      if IsType(NewStr) in [atNumeric,atFloat] 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;
end;


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

begin
  {$IFNDEF TMSDOTNET}
  SendMessage(Handle,EM_GETSEL,Integer(@se),Integer(@ss));
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  se := 0;
  ss := 0;
  Perform(EM_GETSEL,se,ss);
  {$ENDIF}

  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 (goTabs in FGrid.Options) then
    Msg.Result := 1;
end;

procedure TAdvInplaceEdit.WMKeyDown(var Msg:TWMKeydown);
var
  Key: Char;
  oldval, txt: string;
  updown: boolean;

begin
  FGrid.Edit_WMKeyDown(Msg);
  updown := false;
  FOldSelStart := SelStart;

  if Msg.CharCode = VK_ESCAPE then
  begin
    Self.Text := FGrid.OriginalCellValue;
    // **v2.8.7.5**
    FGrid.HideInplaceEdit;
  end;

  if (Msg.CharCode = VK_RETURN) and
     (GetKeyState(VK_CONTROL) and $8000 = $8000) and not FGrid.Navigation.AllowCtrlEnter then
  begin
    Msg.CharCode := 0;
    Msg.Result := 1;
    Exit;
  end;


  if (Msg.CharCode = VK_TAB) and (goTabs in FGrid.Options) then
  begin
    if not FGrid.ValidateCell(Self.Text) then
    begin
      self.Text := FGrid.CurrentCell;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(Text);
      Exit;
    end;

    self.Text := FGrid.CurrentCell;
    FGrid.HideInplaceEdit;
    FGrid.TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
    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
    txt := self.Text;

    FGrid.FValidating := true;
    FGrid.CurrentCell := txt;

    FGrid.FValidating := False;

    oldval := FGrid.FOldCellText;
    if not FGrid.ValidateCell(txt) then
    begin
      self.Text := oldval;
      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
    // 3.0.0.3
    txt := self.Text;

    FGrid.FValidating := true;
    FGrid.CurrentCell := txt;

    FGrid.FValidating := False;

    oldval := FGrid.FOldCellText;
    if not FGrid.ValidateCell(txt) then
    begin
      self.Text := oldval;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(txt);
      Repaint;
      FGrid.FOldCellText := oldval;
      Exit;
    end;
    //self.Text := FGrid.CurrentCell;
    // v3.3
    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
    // fix: 3.2.0.5
    //  self.Text := FGrid.CurrentCell; removed
    oldval := FGrid.FOldCellText;

    if not FGrid.ValidateCell(Self.Text) then
    begin
      self.Text := oldval;
      if FGrid.Navigation.EditSelectAll then
        SelectAll
      else
        SelStart := Length(Text);

      // Repaint;

      FGrid.FOldCellText := oldval;
      Exit;
    end;

    self.Text := FGrid.CurrentCell;
  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.ClearRowSelect;
      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(self.Handle,EM_POSFROMCHAR,SelStart - 1,0);
    pt.x := loword(i);
    pt.y := hiword(i);
    FGrid.EditProgress(self.Text,pt,SelStart);
  end;

  if pos('=',self.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;

begin
  if (Msg.CharCode = ord('.')) and
     FGrid.ExcelStyleDecimalSeparator and
     (Msg.KeyData and $400000 = $400000) then
  begin
    {$IFNDEF TMSDOTNET}
    Msg.CharCode := Ord(DecimalSeparator);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    Msg.CharCode := Ord(DecimalSeparator[1]);
    {$ENDIF}
  end;

  if (Msg.CharCode = 10) and
     (GetKeyState(VK_CONTROL) and $8000 = $8000) and not FGrid.Navigation.AllowCtrlEnter 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
    Exit;

  if (FGrid.EditControl in [edNormal,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: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);
  edPositiveNumeric:if msg.CharCode in Positive_Numeric_Characters then inherited else MessageBeep(0);
  edFloat:
    begin
      if msg.CharCode in Float_Characters then
      begin
        {$IFNDEF TMSDOTNET}
        if ((Msg.CharCode = ord(DecimalSeparator)) and
       {$ENDIF}
        {$IFDEF TMSDOTNET}
        if ((Msg.CharCode = ord(DecimalSeparator[1])) and
       {$ENDIF}
           ((pos(DecimalSeparator,self.Text) > 0) and (pos(DecimalSeparator,self.SelText) = 0) )) then
          Exit;

        {$IFNDEF TMSDOTNET}
        if (Msg.CharCode = ord(ThousandSeparator)) then
          Exit;
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        if (Msg.CharCode = ord(ThousandSeparator[1])) then
          Exit;
        {$ENDIF}

        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;
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;

  // 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.ValidateCell(Self.Text);
      Self.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;
  Self.Text := FGrid.CurrentCell;
  FGrid.FNoEditChange := false;
  FGrid.EditProgress(self.Text,Point(-1,-1),-1);
  FGrid.DoneEditing(FColE,FRowE);
end;

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

  FGrid.FNoEditChange := false;

  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);
end;

procedure TAdvInplaceEdit.CreateWnd;
begin
  inherited CreateWnd;

  //FGrid := Parent as TAdvStringGrid;
  if FGrid.EditControl = edPassword then
  begin
    SendMessage(Self.Handle, EM_SETPASSWORDCHAR, Ord(FGrid.PassWordChar), 0);
  end;

  FLengthLimit := FGrid.GetEditLimit;

  // v3.3.2.6
  // FGrid.FShowEditProcess := False;


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
  inherited UpdateContents;

  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);
    FColE := Col;
    FRowE := Row;

    if Assigned(OnGetEditorProp) then
      OnGetEditorProp(FGrid,Col,Row, nil);
  end;

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;
var
  r: TRect;
  //Hold: Integer;
  //dr: TRect;
begin
  inherited;

  r := FGrid.CellRect(FGrid.Col,FGrid.Row);

  Top := r.Top;
  Left := r.Left;

  if FGrid.UseRightToLeftAlignment then
  begin
    Left := Left + 1;
    //  dr := FGrid.CellRect(FGrid.LeftCol,FGrid.TopRow);
    //  Hold := r.Right - r.Left;
    //  r.Left := dr.Left - (r.Right - dr.Right);
    //  r.Right := r.Left + Hold;
  end;

  SetWindowPos(self.Handle, 0, r.Left, r.Top, r.Right - r.Left - 1, r.Bottom - r.Top - 1,
    SWP_NOREDRAW or SWP_NOZORDER or SWP_SHOWWINDOW);

  //Width := r.Right - r.Left - 1;
  //Height := r.Bottom - r.Top - 1;

  R := Rect(2, 2, Width - 2, Height);
  {$IFNDEF TMSDOTNET}
  SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@R));
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Perform(EM_SETRECTNP,0,R);
  {$ENDIF}
  SendMessage(Handle, EM_SCROLLCARET, 0, 0);
end;

procedure TAdvInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
var
  res1,res2: integer;
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 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
        if LinesInText(self.Text + #13#10 + ' ',FMultiLineCells) < MaxLinesInRow(Row) then
          AutoSizeRow(Row)
        else
          SizeToLines(Row,LinesInText(self.Text + #13#10 + ' ',FMultiLineCells),2 * FXYOffset.Y);

        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;
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
          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
            am := Navigation.AdvanceDirection;
            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;
        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
        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
            HideInplaceEdit;

          am := Navigation.AdvanceDirection;
          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;
      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
      AutoSizeRow(Row);

      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(self.Text) then
    begin
      self.Text := FGrid.CurrentCell;
      Key := #0;
      Exit;
    end;
  end;

  inherited KeyPress(Key);

  if FGrid.Navigation.AdvanceAuto then
  if (Pos(' ',self.Text) = 0) and (self.SelStart = Length(self.Text)) and
     (self.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.GetParentForm(Control: TControl): TCustomForm;
begin
  Result := nil;

  if Assigned(Control) then
    if Control is TCustomForm then
    begin
      Result := Control as TCustomForm;
      Exit;
    end else
    begin
      if Assigned(Control.Parent) then
        Result := GetParentForm(Control.Parent);
    end;
end;


function TAdvStringGrid.CreateEditor: TInplaceEdit;
begin
  Result := TAdvInplaceEdit.Create(Self);
end;

constructor TAdvStringGrid.Create(AOwner:TComponent);
var
  i: Integer;
  Scrollmsg: Integer;
  mshwheel: THandle;
  VerInfo: TOSVersioninfo;

begin
  inherited Create(AOwner);

  ControlStyle := ControlStyle + [csAcceptsControls];

  FFooterPanel := TFooterPanel.Create(Self);
  FFooterPanel.Align := alBottom;
  FFooterPanel.Height := 0;
  FFooterPanel.BorderWidth := 0;

  FSearchPanel := TSearchPanel.Create(Self);
  FSearchPanel.Align := alBottom;
  FSearchPanel.Height := 0;
  FSearchPanel.BorderWidth := 0;
  //FSearchPanel.DoubleBuffered := true;
  FSearchPanel.OnEditChange := SearchEditChange;
  FSearchPanel.OnBackwardClick := SearchBackward;
  FSearchPanel.OnForwardClick := SearchForward;
  FSearchPanel.OnExitClick := SearchExit;
  FSearchPanel.OnHighlightClick := SearchHighLight;

  FSearchFooter := TSearchFooter.Create(Self);
  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(Self);

  FSizeWhileTyping := TSizeWhileTyping.Create;
  FMouseActions := TMouseActions.Create(Self);
  FMouseActions.OnChange := OnMouseActionsChanged;
  FGrouping := TGrouping.Create;
  FColumnHeaders := TStringList.Create;
  FImageCache := THTMLPictureCache.Create;
  FColumnHeaders.OnChange := ColHeaderChanged;
  FLastValidation := true;
  FIsGrouping := false;
  FPaintCount := 0;

  FHoverFixedX := -1;
  FHoverFixedY := -1;
  FHoverFixedCells := hfNone;

  FXMLEncoding := 'ISO-8859-1';


  FOrigColSizes := TIntList.Create(-1,-1);

  FFixedFont := TFont.Create;
  FFixedFont.Name := 'Tahoma';
  FFixedFont.Style := [fsBold];

  FLoaded := false;
  FIsColChanging := false;

  //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;
  FActiveCellFont.Style := [fsBold];
  FActiveCellFont.OnChange := FixedFontChanged;
  FActiveCellColor := clGray;
  FActiveCellColorTo := clNone;
  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);
  FMergedColumns.OnChange := MergedColumnsChanged;
  FRowIndicator := TBitmap.Create;
  
  FBackground := TBackground.Create(Self);

  FScrollHintWnd := THTMLHintWindow.Create(Self);

  FScrollHintShow := False;
  FScrollbars := ssBoth;
  FDeselectState := False;
  FMouseDown := False;
  FCtrlDown := False;

  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;

  SearchTics := 0;

  RowCount := 10;
  Width := 400;
  Height := 250;

  FGridItems := TCollection.Create(TGridItem);
  FFilter := TFilter.Create(self);
  AutoSize := False;
  Invokedchange := False;
  {$IFDEF DELPHI3_LVL}
  FHintColor := clInfoBk;
  {$ELSE}
  FHintColor := clYellow;
  {$ENDIF}
  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;
  FSaveHiddenCells := False;
  FSaveVirtCells := True;
  FDisableChange := False;
  FFindBusy := False;
  FComboIdx := -1;
  FPrintPageFrom := 1;
  FPrintPageTo := 1;
  FPrintPageNum := 0;
  FPrinterDriverFix := False;
  FExcelClipboardFormat := False;
  FOnShowHint := nil;

  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;

  for i := 0 to MAXCOLUMNS 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));

  FIsFlat := False;
  FScrollType := ssNormal;
  FScrollColor := clNone;
  FScrollWidth := GetSystemMetrics(SM_CXVSCROLL);

  WheelMsg := 0;
  WheelScrl := 0;
  WheelPan := False;

  {$IFDEF TMSDOTNET}
  VerInfo.dwOSVersionInfoSize := Marshal.SizeOf(TypeOf(TOSVersionInfo));
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  {$ENDIF}

  GetVersionEx(verinfo);

  FIsWinXP := (verinfo.dwMajorVersion > 5) OR
    ((verinfo.dwMajorVersion = 5) AND (verinfo.dwMinorVersion >= 1));


  FIsWinVista := IsVista;


  i := GetFileVersion('COMCTL32.DLL');
  i := (i shr 16) and $FF;

  FIsComCtl6 := (i > 5);

  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
    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
  else {its win nt 4+ or Win98 ?}
  begin
    {$IFDEF TMSDEBUG}
    DbgMsg('Win NT 4 found or Win 98 found');
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,@i,0);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,i,0);
    {$ENDIF}
    wheelscrl := i;
    wheelmsg := WM_MOUSEWHEEL;
   end;

  FRichEdit := TAdvRichEdit.Create(Self);
  FInplaceRichEdit := TAdvRichEdit.Create(Self);
  FInplaceRichEdit.OnSelectionChange := RichSelChange;
  FNotifierList := TList.Create;
  FColumnOrder := TIntList.Create(0,0);

  FCellGraphic := TCellGraphic.Create;

  {$IFDEF TMSGDIPLUS}
  FOfficeHint := TAdvHintInfo.Create;
  {$ENDIF}

  FIgnoreColumns := TIntList.Create(-1,-1);

  FOldLeftCol := LeftCol;
  FOldTopRow := TopRow;

  if not (csDesigning in ComponentState) then
  begin
    {$IFDEF DELPHI3_LVL}
    ArwU := TArrowWindow.Init(Self,arrUp);
    ArwD := TArrowWindow.Init(Self,arrDown);
    ArwL := TArrowWindow.Init(Self,arrLeft);
    ArwR := TArrowWindow.Init(Self,arrRight);
    {$ENDIF}

    EditCombo := TGridcombo.Create(Self);
    EditCombo.Parent := Self;
    EditCombo.Enabled := False;
    EditCombo.Visible := False;
    EditCombo.IsWinXP := FIsWinXP;

    //v3.0.0.4: commented, WndProc is already handling this
    //EditCombo.OnChange := ComboChange;

    EditMode := False;
    EditControl := edNormal;

    EditSpin := TGridSpin.Create(Self);
    EditSpin.Parent := Self;
    EditSpin.Enabled := False;
    EditSpin.Visible := False;
    EditSpin.Borderstyle := bsNone;
    EditSpin.IsWinXP := FIsWinXP;

    EditTrans := TGridTransEdit.Create(Self);
    EditTrans.Parent := Self;
    EditTrans.Visible := False;
    EditTrans.BorderStyle := bsNone;

    {$IFDEF TMSUNICODE}
    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}

    if ComCtrlOk then
    begin
      EditDate := TGridDatePicker.Create(Self);
      // EditDate.Parent := Self;
      EditDate.Enabled := False;
      EditDate.Visible := False;
      EditDate.OnCloseUp := DatePickerCloseUp;

      EditDateTime := TAdvDateTimePicker.Create(Self);
      EDitDateTime.Enabled := False;
      EditDateTime.Visible := False;
      EditDateTime.OnCloseUp := DatePickerCloseUp;
      EditDateTime.OnTimeChange := DateTimePickerChange;
    end;

    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;

    Gridbutton := TGridbutton.Create(Self);
    Gridbutton.Parent := Self;
    Gridbutton.Enabled := False;
    Gridbutton.Visible := False;

    MoveButton := TPopupButton.Create(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;
  end;

  crURLCursor := crHandPoint;

  {$IFDEF FREEWARE}
  cla := self.ClassName;
  {$ENDIF}
end;

destructor TAdvStringGrid.Destroy;
var
  RCnt,CCnt: integer;
begin
  if (Owner is TForm) and not (csDesigning in ComponentState) then  // restore owner resize Handler
  begin
    (Owner as TForm).OnResize := FOnResize;
  end;

  BalloonDone;

  if FColumnSize.Save then
    SaveColSizes;
  FClearTextOnly := False;

  RCnt := RowCount;
  CCnt := ColCount;

  if (FNumNodes > 0) then
    ExpandAll;

  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;

  FIgnoreColumns.Free;
  FProgressAppearance.Free;
  FFloatingFooter.Free;
  FCellGraphic.Free;
  FControlList.Free;
  FSortRowXRef.Free;
  FUnSortRowXRef.Free;
  FMergedColumns.Free;
  FSelectedCells.Free;
  FSelectedRows.Free;
  FModifiedRows.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;
  //FScrollHintWnd.Free;
  FFooterPanel.Free;
  FSearchPanel.Free;
  FSearchFooter.Free;
  FBalloonSettings.Free;
  FShowModified.Free;
  FOrigColSizes.Free;

  {$IFDEF DELPHI3_LVL}
  if not (csDesigning in ComponentState) then
  begin
    ArwU.Free;
    ArwD.Free;
    ArwL.Free;
    ArwR.Free;
  end;
  {$ENDIF}

  SortList.Free;
  {$IFDEF TMSGDIPLUS}
  FOfficeHint.Free;
  {$ENDIF}

  FGridItems.Free;
  FFilter.Free;

  Cursor := FOldCursor;

  if not (csDesigning in ComponentState) then
  begin
    EditCombo.Free;
    EditSpin.Free;
    EditTrans.Free;
    {$IFDEF TMSUNICODE}
    EditUni.Free;
    MemoUni.Free;
    EditBtnUni.Free;
    FreeAndNil(ComboUni);
    {$ENDIF}

    if ComCtrlOk then
    begin
      EditDate.Free;
      EditDateTime.Free;
    end;

    EditCheck.Free;
    EditBtn.Free;
    UnitEditBtn.Free;
    Gridbutton.Free;
    MoveButton.Free;
    FEditControl.Free;
    FComboControl.Free;
  end;

  FRichEdit.Free;
  FInplaceRichEdit.Free;

  inherited Destroy;
end;

procedure TAdvStringGrid.DestroyWnd;
begin

  inherited DestroyWnd;
end;

procedure TAdvStringGrid.CreateWnd;
begin
  if (csDestroying in Componentstate) then
    Exit;

  inherited CreateWnd;

  if not (Parent is TWinControl) then Exit;

  if not (csDesigning in ComponentState) then
  begin
    EditDate.Parent := Self;
    EditDateTime.Parent := Self;
  end;

  FRichEdit.Parent := Self;
  FRichEdit.Visible := False;
  FRichEdit.Left := 0;
  FRichEdit.Top := 0;
  FRichEdit.Width := 0;
  FRichEdit.Height := 0;
  FRichEdit.BorderStyle := bsNone;
  SetTranspWindow(FRichEdit.Handle);

  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;

  //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;
    ActiveRowShow := (Source as TAdvStringGrid).ActiveRowShow;
    Align := (Source as TAdvStringGrid).Align;
    FAnchorHint := (Source as TAdvStringGrid).AnchorHint;
    FAutoNumAlign := (Source as TAdvStringGrid).AutoNumAlign;
    FAutoSize := (Source as TAdvStringGrid).AutoSize;
    FAutoThemeAdapt := (Source as TAdvStringGrid).AutoThemeAdapt;     
    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);
    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);

    {$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;

    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;

    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;
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) then
    ShowScrollbar(self.Handle, SB_VERT, (ScrollBarAlways in [saBoth, saVert]));

  if (VisibleColCount + FixedCols >= ColCount) 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
    EnableScrollBar(self.Handle, SB_VERT, ESB_ENABLE_BOTH);

  if (VisibleColCount + FixedCols < ColCount) then
    EnableScrollBar(self.Handle, SB_HORZ, ESB_ENABLE_BOTH);
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
    {$IFNDEF TMSDOTNET}
    FGridDropTarget.AcceptText := FOleAcceptText;
    FGridDropTarget.AcceptFiles := FOleAcceptFiles;
    FGridDropTarget.AcceptURLs := FOleAcceptURLs;
    {$ENDIF}
  end;

  case Look of
  glTMS:
    begin
      FTMSGradFrom := clSilver;
      FTMSGradTo := clWhite;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      if not (csDesigning in ComponentState) then
      begin
        MoveButton.GradFrom := FTMSGradFrom;
        MoveButton.GradTo := FTMSGradTo;
        MoveButton.GradMirrorFrom := FTMSGradMirrorFrom;
        MoveButton.GradMirrorTo := FTMSGradMirrorTo;
      end;
    end;
  end;

  if FColumnSize.Save then
    LoadColSizes;

  FFixedRowsMin := FixedRows;
  FFixedColsMin := FixedCols;

  MinRowHeight := DefaultRowHeight;
  MinColWidth := 10;

  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;

  if Balloon.Enable then
    BalloonInit;

  SearchFooter.AutoThemeAdapt := AutoThemeAdapt;
  SearchChanged(Self);

  UpdateScrollBars(false);

  if AutoThemeAdapt then
    ThemeAdapt;

  InitOrigColSizes;
end;

procedure TAdvStringGrid.DateTimePickerChange(Sender: TObject);
begin
  if Assigned(OnDateTimeChange) then
    OnDateTimeChange(Self, Col, Row, EditDateTime.DateTime);
end;

procedure TAdvStringGrid.DatePickerCloseUp(Sender: TObject);
begin
  if Assigned(FOnDatePickerCloseUp) then
    FOnDatePickerCloseUp(self, Row, Col);

  if MouseActions.DirectDateClose then
    HideInplaceEdit;
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 = 0) and (FixedCols > 0)) or
       ((Col = RACol) and (ARow = 0) 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,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): Boolean;
var
  AEditor: TEditorType;
begin
  Result := False;
  if Assigned(OnHasComboBox) then
    OnHasComboBox(Self,ACol,ARow,Result)
  else
  begin
    if ControlLook.DropDownAlwaysVisible then
    begin
      GetCellEditor(ACol,ARow,AEditor);
      {$IFNDEF TMSDOTNET}
      Result := AEditor in [edComboEdit, edComboList, edUniComboEdit, edUniComboList];
      {$ELSE}
      Result := AEditor in [edComboEdit, edComboList];
      {$ENDIF}
    end;
  end;
end;

function TAdvStringGrid.HasSpinEdit(ACol,ARow: Integer): Boolean;
var
  AEditor: 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
        AEditor := DefaultEditor;
        GetCellEditor(ACol,ARow,AEditor);
        Result := AEditor in [edSpinEdit, edFloatSpinEdit, edTimeSpinEdit, edDateSpinEdit];
      end;
    end;
  end;
end;


procedure TAdvStringGrid.GetCellEditor(ACol,ARow: Integer;var AEditor:TEditorType);
begin
  if Assigned(OnGetEditorType) then
    OnGetEditorType(Self,ACol,ARow,AEditor);
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;

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.DoCanEditCell(ACol,ARow: Integer; var CanEdit: boolean);
begin
  if Assigned(OnCanEditCell) then
    OnCanEditCell(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;
  end;

  DoCanEditCell(BC.X, BC.Y, IsReadOnly);
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;
begin
  AState := [];

  GetVisualProperties(ACol,ARow, AState, false, false, false, ABrush, AColorTo, AMirrorColor, AMirrorColorTo, AFont, HA, VA, WW, GD);

  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): Boolean;
begin
  Result := False;
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;
begin
  FColumnOrder.Clear;

  if pos('#',value) = 0 then
    Exit;

  UnHideColumnsAll;

  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
      NewPos := StrToInt(sl.Strings[i]);
      if (NewPos <> -1) then
        FColumnOrder.Add(NewPos);
    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;

  for i := 0 to ColCount - 1 do
  begin
    ColWidths[i] := StrToInt(sl.Strings[i]);
  end;

  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 := TIniFile.Create(FColumnSize.Key);

    with IniFile do
    begin
      for i := 0 to ColCount - 1 do
      begin
        WriteInteger(FColumnSize.section,'Col'+inttostr(i),ColWidths[i]);
      end;
    end;
    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 := TIniFile(tIniFile.Create(FColumnSize.Key));

    with IniFile do
    begin
      for i := 0 to ColCount - 1 do
      begin
        NewWidth := ReadInteger(FColumnSize.Section,'Col'+inttostr(i),ColWidths[i]);
        if (NewWidth <> ColWidths[i]) then
        begin
          ColWidths[i] := NewWidth;
        end;
      end;
    end;
    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 := TIniFile.Create(FColumnSize.Key);

    with IniFile do
    begin
      for i := 1 to FColumnOrder.Count do
      begin
        WriteInteger(FColumnSize.section,'Pos'+inttostr(i-1),FColumnOrder.Items[i - 1]);
      end;
    end;
    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 := TIniFile(TIniFile.Create(FColumnSize.Key));

    with IniFile do
    begin
      NewPos := ReadInteger(FColumnSize.Section,'Pos0',-1);

      if NewPos <> -1 then
      begin
        FColumnOrder.Clear;

        for i := 0 to AllColCount - 1 do
        begin
          NewPos := 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 := ReadInteger(FColumnSize.Section,'Pos'+inttostr(i),-1);
          if (NewPos <> -1) then
            FColumnOrder.Add(NewPos);
        end;


      end;
    end;
    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);
  Reset(f);
  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']);

    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;

    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']);

  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);
  Rewrite(f);
  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);
  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);

  case Look of
    glStandard:  WriteString('Look','glStandard');
    glSoft:      WriteString('Look','glSoft');
    glClassic:   WriteString('Look','glClassic');
    glTMS:       WriteString('Look','glTMS');
    glXP:        WriteString('Look','glXP');
    glListView:  WriteString('Look','glListView');
    glVista:     WriteString('Look','glVista');
  end;

  //-- 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);
  //-- end BackGround

  sl.Free;
  CloseFile(f);
end;

procedure TAdvStringGrid.SavePrintSettings(Key,Section:string);
var
  IniFile: TIniFile;

  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 := TIniFile.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,'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,'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.Free;
end;

procedure TAdvStringGrid.LoadPrintSettings(Key,Section:string);
var
  IniFile: TIniFile;

  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 := TIniFile.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.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','');

  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.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.Free;
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;
    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(sl);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    CellStrings := sl;
    {$ENDIF}
  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;
    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(TStringList.Create);
    Result := TStrings(CellBitmap);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    CellStrings := TStringList.Create;
    Result := CellStrings;
    {$ENDIF}
    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;
  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;

  {$IFNDEF TMSDOTNET}
  if cg.CellType = ctRadio then
    Result := TStrings(cg.CellBitmap);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  if cg.CellType = ctRadio then
    Result := TStrings(cg.CellStrings);
  {$ENDIF}
end;

function TAdvStringGrid.IsRadio(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 = ctRadio;
end;

procedure TAdvStringGrid.RemoveRadio(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctRadio);
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
  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: Integer;

begin
  ExpandNodeInt(ARow);
  dr := DisplRowIndex(ARow);

  for i := 1 to GetNodeSpan(dr) 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 := 0;

      k := i + k;
      i := RemapRow(i);
      RemoveCellGraphic(0,i,ctNode);
      if (FNumNodes > 0) then
        Dec(FNumNodes);
      i := k;  
    end
    else
      inc(i);
  end;
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: integer;
begin
  lvl := GetNodeLevel(Arow);
  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;

  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);
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.ExpandAll;
var
  i: Integer;
  cg: TCellGraphic;
begin
  UnHideRowList;

  for i := FixedRows to RowCount - 1 do
    if IsNode(i) then
    begin
      cg := GetCellGraphic(0,i);
      cg.CellBoolean := False;
    end;
  CalcFooter(-1);
end;


procedure TAdvStringGrid.ContractAll;
var
  i,j: Integer;
  il: TIntList;
  cg: TCellGraphic;
begin
  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;

        for j := 1 to GetNodeSpan(i) - 1 do
          il.Add(i + j);

        i := i + GetNodeSpan(i);
      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: Integer;
  cg: TCellGraphic;
  tr,cr: Integer;
  rs: boolean;
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;

  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);

  {$IFDEF TMSDEBUG}
  outputdebugstring(pchar('unhide rows: '+inttostr(i+1)+' to '+inttostr(j-1)));
  {$ENDIF}

  tr := TopRow;
  cr := Row;

  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
    if FNumCellControls = 0 then
      EndUpdate;
  end;

  CalcFooter(-1);
end;

procedure TAdvStringGrid.ContractNode(ARow: Integer);
var
  i,j,k,d: Integer;
  cg:TCellGraphic;

begin
  HideInplaceEdit;

  ARow := RemapRow(ARow);
  cg := GetCellGraphic(0,ARow);
  if cg = nil then
    Exit;

  if (cg.CellType = ctNode) and (cg.CellBoolean = False) then
    cg.CellBoolean := True
  else
    Exit;

  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;

        {$IFDEF TMSDEBUG}
        outputdebugstring(pchar('span:'+inttostr(cg.CellIndex)));
        outputdebugstring(pchar('hide:'+inttostr(remaprowinv(j))+'->'+inttostr(remaprowinv(k))));
        {$ENDIF}

        d := k - j + 1;

        {$IFDEF TMSDEBUG}
        outputdebugstring(pchar('delta:'+inttostr(d)+':'+inttostr(k + 1 - d)));
        {$ENDIF}

        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;


  {$IFDEF TMSDEBUG}
  outputdebugstring(pchar('last hide:'+inttostr(j)+'->'+inttostr(k-1)));
  outputdebugstring(pchar('last hide:'+inttostr(remaprowinv(j))+'->'+inttostr(remaprowinv(k-1))));
  DebugHiddenRows;
  {$ENDIF}

  HideRows(RemapRowinv(j),RemapRowInv(k - 1));

  // 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
  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(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;
  }
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;

{$IFDEF DELPHI6_LVL}
procedure TAdvStringGrid.AddInterfacedCell(ACol,ARow: Integer; AObject: TInterfacedPersistent);
begin
  with CreateCellGraphic(ACol,ARow) do
    SetInterfacedCell(AObject);
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
  {$IFNDEF TMSDOTNET}
  Result := TInterfacedPersistent(cg.CellBitmap);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Result := cg.CellInterface;
  {$ENDIF}
end;
{$ENDIF}

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
    SetBitmap(abmp,transparent,hal,val);
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.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
  {$IFNDEF TMSDOTNET}
    Result := TPicture(cg.CellBitmap);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
    Result := cg.CellPicture;
  {$ENDIF}
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
    SetFilePicture(AFilePicture,transparent,stretchmode,padding,hal,val);
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.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
  {$IFDEF TMSDOTNET}
    Result := cg.CellFilePicture;
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
    Result := TFilePicture(cg.CellBitmap);
  {$ENDIF}
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.AddIcon(ACol,ARow: Integer;AIcon:TIcon;hal:TCellHalign;val:TCellValign);
begin
  with CreateCellGraphic(ACol,ARow) do
    SetIcon(AIcon,hal,val);
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;
    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(Color);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    CellColor := Color;
    {$ENDIF}
    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;

procedure TAdvStringGrid.AddProgress(ACol,ARow: Integer;FGColor,BkColor: TColor);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctProgress;

    CellHAlign := haLeft;
    CellVAlign := vaTop;

    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(FGColor);
    CellIcon := TIcon(BKColor);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    CellColor := FGColor;
    CellBkColor := BKColor;
    {$ENDIF}
    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;
    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(FGColor);
    CellIcon := TIcon(BKColor);
    CellIndex := TColor(FGTextColor);
    CellAngle := TColor(BKTextColor);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    CellColor := FGColor;
    CellBKColor := BKColor;
    CellTextFGColor := FGTextColor;
    CellTextBKColor := BKTextColor;
    {$ENDIF}

    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;
    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(FGColor);
    CellIcon := TIcon(BKColor);
    CellIndex := TColor(FGTextColor);
    CellAngle := TColor(BKTextColor);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    CellColor := FGColor;
    CellBKColor := BKColor;
    CellTextFGColor := FGTextColor;
    CellTextBKColor := BKTextColor;
    {$ENDIF}

    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;

    {$IFNDEF TMSDOTNET}
    CellBitmap := TBitmap(NegColor);
    CellIcon := TIcon(PosColor);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    CellColor := NegColor;
    CellBKColor := PosColor;
    {$ENDIF}

    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
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctComment;
    CellHAlign := haLeft;
    CellVAlign := vaTop;
    CellText := Comment;
    {$IFNDEF TMSDOTNET}
    CellAngle := clNone;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    CellColor := clNone;
    {$ENDIF}
  end;
end;

procedure TAdvStringGrid.AddColorComment(ACol,ARow: Integer; Comment:string; Color: TColor);
begin
  with CreateCellGraphic(ACol,ARow) do
  begin
    CellType := ctComment;
    CellHAlign := haLeft;
    CellVAlign := vaTop;
    CellText := Comment;
    {$IFNDEF TMSDOTNET}
    CellAngle := Color;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    CellColor := Color;
    {$ENDIF}
  end;
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
    if cg.CellType = ctComment then
    begin
      cg.CellText := value;
    end;
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.CellType = ctComment;
  if Result then
    Comment := cg.CellText;
end;

procedure TAdvStringGrid.RemoveComment(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctComment);
end;

procedure TAdvStringGrid.RemoveAllComments;
var
  i,j: Integer;
  s: string;
begin
  for i := 0 to ColCount - 1 do
    for j := 0 to RowCount - 1 do
    begin
      if IsComment(i,j,s) then
        RemoveCellGraphic(i,j, ctComment);
    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
    SetBitButton(bw,bh,Caption,Glyph,hal,val);
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
    SetButton(bw,bh,caption,hal,val);
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.RemoveButton(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctButton);
  RemoveCellGraphic(ACol,ARow,ctBitButton);
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;
var
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] in [ctButton,ctBitButton]);
end;

function TAdvStringGrid.ButtonRect(ACol,ARow: Integer):TRect;
var
  l: Integer;
  cg: TCellGraphic;
  cr: TRect;

begin
  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: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    AddCheckBox(ACol,i,DefaultState,DataCheckBox);
  end;
end;

procedure TAdvStringGrid.RemoveCheckBoxColumn(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    if HasCheckBox(Acol,i) then
      RemoveCheckBox(ACol,i);
  end;
end;


procedure TAdvStringGrid.AddCheckBox(ACol,ARow: Integer;state,data: Boolean);
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,Data,True,haBeforeText,vaTop);
    vtaCenter: SetCheckBox(state,Data,True,haBeforeText,vaCenter);
    vtaBottom: SetCheckBox(state,Data,True,haBeforeText,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;
begin
  cg := GetCellGraphic(ACol,ARow);
  if cg = Nil then
    Exit;
  if cg.CellType in [ctCheckBox,ctDataCheckBox] then
  begin
    FreeCellGraphic(ACol,ARow);
    RepaintCell(ACol,ARow);
  end;
end;

function TAdvStringGrid.IsInCheckBox(ACol,ARow,XPos,YPos: Integer): Boolean;
var
  cg: TCellGraphic;
  r,cr: TRect;
begin
  Result := false;
  cg := GetCellGraphic(ACol,ARow);
  if cg = Nil then
    Exit;

  if cg.CellType in [ctCheckBox,ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox] 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: r.Left := cr.Right - 2 - ControlLook.CheckSize;
      end;

      r.Right := r.Left + ControlLook.CheckSize;

      Result := PtInRect(r,point(xpos,ypos));
    end;
  end;
end;

function TAdvStringGrid.HasCheckBox(ACol,ARow: Integer): Boolean;
var
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] in [ctCheckBox,ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox]);
end;

function TAdvStringGrid.HasDataCheckBox(ACol,ARow: Integer): Boolean;
var
  BC: TPoint;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] in [ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox]);
end;

procedure TAdvStringGrid.QueryAddRow(var AllowAdd: Boolean);
begin
  if Assigned(OnCanAddRow) then
    OnCanAddRow(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;
begin
  BC := BaseCell(ACol,ARow);
  Result := (CellTypes[BC.X,BC.Y] in [ctCheckBox,ctDataCheckBox,ctVirtCheckBox,ctRadio,ctButton,ctRowCheckBox]);
end;

function TAdvStringGrid.IsChecked(ACol,ARow: integer): boolean;
begin
  GetCheckBoxState(ACol,ARow,Result);
end;

function TAdvStringGrid.GetCheckBoxState(ACol,ARow: Integer;var State: Boolean): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;

begin
  Result := False;

  if (NumHiddenRows > 0) then
  begin
    //r := RealRowIndex(Arow);
    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 = 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 in [ctDataCheckBox,ctVirtCheckBox]) then
      begin
        State := Cells[ACol,ARow] = GetCheckTrue(ACol,ARow);
        Result := True;
      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: Boolean): Boolean;
var
  cg: TCellGraphic;
  cp: TCellProperties;

begin
  Result := False;
  cg := nil;

  if (NumHiddenRows > 0) then
  begin
    cp := TCellProperties(GetAllGraphicsObject(ACol,ARow));
    if Assigned(cp) then
      cg := TCellGraphic(GetCPGraphicObject(cp));
  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 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.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
    {$IFNDEF TMSDOTNET}
      NewIdx := TStrings(cg.CellBitmap).IndexOf(Cells[ACol,ARow]) + 1;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
      NewIdx := cg.CellStrings.IndexOf(Cells[ACol,ARow]) + 1;
    {$ENDIF}

    {$IFNDEF TMSDOTNET}
    if NewIdx >= TStrings(cg.CellBitmap).Count then
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    if NewIdx >= cg.CellStrings.Count then
    {$ENDIF}
      NewIdx := 0;
    if cg.CellIndex >= 0 then
      cg.CellIndex := NewIdx;

    cg.CellVar := NewIdx;

    {$IFNDEF TMSDOTNET}
    Cells[ACol,ARow] := TStrings(cg.CellBitmap).Strings[NewIdx];
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    Cells[ACol,ARow] := cg.CellStrings.Strings[NewIdx];
    {$ENDIF}
  end;

end;

procedure TAdvStringGrid.CheckAll(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
    SetCheckBoxState(Acol,i, true);
end;

procedure TAdvStringGrid.UnCheckAll(ACol: Integer);
var
  i: integer;
begin
  for i := FixedRows to RowCount - 1 do
    SetCheckBoxState(Acol,i, false);
end;

function TAdvStringGrid.ToggleCheck(ACol,ARow: Integer; FromEdit: Boolean): Boolean;
var
  cg: TCellGraphic;
  Canedit: Boolean;
  RColI: Integer;

begin
  Result := False;

  cg := GetCellGraphic(ACol,ARow);
  if cg = nil then
    Exit;

  if cg.CellType in [ctCheckBox,ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox] then
  begin
    if FromEdit and not ControlLook.CheckAlwaysActive then
    begin
      CanEdit := True;
      GetCellReadOnly(ACol,ARow,CanEdit);
      if not CanEdit then Exit;
    end;

    if cg.CellType = ctCheckBox then
      cg.CellBoolean := not cg.CellBoolean
    else
    begin
      if (Cells[ACol,ARow] = GetCheckTrue(ACol,ARow)) then
        Cells[ACol,ARow] := GetCheckFalse(ACol,ARow)
      else
        Cells[ACol,ARow] := GetCheckTrue(ACol,ARow);
    end;

    RColI := RemapColInv(ACol);

    RepaintCell(RColI,ARow);
    Result := True;

    if Assigned(UndoRedo) then
    begin
      if 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.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
    with GetCellGraphic(ACol,ARow) do
    begin
      Idx := CellIndex;
    end;
    Result := True;
  end;
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);
  end;
end;

procedure TAdvStringGrid.RemoveDataImage(ACol,ARow: Integer);
begin
  RemoveCellGraphic(ACol,ARow,ctDataImage);
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
  if CellTypes[ACol,ARow] = ctImages then
  begin
    GetCellGraphic(ACol,ARow).Free;
    RepaintCell(ACol,ARow);
  end;
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
  FURLColor := Value;
  if FURLShow then
    Invalidate;
end;

procedure TAdvStringGrid.SetURLShow(Value: Boolean);
begin
  FURLShow := Value;
  Invalidate;
end;

procedure TAdvStringGrid.SetURLFull(Value: Boolean);
begin
  FURLFull := Value;
  if FURLShow then
    Invalidate;
end;

procedure TAdvStringGrid.SetLook(Value: TGridLook);
begin
  if FLook <> Value then
  begin
    FLook := Value;

    if Value = glVista then
      SetStyle(gsWindowsVista)
    else
    begin
      FTMSGradFrom := clWhite;
      FTMSGradTo := clBtnFace;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      GridFixedLineColor := clGray;
      ControlLook.FixedGradientFrom := clWhite;
      ControlLook.FixedGradientTo := clBtnFace;
      ControlLook.FixedGradientMirrorFrom := clNone;
      ControlLook.FixedGradientMirrorTo := clNone;
      GridFixedLineColor := clGray;
    end;

    Invalidate;
    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);
var
  nc,nr: Integer;

begin
  if ColIndex >= ColCount then Exit;
  if RowIndex >= RowCount then Exit;

  nc := LeftCol;
  nr := TopRow;
  if (ColIndex < LeftCol) or (ColIndex >= LeftCol + VisibleColCount) then
  begin
    Col := ColIndex;
    nc := ColIndex - (VisibleColCount shr 1);
    if nc < FixedCols then nc := FixedCols;
  end;

  if (RowIndex < TopRow) or (RowIndex >= TopRow + VisibleRowCount) then
  begin
    Row := RowIndex;
    nr := RowIndex - (VisibleRowCount shr 1);
    if nr < FixedRows then nr := FixedRows;
  end;

  if nc > ColCount - (VisibleColCount - 1) then // - 1 to avoid partially visible last column
    nc := ColCount - (VisibleColCount - 1);

  LeftCol := nc;

  if nr > RowCount - (VisibleRowCount - 1) then // -1 to avoid partially visible last row
    nr := RowCount - (VisibleRowCount - 1);

  TopRow := nr;
end;

procedure TAdvStringGrid.MoveColumn(FromIndex, ToIndex: Integer);
var
  i: integer;
begin
  if FColumnOrder.Count = 0 then
    SetColumnOrder;

  ColumnMoved(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].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;
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;

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;

procedure TAdvStringGrid.HideSelection;
begin
  FOldSelection := Selection;
  Selection := TGridRect(Rect(ColCount,RowCount,ColCount,RowCount));
  FSelHidden := True;
end;

procedure TAdvStringGrid.HideColumn(Colindex: Integer);
begin
  HideColumns(Colindex,Colindex);
end;

procedure TAdvStringGrid.HideColumns(FromCol,ToCol: Integer);
var
  i,j: Integer;
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);
      ColCount := ColCount - 1;
    end;
  end;
  Invalidate;
end;

procedure TAdvStringGrid.UnHideColumn(Colindex: Integer);
begin
  UnHideColumns(Colindex,Colindex);
end;

procedure TAdvStringGrid.UnHideColumnsAll;
begin
  UnHideColumns(0,ColCount + FNumHidden);
end;

procedure TAdvStringGrid.UnHideColumns(FromCol,ToCol: Integer);
var
  i,j: 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];

      ColWidths[RemapColinv(j)] := FAllColWidths[j];
    end;
  end;
  Invalidate;
end;

function TAdvStringGrid.IsHiddenColumn(Colindex: Integer): Boolean;
begin
  if (ColIndex < MAXCOLUMNS) 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;
begin
  i := 0;
  k := 0;

  while (k <= ARow) do
  begin
    if not IsHiddenRow(i) then Inc(k);
    Inc(i);
  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);
end;

procedure TAdvStringGrid.GroupAvg(Colindex: Integer);
begin
  GroupCalc(Colindex,2);
end;

procedure TAdvStringGrid.GroupMin(Colindex: Integer);
begin
  GroupCalc(Colindex,3);
end;

procedure TAdvStringGrid.GroupMax(Colindex: Integer);
begin
  GroupCalc(Colindex,4);
end;

procedure TAdvStringGrid.GroupCount(Colindex: Integer);
begin
  GroupCalc(Colindex,5);
end;

procedure TAdvStringGrid.GroupCustomCalc(Colindex: Integer);
begin
  GroupCalc(Colindex,6);
end;

procedure TAdvStringGrid.GroupCalc(Colindex,Method: Integer);
var
  i,j,k: Integer;
begin
  i := FixedRows;
  while (i < RowCount) do
  begin
    if IsNode(i) then
    begin
      if not NodeState[i] then
      begin
        j := i + GetNodeSpan(i);

        if Grouping.Summary then
          k := i + GetNodeSpan(i)
        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] := ColumnCustomCalc(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 := #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 := #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.Group(Colindex: Integer);
var
  i,np: Integer;
  lc,nc: string;
  grp,grpc: Integer;
begin
  if (Colindex < FixedCols) then
    Exit;


  if FGroupColumn <> -1 then
    UnGroup;

  if (RowCount - FixedRows < 1) then
    Exit;

  BeginUpdate;

  FIsGrouping := true;

  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};

    // 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 := #255#254;

    i := FixedRows;

    while i <= RowCount - 1 - FFixedFooters do
    begin
      nc := Cells[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 := Cells[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 - 1)) 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;

    Row := FixedRows;
  finally
    FIsGrouping := false;
    EndUpdate;
  end;
end;

procedure TAdvStringGrid.UnGroup;
var
  i,j: Integer;
  nc: string;
  grpc: Integer;
begin
  if FGroupColumn <= 0 then
    Exit;

  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);
        IRemoveRows(i + j,1,false);
      end;

      nc := Cells[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;
  Invalidate;
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;

  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
    Exit;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  for j := FromRow to ToRow do
  begin
    {$IFDEF TMSDOTNET}
    if rlist.IndexOf(TObject(j)) = -1 then
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    if rlist.IndexOf(Pointer(j)) = -1 then
    {$ENDIF}
    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: integer;
  il: TIntList;
begin
  il := TIntList.Create(-1,-1);
  for i := 1 to RowCount do
    il.Add(RowHeights[i - 1]);

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  for i := 1 to RowList.Count do
  begin
    with (FGridItems.Add as TGridItem) do
    begin
      Items.Assign(Rows[ RowList.Items[i - 1]]);
      Idx := RowList.Items[i - 1];
      Height := RowHeights[RowList.Items[i - 1]];
    end;
  end;

  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: Integer;
begin
  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  k := FGridItems.Count - 1;

  l := 1;
  if FloatingFooter.Visible then
    l := 2;

  j := RowCount - l;

  RowCount := RowCount + FGridItems.Count;

  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)  then
      begin
        Rows[i].Assign(Rows[j]);
        RowHeights[i] := RowHeights[j];
        dec(j);
      end;
    end;
  end;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  FGridItems.Clear;
  CellControlsUpdate;
end;


procedure TAdvStringGrid.UnHideRow(Rowindex: Integer);
var
  j,k,l: Integer;
  flg: Boolean;
  ci: TControlItem;
begin
  k := RowIndex;
  Flg := False;
  l := 0;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  // 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
    InsertRows(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;

  CellControlsUpdate;
end;

procedure TAdvStringGrid.UnHideRows(FromRow,ToRow: Integer);
var
  i,j,k,l: Integer;
  Flg: Boolean;
  Num: Integer;
  r: TRect;
begin
  k := FromRow;
  Flg := False;

  if FNumHidden > 0 then
    ColCount := ColCount + FNumHidden;

  // 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 Num > 0 then
    begin
      InsertRows(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;

  if FNumHidden > 0 then
    ColCount := ColCount - FNumHidden;

  CellControlsUpdate;
end;


function TAdvStringGrid.IsHiddenRow(Rowindex: Integer): Boolean;
var
  j: Integer;

begin
  Result := False;
  if FGriditems.Count = 0 then
    Exit;
  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.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.GetRowEx: Integer;
begin
  Result := inherited Row;
end;

procedure TAdvStringGrid.SetRowEx(const Value: Integer);
begin
  inherited Row := Value;
  if (FOldRowSel <> Row) and Assigned(FOnRowChanged) {and (FUpdateCount = 0)} then
  begin
    FOnRowChanged(Self,FOldRowSel,Row);
    FOldRowSel := Row;
  end;  
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
  FVisibleCol[i] := AValue;
end;

function TAdvStringGrid.GetVisibleCol(i: Integer): Boolean;
begin
  Result := FVisibleCol[i];
end;

function TAdvStringGrid.RemapColInv(ACol: Integer): Integer;
var
  i: Integer;
  RemapValue: Integer;
begin
  if (ACol >= MAXCOLUMNS) 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 >= MAXCOLUMNS) or (FNumHidden = 0) then
  begin
    RemapCol := ACol;
    Exit;
  end;

  RemapValue := 0;
  RemapCol := 0;
  i := 0;

  while i < MAXCOLUMNS 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.GetSaveStartCol: Integer;
begin
  if FSaveFixedCells then
    Result := 0
  else
    Result := FixedCols;
end;

function TAdvStringGrid.GetSaveStartRow: Integer;
begin
  if FSaveFixedCells then
    Result := 0
  else
    Result := FixedRows;
end;

function TAdvStringGrid.GetSaveEndCol: Integer;
begin
  if FSaveFixedCells then
    Result := ColCount - 1
  else
    Result := ColCount - FFixedRightCols - 1;
end;

function TAdvStringGrid.GetSaveEndRow: Integer;
begin
  if FSaveFixedCells then
    Result := RowCount - 1
  else
    Result := RowCount - FFixedFooters - 1;
end;

function TAdvStringGrid.GetSaveColCount: Integer;
begin
  if FSaveFixedCells then
    Result := ColCount
  else
    Result := ColCount - FixedCols - FFixedRightCols;
end;

function TAdvStringGrid.GetSaveRowCount: Integer;
begin
  if FSaveFixedCells 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);
begin
  DoCalcFooter(ACol);
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);
          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.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;
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;
  {$IFDEF TMSDOTNET}
  ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  {$ENDIF}
  GetScrollInfo(Handle,SB_VERT,ScrollInfo);


  if FScrollProportional and (1 < 0) then
  begin
    Scrollinfo.FMask := SIF_ALL;
    {$IFDEF TMSDOTNET}
    ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    ScrollInfo.cbSize := SizeOf(ScrollInfo);
    {$ENDIF}
    if (ScrollInfo.npos > 127) or (Scrollinfo.npos < 0) then
      ScrollInfo.npos := 0;
    ScrollInfo.nmax := 127;
    ScrollInfo.nmin := 0;
    ScrollInfo.npage := Round(128 * VisibleRowCount / RowCount);
    //scrollinfo.npos:=round((128-scrollinfo.npage)*(scrollinfo.npos/127));
  end;

  FlatSetScrollInfo(SB_VERT,scrollinfo,True);
end;

procedure TAdvStringGrid.UpdateHScrollBar;
var
  ScrollInfo: TScrollinfo;

  function TotColWidth: Integer;
  var
    i: Integer;
  begin
    Result := 0;
    for i := 0 to ColCount do
      Result := Result + ColWidths[i - 1];
    if Result = 0 then
      Result := 1;
  end;

begin
  if not (ScrollBars in [ssBoth,ssHorizontal]) or not FIsFlat then
    Exit;

  ScrollInfo.fMask := SIF_ALL;
  {$IFDEF TMSDOTNET}
  ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  {$ENDIF}
  GetScrollInfo(self.Handle,SB_HORZ,ScrollInfo);

  if FScrollProportional and (1 < 0) then
  begin
    ScrollInfo.FMask := SIF_ALL;
    {$IFDEF TMSDOTNET}
    ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    ScrollInfo.cbSize := SizeOf(ScrollInfo);
    {$ENDIF}
    if (ScrollInfo.npos > 127) or (ScrollInfo.npos < 0) then
      ScrollInfo.npos := 0;
    ScrollInfo.nmax := 127;
    ScrollInfo.nmin := 0;
    ScrollInfo.nPage := Round(128 * Width / TotColWidth);
  end;

  FlatSetScrollInfo(SB_HORZ,ScrollInfo,True)
end;

procedure TAdvStringGrid.FlatSetScrollInfo(code: Integer;var Scrollinfo:TScrollInfo;FRedraw: bool);
{$IFDEF TMSDOTNET}
begin
  FlatSB_SetScrollInfo(self.Handle,code,scrollinfo,fRedraw);
end;
{$ENDIF}
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}


procedure TAdvStringGrid.FlatSetScrollProp(index, newValue: Integer;
  FRedraw: bool);
{$IFDEF TMSDOTNET}
begin
  FlatSB_SetScrollProp(self.Handle,index,newValue,fRedraw);
end;
{$ENDIF}
{$IFNDEF TMSDOTNET}
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(self.Handle,index,newValue,fRedraw);
  end;
end;
{$ENDIF}


procedure TAdvStringGrid.FlatShowScrollBar(code: Integer;show:bool);
{$IFDEF TMSDOTNET}
begin
  FlatSB_ShowScrollBar(self.Handle,code,show);
end;
{$ENDIF}
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}

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;
{$IFDEF TMSDOTNET}
begin
 InitializeFlatSB(self.Handle);
end;
{$ENDIF}
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}


procedure TAdvStringGrid.FlatDone;
{$IFDEF TMSDOTNET}
begin
  UninitializeFlatSB(self.Handle);
end;
{$ENDIF}
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}

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.SetHovering(Value: Boolean);
begin
  if Value <> FHovering then
  begin
    FHovering := Value;
  end;
end;

procedure TAdvStringGrid.SetAutoThemeAdapt(const Value: Boolean);
begin
  FAutoThemeAdapt := Value;
  SearchFooter.AutoThemeAdapt := Value;
  if FAutoThemeAdapt then
  begin
    ThemeAdapt;
    Invalidate;
  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;

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;
  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
    Exit;
    //FlatInit;
    //FlatUpdate;
  end
  else
  if FIsflat and (FScrollType = ssNormal) then
  begin
    FlatDone;
    {$IFDEF TMSDOTNET}
    ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    ScrollInfo.cbSize := SizeOf(ScrollInfo);
    {$ENDIF}
    ScrollInfo.FMask := SIF_PAGE;
    ScrollInfo.nPage := 0;
    SetScrollInfo(Handle,SB_HORZ,ScrollInfo,True);
    {$IFDEF TMSDOTNET}
    ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    ScrollInfo.cbSize := SizeOf(ScrollInfo);
    {$ENDIF}
    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;
end;

procedure TAdvStringGrid.WMHScroll(var WMScroll: TWMScroll);
var
  page: Integer;
  r:TRect;
  s:string;
  pt:TPoint;
  nr: Integer;
  fcr,tcr:TRect;

begin
  if FScrollHints in [shHorizontal,shBoth] then
  begin
    if wmScroll.ScrollCode = SB_ENDSCROLL then
    begin
      FScrollHintWnd.ReleaseHandle;
      FScrollHintShow := False;
    end;
    {$IFDEF DELPHI3_LVL}
    if wmScroll.ScrollCode = SB_THUMBTRACK then
    begin
      nr := FixedRows + 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;
   {$ENDIF}
  end;

  if (wmScroll.scrollcode = SB_THUMBPOSITION) and (FIsFlat) then
  begin
    Page := Round(128 * VisibleColCount/ColCount);
    wmScroll.Pos := Round(127*wmScroll.pos/(128 - Page));
  end;

  if (wmScroll.scrollcode = SB_THUMBTRACK) and (FScrollSynch) then
  begin
    LeftCol := FixedCols + longmuldiv(wmScroll.pos,ColCount-VisibleColCount-FixedCols,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;

  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;

  UpdateHScrollBar;
  UpdateVScrollBar;

  if HasCheckBox(Col,Row) then
    HideEditor;

  UpdateFooter;
end;

procedure TAdvStringGrid.UpdateHScroller;
var
  R,GLW,RH,TCW: Integer;
  TotalFixedWidth: Integer;
  TotalScrollableWidth: Integer;
  TotalHiddenWidth: Integer;
  ViewRatio: Single;
  IdealNMax: Single;
  IdealNPos: Single;
  ScrollInfo: TScrollInfo;
begin
  if (csLoading in ComponentState) or
     (csDesigning in ComponentState) then
    Exit;

  if not ScrollProportional then
    Exit;

  if FScrollLock then
    Exit;

  { Get current scroll information }
  {$IFNDEF TMSDOTNET}
  FillChar(ScrollInfo,SizeOf(ScrollInfo),0);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  {$ENDIF}

  ScrollInfo.FMask := SIF_ALL;
  GetScrollInfo(Handle,SB_HORZ,ScrollInfo);

  { Calculate proper scrolling region ratio }
  GLW := GridLineWidth;

  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 := (Width - TotalFixedWidth)/TotalScrollableWidth;

  if (ViewRatio >= 0.9999) then
    Exit;

  IdealNMax := (127 + ViewRatio) / (1 - ViewRatio);

  if (TotalScrollableWidth > Width) then
    IdealNPos := TotalHiddenWidth / (TotalScrollableWidth - Width) * 128
  else
    IdealNPos := ScrollInfo.nPos;

  { Set scroll information }
  ScrollInfo.nMax := Trunc(IdealNMax);
  ScrollInfo.nPage := ScrollInfo.nMax - 127 + 1;
  ScrollInfo.nPos := Trunc(IdealNPos);

  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 < Width) or not (ScrollBars in [ssHorizontal,ssBoth]) then
      ShowScrollBar(Handle,SB_HORZ,False);
end;

procedure TAdvStringGrid.UpdateVScroller;
var
  R                     : Integer;
  GLW                   : Integer;
  RH                    : 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 then
    Exit;

  if FScrollLock then
    Exit;

 { Get current scroll information }
  {$IFNDEF TMSDOTNET}
  FillChar(ScrollInfo,SizeOf(ScrollInfo),0);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  ScrollInfo.cbSize := Marshal.SizeOf(TypeOf(ScrollInfo));
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  {$ENDIF}

  ScrollInfo.fMask  := SIF_ALL;
  GetScrollInfo(Handle,SB_VERT,ScrollInfo);

  { Calculate proper scrolling region ratio }
  GLW := GridLineWidth;

  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;

  ViewRatio := (Height - TotalFixedHeight)/TotalScrollableHeight;

  if ViewRatio >= 0.9999 then
    Exit;

  IdealNMax := (127 + ViewRatio) / (1 - ViewRatio);

  if TotalScrollableHeight > Height  then
    IdealNPos := TotalHiddenHeight / (TotalScrollableHeight - Height) * 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;

begin
  if FScrollHints in [shVertical,shBoth] then
  begin
    if (wmScroll.ScrollCode = SB_ENDSCROLL) then
    begin
      FScrollHintWnd.ReleaseHandle;
      FScrollHintShow := False;
    end;

    {$IFDEF DELPHI3_LVL}
    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;
   {$ENDIF}
  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;

  inherited;

  if (wmScroll.ScrollCode = SB_LINEUP) and SearchFooter.Visible then
  begin
    if TopRow = RowCount - VisibleRowCount then
      TopRow := TopRow - 1;
  end;

  if (wmScroll.ScrollCode = SB_ENDSCROLL) and SearchFooter.Visible then
  begin
    if TopRow = RowCount - VisibleRowCount then
      TopRow := TopRow + 1;
  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) and (AComponent = FGridImages) then
    FGridImages := nil;

  if (AOperation = opRemove) and (AComponent = FContainer) then
    FContainer := nil;

  if (AOperation = opRemove) and (AComponent = FCellChecker) then
    FCellChecker := nil;

  if (AOperation = opRemove) and (AComponent = FFixedDropDownMenu) then
    FFixedDropDownMenu := nil;

  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.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)) 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;

{$IFDEF DELPHI3_LVL}
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;
{$ENDIF}

procedure TAdvStringGrid.StretchColumn(ACol: Integer);
var
  i,w: Integer;
begin
  if csLoading in ComponentState then
    Exit;
  if csDestroying in ComponentState then
    Exit;

  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;

  // 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
    ColWidths[ACol] := ClientRect.Right - w - 1
  else
  begin
    if LeftCol = FixedCols then
      ColWidths[ACol] := DefaultColWidth;
  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 then
    StretchColumn(FColumnSize.StretchColumn);

  if csDesigning in ComponentState then
  begin
    if FScrollHintShow 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 then
    UpdateVScroller;
end;

procedure TAdvStringGrid.RowHeightsChanged;
var
  i: Integer;
  Ratio:double;
begin
  if csDesigning in ComponentState then
  begin
    if FScrollHintShow then
      FScrollHintWnd.ReleaseHandle;
    FScrollHintShow := False;
  end;

  inherited RowHeightsChanged;

  if Rowsized and FMouseActions.AllRowSize then
  begin
    Rowsized := False;
    Ratio := RowHeights[Rowclicked]/RowClickedSize;

    for i := FixedRows to RowCount - 1 do
      if i <> RowClicked then
        RowHeights[i] := Round(RowHeights[i] * Ratio);

    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.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.SetComboSelection(idx: Integer);
begin
  FComboIdx := Idx;
end;

function TAdvStringGrid.GetComboCount: Integer;
begin
  GetComboCount := EditCombo.Items.Count;
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;
var
  IsFixed,IsEdit: Boolean;
  BC: TPoint;
begin
  Result := False;

  if not ((goEditing in Options) or MouseActions.RangeSelectAndEdit) and not FEditDisable then
    Exit;

  if IsMergedCell(ACol, ARow) and not IsBaseCell(ACol, ARow) then
    BC := BaseCell(ACol,ARow)
  else
    BC := Point(ACol,ARow);

  IsFixed := False;
  IsEdit := True;

//  GetCellReadOnly(RealColIndex(BC.X),BC.Y,IsEdit);
  GetCellReadOnly(BC.X,BC.Y,IsEdit);
//  GetCellFixed(DisplColIndex(BC.X),BC.Y,IsFixed);
  GetCellFixed(RealColIndex(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);
  // 3.2.0.5
  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.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}

begin
  FSpecialEditor := False;
  FBlockKill := True;

  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;

  {$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;

    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 EditDate.Checked then
      {$IFNDEF TMSDOTNET}
        UpdateEditingCell(ACol,ARow,FormatDateTime(ShortDateFormat + ' ' + ShortTimeFormat,EditDateTime.DateTime))
      {$ENDIF}
      {$IFDEF TMSDOTNET}
        UpdateEditingCell(ACol,ARow,FormatDateTime(ShortDateFormat + ' ' + ShortTimeFormat,EditDateTime.DateTime))
      {$ENDIF}
      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
      {$IFNDEF TMSDOTNET}
        UpdateEditingCell(ACol,ARow,EditDate.Text)
      {$ENDIF}
      {$IFDEF TMSDOTNET}
        UpdateEditingCell(ACol,ARow,EditDate.Text)
      {$ENDIF}
      else
        UpdateEditingCell(ACol,ARow,'');

      EditMode := False;
      EditDate.Enabled := False;
      EditDate.Visible := False;

      {$IFNDEF TMSDOTNET}
      ShowWindow(EditDate.GetCalendarHandle, SW_HIDE);
      {$ENDIF}
    end;
  end;
  edTimeEdit:
  begin
    {$IFDEF DELPHI3_LVL}
    if ComCtrlOk then
    begin
      OldFmt := LongTimeFormat;
      {$IFDEF DELPHI6_LVL}
      if EditDate.Format <> '' then
        LongTimeFormat := EditDate.Format;
      {$ENDIF}
      {$IFNDEF TMSDOTNET}
      UpdateEditingCell(ACol,ARow,EditDate.Text);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      UpdateEditingCell(ACol,ARow,EditDate.Text);
      {$ENDIF}
      LongTimeFormat := OldFmt;
      EditDate.Enabled := False;
      EditDate.Visible := False;
      EditMode := False;
    end;
    {$ENDIF}
  end;
  edCheckBox:
  begin
    EditCheck.Enabled := False;
    EditCheck.Visible := False;
    EditMode := False;
  end;
  edEditBtn,edNumericEditBtn,edFloatEditBtn:
  begin
    if EditMode then
    begin
      EditMode := False;
      UpdateEditingCell(ACol,ARow,EditBtn.Text);
      EditBtn.Enabled := False;
      EditBtn.Visible := False;
    end;
  end;
  edUnitEditBtn:
  begin
    UpdateEditingCell(ACol,ARow,UnitEditBtn.Text + UnitEditBtn.UnitID);
    UnitEditBtn.Enabled := False;
    UnitEditBtn.Visible := False;
    EditMode := False;
  end;
  edRichEdit:
  begin
    UpdateEditingCell(ACol,ARow,RichToString(FInplaceRichEdit));
    FInplaceRichEdit.Enabled := False;
    FInplaceRichEdit.Visible := False;
    EditMode := False;
  end;
  edButton:
  begin
    Gridbutton.Enabled := False;
    Gridbutton.Visible := False;
    EditMode := False;
  end;
  edCustom:
  begin
    if Assigned(EditLink) {and EditMode} then
    begin
      UpdateEditingCell(ACol,ARow,EditLink.GetEditorValue);
      if EditLink.EditStyle <> esPopup then
        EditLink.SetVisible(False);
      EditLink.RestoreWinProc;
      EditMode := False;
    end;
  end;
  end;

  if (EditControl <> edNormal) and (FEditActive) then
    DoneEditing(ACol,ARow);

  FBlockKill := false;
  FEditActive := False;
end;

procedure TAdvStringGrid.HideCellEdit;
begin
  HideEditControl(Col,Row);
end;

procedure TAdvStringGrid.ShowCellEdit;
begin
  Perform(WM_KEYDOWN ,VK_F2,0);
  //PostMessage(Handle,WM_KEYDOWN ,VK_F2,0);
end;

procedure TAdvStringGrid.ShowEditControl(ACol,ARow: Integer);
var
  r: TRect;
  s: string;
  pt: TPoint;
  CellWidth,CellHeight,OCol: Integer;
  EditColor: TColor;
  AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  EditFont: TFont;
  AState: TGridDrawState;
  HAlign: TAlignment;
  VAlign: TVAlignment;
  WW: Boolean;
  GD: TCellGradientDirection;
  ValD: Double;
  Err, ValI: Integer;
  EcC: boolean;
  PForm: TComponent;
  dt: TDateTime;
  {$IFDEF DELPHI5_LVL}
  {$IFNDEF TMSDOTNET}
  i: Integer;
  ws: array of widestring;
  wo: array of TObject;
  {$ENDIF}
  {$ENDIF}

  {$IFDEF TMSUNICODE}
  wt: widestring;
  {$ENDIF}

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;

      if Assigned(FOnGetEditorProp) then
        FOnGetEditorProp(self,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);

      EditCombo.Color := EditColor;

      EditCombo.MaxLength := FMaxComboLength;

      EditCombo.Visible := True;

      EditCombo.Flat := Look in [glSoft,glTMS,glXP,glVista,glListView];
      EditCombo.Etched := Look in [glSoft,glTMS,glXP,glVista,glListView];

      if FNavigation.FAutoComboDropSize 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 FStartEditChar <> #0 then
        PostMessage(EditCombo.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := EditCombo;
    end;
  edComboList:
    begin
      EditMode := True;

      if Assigned(FOnGetEditorProp) then
        FOnGetEditorProp(self,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 := 0;
        EcC := true;
      end
      else
        if (EditCombo.ItemIndex = -1) then
          EditCombo.ItemIndex := FComboIdx;

      EditCombo.Width := CellWidth;
      EditCombo.Height := CellHeight + (EditCombo.DropDownCount+1) * EditCombo.ItemHeight;

      EditCombo.Text := GetEditText(OCol,ARow);
      EditCombo.Color := EditColor;

      EditCombo.Visible := True;

      EditCombo.Flat := Look in [glSoft,glTMS,glXP,glVista,glListView];
      EditCombo.Etched := Look in [glSoft,glTMS,glXP,glVista,glListView];

      if FNavigation.FAutoComboDropSize 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 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;
    end;

  {$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 - XYOffset.X * 2;
      EditUni.Height := CellHeight - 2 - XYOffset.Y * 2;
      EditUni.Visible := True;
      EditUni.Enabled := True;
      EditUni.Color := EditColor;
      EditUni.Font.Assign(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 - XYOffset.X * 2;
      MemoUni.Height := CellHeight - 2 - XYOffset.Y * 2;
      MemoUni.Visible := True;
      MemoUni.Enabled := True;
      MemoUni.Color := EditColor;
      MemoUni.Font.Assign(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(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(Font);
      ComboUni.Flat := Look in [glSoft,glTMS,glXP,glVista,glListView];
      ComboUni.Etched := Look in [glSoft,glTMS,glXP,glVista,glListView];

      if FNavigation.FAutoComboDropSize 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;

      s := GetEditText(OCol,ARow);

      case EditControl of
      edSpinEdit:
        begin
          EditSpin.SpinType := sptNormal;
          Val(s,ValI,Err);
          EditSpin.Value := ValI;
        end;
      edFloatSpinEdit:
        begin
          EditSpin.SpinType := sptFloat;
          s := RemoveSeps(s);
          Val(s,ValD,Err);
          EditSpin.FloatValue := ValD;
        end;
      edTimeSpinEdit:
        begin
          EditSpin.SpinType := sptTime;
          EditSpin.Text := GetEditText(ACol,ARow);
        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
        EditSpin.DoInc(false);
      if FSpinDnClick then
        EditSpin.DoDec(false);

      EditCtrl := EditSpin;
    end;

  edDateTimeEdit:
    begin
      if ComCtrlOk then
      begin
        EditMode := True;
        EditDate.Parent := Self;
        EditDate.ReCreate;

        s := GetEditText(OCol,ARow);

        if s = '' then
        begin
          dt := Now;
        end
        else
        begin
          try
            {$IFNDEF TMSDOTNET}
            //dt := VarToDateTime(s);
            dt := StrToDateTime(s);
            {$ELSE}
            dt := StrToDateTime(s);
            {$ENDIF}
          except
            dt := Now;
          end;
        end;
        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;

        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);

        {$IFNDEF TMSDOTNET}
        try
          if s = '' then
            EditDate.Date := Now
          else
          {$IFDEF DELPHI7_LVL}
          begin
              if Assigned(FOnCustomStrToDate) then
              begin
                dt := Now;
                FOnCustomStrToDate(Self, S, dt);
                EditDate.Date := dt;
              end
              else
                //EditDate.Date := VartoDateTime(s);
                EditDate.Date := StrToDateTime(s);
           end;
          {$ELSE}
          begin
              if Assigned(FOnCustomStrToDate) then
              begin
                dt := Now;
                FOnCustomStrToDate(Self,S,dt);
                EditDate.Date := dt;
              end
              else   
                EditDate.Date := StrToDate(s);
          end;      
          {$ENDIF}  
        except
          EditDate.Date := Now;
        end;
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        try
          if s = '' then
            EditDate.DateTime := Now
          else
            EditDate.DateTime := StrToDate(s);
        except
          EditDate.DateTime := Now;
        end;
        {$ENDIF}

        EditDate.Kind := dtkDate;

        if EditControl = edDateEditUpdown then
          EditDate.DateMode := dmUpDown
        else
          EditDate.DateMode := dmComboBox;

        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);

        EditCtrl := EditDate;
      end;
   end;
  edTimeEdit:
    begin
      {$IFDEF DELPHI3_LVL}
      if ComCtrlOk then
      begin
        EditMode := True;
        EditDate.ReCreate;
        s := GetEditText(OCol,ARow);

        try
        {$IFNDEF TMSDOTNET}
          if s = '' then
            EditDate.Time := Now
          else
            EditDate.Time := StrToTime(GetEditText(OCol,ARow));
        except
          EditDate.Time := Now;
        {$ENDIF}
        {$IFDEF TMSDOTNET}
          if s = '' then
            EditDate.DateTime := Now
          else
            EditDate.DateTime := StrToTime(GetEditText(OCol,ARow));
        except
          EditDate.DateTime := Now;
        {$ENDIF}

        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;
        EditDate.SetFocus;

        EditCtrl := EditDate;        
      end;
      {$ENDIF}
    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,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.SetFocus;
      EditBtn.Height := CellHeight;

      if FStartEditChar <> #0 then
        PostMessage(EditBtn.Handle,WM_CHAR,Ord(FStartEditChar),0);
      EditCtrl := EditBtn;
    end;
  edUnitEditBtn:
    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 := '';
      while (Length(s) > 0) do
      begin
        if CheckSignedNum(s[1]) or (s[1] = ThousandSeparator) or (s[1]= DecimalSeparator) then
          UnitEditBtn.Text := UnitEditBtn.Text+s[1]
        else
          UnitEditBtn.UnitID := UnitEditBtn.unitid+s[1];
        Delete(s,1,1);
      end;
      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);
      Gridbutton.Visible := True;
      Gridbutton.Enabled := True;
      Gridbutton.SetFocus;
      EditCtrl := GridButton;
    end;

  edRichEdit:
    begin
      EditMode := True;
      FInplaceRichEdit.ReCreate;
      FInplaceRichEdit.Parent := Self;
      FInplaceRichEdit.BorderStyle := bsNone;
      FInplaceRichEdit.HideSelection := False;

      FInplaceRichEdit.Top := r.Top;
      FInplaceRichEdit.Left := r.Left;
      FInplaceRichEdit.Width := CellWidth;
      FInplaceRichEdit.Height := CellHeight;

      FInplaceRichEdit.Lock;

      CellToRich(ACol, ARow, FInplaceRichEdit);

      if Navigation.EditSelectAll then
      begin
        FInplaceRichEdit.SelStart := 0;
        FInplaceRichEdit.SelLength := Length(FInplaceRichEdit.Text);
      end;  

      FInplaceRichEdit.Visible := True;
      FInplaceRichEdit.Enabled := True;

      r := Rect(2,2,r.Right - r.Left - 2,r.Bottom - r.Top - 2);
      {$IFNDEF TMSDOTNET}
      SendMessage(FInplaceRichEdit.Handle,EM_SETRECT,0,Longint(@r));
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      Perform(EM_SETRECT,0,r);
      {$ENDIF}

      FInplaceRichEdit.Color := EditColor;
      FInplaceRichEdit.SetFocus;

      if FStartEditChar <> #0 then
        PostMessage(FInplaceRichEdit.Handle,WM_CHAR,Ord(FStartEditChar),0);

      FInplaceRichEdit.UnLock;
      EditCtrl := FInplaceRichEdit;
    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}

          {$IFNDEF TMSDOTNET}
          EditLink.FPopupForm.Left := pt.x;
          EditLink.FPopupForm.Top := pt.y;
          {$ENDIF}

          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 TMSDOTNET}
          EditLink.FPopupForm.Left := pt.x;
          EditLink.FPopupForm.Top := pt.y;
          {$ENDIF}

          {$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;

        if Assigned(FOnGetEditorProp) then
          FOnGetEditorProp(self,ACol,ARow,EditLink);

        EditLink.SetEditorValue(GetEditText(OCol,ARow));
        EditLink.SetFocus(True);

        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;
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.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 := CurrentCell;
    EditControl := FDefaultEditor;
    GetCellEditor(BC.X,BC.Y,EditControl);

    if EditControl = edNone then
    begin
      Result := False;
      Exit;
    end;

    EditMode := True;
    if not (EditControl in [edNormal,edNumeric,edPositiveNumeric,edFloat,edCapital,
      edMixedCase,edPassword,edUpperCase,edLowerCase]) then
    begin
      BC := BaseCell(Col,Row);
      ShowEditControl(BC.X,BC.Y);
      FEntered := True;
      Result := False;
    end
    else
      if Result then
        FShowEditProcess := True;
  end;

  if Result then
  begin
    FEntered := True;
    FEditing := True;
  end;
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: string;
  pt: TPoint;

begin
  if FForceSel then
  begin
    Result := true;
    Exit;
  end;

  if not (Parent is TWinControl) then
  begin
    Result := true;
    Exit;
  end;

  CanChange := True;
  Result := False;
  FEditText := Cells[ACol,ARow];

  // floating bottomrow
  if FloatingFooter.Visible then
  begin
    if FloatingFooter.FooterStyle in [fsColumnPreview, fsCustomPreview] then
    begin
      FFooterPanel.Invalidate;

      R := CellRect(ACol,ARow);
      if (R.Bottom > ClientRect.Bottom - FloatingFooter.Height +2) and
        (ARow < RowCount) then
        TopRow := TopRow + 1;
    end
    else
    begin
      if ARow >= TopRow + VisibleRowCount then
      begin
        TopRow := ARow - VisibleRowCount + FixedRows;
      end;

      R := CellRect(ACol,ARow);

      if (R.Bottom > ClientRect.Bottom - FloatingFooter.Height + 2) and
        (ARow < RowCount - 1) then
      begin
        TopRow := TopRow + 1;
      end;

      if (ARow = RowCount - 1) then
        Exit;
    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) do
    begin
      TopRow := TopRow + 1;
      R := CellRect(ACol,ARow);
    end;
  end;

  if (ACol < 0) or (ARow < 0) then
    Exit;

  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
    begin
      ShowEditor;
    end;

    Exit;
  end;

  if (ARow <> Row) and Assigned(FOnRowChanging) then
    FOnRowChanging(Self,Row,ARow,Canchange);

  if (ACol <> Col) and Assigned(FOnColChanging) then
    FOnColChanging(Self,Col,ACol,Canchange);

  if ((ACol <> Col) or (ARow <> Row)) and Assigned(FOnCellChanging)
    and not FDisableChange then
    FOnCellChanging(Self,Row,Col,ARow,ACol,CanChange);


  // 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;


  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 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) 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
        FEditDisable := True;
        FEditChange := True;
        Options := Options - [goEditing];
      end;
    end;
  end
  else
  begin                         
    CanEdit := true;
    GetCellReadOnly(ECol,ARow,CanEdit);

    FEditDisable := (not CanEdit) and ((goEditing in Options) or MouseActions.RangeSelectAndEdit); //False; /* 3.6.0.2 */

    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
    if IsWideCell(Col,Row) then
      Result := ValidateCellWide(FEditWideText)
    else
      Result := ValidateCell(CurrentCell);

    if Result then
      Result := inherited SelectCell(ACol,ARow);
  end
  else
  begin
    if IsFixed(ACol,ARow) then
    begin
      Result := False
    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 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;

  FCellCache := OrgCellVal;
  {
  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
    if not (cg.CellType in [ctVirtCheckBox,ctRowCheckBox]) then
      cg.Free;

  GraphicObjects[ACol,ARow] := nil;
  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;
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;
    FCellGraphic.CellTransparent := ControlLook.ControlStyle = csFlat;
    FCellGraphic.CellBoolean := RowSelect[ARow];

    Result := FCellGraphic;
  end;
end;

function TAdvStringGrid.GetCellGraphicSize(ACol,ARow: Integer): TPoint;
var
  cg: TCellGraphic;
  w,h,i: Integer;
  s: string;
  CDIM: TPoint;
  r: TRect;
  NoHaFull: boolean;
  {$IFDEF DELPHI6_LVL}
  io: TInterfacedPersistent;
  icg: ICellGraphic;
  {$ENDIF}

begin
  Result.x := 0;
  Result.y := 0;

  NoHaFull := false;

  cg := CellGraphics[ACol,ARow];
  if cg = nil then
    Exit;

  w := 0;
  h := 0;
  s := Cells[ACol,ARow];
  CDIM := CellSize(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
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    w := Result.x;
    h := Result.y;
  end;

  ctFilePicture:
  begin
    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 := Canvas.TextWidth(cg.FCellText) + 4;

      if not (cg.CellVAlign in [vaAboveText,vaUnderText]) then
        h := 0;
    end
    else
    begin
      if (cg.CellHAlign in [haFull]) then
      begin
        Canvas.Font.Assign(Font);
        w := Canvas.TextWidth(cg.FCellText) + 4;
        NoHaFull := cg.FCellText <> '';
      end;
    end;
  end;

  {$IFDEF DELPHI6_LVL}
  ctInterface:
  begin
    {$IFNDEF TMSDOTNET}
    io := TInterfacedPersistent(cg.CellBitmap);
    if io.GetInterface(ICellGraphic, icg) then
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    io := cg.CellInterface;
    icg := ICellGraphic(io.GetType.GetInterface(typeof(ICellGraphic).FullName));    
    if (icg <> nil) then
    {$ENDIF}
   
    begin
      w := icg.CellWidth;
      h := icg.CellHeight;
    end;

  end;
  {$ENDIF}
  
  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
    if Assigned(GridImages) then
    begin
      if cg.CellHAlign in [haBeforeText,haAfterText] then
        w := GridImages.Width
      else
        if s = '' then
          w := GridImages.Width;
      if cg.CellVAlign in [vaUnderText, vaAboveText] then
        h := GridImages.Height
      else
        if s = '' then
          h := GridImages.Height
    end;
  end;
  ctProgressPie:
  begin
    w := 20;
    h := 20;
  end;

  ctCheckbox,ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox:
  begin
    w := FControlLook.CheckSize;
    h := FControlLook.CheckSize;
  end;
  ctRadio:
  begin
    if not cg.CellBoolean then
    begin
      w := 12;
      {$IFNDEF TMSDOTNET}
      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;
      {$ENDIF}

      {$IFDEF TMSDOTNET}
      for i := 1 to cg.CellStrings.Count do
      begin
        if 12 + Canvas.TextWidth(cg.CellStrings.Strings[i - 1]) > w then
         w := 12 + Canvas.TextWidth(cg.CellStrings.Strings[i - 1]);
      end;

      h := (Canvas.TextHeight('gh')) * cg.CellStrings.Count;
      {$ENDIF}

    end
    else
    begin
      w := 0;
      h := Canvas.TextHeight('gh');
      {$IFDEF TMSDOTNET}
      for i := 1 to cg.CellStrings.Count do
        w := w + 12 + Canvas.TextWidth(cg.CellStrings[i - 1]);
      {$ENDIF}
      {$IFNDEF TMSDOTNET}
      for i := 1 to TStringList(cg.CellBitmap).Count do
      begin
        w := w + 12 + Canvas.TextWidth(TStringList(cg.CellBitmap).Strings[i - 1]);
      end;
      {$ENDIF}
    end;
  end;
  ctImages:
  begin
    if Assigned(GridImages) then
    begin
      if cg.CellBoolean then
      begin
        w := CellImages[ACol,ARow].Count * GridImages.Width;
        h := GridImages.Height;
      end
      else
      begin
        h := CellImages[ACol,ARow].Count * GridImages.Height;
        w := GridImages.Width;
      end;
    end;
  end;
  end;

  if (cg.CellVAlign = vaFull) or ((cg.CellHAlign = haFull) and not NoHaFull) 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;

  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;
  {$IFDEF DELPHI6_LVL}
  io: TInterfacedPersistent;
  icg: ICellGraphic;
  {$ENDIF}

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
    {$IFDEF TMSCODESITE}
    CodeSite.SendPoint('picsize',CDIM);
    {$ENDIF}
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    {$IFDEF TMSCODESITE}
    CodeSite.SendPoint('result',Result);
    {$ENDIF}
    w := Round(Result.X / ResFactor);
    h := Round(Result.Y / ResFactor);
  end;

  ctFilePicture:
  begin
    Result := cg.GetPictureSize(CDIM.X,CDIM.Y,s <> '');
    w := Round(Result.X / ResFactor);
    h := Round(Result.Y / ResFactor);
  end;

  ctButton,ctBitButton:
  begin
    w := cg.CellIndex and $FFFF;
    h := (cg.CellIndex and $FFFF0000) shr 16;
  end;

  {$IFDEF DELPHI6_LVL}
  ctInterface:
  begin
    {$IFNDEF TMSDOTNET}
    io := TInterfacedPersistent(cg.CellBitmap);
    if io.GetInterface(ICellGraphic, icg) then
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    io := cg.CellInterface;
    icg := ICellGraphic(io.GetType.GetInterface(typeof(ICellGraphic).FullName));
    if icg <> nil then
    {$ENDIF}


    begin
      w := icg.CellWidth;
      h := icg.CellHeight;
    end;

  end;
  {$ENDIF}
  ctBitmap:
  begin
    w := cg.CellBitmap.Width;
    h := cg.CellBitmap.Height;
  end;
  ctDataImage:
  begin
    if Assigned(GridImages) then
    begin
      w := GridImages.Width;
      h := GridImages.Height;
    end;
  end;
  ctImageList:
  begin
    if Assigned(GridImages) then
    begin
      if cg.CellHAlign in [haBeforeText,haAfterText] then
        w := GridImages.Width
      else
        if s = '' then
          w := GridImages.Width;
      h := GridImages.Height;
    end;
  end;
  ctCheckbox,ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox:
  begin
    w := FControlLook.CheckSize;
    h := FControlLook.CheckSize;
  end;
  ctProgressPie:
  begin
    w := 20;
    h := 20;
  end;
  ctRadio:
  begin
    if not cg.CellBoolean then
    begin
      w := 12;
      {$IFNDEF TMSDOTNET}
      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;
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      for i := 1 to cg.CellStrings.Count do
      begin
        if 12 + Canvas.TextWidth(cg.CellStrings.Strings[i - 1]) > w then
         w := 12 + Canvas.TextWidth(cg.CellStrings.Strings[i - 1]);
      end;

      h := (Canvas.TextHeight('gh')) * cg.CellStrings.Count;
      {$ENDIF}
    end
    else
    begin
      w := 0;
      {$IFNDEF TMSDOTNET}
      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;
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      h := Canvas.TextHeight('gh');
      for i := 1 to cg.CellStrings.Count do
      begin
        w := w + 12 + Canvas.TextWidth(cg.CellStrings.Strings[i - 1]);
      end;
      {$ENDIF}

    end;
  end;
  ctImages:
  begin
    if Assigned(GridImages) then
    begin
      if cg.CellBoolean then
      begin
        w := CellImages[ACol,ARow].Count * GridImages.Width;
        h := GridImages.Height;
      end
      else
      begin
        h := CellImages[ACol,ARow].Count * GridImages.Height;
        w := GridImages.Width;
      end;
    end;
  end;
  ctProgress,ctXPProgress:
  begin
    h := RowHeights[ARow];
    w := ColWidths[ACol];
  end;
  end;

  Result.x := w;
  Result.y := h;
end;


procedure TAdvStringGrid.GetDisplText(c,r: Integer; var Value: string);
var
  ns: integer;
begin
  inherited;

  if Grouping.ShowGroupCount and (c = GroupColumn) 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.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.GetCellImages(ACol,ARow: Integer): TIntList;
begin
  {$IFNDEF TMSDOTNET}
  if CellTypes[ACol,ARow] = ctImages then
    Result := TIntList((GraphicObjects[ACol,ARow] as TCellGraphic).CellBitmap)
  else
    Result := nil;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  if CellTypes[ACol,ARow] = ctImages then
    Result := (GraphicObjects[ACol,ARow] as TCellGraphic).CellList
  else
    Result := nil;
  {$ENDIF}
end;

function TAdvStringGrid.GetCellImageIdx(ACol,ARow: Integer): Integer;
begin
  case CellTypes[ACol,ARow] of
  ctImageList:Result := TCellGraphic(GraphicObjects[ACol,ARow]).CellIndex;
  {$IFDEF TMSDOTNET}
  ctIcon:Result := Integer(TCellGraphic(GraphicObjects[ACol,ARow]).CellIcon.Handle);
  ctBitmap:Result := Integer(TCellGraphic(GraphicObjects[ACol,ARow]).CellBitmap.Handle);
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  ctIcon:Result := Integer(TCellGraphic(GraphicObjects[ACol,ARow]).CellIcon);
  ctBitmap:Result := Integer(TCellGraphic(GraphicObjects[ACol,ARow]).CellBitmap);
  {$ENDIF}
  else
    Result := -1;
  end;
end;


procedure TAdvStringGrid.SetInts(ACol,ARow: Integer;const Value: Integer);
begin
  Cells[ACol,ARow] := IntToStr(Value);
end;

function TAdvStringGrid.GetInts(ACol,ARow: Integer): Integer;
var
  s: string;
  Res,Err: Integer;
begin
  s := Cells[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');

  GetInts := Res;
end;

procedure TAdvStringGrid.SetFloats(ACol,ARow: Integer;const Value:double);
begin
  Cells[ACol,ARow] := Format(FFloatFormat,[Value]);
end;

function TAdvStringGrid.GetFloats(ACol,ARow: Integer): Double;
var
  s: string;
  Res: Double;
  Err: Integer;
begin
  s := RemoveSeps(Cells[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');
  GetFloats := 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;

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 < MAXCOLUMNS) 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 < MAXCOLUMNS) 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;
begin
  if FixedRows > 0 then
    for i := 0 to FColumnHeaders.Count - 1 do
      if i < TotalColCount then
        Cells[i,0] := CLFToLF(FColumnHeaders[i]);
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.ShowRowHeaders;
var
  i: Integer;
begin
 if FixedCols > 0 then
   for i := 0 to FRowHeaders.Count - 1 do
     if i < RowCount then
       Cells[0,i] := CLFToLF(FRowHeaders[i]);
end;

procedure TAdvStringGrid.MarkCells(s,tag:string;DoCase: boolean; FromCol,FromRow,ToCol,ToRow: Integer);
var
  r,c: Integer;
begin
  for r := FromRow to ToRow do
    for c := FromCol to ToCol do
      Cells[c,r] := Hilight(Cells[c,r],s,tag,DoCase);
end;

procedure TAdvStringGrid.UnMarkCells(tag:string;FromCol,FromRow,ToCol,ToRow: Integer);
var
  r,c: Integer;
begin
  for r := FromRow to ToRow do
    for c := FromCol to ToCol do
      Cells[c,r] := UnHilight(Cells[c,r],tag);
end;

function TAdvStringGrid.HilightText(DoCase: Boolean; S,Text: string):string;
begin
  Result := Hilight(S,Text,'hi',DoCase);
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);
end;

function TAdvStringGrid.UnMarkText(S: string):string;
begin
  Result := UnHilight(S,'e');
end;

procedure TAdvStringGrid.HilightInCell(DoCase: Boolean; Col,Row: Integer; HiText: string);
begin
  MarkCells(HiText,'hi',DoCase,Col,Row,Col,Row);
end;

procedure TAdvStringGrid.HilightInCol(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,'hi',DoCase,Col,rs,Col,re);
end;

procedure TAdvStringGrid.HilightInRow(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,'hi',DoCase,cs,Row,ce,Row);
end;

procedure TAdvStringGrid.HilightInGrid(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 + NumHiddenColumns;
    rs := FixedRows;
    re := RowCount - 1 - FFixedFooters;
  end;

  MarkCells(HiText,'hi',DoCase,cs,rs,ce,re);
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
    for c := FromCol to ToCol do
      if not CheckCell(c,r) then Result := False;

  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 := 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.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) then
   raise EAdvGridError.Create('Invalid row accessed');

  if MouseActions.DisjunctRowSelect then
  begin
    //SelectToRowSelect(false);

    i := FRowSelect.Count;

    if i < ARow + 1 then
    begin
      FRowSelect.Count := ARow + 1;
      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) 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(r.Right,r.Bottom);
  UnionRect(ur,r1,r2);
  if IsRectEmpty(r1) or IsRectEmpty(r2) then
    Repaint
  else
    {$IFNDEF TMSDOTNET}
    InvalidateRect(Handle,@ur,True);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    InvalidateRect(Handle,ur,True);
    {$ENDIF}
end;

procedure TAdvStringGrid.RepaintCell(c,r: Integer);
var
  rc: TRect;
begin
  if (r < TopRow) and (r >= FixedRows) and (r > TopRow + VisibleRowCount) then
    Exit;
  if (c < LeftCol) and (c >= FixedCols) and (c > LeftCol + VisibleColCount) then
    Exit;

  rc := CellRect(c,r);
  {$IFNDEF TMSDOTNET}
  InvalidateRect(Handle,@rc,True);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  InvalidateRect(Handle,rc,True);
  {$ENDIF}
end;

procedure TAdvStringGrid.RepaintRow(ARow: Integer);
var
  r1,r2: TRect;
begin
  r1 := CellRect(0,ARow);
  r2 := CellRect(LeftCol + VisibleColCount, ARow);
  r2.Left := r1.Left;
  {$IFDEF TMSDOTNET}
  InvalidateRect(Handle,r2, false);
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  InvalidateRect(Handle,@r2, false);
  {$ENDIF}
  //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;
  {$IFDEF TMSDOTNET}
  InvalidateRect(Handle,r2, false);
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  InvalidateRect(Handle,@r2, false);
  {$ENDIF}
  //InvalidateCol(ACol);
end;

procedure TAdvStringGrid.GotoCell(Col,Row: Integer);
begin
  MoveColRow(Col,Row,true,true);
end;

procedure TAdvStringGrid.FocusCell(Col,Row: Integer);
begin
  MoveColRow(Col,Row,true,true);
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;
end;

procedure TAdvStringGrid.SelectRows(RowIndex, RCount: Integer);
var
  gr: TGridRect;
  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] := True;
    end;
  end
  else
  begin
    gr.Left := FixedCols;
    gr.Right := ColCount - 1;
    gr.Top := Rowindex;
    gr.Bottom := Rowindex + rcount - 1;
    Selection := gr;
  end;
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;

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.ClearRowSelect;
var
  i: Integer;
begin
  if FRowSelect.Count <= 0 then
    Exit;

  for i := 0 to FRowSelect.Count - 1 do
  begin
    if FRowSelect.Items[i] <> nil then
    begin
      RepaintRow(i);
      //RepaintRow(RemapRow(i));
    end;
    FRowSelect.Items[i] := nil;
    
    FSelectedRows.Clear;
  end;
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;


procedure TAdvStringGrid.SelectToRowSelect(IsShift: Boolean);
var
  i,j: Integer;
begin
  for i := FixedRows to RowCount - 1 do
  begin
    if IsShift or
       ((i >= Selection.Top) and (i <= Selection.Bottom)) then
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      RowSelect[j] := (i >= Selection.Top) and (i <= Selection.Bottom);
    end;
  end;
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 FRowSelect.Count do
      if FRowSelect.Items[i-1] <> nil then Inc(Res);
  end
  else
  begin
    Res := Selection.Bottom - Selection.Top;
    if Res < 0 then
      Res := -Res;
    Inc(Res);
  end;
  
  Result := Res;
end;

function TAdvStringGrid.GetColSelectCount: Integer;
var
  Res,i: Integer;
begin
  Res := 0;
  for i := 1 to FColSelect.Count do
    if FColSelect.Items[i-1] <> nil then Inc(Res);
  Result := Res;
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;
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;

  RepaintCell(0, ARow);
end;

procedure TAdvStringGrid.SetRowSelect(ARow: Integer;Value: Boolean);
var
  i,j: Integer;
  Allow: boolean;

begin
  if (ARow >= RowCount + NumHiddenRows) or (ARow < 0) then
    raise EAdvGridError.Create('Invalid row accessed');

  Allow := true;

  if Assigned(FOnRowDisjunctSelect) then
    FOnRowDisjunctSelect(Self, ARow, Value, Allow);

  if not Allow then
    Exit;

  i := FRowSelect.Count;
  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
    {$IFNDEF TMSDOTNET}
    if FRowSelect.Items[ARow] <> Pointer(1) then
    begin
      //RepaintRow(RemapRow(ARow));
      RepaintRow(ARow);
    end;
    FRowSelect.Items[ARow] := Pointer(1);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    if FRowSelect.Items[ARow] <> TObject(1) then
    begin
      RepaintRow(ARow);
    end;
    FRowSelect.Items[ARow] := TObject(1);
    {$ENDIF}

    if not FSelectedRows.HasValue(ARow) then
    begin
      FSelectedRows.Add(ARow);
    end;
  end
  else
  begin
    if FRowSelect.Items[ARow] <> nil then
      //RepaintRow(RemapRow(ARow));
      RepaintRow(ARow);
    FRowSelect.Items[ARow] := nil;
    FSelectedRows.DeleteValue(ARow);
  end;

  if 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
    {$IFNDEF TMSDOTNET}
    if FColSelect.Items[ACol] <> Pointer(1) then
      RepaintCol(ACol);
    FColSelect.Items[ACol] := Pointer(1);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    if FColSelect.Items[ACol] <> TObject(1) then
      RepaintCol(ACol);
    FColSelect.Items[ACol] := TObject(1);
    {$ENDIF}
  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);

    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: TPoint;
  AEditor: TEditorType;
  CanEdit: boolean;
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;

  OldCol := ACol;
  OldRow := ARow;
  FStartEditChar := #0;

  Span := CellSpan(ACol,ARow);

  if Frwrd then
  begin
    if FNavigation.AdvanceDirection = adLeftRight then
    begin
      if ACol + Span.X >= ColCount - 1 - NumFixedRightVis then
      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
            ARow := FixedRows;
            ACol := FixedColsVis;
          end;
        end
        else
        begin
          ARow := ARow + 1;
          ACol := FixedColsVis;
        end;
      end
      else
      begin
        ACol := ACol + 1 + Span.X;
      end;
    end;

    if FNavigation.AdvanceDirection = adTopBottom then
    begin
      if ARow = RowCount - 1 - FFixedFooters then
      begin
        if ACol = ColCount - 1 - FFixedRightCols then
        begin
          if FNavigation.AdvanceInsert then
          begin
            ColCount := ColCount + 1;
            ACol := ACol + 1 + Span.X;
            ARow := FixedRows;
            if Assigned(FOnAutoInsertCol) then
              FOnAutoInsertCol(Self,ColCount - 1 - FFixedRightCols);
          end
          else
          begin
            ARow := FixedRows;
            ACol := FixedColsVis;
          end;
        end
        else
        begin
          ARow := FixedRows;
          ACol := ACol + 1 {+ Span.X};
          if ACol >= ColCount then
            ACol := FixedColsVis;
        end;
        Repaint;
      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;

  rm := RemapCol(ACol);

  CanEdit := true;
  GetCellReadOnly(rm,ARow,CanEdit);

  if not CanEdit {IsEditable(rm,ARow)} then
    AdvanceEdit(ACol,ARow,Advance,Show,Frwrd,True,fromEdit)
  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 Show 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;

      span.X := CellRect(ACol,ARow).Left + 2;
      span.Y := CellRect(ACol,ARow).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
        begin
          HideEditor;
        end;
      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,edNumeric,edUpperCase,edLowerCase,edPositiveNumeric,edLowerCase,edCapital,edMixedCase,edPassword]) then
      begin
        HideEditor;
      end;
    end;
  end;

  if MouseActions.DisjunctRowSelect then
  begin
    ClearRowSelect;
    RowSelect[Row] := true;
  end;

end;

procedure TAdvStringGrid.KeyPress(var Key:Char);
var
  p: Integer;
  RCol: Integer;
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 Navigation.AdvanceOnEnter then
  begin
    if not IsEditable(RCol,Row) then
    begin
      if Assigned(OnKeyPress) then
        OnKeyPress(Self, Key);
      Key := #0;
      Exit;
    end;
  end;

  if (Key = #13) and ((GetFocus <> Handle) or HasStaticEdit(RCol,Row)) then
  begin
    AdvanceEdit(Col,Row,False,False,True,False,EditMode);

    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.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;
begin
  lr := RowCount;

  if (RowCount = FixedRows) and (FixedRowAlways) then
    UnHideSelection;

  inherited RowCount := Value;

  if (RowCount > FFixedRowsMin) and FixedRowAlways then
    FixedRows := FFixedRowsMin;

  if Value > FMaxRowCount then
    FMaxRowCount := Value;

  NormalRowCount := Value;
  UpdateFooter;
  UpdateVScroller;
  UpdateHScroller;
  UpdateScrollBars(false);

  // 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);
begin
  inherited ColCount := Value;

  if (ColCount > FFixedColsMin) and FixedColAlways then
    FixedCols := FFixedColsMin;

  if Value > FMaxColCount then
    FMaxColCount := Value;

  UpdateFooter;
  SetBounds(Left,Top,Width,Height);
  UpdateHScroller;
  UpdateVScroller;
  UpdateScrollBars(false);
end;

function TAdvStringGrid.GetColCountEx: Integer;
begin
  Result := inherited ColCount;
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
  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
    if (Value <> DefaultRowHeight) then
    begin
       for i := 1 to FixedRows do
         RowHeights[i - 1] := Value;
    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: Integer;
  s:string;
  temp: Boolean;

begin
  Result := True;

  for i := 1 to FFilter.Count do
  begin
    with FFilter.Items[i - 1] do
    begin
      case FFilter.Items[i - 1].Data of
      fcVirtual: s := Cells[Column,ARow];
      fcNormal: s := GridCells[Column, ARow];
      fcStripHTML: s := Strippedcells[Column, ARow];
      fcCalculated: s := CalcCell(Column,ARow);
      end;

      if (pos('|\',s) > 0) then
        s := DecodeWideStr(s);

      {
      if (FFilter.Items[i - 1].Data = fcVirtual) then
        s := Cells[Column,ARow]
      else
        s := GridCells[Column,ARow];
      }
      
      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));

      try
        //if s = '' then
        //  temp := Condition = '=""'
        //else
        temp := MatchStrEx(Condition,s,CaseSensitive);
      except
        temp := false;
      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;

  if Assigned(FOnCustomFilter) then
  begin
    temp := Result;
    FOnCustomFilter(Self, ARow, temp);
    Result := temp;
  end;

end;

procedure TAdvStringGrid.FilterRow(ARow: Integer);
begin
  if not MatchFilter(ARow) then
  begin
    HideRow(RemapRowInv(ARow));
  end;
end;

procedure TAdvStringGrid.ApplyFilter;
var
  i: Integer;
  RowsToDo,RowsDone: Integer;
  il: TIntList;

begin
  RowsDone := 0;
  RowsTodo := RowCount - FFixedFooters - FixedRows;

  il := TIntList.Create(0,0);

  for i := FixedRows to RowCount - FFixedFooters - 1 do
  begin
    if not MatchFilter(i) then
      il.Add(i);

    Inc(RowsDone);

    if Assigned(FOnFilterProgress) and (RowsTodo > 0) then
      FOnFilterProgress(Self, Round(100* (RowsDone / RowsTodo)));
  end;

  HideRowList(il);
  il.Free;

  if Assigned(FOnFilterProgress) and (RowsTodo > 0) then
    FOnFilterProgress(Self, Round(100* (RowsDone / RowsTodo)));
end;

procedure TAdvStringGrid.SetFilterActive(const Value: Boolean);
begin
  if FFilterActive <> Value then
  begin
    FFilterActive := Value;
    if FFilterActive then
    begin
      FFilterFixedRows := 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;
      }
    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;
    end;
  end;
  // update floating footer if necessary
  CalcFooter(-1);
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.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;
    Invalidate;
  end;
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.SetAutoSizeP(AAutoSize: Boolean);
begin
  FAutoSize := AAutoSize;
  if FAutosize 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;
begin
  HAlign := taLeftJustify;
  VAlign := VAlignment;

  if FAutoNumAlign then
  begin
    s := Cells[ACol,ARow];
    if Pos('=',s) = 1 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(Trim(s)) in [atNumeric,atFloat,atScientific] then
    begin
      HAlign := taRightJustify;
    end;
  end;

  if HasCellProperties(ACol,ARow) then
  begin
    if not (FAutoNumAlign and (Pos('=',Cells[ACol,ARow]) = 1)) then
      HAlign := CellProperties[ACol,ARow].Alignment
    //else
    //  HAlign := CellProperties[ACol,ARow].Alignment;
  end;

  GetCellAlign(ACol,ARow,HAlign,VAlign);

  Result.Alignment := HAlign;
  Result.VAlignment := VAlign;
end;

function TAdvStringGrid.GetCellTextSize(ACol,ARow: Integer;VS: Boolean): TSize;
var
  s,su,Anchor,Stripped,FocusAnchor,AnchorHint: string;
  MaxSize,NewSize,NumLines,hl,ml: Integer;
  r,hr,cr: TRect;
  ctt: TTextType;
  AState: TGridDrawState;
  HAlign: TAlignment;
  VAlign: TVAlignment;
  WW: Boolean;
  GD: TCellGradientDirection;
  AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  CID,CT,CV: string;
  AAngle: Integer;
  x1,x2,y1,y2: Integer;
  th: Integer;
  {$IFDEF TMSUNICODE}
  ws: widestring;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  cx, cy : integer;
  {$ENDIF}

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(ACol,ARow);

  ctt := TextType(s,FEnableHTML);

  AState := [];

  //2.50.3 -> ACol changed to RemapColInv
  GetVisualProperties(RemapColInv(ACol),ARow,AState,False,True,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlign,VAlign,WW,GD);

  Canvas.Font.Size := Canvas.Font.Size + FZoomFactor;

  if ctt = ttFormula then
    s := CalcCell(ACol,ARow);

  if ctt = ttHTML then
  begin
    {$IFNDEF TMSDOTNET}
    FillChar(r,SizeOf(r),0);
    {$ENDIF}

    //2.7.0.3 modified to take merged cells in account
    r := CellRect(RemapColInv(ACol),ARow);
    InflateRect(r, - FXYOffset.X, - FXYOffset.Y);

    {
    if VS then
      r.Right := ColWidths[ACol] - 4
    else
      r.Right := $ffff;
    }

    if not VS then
      r.Right := $ffff;

    r.Bottom := $ffff;

    {$IFNDEF TMSDOTNET}
    HTMLDrawEx(Canvas,s,r,Gridimages,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);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    cx := 0;
    cy := 0;
    HTMLDrawEx(Canvas,s,r,Gridimages,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(cx),Integer(cy),hl,ml,hr,cr,CID,CT,CV,FImageCache,FContainer,Handle);
    Result.cx := cx;
    Result.cy := cy;
    {$ENDIF}

    Result.cx := Result.cx + 2 + FXYOffset.X * 2;
    Result.cy := Result.cy + 2 + FXYOffset.Y * 2;
    Exit;
  end;

  if ctt = ttRTF then
  begin
    FRichEdit.Clear;
    FRichEdit.Left := 0;
    FRichEdit.Top := 0;
    FRichEdit.Width := 0;
    FRichEdit.Height := 0;

    CellToRich(ACol,ARow,FRichEdit);
    Canvas.Font.Name := FRichEdit.SelAttributes.Name;
    Canvas.Font.Size := FRichEdit.SelAttributes.Size;
    Canvas.Font.Style := FRichEdit.SelAttributes.Style;
    s := FRichEdit.Text;
  end;

  {$IFDEF TMSUNICODE}
  if ctt = ttUnicode then
  begin
    ws := WideCells[ACol,ARow];
    r := CellRect(RemapColInv(ACol),ARow);

    r.Left := r.Left + xyoffset.X;
    r.Right := r.Right - xyoffset.X;

    {
    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) + 2 * FXYOffset.X;
    Exit;
  end;
  {$ENDIF}

  if VS then
  begin
    r := CellRect(RemapColInv(ACol),ARow);

    InflateRect(r,-2 - FXYOffset.X, -2 - FXYOffset.Y);

    // if editing cell and return pressed, calculate height assuming new line
    if EditMode and (RemapColInv(ACol) = Col) and (ARow = Row) and (length(s) > 0) then
    begin
      if s[length(s)] = #10 then
        s := s + 'w';
    end;

    {$IFNDEF TMSDOTNET}
    Result.cy := DrawTextEx(Canvas.Handle,PChar(s),Length(s),r,DT_EDITCONTROL or DT_CALCRECT or DT_WORDBREAK or DT_LEFT or DT_NOPREFIX,nil) + 2 * FXYOffset.Y;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    Result.cy := DrawTextEx(Canvas.Handle,s,Length(s),r,DT_EDITCONTROL or DT_CALCRECT or DT_WORDBREAK or DT_LEFT or DT_NOPREFIX,nil) + 2 * FXYOffset.Y;
    {$ENDIF}
    Result.cx := (r.Right - r.Left) + 2 * FXYOffset.X;
  end
  else
  begin
    repeat
      su := GetNextLine(s,FMultiLineCells);

      if URLShow and not URLFull and (ctt = ttText) then
        StripURLProtoCol(su);

      NewSize := Canvas.TextWidth(su) + 2 * FXYOffset.X;
      if NewSize > MaxSize then
        MaxSize := NewSize;
      Inc(NumLines);
    until s = '';

    Result.cx := MaxSize;
    th := Canvas.TextHeight('gh');
    Result.cy := NumLines * th + 2 * FXYOffset.Y;
  end;

  if IsRotated(ACol,ARow,AAngle) then
  begin
    x1 := Abs(Trunc(Result.cx * cos(AAngle*Pi/180)));
    x2 := Abs(Trunc(Result.cy * sin(AAngle*Pi/180)));

    y1 := Abs(Trunc(Result.cx * sin(AAngle*Pi/180)));
    y2 := Abs(Trunc(Result.cy * cos(AAngle*Pi/180)));

    // distance + correction for font corners
    Result.cx := Abs(x2 - x1) + 12;
    Result.cy := Abs(y2 - y1) + 12;
  end;

  if ctt = ttRTF then
  begin
    r := CellRect(RemapColInv(ACol),ARow);
    FRichEdit.Width := r.Right - r.Left;
    FRichEdit.Height := r.Bottom - r.Top;
    FRichEdit.WordWrap := True;
    FRichEdit.WordWrap := False;
    FRichEdit.WordWrap := FWordWrapEx;

    SetTranspWindow(FRichEdit.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!
    }
    FRichEdit.Lines.Add('');
    FRichEdit.Lines.Delete(FRichEdit.Lines.Count - 1);

    
    Result.cx := FRichEdit.ReqWidth + XYOffset.X * 2;
    Result.cy := FRichEdit.ReqHeight + XYOffset.Y * 2;
  end;
end;

procedure TAdvStringGrid.NCPaintProc;
var
  DC: HDC;
  WindowBrush:hBrush;
  Canvas: TCanvas;

begin
  if not (Look in [glSoft,glTMS,glXP,glVista,glListView]) then
    Exit;

  if BorderStyle = bsNone then
    Exit;
  if Flat then
    Exit;

  DC := GetWindowDC(Handle);
  WindowBrush := 0;
  try
    Canvas := TCanvas.Create;
    Canvas.Handle := DC;

    WindowBrush := CreateSolidBrush(ColorToRGB(clRed));

    if FIsWinXP then
      Canvas.Pen.Color := $B99D7F
    else
      Canvas.Pen.Color := clGray;

    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;

    Canvas.Free;

    // FrameRect(DC, ARect, WindowBrush);
  finally
    DeleteObject(WindowBrush);
    ReleaseDC(Handle,DC);
  end;
end;

{$IFNDEF TMSDOTNET}
procedure TAdvStringGrid.WMNotify(var Message: TWMNOTIFY);
{$ENDIF}
{$IFDEF TMSDOTNET}
procedure TAdvStringGrid.WMNotify(var Message: TWMNOTIFYTT);
{$ENDIF}
var
  buffer:array[0..255] of char;
  pt: TPoint;
  {$IFDEF TMSDOTNET}
  di: TToolTipText;
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  di: PNMTTDispInfo;
  {$ENDIF}
  ATitle, AText, s: string;
  AIcon: Integer;
  cellX,cellY: Integer;
  len1, len2, i: Integer;
  FDateTime: TDateTime;

begin

  {$IFDEF TMSDOTNET}
  with Message.NMHdr do
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  with Message.NMHdr^ do
  {$ENDIF}
    case code of
    TTN_NEEDTEXT:
    begin
      if not Balloon.Enable then
        Exit;

      {$IFDEF TMSDOTNET}
      di := Message.ToolTipText;
      {$ENDIF}

      {$IFNDEF TMSDOTNET}
      di := PNMTTDispInfo(TMessage(Message).LParam);
      {$ENDIF}

      GetCursorPos(pt);
      pt := ScreenToClient(pt);

      MouseToCell(pt.X,pt.Y,cellX,cellY);

      //ATitle := 'test';
      //AText := 'hello world '+inttostr(cellx)+':'+inttostr(celly);


      if (cellx <> -1) and (celly <> -1) then
      begin
        s := Cells[cellX,cellY];

        case TextType(s,FEnableHTML) of
        ttUnicode: s := WideCells[cellX, cellY];
        ttRTF:
          begin
            CellToRich(cellX, cellY, RichEdit);
            s := RichEdit.Text;
          end;
        ttHTML: s := HTMLStrip(s);
        else
          s := Cells[cellX, cellY];
        end;

        AText := s;
      end;

      {$IFNDEF TMSDOTNET}
      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);
      {$ENDIF}

      AIcon := 1;
      // for some reason, balloon tips will not show multiline when there is no title  ...
      if ATitle = '' then
        ATitle := ' ';

      if Assigned(OnCellBalloon) then
         OnCellBalloon(self, cellX, cellY, ATitle, AText, AIcon);

      FLastBalloonPos := Point(cellX, cellY);

      {$IFNDEF TMSDOTNET}
      strpcopy(ftooltipbuffer,AText);

      if length(ATitle) > 100 then
        ATitle := copy(ATitle,1, 97) + '...';

      strpcopy(buffer,ATitle);

      di^.lpszText := @ftooltipbuffer;
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      di.lpszText := AText;
      Message.ToolTipText := di;
      {$ENDIF}

      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);

      {$IFDEF TMSDOTNET}
      SendTextMessage(fhtooltip,TTM_SETTITLE,AIcon,ATitle);
      {$ENDIF}
      {$IFNDEF TMSDOTNET}
      SendMessage(fhtooltip,TTM_SETTITLE,AIcon,longint(@buffer));
      {$ENDIF}
    end;
    TTN_SHOW:
    begin
    end;
    TTN_POP:
    begin
    end;

    DTN_DATETIMECHANGE:
    begin
      if Assigned(FOnDateTimeChange) then
      begin
        {$IFNDEF TMSDOTNET}
        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;
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        FOnDateTimeChange(Self, Col, Row, DateTimePicker.DateTime);
        {$ENDIF}
      end;
      inherited;
    end;

    else
      inherited;
    end;

end;


{$IFNDEF TMSDOTNET}
procedure TAdvStringGrid.WMNCPaint(var Message: TMessage);
begin
  inherited;
  if FUpdateCount > 0 then Exit;
  NCPaintProc;
  Message.Result := 0;
end;
{$ENDIF}

(*
function TAdvStringGrid.MouseOverDesignChoice(X, Y: Integer): Integer;
var
  r: TRect;
  fh: Integer;
begin
  Result := -1;
  r := ClientRect;
  Canvas.Font.Name := 'Tahoma';
  Canvas.Font.Size := 8;

  fh := Canvas.TextHeight('gh') + 2;
  if (x > r.Right - 150) and (x < r.Right - 150 + Canvas.TextWidth(s_AddAllFields)) and
    (y > r.Bottom - 40 + fh + 4) and
    (y < r.Bottom - 40 + 2 * fh + 4) then
    Result := 1;
  {
  if (x > r.Right - 150) and (x < r.Right - 150 + Canvas.TextWidth(s_RemoveAllFields)) and
    (y > r.Bottom - 70 + 2 * fh + 4) and
    (y < r.Bottom - 70 + 3 * fh + 4) then
    Result := 2;

  if (x > r.Right - 150) and (x < r.Right - 150 + Canvas.TextWidth(s_RemoveAllColumns)) and
    (y > r.Bottom - 70 + 3 * fh + 4) and
    (y < r.Bottom - 70 + 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) 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);
      {$IFNDEF TMSDOTNET}
      InvalidateRect(Handle, @r, true);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      InvalidateRect(Handle, r, true);
      {$ENDIF}
    end;

    FLastDesignChoice := nc;

    if nc in [1, 2, 3] then
      Msg.Result := 1;
  end;
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,1,1);

  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,1,1);

  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.Paint;
var
  R: TRect;
//  fh,i: Integer;
//  P: TPoint;

begin
  Canvas.Pen.Style := psSolid;

  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;

  (*
  if (csDesigning in ComponentState) then
  begin
    r := ClientRect;
    Canvas.Font.Name := 'Tahoma';
    Canvas.Font.Size := 8;
    Canvas.Brush.Color := clInfoBk;
    Canvas.Pen.Color := clRed;
    r.Left := r.Right - 150;
    r.Top := r.Bottom - 40;
    Canvas.Rectangle(r);
    Canvas.Font.Color := clNavy;
    Canvas.Font.Style := [fsUnderline];
    fh := Canvas.TextHeight('gh') + 2;
    Canvas.TextOut(r.Left + 4, r.Top + 4, s_QuickConfig);
    GetCursorPos(P);
    P := ScreenToClient(P);
//    i := MouseOverDesignChoice(P.X, P.Y);

    if i = 1 then
      Canvas.Font.Style := [fsUnderline]
    else
      Canvas.Font.Style := [];
    Canvas.TextOut(r.Left + 4, r.Top + 4 + fh, s_Gallery);
  end;
  *)

  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;
  {$IFDEF TMSDOTNET}
  ap: array of TPoint;
  {$ENDIF}

begin
  CellToRich(ACol,ARow,FRichEdit);

  if FMouseActions.RowSelectPersistent then
    RRow := RemapRowInv(ARow)
  else
    RRow := ARow;

  FRichEdit.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
      FRichEdit.SelStart := 0;
      FRichEdit.SelLength := $FFFF;
      if FSelectionTextColor <> clNone then
        FRichEdit.SelAttributes.Color := FSelectionTextColor;
    end;
  end;

  {$IFNDEF TMSDOTNET}
  FillChar(fr, SizeOf(TFormatRange), 0);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  SetLength(ap, 2);
  ap[0] := ARect.TopLeft;
  ap[1] := ARect.BottomRight;
  lptodp(Canvas.Handle,ap,2);
  ARect.TopLeft := ap[0];
  ARect.BottomRight := ap[1];
  {$ENDIF}

  {$IFNDEF TMSDOTNET}
  lptodp(Canvas.Handle,ARect.Topleft,1);
  lptodp(Canvas.Handle,ARect.Bottomright,1);
  {$ENDIF}

  nLogPixelsX := GetDeviceCaps(Canvas.Handle,LOGPIXELSX);
  nLogPixelsY := GetDeviceCaps(Canvas.Handle,LOGPIXELSY);

  pt.x := XYOffset.X;
  pt.y := XYOffset.Y;

  {$IFNDEF TMSDOTNET}
  dptolp(Canvas.Handle,pt,1);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  ap[0] := pt;
  dptolp(Canvas.Handle,ap,1);
  pt := ap[0];
  {$ENDIF}

  RtfOffsetX := ((pt.x * nLogPixelsX) div 96);
  RtfOffsetY := ((pt.x * nLogPixelsX) div 96);

  with fr do
  begin
    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;
  end;

  mm := GetMapMode(Canvas.Handle);
  SetMapMode(Canvas.Handle,mm_text);

  {$IFNDEF TMSDOTNET}
  SendMessage(FRichEdit.Handle,EM_FORMATRANGE,1,Integer(@fr));
  {$ENDIF}

  {$IFDEF TMSDOTNET}
   Perform(EM_FORMATRANGE,1,fr);
  {$ENDIF}

  {clear the richtext cache}
  SendMessage(FRichEdit.Handle,EM_FORMATRANGE,0,0);

  SetMapMode(Canvas.Handle,mm);
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);
begin
  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.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;

begin
  if FSaveVirtCells then
    Result := DisplCells[ACol,ARow]
  else
    Result := GridCells[ACol,ARow];

  if (Result = '') and (CellTypes[ACol,ARow] = ctCheckBox) then
  begin
    GetCheckBoxState(ACol,ARow,State);
    if State then
      Result := GetCheckTrue(ACol,ARow)
    else
      Result := GetCheckFalse(ACol,ARow);
  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;
  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
  left := x;
  vpos := y;

  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
        {$IFDEF DELPHI3_LVL}
        FSortSettings.IndexUpGlyph.Transparent := True;
        FSortSettings.IndexUpGlyph.TransparentMode := tmAuto;
        {$ENDIF}
        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
        {$IFDEF DELPHI3_LVL}
        FSortSettings.IndexDownGlyph.Transparent := True;
        FSortSettings.IndexDownGlyph.TransparentMode := tmAuto;
        {$ENDIF}
        Canvas.Draw(Left - 7,vpos - 7,FSortSettings.IndexDownGlyph);
      end;
      Canvas.Textout(Left - 2,vpos - 2,inttostr(idx+1));
    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
      {$IFDEF DELPHI3_LVL}
      FSortSettings.DownGlyph.Transparent := True;
      FSortSettings.DownGlyph.TransparentMode := tmAuto;
      {$ENDIF}
      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
      {$IFDEF DELPHI3_LVL}
      FSortSettings.UpGlyph.Transparent := True;
      FSortSettings.UpGlyph.TransparentMode := tmAuto;
      {$ENDIF}
      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;
end;


procedure TAdvStringGrid.DrawCell(ACol, ARow : longint; ARect : TRect;
  AState : TGridDrawState);
begin
  inherited DrawCell(ACol,ARow,ARect,AState);
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;

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
      AFont.Assign(Font);
  end;


  if Remap then
    RCol := RemapCol(ACol)
  else
    RCol := ACol;

  if MouseActions.DisjunctRowSelect and MouseActions.RowSelectPersistent then
    RRow := RemapRowInv(ARow)
  else
    RRow := ARow;

  ABrush.Color := clNone;
  AColorTo := clNone;
  AMirrorColor := clNone;
  AMirrorColorTo := clNone;
  isCtrl := false;
  hasBrush := false;

  if HasCellProperties(RCol,ARow) then
  begin
    cp := CellProperties[RCol,ARow];
    ct := CellTypes[ACol,ARow];

    if (ct in [ctEmpty,ctNone]) then
    begin
      if cp.BrushColor <> clNone then
        ABrush.Color := cp.BrushColor;
    end
    else
    begin
      isCtrl := ct in [ctCheckBox, ctRadio, ctDataCheckBox, ctButton];
      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 cp.FontSize <> 0 then
      AFont.Size := cp.FontSize;

    if cp.FontName <> '' then
      AFont.Name := cp.FontName;

    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.FTotalLength > 0 then
      begin
        if (((ARow - FixedRows) mod FBands.FTotalLength) < FBands.FPrimaryLength) 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 then
  begin
    ABrush.Color := FixedColor;
    //AFont.Color := FFixedFont.Color;
    //3.1
    AFont.Assign(FFixedFont);
    AState := AState + [gdFixed];
  end;


  if Print then
    GetCellPrintColor(RCol,ARow,AState,ABrush,AFont)
  else
    GetCellColor(RCol,ARow,AState,ABrush,AFont);

  if (ACol >= FixedCols) and (ARow >= FixedRows) and MouseActions.DisjunctRowSelect
    and not Print and Select and ShowSelection 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];
      ABrush.Color := FSelectionColor;
      AColorTo := FSelectionColorTo;
      AMirrorColor := FSelectionMirrorColor;
      AMirrorColorTo := FSelectionMirrorColorTo;

      if FSelectionTextColor <> clNone then
        AFont.Color := FSelectionTextColor;
    end;
  end;

  if (ARow >= FixedRows) and (ACol >= FixedCols) and MouseActions.DisjunctColSelect
    and not Print and Select and ShowSelection 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 ShowSelection and not FixedCell and
    (IsSelected(ACol,ARow) and not (MouseActions.DisjunctRowSelect or MouseActions.DisjunctColSelect))
    or ((gdSelected in AState) and FMouseDown and ShowSelection) then
  begin
    ABrush.Color := FSelectionColor;
    AColorTo := FSelectionColorTo;
    AMirrorColor := FSelectionMirrorColor;
    AMirrorColorTo := FSelectionMirrorColorTo;

    if FSelectionTextColor <> clNone then
      AFont.Color := FSelectionTextColor;
    AState := AState + [gdSelected];
  end;

  if MouseActions.DisjunctCellSelect and ShowSelection then
  {$IFNDEF TMSDOTNET}
    if FSelectedCells.IndexOf(Pointer(MakeLong(ACol,ARow))) <> -1 then
  {$ENDIF}
  {$IFDEF TMSDOTNET}
    if FSelectedCells.IndexOf(TObject(MakeLong(ACol,ARow))) <> -1 then
  {$ENDIF}
    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 := self.Color;
        AFont.Color := Font.Color;
      end;
    end;

  {$IFDEF FREEWARE}
  if (ARow = RowCount - 1) then
    AFont.Color := clSilver;
  {$ENDIF}

  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;
  {$IFDEF DELPHI6_LVL}
  icg: ICellGraphic;
  io: TInterfacedPersistent;
  {$ENDIF}

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
    ctBitmap:
    begin
      W := cg.CellBitmap.Width;
      H := cg.CellBitmap.Height;
    end;
    {$IFDEF DELPHI6_LVL}
    ctInterface:
    begin
      {$IFNDEF TMSDOTNET}
      io := TInterfacedPersistent(cg.CellBitmap);
      if io.GetInterface(ICellGraphic, icg) then
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      io := cg.CellInterface;
      icg := ICellGraphic(io.GetType.GetInterface(typeof(ICellGraphic).FullName));
      if icg <> nil then
      {$ENDIF}
      begin
        W := icg.CellWidth;
        H := icg.CellHeight;
      end;
    end;
    {$ENDIF}
    ctButton,ctBitButton:
    begin
      W := cg.CellIndex and $FFFF;
      H := (cg.CellIndex and $FFFF0000) shr 16;
    end;
    ctFilePicture, ctPicture:
    begin
      pt := CellSize(ACol,ARow);
      pt := cg.GetPictureSize(pt.X,pt.Y,False);
      W := pt.X;
      H := pt.Y;
    end;
    ctCheckBox:
    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
      if Assigned(FGridImages) then
      begin
        W := FGridImages.Width;
        H := FGridImages.Height;
        if cg.CellType = ctDataImage then
          DisplText := False;
      end;
    end;
    ctImages:
    begin
      if Assigned(FGridImages) then
      begin
        if cg.CellBoolean then
        begin
          W := FGridImages.Width * CellImages[ACol,ARow].Count;
          H := FGridImages.Height;
        end
        else
        begin
          H := FGridImages.Height * CellImages[ACol,ARow].Count;
          W := FGridImages.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.SetComponentStyle(AStyle: TTMSStyle);
begin
  SetStyle(TAdvGridStyle(AStyle));
end;


procedure TAdvStringGrid.SetStyle(AStyle: TAdvGridStyle);
begin
  SelectionTextColor := clBlack;
  
  case AStyle of
    gsOffice2003Blue:
      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;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      end;
    gsOffice2003Silver:
      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;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      end;
    gsOffice2003Olive:
      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;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      end;
    gsOffice2003Classic:
      begin
      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;
      end;
    gsOffice2007Luna:
      begin
      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 := $E5D7D0;
      GridFixedLineColor := clGray;
      SelectionColor := $5EC1F1;
      end;
    gsOffice2007Obsidian:
      begin
      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;
      end;
    gsOffice2007Silver:
      begin
      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;
      end;
    gsWindowsXP:
      begin
      FActiveCellColor := clBtnFace;
      FActiveCellColorTo := clBtnFace;
      FTMSGradFrom := clBtnFace;
      FTMSGradTo := clBtnFace;
      FTMSGradMirrorFrom := clNone;
      FTMSGradMirrorTo := clNone;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      FSearchFooter.Color := clBtnFace;
      FSearchFooter.ColorTo := clBtnFace;
      SelectionColor := clHighLight;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      end;
    gsWindowsVista:
      begin
      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;

      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 := clBtnFace;
      FActiveCellColorTo := clBtnFace;
      FControlLook.FixedGradientFrom := clNone;
      FControlLook.FixedGradientTo := clNone;
      FSearchFooter.Color := clBtnFace;
      FSearchFooter.ColorTo := clBtnFace;
      SelectionColor := $00EACAB6;
      SelectionTextColor := clWhite;

      GridLineColor := clSilver;
      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;
      SelectionColor := clHighLight;
      GridLineColor := clSilver;
      GridFixedLineColor := clGray;
      end;
  end;
  Invalidate;
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
  eTheme: TXPColorScheme;

  function CurrentXPTheme: TXPColorScheme;
  var
    {$IFNDEF TMSDOTNET}
    FileName, ColorScheme, SizeName: WideString;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    FileName, ColorScheme, SizeName: StringBuilder;
    {$ENDIF}
  begin
    Result := xpNone;

    if FIsWinVista then
      Result := vistaAero
    else
    if IsWinXP then
    begin
      if IsThemeActive then
      begin
        {$IFDEF TMSDOTNET}
        FileName := StringBuilder.Create(255);
        SizeName := StringBuilder.Create(255);
        ColorScheme := StringBuilder.Create(255);
        GetCurrentThemeName(FileName, 255, ColorScheme, 255, SizeName, 255);
        if(ColorScheme.ToString = 'NormalColor') then
          Result := xpBlue
        else if (ColorScheme.ToString = 'HomeStead') then
          Result := xpGreen
        else if (ColorScheme.ToString = 'Metallic') then
          Result := xpGray
        else
          Result := xpNone;
        {$ENDIF}

        {$IFNDEF TMSDOTNET}
        SetLength(FileName, 255);
        SetLength(ColorScheme, 255);
        SetLength(SizeName, 255);
        GetCurrentThemeName(PWideChar(FileName), 255,
        PWideChar(ColorScheme), 255, PWideChar(SizeName), 255);

        if(PWideChar(ColorScheme)='NormalColor') then
          Result := xpBlue
        else if (PWideChar(ColorScheme)='HomeStead') then
          Result := xpGreen
        else if (PWideChar(ColorScheme)='Metallic') then
          Result := xpGray
        else
          Result := xpNone;

        {$ENDIF}
      end;
    end;
  end;

begin
  eTheme := CurrentXPTheme();
  SetTheme(eTheme);
end;



function TAdvStringGrid.GetFormattedCell(ACol,ARow: Integer): string;
var
  IsFloat: Boolean;
  Fmt: string;
  f: extended;
  d: integer;
begin
  Result := Cells[ACol,ARow];

  if Assigned(OnGetFloatFormat) then
  begin
    IsFloat := IsType(Result) in [atNumeric,atFloat,atScientific];
    if IsFloat then
    begin
      Fmt := FloatFormat;
      OnGetFloatFormat(Self,ACol,ARow,IsFloat,Fmt);
      if IsFloat then
      begin
        try
          if pos('d',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;
    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;

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 ShowSelection 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;

          {$IFNDEF TMSDOTNET}
          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);
          {$ENDIF}

          {$IFDEF TMSDOTNET}
          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);
          {$ENDIF}

        end;
      end;
    end;
  end;
end;


procedure TAdvStringGrid.DrawGridCell(Canvas: TCanvas; ACol, ARow : longint; ARect : TRect;
  AState : TGridDrawState);
const
  WordWraps: array[Boolean] of DWORD = (DT_SINGLELINE,DT_WORDBREAK or DT_EDITCONTROL);
  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: string;
  xsize,ysize: Integer;
  ctt: TTextType;
  cg: TCellGraphic;
  OCol,RRow: Integer;
  FOldBrushColor,FOldFontColor, AColorTo,AMirrorColor,AMirrorColorTo: TColor;
  BRect, DRect, CRect: TRect;
  OrigRight,lvl, Hold: Integer;
  HTheme: THandle;
  pt: TPoint;
  CellWW: boolean;
  GD: TCellGradientDirection;
  Settings: TGaugeSettings;
  ci: integer;
  brshColor: TColor;
  brdrColor: TColor;
  BStyle: dword;
  {$IFDEF DELPHI6_LVL}
  io: TInterfacedPersistent;
  icg: ICellGraphic;
  {$ENDIF}

  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 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(tr.Left - GLWV, tr.Top - GLWH);
      Canvas.LineTo(tr.Left - GLWV, tr.Bottom);
    end;

    if cbRight in Borders then
    begin
      Canvas.Pen.Assign(PenR);
      Canvas.MoveTo(tr.Right - 1,tr.Top);
      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,tr.Top  - GridLineWidth);
        Canvas.LineTo(tr.Right,tr.Top  - GridLineWidth);
      end;
    end;

    if cbBottom in Borders then
    begin
      Canvas.Pen.Assign(PenB);
      Canvas.MoveTo(tr.Left - 1 - GridLineWidth,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);
  var
    DrawState: Integer;
    DrawRect: TRect;
    BMP: TBitmap;
    HTheme: THandle;
    cstyle: TControlStyle;

  begin
    if ControlLook.NoDisabledCheckRadioLook or ControlLook.CheckAlwaysActive then
      Enabled := true;

    cstyle := ControlStyle;
    if (cstyle = csTheme) and not FIsWinXP then
      cstyle := csClassic;

    case cstyle of
    csClassic,csFlat:
      begin
        if State then
          DrawState := DFCS_BUTTONCHECK or DFCS_CHECKED
        else
          DrawState := DFCS_BUTTONCHECK;

        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;
          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(False);
          {$ELSE}
          SetGridOrientation(False);
          {$ENDIF}
        end;

        DrawFrameControl(Canvas.Handle,DrawRect,DFC_BUTTON,DrawState);

        if UseRightToLeftAlignment then
        begin
          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(True);
          {$ELSE}
          SetGridOrientation(True);
          {$ENDIF}
          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;

          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(False);
          {$ELSE}
          SetGridOrientation(False);
          {$ENDIF}
        end;

        Canvas.Draw(R.Left,R.Top,bmp);
        Bmp.free;

        if UseRightToLeftAlignment then
        begin
          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(True);
          {$ELSE}
          SetGridOrientation(True);
          {$ENDIF}
        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;

          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(False);
          {$ELSE}
          SetGridOrientation(False);
          {$ENDIF}
        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
          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(True);
          {$ELSE}
          SetGridOrientation(True);
          {$ENDIF}
        end;

      end;
    csTheme:
      begin
        if FIsWinXP then
        begin
          {$IFNDEF TMSDOTNET}
          HTheme := OpenThemeData(Self.Handle,'button');

          r := Rect(R.Left, R.Top, R.Left + FControlLook.CheckSize, R.Top + FControlLook.CheckSize);

          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;

          CloseThemeData(HTheme);
          {$ENDIF}
          {$IFDEF TMSDOTNET}
          HTheme := OpenThemeData(Self.Handle,'button');

          r := Rect(R.Left, R.Top, R.Left + FControlLook.CheckSize, R.Top + FControlLook.CheckSize);

          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;

          CloseThemeData(HTheme);
          {$ENDIF}

        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;

          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(False);
          {$ELSE}
          SetGridOrientation(False);
          {$ENDIF}
        end;

        Canvas.Draw(R.Left,R.Top,bmp);
        Bmp.free;

        if UseRightToLeftAlignment then
        begin
          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(True);
          {$ELSE}
          SetGridOrientation(True);
          {$ENDIF}
        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;

          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(False);
          {$ELSE}
          SetGridOrientation(False);
          {$ENDIF}

        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
          {$IFDEF DELPHI6_LVL}
          ChangeGridOrientation(True);
          {$ELSE}
          SetGridOrientation(True);
          {$ENDIF}
        end;

      end;
    end;
  end;

  // Draws graphic in the cell
  procedure DrawCellGraphic(r: TRect; CellGraphic: TCellGraphic; VertAlign: TVAlignment);
  var
    TgtRect,SrcRect: TRect;
    tmpbmp: TBitmap;
    srcColor: TColor;
    idx: Integer;
    s: string;
    IsEdit: Boolean;
    DrawStyle : DWord;
    HTheme: THandle;
    VA: TCellVAlign;
    {$IFDEF DELPHI6_LVL}
    io: TInterfacedPersistent;
    icg: ICellGraphic;
    {$ENDIF}

  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, ctRowCheckBox] 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,ctVirtCheckBox,ctRowCheckBox:
    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;

      IsEdit := True;

      GetCellReadOnly(ACol,ARow,IsEdit);

      if (CellGraphic.CellType in [ctCheckBox,ctRowCheckBox]) then
        DrawCheck(TgtRect,CellGraphic.CellBoolean,IsEdit,FControlLook.ControlStyle)
      else
        DrawCheck(TgtRect,Cells[ACol,ARow] = GetCheckTrue(ACol,ARow),IsEdit,FControlLook.ControlStyle);
    end;

    ctRotated:
    begin
      SrcRect := r;

      CalcTextPos(SrcRect,CellGraphic.CellAngle,Cells[ACol,ARow],HAlignment,VAlign);

      {$IFNDEF TMSDOTNET}
      GetObject(Canvas.Font.Handle,SizeOf(LFont),Addr(LFont));
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      GetObject(Canvas.Font.Handle,Marshal.SizeOf(TypeOf(LFont)),LFont);
      {$ENDIF}
      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,-2,-2);

      Canvas.Brush.Style := bsCLear;
      Canvas.TextRect(r,SrcRect.Left,SrcRect.Top,Cells[ACol,ARow]);

      hNewFont := SelectObject(Canvas.Handle,hOldFont);
      DeleteObject(hNewFont);
    end;

    ctComment:
    begin
      if ControlLook.CommentColor <> clNone then
      begin
        Canvas.Pen.Color := ControlLook.CommentColor;

        {$IFDEF TMSDOTNET}
        if CellGraphic.CellColor <> clNone then
          Canvas.Pen.Color := CellGraphic.CellColor;
        {$ENDIF}

        {$IFNDEF TMSDOTNET}
        if TColor(CellGraphic.CellAngle) <> clNone then
          Canvas.Pen.Color := TColor(CellGraphic.CellAngle);
        {$ENDIF}

        Canvas.Brush.Color := Canvas.Pen.Color;
        Canvas.Polygon([Point(r.Right-7,r.Top+1),Point(r.Right-2,r.Top+1),Point(r.Right-2,r.Top+6)]);
        Canvas.Brush.Color := Self.Color;
      end;
    end;

    ctProgressPie:
    begin
      {$IFNDEF TMSDOTNET}
      DrawProgressPie(Canvas,Rect(TgtRect.left,TgtRect.Top,TgtRect.left+20,TgtRect.Top+20),TColor(CellGraphic.CellBitmap),CellGraphic.CellAngle, false);
      {$ENDIF}

      {$IFDEF TMSDOTNET}
      DrawProgressPie(Canvas,Rect(TgtRect.left,TgtRect.Top,TgtRect.left+20,TgtRect.Top+20),CellGraphic.CellColor,CellGraphic.CellAngle, false);
      {$ENDIF}
    end;

    ctRangeIndicator:
    begin
      InflateRect(r,-ControlLook.ProgressMarginX,-ControlLook.ProgressMarginY);

      with CellGraphic do
      {$IFNDEF TMSDOTNET}
        DrawRangeIndicator(Canvas,r,Ints[ACol,ARow],CellIndex,CellBoolean,TColor(CellBitmap),TColor(CellIcon));
      {$ENDIF}
      {$IFDEF TMSDOTNET}
        DrawRangeIndicator(Canvas,r,Ints[ACol,ARow],CellIndex,CellBoolean,CellColor,CellBKColor);
      {$ENDIF}
    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  := self.Font;
      Settings.Font.Color := 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(Ints[ACol,ARow] / (CellGraphic.CellErrLen - CellGraphic.CellErrFrom) * 100), Settings);
    end;

    ctProgress:
    begin
      if (ControlLook.ControlStyle in [csWinXP,csTheme]) and FIsWinXP and ControlLook.ProgressXP then
      begin
        {$IFNDEF TMSDOTNET}
        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)*(Floats[ACol,ARow])/100);

        DrawThemeBackground(HTHeme,Canvas.Handle,PP_CHUNK,1,@SrcRect,nil);

        CloseThemeData(HTheme);
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        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)*(Floats[ACol,ARow])/100);

        DrawThemeBackground(HTHeme,Canvas.Handle,PP_CHUNK,1,SrcRect,nil);

        CloseThemeData(HTheme);
        {$ENDIF}
      end
      else
      begin
        InflateRect(r,-2,-2);

        {$IFNDEF TMSDOTNET}
        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);

        {$ENDIF}

        {$IFDEF TMSDOTNET}
        with CellGraphic do
        if CellBoolean then
          DrawProgressLin(Canvas,r,CellColor, CellTextFGColor,
            CellBKColor,CellTextBKColor,Floats[ACol,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor,false)
        else
          DrawProgressLin(Canvas,r,CellColor,CellColor xor $FFFFFF,
            CellBKColor,CellBKColor xor $FFFFFF,Floats[ACol,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor,false);
        {$ENDIF}
      end;
    end;

    {$IFDEF DELPHI6_LVL}
    ctInterface:
    begin
      {$IFNDEF TMSDOTNET}
      io := TInterfacedPersistent(cg.CellBitmap);
	  if io.GetInterface(ICellGraphic, icg) then
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      io := cg.CellInterface;
      icg := ICellGraphic(io.GetType.GetInterface(typeof(ICellGraphic).FullName));
      if icg <> nil then
      {$ENDIF}
      begin
        icg.Draw(Canvas, Rect(r.Left-1,r.Top-1,r.Right,r.Bottom), ACol,ARow, (gdSelected in AState), self);
      end;
    end;
    {$ENDIF}
    
    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;
      end
      else
        Canvas.Draw(TgtRect.Left,TgtRect.Top,CellGraphic.CellBitmap);
    end;

    ctButton,ctBitButton:
    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 FIsWinXP then
      begin
        if IsThemeActive then
        begin
          {$IFNDEF TMSDOTNET}
          HTheme := OpenThemeData(Self.Handle,'button');

          if CellGraphic.cellBoolean then
          begin
            if not IsEdit then
              DrawStyle := PBS_DISABLED
            else
              DrawStyle := PBS_PRESSED;

            DrawThemeBackground(HTheme,Canvas.Handle, BP_PUSHBUTTON,DrawStyle ,@TgtRect,nil);
            InflateRect(TgtRect,-3,-3);
          end
          else
          begin
            if not IsEdit then
              DrawStyle := PBS_DISABLED
            else
              DrawStyle := PBS_NORMAL;
            DrawThemeBackground(HTheme,Canvas.Handle, BP_PUSHBUTTON,DrawStyle ,@TgtRect,nil);
            InflateRect(TgtRect,-2,-2);
          end;

          CloseThemeData(HTheme);
          {$ENDIF}

          {$IFDEF TMSDOTNET}
          HTheme := OpenThemeData(Self.Handle,'button');

          if CellGraphic.cellBoolean then
          begin
            if not IsEdit then
              DrawStyle := PBS_DISABLED
            else
              DrawStyle := PBS_PRESSED;

            DrawThemeBackground(HTheme,Canvas.Handle, BP_PUSHBUTTON,DrawStyle ,TgtRect,nil);
            InflateRect(TgtRect,-3,-3);
          end
          else
          begin
            if not IsEdit then
              DrawStyle := PBS_DISABLED
            else
              DrawStyle := PBS_NORMAL;
            DrawThemeBackground(HTheme,Canvas.Handle, BP_PUSHBUTTON,DrawStyle ,TgtRect,nil);
            InflateRect(TgtRect,-2,-2);
          end;

          CloseThemeData(HTheme);
          {$ENDIF}

        end;
      end
      else
      begin
        DrawStyle := DFCS_BUTTONPUSH;
        if FControlLook.FlatButton then
          DrawStyle := DrawStyle or DFCS_FLAT;

        if CellGraphic.cellBoolean then
        begin
          DrawFrameControl(Canvas.Handle,TgtRect,DFC_BUTTON, DrawStyle or DFCS_PUSHED);
          InflateRect(TgtRect,-3,-3);
        end
        else
        begin
          DrawFrameControl(Canvas.Handle,TgtRect,DFC_BUTTON,DrawStyle);
          InflateRect(TgtRect,-2,-2);
        end;
      end;

      //Canvas.Font.Assign(Font);

      if CellGraphic.CellType = ctBitButton then
      begin
        if not Cellgraphic.CellBitmap.Empty then
        begin
          DrawBitmapTransp(Canvas,Cellgraphic.CellBitmap,clBtnFace,TgtRect);
          TgtRect.Left := TgtRect.Left + Cellgraphic.CellBitmap.Width + 2;
        end;
      end;

      if Pos(#13,s) = 0 then
        BStyle := DT_SINGLELINE
      else
        BStyle := DT_WORDBREAK;

      SetBkMode(Canvas.Handle,TRANSPARENT);
      {$IFNDEF TMSDOTNET}
      DrawText(Canvas.Handle,PChar(s),Length(s),TgtRect,DT_CENTER or DT_VCENTER or DT_END_ELLIPSIS or BStyle);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      DrawText(Canvas.Handle,s,Length(s),TgtRect,DT_CENTER or DT_VCENTER or DT_END_ELLIPSIS or BStyle);
      {$ENDIF}
      SetBKColor(Canvas.Handle,srcColor);
    end;

    ctPicture:
    begin
      {$IFNDEF TMSDOTNET}
      if (CellGraphic.CellAngle=0) then
        Canvas.Draw(TgtRect.Left,TgtRect.Top,TPicture(CellGraphic.CellBitmap).Graphic)
      else
        Canvas.StretchDraw(TgtRect,TPicture(CellGraphic.CellBitmap).Graphic);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      if (CellGraphic.CellAngle=0) then
        Canvas.Draw(TgtRect.Left,TgtRect.Top,CellGraphic.CellPicture.Graphic)
      else
        Canvas.StretchDraw(TgtRect,CellGraphic.CellPicture.Graphic);
      {$ENDIF}
    end;

    ctFilePicture:
    begin
      {$IFDEF TMSDOTNET}
      CellGraphic.CellFilePicture.DrawPicture(Canvas,TgtRect);
      {$ENDIF}
      {$IFNDEF TMSDOTNET}
      TFilepicture(CellGraphic.CellBitmap).DrawPicture(Canvas,TgtRect);
      {$ENDIF}
    end;

    ctIcon:
    begin
      Canvas.Draw(TgtRect.Left,TgtRect.Top,CellGraphic.cellIcon);
    end;

    ctRadio:
    begin
      IsEdit := True;
      GetCellReadOnly(ACol,ARow,IsEdit);

      {$IFNDEF TMSDOTNET}
      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);
      {$ENDIF}

      {$IFDEF TMSDOTNET}
      DrawRadio(Canvas,r,GetRadioStrings(ACol,ARow).Count,CellGraphic.CellIndex,CellGraphic.cellBoolean,not IsEdit,
                CellGraphic.CellStrings, gdSelected in AState, ACol,ARow, ControlLook.ControlStyle, 1.0);
      {$ENDIF}
    end;

    ctImageList:
    begin
      if Assigned(FGridImages) then
        FGridImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,CellGraphic.CellIndex);
    end;

    ctImages:
    begin
      if Assigned(FGridImages) then
      begin
        {$IFDEF TMSDOTNET}
        for idx := 1 to CellGraphic.CellList.Count do
        begin
          FGridImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,CellGraphic.CellList.Items[idx-1]);
           if CellGraphic.CellBoolean then
             TgtRect.Left := TgtRect.Left + Gridimages.Width
           else
             TgtRect.Top := TgtRect.Top + Gridimages.Height;
        end;
        {$ENDIF}

        {$IFNDEF TMSDOTNET}
        for idx := 1 to TIntList(CellGraphic.CellBitmap).Count do
        begin
          FGridImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,TIntList(CellGraphic.CellBitmap).Items[idx-1]);
           if CellGraphic.CellBoolean then
             TgtRect.Left := TgtRect.Left + Gridimages.Width
           else
             TgtRect.Top := TgtRect.Top + Gridimages.Height;
        end;
        {$ENDIF}
      end;
    end;

    ctDataImage:
    begin
      if Assigned(FGridImages) then
      begin
        idx := Ints[ACol,ARow];
        if idx + CellGraphic.CellIndex < FGridImages.Count then
          FGridImages.Draw(Canvas,TgtRect.Left,TgtRect.Top,idx + CellGraphic.CellIndex);
      end;
    end;

    ctNode:
    begin
      r.Left := NodeIndent(ARow)  - CellNode.NodeIndent;

      if FCellNode.ShowTree and (ARow >= FixedRows) {and not CellGraphic.CellBoolean} then
      begin
        Canvas.Pen.Color := FCellNode.TreeColor;
        Canvas.Pen.Width := 1;

//        if (ACol < FixedCols) and not Flat and (Flook in [glTMS,glXP,glListView,glSoft]) then
//          r.Left := r.Left - 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 + 6);
          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 + 6);
        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 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,Canvas.Brush.Color,r,'XPNODEC')
        else
          DrawBitmapResourceTransp(Canvas,Canvas.Brush.Color,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 - 1,r.Top - 1,r.Right + 1,r.Bottom + 1);
        if CellGraphic.CellBoolean then
        begin
          Canvas.MoveTo(r.Left + 1,r.Top+3);
          Canvas.LineTo(r.Left + 6,r.Top+3);
          Canvas.MoveTo(r.Left + 3,r.Top+1);
          Canvas.LineTo(r.Left + 3,r.Top+6);
        end
        else
        begin
          Canvas.MoveTo(r.Left + 1,r.Top + 3);
          Canvas.LineTo(r.Left + 6,r.Top + 3);
        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;
  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);
      crect.Bottom := crect.Bottom -1 ;
    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);
      crect.Right := crect.Right -1 ;
    end;

    Canvas.Brush.Color := C2;
    Canvas.Pen.Color := C2;

    DrawGradient(Canvas,C1,C2,128,crect,FBackground.Display = bdGradientHorz);
  end;

  procedure DrawCellText;
  var
    AlignValue: TAlignment;
    FontHeight: Integer;
    Rect,Hr,CR: 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;
    {$IFDEF TMSUNICODE}
    ws: widestring;
    {$ENDIF}
    //ch: 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(RemapColInv(ACol),RRow) then
    begin
      if FShowSelection then
      begin
        if FSelectionColor <> clNone then
          Canvas.Brush.Color := FSelectionColor;
        if FSelectionTextColor <> clNone then
          Canvas.Font.Color := FSelectionTextColor;

        URLCol := FSelectionTextColor;
      end;

      if (not (GetFocus = Handle) or (HasCheckBox(ACol,ARow))) and not FShowSelection  then
      begin
        Canvas.Brush.Color := FOldBrushColor;
        Canvas.Font.Color := FOldFontColor;
        URLCol := FURLColor;
      end;
    end;

    TmpStr := GetFormattedCell(ACol,ARow);

    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);

    Rect := ARect;

    if (ARow = 0) and GetFilter(ACol) then
    begin
      FltrBmp := TBitmap.Create;
      FltrBmp.LoadFromResourceName(HInstance,'ASGFILT');
      Rect.Left := Rect.Right -16;
      DrawBitmapTransp(Canvas,FltrBmp,FixedColor,Rect);
      FltrBmp.Free;
      Rect := ARect;
    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);
      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 (((not ((gdSelected in Astate) and not (gdFocused in Astate))) and
       not ((gdFocused in Astate) and (goDrawFocusSelected in Options))) or (FShowSelection = False)) then
    begin
      if FBackground.Display = bdTile then
        DrawWallPaperTile(Rect)
      else
        DrawWallPaperFixed(Rect);
    end;

    if (FBackground.Display in [bdGradientVert, bdGradientHorz]) and ((Colors[ACol,ARow] = clNone) or (CellTypes[ACol,ARow] in [ctCheckBox,ctDataCheckBox,ctRadio,ctButton])) 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 not (gdFocused in Astate))) and
       not ((gdFocused in Astate) and (goDrawFocusSelected in Options))) or (FShowSelection = False)) then
       DrawGradientBackground(Rect);

    // do the selection rectangle painting here
    c := ACol;
    ACol := RemapColInv(ACol);

    if FSelectionRectangle and IsInGridRect(Selection,ACol,ARow) then
    begin
      Canvas.Pen.Color := FSelectionRectangleColor;
      Canvas.Pen.Width := 2;

      with Canvas do
      begin
        if Selection.Left = ACol then
        begin
          MoveTo(Rect.Left + 1 - GridLineWidth,Rect.Bottom {- 1});
          LineTo(Rect.Left + 1 - GridLineWidth,Rect.Top {+ 1} - GridLineWidth );
        end;

        if Selection.Right = ACol then
        begin
          MoveTo(Rect.Right - 1,Rect.Bottom {- 1});
          LineTo(Rect.Right - 1,Rect.Top {+ 1} - GridLineWidth );
        end;

        if Selection.Top = ARow then
        begin
          MoveTo(Rect.Left {+ 1} - GridLineWidth ,Rect.Top + 1 - GridLineWidth );
          if Selection.Right = ACol then
            LineTo(Rect.Right - 1,Rect.Top + 1 - GridLineWidth )
          else
            LineTo(Rect.Right,Rect.Top + 1 - GridLineWidth )
        end;

        if Selection.Bottom = ARow then
        begin
          MoveTo(Rect.Left {+ 1} - GridLineWidth ,Rect.Bottom {- 1});
          if Selection.Right = ACol then
            LineTo(Rect.Right - 1,Rect.Bottom {- 1})
          else
            LineTo(Rect.Right,Rect.Bottom {- 1});
        end;
      end;

      if SelectionResizer and
         (ARow = Selection.Bottom) and (ACol = Selection.Right) then
      begin
        CR := CellRect(Selection.Right,Selection.Bottom);
        CR.Left := Rect.Right - 4;
        CR.Top := Rect.Bottom - 4;
        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 Exit;

    // drawing of text
    with Rect do
    begin
      Dec(Right,FXYOffset.X);
      Inc(Left,FXYOffset.X);
      Inc(Top,FXYOffset.Y);
    end;


    // 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
      Rect.Left := Rect.Left + GraphicWidth;
      sortindent := GraphicWidth;
    end;

    if (hal = haLeft) then
    begin
      sortindent := GraphicWidth;
    end;

    if (HAlignment in [taLeftJustify,taCenter]) and (hal = haAfterText) then
    begin
      Rect.Right := Rect.Right - GraphicWidth;
    end;

    if (HAlignment = taRightJustify) and (hal = haAfterText) then
    begin
      Rect.Right := Rect.Right - GraphicWidth;
    end;

    if (HAlignment in [taRightJustify,taCenter]) and (hal = haBeforeText) then
    begin
      Rect.Left := Rect.Left + GraphicWidth;
    end;


    if val = vaAboveText then
    begin
      Rect.Top := Rect.Top + GraphicHeight;
    end;

    if val = vaUnderText then
    begin
      Rect.Bottom := Rect.Bottom - GraphicHeight;
    end;

    if (ACol = 0) and (FNumNodes > 0) and not IsNode(ARow) then
    begin
      Rect.Left := Rect.Left + NodeIndent(ARow);
    end;

    if ctt = ttHTML then
    begin
      if (ARow = 0) and GetFilter(ACol) then
        Rect.Right := Rect.Right - 18;

      Rect.Left := Rect.Left - 1;

      if FSortSettings.Show and (ARow = FSortSettings.Row) and (RowCount > 2) and
         ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and (FixedRows > 0) and
         ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      begin
        Rect.Right := Rect.Right - 10;
      end;

      if UseRightToLeftAlignment then
      begin
        DRect := Rect;

        if not FNoRTLOrientation then
        begin
          Rect.Left := ClientWidth - Rect.Left;
          Rect.Right := ClientWidth - Rect.Right;
        end
        else
        begin
          Rect.Left := Rect.Left - XYOffset.X;
          Rect.Right := Rect.Right + XYOffset.X;
        end;

        Hold := Rect.Left;
        Rect.Left := Rect.Right;
        Rect.Right := Hold;
        {$IFDEF DELPHI6_LVL}
        ChangeGridOrientation(False);
        {$ELSE}
        SetGridOrientation(False);
        {$ENDIF}
      end;

      HTMLDrawEx(Canvas,TmpStr,Rect,Gridimages,
               Rect.Left,Rect.Top,-1,0,1,False,False,False,False,FGridBlink,False,not EnhTextSize,FCtrlDown,
               0.0,URLCol,clNone,clNone,clGray,Anchor,Stripped,FocusAnchor,AnchorHint,
               XSize,YSize,ml,hl,hr,cr,CID,CT,CV,FImageCache,FContainer,Handle);

      if UseRightToLeftAlignment then
      begin
        {$IFDEF DELPHI6_LVL}
        ChangeGridOrientation(True);
        {$ELSE}
        SetGridOrientation(True);
        {$ENDIF}
        Rect := DRect;
      end;

      if FSortSettings.Show and (ARow = FSortSettings.Row) and (RowCount > 2) 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 := Rect.Top + 8;
        vtaCenter:vpos := Top +((Rect.Bottom - Rect.Top) shr 1);
        vtaBottom:vpos := Rect.Bottom - 8;
        end;

        if not ((SortIndexes.FindIndex(ACol) > 0) and not FSortSettings.IndexShow) then
          DrawSortIndicator(Canvas,ACol,Rect.Right + 2,vpos);
      end;

      //Solves the problem that DrawFocusRect only takes the Canvas Color of the last drawn Font!
      Canvas.TextOut(Rect.Left,Rect.Top,'');

      MaxTextWidth := XSize + 2;

      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(Rect.Left,Rect.Top,Rect.Right,Rect.Bottom);
      Canvas.Brush.Style := bsClear;

      if UseRightToLeftAlignment then
      begin
        DRect := Rect;
        if not FNoRTLOrientation then
        begin
          Rect.Left := ClientWidth - Rect.Left;
          Rect.Right := ClientWidth - Rect.Right;
        end
        else
        begin
          Rect.Left := Rect.Left - XYOffset.X;
          Rect.Right := Rect.Right + XYOffset.X;
        end;

        Hold := Rect.Left;
        Rect.Left := Rect.Right;
        Rect.Right := Hold;
        {$IFDEF DELPHI6_LVL}
        ChangeGridOrientation(False);
        {$ELSE}
        SetGridOrientation(False);
        {$ENDIF}
      end;

      RTFPaint(ACol,ARow,Canvas,Rect);
      Canvas.Brush.Style := bsSolid;
      Canvas.Font.Color := clBlack; // forces a canvas font reinitialize

      if UseRightToLeftAlignment then
      begin
        {$IFDEF DELPHI6_LVL}
        ChangeGridOrientation(True);
        {$ELSE}
        SetGridOrientation(True);
        {$ENDIF}
        Rect := DRect;
      end;

      Exit;
    end;

    {$IFDEF TMSUNICODE}
    if ctt = ttUnicode then
    begin
      ws := DecodeWideStr(TmpStr);

      //ws := WideCells[ACol,ARow];
      TmpStr := ws;

      if FSortSettings.Show and (ARow = FSortSettings.Row) and (RowCount > 2) and
         ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and (FixedRows > 0) and
         ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      begin
        Rect.Right := Rect.Right - 10;
        case VAlign of
        vtaTop:vpos := Rect.Top + 8;
        vtaCenter:vpos := Top +((Rect.Bottom - Rect.Top) shr 1);
        vtaBottom:vpos := Rect.Bottom - 8;
        end;

        if not ((SortIndexes.FindIndex(ACol)>0) and not FSortSettings.IndexShow) then
          DrawSortIndicator(Canvas,ACol,Rect.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 := Rect;
        if not FNoRTLOrientation then
        begin
          Rect.Left := ClientWidth - Rect.Left;
          Rect.Right := ClientWidth - Rect.Right;
        end
        else
        begin
          Rect.Left := Rect.Left - XYOffset.X;
          Rect.Right := Rect.Right + XYOffset.X;
        end;

        Hold := Rect.Left;
        Rect.Left := Rect.Right;
        Rect.Right := Hold;
        {$IFDEF DELPHI6_LVL}
        ChangeGridOrientation(False);
        {$ELSE}
        SetGridOrientation(False);
        {$ENDIF}
      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),rect,DT_LEFT or DT_NOPREFIX or DT_WORDBREAK OR DT_END_ELLIPSIS or DrawStyle,nil)
        else
          DrawTextExW(Canvas.Handle,PWidechar(ws),Length(ws),rect,DT_LEFT or DT_NOPREFIX or DrawStyle or DT_SINGLELINE or DT_END_ELLIPSIS,nil);
      end
      else
      begin
        ExtTextOutW(Canvas.Handle,rect.Left,rect.Top,ETO_CLIPPED,@rect,PWideChar(ws),Length(ws),nil);
      end;

      if UseRightToLeftAlignment then
      begin
        {$IFDEF DELPHI6_LVL}
        ChangeGridOrientation(True);
        {$ELSE}
        SetGridOrientation(True);
        {$ENDIF}
        Rect := DRect;
      end;

      Exit;
    end;
    {$ENDIF}

    if (HAlignment = taCenter) and (ARow = FSortSettings.Row) and FSortSettings.Show and
       (ACol = FSortSettings.Column) then
    begin
      Rect.Left := Rect.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;

    if LinesInText(TmpStr,FMultiLineCells) = 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 WordWraps[CellWW] or
      Alignments[HAlignment] or FVAlign;

    DrawStyle := DrawTextBiDiModeFlags(DrawStyle);

    SetBkMode(Canvas.Handle,TRANSPARENT);

    case HAlignment of
    taLeftJustify:Rect.Right := Rect.Right - SortWidth;
    taRightJustify,taCenter:Rect.Left := Rect.Left + SortWidth;
    end;

    if (ARow = 0) and GetFilter(ACol) then
      Rect.Right := Rect.Right - 16;


    if UseRightToLeftAlignment then
    begin
      DRect := Rect;
      if not FNoRTLOrientation then
      begin
        Rect.Left := ClientWidth - Rect.Left;
        Rect.Right := ClientWidth - Rect.Right;
      end
      else
      begin
        Rect.Left := Rect.Left - XYOffset.X;
        Rect.Right := Rect.Right + XYOffset.X;
      end;

      Hold := Rect.Left;
      Rect.Left := Rect.Right;
      Rect.Right := Hold;
      {$IFDEF DELPHI6_LVL}
      ChangeGridOrientation(False);
      {$ELSE}
      SetGridOrientation(False);
      {$ENDIF}
    end;

    if Assigned(cg) and (TmpStr <> '') then
    begin
      CR := Rect;
      {$IFNDEF TMSDOTNET}
      DrawTextEx(Canvas.Handle,PChar(TmpStr),Length(TmpStr), CR, DrawStyle OR DT_CALCRECT, nil);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      DrawTextEx(Canvas.Handle,TmpStr,Length(TmpStr), CR, DrawStyle OR DT_CALCRECT, nil);
      {$ENDIF}
      MaxTextWidth := CR.Right - Rect.Left + 2;
    end;

    {$IFNDEF TMSDOTNET}
    DrawTextEx(Canvas.Handle,PChar(TmpStr),Length(TmpStr), Rect, DrawStyle, nil);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    DrawTextEx(Canvas.Handle,TmpStr,Length(TmpStr), Rect, DrawStyle, nil);
    {$ENDIF}

    if UseRightToLeftAlignment then
    begin
      {$IFDEF DELPHI6_LVL}
      ChangeGridOrientation(True);
      {$ELSE}
      SetGridOrientation(True);
      {$ENDIF}
      Rect := DRect;
    end;

    if (ErrLen > 0) and Assigned(cg) and (cg.CellType = ctEmpty) then
    begin
      DrawErrorLines(Self,Canvas, TmpStr, Rect, FontHeight, ErrPos,ErrLen);
    end;

    MaxTextHeight := FontHeight;
    Rect := ARect;

    if (ARow = 0) and GetFilter(ACol) then
      Rect.Right := Rect.Right - 16;

    if FSortSettings.Show and (ARow = FSortSettings.Row) and (RowCount > 2) and
       ((ACol = FSortSettings.Column) or (SortIndexes.FindIndex(ACol) <> -1)) and
       (FixedRows > 0) and ((ACol + 1 > FixedCols) or FSortSettings.FixedCols) then
      with Rect do
      begin
        SortWidth := Min(Rect.Right - Rect.Left - 16,Canvas.TextWidth(TmpStr));

        if SortWidth < 0 then
          SortWidth := 0;

        case AlignValue of
        taLeftJustify:Rect.Left := Rect.Left + SortWidth + 10 + sortindent;
        taRightJustify:Rect.Left := Rect.Right - SortWidth - 10;
        taCenter: Rect.Left := Rect.Left + 8;
        end;

        case VAlign of
        vtaTop:vpos := Rect.Top + 8;
        vtaCenter:vpos := Rect.Top + ((Rect.Bottom - Rect.Top) shr 1);
        vtaBottom:vpos := Rect.Bottom - 8;
        end;

        if not ((SortIndexes.FindIndex(ACol) > 0) and not FSortSettings.IndexShow) then
          DrawSortIndicator(Canvas,ACol,Rect.Left,vpos);
      end;

      if URLShow then
        Canvas.Font.Style := Canvas.Font.Style - [fsUnderline];
  end;


begin
  if MultiLineCells then
    WordWraps[False] := 0;

  MaxTextWidth := 0;
  MaxTextHeight := 0;

  Ctl3d := not FFlat;

  OCol := ACol;

  // calculate real Col based on hidden Cols
  ACol := RemapCol(ACol);

  if MouseActions.DisjunctRowSelect and MouseActions.RowSelectPersistent then
    RRow := RemapRowInv(ARow)
  else
    RRow := ARow;

  CellWW := WordWrap;

  GetVisualProperties(OCol,ARow,AState,False,False,True,Canvas.Brush,AColorTo,AMirrorColor,AMirrorColorTo,Canvas.Font,HAlignment,VAlign,CellWW,GD);

  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;

  Canvas.Font.Size := Canvas.Font.Size + FZoomFactor;

  FOldBrushColor := Canvas.Brush.Color;
  FOldFontColor := Canvas.Font.Color;

  if (IsFixed(OCol,ARow) or (OCol < FixedCols) or (ARow < FixedRows)) and
     ((Flook in [glTMS,glXP,glVista]) and not Flat) then
  begin
    if (Look = glVista) then
    begin
      ARect.Left := ARect.Left - 1;
      ARect.Top := ARect.Top - 1;
      ARect.Bottom := ARect.Bottom - 1;
    end;

    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.Right := ARect.Right + 1;
      ARect.Bottom := ARect.Bottom + 1;

      if FMouseDownMove or ((FGridState = gsColMoving) and (MoveCell >= 0)) then
      begin
        if ControlLook.FixedDropDownButton 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
        DrawVistaGradient(Canvas, ARect, FTMSGradHoverFrom, FTMSGradHoverTo, FTMSGradHoverMirrorFrom, FTMSGradHoverMirrorTo, True, FTMSGradHoverBorder, false);

      if ControlLook.FixedDropDownButton 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
          DrawVistaGradient(Canvas, ARect, FTMSGradFrom, FTMSGradTo, FTMSGradMirrorFrom, FTMSGradMirrorTo, True, brdrColor, true);
      end;
    end;
  end;

  // text draw with alignment
  if (ACol = 0) and (ARow = Row) and (FixedCols > 0) and Assigned(FRowIndicator) 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;
      //DrawBitmapTransp(Canvas,FRowIndicator,FixedColor,ARect);
      ARect.Left := ARect.Left + FRowIndicator.Width + 2;
    end;
  end;

  if (IsFixed(OCol,ARow) or (OCol < FixedCols) or (ARow < FixedRows)) and
     ((Flook in [glListView]) and not Flat) then
  begin
    if FIsWinXP then
    begin
      ARect.Bottom := ARect.Bottom + 1;
      ARect.Top := ARect.Top - 1;

      {$IFNDEF TMSDOTNET}
      HTheme := OpenThemeData(Self.Handle,'header');
      ARect.left := ARect.Left - 1;
      ARect.Right := ARect.Right + 1;

      GetCursorPos(pt);
      pt := ScreenToClient(pt);

      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_HEADERITEM,HIS_NORMAL,@ARect,nil);

      CloseThemeData(HTheme);
      {$ENDIF}

      {$IFDEF TMSDOTNET}
      HTheme := OpenThemeData(Self.Handle,'header');
      ARect.left := ARect.Left - 1;
      ARect.Right := ARect.Right + 1;

      GetCursorPos(pt);
      pt := ScreenToClient(pt);

      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_HEADERITEM,HIS_NORMAL,ARect,nil);

      CloseThemeData(HTheme);
      {$ENDIF}

      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 RowModified[ARow] and ShowModified.Enabled then
  begin
    Canvas.Brush.Color := ShowModified.Color;
    Canvas.Pen.Color := ShowModified.Color;
    Canvas.Rectangle(ARect.Right - 4,ARect.Top, ARect.Right, ARect.Bottom);
  end;

  OrigRight := ARect.Right;

  if not IsFixed(OCol,ARow) then
  begin
    if ControlLook.DropDownAlwaysVisible then
    begin
      if HasCombo(RealColIndex(OCol),ARow) then
      begin
        DrawComboButton(Canvas,Self.Handle, ARect,FIsWinXP and FIsComCtl6, False);
        ARect.Right := ARect.Right - 16;
      end;
    end;

    if ControlLook.SpinButtonsAlwaysVisible then
    begin
      if HasSpinEdit(RealColIndex(OCol),ARow) then
      begin
        DrawSpinButtons(Canvas,Self.Handle, ARect,FIsWinXP {and FIsComCtl6}, False);
        ARect.Right := ARect.Right - 16;
      end;
    end;
  end;

  if Assigned(cg) then
  begin
    {$IFDEF DELPHI6_LVL}
    if cg.CellType = ctInterface then
    begin
      {$IFNDEF TMSDOTNET}
      io := TInterfacedPersistent(cg.CellBitmap);
	  if io.GetInterface(ICellGraphic, icg) then
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      io := cg.CellInterface;
      icg := ICellGraphic(io.GetType.GetInterface(typeof(ICellGraphic).FullName));
      if icg <> nil then
      {$ENDIF}
      begin
        if icg.IsBackground then
        begin
          InflateRect(ARect,1,1);
          DrawCellGraphic(ARect, cg, VAlign);
          InflateRect(ARect,-1,-1);
        end;
      end;
    end;
    {$ENDIF}
    if not NoImageAndText then
      if not ((Assigned(OnDrawCell) or Assigned(OnCustomCellDraw)) and NoDefaultDraw) then
        DrawCellText;
  end
  else
    if not ((Assigned(OnDrawCell) or Assigned(OnCustomCellDraw)) and NoDefaultDraw) then
      DrawCellText;

  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;

  if (IsFixed(OCol,ARow) or (OCol < FixedCols) or (ARow < FixedRows)) and
     ((Flook = glClassic) and not Flat) then
  begin
    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 (IsFixed(OCol,ARow) or (OCol < FixedCols) or (ARow < FixedRows)) and
     ((Flook in [glTMS,glXP]) and not Flat) then
  begin
    InflateRect(ARect,1,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;
  end;

  if (IsFixed(OCol,ARow) or (OCol < FixedCols) or (ARow < FixedRows)) and
     ((FLook = glSoft) and not Flat) then
  begin
    if Ctl3D then
    begin
      if (FLook = glSoft) and not Flat then
        InflateRect(ARect,1,1);

      ARect.Bottom := ARect.Bottom - 1;

      if ((FLook = glSoft) and not Flat) and (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 ((FLook = glSoft) and not Flat) and (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 (NodeIndent(ARow) > 0) and (ACol = 0) then
  //  ARect.Left := ARect.Left + 4;


  if (FNumNodes > 0) and (ACol = 0) and (ARow >= FixedRows) and (FCellNode.ShowTree) then
  begin
    Canvas.Pen.Color := FCellNode.TreeColor;
    Canvas.Pen.Width := 1;

    //ARect.Left := ARect.Left - 4;

    lvl := CellProperties[0,ARow].NodeLevel;

    ARect.Left := NodeIndent(ARow);

    ci := ARect.Left - CellNode.NodeIndent + 2 + CellNode.NodeIndent div 2;

    if (lvl > 0) then
    begin
      //Canvas.MoveTo(ARect.Left - 4 { + 2 + (CellNode.NodeIndent div 2)},ARect.Top + (ARect.Bottom - ARect.Top) shr 1);

      // horizontal node line
      Canvas.MoveTo(ci,ARect.Top + (ARect.Bottom - ARect.Top) shr 1);

      if FCellNode.ShowTreeFull then
        Canvas.LineTo(ARect.Left + 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 = 0) 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
    {$IFDEF DELPHI6_LVL}
    if cg.CellType = ctInterface then
    begin
      {$IFNDEF TMSDOTNET}
      io := TInterfacedPersistent(cg.CellBitmap);
	  if io.GetInterface(ICellGraphic, icg) then
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      io := cg.CellInterface;
      icg := ICellGraphic(io.GetType.GetInterface(typeof(ICellGraphic).FullName));
      if icg <> nil then
      {$ENDIF}
      begin
        if not icg.IsBackground then
         DrawCellGraphic(ARect, cg, VAlign);
      end;
    end
    else
    {$ENDIF}
      DrawCellGraphic(ARect,cg, VAlign);
  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) then
    begin
      if not (goRowSelect in Options) then
      begin
        InflateRect(ARect,GridLineWidth - 1,GridLineWidth - 1);
        ARect.Right := ARect.Right - 1;
        ARect.Bottom := ARect.Bottom - 1;
        Canvas.DrawFocusRect(ARect);
      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);

  {$IFDEF DELPHI6_LVL}
  if IsWide then
  begin
    if not (fnMatchCase in FFindParams) then
      ctw := WideUpperCase(WideCells[Col,Row])
    else
      ctw := WideCells[Col,Row];
  end
  else
  {$ENDIF}
  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;

{$IFNDEF TMSDOTNET}
  if IsWide then
    ic := StrPosWide(SearchCacheWide,ctw)
  else
    ic := Pos(SearchCache,ct);
{$ENDIF}

  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.Find(StartCell:TPoint; s:string; FindParams: TFindParams):TPoint;
begin
//  if (StartCell.X = -1) and (StartCell.Y = -1) then
  ExportNotification(esExportStart, -1);

  Result := FindInternal(StartCell,s,'',False,FindParams);

  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
  Result := FindInternal(StartCell,'',s,True,FindParams);
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;

  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;

  FFindParams := FindParams;
  FFindBusy := True;

  if not (fnMatchCase in FindParams) then
    SearchCache := AnsiUpperCase(s)
  else
    SearchCache := s;

  {$IFDEF DELPHI6_LVL}
  if not (fnMatchCase in FindParams) then
    SearchCacheWide := WideUpperCase(sw)
  else
  {$ENDIF}
    SearchCacheWide := sw;

  if (ColCount = FixedCols) or (ColCount = 0) then Exit;
  if (RowCount = 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 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(esExportNewRow,j);

        if not IsIgnoredColumn(i) then
        begin

          if MatchCell(i,j,IsWide) then
          begin
            SearchCell.x := i;
            SearchCell.y := j;
            Result := SearchCell;
            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
                    ExpandNode(pr);
                end;
                nr := DisplRowIndex(nr);
              end;

              if MouseActions.DisjunctRowSelect then
              begin
                ClearRowSelect;
                RowSelect[nr] := true;
              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(esExportNewRow,j);      
        if MatchCell(i,j,IsWide) then
        begin
          SearchCell.x := i;
          SearchCell.y := j;
          Result := Searchcell;
          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
                  ExpandNode(pr);
              end;
              nr := DisplRowIndex(nr);
            end;

            if MouseActions.DisjunctRowSelect then
            begin
              ClearRowSelect;
              RowSelect[nr] := true;
            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;

  FFindBusy := False;
end;


function TAdvStringGrid.FindFirst(s:string;FindParams: TFindParams):TPoint;
begin
  SearchCell := Find(Point(-1,-1),s,FindParams);
  Result := SearchCell;
end;

function TAdvStringGrid.FindNext:TPoint;
begin
  SearchCell := Find(SearchCell,SearchCache,FFindParams);
  Result := SearchCell;
end;

procedure TAdvStringGrid.SearchEditChange(Sender: TObject);
var
  DefaultSearch: boolean;

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 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.SearchColumn >= 0) and (FSearchFooter.SearchColumn < ColCount) then
  begin
    FindCol := FSearchFooter.SearchColumn;
    FFindParams := FFindParams + [fnFindInPresetCol];
  end;

  if (FSearchPanel.FEdit.Text <> '') then
  begin
    SearchCell := Find(Point(-1,-1),FSearchPanel.FEdit.Text,FFindParams);

    DoSearchFooterAction(FSearchPanel.FEdit.Text, SearchCell.X, SearchCell.Y, saFindFirst);

    if SearchCell.X = -1 then
    begin
      FSearchPanel.FEdit.Color := clRed;
      UnHilightInGrid(false);
    end
    else
    begin
      FSearchPanel.FEdit.Color := clWindow;
      ScrollInView(SearchCell.X, SearchCell.Y);

      if FSearchPanel.FHiliteButton.Down then
      begin
        UnHilightInGrid(false);
        HilightInGrid(false,false, FSearchPanel.FEdit.Text)
      end
      else
        UnHilightInGrid(false);
    end;
  end
  else
  begin
    FSearchPanel.FEdit.Color := clWindow;
    UnHilightInGrid(false);
  end;

  if (Row > TopRow + VisibleRowCount - 2) and (VisibleRowCount + FixedRows < RowCount) then
    TopRow := TopRow + 2;
end;

procedure TAdvStringGrid.SearchBackward(Sender: TObject);
begin
  if not SearchFooter.AutoSearch then
  begin
    if (SearchFooter.LastSearch <> FSearchPanel.FEdit.Text) then
      SearchCell := Point(-1,-1);
    SearchFooter.LastSearch := FSearchPanel.FEdit.Text;
  end;

  FFindParams := [fnAutoGoto, fnBackward];

  if FSearchPanel.FHiliteButton.Down 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.SearchColumn >= 0) and (FSearchFooter.SearchColumn < ColCount) then
  begin
    FindCol := FSearchFooter.SearchColumn;
    FFindParams := FFindParams + [fnFindInPresetCol];
  end;    

  SearchCell := Find(SearchCell,FSearchPanel.FEdit.Text,FFindParams);
  if (Row > TopRow + VisibleRowCount - 2) and (VisibleRowCount + FixedRows < RowCount) then
    TopRow := TopRow + 2;

  if (SearchCell.X <> -1) then
    ScrollInView(SearchCell.X, SearchCell.Y);

  DoSearchFooterAction(FSearchPanel.FEdit.Text, SearchCell.X, SearchCell.Y, saFindPrevious);

  SearchPanel.Invalidate;
end;

procedure TAdvStringGrid.SearchForward(Sender: TObject);
begin
  if not SearchFooter.AutoSearch then
  begin
    if (SearchFooter.LastSearch <> FSearchPanel.FEdit.Text) then
      SearchCell := Point(-1,-1);
    SearchFooter.LastSearch := FSearchPanel.FEdit.Text;
  end;

  FFindParams := [fnAutoGoto];

  if FSearchPanel.FHiliteButton.Down 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.SearchColumn >= 0) and (FSearchFooter.SearchColumn < ColCount) then
  begin
    FindCol := FSearchFooter.SearchColumn;
    FFindParams := FFindParams + [fnFindInPresetCol];
  end;

  SearchCell := Find(SearchCell,FSearchPanel.FEdit.Text,FFindParams);

  if (SearchCell.X <> -1) then
    ScrollInView(SearchCell.X, SearchCell.Y);



  if (Row > TopRow + VisibleRowCount - 2) and (VisibleRowCount + FixedRows < RowCount) then
    TopRow := TopRow + 2;

  DoSearchFooterAction(FSearchPanel.FEdit.Text, SearchCell.X, SearchCell.Y, saFindNext);

  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 FSearchPanel.FHiliteButton.Down then
    HilightInGrid(false,false, FSearchPanel.FEdit.Text)
  else
    UnHilightInGrid(false);
end;

procedure TAdvStringGrid.Click;
begin
  inherited Click;
  FEntered := False;
  InitValidate(Col,Row);
end;

procedure TAdvStringGrid.InitValidate(ACol,ARow: Integer);
begin
  FOldCol := ACol;
  FOldRow := ARow;
  FOldCellText := GridCells[RemapCol(FOldCol), FOldRow];

//  FOldCellText := inherited GetEditText(RemapCol(FOldCol), FOldRow);

  FOldCellTextWide := WideCells[RemapCol(FOldCol), FOldRow];
  FOldModifiedValue := FModified;
end;

procedure TAdvStringGrid.CellsLoaded;
begin
  CalcFooter(-1);
end;

procedure TAdvStringGrid.CellsChanged(R:TRect);
var
  Idx: Integer;
begin
  if Assigned(FOnCellsChanged) then
    FOnCellsChanged(Self,R);

  for Idx := 1 to FNotifierList.Count do
    TGridChangeNotifier(FNotifierList.Items[Idx - 1]).CellsChanged(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;
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
        if CellChecker.AutoCorrect then
          Value := CellChecker.Correct(ROldCol,FOldRow,Value);

      if Assigned(FOnCellValidate) then
        FOnCellValidate(Self,ROldCol,FOldRow,Value,Valid);

      if (FOldCellText <> Value) then
        Modified := true;

      if {ShowModified.Enabled and }(FixedCols > 0) and (FOldCellText <> Value) then
      begin
        RowModified[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;

        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;
      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;

  finally
    InitValidate(Col,Row);
    FValidating := False;
  end;

  Result := Valid;
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);
begin
  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
      inherited;

  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;

  if FCtrlDown then
  begin
    FCtrlDown := False;
    RepaintCell(FCtrlXY.X,FCtrlXY.Y);
  end;
end;

procedure TAdvStringGrid.WMSetFocus(var Msg: TWMSetFocus);
var
  editable: boolean;
begin
  if InvokedFocusChange then
    Exit;

  inherited;

  if HasCheckBox(Col,Row) then
    Exit;

  if 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 = edNormal) 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
             ShowInplaceEdit;
         end;

    end;

  if ((RowCount=1) and (FixedRowAlways)) or
     ((ColCount=1) and (FixedColAlways)) then HideSelection;
end;

procedure TAdvStringGrid.DoEnter;
begin
  if FBlockFocus then Exit;
  try
    inherited DoEnter;
    // FEntered := True;
    if (goEditing in Options) or (MouseActions.RangeSelectAndEdit) then
      SelectCell(Col,Row);
  finally
    InitValidate(Col,Row);
  end;
end;

procedure TAdvStringGrid.DoExit;
begin
  if  FBlockKill then
    Exit;
  inherited DoExit;
end;

function TAdvStringGrid.GetEditLimit: Integer;
begin
  Result := MaxEditLength;
end;

procedure TAdvStringGrid.CMDialogChar(var Msg: TCMDialogChar);
begin
  //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;

{$IFNDEF TMSDOTNET}
procedure TAdvStringGrid.CMHintShow(var Msg: TMessage);
{$ENDIF}
{$IFDEF TMSDOTNET}
procedure TAdvStringGrid.CMHintShow(var Msg: TCMHintShow);
{$ENDIF}
var
  CanShow: Boolean;
{$IFNDEF TMSDOTNET}
  hi: PHintInfo;
{$ENDIF}
{$IFDEF TMSDOTNET}
  hi: THintInfo;
{$ENDIF}

{$IFNDEF DELPHI3_LVL}
  s: string;
{$ENDIF}

Begin
  CanShow := True;
  {$IFNDEF TMSDOTNET}
  hi := PHintInfo(Msg.LParam);
  {$IFNDEF DELPHI3_LVL}
  s := self.Hint;
  ShowHintProc(s,CanShow,hi^);
  self.Hint := s;
  {$ELSE}
  ShowHintProc(hi.HintStr,CanShow,hi^);
  {$ENDIF}
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  hi := Msg.HintInfo;
  {$IFNDEF DELPHI3_LVL}
  s := self.Hint;
  ShowHintProc(s,CanShow,hi);
  self.Hint := s;
  {$ELSE}
  ShowHintProc(hi.HintStr,CanShow,hi);
  {$ENDIF}
  {$ENDIF}

  Msg.Result := Ord(Not CanShow);
end;


procedure TAdvStringGrid.CMColorChanged(var Message: TMessage);
begin
  inherited;
  if FloatingFooter.Visible then
    FloatingFooter.Invalidate;
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);
  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 FUpdateCount = 0 then
  begin
    SendMessage(Handle,WM_SETREDRAW,integer(True),0);
    InvalidateRect(Handle, Nil, False);
    NCPaintProc;
  end;
end;

procedure TAdvStringGrid.ResetUpdate;
begin
  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: Longint;
  r: TRect;
  i,j: Integer;

begin
  if (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
         for j := LeftCol to LeftCol + VisibleColCount -1 do
         begin
           if (FIPos('<BLI',Cells[j,i]) > 0) then RepaintCell(j,i);
         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(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(i,j);
         end;
      end;
    end
  else
    inherited;
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;
  Exit;

  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;

begin
  us := True;

  if FSearchPanel.Visible then
    FSearchPanel.Align := alBottom;

  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;

    for i := 1 to ColCount do
      if FOrigColSizes.Count > i - 1 then
        ColWidths[i - 1] := Trunc(FOrigColSizes[i - 1] * r);
  end;


  if FColumnSize.FStretch and (ScrollBarAlways in [saNone, saVert]) then
  begin
    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 < Width then
    begin
      StretchColumn(FColumnSize.StretchColumn);
      us := False;
    end;

    if (ScrollBars in [ssBoth, ssHorizontal]) and (ScrollbarAlways = saNone) then
        ShowScrollbar(Handle,SB_HORZ,(tw + ColWidths[sc] > ClientWidth ));

      if (ScrollBars in [ssBoth, ssVertical]) and (ScrollbarAlways = saNone)  then
        ShowScrollbar(Handle,SB_VERT,RowCount - FixedRows > VisibleRowCount);


    if (not us) and (ScrollBarAlways = saNone) then
      Exit;
  end;


  inherited;

  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;
begin
  rm := RemapCol(Col);

  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);
    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
    {$IFNDEF TMSDOTNET}
    Msg.CharCode := Ord(DecimalSeparator);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    Msg.CharCode := Ord(DecimalSeparator[1]);
    {$ENDIF}
  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 then
      inherited;
  end;

end;

function TAdvStringGrid.GetFooterCanvas: TCanvas;
begin
  Result := FFooterPanel.Canvas;
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;

procedure TAdvStringGrid.TabEdit(Dir: Boolean);
var
  Key,X: word;
  Shift: TShiftState;
  pt: TPoint;
  fc: integer;
  allow: boolean;
  AllowAdd: boolean;

  function CanVisitCell(col,row: Integer): boolean;
  begin
    if (goEditing in Options) then
      Result := IsEditable(RemapCol(col),row)
    else
      Result := not IsFixed(col,row);
  end;

  function FirstCellInRow(row: integer): integer;
  var
    i: integer;
  begin
    Result := -1;

    for i := 0 to ColCount - 1 do
    begin
      if CanVisitCell(i, row) then
      begin
        Result := i;
        Break;
      end;
    end;
  end;

  function LastCellInRow(row: integer): integer;
  var
    i: integer;
  begin
    Result := -1;

    for i := ColCount - 1 downto 0 do
    begin
      if CanVisitCell(i, row) then
      begin
        Result := i;
        Break;
      end;
    end;
  end;

begin
  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 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
               Selection := TGridRect(Rect(fc, Row - 1, fc, Row - 1));
            //Row := Row - 1;
            //Col := ColCount - NumFixedRightVis - 1;
          end
          else
          begin
            fc := LastCellInRow(RowCount - 1 - FixedFooters);
            if (fc >= 0) then
            begin
              Selection := TGridRect(Rect(fc, RowCount - 1 - FixedFooters, fc, RowCount - 1 - FixedFooters));
            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 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
              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)
            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
            TabEdit(Dir);
        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
            Col := FixedCols;
            Row := Row + 1;
            TabEdit(Dir);
          end
          else
          begin
            //FocusCell(X,Row + 1);
            Col := X;
            Row := Row + 1;
          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 := FixedCols;

          if (Parent is TWinControl) and Navigation.TabToNextAtEnd then
            PostMessage((Parent as TWinControl).Handle,WM_KEYDOWN,VK_TAB,0);
          //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);
          end;
        end;
      end;
    end;
  end;

  if not IsEditable(remapcol(Col),Row) and (goEditing in Options) then
    TabEdit(Dir);

  if Navigation.AlwaysEdit then
    SetFocus;
end;

procedure TAdvStringGrid.WMKeyUp(var Msg: TWMKeyDown);
begin
  inherited;
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;
  sl: TStringList;
  CC: word;
  CanEdit,Chk: Boolean;
  Allow: Boolean;
  SelCol,SelRow,CurRow,RCol,NewIdx: Integer;
  IsCtrl,IsShift,IsAlt: Boolean;
  OldLeftCol: Integer;
  RRow: Integer;
  SS: TShiftState;
  GR: TGridRect;
  R: TRect;
  chw: word;
  OnLastRow: Boolean;
  DownChar: Boolean;
  ctt: TTextType;
  hscrflg: boolean;
  tr: integer;
  updflg: boolean;
  CR: TRect;
  wc: TCustomForm;
  rngsel: boolean;
  
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_MENU) 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 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 hscrflg then
    BeginUpdate;

  if MouseActions.EditOnDblClickOnly and (Msg.CharCode in [VK_F2, VK_RETURN]) 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
      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);

        if Assigned(FOnCheckBoxClick) then
          FOnCheckBoxClick(Self,RCol,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 then
        if HasButton(RCol,Row) then
        begin
          if Assigned(OnButtonClick) then
            OnButtonClick(Self, RCol, Row);
        end;

      RepaintCell(Col,Row);

    end;
  end;

  if (Msg.CharCode = VK_HOME) and (FNavigation.HomeEndKey = heFirstLastRow) then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;

    Row := FixedRows;
    SelectBaseCell;

    if not IsShift and MouseActions.DisjunctRowSelect then
    begin
      ClearRowSelect;
      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;

    Exit;
  end;

  if (Msg.CharCode = VK_HOME) and (FNavigation.HomeEndKey = heFirstLastColumn) and
     (goRowSelect in Options) then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;

    Col := FixedColsVis;
    SelectBaseCell;
    LeftCol := FixedColsVis;
    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);
    Msg.Result := 0;
    Exit;
  end;

  if (Msg.CharCode = VK_END) and (FNavigation.HomeEndKey = heFirstLastRow) 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
      ClearRowSelect;
      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;

    Exit;
  end;

  if (Msg.CharCode = VK_END) and (FNavigation.HomeEndKey = heFirstLastColumn) and
     (goRowSelect in Options) then
  begin
    if FixedRowAlways and (RowCount = 1) then
    begin
      inherited;
      Exit;
    end;
    Col := ColCount - 1;
    SelectBaseCell;
    LeftCol := ColCount - VisibleColCount;
    Msg.Result := 0;
    chw := Msg.CharCode;
    if Assigned(OnKeyDown) then
      OnKeyDown(self,chw,SS);
    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 (goTabs in Options) then
  begin
    // if IsMergedCell(Col,Row) then
    // begin
    TabEdit(GetKeyState(VK_SHIFT) and $8000 = $8000);
    Exit;
    // end;
  end;

  if Navigation.SkipFixedCells then
  begin

    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) do
      begin
        dec(nr);
      end;

      if (nr - 1 >= FixedRows) and 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) do
      begin
        inc(nr);
      end;
      if (nr + 1 < RowCount - FixedFooters) and 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
    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, Row);
    end;
  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;

  if (SearchFooter.Visible) then
  begin
    if (tr >= 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
      begin
        BeginUpdate;
        updflg := true;
      end;
  end;

  inherited;

  if (SearchFooter.Visible) 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 = VK_DOWN) or (Msg.CharCode = VK_NEXT) 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;
    if Assigned(FOnClipboardCut) then
      FOnClipboardCut(self,Allow);
    if Allow then CutSelectionToClipboard;
    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;
    if Assigned(FOnClipboardCopy) then
      FOnClipboardCopy(Self,Allow);
    if Allow then CopySelectionToClipboard;
    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 CutSelectionToClipboard;
    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;
    if FNavigation.InsertPosition = pInsertAfter then
    begin
      if not (FixedRowAlways and (FixedRows = RowCount)) then
      begin
        if Row < RowCount then
        begin
          DoInsertRow(RealRowIndex(Row + 1));
          if Row + 1 < RowCount then
            Row := Row + 1;
        end
        else
        begin
          DoInsertRow(RealRowIndex(Row));
          Row := Row;
        end;
      end
      else
      begin
        DoInsertRow(RealRowIndex(Row));
        Row := 1;
      end;
    end
    else
    begin
      DoInsertRow(RealRowIndex(Row));
    end;
    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;

      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
      ClearRowSelect;

    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
      CurRow := Row;

      Allow := True;

      if Assigned(FOnCanDeleteRow) then
        FOnCanDeleteRow(self, Row, Allow);

      if not Allow then Exit;

      DoDeleteRow(CurRow);

      if FloatingFooter.Visible and (Row = RowCount - 1) then
        Row := RowCount - 2;

      InitValidate(Col,Row);
      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,'');
  end;

  if not EqualRect(TRect(FMoveSelection), TRect(Selection)) then
    SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);
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 (x <> -1) and (y <> -1) then
    begin
      if (not IsSelected(x, y)) 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) then
        RowSelect[y] := not RowSelect[y]
      else
      begin

        if (RowSelectCount > 1) and Assigned(PopupMenu) Then
        begin
          if (not IsSelected(x, y)) then
          begin
            ClearRowSelect;
            RowSelect[y] := true;
          end;
        end
        else
        begin
          ClearRowSelect;
          RowSelect[y] := true;
        end;

//        ClearRowSelect;
//        RowSelect[y] := true;
      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: boolean;
begin
  MouseToCell(Message.XPos,Message.YPos,x,y);

  if MouseActions.RangeSelectAndEdit 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;
        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;
        Exit;
      end;
    end;
  end;

  if HasButton(x,y) then
  begin
    if PtInRect(ButtonRect(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 MouseActions.EditOnDblClickOnly then
  begin
    rngsel := MouseActions.RangeSelectAndEdit;
    MouseActions.RangeSelectAndEdit := true;

    if IsEditable(x,y) then
    begin
      Options := Options + [goEditing];
      FOldCol := x;
      FOldRow := y;
      ShowInplaceEdit;
    end;
    MouseActions.RangeSelectAndEdit := rngsel;
  end;


  rx := RemapCol(x);

  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);
var
  r: TRect;
  IsReadOnly: Boolean;
begin
  if EditTrans.Visible then
  begin
    if not EditTrans.StopEdit then
      Exit;
  end;

  IsReadOnly := false;
  GetCellReadOnly(x,y,IsReadOnly);
  if IsReadOnly then
    Exit;

  r := CellRect(x,y);
  InflateRect(r,-1,-1);
  EditTrans.Left := r.Left;
  EditTrans.Width := r.Right - r.Left;
  EditTrans.Top := r.Top;
  EditTrans.Height := r.Bottom - r.Top;
  EditTrans.Text := Cells[x,y];
  EditTrans.Col := x;
  EditTrans.Row := y;
  EditTrans.Visible := True;
  EditTrans.SetFocus;
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 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[FromIndex];

        for j := FromIndex to ColCount - 2 do
          Items[j] := Items[j + 1];

        for j := ColCount - 1 downto ToIndex + 1 do
          Items[j] := Items[j - 1];

        Items[ToIndex] := 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; 
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);
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: Longint;
  idx,i,nw: Integer;
  doit,chk, WasMove: Boolean;
  r: TRect;
  gr: TGridRect;
  FIsSizing: Boolean;
  lc,offs: Integer;
  UndoSort, CanEdit: Boolean;
  allowdrop: boolean;
begin
  ColMoveFlg := False;
  ColSizeFlg := False;
  FMouseDown := False;
  FMouseKeepDown := False;
  FMouseSelectMode := msNormal;


  if FCtrlDown = True then
  begin
    FCtrlDown := False;
    InvalidateCell(FCtrlXY.X,FCtrlXY.Y);
  end;

  FMouseDownMove := False;

  if (Look = glListview) then
    Invalidate;

  FMouseSelectStart := -1;

  {$IFDEF DELPHI3_LVL}
  if not (csDesigning in ComponentState) then
  begin
    ArwU.visible := False;
    ArwD.visible := False;
    ArwL.visible := False;
    ArwR.visible := False;
  end;
  {$ENDIF}

  if FSizingFixed then
  begin
    FSizeFixed := False;
    FSizingFixed := False;

    offs := 0;
    for i := 1 to FSizeFixedCol do
      offs := offs + ColWidths[i - 1];

    nw := Msg.XPos - offs;
    ColWidths[FSizeFixedCol] := nw;

    if Assigned(FOnEndColumnSize) then
      FOnEndColumnSize(Self,FSizeFixedCol);

    if Assigned(FOnUpdateColumnSize) then
    begin
      FOnUpdateColumnSize(Self, FSizeFixedCol, nw);
      if nw <> ColWidths[FSizeFixedCol] then
        ColWidths[FSizeFixedCol] := nw;
    end;
  end;

  if FSizingFixedR then
  begin
    FSizeFixedR := False;
    FSizingFixedR := False;

    offs := 0;
    for i := 1 to FSizeFixedRow do
      offs := offs + RowHeights[i - 1];

    nw := Msg.YPos - offs;
    RowHeights[FSizeFixedRow] := nw;

    if Assigned(FOnEndRowSize) then
      FOnEndRowSize(Self,FSizeFixedRow);

      {
    if Assigned(FOnUpdateRowSize) then
    begin
      FOnUpdateRowSize(Self, FSizeFixedRow, nw);
      if nw <> RowHeights[FSizeFixedRow] then
        RowHeights[FSizeFixedRow] := nw;
    end;
      }
  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);

    if not ControlLook.NoDisabledButtonLook then
      CanEdit := IsEditable(x,y); //GetCellReadOnly(x,y,CanEdit);

    if CanEdit or ControlLook.NoDisabledButtonLook or
      (FPushedCellButton.x < FixedCols) or (FPushedCellButton.y < FixedRows) then
    begin
      if not IsNode(FPushedCellButton.y) then
        PushButton(FPushedCellButton.x,FPushedCellButton.y,False);
      if Assigned(FOnButtonClick) then
        FOnButtonClick(Self,FPushedCellButton.x,FPushedCellButton.y);
    end;

    FPushedCellButton := Point(-1,-1);
    ReleaseCapture;
    //inherited;
    //Exit;
  end;


  if ((csDesigning in ComponentState) or FHintShowSizing) and FScrollHintShow then
  begin
    FScrollHintWnd.ReleaseHandle;
    FScrollHintShow := False;
  end;

  if (x <> -1) and (y <> -1) then
  begin
    if HasButton(x,y) then
    begin
      if PtInRect(ButtonRect(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 not FIsSizing and (((y < FixedRows) or (x < FixedCols)) or (not (goEditing in Options))) then
  begin
    OnClick(Self);
  end;

  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
        ClearRowSelect;
      end;

      if MouseActions.DisjunctRowSelect and DragDropSettings.OleDropSource and
        (GetKeyState(VK_CONTROL) and $8000 = $8000) then
      begin
        RowSelect[y] := not RowSelect[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 not (IsNode(y) and (x = 0))  then
  begin
    SelectToRowSelect(False);

    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;
      end;
    end;
    FDeselectState := False;
  end;


  if (IsNode(y) and (Grouping.AutoSelectGroup)) and (x > 0) and not GetNodeState(y) then
  begin
    if FMouseActions.DisjunctRowSelect then
    begin
      for i := 1 to GetNodeSpan(y) - 1 do
        RowSelect[RemapRowInv(y + i)] := true;
    end
    else
    begin
      Selection := TGridRect(Rect(FixedCols,y,ColCount,y + GetNodeSpan(y)-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 ((Screen.Cursor = crDrag) or (Screen.Cursor = crNoDrop)) and
     (FGridstate in [gsColMoving,gsRowMoving]) and FEnhRowColMove then
  begin
    MoveButton.Enabled := False;
    MoveButton.Visible := False;

    if Assigned(MoveForm) then
    begin
      FreeAndNil(MoveForm);
    end;

    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;

  if (FGridState = gsSelecting) then
  begin
    FGridState := gsNormal;
  end;

  if FMouseResize then
  begin
    if Assigned(OnSelectionResize) then
      OnSelectionResize(Self,FDropSelection, Selection);
    FEditDisable := True;
    PasteSelectionFromClipboard;
    FMouseResize := False;
    FEditDisable := False;
    if Assigned(OnSelectionResized) then
      OnSelectionResized(Self,FDropSelection, Selection);
  end;


  if Colmoveflg or Colsizeflg or (x < 0) or (y < 0) or
    ((x < Self.FixedCols) and not FSortSettings.FixedCols) 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;

  // Handle here if it is a sortable Column
  Doit := True;

  if FDblClk then
  begin
    FDblClk := False;
    Exit;
  end;

  r := CellRect(displx,y);


  if (y = 0) 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 (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;
       
     if (Assigned(FOnCanSort)) then
       FOnCanSort(self,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 (GetKeyState(VK_SHIFT) and $8000 = $8000) 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 Assigned(FOnClickSort) then
      FOnClickSort(self,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;

  {$IFNDEF TMSDOTNET}
  sl := TStringList(cg.CellBitmap);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  sl := cg.CellStrings;
  {$ENDIF}

  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] := Cells[RCol,ARow];

        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] := Cells[RCol,ARow];

        //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,ox,oy: 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, CanSelect: Boolean;
  {$IFNDEF DELPHI7}
  ks: TKeyboardState;
  {$ENDIF}
  GR: TGridRect;
  SS: TShiftState;
  ForceSelect, CanChange: boolean;
  noderow: boolean;

begin
  FMouseDownMove := True;
  FMouseKeepDown := True;
  FSpinUpClick := False;
  FSpinDnClick := False;
  ForceSelect := False;
  MouseToCell(Msg.XPos,Msg.YPos,X,Y);
  PrevSel := Selection;

  if SelectionResizer and SelectionRectangle then
  begin
    r := CellRect(Selection.Right,Selection.Bottom);
    r.Left := R.Right - 6;
    r.Top := r.Bottom - 6;

    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;

  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;

  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.DisjunctCellSelect and not (ssCtrl in SS) 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
    cpt := BaseCell(x,y);
    x := cpt.x;
    y := cpt.y;
    ClickRect := CellRect(x,y)
  end
  else
  begin
    HideInplaceEdit;
    if not FixedRowAlways then
      inherited;
    Exit;
  end;

  if FMouseActions.CaretPositioning then
    LButFlg := True;

  if FSizeFixed then
  begin
    FSizingFixed := True;
    FSizeFixedX := Msg.XPos;
    DrawSizingLine(FSizeFixedX);
    Exit;
  end;

  if FSizeFixedR then
  begin
    FSizingFixedR := True;
    FSizeFixedY := Msg.YPos;
    DrawSizingLineR(FSizeFixedY);
    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 not (GraphicObjects[0,y] as TCellGraphic).CellBoolean then
        begin
          Allow := True;

          if Assigned(FOnBeforeContractNode) then
            FOnBeforeContractNode(Self,y,RemapRowInv(y),Allow);

          if Allow then
          begin
            ContractNode(RemapRowInv(y));
            if Assigned(FOnContractNode) then
              FOnContractNode(self,y,RemapRowInv(y));
          end;
        end
        else
        begin
          Allow := True;

          if Assigned(FOnBeforeExpandNode) then
            FOnBeforeExpandNode(Self,y,RemapRowInv(y),Allow);

          if Allow then
          begin
            ExpandNode(RemapRowinv(y));
            if Assigned(FOnExpandNode) then
              FOnExpandNode(self,y,RemapRowinv(y));
          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);
        Exit;
      end;

    if (x = 0) and (y >= FixedRows) and (FNumNodes > 0) and not
      (MouseActions.RowSelect or (goRowSizing in Options)) then
    begin
      if Assigned(OnMouseDown) then
        OnMouseDown(Self, mbLEFT,SS ,msg.XPos, msg.YPos);

      if Assigned(OnClickCell) then
        OnClickCell(self,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
        if Assigned(OnMouseDown) then
          OnMouseDown(Self, mbLEFT,SS ,msg.XPos, msg.YPos);

        FSelectionClick := True;
        if Assigned(OnClickCell) then
          OnClickCell(self,y,x);
          
        Exit;
      end;
    end;

  end;

  if HasButton(rx,y) then
  begin
    HideInplaceEdit;

    // v2.5 added
    FForceSel := true;
    SelectCell(x,y);
    FForceSel := false;

    //move from here
    //Selection := TGridRect(Rect(x,y,x,y));

    if PtInRect(ButtonRect(x,y),Point(Msg.XPos,Msg.YPos)) then
    begin
      //move to here
      //Selection := TGridRect(Rect(x,y,x,y));
      PushButton(x,y,True);

      FPushedCellButton := Point(x,y);
      SetCapture(Self.Handle);

      if Assigned(OnClickCell) then
        OnClickCell(self,y,x);

      //if (goEditing in Options) then
      //  Options := Options - [goEditing];
      Exit;
    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 (FMouseActions.DisjunctRowSelect) and (y >= FixedRows) and (goEditing in Options) and
    not ((x = 0) and (FMouseActions.HotmailRowSelect)) then
  begin
    if GetKeystate(VK_SHIFT) and $8000 = $8000 then
    begin
      inherited;
      Selection := TGridRect(Rect(x,y,PrevSel.Left, PrevSel.Top));
      Exit;
    end;
  end;

  // if ctrl-pressed / shift pressed
  if (FMouseActions.DisjunctRowSelect) and (y >= FixedRows) and
    not ((x = 0) and (FMouseActions.HotmailRowSelect)) then
  begin
    if GetKeystate(VK_CONTROL) and $8000 = $8000 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
        ClearRowSelect;
    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
        r.Left := r.Left + 1 + FXYOffset.X;
        r.Top := r.Top + 1 + FXYOffset.Y;
        if HasCheckBox(rx,y) then
          r.Left := r.Left + ControlLook.CheckSize;

        if not HTMLDrawEx(Canvas,s,r,Gridimages,Msg.XPos,Msg.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,CID,CV,CT,FImageCache,FContainer,self.Handle) then
          Anchor := '';
      end;

    if Anchor <> '' then
    begin
      Handle := True;

      CanEdit := (goEditing in Options);

      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 Assigned(FOnControlClick) then
          FOnControlClick(Self,y,x,CID,CT,CV);

        ControlEnter(S, CT, CID, CV, CR, x,rx,y);
      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
          {$IFNDEF TMSDOTNET}
          ShellExecute(Application.Handle,'open',PChar(Anchor), nil, nil, SW_NORMAL);
          {$ENDIF}

          {$IFDEF TMSDOTNET}
          ShellExecute(Application.Handle,'open',Anchor,'' ,'', SW_NORMAL);
          {$ENDIF}
        Exit;
    end;

    if (ctt = ttHTML) and (pos('<CONTROL',uppercase(s))> 0) then
    begin
      if Assigned(OnClickCell) then
        OnClickCell(self, ox, oy);
      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
     (goRangeSelect in Options) and
     (FMouseSelectMode = msRow) then
  begin
    ORow := Selection.Top;
    OCol := Selection.Left;

    if EditMode then
      SetFocus; // make sure inplace editors are hidden

    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
      Selection := TGridRect(Rect(FixedCols,y,ColCount - 1,y));

    FSelHidden := False;
    DoExit;   // force validatecell call
    FMouseSelectStart := y;
    if ActiveCellShow then
      UpdateActiveCells(OCol,ORow,x,y);
  end;

  if (x >= FixedCols) and (y < FixedRows) and
     (FMouseActions.ColSelect) and
     (goRangeSelect in Options) and
     (FMouseSelectMode = msColumn) then
  begin

    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
      Selection := TGridRect(Rect(OCol,FixedRows,x,RowCount - 1));
    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);

  if (x < ColCount) and (y < RowCount) and
     //(((x >= FixedCols) and
     (CanEdit or ControlLook.CheckAlwaysActive) and
     //((y >= FixedRows) or MouseActions.CheckAllCheck)) or
     //( (x = 0) and (MouseActions.HotmailRowSelect))) and
     HasCheckBox(rx,y) and IsInCheckBox(rx,y,Msg.XPos,Msg.YPos) then
  begin
    // hide any other possible active inplace editors
    HideInplaceEdit;
    SetFocus;

    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[y] := not RowSelect[y];

      if (y = Row) and not RowSelect[y] then
      begin
        HideSelection;
        FSelHidden := false;
      end;
    end;

    ry := RealRowIndex(y);

    GetCheckBoxState(rx,ry,chk);

    // move focus to checkbox cell
    if not Navigation.AlwaysEdit then
      MoveColRow(x,y,True,True);

    if Assigned(FOnCheckBoxClick) then
      FOnCheckBoxClick(Self,x,y,chk);

    if FHideFocusRect then
    begin
      RepaintCell(x,y);
    end;

    if (y < FixedRows) and (MouseActions.CheckAllCheck) then
    begin
      if chk then
        CheckAll(rx)
      else
        UnCheckAll(rx);
    end;

    if Assigned(OnMouseDown) then
    begin
      {$IFDEF DELPHI7}
      OnMouseDown(Self,mbLeft,KeyboardStateToShiftState,msg.XPos,msg.Ypos);
      {$ELSE}
      GetKeyboardState(ks);
      OnMouseDown(Self,mbLeft,KeyboardStateToShiftState(ks),msg.XPos,msg.Ypos);
      {$ENDIF}
    end;
    Click;
    Exit;
  end;

  if (x >= FixedCols) and
     (y >= FixedRows) and
     CanEdit and (FMouseActions.DirectEdit or (ControlLook.DropDownAlwaysVisible and HasCombo(x,y))) then
  begin
    HideEditor;
    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;


  // 4.0.6.13
  if ClickInSelect and not CanEdit then
  begin
    Options := Options - [goEditing];
  end;

  FOldAlwaysEdit := FNavigation.AlwaysEdit;

  if FixCellClick then
  begin
    if  not ((y = RowCount - 1) and (FloatingFooter.Visible = true) and (FloatingFooter.FooterStyle = fsFixedLastRow)) then
    if Assigned(FOnClickCell) then
      FOnClickCell(Self,Y,X);
    Exit;
  end;

  LastCellClicked := (Y = TopRow + VisibleRowCount) or (X = LeftCol + VisibleColCount);

  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;
      // 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
    if Assigned(FOnClickCell) then
      FOnClickCell(Self,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
    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 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 and
     (FMouseActions.DirectEdit or (ControlLook.DropDownAlwaysVisible and HasCombo(rx,y))) and not HasStaticEdit(rx,y) 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;

//  FMouseActions.RangeSelectAndEdit := true;

  if ForceSelect then
  begin
    FGridState := gsSelecting;
  end;
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 + 4;
    FEditControl.Height := CR.Bottom - CR.Top - 4;
    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.Left := CR.Left + 1;
    FComboControl.Width := CR.Right - CR.Left - 4;
    FComboControl.Top := CR.Top + 4;

    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 (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}

begin
  Inc(Compares);

  if FSortSettings.AutoFormat then
    aStyle := ssAutomatic
  else
    aStyle := ssAlphabetic;

  Prefix := '';
  Suffix := '';
  GetColFormat(Col,AStyle,Prefix,Suffix);

  res := 1;

  s1 := Cells[Col,ARow1];
  s2 := Cells[Col,ARow2];


  if AStyle = ssAutomatic then
  begin
    if (CellTypes[Col,ARow1] in [ctCheckBox, ctDataCheckBox,ctVirtCheckBox,ctRowCheckBox]) then
      aStyle := ssCheckBox
    else
    begin
      s1 := Cells[Col,ARow1];
      if (IsType(s1) in [atNumeric,atFloat,atScientific]) then
        aStyle := ssNumeric
      else
      begin
        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])) then
          begin
            {$IFDEF DELPHI7_LVL}
            if (pos(TimeSeparator,s1) > 0) then
              aStyle := ssDateTime
            else
            {$ENDIF}
            aStyle := ssDate
          end
          else
            aStyle := ssAlphabetic;
        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])) then
              aStyle := ssTime
            else
              aStyle := ssAlphaBetic
          end
          else
          {$ENDIF}
            aStyle := ssAlphabetic;
        end;
      end;
    end;
  end;

  if (AStyle in [ssAlphaNumeric, ssAlphaNumericNoCase]) then
  begin
    if (IsType(s1) in [atNumeric,atFloat,atScientific]) and (IsType(s2) in [atNumeric,atFloat,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 (Cells[Col,ARow1] > Cells[Col,ARow2]) then
      res := 1
    else
      if (Cells[Col,ARow1] = Cells[Col,ARow2]) then
        res := 0
      else
        res := -1;
  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(Cells[Col,ARow1]);
    s2 := UpperCase(Cells[Col,ARow2]);

    if s1 > s2 then
      res := 1
    else
      if s1 = s2 then
      begin
        if (Cells[Col,ARow1] > Cells[Col,ARow2]) then
          res := 1
        else
          if (Cells[Col,ARow1] = Cells[Col,ARow2]) then
            res := 0
          else
            res := -1;
      end
      else
        res := -1;
  end;
  ssAnsiAlphaCase:
  begin
    res := AnsiCompareStr(self.Cells[Col,ARow1],self.Cells[Col,ARow2]);
    if res > 0 then
      res := 1
    else
      if res < 0 then
        res := -1;
  end;
  ssAnsiAlphaNoCase:
  begin
    res := AnsiCompareText(self.Cells[Col,ARow1],self.Cells[Col,ARow2]);
    if res > 0 then
      res := 1
    else
      if res < 0 then
        res := -1;
  end;
  ssNumeric,ssFinancial:
  begin
    s1 := Cells[Col,ARow1];
    s2 := Cells[Col,ARow2];

    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;

    Val(s1,r1,code1);
    Val(s2,r2,code2);

    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
    begin
      if not SortSettings.SortOnVirtualCells then
        FCustomCompare(Self,GridCells[Col,ARow1],GridCells[Col,ARow2],res)
      else
        FCustomCompare(Self,Cells[Col,ARow1],Cells[Col,ARow2],res);
    end;
  end;

  ssRaw:
  begin
    res := 0;
    if Assigned(FRawCompare) then
      FRawCompare(self,Col,ARow1,ARow2,res);
  end;

  {$IFDEF DELPHI7_LVL}
  ssTime:
  begin
    s1 := Cells[Col,ARow1];
    s2 := Cells[Col,ARow2];
    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
    s1 := Cells[Col,ARow1];
    s2 := Cells[Col,ARow2];
    try
      dt1 := StrToDateTime(s1);
    except
      dt1 := 0;
    end;
    try
      dt2 := StrToDateTime(s2);
    except
      dt2 := 0;
    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;
    s1 := Cells[Col,ARow1];
    s2 := Cells[Col,ARow2];


    case aStyle of
    ssDate:
    begin
      {$IFDEF TMSDOTNET}
      try
        if s1 = '' then
          dt1 := 0
        else
          dt1 := system.datetime.parse(s1);
      except
        dt1 := 0;
      end;

      try
        if s2 = '' then
          dt2 := 0
        else
          dt2 := system.datetime.parse(s2);
      except
        dt2 := 0;
      end;
     {$ENDIF}

     {$IFNDEF TMSDOTNET}
      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;
      {$ENDIF}
      
    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 (Cells[Col,ARow1] = '') and (Cells[Col,ARow2] <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := -1
          else
            res := +1;

        if (Cells[Col,ARow2] = '') and (Cells[Col,ARow1] <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := +1
          else
            res := -1;

      end;
    sdDescending:
      begin
        if (Cells[Col,ARow1] = '') and (Cells[Col,ARow2] <> '') then
          if FSortSettings.BlankPos = blFirst then
            res := +1
          else
            res := -1;

        if (Cells[Col,ARow2] = '') and (Cells[Col,ARow1] <> '') 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.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: 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 (CompareLine(Col,RowCount - 2,i) = SortDir) and (i < Right) do Inc(i);
    while (CompareLine(Col,j,RowCount - 2) = 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);

  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: integer;
  tr: Integer;
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;

  BeginUpdate;

  try
    RowCount := RowCount + 3;
    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;
    RowCount := RowCount - 3;

  finally
    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(FCols);
      FCols.Free;
    end;

    if FNavigation.KeepScrollOnSort then
      TopRow := tr;

    EndUpdate;
  end;
end;

procedure TAdvStringGrid.Sort(Column: integer; Direction: TSortDirection = sdAscending);
begin
  SortSettings.Column := Column;
  SortSettings.Direction := Direction;
  QSort;
end;

procedure TAdvStringGrid.QSort;
var
  cw,cc,cr: Integer;
  enterstate: Boolean;
  FCols: TStringList;
  tr: Integer;

begin
  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;

  BeginUpdate;

  try
    RowCount := RowCount + 3;
    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;
    cr := Row;

    if FNavigation.MoveRowOnSort then
      Row := RowCount - 3;

    QuickSortRows(FSortSettings.Column,FixedRows,(RowCount - 1) - 3 - FFixedFooters);

    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;

    FEntered := Enterstate;

    ColCount := ColCount - NumHiddenColumns;
    ColWidths[cc] := cw;
    RowCount := RowCount - 3;

    if Assigned(FOnRowChanged) and not Navigation.MoveRowOnSort then
      FOnRowChanged(Self,cr,Row);

  finally
    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(fCols);
      FCols.Free;
    end;

    if FNavigation.KeepScrollOnSort then
      TopRow := tr;
    EndUpdate;

  end;
end;

procedure TAdvStringGrid.QSortIndexed;
var
  cw,cc,cr: Integer;
  enterstate: Boolean;
  FCols: TStringList;
  tr: integer;
  
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;

  try
    RowCount := RowCount + 3;
    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,self.FixedRows,(self.RowCount - 1) - 3 - FFixedFooters);

    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;
    RowCount := RowCount - 3;
  finally
    if FSortSettings.NormalCellsOnly and (FixedCols > 0) then
    begin
      Cols[0].Assign(fCols);
      FCols.Free;
    end;

    if FNavigation.KeepScrollOnSort then
      TopRow := tr;

    EndUpdate;
  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.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
         FRowSelect.Delete(RowIndex);
    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;

begin
  if RowIndex > RowCount 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;

  SelectCell(Col,Row);

  BeginUpdate;

  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
          (FGriditems.Items[i - 1] as TGridItem).Idx :=
            (FGriditems.Items[i - 1] as TGridItem).Idx - RCount;
      end;
    end;

    for i := 1 to RCount do
    begin
      if ShowModified.Enabled then
        if FModifiedRows.Count > RowIndex then
          FModifiedRows.Delete(RowIndex);

      if FMouseActions.DisjunctRowSelect and (FRowSelect.Count > RowIndex) then
      begin
        FRowSelect.Delete(RowIndex);
      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;

    FMaxRowCount := FMaxRowCount - RCount;

{
    for i := 1 to RCount do
    begin
      DeleteRow(RowIndex);
    end;
}

    if cr < RowCount - FFixedFooters then
    begin
      Row := cr;
      TopRow := tr;
    end
    else
    begin
      if RowCount - FFixedFooters > FixedRows then
        Row := RowCount - FFixedFooters - 1
      else
        HideSelection;
      // no need to keep this set from here: v2.4.0.5
      FSelHidden := False;
    end;

    ColCount := ColCount - FNumHidden;
    ColWidths[cc] := cw;
    FloatingFooter.Visible := fv;
    FFixedFooters := ff;
  finally
    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;
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;

  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;

    try
      BeginUpdate;
      ColCount := ColCount + FNumHidden;

      tr := TopRow;
      cr := Row;

      rs := goRowSelect in Options;

      if rs then
        Options := Options - [goRowSelect];

      if FNumNodes > 0 then
        Col := 1;

      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;

      ColCount := ColCount - FNumHidden;
      ColWidths[cc] := cw;

    finally
      EndUpdate;
    end;

    FEntered := EnterState;

    CellsChanged(Rect(0,RowIndex,ColCount-1,RowIndex + RCount));

    if TopRow >= RowCount - 1 then
      TopRow := RowCount - 1;

    if (Row >= 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 then
        Options := Options + [goRowSelect];

  finally
    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;
begin
  ACol := RemapCol(ACol);
  sl := TStringList.Create;
  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]));
        Inc(i);
      end
      else
        RemoveRowsInternal(i,1);
    end;
  finally
    EndUpdate;
    sl.Free;
  end;  
end;

procedure TAdvStringGrid.RemoveSelectedRows;
var
  i,j: Integer;
  ss,se: Integer;
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);

      Exit;
    end;

    i := RowCount - FixedFooters - 1;

    //while i < RowCount - FixedFooters do
    while i >= FixedRows do
    begin

      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      if RowSelect[j] then
      begin
        RemoveRowsInternal(i,1);
        //inc(i);
        //FRowSelect.Delete(j);  // 2.7.0.7
      end;
      //else
      //  Inc(i);

      dec(i);

    end;
  finally
    EndUpdate;
  end;  
end;

procedure TAdvStringGrid.RemoveUnSelectedRows;
var
  i,j: Integer;
begin
  BeginUpdate;
  try
    i := FixedRows;
    while i < RowCount - FixedFooters do
    begin
      if FMouseActions.RowSelectPersistent then
        j := RemapRowInv(i)
      else
        j := i;

      if not RowSelect[j] then
        RemoveRowsInternal(i,1)
      else
        Inc(i);
    end;
  finally
    EndUpdate;
  end;  
end;


procedure TAdvStringGrid.HideSelectedRows;
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 RowSelect[k] then
      begin
        j := RealRowIndex(i);
        HideRows(j,j);
      end
      else
        Inc(i);
    end;
  finally
    EndUpdate;
  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.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 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 (ACol2 >= ColCount - 1) and (ARow2 >= RowCount - 1) and (ACol1 = 0) and (ARow1 = 0) then
    FHasCellProps := false;

  if not (csDestroying in ComponentState) 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);
var
  i,j: Integer;
  cw,cc: Integer;
begin
  cc := ColCount - 1;
  cw := ColWidths[cc];

  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;

  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
    ColWidths[i] := DefaultColWidth;
    FVisibleCol[i] := True;
  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] := 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;
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
    if FMouseActions.DisjunctColSelect then
    begin
      for i := FixedCols to ColCount - 1 do
      begin
        if ColSelect[i] then
          ClearCols(i,1);
      end;
    end
    else
      ClearRect(Selection.Left,Selection.Top,Selection.Right,Selection.Bottom);
  end;
end;

procedure TAdvStringGrid.Clear;
begin
  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 := '';
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: Integer;

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;

  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 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);

        // 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);
            {$IFNDEF TMSDOTNET}
            cg.CellBitmap := TBitmap(pic);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            cg.CellPicture := pic;
            {$ENDIF}
          end;
        ctFilePicture:
          begin
            Stream.ReadComponent(gfio);
            gfio.Name := '';
            fpic := TFilePicture.Create;
            fpic.Assign(gfio.Picture);
            {$IFNDEF TMSDOTNET}
            cg.CellBitmap := TBitmap(fpic);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            cg.CellFilePicture := fpic;
            {$ENDIF}
          end;
        ctRadio:
          begin
            Stream.ReadComponent(gsio);
            gsio.Name := '';
            sl := TStringList.Create;
            sl.Assign(gsio.Strings);
            {$IFNDEF TMSDOTNET}
            cg.CellBitmap := TBitmap(sl);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            cg.CellStrings := sl;
            {$ENDIF}
          end;
        ctImages:
          begin
            Stream.ReadComponent(gsio);
            gsio.Name := '';
            il := TIntList.Create(c,r);
            il.StrValue := gsio.Strings.CommaText;
            {$IFNDEF TMSDOTNET}
            cg.CellBitmap := TBitmap(il);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            cg.CellList := il;
            {$ENDIF}
          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);
var
  i,j: Integer;
  cpio: TGridCellIO;
  cgio: TGridGraphicIO;
  gpio: TGridPropIO;
  gbio: TGridBMPIO;
  giio: TGridIconIO;
  gtio: TGridPicIO;
  gfio: TGridFilePicIO;
  gsio: TGridSLIO;
  pio: TGridCellPropIO;
  HasProp: Boolean;
  nprogr,oprogr: Integer;

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;
  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, -1);

  for j := Rect.Top to Rect.Bottom do
  begin
    ExportNotification(esExportNewRow, j);

    for i := Rect.Left to Rect.Right do
    begin
      HasProp := HasCellProperties(i,j);
      if (1 > 0) {(Cells[i,j] <> '') or HasProp} then
      begin
        cpio.Col := i;
        cpio.Row := j;
        cpio.Cell := Cells[i,j];

        cpio.HasProp := HasProp;

        Stream.WriteComponent(cpio);

        if HasProp then
        begin
          pio.CellProperties.Assign(CellProperties[i,j]);

          pio.HasGraphic := (CellTypes[i,j] <> ctEmpty) and
                  (not ((CellTypes[i,j] in [ctBitmap,ctBitButton,ctPicture,ctFilePicture,ctImages,ctRadio,ctIcon])
                   and not CellGraphics[i,j].CellCreated));

          Stream.WriteComponent(pio);

          if pio.HasGraphic then
          begin
            cgio.CellGraphic.CellText := '';
            cgio.CellGraphic.Assign(CellGraphics[i,j]);
            Stream.WriteComponent(cgio);

            case CellTypes[i,j] of
            ctBitmap,ctBitButton:
              begin
                gbio.Bitmap.Assign(CellGraphics[i,j].CellBitmap);
                Stream.WriteComponent(gbio);
              end;
            ctIcon:
              begin
                giio.Icon.Assign(CellGraphics[i,j].CellIcon);
                Stream.WriteComponent(giio);
              end;
            ctPicture:
              begin
                {$IFNDEF TMSDOTNET}
                gtio.Picture.Assign(TPicture(CellGraphics[i,j].CellBitmap));
                {$ENDIF}
                {$IFDEF TMSDOTNET}
                gtio.Picture.Assign(CellGraphics[i,j].CellPicture);
                {$ENDIF}
                Stream.WriteComponent(gtio);
              end;
            ctFilePicture:
              begin
                {$IFNDEF TMSDOTNET}
                gfio.Picture.Assign(TFilePicture(CellGraphics[i,j].CellBitmap));
                {$ENDIF}
                {$IFDEF TMSDOTNET}
                gfio.Picture.Assign(CellGraphics[i,j].CellFilePicture);
                {$ENDIF}
                Stream.WriteComponent(gfio);
              end;
            ctRadio:
              begin
                {$IFNDEF TMSDOTNET}
                gsio.Strings.Assign(TStringList(CellGraphics[i,j].CellBitmap));
                {$ENDIF}
                {$IFDEF TMSDOTNET}
                gsio.Strings.Assign(CellGraphics[i,j].CellStrings);
                {$ENDIF}
                Stream.WriteComponent(gsio);
              end;
            ctImages:
              begin
                {$IFNDEF TMSDOTNET}
                gsio.Strings.CommaText := TIntList(CellGraphics[i,j].CellBitmap).StrValue;
                {$ENDIF}
                {$IFDEF TMSDOTNET}
                gsio.Strings.CommaText := CellGraphics[i,j].CellList.StrValue;
                {$ENDIF}
                Stream.WriteComponent(gsio);
              end;
            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);
begin
  if FSaveFixedCells then
    SaveRectToBinStream(Rect(0,0,ColCount - 1,RowCount - 1),Stream)
  else
    SaveRectToBinStream(Rect(FixedCols,FixedRows,ColCount - 1, RowCount - 1), Stream);
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, -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);
        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 then
  begin
    StrtCol := 0;
    strtRow := 0;
  end;

  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[0..MaxColumns] of byte;
  OldCursor: TCursor;
  StrtCol, StrtRow: integer;
  sl: TFileStringList;
  
begin
  OldCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  (*
  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 then
  begin
    StrtCol := 0;
    strtRow := 0;
  end;

  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, -1);

    MultiLineList := TStringlist.Create;
    for z := StrtRow to RowCount - 1 do
    begin
      ExportNotification(esExportNewRow, 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, TEncoding.Unicode)
    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);
begin
  OutputToHTML(Filename,False);

  {$IFNDEF TMSDOTNET}
  if Show then
    ShellExecute(Application.Handle, 'open', PChar(FileName), nil, nil, SW_NORMAL);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  if Show then
    ShellExecute(Application.Handle, 'open', FileName, '', '', SW_NORMAL);
  {$ENDIF}

end;

procedure TAdvStringGrid.AppendToHTML(Filename:string);
begin
  OutputToHTML(Filename,True);
end;


{$IFNDEF DELPHI6_LVL}
function DirectoryExists(const Name: string): Boolean;
var
  Code: Integer;
begin
  Code := GetFileAttributes(PChar(Name));
  Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
end;
{$ENDIF}

function TAdvStringGrid.SaveToHTMLString(dir:string): string;
var
  i,j,mc,mr: Integer;
  s,al,ac,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;
  image: string;
  htmlhdr: string;


  {$IFNDEF TMSDOTNET}
  function HTMLAddImage(Pic: TGraphic;counter:integer;dir:string):string;
  var
    JPic: TJPEGImage;
    BPic: TBitmap;
    fname:string;
  begin
    if not DirectoryExists(dir + 'images') then
      if not CreateDir(dir + 'images') then
        raise Exception.Create('Cannot create ' + dir + 'images');

    fname := dir + 'images\img' + 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);
          fname := dir + 'images\img' + inttostr(counter) + '.bmp';
        end; //finally
        fname := dir + 'images\img' + inttostr(counter) + '.jpg';
        JPic.SaveTofile(fname);
      finally
        FreeAndNil(JPic);
      end; //finally
    end
    else
      Pic.SaveTofile(fname);

    Result := fname;
  end;
  {$ENDIF}

  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;

begin
  StrtCol := FixedCols;
  StrtRow := FixedRows;

  if FSaveFixedCells then
  begin
    StrtCol := 0;
    StrtRow := 0;
  end;

  SList := TStringlist.Create;
  SList.Sorted := False;

  CSSList := TStringList.Create;

  DoneColW := False;

  htmlhdr := '';

  with SList do
  begin
    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;

    if FHTMLSettings.PrefixTag <> '' then
      htmlhdr := htmlhdr + FHTMLSettings.PrefixTag;

    if FHTMLSettings.TableStyle <> '' then
      TableStyle := ' ' + FHTMLSettings.TableStyle + ' '
    else
      TableStyle := '';

    Add('<table border="'+IntToStr(FHTMLSettings.BorderSize)+
        '" cellspacing="'+IntToStr(FHTMLSettings.CellSpacing)+
        '" cellpadding="'+IntToStr(FHTMLSettings.CellPadding)+
        '" ' + TableStyle +
        ' width="' + IntToStr(FHTMLSettings.Width) + '%">');  // begin the table

    TopRow := StrtRow;

    if (FixedRows > 0) and FSaveFixedCells then
    begin
      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) + '"';

          CellText := SaveCell(RemapCol(i),0);

          s := HTMLLineBreaks(CellText);
          s := MakeHREF(s);
          if s = '' then
            s := '<br>';
          {
          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])
          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';

          cssval := css(Canvas.Font, FixedColor, HAlign, VAlign);

          cssidx := CSSList.IndexOf(cssval);
          if cssidx = -1 then
            cssidx := CSSList.Add(cssval);



          ac := ' bgcolor="#' + HTMLColor(ColorToRGB(FixedColor)) + '"';

          //Add('<td' + wraptxt + al + ac + av + colwtxt + spantxt + '>' + ass + afs + s + afe + ase + '</td>');

          Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');

        end;
      end;
      Add('</tr>');
      TopRow := 1;
    end;

    ExportNotification(esExportStart, -1);
    images_counter := 1;
    for i := TopRow to RowCount - 1 do
    begin
      ExportNotification(esExportNewRow, i);
      Add('<tr>');

      for j := StrtCol to ColCount-1 do

      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) + '"';

        CellText := SaveCell(RemapCol(j),i);
        s := CellText;

        if HTMLSettings.ConvertSpecialChars then
          s := FixMarkup(s);

        if HTMLSettings.NonBreakingText then
          s := FixNonBreaking(s);

        s := HTMLLineBreaks(s);
        s := MakeHREF(s);

        al := '';
        ac := '';
        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(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 (i < FixedRows) or (j < FixedCols) then
        begin
          ac := ' bgcolor="#' + HTMLColor(ColorToRGB(FixedColor)) + '"';
        end
        else
          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 (Canvas.Brush.Color <> $7fffffff) and FHTMLSettings.SaveColor then
           ac := ' bgcolor="#' + HTMLColor(dword(ColorToRGB(Canvas.Brush.Color))) + '"';

        if (Canvas.Font.Color <> $7fffffff) and FHTMLSettings.SaveColor then
        begin
          afs := '<font color="#' + HTMLColor(dword(ColorToRGB(Canvas.Font.Color))) + '">';
          afe := '</font>';
        end;

        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;

          afs := '';
          afc := '';
          aff := '';
          afe := '';

          if (Canvas.Font.Color <> $7fffffff) and FHTMLSettings.SaveColor then
            afc := 'color="#'+HTMLColor(dword(ColorToRGB(Canvas.Font.Color))) + '"';

          if Canvas.Font.Name <> Font.Name then
          begin
            aff := 'face="'+Canvas.Font.Name+'"';
          end;

          if (aff <> '') or (afc <> '') then
          begin
            afs := '<font ' + afc + ' ' + aff + '>';
            afe := '</font>';
          end;
        end;
        }
        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 ])
        else
          colwtxt := '';

        if Trim(s) = '' then
          if HTMLSettings.XHTML then
            s := '<br/>'
          else
            s := '<br>';

        //Add('<td' + spantxt + wraptxt + al + av + ac + colwtxt + '>'+ afs + ass + s + ase + afe + '</td>');

        if WW then
          WrapTxt := ''
        else
          WrapTxt := ' nowrap';

        //Export Images

        {$IFNDEF TMSDOTNET}
        Pic := CellGraphics[j, i];
        if (Pic <> nil) then
          case Pic.Celltype of
          ctImageList:
            begin
              if Assigned(GridImages) and (pic.FCellIndex >= 0) and (pic.FCellIndex < GridImages.Count) then
              begin
                ImgLstBmp := TBitmap.Create;
                GridImages.GetBitmap(pic.FCellIndex, ImgLstBmp);
                image := '<img src= "file://' + HTMLAddImage(ImgLstBmp,images_counter,dir)+'">';
                Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' + s + image + '</td>');
                ImgLstBmp.Free;
                inc(images_counter);
              end
              else
                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)+'">';
                Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' + s + image + '</td>');
                inc(images_counter);
              end
              else
                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) + '"';
                Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+image+'</td>');
                inc(images_counter);
              end
              else
                Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
            end;
          end
          else
            Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
         {$ENDIF}

         {$IFDEF TMSDOTNET}
         Add('<td class="c'+inttostr(cssidx)+'"'+spantxt + wraptxt + colwtxt+'>' +s+'</td>');
         {$ENDIF}
       end;

      Add('</tr>');
    end;

    ExportNotification(esExportDone, -1);

    Add('</table>');
    if FHTMLSettings.SuffixTag <> '' then
      Add(FHTMLSettings.SuffixTag);

    if FHTMLSettings.XHTML then
      Add('</html>');
  end; // with SList

  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);
var
  f,hdr: TextFile;
  s: string;
  dir:string;
begin
  AssignFile(f,FileName);

  if AppendMode then
  begin
    {$i-}
    Reset(f);
    {$i+}
    if IOResult <> 0 then
    begin
      {$i-}
      Rewrite(f);
      {$i+}
      if IOResult <> 0 then
      begin
        raise EAdvGridError.Create('Cannot Create file '+FileName);
      end;
    end
    else Append(f);
  end
  else
  begin
    {$i-}
    Rewrite(f);
    {$i+}
    if  IOResult <> 0 then
    begin
      raise EAdvGridError.Create('Cannot Create file '+FileName);
    end;
  end;

  if FHTMLSettings.HeaderFile <> '' then
  begin
    AssignFile(hdr,FHTMLSettings.HeaderFile);
    {$i-}
    Reset(hdr);
    {$i+}
    if IOResult = 0 then
    begin
      while not eof(hdr) do
      begin
        ReadLn(hdr,s);
        WriteLn(f,s);
      end;
      CloseFile(hdr);
    end;
  end;

  dir := ExtractFilePath(filename);
  writeln(f,SaveToHTMLString(dir));

  if FHTMLSettings.FooterFile <> '' then
  begin
    AssignFile(hdr,FHTMLSettings.FooterFile);
    {$i-}
    Reset(hdr);
    {$i+}
    if IOResult = 0 then
    begin
      while not eof(hdr) do
      begin
        ReadLn(hdr,s);
        WriteLn(f,s);
      end;
      CloseFile(hdr);
    end;
  end;
  CloseFile(f);


  if FHTMLSettings.AutoPreview then
  {$IFNDEF TMSDOTNET}
    ShellExecute(0,'open',PChar(FileName),nil,nil,SW_NORMAL);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
    ShellExecute(0,'open',FileName,'','',SW_NORMAL);
  {$ENDIF}
end;

procedure TAdvStringGrid.LoadFromXML(FileName: string; LevelToRow: boolean = false);
{$IFNDEF TMSDOTNET}
var
  Doc: Variant;
  i, Fc, Fr, c, r, 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 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);
          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 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);
        end;
        inc(c);
      end;
    end
    else  // if Node has childs
    begin
      if LevelToRow and not RowAlreadyAdded then
        inc(r);

      inc(l);

      for j:= 0 to aNode.childNodes.Length - 1 do
      begin
        LoadChildNodes(aNode.childNodes.Item[j]);
      end;
    end;
  end;
{$ENDIF}

begin
{$IFNDEF TMSDOTNET}

  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;

  if FSaveFixedCells then
  begin
    fc := 0;
  end
  else
  begin
    fc := FixedCols;
  end;


  fr := FixedRows;
  ColCount := FixedCols + 1;
  RowCount := FixedRows + 1;
  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 // Temporary
        inc(r);
    end;
  finally
    //Doc._Release;
  end;
{$ENDIF}
  CellsLoaded;
end;

procedure TAdvStringGrid.SaveToXML(FileName: String; ListDescr, RecordDescr:string;FieldDescr: TStrings; ExportEmptyCells: boolean=false);
var
  i,j: Integer;
  f: TextFile;
  s: string;
  cr: 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, -1);

  for i := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNewRow, i);

    writeln(f,'<'+RecordDescr+'>');
    for j := SaveStartCol to SaveEndCol do
    begin
      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 (j - SaveStartCol < FieldDescr.Count) then
            write(f,'<' + FieldDescr.Strings[j - SaveStartCol]+'>')
          else
            write(f,'<FIELD' + IntToStr(j - 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 (j - SaveStartCol< FieldDescr.Count) then
            writeln(f,'</' + FieldDescr.Strings[j - SaveStartCol]+'>')
          else
            writeln(f,'</FIELD' + IntToStr(j - SaveStartCol)+'>');
        end;
      end;
    end;
    writeln(f,'</' + RecordDescr + '>');
  end;

  writeln(f,'</' + ListDescr + '>');

  ExportNotification(esExportDone, -1);
  CloseFile(f);
end;

procedure TAdvStringGrid.CopyBinFunc(gd: TGridRect);
var
  ms: TMemoryStream;
  Data: THandle;
  {$IFNDEF TMSDOTNET}
  DataPtr: Pointer;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  DataPtr : IntPtr;
  {$ENDIF}
  Clipboard: TClipboard;
begin
  ms := TMemoryStream.Create;
  Clipboard := TClipboard.Create;
  Clipboard.Open;

  try
    SaveRectToBinStream(TRect(gd),ms);

    Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, ms.Size);
    try
      DataPtr := GlobalLock(Data);
      try
        {$IFNDEF TMSDOTNET}
        Move(ms.Memory^, DataPtr^, ms.Size);
        {$ENDIF}
        SetClipboardData(CF_GRIDCELLS, Data);
      finally
        GlobalUnlock(Data);
      end;
    except
      GlobalFree(Data);
      raise;
    end;
  finally
    ms.Free;
    Clipboard.Close;
    Clipboard.Free;
  end;
end;

procedure TAdvStringGrid.CopyRTFFunc(ACol,ARow: Integer);
var
  s: string;
  GHandle: THandle;
  {$IFNDEF TMSDOTNET}
  Gptr: PChar;
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  Gptr: IntPtr;
  {$ENDIF}

  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;

  {$IFNDEF TMSDOTNET}
  StrCopy(gptr,'');
  StrCat(gptr,PChar(s));
  {$ENDIF}

  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.CopyFunc(gd: TGridRect; DoDisjunct: Boolean);
var
  s,z,rc,zr: Integer;
  len: Integer;
  {$IFNDEF TMSDOTNET}
  buffer,ptr: PChar;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  buffer, ptr : string;
  {$ENDIF}
  ct: string;
  es: TGridExportState;

begin
  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,FRichEdit);
            ct := FRichEdit.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;

  {$IFNDEF TMSDOTNET}
  Buffer := nil;
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  Buffer := '';
  {$ENDIF}

  {$IFDEF DELPHI_UNICODE}
  len := len * 2;
  {$ENDIF}

  //fill buffer and copy to clipboard
  try
    {$IFNDEF TMSDOTNET}
    GetMem(Buffer,len);
    //fill buffer
    Buffer^ := #0;
    {$ENDIF}

    ptr := 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,FRichEdit);
               ct := FRichEdit.Text;
            end;

            if (LinesInText(ct,FMultiLineCells)>1) and FExcelClipboardFormat then
              LineFeedsToCSV(ct);

            {$IFNDEF TMSDOTNET}
            ptr := StrEnd(StrPCopy(ptr,ct + #9));
            {$ENDIF}

            {$IFDEF TMSDOTNET}
            if s < gd.Right then
              buffer := buffer + ct + #9
            else
              buffer := buffer + ct;  
            {$ENDIF}
          end;
        end;

        {$IFNDEF TMSDOTNET}
        Dec(ptr);
        {$ENDIF}

        if gd.Top < gd.Bottom then
        begin
          {$IFNDEF TMSDOTNET}
          ptr := StrEnd(StrPCopy(ptr,#13#10));
          {$ENDIF}
          {$IFDEF TMSDOTNET}
          buffer := buffer + #13#10;
          {$ENDIF}
        end;
      end;
    end;

    {$IFNDEF TMSDOTNET}

    {$IFDEF DELPHI_UNICODE}
    Clipboard.AsText := buffer;
    {$ENDIF}

    {$IFNDEF DELPHI_UNICODE}
    ptr^ := #0;
    ClipBoard.SetTextBuf(buffer)
    {$ENDIF}
    
    {$ENDIF}
    
    {$IFDEF TMSDOTNET}
    Clipboard.SetTextBuf(buffer);
    {$ENDIF}

  finally
    {$IFNDEF TMSDOTNET}
    FreeMem(buffer,len);
    {$ENDIF}
  end;

  if FNavigation.AllowRTFClipboard then
    CopyRTFFunc(gd.Left,gd.Top);

  if FNavigation.AllowFmtClipboard then
    CopyBinFunc(gd);

  ExportNotification(esExportDone, -1);
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 := GetSaveStartCol;
      gd.Bottom := GetSaveEndRow;
      gd.Right := GetSaveEndCol;
      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;
{$IFDEF TMSDOTNET}
begin
end;
{$ENDIF}
{$IFNDEF TMSDOTNET}
var
  Data: THandle;
  DataPtr: Pointer;
  CF_HTML: word;
  s: string;

begin
  s := SaveToHTMLString('');
  MakeFragment(s);

  CF_HTML := RegisterClipboardFormat('HTML Format');

  Data := GlobalAlloc(GMEM_MOVEABLE, Length(s));
  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(s[1], DataPtr^, Length(s));

      Clipboard.Open;
      try
        ClipBoard.SetAsHandle(CF_HTML, Data);
        ClipBoard.AsText := s;
      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;
{$ENDIF}

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: Integer;
  gd: TGridRect;
begin
  gd.Top := GetSaveStartRow;
  gd.Left := GetSaveStartCol;
  gd.Bottom := GetSaveEndRow;
  gd.Right := GetSaveEndCol;
  CopyFunc(gd,False);

  for s := gd.Top to gd.Bottom  do
    for z := gd.Left to gd.Right do
      if (IsEditable(RemapCol(z),s) or (Navigation.AllowClipboardAlways)) then
        Cells[s,z] := '';
  FClipLastOp := coCut;
end;

procedure TAdvStringGrid.CutSelectionToClipboard;
var
  s,z,rc,zr: Integer;
begin
  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 ClearRows(z,1);
    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 Assigned(UndoRedo) then
          UndoRedo.StopSequence;

        if Navigation.AllowFmtClipboard then
          ClearPropRect(Left,Top,Right,Bottom);
      end;
  end;

  FClipLastOp := coCut;

  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: Integer;
  s1,s2: string;
  dt1,dt2,dtv: TDateTime;
  f1,f2,fv: Double;
  i1,i2,iv,err1,err2: Integer;
  da1,da2,mo1,mo2,ye1,ye2,dmo,dye,dda: Word;
  Allow: Boolean;
  pc: string;
  selsize: Integer;
  cstate: boolean;

begin
  ImportNotification(isImportStart,-1);

  FPasteAll := false;

  CorrectSelection;

  if (goRowSelect in Options) then
    i := PasteFunc(FixedCols,Selection.Top)
  else
    i := PasteFunc(Selection.Left,Selection.Top);

  if not FNavigation.AllowSmartClipboard then
    Exit;

  selsize := (Selection.Bottom - Selection.Top + 1) * (Selection.Right - Selection.Left + 1);

  // selection size is equal to copy size -> no smart clipboard
  if (selsize = i - 1) 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
      for k := Selection.Top to Selection.Bottom do
        if IsEditable(RemapCol(j),k) or Navigation.AllowClipboardAlways then
        begin
          Allow := true;
          pc := Cells[RemapCol(Selection.Left),Selection.Top];

          if HasCheckBox(Selection.Left,Selection.Top) then
          begin
            GetCheckBoxState(Selection.Left,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);
        end;
  end;

  PasteDone;

  if (i > 1) and
     ((Selection.Left = Selection.Right) or
      (Selection.Top = Selection.Bottom)) then
  begin
    s1 := Cells[Selection.Left,Selection.Top];
    if (Selection.Left = Selection.Right) then
      s2 := Cells[Selection.Left,Selection.Top + 1];
    if (Selection.Top = Selection.Bottom) then
      s2 := Cells[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);
            end;
            dt1 := GetNextDate(dt1,dye,dmo,dda,dtv);
          end;
        end;
        except
        end;
        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
                PasteInCell(j,k,pc);
            end;
            f1 := f1 + fv;
          end;
        end;
      except
      end;
      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
              PasteInCell(j,k,pc);
          end;
          i1 := i1 + iv;
        end;
      end;
      Exit;
    end;

    // normal text repeat

    if Selection.Left = Selection.Right then
      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
            PasteInCell(Selection.Left,k, pc);
        end;
      end;

    if Selection.Top = Selection.Bottom then
      for k := Selection.Left + i to Selection.Right do
      begin
        if IsEditable(RemapCol(k),Selection.Top) then
        begin
          Allow := true;
          pc := Cells[k - i,Selection.Top];

          if Assigned(OnClipboardBeforePasteCell) and
             not (k = Selection.Left)  then
            OnClipboardBeforePasteCell(Self,k,Selection.Top,pc,Allow);

          if Allow then
            PasteInCell(k,Selection.Top,pc);
        end;
      end;

  end;
  ImportNotification(isImportDone,-1);
  CellsLoaded;
end;

procedure TAdvStringGrid.PasteFromClipboard;
begin
  ImportNotification(isImportStart,-1);
  FPasteAll := true;
  PasteFunc(SaveStartCol,SaveStartRow);
  ImportNotification(isImportDone,-1);
  CellsLoaded;
end;


{$IFNDEF TMSDOTNET}
function TAdvStringGrid.PasteSize(p:PChar):TPoint;
{$ENDIF}
{$IFDEF TMSDOTNET}
function TAdvStringGrid.PasteSize(p:string):TPoint;
{$ENDIF}
var
  {$IFNDEF TMSDOTNET}
  Content,endofRow,cr:PChar;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Content, endofRow, cr : integer;
  {$ENDIF}
  Rows,Cols,c: Integer;
  tabpos: Integer;
  line: string;


begin
  {$IFNDEF TMSDOTNET}
  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;
 {$ENDIF}


  {$IFDEF TMSDOTNET}
  //Content := p;
  Content := 0;

  EndOfRow := Pos(#0,p);
  //EndOfRow := StrScan(Content,#0);

  Rows := 0;
  Cols := 0;

  repeat
    //cr := StrScan(Content,#13);
    cr := Pos(#13,p);
    if (cr <= 0) then
    //if cr = nil then
      cr := EndofRow;

    if cr = 1 then
      dec(Rows);

    //Line := Copy(strpas(Content),1,cr - Content);
    Line := Copy(p,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 (p[Content] = #10) then
    //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;
 {$ENDIF}

end;


procedure TAdvStringGrid.PasteInCell(ACol,ARow: Integer; Value: string);
var
  rc: Integer;
begin
  rc := RemapCol(ACol);

  if Assigned(UndoRedo) then
  begin
    UndoRedo.RegisterChange(ACol,ARow,Cells[rc,ARow],Value);
  end;

  if HasCheckBox(ACol,ARow) then
    SetCheckBoxState(ACol,ARow, Value = CheckTrue)
  else
    Cells[rc,ARow] := Value;

  // take hidden cells into account
  if rc <> ACol then
    RepaintCell(ACol,ARow);
end;

{$IFNDEF TMSDOTNET}
function TAdvStringGrid.PasteText(ACol,ARow: Integer;p:PChar): Integer;
{$ENDIF}
{$IFDEF TMSDOTNET}
function TAdvStringGrid.PasteText(ACol,ARow: Integer;p:string): Integer;
{$ENDIF}
var
  {$IFNDEF TMSDOTNET}
  Content,endofRow: PChar;
  cr: PChar;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Content,endofRow: integer;
  cr: integer;
  {$ENDIF}

  ct,line:string;
  s,z,tabpos: Integer;
  numcells: Integer;
  gr:TGridRect;
  Allow: Boolean;
  ws: widestring;
  ll: Integer;

begin
  Result := 0;

  if (ACol < 0) or (ARow < 0) then
    Exit;

  if not ((goEditing in Options) or
    (Navigation.AllowClipboardAlways) or (MouseActions.RangeSelectAndEdit)) then
     Exit;

  z := ARow;
  s := ACol;

  {$IFNDEF TMSDOTNET}
  Content := p;
  EndOfRow := StrScan(Content,#0);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  Content := 0;
  EndOfRow := Length(p);
  {$ENDIF}

  NumCells := 0;
  gr.Top := ARow;
  gr.Left := ACol;
  gr.Right := ACol;
  gr.Bottom := ARow;

  if Assigned(UndoRedo) then
    UndoRedo.StartSequence;

  repeat
    {$IFNDEF TMSDOTNET}
    cr := StrScan(Content,#13);
    if cr = nil then
      cr := EndOfRow;
    Line := Copy(StrPas(Content),1,cr - Content);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    cr := Pos(#13,p);
    if (cr <= 0) then
      cr := EndOfRow;
    Line := Copy(p,1,cr);
    {$ENDIF}

    if FPasteAll then
      ImportNotification(isImportNewRow,z)
    else
      ImportNotification(isImportSelRow,z);
      
    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
        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
            PasteInCell(s,z,ct);
          end;
        end;

      Inc(NumCells);
      Delete(line,1,tabpos);
      inc(s);
      if (s > ColCount) and Navigation.AllowClipboardColGrow then
        ColCount := s;
      if s > gr.Right then
        gr.Right := s;
    end;

    if (s <= ColCount) and (z <= RowCount) then
    begin
      if (IsEditable(RemapCol(s),z) or Navigation.AllowClipboardAlways) then
      begin
        if (cr <> EndOfRow) or (Line <> '') then
        begin
          Allow := 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
            PasteInCell(s,z,Line);
          end;
        end;
      end;
    end;

    Inc(NumCells);
    Inc(s);

    if (s > ColCount) and Navigation.AllowClipboardColGrow then
      ColCount := s;
    if s > gr.Right then
      gr.Right := s;

    Content := cr + 1;

    {$IFNDEF TMSDOTNET}
    if Content^ = #10 then
    begin
      Content := cr + 2;
    end;
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    if (length(p) > 0) and (p[1] = #10) then
      Delete(p, 1, 1);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    Delete(p,1, Content);
    {$ENDIF}

    s := ACol;

    {$IFNDEF TMSDOTNET}
    if (Content^ <> #0) then
      Inc(z);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    if (length(p) > 0) and (p[1] <> #0) then
      Inc(z);
    {$ENDIF}

    if FloatingFooter.Visible and (FloatingFooter.FooterStyle = fsFixedLastRow) then
      ll := RowCount - 1
    else
      ll := RowCount;

    if (z = ll) and
       {$IFNDEF TMSDOTNET}
       (cr <> EndOfRow) and (Content^ <> #0) and
       {$ENDIF}

       {$IFDEF TMSDOTNET}
       (cr <> EndOfRow) and (p <> '') and
       {$ENDIF}
       Navigation.AllowClipboardRowGRow then
       begin
         RowCount := RowCount + 1;
       end;

    if z > gr.Bottom then
      gr.Bottom := z;

  until cr = EndOfRow;

  if Assigned(UndoRedo) then
    UndoRedo.StopSequence;

  gr.Bottom := gr.Bottom - 1;
  gr.Right := gr.Right - 1;

  PasteNotify(FClipTopLeft,gr,FClipLastOp);

  gr.Left := RemapCol(gr.Left);
  gr.Right := RemapCol(gr.Right);

  CellsChanged(TRect(gr));

  Result := NumCells;
end;

procedure TAdvStringGrid.PasteNotify(orig:TPoint;gr:TGridRect;lastop:TClipOperation);
begin
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): Integer;
var
  {$IFNDEF TMSDOTNET}
  {$IFDEF DELPHI_UNICODE}
  ContentStr: string;
  {$ENDIF}
  Content: PChar;
  DataPtr: Pointer;
  s: string;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Content : string;
  DataPtr : IntPtr;
  {$ENDIF}
  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
          {$IFNDEF TMSDOTNET}
          MemStream.WriteBuffer(DataPtr^, GlobalSize(Data));
          {$ENDIF}
          MemStream.Position := 0;

          if Navigation.AllowClipboardRowGrow or
             Navigation.AllowClipboardColGrow 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;

            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);
      {$IFNDEF TMSDOTNET}
      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);
      {$ENDIF}
      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 TMSDOTNET}
    Content := Clipboard.AsText;
    if Content <> '' then
      Result := PasteText(ACol,ARow,Content);
    {$ENDIF}

    {$IFNDEF TMSDOTNET}

    {$IFDEF DELPHI_UNICODE}
    ContentStr := Clipboard.AsText;
    if ContentStr <> '' then
      Result := PasteText(ACol,ARow,PChar(ContentStr));
    {$ENDIF}

    {$IFNDEF DELPHI_UNICODE}
    if Data <> 0 then
      Content := PChar(GlobalLock(Data))
    else
      Content := nil;
    if Content <> nil then
      Result := PasteText(ACol,ARow,Content);
    {$ENDIF}
    {$ENDIF}

  finally
    if Data <> 0 then
      GlobalUnlock(Data);

    ClipBoard.Close;
    Clipboard.Free;
  end;
end;

function TAdvStringGrid.GetXLSSheets(FileName: string): TStringList;
{$IFNDEF TMSDOTNET}
var
  FExcel: variant;
  FWorkBook: variant;
  FWorkSheets: variant;
  FWorkSheet: variant;
  i: Integer;
  OldCursor : TCursor;
{$ENDIF}

begin
  {$IFNDEF TMSDOTNET}
  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;

  finally
    FExcel.Quit;
    FExcel := UnAssigned;
    Screen.Cursor := OldCursor;
  end;
  {$ENDIF}
end;


procedure TAdvStringGrid.LoadFromXLS(filename:string);
begin
  LoadXLS(filename,'');
end;

procedure TAdvStringGrid.LoadFromXLSSheet(filename,sheetname:string);
begin
  LoadXLS(filename,sheetname);
end;

{$IFNDEF  DELPHI6_LVL}
function VarIsClear(const v: variant): boolean;
begin
  Result := VarIsNull(v);
end;
{$ENDIF}

procedure TAdvStringGrid.LoadXLS(Filename,sheetname:string);
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}
begin
  {$IFNDEF TMSDOTNET}
  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;

    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;

    if Pos(':',rangestr) > 0 then
    begin
      startstr := Copy(rangestr,1,pos(':',rangestr)-1);
      endstr := Copy(rangestr,pos(':',rangestr)+1,255);

      if pos('$',startstr) = 1 then
        Delete(startstr,1,1);

      if pos('$',endstr) = 1 then
        Delete(endstr,1,1);

      ulc := not (Pos('$',startstr) > 0);

      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
      sc := 1;
      sr := 1;
      ec := 1;
      er := 1;
    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 (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);

    FArray := FWorkSheet.Range[RangeStr].Value;

    if FSaveFixedCells then
    begin
      strtCol := 0;
      strtRow := 0;
    end
    else
    begin
      StrtCol := FOldFixedCols;
      StrtRow := FOldFixedRows;
      ColCount := ColCount + FOldFixedCols;
      RowCount := RowCount + FOldFixedRows;
    end;

    if ColCount > FOldFixedCols then
      FixedCols := FOldFixedCols;
    if RowCount  >FOldFixedRows then
      FixedRows := FOldFixedRows;

    for s := 1 to RowCount - StrtRow do
    begin
      for z := 1 to ColCount - StrtCol do
      begin
        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);
      end;
    end;

    FWorkBook.Close(SaveChanges:=False);

  finally
    FExcel.Quit;
    FExcel := UnAssigned;
    Screen.Cursor := OldCursor;
    CellsChanged(Rect(0,0,ColCount,RowCount));
    CellsLoaded;
  end;
  {$ENDIF}
end;

procedure TAdvStringGrid.LoadFromMDBTable(Filename, Table: string);
begin
  LoadFromMDBSQL(Filename,'SELECT * FROM ' + Table);
end;

procedure TAdvStringGrid.LoadFromMDBSQL(Filename, SQL: string);
{$IFNDEF TMSDOTNET}
var
  ObjConnC, ObjRSC: variant;
  DSN: string;
  i,j,k: Integer;
{$ENDIF}
begin
  {$IFNDEF TMSDOTNET}
  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;
  {$ENDIF}
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);
begin
  inherited;
  if M <> D then 
  begin
    FixedFont.Size      := MulDiv(FixedFont.Size, M, D);
    ActiveCellFont.Size := MulDiv(ActiveCellFont.Size, M, D);
  end;
end;

procedure TAdvStringGrid.SaveToDOCInt(filename, bookmark:string; CreateNewDocument, Append: boolean);
{$IFNDEF TMSDOTNET}
var
  fword: Variant;
  fdoc: Variant;
  ftable: Variant;
  frng: Variant;
  fcell: Variant;
  s,z: Integer;
  OldCursor: TCursor;
  FActive: Boolean;
{$ENDIF}
begin
  {$IFNDEF TMSDOTNET}
  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);

    for s := 1 to RowCount do
      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;


    FDoc.SaveAs(FileName);
  finally
    if not FActive then
      FWord.Quit;
      
    FWord := Unassigned;
    Screen.Cursor := OldCursor;
  end;
  {$ENDIF}
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);
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}
begin
  {$IFNDEF TMSDOTNET}
  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;

  if FSaveFixedCells then
  begin
    StrtCol := 0;
    StrtRow := 0;
  end
  else
  begin
    StrtCol := FixedCols;
    StrtRow := FixedRows;
  end;

  FArray := VarArrayCreate([0,RowCount - 1 - StrtRow,0, ColCount - 1 - StrtCol],VarVariant);

  ExportNotification(esExportStart,-1);

  for s := StrtRow to RowCount - 1 do
  begin

    ExportNotification(esExportNewRow,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;
  {$ENDIF}
end;

procedure TAdvStringGrid.OutputToCSV(FileName:String;appendmode: Boolean; Unicode: boolean);
var
  //f: TextFile;
  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;

  (*
  AssignFile(f,FileName);

  if AppendMode then
  begin
    {$i-}
    Reset(f);
    {$i+}
    if IOResult <> 0 then
    begin
      {$i-}
      Rewrite(f);
      {$i+}
      if IOResult <> 0 then raise EAdvGridError.Create('Cannot Create file '+FileName);
    end
    else
      Append(f);
  end
  else
  begin
    {$i-}
    Rewrite(f);
    {$i+}
    if IOResult<>0 then raise EAdvGridError.Create('Cannot Create file '+FileName);
  end;
  *)

  sl := TFileStringList.Create;
  if AppendMode then
    sl.LoadFromFile(FileName);


  ExportNotification(esExportStart, -1);

  for z := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNewRow, 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,FMultiLineCells) > 1) then
      begin
        if JavaCSV then
          LinefeedstoJava(CellText)
        else
        begin
          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, TEncoding.Unicode)
  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
  buffer,celltext: string;
  s,z: Integer;
  //f: TextFile;
  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;

begin
  StrtCol := FixedCols;
  StrtRow := FixedRows;

  if FSaveFixedCells then
  begin
    StrtCol := 0;
    StrtRow := 0;
  end;

  (*
  AssignFile(f, FileName);
  {$i-}
  Reset(f);
  {$i+}

  if (IOResult<>0) then
    raise EAdvGridError.Create('Cannot open file ' + FileName);
  *)

  sl := TFileStringList.Create;
  sl.LoadFromFile(FileName);

  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
      if Buffer[1] = '"' 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);
        CellText := DoubleToSingleChar('"',CellText);
      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;

    if Length(Buffer) > 0 then
    begin
      if Buffer[1] = '"' then
        Delete(buffer,1,1);
      if Length(Buffer) > 0 then
      begin
        if Buffer[Length(Buffer)] = '"' then
          Delete(Buffer,Length(Buffer),1);
      end;

      CellText := DoubleToSingleChar('"',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);
      nprogr := Round(LinePos / LineCount * 100);
      if nprogr <> oprogr then
        FOnFileProgress(Self,nprogr);
      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.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);
  {$IFNDEF TMSDOTNET}
  var
    buf:PChar;
    c: array[0..1] of char;
    l,len: integer;

  {$ENDIF}
  {$IFDEF TMSDOTNET}
  var
    sb: TBytes;
  {$ENDIF}
  begin
  {$IFNDEF TMSDOTNET}

    {$IFDEF DELPHI_UNICODE}
    l := length(s) * 2;
    len := l + 2;
    {$ENDIF}
    {$IFNDEF DELPHI_UNICODE}
    l := length(s);
    len := l + 1;
    {$ENDIF}

    GetMem(buf,len);

    Move(s[1],buf^,l);
    //StrPLCopy(buf,s,l);

    Stream.Writebuffer(buf^,l);

    c[0] := #13;
    c[1] := #10;

    {$IFDEF DELPHI_UNICODE}
    Stream.Writebuffer(c,4);
    {$ENDIF}
    {$IFNDEF DELPHI_UNICODE}
    Stream.Writebuffer(c,2);
    {$ENDIF}

    FreeMem(buf);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
    s := s + #13#10;
    sb := BytesOf(s);
    Stream.WriteBuffer(sb, Length(sb));
  {$ENDIF}
  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, -1);

  //save cell contents
  for i := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNewRow, 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, -1);

  for r := SaveStartRow to SaveEndRow do
  begin
    ExportNotification(esExportNewRow, 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;

{$IFNDEF TMSDOTNET}
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;
{$ENDIF}


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;

  {$IFNDEF TMSDOTNET}
  positions.Sort(@compareInts);
  {$ENDIF}

  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,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
      {$IFDEF DELPHI_UNICODE}
      Stream.Read(c,2);
      {$ENDIF}
      {$IFNDEF DELPHI_UNICODE}
      Stream.Read(c,1);
      {$ENDIF}
      if (c <> #13) then s := s + c;
    end;

    //Stream.Read(c,1); {read the #10 newline marker}
    {$IFDEF DELPHI_UNICODE}
    Stream.Read(c,2);
    {$ENDIF}
    {$IFNDEF DELPHI_UNICODE}
    Stream.Read(c,1);
    {$ENDIF}

    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(OnGroupCalc) then
    OnGroupCalc(Self, ACol, FromRow, ToRow, Result);
end;

function TAdvStringGrid.ColumnSum(ACol,FromRow,ToRow: Integer):Double;
var
  i,di: Integer;
  sum: Double;
  doh: Boolean;
  cnt: boolean;
begin
  sum := 0;

  if FloatingFooter.Visible then
    doh := ToRow > RowCount - 1
  else
    doh := ToRow > RowCount;

  ExportNotification(esExportStart, -1);

  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));

    if cnt and IsBaseCell(ACol, di) then
    begin
      ExportNotification(esExportNewRow, i);
      try
        if doh then
          Sum := Sum + AllFloats[ACol,i]
        else
          Sum := Sum + Floats[ACol,i];
      except
      end;
    end;
  end;

  ExportNotification(esExportDone, -1);
  Result := sum;
end;

function TAdvStringGrid.ColumnAvg(ACol,FromRow,ToRow: Integer):Double;
begin
  if (ToRow - FromRow + 1) > 0 then
    Result := ColumnSum(ACol,FromRow,ToRow)/(ToRow - FromRow + 1)
  else
    Result := 0;
end;

function TAdvStringGrid.ColumnMin(ACol,fromRow,toRow: Integer):Double;
var
  m: Double;
  i,di: Integer;
  doh: Boolean;
  cnt: boolean;
begin
  if FloatingFooter.Visible then
    doh := ToRow > RowCount - 1
  else
    doh := ToRow > RowCount;

  m := Floats[ACol,fromRow];

  ExportNotification(esExportStart, -1);

  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));

    if cnt and IsBaseCell(ACol, di) then
    begin
      ExportNotification(esExportNewRow, 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;
  
  ExportNotification(esExportDone, -1);  
  Result := m;
end;

function TAdvStringGrid.ColumnMax(ACol,FromRow,ToRow: Integer):Double;
var
  m: Double;
  i,di: Integer;
  doh: Boolean;
  cnt: Boolean;
begin
  if FloatingFooter.Visible then
    doh := ToRow > RowCount - 1
  else
    doh := ToRow > RowCount;


  ExportNotification(esExportStart, -1);
  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));

    if cnt and IsBaseCell(ACol, di) then
    begin
      ExportNotification(esExportNewRow, 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;
  ExportNotification(esExportDone, -1);
  Result := m;
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.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 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
           ct := Cells[s,z];
           if Pos('{\',ct) > 0 then
           begin
             CellToRich(s,z,FRichEdit);
             ct := FRichEdit.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
      ct := Cells[s,z];
      if Pos('{\',ct) > 0 then
      begin
        CellToRich(s,z,FRichEdit);
        ct := FRichEdit.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.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;

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: 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;

      for j := y to RowCount - 1 do
      begin
        oh := RowHeights[j];

        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;
            end;
          end;
        end;
      end;
    end;

  finally
    EndUpdate;
  end;
end;

procedure TAdvStringGrid.AutoSizeColumns(const DoFixedCols: Boolean; const Padding: Integer = 4);
var
  i,j: Integer;
begin
  if DoFixedCols then
    j := 0
  else
    j := FixedCols;

  for i := j to ColCount - 1 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;
begin
  MaxWidth := 0;

  RCol := RemapCol(ACol);

  for i := 0 to RowCount - 1 do
  begin
    if not IsXMergedCell(ACol,i) then
    begin
      if (ACol < FixedCols) or (i < FixedRows) then
        Canvas.Font.Assign(FixedFont)
      else
        Canvas.Font.Assign(Font);

      GetCellColor(RCol,i,[],Canvas.Brush,Canvas.Font);

      Canvas.Font.Size := Canvas.Font.Size + FZoomFactor;

      TextW := GetCellTextSize(RCol,i,False).cx + CellGraphicSize[RCol,i].x;

      if (ControlLook.DropDownAlwaysVisible) then
      begin
        if HasCombo(ACol,i) then
          TextW := TextW + 16;
      end;

      cg := GetCellGraphic(RCol,i);

      if Assigned(cg) then
        if cg.FCellHAlign = haFull then
          TextW := CellGraphicSize[ACol,i].x - (XYOffset.X + 2 * (GridLineWidth + 1)) ;

      if TextW > MaxWidth then
        MaxWidth := TextW;
    end;
  end;

  // Allow 2 pixel spacing at begin & end
  NewW := MaxWidth + XYOffset.X + 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);
var
  cg: TCellGraphic;
  MaxHeight, TextH, NewH, i: 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(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);

      Canvas.Font.Size := Canvas.Font.Size + FZoomFactor;

      ts := GetCellTextSize(RemapCol(i),ARow,WordWrap).cy;

      gs := CellGraphicSize[i,ARow].y;

      cg := GetCellGraphic(i,ARow);

      if Assigned(cg) then
      begin
        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] then
          TextH := DefaultRowHeight;
      end;

      if TextH > MaxHeight then
        MaxHeight := TextH;
    end;
  end;

  // Allow 2 pixel spacing at begin & end
  NewH := MaxHeight + XYOffset.Y + 2 * (GridLineWidth);


  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.AutoSizeCol(const ACol: Integer);
begin
  SizetoWidth(ACol,SizeGrowOnly);
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, -1);

  for i := j to RowCount - 1 do
  begin
    ExportNotification(esExportNewRow, 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;

  ExportNotification(esExportDone, -1);
end;

procedure TAdvStringGrid.SizeToLines(const ARow,Lines,padding: Integer);
var
  th: Integer;
begin
  GetCellColor(FixedCols,ARow,[],Canvas.Brush,Canvas.Font);
  th := Canvas.TextHeight('gh');
  RowHeights[ARow] := CheckLimits(Padding+((th + (th shr 3)) * Lines),MinRowHeight,MaxRowHeight);
end;

procedure TAdvStringGrid.AutoSizeRow(const ARow: Integer);
begin
  SizetoHeight(ARow,SizeGrowOnly);
end;

procedure TAdvStringGrid.AutoFitColumns;
var
  ratio: real;
  CurrW: integer;
  ScrlW: integer;
  ColW: integer;
  BrdrW: integer;
  LineW: integer;
  UseW,RemW,ShareW: integer;
  i, Largest: 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;

  LineW := 0;
  if (goVertLine in Options) then
    LineW := LineW + ((ColCount - (FixedCols + FixedRightCols)) * GridLineWidth);

  if (goFixedVertLine in Options) then
    LineW := LineW + FixedCols + FixedRightCols;


  if ColCount > 1 then
  begin
    ColW := 0;
    for i := 0 to ColCount - 1 do
      ColW := ColW + ColWidths[i];

    UseW := Width - (ScrlW + BrdrW + LineW);
    ratio := UseW / ColW;

    CurrW := 0;
    if ColCount > 2 then
    begin
      for i := 0 to ColCount - 1 do
        CurrW := CurrW + Round(ColWidths[i] * ratio);

      ratio := CurrW / ColW;
      for i := 0 to ColCount - 1 do
        ColWidths[i] := Round(ColWidths[i] * ratio);
    end
    else
    begin
      for i := 0 to ColCount - 1 do
        CurrW := CurrW + Round(ColWidths[i] * ratio);

      ratio := CurrW / ColW;

      for i := 0 to ColCount - 1 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 := 0 to ColCount - 1 do
    ColW := ColW + ColWidths[i];

  RemW := Width - (ColW + ScrlW + BrdrW);

  if RemW > ColCount then
  begin
    ShareW := RemW div ColCount;
    RemW := RemW - (ShareW * ColCount);
    for i := 0 to ColCount - 1 do
    begin
      ColWidths[i] := ColWidths[i] + ShareW;
    end;
  end;

  // find the biggest column and dump the remainder into that
  Largest := 0;
  for i := 1 to ColCount - 1 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];
  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 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.FDisjunctRowSelect 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;
  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;

  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;
  
  ExportNotification(esExportDone,-1);
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;

begin
  ExportNotification(esExportStart,-1);
  FPrintRect := Gridrect;
  with Printer do
  begin
    if not FPrintSettings.UseDefaultOrientation then
      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
    Title := FPrintSettings.JobName;
//    BeginDoc;
//    if not FFastPrint then
//      i := BuildPages(Canvas,prCalcPrint,-1,SelRows)
//    else i := 1;

    // do not use printer canvas for calc

    BeginDoc;
    mm := GetMapMode(Canvas.Handle);

    if not FFastPrint then
    begin
      //BeginDoc;
      SetMapMode(Canvas.Handle,mm_lometric);
      pages := BuildPages(Canvas,prCalcPrint,-1,SelRows);
      //Abort;
    end
    else
      pages := MaxInt;

    FPrintPageFrom := 1;
    FPrintPageTo := pages;
    FPrintPageNum := pages;

    if Assigned(FOnPrintStart) then
    begin
      Abort;
      
      FOnPrintStart(Self,pages,FPrintPageFrom,FPrintPageTo);

      if (FPrintPageFrom = 0) or (FPrintPageTo = 0) or (FPrintPageTo < FPrintPageFrom) then
        Exit;

      BeginDoc;
    end;

    FPrintPageNum := FPrintPageTo;

    // do not use printer canvas for calc
//    Title := FPrintSettings.JobName;
//    BeginDoc;
//    mm := GetMapMode(Canvas.Handle);
//    SetMapMode(Canvas.Handle,mm_lometric);
    BuildPages(Canvas,prPrint,pages,SelRows);

    SetMapMode(Canvas.Handle,mm);
    EndDoc;
  end;
  ExportNotification(esExportDone,-1);
end;
(*
procedure TAdvStringGrid.PrivatePreviewRect(Preview: TPrintPreview; Gridrect:TGridRect;SelRows: Boolean);
var
  i: Integer;
  mm: Integer;

begin

  FPrintPreview := Preview;

  FPrintRect := Gridrect;
  with Preview do
  begin
    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));

    PrevRect.Right := PaperWidth;
    PrevRect.Bottom := PaperHeight;


    if not FFastPrint then
      i := BuildPages(Self.Canvas,prCalcPrint,-1,SelRows)
    else i := 1;

    FPrintPageFrom := 1;
    FPrintPageTo := i;
    FPrintPageNum := i;

    if Assigned(FOnPrintStart) then
    begin
      FOnPrintStart(Self,i,FPrintPageFrom,FPrintPageTo);

      if (FPrintPageFrom = 0) or (FPrintPageTo = 0) or
        (FPrintPageTo < FPrintPageFrom) then Exit;
    end;

    FPrintPageNum := FPrintPageTo;

//    Title := FPrintSettings.JobName;
    BeginDoc;
    mm := GetMapMode(Canvas.Handle);
    SetMapMode(Canvas.Handle,mm_lometric);

    BuildPages(Canvas,prPrint,i,SelRows);

    SetMapMode(Canvas.Handle,mm);
    EndDoc;
  end;

  FPrintPreview := nil;
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.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;AAngle: Integer;ATxt:String;hal: TAlignment; val:TVAlignment);
var
  hSaveFont: HFont;
  Size: TSize;
  y1,y2: Integer;
  x1,x2: Integer;

begin
  hSaveFont := SelectObject(Canvas.Handle,Canvas.Font.Handle);
  {$IFNDEF TMSDOTNET}
  GetTextExtentPoint32(Canvas.Handle,PChar(aTxt + 'w'),Length(aTxt),Size);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  GetTextExtentPoint32(Canvas.Handle,aTxt + 'w',Length(aTxt),Size);
  {$ENDIF}
  SelectObject(Canvas.Handle,hSaveFont);
  InflateRect(ARect,-2,-2);

  x1 := Abs(Trunc(Size.cx * cos(AAngle*Pi/180)));
  x2 := Abs(Trunc(Size.cy * sin(AAngle*Pi/180)));

  y1 := Abs(Trunc(Size.cx * sin(AAngle*Pi/180)));
  y2 := Abs(Trunc(Size.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 - FNumHidden 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);
{$IFNDEF TMSDOTNET}
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;
{$ENDIF}
{$IFDEF TMSDOTNET}
var
  BitmapHeader:  TBitmapInfo;
  HeaderSize  :  DWORD;
  ImageSize   :  DWORD;
  Bits: HBITMAP;
  Image: TBytes;
  Info: IntPtr;

begin
  Bits := Bitmap.Handle;

  GetDIBSizes(Bits, HeaderSize, ImageSize);

  Info := Marshal.AllocHGlobal(HeaderSize);

  try
    SetLength(Image, ImageSize);
    GetDIB(Bits, 0, Info, Image);

    BitmapHeader := TBitmapInfo(Marshal.PtrToStructure(Info, TypeOf(TBitmapInfo)));

    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
                  Image,
                  Info,
                  DIB_RGB_COLORS,
                  SRCCOPY)
  finally
    Marshal.FreeHGlobal(Info);
  end;
{$ENDIF}
end;

procedure PrintBitmapRop(Canvas:  TCanvas; DesTRect:  TRect;  Bitmap:  TBitmap; rop:dword);
{$IFNDEF TMSDOTNET}
var
  BitmapHeader: PBitmapInfo;
  BitmapImage: Pointer;
  HeaderSize,ImageSize: DWord;
{$ENDIF}

begin
{$IFNDEF TMSDOTNET}
  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;
{$ENDIF}
end;

//-----------------------------------------
// Routine to build the page on the Canvas
//-----------------------------------------
function TAdvStringGrid.BuildPages(Canvas: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: Boolean;
  forcednewpage: Boolean;
  Allowfittopage: Boolean;
  scalefactor: Double;
  angle: Integer;
  ResFactor,HTMLFactor: Double;
  prevendCol: Integer;
  LFont: TLogFont;
  hOldFont,hNewFont: HFont;
  bmp: TBitmap;
  pic: TPicture;
  iconinfo: TIconinfo;
  hdc: THandle;
  cache_Row,cache_Height: Integer;
  Cancelled: Boolean;
  {$IFDEF TMSUNICODE}
  sz: TSize;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  ap: array of TPoint;
  {$ENDIF}
  es: TGridExportState;
  GD: TCellGradientDirection;

  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 (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}
    {$IFDEF TMSDOTNET}
    respt: TPoint;
    ap: array of TPoint;
    {$ENDIF}
  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,FRichEdit);
        s := FRichEdit.Text;
      end;
    {$IFDEF TMSUNICODE}
    ttUnicode:
      begin
        FillChar(r,SizeOf(r),0);

        if PrintSettings.NoAutoSize then
          r.Right := Round((ColWidths[Col] + 12) * resfactor)
        else
          r.Right := $FFFF;

        r.Bottom := $FFFF;

        ws := WideCells[col,row];

        if WordWrap then
        begin
          sz.cy := -DrawTextExW(Canvas.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(Canvas.Handle,PWideChar(ws),Length(ws),sz);

        s := ws;
        Result.cx := sz.cx;
        Result.cy := sz.cy;
        Exit;
      end;
    {$ENDIF}
    ttHTML:
      begin
        OldFont.Assign(Canvas.Font);
        NewFont.Assign(Canvas.Font);
        NewFont.Size := orgsize;

        {$IFNDEF TMSDOTNET}
        FillChar(r,SizeOf(r),0);
        {$ENDIF}

        if PrintSettings.NoAutoSize then
          r.Right := (ColWidths[Col] + 12)
        else
          r.Right := $FFFF;

        r.Bottom := $FFFF;

        Oldsize := Canvas.Font.Size;
        SetMapMode(Canvas.Handle,MM_TEXT);
        Canvas.Font.size := Trunc(FPrintSettings.Font.Size * ScaleFactor);

        HTMLDrawEx(Canvas,s,r,GridImages,0,0,-1,0,1,False,True,False,True,True,False,not EnhTextSize,False,
                   HTMLFactor,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);

        // Correct it for the new mapping mode

        SetMapMode(Canvas.Handle,MM_LOMETRIC);
        {$IFNDEF TMSDOTNET}
        dptolp(Canvas.Handle,htmlsize,1);
        {$ENDIF}

        {$IFDEF TMSDOTNET}
        SetLength(ap,1);
        ap[0] := htmlsize;
        dptolp(Canvas.Handle, ap, 1);
        htmlsize := ap[0];
        {$ENDIF}

        Canvas.Font.Size := Oldsize;

        Result.cx :=  htmlsize.x;
        Result.cy := -htmlsize.y;
        Exit;
      end;
    end;

    OldFont.Assign(Canvas.Font);
    NewFont.Assign(Canvas.Font);
    NewFont.Size := orgsize;

    AState := [];

    GetVisualProperties(Col,Row,AState,True,False,False,OldBrush,AColorTo,AMirrorColor,AMirrorColorTo,NewFont,HAlign,VAlign,WW,GD);

    Canvas.Font.Assign(NewFont);
    Canvas.Font.Height := MapFontHeight(NewFont.Size);

    if IsRotated(Col,Row,angle) then
    begin
      {$IFNDEF TMSDOTNET}
      GetObject(Canvas.Font.Handle,SizeOf(LFont),Addr(LFont));
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      GetObject(Canvas.Font.Handle,Marshal.SizeOf(TypeOf(LFont)),LFont);
      {$ENDIF}
      LFont.lfEscapement := -Angle * 10;
      LFont.lfOrientation := -Angle * 10;
      hNewFont := CreateFontIndirect(LFont);
      hOldFont := SelectObject(Canvas.Handle,hNewFont);
    end;

    maxsize := 0;
    numlines := 0;

    if FPrintSettings.PrintGraphics then
    begin
      gt := CellGraphicSize[Col,Row];
      gt.x := Round(gt.x * resfactor);
      gt.y := Round(gt.y * resfactor);
    end
    else gt := point(0,0);

    if s = '' then
      s := 'gh';

    if WordWrap 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[Col];

      r.Bottom := 50;
      DrawStyle := DT_CALCRECT or DT_WORDBREAK or DT_NOPREFIX;
      DrawStyle := DrawTextBiDiModeFlags(DrawStyle);

      {$IFNDEF TMSDOTNET}
      r.Bottom := DrawText(Canvas.Handle,PChar(s),Length(s),r,DrawStyle);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      r.Bottom := DrawText(Canvas.Handle,s,Length(s),r,DrawStyle);
      {$ENDIF}
      Result.cx := r.Right;
      Result.cy := -r.Bottom;
    end
    else
    begin
      repeat
        su := GetNextLine(s,FMultiLineCells);
        if FURLShow and not FURLFull then StripURLProtoCol(su);
        newsize := Canvas.TextWidth(su) + gt.x;
        if (newsize > maxsize) then maxsize := newsize;
        inc(numlines);
      until (s = '');

      Result.cx := maxsize;
      Result.cy := numlines * Canvas.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(Canvas.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;

    Canvas.Font.Assign(oldFont);

    if Assigned(FOnCustomCellSize) then
    begin
      {$IFNDEF TMSDOTNET}
      FOnCustomCellSize(Self,Canvas,Col,Row,TPoint(Result),True);
      {$ENDIF}

      {$IFDEF TMSDOTNET}
      respt.X := Result.cx;
      respt.Y := Result.cy;
      FOnCustomCellSize(Self,Canvas,Col,Row,respt,True);
      Result.cx := respt.X;
      Result.cy := respt.Y;
      {$ENDIF}
    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;
      Exit;
    end;

    if FPrintSettings.UseFixedHeight then
      Result := FPrintSettings.FixedHeight
    else
    begin
      nh := 0;
      for j := FPrintRect.Left to FPrintRect.Right do
      begin
        FontScaleFactor := ScaleFactor;

        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;

      if Assigned(FOnPrintSetRowHeight) then
      begin
        OnPrintSetRowHeight(Self,ARow,Result);
      end;

    end;

    cache_Row := ARow;
    cache_Height := Result;
  end;

  {$IFDEF DELPHI3_LVL}
  function GetPrinterOrientation: Integer;
  {$IFNDEF TMSDOTNET}
  var
    Device : array[0..255] of char;
    Driver : array[0..255] of char;
    Port : array[0..255] of char;
    hDMode : THandle;
  {$ENDIF}
  begin
    // Printer.PrinterIndex := Printer.PrinterIndex; not required ?
    {$IFNDEF TMSDOTNET}
    Printer.GetPrinter(Device, Driver, Port, hDMode);
    Result := winspool.DeviceCapabilities(device,port,DC_ORIENTATION,Nil,Nil);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    Result := 0;
    {$ENDIF}
  end;
 {$ENDIF}

  // Routine to draw header & footer
  function BuildColumnsRow(ypos,Col1,Col2,ARow,hght: Integer): Integer;
  var
    c,k,d,cn,swp,lit: Integer;
    th,thm,tb,yp,cr,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;
    TextPos: TPoint;
    Q: byte;
    cg: TCellGraphic;
    borders: TCellBorders;
    flg, 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;
    ws: widestring;
    {$IFDEF TMSDOTNET}
    ap: array of TPoint;
    {$ENDIF}
  label
    BorderDrawing;

  begin
    FontScaleFactor := ScaleFactor;

    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 := Trunc((RowHeights[i] - 4) * ResFactor);
            di := di + (di shr 3);
            CDIM.Y := CDIM.Y + di + 2 * fntvspace + FPrintSettings.RowSpacing;
          end;
      end
      else
        CDIM.Y := (CSP.Y + 1) * Result; // take vertical cell merging into account

      tr.Left := Indents[c];
      tr.Right := tr.Left + CDIM.X;

      tr.Top := ypos;
      tr.Bottom := ypos - CDIM.Y;

      if not IsBaseCell(cn,ARow) then
      begin
        goto BorderDrawing;
        // Continue;
        // do some extra border drawing here
      end;

      OldBrush.Assign(Canvas.Brush);
      OldFont.Assign(Canvas.Font);
      NewBrush.Assign(Canvas.Brush);
      NewFont.Assign(Canvas.Font); // Copy everything except size, which is mapped into mm_lometric
      NewFont.Size := OrgSize;

      GetVisualProperties(cn,ARow,AState,True,False,False,NewBrush,AColorTo,AMirrorColor,AMirrorColorTo,NewFont,HAlign,VAlign,WW,GD);

      Canvas.Brush.Assign(NewBrush);
      Canvas.Font.Assign(NewFont);
      Canvas.Font.Height := MapFontHeight(NewFont.Size);

      SetTextColor(Canvas.Handle,ColorToRGB(NewFont.Color));

      if HasDataCell(cn,ARow) then
        cs := ''
      else
        cs := GetFormattedCell(cn,ARow);

      ctt := TextType(cs,FEnableHTML);

      if ctt = ttFormula then
        cs := CalcCell(cn,ARow);

      // do background painting
      OldCol := Canvas.Pen.Color;
      Canvas.Pen.Color := Canvas.Brush.Color;
      Canvas.Rectangle(tr.Left,tr.Top,tr.Right,tr.Bottom);
      Canvas.Pen.Color := OldCol;

      AlignValue := GetCellAlignment(cn,ARow).Alignment;

      th := Canvas.TextHeight('gh') + FPrintSettings.RowSpacing;
      th := th + (th shr 3);

      first := 0;
      s := cs;

      repeat
        su := GetNextLine(s,FMultiLineCells);
        tb := Canvas.TextWidth(su);
        if tb > first then
          first := tb;
      until (s = '');

      tb := first;

      s := cs;

      Angle := 0;

      if IsRotated(cn,ARow,angle) then
      begin
        {$IFNDEF TMSDOTNET}
        GetObject(Canvas.Font.Handle,SizeOf(LFont),Addr(LFont));
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        GetObject(Canvas.Font.Handle,Marshal.SizeOf(TypeOf(LFont)),LFont);
        {$ENDIF}
        if (PrintMethod = prPreview) or not PrinterDriverFix
           {$IFDEF DELPHI3_LVL}
           or (GetPrinterOrientation = 270) {$ENDIF} 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(Canvas.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);

        CGS.X := Round(CGS.X * ResFactor);
        CGS.Y := Round(CGS.Y * ResFactor);

        // 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]) 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]) and (s = '') then
        begin
          rg.Left := Indents[c] + ((CDIM.X - CGS.X ) div 2);
          rg.Right := rg.Left + CGS.X;
        end;

      end;

      case ctt of
      ttRTF:
        begin
          Canvas.Brush.style := bsClear;
          RTFPaint(cn,ARow,Canvas,tr);
          Canvas.Brush.style := bsSolid;
        end;
      ttHTML:
        begin
          {$IFDEF TMSDOTNET}
          SetLength(ap,2);
          ap[0] := tr.TopLeft;
          ap[1] := tr.BottomRight;
          lptodp(Canvas.Handle,ap,2);
          tr.TopLeft := ap[0];
          tr.BottomRight := ap[1];
          {$ENDIF}

          {$IFNDEF TMSDOTNET}
          lptodp(Canvas.Handle,tr.Topleft,1);
          lptodp(Canvas.Handle,tr.Bottomright,1);
          {$ENDIF}

          mm := GetMapMode(Canvas.Handle);
          OldSize := Canvas.Font.Size;
          SetMapMode(Canvas.Handle,MM_TEXT);
          Canvas.Font.Size := Trunc(FPrintSettings.Font.Size * ScaleFactor);
          Canvas.Brush.Style := bsClear;

          HTMLDrawEx(Canvas,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,self.Handle);

          SetMapMode(Canvas.Handle,mm);
          Canvas.Font.Size := Oldsize;
          Canvas.Brush.Style := bsSolid;
        end
      {$IFDEF TMSUNICODE}  ;
      ttUnicode:
        begin
          if tr.Right > XSize then
            tr.Right := Indents[EndCol + 1];

          Canvas.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 WordWrap then
            DrawStyle := DrawStyle or DT_WORDBREAK;

          if Win32Platform = VER_PLATFORM_WIN32_NT then
            DrawTextExW(Canvas.Handle,PWideChar(ws),Length(ws), tr, DrawStyle,nil)
          else
            ExtTextOutW(Canvas.Handle,tr.Left,tr.Top,ETO_CLIPPED,@tr,PWideChar(ws),Length(ws),nil);
        end
      {$ENDIF}
      else
        begin
          // wordwrap printing

          if Wordwrap and FPrintSettings.NoAutoSize and not IsRotated(cn,ARow,Angle) then
          begin
            // Make sure the background is fully drawn in background color
            if tr.Right > XSize then
              tr.Right := Indents[EndCol + 1];

            Canvas.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);
            {$IFNDEF TMSDOTNET}
            DrawText(Canvas.Handle,PChar(s),Length(s),tp,DrawStyle);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            DrawText(Canvas.Handle,s,Length(s),tp,DrawStyle);
            {$ENDIF}
          end
          else
          begin
            lit := LinesInText(s,FMultiLineCells);

            if lit = 1 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];

                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
                  Canvas.TextRect(tr,tp.Left,tp.Top,su);
                end
                else
                begin
                  tr.Left := tr.Left + FXYOffset.X;
                  tr.Top := tp.Top + FXYOffset.Y;
                  {$IFNDEF TMSDOTNET}
                  DrawText(Canvas.Handle,PChar(su),Length(su),tr,DrawStyle);
                  {$ENDIF}
                  {$IFDEF TMSDOTNET}
                  DrawText(Canvas.Handle,su,Length(su),tr,DrawStyle);
                  {$ENDIF}
                end;
              end
              else
              begin
                if angle <> 0 then
                begin
                  //tp := tr;
                  Canvas.TextRect(tr,tp.Left,tp.Top,su)
                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;

                  {$IFNDEF TMSDOTNET}
                  DrawText(Canvas.Handle,PChar(su),Length(su),tp,DrawStyle);
                  {$ENDIF}
                  {$IFDEF TMSDOTNET}
                  DrawText(Canvas.Handle,su,Length(su),tp,DrawStyle);
                  {$ENDIF}
                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 - Canvas.TextWidth(su);
                taCenter:tp.Left := tp.Left+( (tp.Right - tp.Left - Canvas.TextWidth(su)) div 2);
                end;

                Canvas.TextRect(tr,tp.Left,tr.Top - First,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;

      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);

            // Canvas.rectangle(rg.Left,rg.Top,rg.Right,rg.Bottom);
            GetCheckBoxState(cn,ARow,checkstate);
            if checkstate then
              DrawFrameControl(Canvas.Handle,rg,DFC_BUTTON, DFS or DFCS_CHECKED)
            else
              DrawFrameControl(Canvas.Handle,rg,DFC_BUTTON, DFS);

          end;
        ctRadio:
          begin
            rg.Bottom := rg.Top + Round(CellGraphicSize[cn,ARow].y * ResFactor);

            (*
            {$IFDEF TMSDOTNET}
            SetLength(ap,2);
            ap[0] := rg.TopLeft;
            ap[1] := rg.BottomRight;
            lptodp(Canvas.Handle,ap,2);
            rg.TopLeft := ap[0];
            rg.BottomRight := ap[1];
            {$ENDIF}

            {$IFNDEF TMSDOTNET}
            lptodp(Canvas.Handle,rg.Topleft,1);
            lptodp(Canvas.Handle,rg.Bottomright,1);
            {$ENDIF}

            mm := GetMapMode(Canvas.Handle);
            SetMapMode(Canvas.Handle,MM_TEXT);
            *)

            {$IFNDEF TMSDOTNET}
            DrawRadio(Canvas, rg, GetRadioStrings(cn,ARow).Count,cg.CellIndex,cg.cellBoolean, false,
                      TStringList(cg.cellbitmap), false, cn, ARow, csClassic, ResFactor, true);
            {$ENDIF}

            {$IFDEF TMSDOTNET}
            DrawRadio(Canvas, rg,GetRadioStrings(cn,ARow).Count,cg.CellIndex,cg.cellBoolean, false,
                      cg.CellStrings, false, cn, ARow, csClassic, ResFactor, true);
            {$ENDIF}

            //SetMapMode(Canvas.Handle,mm);
          end;
        ctButton,ctBitButton:
          begin
            {
            rg.Bottom:=rg.Top+round(CellGraphicSize[c,ARow].y*resfactor);
            DrawFrameControl(Canvas.Handle,rg,DFC_BUTTON,DFCS_BUTTONPUSH);
            }
          end;
        ctBitmap:AsgPrintBitmap(Canvas,rg,cg.CellBitmap);
        ctComment:
          begin

          end;
        ctPicture,ctInterface:
          begin
            bmp := TBitmap.Create;
            {$IFNDEF TMSDOTNET}
            bmp.Width := TPicture(cg.CellBitmap).Graphic.Width;
            bmp.Height := TPicture(cg.CellBitmap).Graphic.Height;
            bmp.Canvas.draw(0,0,TPicture(cg.CellBitmap).Graphic);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            bmp.Width := cg.CellPicture.Graphic.Width;
            bmp.Height := cg.CellPicture.Graphic.Height;
            bmp.Canvas.draw(0,0,cg.CellPicture.Graphic);
            {$ENDIF}
            AsgPrintBitmap(Canvas,rg,bmp);
            bmp.free;
          end;
        ctFilePicture:
          begin
            pic := TPicture.Create;
            {$IFNDEF TMSDOTNET}
            pic.LoadFromFile(TFilePicture(cg.CellBitmap).Filename);
            {$ENDIF}
            {$IFDEF TMSDOTNET}
            pic.LoadFromFile(cg.CellFilePicture.Filename);
            {$ENDIF}
            bmp := TBitmap.Create;
            bmp.Width := pic.Graphic.Width;
            bmp.Height := pic.Graphic.Height;
            bmp.Canvas.Draw(0,0,pic.graphic);
            AsgPrintBitmap(Canvas,rg,bmp);
            bmp.Free;
            pic.Free;
          end;
        ctIcon:
          begin
            GetIconInfo(cg.CellIcon.Handle,IconInfo);
            bmp := TBitmap.Create;
            bmp.Handle := Iconinfo.hbmmask;
            PrintBitmapRop(Canvas,rg,bmp,SRCCOPY);
            bmp.Free;
            GetIconInfo(cg.CellIcon.Handle,IconInfo);
            bmp := TBitmap.Create;
            bmp.Handle := IconInfo.hbmColor;
            PrintBitmapROP(Canvas,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(Canvas,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(Canvas,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 := Canvas.Brush.Color;
                bmp.Canvas.Pen.Color := Canvas.Brush.Color;
                bmp.Canvas.Rectangle(0,0,bmp.Width,bmp.Height);
                {$IFDEF TMSDOTNET}
                FGridImages.Draw(bmp.Canvas,0,0,cg.CellList.Items[d - 1]);
                {$ENDIF}
                {$IFNDEF TMSDOTNET}
                FGridImages.Draw(bmp.Canvas,0,0,TIntList(cg.CellBitmap).Items[d - 1]);
                {$ENDIF}

                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(Canvas,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;

            {$IFNDEF TMSDOTNET}
            with cg do
              if CellBoolean then
                DrawProgressLin(Canvas,rg,TColor(CellBitmap),TColor(CellIndex),
                  TColor(CellIcon),TColor(CellAngle),Ints[c,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor,true)
              else
                DrawProgressLin(Canvas,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);
            {$ENDIF}

            {$IFDEF TMSDOTNET}
            with cg do
            if CellBoolean then
              DrawProgressLin(Canvas,rg,CellColor, CellTextFGColor,
                CellBKColor,CellTextBKColor,Ints[c,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor, true)
            else
              DrawProgressLin(Canvas,rg,CellColor,CellColor xor $FFFFFF,
                CellBKColor,CellBKColor xor $FFFFFF,Ints[c,ARow],ControlLook.ProgressMarginX,ControlLook.ProgressMarginY, CellErrFrom, CellErrLen, CellText, ControlLook.ProgressBorderColor, true);
            {$ENDIF}

            Canvas.Pen.Color := clBlack;
          end;
        ctProgressPie:
          begin
            {$IFNDEF TMSDOTNET}
            DrawProgressPie(Canvas,rg,TColor(cg.CellBitmap),cg.CellAngle, true);
            {$ENDIF}

            {$IFDEF TMSDOTNET}
            DrawProgressPie(Canvas,rg,cg.CellColor,cg.CellAngle, true);
            {$ENDIF}
          end;
        end;

        if IsRotated(cn,ARow,angle) then
        begin
          hNewFont := SelectObject(Canvas.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;

        {$IFDEF TMSDOTNET}
        SetLength(ap,2);
        ap[0] := tr.TopLeft;
        ap[1] := tr.BottomRight;
        lptodp(Canvas.Handle,ap,2);
        tr.TopLeft := ap[0];
        tr.BottomRight := ap[1];
        {$ENDIF}

        {$IFNDEF TMSDOTNET}
        lptodp(Canvas.Handle,tr.TopLeft,1);
        lptodp(Canvas.Handle,tr.BottomRight,1);
        {$ENDIF}

        mm := GetMapMode(Canvas.Handle);
        OldSize := Canvas.Font.Size;
        SetMapMode(Canvas.Handle,MM_TEXT);
        Canvas.Font.Size := FPrintSettings.Font.size;

        OnCustomCellDraw(Self,Canvas,cn,ARow,[],tr,true);

        SetMapMode(Canvas.Handle,mm);
        Canvas.Font.Size := Oldsize;
      end;

    BorderDrawing:

      Oldpen.Assign(Canvas.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];

      if  CSP.X > 0 then
        borders := borders - [cbRight,cbLeft];

      if  CSP.Y > 0 then
        borders := borders - [cbBottom,cbTop];

      if IsYMergedCell(cn,ARow) and (CSP.Y = 0) then
        borders := borders - [cbTop];

      if IsXMergedCell(cn,ARow) and (CSP.X = 0) then
        borders := borders - [cbLeft];

      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;
      }
      Canvas.Pen.Width := 1;
      GetCellPrintBorder(cn,ARow,Canvas.Pen,borders);

      // adapt pen width for printout

      if PrintMethod = prPreview then
        Canvas.Pen.Width := Canvas.Pen.Width
      else
        Canvas.Pen.Width := round(Canvas.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
        Canvas.MoveTo(tr.Left,tr.Top);
        Canvas.LineTo(tr.Left,tr.Bottom);
      end;

      if cbRight in borders then
      begin
        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
        Canvas.MoveTo(tr.Left,tr.Top);
        Canvas.LineTo(tr.Right,tr.Top);
      end;

      if cbBottom in borders then
      begin
        Canvas.MoveTo(tr.Left,tr.Bottom);
        Canvas.LineTo(tr.Right,tr.Bottom);
      end;

      Canvas.Pen.Assign(OldPen);
    end;

    Fontscalefactor := 1.0;
  end;

   // Routine to draw header & footer
   function BuildHeader: 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
         Result := IntToStr(PagRow+1) + '-' + IntToStr(PagCol)
       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);
       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 := FTitleLines.Strings[0]+' '+tl;
             ppTopRight:tr := tr + ' ' + FTitleLines.Strings[0];
             ppTopCenter:tc := tc + ' ' + FTitleLines.Strings[0];
             ppBottomLeft:bl := FTitleLines.Strings[0] + ' ' + bl;
             ppBottomRight:br := br + ' ' + FTitleLines.Strings[0];
             ppBottomCenter:bc := bc + ' ' + FTitleLines.Strings[0];
           end;
         end;
       end;
     end;

     {$IFDEF FREEWARE}
     if PrintMethod = prPrint then GetFreeStr(cla,bc);
     {$ENDIF}

     OldFont.Assign(Canvas.Font);
     OldBrush.Assign(Canvas.Brush);
     Canvas.Brush.Style := bsClear;
     Canvas.Font.Assign(FPrintSettings.HeaderFont);

     Canvas.Font.Height := MapFontHeight(FPrintSettings.HeaderFont.Size); {map into mm_lometric space}

     if tl <> '' then Canvas.Textout(Indent,-Headersize,tl);
     if tr <> '' then Canvas.Textout(xsize-Canvas.TextWidth(tr) - 20 - FPrintSettings.RightSize ,-Headersize,tr);
     if tc <> '' then Canvas.Textout((xsize-Canvas.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 + Canvas.TextHeight('gh');
         tc := FPrintSettings.TitleLines[i-1];
         case FPrintSettings.FTitle of
         ppTopLeft:Canvas.Textout(Indent,-Headersize-j,tc);
         ppTopRight:Canvas.Textout(xsize-Canvas.TextWidth(tc)-20-FPrintSettings.RightSize ,-HeaderSize-j,tc);
         ppTopCenter:Canvas.Textout((xsize-Canvas.TextWidth(tc)) shr 1,-HeaderSize - j,tc);
         end;
       end;
     end;

     if (HTMLHeader <> '') and HTMLTitle then
     begin

       HTMLDrawEx(Canvas,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,self.Handle);

       HTMLRect := Rect(Indent, -PrintSettings.FHeaderSize, xsize, -HeaderSize - HTMLYSize);

       {$IFDEF TMSDOTNET}
       SetLength(ap,2);
       ap[0] := HTMLRect.TopLeft;
       ap[1] := HTMLRect.BottomRight;
       lptodp(Canvas.Handle,ap,2);
       HTMLRect.TopLeft := ap[0];
       HTMLRect.BottomRight := ap[1];
       {$ENDIF}

       {$IFNDEF TMSDOTNET}
       lptodp(Canvas.Handle,HTMLRect.Topleft,1);
       lptodp(Canvas.Handle,HTMLRect.Bottomright,1);
       {$ENDIF}

       HTMLMM := GetMapMode(Canvas.Handle);
       HTMLFontSize := Canvas.Font.Size;
       SetMapMode(Canvas.Handle,MM_TEXT);
       Canvas.Font.Size := FPrintSettings.HeaderFont.size;

       HTMLDrawEx(Canvas,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,self.Handle);

       SetMapMode(Canvas.Handle,HTMLMM);
       Canvas.Font.Size := HTMLFontSize;
     end;

     Canvas.Font.Assign(FPrintSettings.FooterFont);
     Canvas.Font.Height := MapFontHeight(Canvas.Font.size); {map into mm_lometric space}

     if bl <> '' then Canvas.Textout(Indent,ysize + FFntSize+FntVSpace + Footersize,bl);
     if br <> '' then Canvas.Textout(xsize-Canvas.TextWidth(br)-20-FPrintSettings.RightSize ,ysize+ffntsize+fntvspace+footersize,br);
     if bc <> '' then Canvas.Textout((xsize-Canvas.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 + Canvas.TextHeight('gh');
         tc := FPrintSettings.TitleLines[i-1];
         case FPrintSettings.FTitle of
         ppBottomLeft:Canvas.Textout(Indent,ysize+ffntsize+fntvspace+footersize-j,tc);
         ppBottomRight:Canvas.Textout(xsize-Canvas.TextWidth(tc)-20-FPrintSettings.RightSize ,ysize+ffntsize+fntvspace+footersize-j,tc);
         ppBottomCenter:Canvas.Textout((xsize-Canvas.TextWidth(tc)) shr 1,ysize+ffntsize+fntvspace+footersize-j,tc);
         end;
       end;
     end;

     if (HTMLHeader <> '') and not HTMLTitle then
     begin
       HTMLRect := Rect(Indent, ysize + FPrintSettings.FooterSize, xsize, ysize );

       {$IFDEF TMSDOTNET}
       SetLength(ap,2);
       ap[0] := HTMLRect.TopLeft;
       ap[1] := HTMLRect.BottomRight;
       lptodp(Canvas.Handle,ap,2);
       HTMLRect.TopLeft := ap[0];
       HTMLRect.BottomRight := ap[1];
       {$ENDIF}

       {$IFNDEF TMSDOTNET}
       lptodp(Canvas.Handle,HTMLRect.Topleft,1);
       lptodp(Canvas.Handle,HTMLRect.Bottomright,1);
       {$ENDIF}

       HTMLMM := GetMapMode(Canvas.Handle);
       HTMLFontSize := Canvas.Font.Size;
       SetMapMode(Canvas.Handle,MM_TEXT);
       Canvas.Font.Size := FPrintSettings.HeaderFont.size;

       HTMLDrawEx(Canvas,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,self.Handle);

       SetMapMode(Canvas.Handle,HTMLMM);
       Canvas.Font.Size := HTMLFontSize;
     end;

     Canvas.Font.Assign(OldFont);
     Canvas.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;

       Canvas.MoveTo(Indents[k],-TopIndent - FPrintSettings.TitleSpacing);
       Canvas.LineTo(Indents[EndCol + 1],-TopIndent - FPrintSettings.TitleSpacing);
       Canvas.LineTo(Indents[EndCol + 1],yposprint +(fntvspace shr 1));
       Canvas.LineTo(Indents[k],yposprint + (fntvspace shr 1));
       Canvas.LineTo(Indents[k],-TopIndent - FPrintSettings.TitleSpacing);
     end;

     if (FPrintSettings.FBorders in [pbDouble,pbHorizontal,pbAroundHorizontal]) then
     begin
       if RepeatCols then
         Canvas.MoveTo(Indents[0],yposprint+(fntvspace shr 1))
       else
         Canvas.MoveTo(Indents[StartCol],yposprint+(fntvspace shr 1));

       Canvas.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
           Canvas.MoveTo(Indents[k],-topIndent-FPrintSettings.TitleSpacing);
           Canvas.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(Canvas.Handle,MM_LOMETRIC);

     if (PrintMethod in [prPrint,prPreview]) then
     if Assigned(FOnPrintPage) then
     begin
       FOnPrintPage(Self,Canvas,PagNum + 1,xsize,ysize);
     end;
   end;


begin
  SetMapMode(Canvas.Handle,MM_TEXT);

  try
    hdc := GetDC(self.Handle);
    HTMLFactor := GetDeviceCaps(Canvas.Handle,LOGPIXELSX)/GetDeviceCaps(hdc,LOGPIXELSX);
    ReleaseDC(self.Handle,hdc);
  except
    HTMLFactor := 1.0;
  end;

  SetMapMode(Canvas.Handle,MM_LOMETRIC);
  FontScalefactor := 1.0;

  newFont := TFont.Create;
  oldFont := TFont.Create;
  oldpen := TPen.Create;
  newBrush := TBrush.Create;
  oldBrush := TBrush.Create;

  Canvas.Pen.Color := clBlack;
  Canvas.Pen.style := FPrintSettings.BorderStyle;

  if FPrintSettings.Borders = pbDouble then
    Canvas.Pen.Width := 10
  else
    Canvas.Pen.Width := 2;

  Canvas.Font.Assign(FPrintSettings.HeaderFont);
  Canvas.Font.Height:=MapFontHeight(Canvas.Font.size);

  hfntsize := Canvas.TextHeight('gh');

  Canvas.Font := FPrintSettings.FooterFont;
  Canvas.Font.Height := MapFontHeight(Canvas.Font.size);
  ffntsize := Canvas.TextHeight('gh');

  Canvas.Font := FPrintSettings.Font;

  cache_Row := -1;

  orgsize := Canvas.Font.size;

  Canvas.Font.Height := MapFontHeight(Canvas.Font.size); {map into mm_lometric space}

  FntlineHeight := Canvas.TextHeight('gh');

  FntVSpace := fntlineHeight shr 3;
  FntHSpace := 4; // 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 := Canvas.Cliprect.Right - Canvas.Cliprect.Left;
        ysize := Canvas.Cliprect.Bottom;
//      end;
    end;
  prCalcPrint:
    begin
      xsize := prevrect.Right - prevrect.Left;
      ysize := -prevrect.Bottom - prevrect.Top;
    end;
  prPreview,prCalcPreview:
    begin
      {$IFDEF TMSDOTNET}
      SetLength(ap, 2);
      ap[0] := prevrect.TopLeft;
      ap[1] := prevrect.BottomRight;
      dptolp(Canvas.Handle,ap,2);
      prevrect.TopLeft := ap[0];
      prevrect.BottomRight := ap[1];
      {$ENDIF}

      {$IFNDEF TMSDOTNET}
      dptolp(Canvas.Handle,prevrect.Topleft,1);
      dptolp(Canvas.Handle,prevrect.Bottomright,1);
      {$ENDIF}
      xsize := (prevrect.Right - prevrect.Left);
      ysize := (prevrect.Bottom - prevrect.Top);
    end;
  end;

  ResFactor := GetDeviceCaps(Canvas.Handle,LOGPIXELSX)/GetDeviceCaps(Self.Canvas.Handle,LOGPIXELSX)*(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.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;

    i := FPrintRect.Top;

    if (PrintMethod in [prPrint,prPreview]) then
      if Assigned(FOnPrintPage) then
      begin
        FOnPrintPage(self,Canvas,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;

      if IsSelRow(i) then
      begin
        if RepeatCols then
          BuildColumnsRow(yposprint,0,FixedCols - 1,i,0);

        th := BuildColumnsRow(YPosPrint,StartCol,EndCol,i,0);
        YPosPrint := YPosPrint - th;
      end;

      inc(i);
      inc(j);

      ForcedNewPage := False;

      // query to print new page after each row
      if Assigned(FOnPrintNewPage) then
      begin
        FOnPrintNewPage(Self,i,ForcedNewPage);
      end;

      if ((YPosPrint - GetRowHeight(j) < YSize + FootIndent) or
         (i >= FPrintRect.Bottom + 1)) or ForcedNewPage then
      begin
        if (PrintMethod in [prPrint,prPreview]) then
        begin
          if Assigned(FOnPrintPageDone) then
            FOnPrintPageDone(Self, Canvas, i, YPosPrint, PagNum + 1, XSize, YSize);

          if Assigned(FOnPrintCancel) then
            FOnPrintCancel(Self,PagNum + 1, Cancelled);
        end;
      end;

      if ((YPosPrint - GetRowHeight(j) < YSize + FootIndent) and
         (i < FPrintRect.Bottom + 1)) 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;
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);
  {$IFNDEF TMSDOTNET}
  InvalidateRect(Handle,@gdr3,False);
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  InvalidateRect(Handle,gdr3,False);
  {$ENDIF}
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
    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
        {$IFNDEF TMSDOTNET}
        if FSelectedCells.IndexOf(Pointer(MakeLong(i,j))) = -1 then
          FSelectedCells.Add(MakeLong(i,j));
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        if FSelectedCells.IndexOf(TObject(MakeLong(i,j))) = -1 then
          FSelectedCells.Add(MakeLong(i,j));
        {$ENDIF}
      end;
    end;
  end
  else
  begin
    {$IFNDEF TMSDOTNET}
    if FSelectedCells.IndexOf(Pointer(MakeLong(Col,Row))) = -1 then
      FSelectedCells.Add(MakeLong(Col,Row));
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    if FSelectedCells.IndexOf(TObject(MakeLong(Col,Row))) = -1 then
      FSelectedCells.Add(MakeLong(Col,Row));
    {$ENDIF}
  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
    {$IFNDEF TMSDOTNET}
    Result := FSelectedCells.IndexOf(Pointer(MakeLong(i,j))) <> -1;
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    Result := FSelectedCells.IndexOf(TObject(MakeLong(i,j))) <> -1;
    {$ENDIF}
  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
  {$IFNDEF TMSDOTNET}
  k := FSelectedCells.IndexOf(Pointer(makelong(i,j)));
  {$ENDIF}

  {$IFDEF TMSDOTNET}
  k := FSelectedCells.IndexOf(TObject(makelong(i,j)));
  {$ENDIF}

  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.GetSelectedRowCount: integer;
var
  pt: TPoint;
begin
  if MouseActions.DisjunctRowSelect then
    Result := FSelectedRows.Count
  else
  begin
    if IsMergedCell(Selection.Left, Selection.Top) then
    begin
      pt := CellSpan(Selection.Left, Selection.Top);
      if pt.y + Selection.Top > Selection.Bottom then
        Result := pt.y + 1
      else
        Result := Abs(Selection.Top - Selection.Bottom) + 1;
    end
    else
      if IsMergedCell(Selection.Left, Selection.Bottom) then
      begin
        pt := CellSpan(Selection.Left, Selection.Bottom);
        Result := Abs(Selection.Top - Selection.Bottom) + pt.y + 1;
      end
      else
        Result := Abs(Selection.Top - Selection.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.MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:Integer);
var
  XSelection: TGridRect;
  c,r: Integer;
  cr: TRect;
  menu: TPopupMenu;
  pt: TPoint;
  keephighlighted: boolean;

begin
  XSelection := Selection;

  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(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;

  FEditStart := true;

  inherited;

  FEditStart := false;

  if (c <> -1) and (r <> -1) then
  begin
    CR := CellRect(c,r);

    if (X > CR.Right - 16) and HoverFixedCell(c,r) and (ControlLook.FixedDropDownButton) then
    begin
      FDropDownDown := true;
      keephighlighted := false;

      if (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 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 < FixedRows)) then
  begin
    if (MouseActions.FixedRowsEdit = fceLeftClick) and (Button = mbLeft) and (r < FixedRows) 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;
end;

procedure TAdvStringGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  r,c,i,j: Integer;
  XSelection: TGridRect;
  pt: TPoint;
  CanSelect: Boolean;
begin
  if not EqualRect(TRect(XSelection), TRect(Selection)) then
  begin
    SelectionChanged(Selection.Left, Selection.Top,Selection.Right, Selection.Bottom);
  end;

  XSelection := Selection;

  MouseToCell(x,y,c,r);

  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.DisjunctRowSelect then
    begin
      if (GetKeystate(VK_CONTROL) and $8000 = $8000) then
        RowSelect[y] := not RowSelect[y]
      else
      begin

        if (RowSelectCount > 1) and Assigned(PopupMenu) Then
        begin
          if (not IsSelected(x, y)) then
          begin
            ClearRowSelect;
            RowSelect[y] := true;
          end;
        end
        else
        begin
          ClearRowSelect;
          RowSelect[y] := true;
        end;

//        ClearRowSelect;
//        RowSelect[y] := true;
      end;
    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
      end
      else
        if ssCtrl in Shift then
        begin
          {$IFNDEF TMSDOTNET}
          i := FSelectedCells.IndexOf(Pointer(makelong(pt.x,pt.y)));
          {$ENDIF}
          {$IFDEF TMSDOTNET}
          i := FSelectedCells.IndexOf(TObject(makelong(pt.x,pt.y)));
          {$ENDIF}
          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
    else
    begin
      if MouseActions.DisjunctCellSelect and not (ssCtrl in Shift) then
      begin
        FSelectedCells.Clear;
        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)) 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 ((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.CMMouseLeave(var Msg: TMessage);
var
  hx,hy: Integer;
begin
  inherited;

  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;
end;

procedure TAdvStringGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  ACol,ARow: longint;
  mrg,i: Integer;
  nondef: Boolean;
  s,Anchor,Stripped,FocusAnchor,AnchorHint: string;
  r,hr,cr: TRect;
  pt: TPoint;
  xsize,ysize,ml,hl: Integer;
  ctt: TTextType;
  Allow: Boolean;
  dwEffects: Integer;
  {$IFNDEF TMSDOTNET}
  DropSource: TGridDropSource;
  {$ENDIF}
  CID,CV,CT: string;
  OldSel,XSelection: TGridRect;
  cc,rc,offs,offsy: Integer;
  SmartResize: boolean;
  irsel,allowmoving: Boolean;
  {$IFDEF DELPHI6_LVL}
  gr: TGridRect;
  {$ENDIF}

begin
  if FMouseDownMove and FMouseActions.RangeSelectAndEdit and (goEditing in Options) and not EditMode then
  begin
    Options := Options - [goEditing];
  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 (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 (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
      FSizeFixedCol := i - 1;
      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
      FSizeFixedRow := i - 1;
      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);
    r.Left := R.Right - 6;
    r.Top := r.Bottom - 6;

    if PtInRect(r,Point(x,y)) then
    begin
      SmartResize := true;
    end;
  end;

  if FSelectionClick and (ACol >= 0) and (ARow >= 0) 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 Assigned(FOnOleDrag) then
      FOnOleDrag(self,ARow,ACol,Cells[x,y],Allow);

    if Allow then
    begin
      {$IFNDEF TMSDOTNET}
      DropSource := TGridDropSource.Create(self);
      {$ENDIF}
      if Assigned(FOnOleDragStart) then
        FOnOleDragStart(Self,ARow,ACol);

      pt := ClientToScreen(point(x,y));

      {$IFDEF DELPHI6_LVL}
      if DragDropSettings.ShowCells then
      begin
        if not Assigned(MoveForm) then
        begin
          ShowSelection := false;

          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;
          MoveForm.Visible := true;
        end;

        if BiDiMode = bdRightToLeft then
          MoveForm.Left := pt.X - MoveForm.Width + ColWidths[0]
        else
          MoveForm.Left := pt.X;
          
        MoveForm.Top := pt.Y;
      end;
      {$ENDIF}

      if (ARow < FixedRows) and (ACol >= 0) and DragDropSettings.OleColumnDragDrop then
      begin
        MoveButton.Left := pt.x;
        MoveButton.Top := pt.y;
        MoveButton.Width := ColWidths[ACol];
        MoveButton.Height := RowHeights[0];
        MoveButton.Caption := Cells[ACol,ARow];

        case Look of
        glVista:
          begin
            MoveButton.GradFrom := FTMSGradFrom;
            MoveButton.GradTo := FTMSGradTo;
            MoveButton.GradMirrorFrom := FTMSGradMirrorFrom;
            MoveButton.GradMirrorTo := FTMSGradMirrorTo;
          end;
        glXP:
          begin
            MoveButton.GradFrom := FTMSGradFrom;
            MoveButton.GradTo := FTMSGradTo;
            MoveButton.GradMirrorFrom := clNone;
            MoveButton.GradMirrorTo := clNone;
          end;
        glTMS:
          begin
            MoveButton.GradFrom := FTMSGradFrom;
            MoveButton.GradTo := FTMSGradTo;
            MoveButton.GradMirrorFrom := clNone;
            MoveButton.GradMirrorTo := clNone;
          end;
        else
        begin
          MoveButton.GradFrom := clNone;
          MoveButton.GradTo := clNone;
          MoveButton.GradMirrorFrom := clNone;
          MoveButton.GradMirrorTo := clNone;
        end;
        end;

        MoveButton.Visible := True;
        MoveButton.Images := FGridImages;
        SetWindowPos(MoveButton.Handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);

        {$IFNDEF TMSDOTNET}
        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;
        {$ENDIF}

       MoveButton.Visible := False;
       ArwD.Visible := False;
       ArwU.Visible := False;
      end
     else
      begin
        FDropSelection := Selection;
        {$IFNDEF TMSDOTNET}
        if not (StartTextDoDragDrop(DropSource,SelectedText,Cells[ACol,ARow],DROPEFFECT_COPY or DROPEFFECT_MOVE,dwEffects) = DRAGDROP_S_CANCEL) 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;

          if Assigned(FOnOleDragStop) then
            FOnOleDragStop(self,dwEffects);
        end
        {$ENDIF}
       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
       ( (clickposx <> x) or (clickposy <> y)) and FEnhRowColMove and not FSizingFixed and not FSizingFixedR then
    begin
      allowmoving := true;

      if (FGridState = gsColMoving) and (MoveCell >= FixedCols) and (ARow >= 0) then
      begin
        {$IFDEF DELPHI6_LVL}
        if not Assigned(MoveForm) and DragDropSettings.ShowCells then
        begin
          MoveForm := SelectionToForm(TGridRect(Rect(MoveCell,0,MoveCell,TopRow + VisibleRowCount - FixedRows)));
          MoveForm.Visible := true;
        end;
        {$ENDIF}

        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
        {$IFDEF DELPHI6_LVL}
        if not Assigned(MoveForm) and DragDropSettings.ShowCells then
        begin
          MoveForm := SelectionToForm(TGridRect(Rect(0, MoveCell, LeftCol + VisibleColCount - FixedCols, MoveCell)));
          MoveForm.Visible := true;
        end;
        {$ENDIF}
        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
        {$IFDEF DELPHI6_LVL}
        if BiDiMode = bdRightToLeft then
          MoveForm.Left := pt.X - MoveForm.Width + ColWidths[0]
        else
          MoveForm.Left := pt.x;

        MoveForm.Top := pt.y;
        {$ENDIF}
      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
        case Look of
        glVista:
          begin
            MoveButton.GradFrom := FTMSGradFrom;
            MoveButton.GradTo := FTMSGradTo;
            MoveButton.GradMirrorFrom := FTMSGradMirrorFrom;
            MoveButton.GradMirrorTo := FTMSGradMirrorTo;
          end;
        glXP:
          begin
//            MoveButton.GradFrom := clWhite;
//            MoveButton.GradTo := ColorToRGB(clBtnFace);
            MoveButton.GradFrom := FTMSGradFrom;
            MoveButton.GradTo := FTMSGradTo;
            MoveButton.GradMirrorFrom := clNone;
            MoveButton.GradMirrorTo := clNone;
          end;
        glTMS:
          begin
            //FTMSGradFrom := clSilver;
            //FTMSGradTo := clWhite;
            MoveButton.GradFrom := FTMSGradFrom;
            MoveButton.GradTo := FTMSGradTo;
            MoveButton.GradMirrorFrom := clNone;
            MoveButton.GradMirrorTo := clNone;
          end;
        else
        begin
          MoveButton.GradFrom := clNone;
          MoveButton.GradTo := clNone;
          MoveButton.GradMirrorFrom := clNone;
          MoveButton.GradMirrorTo := clNone;
        end;
        end;

        MoveButton.Visible := not DragDropSettings.ShowCells;
        MoveButton.Images := FGridImages;

        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 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 >= self.FixedCols) and
       (FMouseActions.ColSelect) and not InSizeZone(x,y) then
    begin
      Nondef := True;
      Invokedchange := True;
      FMouseSelectMode := msColumn;
    end;

    if (ACol < Self.FixedCols) and
       (ARow >= 0) and (ACol >= 0) and
       ((ARow >= Self.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;

        if HasCheckBox(ACol,ARow) then
          r.Left := r.Left + ControlLook.CheckSize;

        if not HTMLDrawEx(Canvas,s,r,GridImages,x,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,CV,CT,FImageCache,FContainer,self.Handle) then
          Anchor := '';

        if (Anchor <> '') then
        begin
          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;
   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);
    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);
    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
      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);

    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;


  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;

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: Integer;
  hr,cr: TRect;
  CID,CV,CT: string;
  csize: TSize;
  ctt: TTextType;
  ws: widestring;
begin
  MouseToCell(HintInfo.CursorPos.x,HintInfo.CursorPos.y,Col,Row);

  WideHintFontName := Font.Name;

  if (Col >= 0) and (Row >= 0) then
  begin
    FLastHintPos := Point(Col,Row);

    HintPos := CellRect(Col,Row);

    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 := 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) then
        Anchor := '';

      if (Anchor <> '') then
      begin
        if AnchorHint = '' then
          AnchorHint := Anchor;
        if Assigned(FOnAnchorHint) then
          FOnAnchorHint(self,Row,RCol,AnchorHint);
        HintStr := AnchorHint;

        HintInfo.HintPos.x := HintInfo.CursorPos.x + 8;
        HintInfo.HintPos.y := HintInfo.CursorPos.y - 16;
      end;
    end;


    {$IFDEF DELPHI3_LVL}
    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;

    csize := GetCellTextSize(RCol,Row,true);

    if FHintShowLargeText and
       ((csize.cx > ColWidths[Col]) or (csize.cy > RowHeights[Row])) then
    begin
      HintInfo.HintPos.y := HintPos.Top;

      ctt := TextType(Cells[RCol,Row],FEnableHTML);
      if ctt = ttUnicode then
        HintStr := Cells[RCol,Row]
      else
        if HTMLHint then
          HintStr := Cells[RCol,Row]
        else
          HintStr := StrippedCells[RCol,Row];
    end;
    {$ENDIF}

    if not (FloatingFooter.Visible and (Row = RowCount - 1)) then
      GetCellHint(Col,Row,HintStr, ws);

    if (TextType(HintStr, true) in [ttUnicode, ttHTML]) then
    begin
      HintInfo.HintWindowClass := THTMLHintWindow;
    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: TMemoryStream;
  RtfText: string;
  {$IFDEF DELPHI_UNICODE}
  ch: char;
  ach: ansichar;
  i: integer;
  {$ENDIF}
begin
  RtfText := Cells[Col,Row];

  {$IFDEF DELPHI_UNICODE}
  if RtfText <> '' then
  begin
    MemoryStream := TMemoryStream.Create;
    for i := 1 to length(rtftext) do
    begin
      ch := rtftext[i];
      ach := ansichar(ch);
      MemoryStream.Write(ach, 1);
    end;
    MemoryStream.Position := 0;
    RichEditor.Lines.LoadFromStream(MemoryStream);
    MemoryStream.Free;
  end
  else
    RichEditor.Clear;
  {$ENDIF}

  {$IFNDEF DELPHI_UNICODE}
  if RtfText <> '' then
  begin
    MemoryStream := TMemoryStream.Create;
    MemoryStream.Write(RtfText[1], Length(RtfText));
    MemoryStream.Position := 0;
    RichEditor.Lines.LoadFromStream(MemoryStream);
    MemoryStream.Free;
  end
  else
    RichEditor.Clear;
  {$ENDIF}
end;

procedure TAdvStringGrid.RichToCell(Col,Row: Integer; RichEditor: TRichEdit);
begin
  Cells[Col,Row] := RichToString(RichEditor);
end;

function TAdvStringGrid.RichToString(RichEditor: TRichEdit):string;
var
  MemoryStream: TMemoryStream;
  {$IFNDEF DELPHI_UNICODE}
  RtfText: string;  
  {$ENDIF}
  {$IFDEF DELPHI_UNICODE}
  RtfText: ansistring;
  i: integer;
  ch:ansichar;
  {$ENDIF}
begin
  MemoryStream := TMemoryStream.Create;

  {$IFDEF DELPHI_UNICODE}
  RichEditor.Lines.SaveToStream(MemoryStream,TEncoding.Unicode);
  {$ENDIF}
  {$IFNDEF DELPHI_UNICODE}
  RichEditor.Lines.SaveToStream(MemoryStream);
  {$ENDIF}

  MemoryStream.Position := 0;

  {$IFDEF DELPHI_UNICODE}
  rtftext := '';
  for i := 1 to memorystream.size  do
  begin
    MemoryStream.read(ch,1);
    RtfText := RtfText + ch;
  end;
  Result := WideString(RtfText);
  {$ENDIF}

  {$IFNDEF DELPHI_UNICODE}
  {$IFNDEF TMSDOTNET}
  if MemoryStream.Size > 0 then
    SetString(RtfText, PChar(MemoryStream.Memory), MemoryStream.Size);
  {$ENDIF}
  MemoryStream.Free;
  Result := RtfText;
  {$ENDIF}
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
    Result := (FGridItems.Items[i - 1] as TGridItem).Items;
  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 IsBasecell(RealCol, Row) then
    Result := GridCells[RealCol,Row]
  else
  begin
    pt := BaseCell(RealCol, Row);
    Result := GridCells[pt.x, pt.y];
  end;
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;
begin
  if IsHiddenRow(j) then
  begin
    Result := HiddenRow(j).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
  Result := DecodeWideStr(AllCells[i,j]);
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;
begin
  if IsHiddenRow(j) then
    HiddenRow(j).Strings[i] := Value
  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
  AllCells[i,j] := EncodeWideStr(Value);
end;

function TAdvStringGrid.GetAllGraphicsObject(i,j: integer): TObject;
begin
  if IsHiddenRow(j) then
    Result := HiddenRow(j).Objects[i]
  else
  begin
    j := RemapRow(j);
    Result := GridObjects[i,j];
  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 := TCellProperties(CO).CellObject
    else
      Result := CO;
  end
  else
  begin
    j := RemapRow(j);
    Result := Objects[i,j];
  end;
end;

procedure TAdvStringGrid.SetObjectsEx(i,j: Integer; AObject:TObject);
begin
  if IsHiddenRow(j) then
    HiddenRow(j).Objects[i] := AObject
  else
  begin
    j := RemapRow(j);
    Objects[i,j] := AObject;
  end;
end;

function TAdvStringGrid.GetCellControls(i,j: Integer): TControl;
begin
  Result := nil;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].Control;
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);
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
      ClearPropCell(j,i);
  end
  else
  begin
    for j := FixedCols to AllColCount - 1 do
      CellProperties[j,i].BrushColor := AColor;
  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
      ClearPropCell(j,i);
  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.GetReadOnly(i,j: Integer): Boolean;
begin
  Result := CellProperties[i,j].ReadOnly;
end;

procedure TAdvStringGrid.SetReadOnly(i,j: Integer;AValue: Boolean);
begin
  CellProperties[i,j].ReadOnly := AValue;
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;
end;

function TAdvStringGrid.GetFontColors(i, j: Integer): TColor;
begin
  Result := clNone;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontColor;
end;

procedure TAdvStringGrid.SetFontColors(i, j: Integer; const Value: TColor);
begin
  CellProperties[i,j].FontColor := Value;
  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;
  RepaintCell(DisplColIndex(i),j);
end;

function TAdvStringGrid.GetFontNames(i, j: Integer): string;
begin
  Result := '';
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontName;
end;

function TAdvStringGrid.GetFontSizes(i, j: Integer): Integer;
begin
  Result := 0;
  if HasCellProperties(i,j) then
    Result := CellProperties[i,j].FontSize;
end;

procedure TAdvStringGrid.SetFontNames(i, j: Integer; const Value: string);
begin
  CellProperties[i,j].FontName := Value;
  RepaintCell(DisplColIndex(i),j);
end;

procedure TAdvStringGrid.SetFontSizes(i, j: Integer;
  const Value: Integer);
begin
  CellProperties[i,j].FontSize := Value;
  RepaintCell(DisplColIndex(i),j);
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;
  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;


procedure TAdvStringGrid.Zoom(x: Integer);
var
  i: Integer;
begin

  if FZoomFactor + x > 10 then
    Exit;
  if FZoomFactor + x < -10 then
    Exit;

  FScrollLock := true;

  FZoomfactor := FZoomFactor + x;

  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;
  if ScrollProportional 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;
  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);
  focusbmp.free;
  tmpbmp.free;
end;

procedure TAdvStringGrid.EraseIntelliFocusPoint;
var
  r:TRect;
begin
  r := Rect(wheelpanpos.x,wheelpanpos.y,wheelpanpos.x + 32,wheelpanpos.y + 32);

  {$IFNDEF TMSDOTNET}
  InvalidateRect(self.Handle,@r,False);
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  InvalidateRect(self.Handle,r,False);
  {$ENDIF}
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;
  {$IFDEF TMSDOTNET}
  k: string;
  i: Integer;
  {$ENDIF}
  FOldSelection: TGridRect;
  delta: integer;
  Res: integer;

begin
  if Message.Msg = WM_DESTROY then
  begin
    {$IFDEF TMSUNICODE}
    if not (csDesigning in ComponentState) and Assigned(ComboUni) then
      if Assigned(ComboUni.Items) then
         ComboUni.Items.Clear;
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    if FOleDropTargetAssigned then
      RevokeDragDrop(self.Handle);
    {$ENDIF}
    KillTimer(Handle,FGridTimerID);
  end;
  if (csDestroying in ComponentState) then
  begin
    inherited;
    Exit;
  end;

  FOldSelection := Selection;

  if Message.Msg = WM_GRIDEDITDONE then
  begin
    if Assigned(FOnEditCellDone) then
      FOnEditCellDone(Self, Message.wparam, Message.Lparam);

    if MouseActions.EditOnDblClickOnly then
    begin
      HideInplaceEdit;
      EditMode := false;
      Options := Options - [goEditing];
    end;

  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_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) then
    if FAutoThemeAdapt then
      ThemeAdapt;

  {$IFDEF TMSDOTNET}
  if (Message.Msg = WM_NCPAINT) then
  begin
    inherited;
    if FUpdateCount > 0 then Exit;
    NCPaintProc;
    Message.Result := 0;
    Exit;
  end;
  {$ENDIF}

  // 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,
        edCapital,
        edMixedCase,
        edPassword,
        edLowerCase,
        edUpperCase: SetEditText(Col,Row, NormalEdit.Text);

        edSpinEdit,
        edFloatSpinEdit,
        edTimeSpinEdit,
        edDateSpinEdit: SetEditText(Col,Row, SpinEdit.Text);

        edEditBtn,
        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);
      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)) then
    begin
      nr := EditCombo.Itemindex;
      if Assigned(FOnComboChange) then
      begin
        FOnComboChange(Self,RealColIndex(Col),Row,nr,EditCombo.Items[nr]);
      end;

      if Assigned(FOnComboObjectChange) then
      begin
        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
              {$IFNDEF TMSDOTNET}
              SendMessage(CH, CB_GETLBTEXT, nr,integer(@buf));
              s := strpas(buf);
              {$ENDIF}
              {$IFDEF TMSDOTNET}
              k := '';
              for i := 0 to length(buf) - 1 do
                k := k + buf[i];
              Perform(CB_GETLBTEXT, nr,k);
              s := k;
              {$ENDIF}
            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 = Integer(EditCombo.Handle)) then
  begin

    if MouseActions.DirectComboClose then
    begin
      EditCombo.Text := EditCombo.Items[EditCombo.ItemIndex];
      HideInplaceEdit;
    end;

    if Assigned(FOnComboCloseUp) then
      FOnComboCloseUp(Self,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 then //intellimouse event here
  begin
    Res := 0;
    
    // allow for processing by the parent
    if Parent <> nil 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 message.wparam < 0 then
          Zoom(wheelscrl)
        else
          Zoom(-wheelscrl);
      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 (message.wparam < 0) then
            nr := Row + wi
          else
            nr := Row - wi;
        end
        else
        begin
          if (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) then
          Col := ColCount - 1;
        if Col < FixedCols then
          Col := FixedCols;

        lc := LeftCol;
        delta := 0;

        if (nr < RowCount) and (nr >= 0) then
        begin
          StartUpdate;

          delta := nr - Row;

          Row := nr;

          // 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;

        if (MouseActions.WheelIncrement <> 0) then
        begin
          Message.Result := 1;
          DirectWheelChange(delta);
        end;

        if not EqualRect(TRect(FOldSelection), TRect(Selection)) then
        begin
          SelectionChanged(Selection.Left, Selection.Top, Selection.Right, Selection.Bottom);
        end;
      end;

      {$IFNDEF DELPHI9_LVL}
      if (MouseActions.WheelIncrement <> 0) then
      begin
        Exit;
      end;
      {$ENDIF}
    end;
  end;
  inherited;
end;

procedure TAdvStringGrid.DirectWheelChange(delta: integer);
begin
  //
end;

{$IFDEF DELPHI5_LVL}
function TAdvStringGrid.DoMouseWheelDown(Shift: TShiftState;
  MousePos: TPoint): Boolean;
var
  lc: Integer;
  em: Boolean;
begin
  if MouseActions.WheelAction = waScroll then
  begin
    Result := False;
    Exit;
  end;
  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;
end;

function TAdvStringGrid.DoMouseWheelUp(Shift: TShiftState;
  MousePos: TPoint): Boolean;
var
  lc: Integer;
  em: Boolean;
begin
  if MouseActions.WheelAction = waScroll then
  begin
    Result := False;
    Exit;
  end;

  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;
end;
{$ENDIF}

procedure TAdvStringGrid.Select;
begin
  SelectCell(Col,Row);
end;


procedure TAdvStringGrid.ShowInplaceEdit;
begin
  if not HasStaticEdit(Col,Row) then
  begin
    if Row < TopRow then
      TopRow := Row;
    if Col < LeftCol then
      LeftCol := Col;

    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 Assigned(FOnEditingDone) then
    FOnEditingDone(Self);

  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;

  HideInplaceEdit;

  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;
var
  i: Integer;
  ctrl: TControl;
  r: TRect;
  ci: TControlItem;
  pt: TPoint;

begin
  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;
    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,r.Top,r.Right - r.Left - 1,r.Bottom - r.Top - 1);
          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;

  {
  for i := FOldLeftCol to FOldLeftCol + FOldVisibleColCount do
    for j := FOldTopRow to FOldTopRow + FOldVisibleRowCount do
    begin
      if (i < LeftCol) or (i > LeftCol + VisibleColCount) or
         (j < TopRow) or ( j > TopRow + VisibleRowCount) then
      begin
        ctrl := CellControls[i,j];
        if Assigned(ctrl) then
        begin
          if ctrl.Visible then
          begin
            r := CellRect(i,j);
            ctrl.SetBounds(r.Left,r.Top,0,0);
          end;
        end;
      end;
    end;


  for i := LeftCol to LeftCol + VisibleColCount do
    for j := TopRow to TopRow + VisibleRowCount do
    begin
      ctrl := CellControls[i,j];

      if Assigned(ctrl) then
      begin
        if ctrl.Visible then
        begin
          r := CellRect(i,j);
          ctrl.SetBounds(r.Left,r.Top,r.Right - r.Left,r.Bottom - r.Top);
        end;
      end;
    end;
  }
end;

procedure TAdvStringGrid.TopLeftChanged;
var
  fcr,tcr,lr: TRect;
begin
  // 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;

  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
  with FBackground do
  begin
    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));
      RepaintRect(fcr);
      RepaintRect(tcr);
    end;
  end;

  if (Background.Display in [bdGradientHorz, bdGradientVert]) and (Background.ColorTo <> clNone) then
    Invalidate;

  if (EditMode) and (EditControl <> edNormal) then
    HideInplaceEdit;


  UpdateVScrollBar;
  UpdateHScrollBar;
  UpdateFooter;

  CellControlsUpdate;

  FOldLeftCol := LeftCol;
  FOldTopRow := TopRow;
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;

{$IFDEF DELPHI3_LVL}
function TAdvStringGrid.GeTDateTimePicker:TDateTimePicker;
begin
  Result := TDateTimePicker(EditDate);
end;
{$ENDIF}

procedure TAdvStringGrid.KeyUp(var Key: Word; Shift: TShiftState);
var
  pt: TPoint;
  CanSelect: Boolean;
  i,j: integer;

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 := '';

  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 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
        {$IFNDEF TMSDOTNET}
        i := FSelectedCells.IndexOf(Pointer(makelong(pt.x,pt.y)));
        {$ENDIF}
        {$IFDEF TMSDOTNET}
        i := FSelectedCells.IndexOf(TObject(makelong(pt.x,pt.y)));
        {$ENDIF}
        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;
{$IFDEF DELPHI6_LVL}
var
  bmp, finalbmp: TBitmap;
  cr1,cr2,ar:TRect;
  img: TImage;
{$ENDIF}
begin
{$IFNDEF DELPHI6_LVL}
  Result := nil;
{$ENDIF}
{$IFDEF DELPHI6_LVL}
  bmp := TBitmap.Create;
  bmp.Width := Width;
  bmp.Height := Height;
  PaintTo(bmp.Canvas,0,0);

  cr1 := CellRect(ARect.Left, ARect.Top);
  cr2 := CellRect(ARect.Right, ARect.Bottom);

  if cr1.Left > cr2.Left then
  begin
    ar := cr1;
    cr1 := cr2;
    cr2 := ar;
  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 := TForm.Create(self);
  Result.BorderStyle := bsNone;
  Result.Width := finalbmp.Width;
  Result.Height := finalbmp.Height;

  img := TImage.Create(Result);
  img.Parent := Result;
  img.Align := alClient;

  img.Picture.Bitmap.Assign(finalbmp);

  Result.AlphaBlendValue := 192;
  Result.AlphaBlend := true;

  finalbmp.Free;
{$ENDIF}
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);
   {$IFDEF TMSDOTNET}
   SetLayeredWindowAttributes(hwnd,colorkey,alpha,2);
   {$ENDIF}
   {$IFNDEF TMSDOTNET}
   DynaLink_SetLayeredWindowAttributes(hwnd,DWORD(colorkey),alpha,2);
   {$ENDIF}
   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);
   {$IFDEF TMSDOTNET}
//   UpdateLayeredWindow(hwnd,dskdc,nil,size,hdc,src,colorkey, blnd,ULW_ALPHA);
   {$ENDIF}
   {$IFNDEF TMSDOTNET}
   DynaLink_UpdateLayeredWindow(hwnd,dskdc,nil,@size,hdc,@src,dword(colorkey), blnd,ULW_ALPHA);
   {$ENDIF}
   ReleaseDC(0,dskdc);
   ReleaseDC(hwnd,hdc);
  end;

begin
  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.Enable then
    DestroyToolTip;
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.SearchChanged(Sender: TObject);
begin
  if FSearchPanel.FHiliteButton.Down and FSearchPanel.Visible and not FSearchFooter.Visible then
  begin
    UnHilightInGrid(false);
  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 = csWinXP) 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.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
    FSearchPanel.FMatchCase.Left := 330
  else
    FSearchPanel.FMatchCase.Left := 425;

//  if (csDesigning in ComponentState) then
//  begin
    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 := 17;

    if not FSearchFooter.Visible then
      FSearchPanel.Height := 0
    else
      FSearchPanel.Height := 32;
//  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.AddToolTip(IconType: Integer; Text, Title: string);
{$IFDEF TMSDOTNET}
type
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  TTOOLINFOEX = packed record
    cbSize: UINT;
    uFlags: UINT;
    hwnd: HWND;
    uId: UINT;
    Rect: TRect;
    hInst: THandle;
    lpszText: IntPtr;
    lParam: LPARAM;
  end;
{$ENDIF}
var
  Item: THandle;
  Rect: TRect;
  {$IFDEF TMSDOTNET}
  ti: TToolInfoEx;
  {$ENDIF}
  {$IFNDEF TMSDOTNET}
  ti: TToolInfo;
  {$ENDIF}
  buffer: array[0..255] of char;
  {$IFDEF TMSDOTNET}
  Mem: IntPtr;
  {$ENDIF}
begin
  Item := self.Handle;

  if (Item <> 0) AND (Windows.GetClientRect(Item, Rect)) then
  begin
    {$IFNDEF TMSDOTNET}
    ti.cbSize := SizeOf(TToolInfo);
    {$ENDIF}

    {$IFDEF TMSDOTNET}
    ti.cbSize := Marshal.SizeOf(TypeOf(TToolInfo));
    {$ENDIF}

    ti.uFlags := TTF_SUBCLASS or TTF_IDISHWND ;
    ti.hInst := hInstance;

    ti.hwnd := Item;
    ti.Rect := Rect;
    ti.uId := Handle;

    {$IFDEF TMSDOTNET}

    ti.lpszText := IntPtr(LPSTR_TEXTCALLBACK);

    try
      Mem := Marshal.AllocHGlobal(Marshal.SizeOf(TypeOf(ti)));
      Marshal.StructureToPtr(TObject(ti),Mem,False);
      SendMessage(fhToolTip, TTM_ADDTOOL, 0, Longint(mem));
    finally
      Marshal.FreeHGlobal(Mem);
    end;
    if (IconType > 3) or (IconType < 0) then IconType := 0;
    SendTextMessage(fhToolTip, TTM_SETTITLE, IconType, Title);

    {$ENDIF}

    {$IFNDEF TMSDOTNET}
    ti.lpszText :=  LPSTR_TEXTCALLBACK;
    SendMessage(fhToolTip, TTM_ADDTOOL, 0, Integer(@ti));
    FillChar(buffer, sizeof(buffer), #0);
    lstrcpy(buffer, PChar(Title));
    if (IconType > 3) or (IconType < 0) then IconType := 0;
    SendMessage(fhToolTip, TTM_SETTITLE, IconType, Integer(@buffer));
    {$ENDIF}
  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;


{OLE Drag & Drop interface only supported in Delphi 4+}

{$IFNDEF TMSDOTNET}
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
    {$IFDEF DELPHI6_LVL}
    if Assigned(FGrid.MoveForm) then
    begin
      FGrid.MoveForm.Left := pt.x + 4;
      FGrid.MoveForm.Top := pt.y + 4;
    end;
    {$ENDIF}
  end;
end;

procedure TGridDropSource.DragDropStop;
begin
  inherited;

  if FGrid.DragDropSettings.ShowCells then
  begin
    {$IFDEF DELPHI6_LVL}
    if Assigned(FGrid.MoveForm) then
      FreeAndNil(FGrid.MoveForm);
    {$ENDIF}  
  end;

end;

constructor TGridDropTarget.Create(AGrid: TAdvStringGrid);
begin
  inherited Create;
  FGrid := AGrid;
end;

procedure TGridDropTarget.DropCol(pt:TPoint; Col: Integer);
var
  c,r: Integer;
begin
  FGrid.ScreenToCell(pt,c,r);

  if dfCol in DropFormats then
  begin
    FGrid.ArwD.Visible := False;
    FGrid.ArwU.Visible := False;
    FGrid.MoveButton.Visible := False;
  end;

  if Assigned(FGrid.OnOleDropCol) then
    FGrid.OnOleDropCol(FGrid,r,c,Col);
end;

procedure TGridDropTarget.DropText(pt: TPoint; s: string);
var
  c,r,tr,i: Integer;
  Allow: Boolean;
  gr: TGridRect;
  Size: TPoint;

begin
  FGrid.ScreenToCell(pt,c,r);

  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
      //+++ v2.8.0.1
      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;

      //gr.Top := gr.Top + size.y;
      //gr.Bottom := gr.Bottom + size.y;
    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);

      FGrid.InsertRows(r,size.y + 1);


      if (tr > 0) then
        FGrid.TopRow := tr;
    end;

    FGrid.PasteText(c,r,PChar(s));

    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;
begin
  inherited;

  FGrid.ScreenToCell(pt,c,r);

  pt := FGrid.ScreenToClient(pt);

  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 (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;

  if Assigned(FGrid.FOnOleDragOver) then
    FGrid.FOnOleDragOver(FGrid,r,c,Allow);

  Allow := Allow and (r >= 0) and (c >= 0);

  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 then
  begin
    if (r = 0) and FGrid.FixedRowAlways then
      Inc(r);

    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));

    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;
var
  Result : HResult;
begin
  Result := OleInitialize(Nil);
  Assert(Result in [S_OK, S_False], Format ('OleInitialize failed ($%x)', [Result]));
end;


{$ENDIF}

{ 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
  {$IFNDEF TMSDOTNET}
  FillChar( Format, SizeOf(Format), 0);
  {$ENDIF}
  with Format do
  begin
    {$IFDEF TMSDOTNET}
    cbSize := Marshal.SizeOf(TypeOf(Format));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    cbSize := SizeOf(Format);
    {$ENDIF}
    dwMask := CFM_OFFSET;
    yOffset := Offset; { superscript by 40 twips, negative Values give subscripts}
  end;
  {$IFNDEF TMSDOTNET}
  Perform( EM_SETCHARFORMAT, SCF_SELECTION,Integer(@Format));
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Perform( EM_SETCHARFORMAT, SCF_SELECTION,Format);
  {$ENDIF}
end;

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

procedure TAdvRichEdit.ReCreate;
begin
  ReCreateWnd;
end;

procedure TAdvRichEdit.WMKillFocus(var Msg: TMessage);
begin
  if FGrid.InvokedFocusChange then
    Exit;

  if Msg.wparam = Integer(FGrid.Handle) then
    FGrid.HideInplaceEdit;
  inherited;
end;

{$IFDEF TMSDOTNET}
procedure TAdvRichEdit.CNNotify(var Msg: TWMNotify);
begin
end;
{$ENDIF}

{$IFNDEF TMSDOTNET}
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 FGrid.FRichEdit.HandleAllocated then
    begin
      if Msg.NMHdr^.hwndFrom = FGrid.FRichEdit.Handle then
      begin
        FGrid.FRichEdit.FReqWidth := ReqResize^.rc.Right - ReqResize^.rc.Left;
        FGrid.FRichEdit.FReqHeight := ReqResize^.rc.Bottom - ReqResize^.rc.Top;
      end;
    end;

    if not FGrid.FInplaceRichEdit.HandleAllocated then
      Exit;

    ReqResize := PREQRESIZE(Msg.NMHdr);

    with ReqResize^ do
    begin
      if FGrid.SizeWhileTyping.Height and
         (Msg.NMHdr^.hwndFrom = FGrid.FInplaceRichEdit.Handle)
         and not FGrid.FInplaceRichEdit.FLocked then
      begin
        NewHeight := ReqResize^.rc.Bottom - ReqResize^.rc.Top;
        // 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;

            {$IFDEF TMSDOTNET}
            VerInfo.dwOSVersionInfoSize := Marshal.SizeOf(TypeOf(TOSVersionInfo));
            {$ENDIF}
            {$IFNDEF TMSDOTNET}
            VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
            {$ENDIF}
            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;
  inherited;
end;
{$ENDIF}

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 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
  {$IFNDEF TMSDOTNET}
  FillChar( Format, SizeOf(Format), 0);
  {$ENDIF}
  with Format do
  begin
    {$IFDEF TMSDOTNET}
    cbSize := Marshal.SizeOf(TypeOf(Format));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    cbSize := SizeOf(Format);
    {$ENDIF}
    dwMask := CFM_OFFSET;
  end;
  {$IFNDEF TMSDOTNET}
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,Integer(@Format));
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,Format);
  {$ENDIF}
  Result := Format.yOffset = -40;
end;

function TAdvRichEdit.IsSelNormal: Boolean;
var
  Format: TCharFormat; { defined in Unit RichEdit }
begin
  {$IFNDEF TMSDOTNET}
  FillChar( Format, SizeOf(Format), 0);
  {$ENDIF}
  with Format do
  begin
    {$IFDEF TMSDOTNET}
    cbSize := Marshal.SizeOf(TypeOf(Format));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    cbSize := SizeOf(Format);
    {$ENDIF}
    dwMask := CFM_OFFSET;
  end;
  {$IFNDEF TMSDOTNET}
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,Integer(@Format));
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,Format);
  {$ENDIF}
  Result := Format.yOffset = 0;
end;

function TAdvRichEdit.IsSelSuperscript: Boolean;
var
  Format: TCharFormat; { defined in Unit RichEdit }
begin
  {$IFNDEF TMSDOTNET}
  FillChar( Format, SizeOf(Format), 0);
  {$ENDIF}
  with Format do
  begin
    {$IFDEF TMSDOTNET}
    cbSize := Marshal.SizeOf(TypeOf(Format));
    {$ENDIF}
    {$IFNDEF TMSDOTNET}
    cbSize := SizeOf(Format);
    {$ENDIF}
    dwMask := CFM_OFFSET;
  end;
  {$IFNDEF TMSDOTNET}
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,Integer(@Format));
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  Perform( EM_GETCHARFORMAT, SCF_SELECTION,Format);
  {$ENDIF}
  Result := Format.yOffset = 0;
end;

{ TFilter }

function TFilter.Add: TFilterData;
begin
  Result := TFilterData(inherited Add);
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;

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;

{ TBackGround }

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;

{ TBands }

constructor TBands.Create(AOwner: TAdvStringGrid);
begin
  inherited Create;
  FOwner := AOwner;
  FActive := False;
  FPrimaryColor := clInfoBk;
  FSecondaryColor := clWindow;
  FPrimaryLength := 1;
  FSecondaryLength := 1;
  FTotalLength := FPrimaryLength + FSecondaryLength;
end;

procedure TBands.Assign(Source: TPersistent);
begin
  if (Source is TBands) then
  begin
    FActive := (Source as TBands).Active;
    FPrimaryColor := (Source as TBands).PrimaryColor;
    FPrimaryLength := (Source as TBands).PrimaryLength;
    FSecondaryColor := (Source as TBands).SecondaryColor;
    FSecondaryLength := (Source as TBands).SecondaryLength;
    FPrint := Print;
  end;
end;

procedure TBands.SetActive(const Value: Boolean);
begin
  FActive := Value;
  FOwner.Invalidate;
end;

procedure TBands.SetPrimaryColor(const Value: TColor);
begin
  FPrimaryColor := Value;
  if FActive then FOwner.Invalidate;
end;

procedure TBands.SetPrimaryLength(const Value: Integer);
begin
  FPrimaryLength := Value;
  FTotalLength :=  FSecondaryLength + FPrimaryLength;
  if FActive then FOwner.Invalidate;
end;

procedure TBands.SetSecondaryColor(const Value: TColor);
begin
  FSecondaryColor := Value;
  if FActive then FOwner.Invalidate;
end;

procedure TBands.SetSecondaryLength(const Value: Integer);
begin
  FSecondaryLength := Value;
  FTotalLength :=  FSecondaryLength + FPrimaryLength;
  if FActive then FOwner.Invalidate;
end;




{ TEditLink }

constructor TEditLink.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FForcedExit := False;
  FPopupLeft := -1;
  FPopupTop := -1;
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
    // +++Added in v2.6.0.3
    DestroyEditor;
    FPopupForm.Hide;
    // +++

    // ---Removed in v2.6.0.3
    // FPopupForm.Free;
    // FPopupForm := Nil;
    // ---
  end;
end;

procedure TEditLink.EditKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  Allow: Boolean;
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];

  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 Allow then
    with FOwner do
    begin
      if Key = VK_ESCAPE then
      begin
        SetEditorValue(OriginalCellValue);
      end;

      //FOwner.Cells[FOwner.Col,FOwner.Row] := OriginalCellValue;
      FForcedExit := True;
      SetFocus;
      FForcedExit := False;

      // HideInplaceEdit;

      HideEditControl(Col,Row);

      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;
    end
  else
    inherited;
end;

procedure TEditLink.FormExit(Sender: TObject);
begin
  //necessary patch for hidden cells
  if Assigned(FOwner.NormalEdit) then
    FOwner.NormalEdit.Text := GetEditorValue;

  if not FForcedExit then
  begin
    EditExit(Sender);
    FOwner.InvokedFocusChange := true;
  end
  else
    SetCellValue(GetEditorValue);
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;

    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) then
  begin
    FOwner.FGridControlWndProc := ec.WindowProc;
    ec.WindowProc := FOwner.SubClassProc;
  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);
begin
  GetEditControl.Visible := Value;
end;

{ TGridChangeNotifier}

procedure TGridChangeNotifier.CellsChanged(R:TRect);
begin
end;

{ TFilterData }

constructor TFilterData.Create(ACollection: TCollection);
begin
  inherited;
  FCaseSensitive := True;
end;

procedure TFilterData.Assign(Source: TPersistent);
begin
  if (Source is TFilterData) then
  begin
    with (Source as TFilterData) do
    begin
      FColumn  := Column;
      FCondition := Condition;
      FCaseSensitive := CaseSensitive;
      FData := Data;
      FPrefix := Prefix;
      FSuffix := Suffix;
      FOperation := Operation;
    end;
  end;    
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;
    {$IFNDEF TMSDOTNET}
    DrawTextExW(Canvas.Handle,PWideChar(WideCaption),Length(WideCaption),rd,DT_SINGLELINE or DT_LEFT or DT_NOPREFIX,nil);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    DrawTextEx(Canvas.Handle,WideCaption,Length(WideCaption),rd,DT_SINGLELINE or DT_LEFT or DT_NOPREFIX,nil);
    {$ENDIF}
  end
  else
    HTMLDrawEx(Canvas,Caption,rd,nil,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,nil,self.Handle);
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;
{$IFDEF DELPHI6_LVL}
  Monitor : TMonitor;
{$ENDIF}
  ws: widestring;

begin
  Caption := AHint;
  dx := 16;
  dy := 4;

  with Rect do
  begin
    // Calculate width and height
    Rect.Right := Rect.Left + 1024 - dx;

    if TextType(AHint,true) = ttUnicode then
    begin
      Canvas.Font.Name := WideHintFontName;
      ws := DecodeWideStr(AHint);
      {$IFNDEF TMSDOTNET}
      YSize := DrawTextExW(Canvas.Handle,PWideChar(ws),Length(ws),Rect,DT_SINGLELINE or DT_CALCRECT or DT_LEFT or DT_NOPREFIX,nil);
      {$ENDIF}
      {$IFDEF TMSDOTNET}
      YSize := DrawTextEx(Canvas.Handle,ws,Length(ws),Rect,DT_SINGLELINE or DT_LEFT or DT_CALCRECT or DT_NOPREFIX,nil);
      {$ENDIF}
      XSize := Rect.Right - Rect.Left;
      WideCaption := ws;
      dx := 8;
    end
    else
      HTMLDrawEx(Canvas,AHint,Rect,nil,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,nil,self.Handle);

    FTextWidth := XSize;
    Right := Left + FTextWidth + dx;

    FTextHeight := YSize;
    Bottom := Top + FTextHeight + dy;

    // Calculate position
    Pnt := Point(Rect.Left,Rect.Top);
    Left := Pnt.X;
    Top := Pnt.Y;
    Right := Right - Left + Pnt.X;
    Bottom := Bottom - Top + Pnt.Y;

    {$IFDEF DELPHI6_LVL}
    Monitor := Screen.MonitorFromPoint(Pnt);

    if Right - Monitor.Left > Monitor.Width then
    begin
      Left := Monitor.Left + Monitor.Width - Right + Left - 2;
      Right := Left + FTextWidth + dx;
    end;

    if Bottom - Monitor. Top > Monitor. Height then
    begin
      Bottom := Monitor. Top + Monitor. Height - 2;
      Top := Bottom - FTextHeight - dy;
    end;
    {$ELSE}


    if Right > Screen.DesktopWidth then
    begin
      Left := Screen.DesktopWidth - Right + Left -2;
      Right := Left + FTextWidth + dx;
    end;

    if Bottom > Screen.DesktopHeight then
    begin
      Bottom := Screen.DesktopHeight - 2;
      Top := Bottom - FTextHeight - dy;
    end;

    {$ENDIF}

{
    // 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;
}
  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;

{$IFNDEF TMSDOTNET}
function THTMLHintWindow.CalcHintRect(MaxWidth: Integer;
  const AHint: string; AData: Pointer): TRect;
{$ENDIF}
{$IFDEF TMSDOTNET}
function THTMLHintWindow.CalcHintRect(MaxWidth: Integer;
  const AHint: string; AData: TObject): TRect;
{$ENDIF}
var
  ARect,hr,cr: TRect;
  XSize,YSize,ml,hl: Integer;
  Anchor,Stripped,FocusAnchor,AnchorHint: string;
  CID,CT,CV: string;
  ws: widestring;
begin
  {$IFNDEF TMSDOTNET}
  FillChar(ARect,SizeOf(ARect),0);
  {$ENDIF}

  ARect.Right := ARect.Left + MaxWidth;

  if TextType(AHint,true) = ttUnicode then
  begin
    Canvas.Font.Name := WideHintFontName;
    ws := DecodeWideStr(AHint);
    {$IFNDEF TMSDOTNET}
    YSize := DrawTextExW(Canvas.Handle,PWideChar(ws),Length(ws),ARect,DT_SINGLELINE or DT_CALCRECT or DT_LEFT or DT_NOPREFIX,nil);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    YSize := DrawTextEx(Canvas.Handle,ws,Length(ws),ARect,DT_SINGLELINE or DT_LEFT or DT_CALCRECT or DT_NOPREFIX,nil);
    {$ENDIF}
    XSize := ARect.Right;
  end
  else
    HTMLDrawEx(Canvas,AHint,ARect,nil,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,nil,self.Handle);

  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;
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;
    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);
    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;

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.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;
  FCheckedGlyph := TBitmap.Create;
  FUnCheckedGlyph := TBitmap.Create;
  FRadioOnGlyph := TBitmap.Create;
  FRadioOffGlyph := TBitmap.Create;
  FControlStyle := csWinXP;
  FProgressMarginX := 2;
  FProgressMarginY := 2;
  FColor := clBlack;
  FCommentColor := clRed;
  FProgressBorderColor := clGray;
  FFixedGradientFrom := clNone;
  FFixedGradientTo := clNone;
  FFixedGradientMirrorFrom := clNone;
  FFixedGradientMirrorTo := clNone;
  FFixedGradientHoverFrom := clNone;
  FFixedGradientHoverTo := clNone;
  FFixedGradientHoverMirrorFrom := clNone;
  FFixedGradientHoverMirrorTo := clNone;
  FFixedGradientHoverBorder := clNone;
  FFixedGradientDownFrom := clNone;
  FFixedGradientDownTo := clNone;
  FFixedGradientDownMirrorFrom := clNone;
  FFixedGradientDownMirrorTo := clNone;
  FFixedGradientDownBorder := clNone;
  FFixedDropDownButton := false;
end;

destructor TControlLook.Destroy;
begin
  FCheckedGlyph.Free;
  FUnCheckedGlyph.Free;
  FRadioOnGlyph.Free;
  FRadioOffGlyph.Free;
  inherited;
end;

procedure TControlLook.Assign(Source: TPersistent);
begin
  if (Source is TControlLook) then
  begin
    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;
  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
  FControlStyle := Value;
  FGrid.Invalidate;
end;

procedure TControlLook.SetDropDownAlwaysVisible(const Value: Boolean);
begin
  FDropDownAlwaysVisible := Value;
  FGrid.Invalidate;
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);
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 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;
  if Value <> clNone then
    FGrid.TMSGradientMirrorTo := Value
end;

procedure TControlLook.SetFixedGradientMirrorTo(const Value: TColor);
begin
  FFixedGradientMirrorTo := Value;
  if Value <> clNone then
    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;
  if Value <> clNone then
    FGrid.TMSGradientHoverMirrorTo := Value
end;

procedure TControlLook.SetFixedGradientHoverMirrorTo(const Value: TColor);
begin
  FFixedGradientHoverMirrorTo := Value;
  if Value <> clNone then
    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;
  if Value <> clNone then
    FGrid.TMSGradientDownMirrorTo := Value
end;

procedure TControlLook.SetFixedGradientDownMirrorTo(const Value: TColor);
begin
  FFixedGradientDownMirrorTo := Value;
  if Value <> clNone then
    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;
end;

function TFooterPanel.PaintColPreview: Integer;
var
  i, FW: Integer;
  r: TRect;
  OldColor: TColor;
  rtl: boolean;

begin
  FW := 0;

  rtl := FGrid.UseRightToLeftAlignment;

  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];

  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 := R.Right;
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
  i, 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 := 0;

  rtl := FGrid.UseRightToLeftAlignment;

  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];

  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;
    {$IFNDEF TMSDOTNET}
    DrawText(Canvas.Handle,PChar(s),Length(s),R,0);
    {$ENDIF}
    {$IFDEF TMSDOTNET}
    DrawText(Canvas.Handle,s,Length(s),R,0);
    {$ENDIF}
  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);
    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 := R.Right;
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 := 0;
  
  rtl := FGrid.UseRightToLeftAlignment;
  lft := FGrid.LeftCol;

  for i := 1 to FGrid.FixedCols do
    FW := FW + FGrid.ColWidths[i - 1];

  for i := lft to FGrid.ColCount - 1 do
    FW := FW + FGrid.ColWidths[i];

  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;
  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;

procedure TFooterPanel.CMHintShow(var Msg: TCMHintShow);
var
  CanShow: Boolean;
  {$IFNDEF TMSDOTNET}
  hi: PHintInfo;
  {$ENDIF}
  {$IFDEF TMSDOTNET}
  hi: THintInfo;
  {$ENDIF}
  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);

  if Assigned(FGrid.OnClickCell) then
    FGrid.OnClickCell(FGrid,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;
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;

  FGrid.HideLastRow := (FFooterStyle = fsFixedLastRow) and Visible;
  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
  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;

  FGrid.HideLastRow := (FFooterStyle = fsFixedLastRow) and Value;
  FGrid.Invalidate;
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 := TCellGraphic.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.ColumnPosition(ACol: integer): integer;
var
  i: integer;
begin
  Result := -1;
  for i := 1 to ColCount do
  begin
    if ACol = FColumnOrder.Items[i - 1] then
    begin
      Result := i - 1;
      break;
    end;
  end;
end;

function TAdvStringGrid.ColumnAtPosition(ACol: integer): integer;
begin
  Result := FColumnOrder.Items[ACol];
end;

procedure TAdvStringGrid.ResetColumnOrder;
var
  i: Integer;
  rst: Boolean;
begin
  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);
end;

function TAdvStringGrid.GetWideCells(i, j: Integer): widestring;
begin
  Result := DecodeWideStr(Cells[i,j]);
end;

procedure TAdvStringGrid.SetWideCells(i, j: Integer;
  const Value: widestring);
begin
  GridCells[i,j] := EncodeWideStr(Value);
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;
    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
    Key := #0;
  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;
  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;
  {$IFDEF DELPHI6_LVL}
  FShowCells := True;
  {$ENDIF}
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;
    FOleDropRTF := (Source as TDragDropSettings).OleDropRTF;
    FOleColumnDragDrop := (Source as TDragDropSettings).OleColumnDragDrop;
  end;
end;

procedure TDragDropSettings.SetOleDropRTF(const Value: Boolean);
begin
  {$IFNDEF TMSDOTNET}
  SetRTFAware(Value);
  {$ENDIF}
  FOleDropRTF := Value;
end;

procedure TDragDropSettings.SetOleDropTarget(const Value: Boolean);
begin
  FOleDropTarget := Value;

  {$IFNDEF TMSDOTNET}
  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;
  {$ENDIF}
end;


procedure TDragDropSettings.SetShowCells(const Value: boolean);
begin
  {$IFDEF DELPHI6_LVL}
  FShowCells := Value;
  {$ENDIF}
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
  FEnable := Value;
  if Assigned(FOnEnableChange) then
    FOnEnableChange(self);
end;

{$IFDEF TMSDOTNET}
procedure TWMNotifyTT.SetToolTipText(Value: TToolTipText);
begin
  Marshal.StructureToPtr(TObject(Value), IntPtr(OriginalMessage.LParam), False);
end;

function TWMNotifyTT.GetToolTipText: TToolTipText;
begin
  Result := TToolTipText(Marshal.PtrToStructure(IntPtr(LParam), TypeOf(TToolTipText)));
end;
{$ENDIF}


{ 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 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)] 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;

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 := TCheckBox.Create(Self);
  FColorTo := clNone;
end;

procedure TSearchPanel.CreateWnd;
begin
  inherited;

  FEdit.Parent := Self;
  FEdit.Top := 6;
  FEdit.Width := 110;
  FEdit.Left := 25;
  FEdit.OnChange := EditChange;
  FEdit.OnReturn := EditReturn;

  if UseRightToLeftAlignment then
    FEdit.Left := Width - FEdit.Width - FEdit.Left;

  FForwardButton.Parent := self;
  FForwardButton.Left := 140;
  FForwardButton.Top := 5;
  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;

  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; 

  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 := '';

  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 := tasCheck;
  FHiliteButton.OnClick := HighLightClick;
  FHiliteButton.Glyph.LoadFromResourceName(hinstance,'ASGHI');
  FHiliteButton.GlyphDisabled.LoadFromResourceName(hinstance,'ASGHID');

  FMatchCase.Parent := Self;
  FMatchCase.Top := 8;

  if FHiliteButton.Visible then
    FMatchCase.Left := 425
  else
    FMatchCase.Left := 330;

  FMatchCase.Caption := MatchCaseCaption;
end;

destructor TSearchPanel.Destroy;
begin
  inherited;
end;

procedure TSearchPanel.EditReturn(Sender: TObject);
begin
  ForwardClick(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);
end;

procedure TSearchPanel.SetColorTo(const Value: TColor);
begin
  FColorTo := Value;
  Invalidate;
end;

{ TSearchFooter }

procedure TSearchFooter.Assign(Source: TPersistent);
begin
  if (Source is TSearchFooter) then
  begin
    FColor := (Source as TSearchFooter).Color;
    FColorTo := (Source as TSearchFooter).ColorTo;
    FFindNextCaption := (Source as TSearchFooter).FindNextCaption;
    FFindPrevCaption := (Source as TSearchFooter).FindPrevCaption;
    FHighLightCaption := (Source as TSearchFooter).HighLightCaption;
    FHintClose := (Source as TSearchFooter).HintClose;
    FHintFindNext := (Source as TSearchFooter).HintFindNext;
    FHintFindPrev := (Source as TSearchFooter).HintFindPrev;
    FHintHighlight := (Source as TSearchFooter).HintHighLight;
    FMatchCaseCaption := (Source as TSearchFooter).MatchCaseCaption;
    FShowClose := (Source as TSearchFooter).ShowClose;
    FShowFindNext := (Source as TSearchFooter).ShowFindNext;
    FShowFindPrev := (Source as TSearchFooter).ShowFindPrev;
    FShowHighLight := (Source as TSearchFooter).ShowHighLight;
    FShowMatchCase := (Source as TSearchFooter).ShowMatchCase;
    FSearchActiveColumnOnly := (Source as TSearchFooter).SearchActiveColumnOnly;
    FSearchMatchStart := (Source as TSearchFooter).SearchMatchStart;
    FSearchColumn := (Source as TSearchFooter).SearchColumn;
    FVisible := (Source as TSearchFooter).Visible;
    FFont.Assign((Source as TSearchFooter).Font);
  end;
end;

procedure TSearchFooter.Changed;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

constructor TSearchFooter.Create(AOwner: TComponent);
begin
  inherited Create;
  FColor := clWhite;
  FColorTo := clBtnFace;
  FShowFindNext := true;
  FShowFindPrev := true;
  FSearchActiveColumnOnly := false;
  FSearchColumn := -1;
  FFindPrevCaption := 'Find &previous';
  FFindNextCaption := 'Find &next';
  FMatchCaseCaption :='Match case';
  FHighLightCaption := 'Highlight';

  FHintClose := 'Close';
  FHintFindNext := 'Find next occurence';
  FHintFindPrev := 'Find previous occurence';
  FHintHighlight := 'Highlight occurences';

  FShowMatchCase := true;
  FShowHighLight := true;
  FShowClose := true;
  FAutoSearch := true;
  FFont := TFont.Create;
end;

destructor TSearchFooter.Destroy;
begin
  FFont.Free;
  inherited;
end;

procedure TSearchFooter.SetAutoThemeAdapt(const Value: boolean);
begin
  FAutoThemeAdapt := Value;
  Changed;
end;

procedure TSearchFooter.SetColor(const Value: TColor);
begin
  FColor := Value;
  Changed;
end;

procedure TSearchFooter.SetColorTo(const Value: TColor);
begin
  FColorTo := Value;
  Changed;
end;

procedure TSearchFooter.SetFindNextCaption(const Value: string);
begin
  FFindNextCaption := Value;
  Changed;
end;

procedure TSearchFooter.SetFindPrevCaption(const Value: string);
begin
  FFindPrevCaption := Value;
  Changed;
end;

procedure TSearchFooter.SetFont(const Value: TFont);
begin
  FFont.Assign(Value);
  Changed;
end;

procedure TSearchFooter.SetHighLightCaption(const Value: string);
begin
  FHighLightCaption := Value;
  Changed;
end;

procedure TSearchFooter.SetHintClose(const Value: string);
begin
  FHintClose := Value;
  Changed;
end;

procedure TSearchFooter.SetHintFindNext(const Value: string);
begin
  FHintFindNext := Value;
  Changed;
end;

procedure TSearchFooter.SetHintFindPrev(const Value: string);
begin
  FHintFindPrev := Value;
  Changed;
end;

procedure TSearchFooter.SetHintHighlight(const Value: string);
begin
  FHintHighLight := Value;
  Changed;  
end;

procedure TSearchFooter.SetMatchCaseCaption(const Value: string);
begin
  FMatchCaseCaption := Value;
  Changed;
end;

procedure TSearchFooter.SetShowClose(const Value: Boolean);
begin
  FShowClose := Value;
  Changed;
end;

procedure TSearchFooter.SetShowFindNext(const Value: boolean);
begin
  if (FShowFindNext <> Value) then
  begin
    FShowFindNext := Value;
    Changed;
  end;
end;

procedure TSearchFooter.SetShowFindPrev(const Value: boolean);
begin
  if (FShowFindPrev <> Value) then
  begin
    FShowFindPrev := Value;
    Changed;
  end;  
end;

procedure TSearchFooter.SetShowHighLight(const Value: Boolean);
begin
  if (FShowHighLight <> Value) then
  begin
    FShowHighLight := Value;
    Changed;
  end;
end;

procedure TSearchFooter.SetShowMatchCase(const Value: Boolean);
begin
  if (FShowMatchCase <> Value) then
  begin
    FShowMatchCase := Value;
    Changed;
  end;  
end;

procedure TSearchFooter.SetVisible(const Value: boolean);
begin
  if FVisible <> Value then
  begin
    FVisible := Value;
    Changed;
  end;
end;

procedure TMouseActions.Assign(Source: TPersistent);
begin
  if (Source is TMouseActions) then
  begin
    FAllColumnSize := (Source as TMouseActions).AllColumnSize;
    FAllRowSize := (Source as TMouseActions).AllRowSize;
    FAllSelect := (Source as TMouseActions).AllSelect;
    FAutoSizeColOnDblClick := (Source as TMouseActions).AutoSizeColOnDblClick;
    FCaretPositioning := (Source as TMouseActions).CaretPositioning;
    FCheckAllCheck := (Source as TMouseActions).CheckAllCheck;
    FColSelect := (Source as TMouseActions).ColSelect;
    FDirectComboClose := (Source as TMouseActions).DirectComboClose;
    FDirectComboDrop := (Source as TMouseActions).DirectComboDrop;
    FDirectDateClose := (Source as TMouseActions).DirectDateClose;
    FDirectDateDrop := (Source as TMouseActions).DirectDateDrop;
    FDirectEdit := (Source as TMouseActions).DirectEdit;
    FDisjunctRowSelect := (Source as TMouseActions).DisjunctRowSelect;
    FDisjunctColSelect := (Source as TMouseActions).DisjunctColSelect;
    FDisjunctCellSelect := (Source as TMouseActions).DisjunctCellSelect;
    FFixedRowsEdit := (Source as TMouseActions).FixedRowsEdit;
    FFixedColsEdit := (Source as TMouseActions).FixedColsEdit;
    FMoveRowOnNodeClick := (Source as TMouseActions).MoveRowOnNodeClick;
    FNoAutoRangeScroll :=  (Source as TMouseActions).NoAutoRangeScroll;
    FNodeAllExpandContract := (Source as TMouseActions).NodeAllExpandContract;
    FNoScrollOnPartialRow := (Source as TMouseActions).NoScrollOnPartialRow;
    FPreciseCheckBoxCheck := (Source as TMouseActions).PreciseCheckBoxCheck;
    FRangeSelectAndEdit := (Source as TMouseActions).RangeSelectAndEdit;
    FRowSelect := (Source as TMouseActions).RowSelect;
    FRowSelectPersistent := (Source as TMouseActions).RowSelectPersistent;
    FSelectOnRightClick := (Source as TMouseActions).SelectOnRightClick;
    FSizeFixedCol := (Source as TMouseActions).SizeFixedCol;
    FWheelIncrement := (Source as TMouseActions).WheelIncrement;
    FWheelAction := (Source as TMouseActions).WheelAction;
  end;
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;


initialization
{$IFNDEF TMSDOTNET}
{$IFNDEF TMSDISABLEOLE}
  Initialize;
{$ENDIF}
{$ENDIF}

  {$IFDEF ISDELPHI}
  try
    RegisterClass(TAdvStringGrid);
  except
  end;
  {$ENDIF}

  ComCtrlOk := GetfileVersion(comctrl) >= $00040046;

  CF_GRIDCELLS := RegisterClipboardFormat('TAdvStringGrid Cells');
  WM_GRIDEDITDONE := RegisterWindowMessage('GridEditDone');

finalization
{$IFNDEF TMSDOTNET}
{$IFNDEF TMSDISABLEOLE}
  OleUninitialize;
{$ENDIF}
{$ENDIF}

end.
