home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 January / Chip_2003-01_cd1.bin / zkuste / delphi / kompon / D34567 / SMDBG / SMDBGRID.ZIP / Smdbgrid.pas < prev    next >
Pascal/Delphi Source File  |  2002-11-04  |  72KB  |  2,369 lines

  1. {$A+,B-,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
  2.  
  3. { Copyright (C) 1998-2000, written by Shkolnik Mike
  4.   FIDOnet: 2:463/106.14
  5.   E-Mail:  mshkolnik@scalabium.com
  6.            mshkolnik@yahoo.com
  7.   WEB: http://www.scalabium.com
  8.        http://www.geocities.com/mshkolnik
  9.   tel: 380-/44/-552-10-29
  10.  
  11. English:
  12.   The successor TDBGrid with the extended features.
  13.   Is able to display multiline wordwrap column titles,
  14.   checkboxs for boolean fields, checkboxs for record selecting,
  15.   fixing of columns, a convenient select of records from the keyboard,
  16.   stretch drawing of the graphic fields in the cells,
  17.   possibility to exclude insert and delete of records in the DBGrid,
  18.   own standard PopupMenu, save/restore of a column states, processing of
  19.   additional events etc.
  20.  
  21.   1. movement from column to column by ENTER key (like TAB)
  22.   2. multiline wordwrap column titles (partly is transfered
  23.      from TBitDBGrid - Ilya Andreev, ilya_andreev@geocities.com
  24.      FIDONet: 2:5030/55.28 AKA 2:5030/402.17)
  25.   3. display opportunity of selected record mark (like checkbox)
  26.   4. editing of boolean fields like checkbox
  27.   5. a convenient select of records from keyboard (is transfered from TRXDBGrid, RXLibrary)
  28.   6. an opportunity to exclude insert and delete of records in the SMDBGrid
  29.   7. save and restore of the column order and column width in the INI-file
  30.   8. own PopUp-menu with standard items (Add/Edit/Delete record, Print/Export
  31.      data, Save/Cancel changes, Refresh data, Select/UnSelect records,
  32.      Save/Restore layout)
  33.   9. fixing of the few columns in horizontal scrolling
  34.  10. delete of the all selected records
  35.  11. Refresh of the data in SMDBGrid (useful for TQuery because Refresh
  36.      correctly works only for TTable)
  37.  12. processing of events by pressing on column title (is transfered
  38.      from TRXDBGrid, RXLibrary)
  39.  13. ability of display of the MEMO/BLOB/PICTURE-fields as Bitmap (is
  40.      transfered from TRXDBGrid, RXLibrary)
  41.  14. display hints for each cells if cell text is cutted by column width
  42.      (transfered from TBitDBGrid - Ilya Andreev, ilya_andreev@geocities.com
  43.      FIDONet: 2:5030/55.28 AKA 2:5030/402.17)
  44.  15. opportunity to assign of events: OnAppendRecord, OnEditRecord,
  45.      OnDeleteRecord, OnPrintData, OnExportData
  46.  16. lowered draw of the current selected column (like grid in
  47.      1C-accounting)
  48.  17. standard Popup menu like window system menu:
  49.        "Add record",
  50.        "Insert record",
  51.        "Edit record",
  52.        "Delete record",
  53.        "-",
  54.        "Print ...",
  55.        "Export ...",
  56.        "-",
  57.        "Save changes",
  58.        "Cancel changes",
  59.        "Refresh data",
  60.        "-",
  61.        "Select/Unselect records",
  62.        "-",
  63.        "Save layout",
  64.        "Restore layout",
  65.        "-",
  66.        "Setup..."
  67.  
  68. PS: in archive there are English, French, German, Italian, Dutch,
  69.     Brazilian Portuguese, Russian, Ukrainian and Japan resources
  70.     (view a file SMCnst.PAS in Resourse directory).
  71. If anybody want to send a native resources, then I shall include it in next build.
  72.  
  73.  
  74. Thanks to native tranclators:
  75. - Remy (walloon@euronet.be) for French resources
  76. - Thomas Grimm (tgrimm@allegro-itc.de) for German resources
  77. - Naohiro Fukuda (nao@nagoya.terracom.co.jp) for Japan resources
  78. - Julian (gzorzi@misam.it) for Italian resources
  79. - Rodrigo Hjort (rodrigo_hjort@excite.com) for Brazilian Portuguese resources
  80. - sam francke (s.j.francke@hccnet.nl) for Dutch resources
  81. - Daniel Ramirez Jaime (rdaniel2000@hotmail.com) for Spanish Mexican resources
  82.  
  83. I want to thank Naohiro Fukuda (nao@nagoya.terracom.co.jp)
  84. and Remy (walloon@euronet.be), due to which in TSMDBGrid
  85. there was much less errors and bugs and for their sentences
  86. on improverment a component.
  87. }
  88.  
  89. unit SMDBGrid;
  90.  
  91. interface
  92.  
  93. uses
  94.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  95.   Menus, Grids, DBGrids, DB, StdCtrls, SMCnst;
  96.  
  97. type
  98.   TExOptions = set of (eoBooleanAsCheckBox,
  99.                        eoCheckBoxSelect, eoCellHint,
  100.                        eoDisableDelete, eoDisableInsert, eoDrawGraphicField,
  101.                        eoENTERlikeTAB, eoFixedLikeColumn,
  102.                        eoKeepSelection, eoLayout,
  103.                        eoSelectedTitle, eoShowGlyphs, eoShowLookup, eoStandardPopup,
  104.                        eoTitleButtons);
  105.  
  106. type
  107.   {start cutting from TRxDBGrid}
  108.   TCheckTitleBtnEvent = procedure (Sender: TObject; ACol: Longint; Field: TField; var Enabled: Boolean) of object;
  109.   TGetCellParamsEvent = procedure (Sender: TObject; Field: TField; AFont: TFont; var Background: TColor; Highlight: Boolean) of object;
  110.   TGetBtnParamsEvent = procedure (Sender: TObject; Field: TField; AFont: TFont; var Background: TColor; IsDown: Boolean) of object;
  111.   {end cutting from TRxDBGrid}
  112.  
  113.   TGetGlyphEvent = procedure (Sender: TObject; var Bitmap: TBitmap) of object;
  114.  
  115. type
  116.   TSMSortType = (stNone, stAscending, stDescending);
  117.  
  118.   TSMSortColumn = class
  119.     FieldName: string;
  120.     SortCaption: string;
  121.     SortType: TSMSortType;
  122.   end;
  123.  
  124.   TSMDBGrid = class;
  125.  
  126.   TSMListSortColumns = class(TList)
  127.   private
  128.     function GetColumn(Index: Integer): TSMSortColumn;
  129.     procedure SetColumn(Index: Integer; Value: TSMSortColumn);
  130.   public
  131.     function Add: TSMSortColumn;
  132.     procedure RebuildColumns(Grid: TSMDBGrid);
  133.  
  134.     property Items[Index: Integer]: TSMSortColumn read GetColumn write SetColumn; default;
  135.   end;
  136.  
  137.  
  138.   TSMDBGrid = class(TDBGrid)
  139.   private
  140.     { Private declarations }
  141.     FExOptions: TExOptions;
  142.  
  143.     {selection: from TRxDBGrid}
  144.     FMultiSelect: Boolean;
  145.     FSelecting: Boolean;
  146.     FMsIndicators: TImageList;
  147.     FSelectionAnchor: TBookmarkStr;
  148.     FDisableCount: Integer;
  149.     FFixedCols: Integer;
  150.     FSwapButtons: Boolean;
  151.     FOnCheckButton: TCheckTitleBtnEvent;
  152.     FTracking: Boolean;
  153.     FPressedCol: Longint;
  154.     FPressed: Boolean;
  155.     FOnGetCellParams: TGetCellParamsEvent;
  156.     FOnGetBtnParams: TGetBtnParamsEvent;
  157.  
  158.     {Registry}
  159.     FRegistryKey: string;
  160.     FRegistrySection: string;
  161.  
  162.     {popup menu with standard operations}
  163.     FDBPopUpMenu: TPopUpMenu;
  164.     FOnAppendRecord: TNotifyEvent;
  165.     FOnInsertRecord: TNotifyEvent;
  166.     FOnEditRecord: TNotifyEvent;
  167.     FOnDeleteRecord: TNotifyEvent;
  168.     FOnPostData: TNotifyEvent;
  169.     FOnCancelData: TNotifyEvent;
  170.     FOnRefreshData: TNotifyEvent;
  171.     FOnPrintData: TNotifyEvent;
  172.     FOnExportData: TNotifyEvent;
  173.     FOnSetupGrid: TNotifyEvent;
  174.     FOnChangeSelection: TNotifyEvent;
  175.  
  176.     FOnDrawColumnTitle: TDrawColumnCellEvent;
  177.     FOnGetGlyph: TGetGlyphEvent;
  178.     FWidthOfIndicator: Integer;
  179.  
  180.     StartOfSelect: TBookmark;
  181.  
  182.     procedure SetIndicatorWidth(Value: Integer);
  183.  
  184.     procedure AppendClick(Sender: TObject);
  185.     procedure InsertClick(Sender: TObject);
  186.     procedure EditClick(Sender: TObject);
  187.     procedure DeleteClick(Sender: TObject);
  188.     procedure PrintClick(Sender: TObject);
  189.     procedure ExportClick(Sender: TObject);
  190.     procedure PostClick(Sender: TObject);
  191.     procedure CancelClick(Sender: TObject);
  192.     procedure RefreshClick(Sender: TObject);
  193.     procedure SetupGridClick(Sender: TObject);
  194.  
  195.     procedure SaveLayoutClick(Sender: TObject);
  196.     procedure RestoreLayoutClick(Sender: TObject);
  197.  
  198.     {start cutting from TRxDBGrid}
  199.     procedure SetFixedCols(Value: Integer);
  200.     function GetFixedCols: Integer;
  201.     function GetTitleOffset: Byte;
  202.     procedure StopTracking;
  203.     procedure TrackButton(X, Y: Integer);
  204.     function AcquireFocus: Boolean;
  205.     function ActiveRowSelected: Boolean;
  206.     function GetOptions: TDBGridOptions;
  207.     procedure SetOptions(Value: TDBGridOptions);
  208.     {end cutting from TRxDBGrid}
  209.  
  210.     function GetImageIndex(Field: TField): Integer;
  211.     procedure SetExOptions(Val: TExOptions);
  212.  
  213.    {partly is transfered from TBitDBGrid:
  214.     Ilya Andreev, ilya_andreev@geocities.com
  215.     FIDONet: 2:5030/55.28 AKA 2:5030/402.17}
  216.     procedure SetTitlesHeight;
  217.     procedure CMHintShow(var Msg: TMessage); message CM_HINTSHOW;
  218.     {end of transfered}
  219.  
  220.     function GetSortImageWidth: Integer;
  221.   protected
  222.     { Protected declarations }
  223. //    procedure Paint; override;
  224.  
  225.     {start cutting from TRxDBGrid}
  226.     function HighlightCell(DataCol, DataRow: Integer; const Value: string;
  227.       AState: TGridDrawState): Boolean; override;
  228.     procedure Scroll(Distance: Integer); override;
  229.  
  230.     procedure LayoutChanged; override;
  231.     procedure ColWidthsChanged; override;
  232.     procedure SetColumnAttributes; override;
  233.     procedure TopLeftChanged; override;
  234.     function CanEditShow: Boolean; override;
  235.  
  236.     procedure CheckTitleButton(ACol: Longint; var Enabled: Boolean); dynamic;
  237.     procedure GetCellProps(Field: TField; AFont: TFont; var Background: TColor;
  238.       Highlight: Boolean); dynamic;
  239.     {end cutting from TRxDBGrid}
  240.  
  241.     procedure CellClick(Column: TColumn); override;
  242.     function CellRectForDraw(R: TRect; ACol: Longint): TRect;
  243.  
  244.     procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;
  245.       Column: TColumn; State: TGridDrawState); override;
  246.     function GetGlyph: TBitmap; virtual;
  247.     procedure DrawCheckBox(R: TRect; AState: TCheckBoxState; al: TAlignment); virtual;
  248.  
  249.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  250.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  251.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  252.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  253.   public
  254.     { Public declarations }
  255.     SortColumns: TSMListSortColumns;
  256.  
  257.     constructor Create(AOwner: TComponent); override;
  258.     destructor Destroy; override;
  259.     procedure DeleteData;
  260.     procedure RefreshData;
  261.  
  262.     procedure SelectOneClick(Sender: TObject);
  263.     procedure SelectAllClick(Sender: TObject);
  264.     procedure UnSelectOneClick(Sender: TObject);
  265.     procedure UnSelectAllClick(Sender: TObject);
  266.  
  267.     procedure SaveLayoutToRegistry;
  268.     procedure RestoreLayoutFromRegistry;
  269.  
  270.     procedure ToggleRowSelection;
  271.     procedure GotoSelection(Index: Longint);
  272.  
  273.     procedure DisableScroll;
  274.     procedure EnableScroll;
  275.     function ScrollDisabled: Boolean;
  276.  
  277.     property IndicatorOffset;
  278.     property TitleOffset: Byte read GetTitleOffset;
  279.   published
  280.     { Published declarations }
  281.  
  282.     property GridLineWidth;
  283.     property ExOptions: TExOptions read FExOptions write SetExOptions;
  284.  
  285.     {selection}
  286.     property Options: TDBGridOptions read GetOptions write SetOptions;
  287.     property FixedCols: Integer read GetFixedCols write SetFixedCols default 0;
  288.     property OnGetCellParams: TGetCellParamsEvent read FOnGetCellParams write FOnGetCellParams;
  289.  
  290.     {Registry}
  291.     property RegistryKey: string read FRegistryKey write FRegistryKey;
  292.     property RegistrySection: string read FRegistrySection write FRegistrySection;
  293.  
  294.     property OnAppendRecord: TNotifyEvent read FOnAppendRecord write FOnAppendRecord;
  295.     property OnInsertRecord: TNotifyEvent read FOnInsertRecord write FOnInsertRecord;
  296.     property OnEditRecord: TNotifyEvent read FOnEditRecord write FOnEditRecord;
  297.     property OnDeleteRecord: TNotifyEvent read FOnDeleteRecord write FOnDeleteRecord;
  298.     property OnPostData: TNotifyEvent read FOnPostData write FOnPostData;
  299.     property OnCancelData: TNotifyEvent read FOnCancelData write FOnCancelData;
  300.     property OnRefreshData: TNotifyEvent read FOnRefreshData write FOnRefreshData;
  301.     property OnPrintData: TNotifyEvent read FOnPrintData write FOnPrintData;
  302.     property OnExportData: TNotifyEvent read FOnExportData write FOnExportData;
  303.     property OnCheckButton: TCheckTitleBtnEvent read FOnCheckButton write FOnCheckButton;
  304.     property OnChangeSelection: TNotifyEvent read FOnChangeSelection write FOnChangeSelection;
  305.  
  306.     property OnSetupGrid: TNotifyEvent read FOnSetupGrid write FOnSetupGrid;
  307.     property OnDrawColumnTitle: TDrawColumnCellEvent read FOnDrawColumnTitle write FOnDrawColumnTitle;
  308.     property OnGetGlyph: TGetGlyphEvent read FOnGetGlyph write FOnGetGlyph;
  309.     property WidthOfIndicator: Integer read FWidthOfIndicator write SetIndicatorWidth;
  310.  
  311.     property ScrollBars;
  312.     property ColCount;
  313.     property RowCount;
  314.     property VisibleColCount;
  315.     property VisibleRowCount;
  316.     property Col;
  317.     property Row;
  318.  
  319.     property OnMouseDown;
  320.     property OnMouseUp;
  321.     property OnMouseMove;
  322.   end;
  323.  
  324. procedure Register;
  325.  
  326. implementation
  327. uses RXUtils {ex VCLUtils from RX-Lib}, TypInfo, Registry, DBTables
  328.      {$IFDEF VER140} , Variants
  329.      {$ELSE}
  330.        {$IFDEF VER150} , Variants
  331.        {$ENDIF}
  332.      {$ENDIF}
  333.      ;
  334.  
  335. {$R *.RES}
  336. var
  337.   FCheckWidth, FCheckHeight: Integer;
  338.  
  339. procedure Register;
  340. begin
  341.   RegisterComponents('SMComponents', [TSMDBGrid]);
  342. end;
  343.  
  344.  
  345. { TSMListSortColumns }
  346. function TSMListSortColumns.Add: TSMSortColumn;
  347. begin
  348.   Result := TSMSortColumn.Create;
  349.  
  350.   inherited Add(Result);
  351. end;
  352.  
  353. function TSMListSortColumns.GetColumn(Index: Integer): TSMSortColumn;
  354. begin
  355.   Result := TSMSortColumn(inherited Items[Index]);
  356. end;
  357.  
  358. procedure TSMListSortColumns.SetColumn(Index: Integer; Value: TSMSortColumn);
  359. begin
  360.   Items[Index] := Value;
  361. end;
  362.  
  363. procedure TSMListSortColumns.RebuildColumns(Grid: TSMDBGrid);
  364. var i: Integer;
  365. begin
  366.   if Assigned(Grid) and Assigned(Grid.DataSource) and
  367.     Assigned(Grid.DataSource.DataSet) then
  368.   begin
  369.     Grid.BeginLayout;
  370.     try
  371.       Clear;
  372.       with Grid.DataSource.DataSet do
  373.         for i := 0 to FieldCount-1 do
  374.           Add.FieldName := Fields[i].FieldName
  375.     finally
  376.       Grid.EndLayout;
  377.     end
  378.   end
  379.   else
  380.     Clear;
  381. end;
  382.  
  383.  
  384.  
  385.  
  386.  
  387. type
  388.   TBookmarks = class(TBookmarkList);
  389.   TGridPicture = (gpBlob, gpMemo, gpPicture, gpOle, gpSortAsc, gpSortDesc);
  390.  
  391. const
  392.   GridBmpNames: array[TGridPicture] of PChar = ('SM_BLOB', 'SM_MEMO', 'SM_PICT', 'SM_OLE',
  393.                                                 'SM_ARROWASC', 'SM_ARROWDESC');
  394.   GridBitmaps: array[TGridPicture] of TBitmap = (nil, nil, nil, nil, nil, nil);
  395.   bmMultiDot = 'SM_MSDOT';
  396.   bmMultiArrow = 'SM_MSARROW';
  397.   bmMultiCheckBox = 'SM_MSCHECKBOX';
  398.  
  399. function GetGridBitmap(BmpType: TGridPicture): TBitmap;
  400. begin
  401.   if GridBitmaps[BmpType] = nil then
  402.   begin
  403.     GridBitmaps[BmpType] := TBitmap.Create;
  404.     GridBitmaps[BmpType].Handle := LoadBitmap(HInstance, GridBmpNames[BmpType]);
  405.   end;
  406.   Result := GridBitmaps[BmpType];
  407. end;
  408.  
  409. procedure DestroyLocals; far;
  410. var I: TGridPicture;
  411. begin
  412.   for I := Low(TGridPicture) to High(TGridPicture) do
  413.     GridBitmaps[I].Free;
  414. end;
  415.  
  416. procedure GridInvalidateRow(Grid: TSMDBGrid; Row: Longint);
  417. var I: Longint;
  418. begin
  419.   for I := 0 to Grid.ColCount - 1 do Grid.InvalidateCell(I, Row);
  420. end;
  421.  
  422. procedure GetCheckBoxSize;
  423. begin
  424.   with TBitmap.Create do
  425.     try
  426.       Handle := LoadBitmap(0, PChar(32759));
  427.       FCheckWidth := Width div 4;
  428.       FCheckHeight := Height div 3;
  429.     finally
  430.       Free;
  431.     end;
  432. end;
  433.  
  434. constructor TSMDBGrid.Create(AOwner: TComponent);
  435. var NewItem: TMenuItem;
  436.     j: Integer;
  437.     Bmp: TBitmap;
  438. begin
  439.   inherited Create(AOwner);
  440.  
  441.   SortColumns := TSMListSortColumns.Create;
  442.  
  443.   FRegistryKey := 'Software\MikeSoft';
  444.   FRegistrySection := 'SMDBGrid';
  445.  
  446.   Bmp := TBitmap.Create;
  447.   try
  448.     Bmp.Handle := LoadBitmap(hInstance, bmMultiDot);
  449.     FMsIndicators := TImageList.CreateSize(Bmp.Width, Bmp.Height);
  450.     FMsIndicators.AddMasked(Bmp, clWhite);
  451.     Bmp.Handle := LoadBitmap(hInstance, bmMultiArrow);
  452.     FMsIndicators.AddMasked(Bmp, clWhite);
  453.     Bmp.Handle := LoadBitmap(hInstance, bmMultiCheckBox);
  454.     FMsIndicators.AddMasked(Bmp, clWhite);
  455.  
  456.   finally
  457.     Bmp.Free;
  458.   end;
  459.   FPressedCol := -1;
  460.  
  461.   FDBPopUpMenu := TPopUpMenu.Create(Self {AOwner});
  462.   if not (csDesigning in ComponentState) then
  463.   begin
  464.     for j := 0 to High(PopUpCaption) do
  465.     begin
  466.       NewItem := TMenuItem.Create(Self);
  467.       NewItem.Caption := PopUpCaption[j];
  468.       case j of
  469.         0: NewItem.OnClick := AppendClick;
  470.         1: NewItem.OnClick := InsertClick;
  471.         2: NewItem.OnClick := EditClick;
  472.         3: NewItem.OnClick := DeleteClick;
  473.  
  474.         5: NewItem.OnClick := PrintClick;
  475.         6: NewItem.OnClick := ExportClick;
  476.  
  477.         8: NewItem.OnClick := PostClick;
  478.         9: NewItem.OnClick := CancelClick;
  479.        10: NewItem.OnClick := RefreshClick;
  480.  
  481.        13: NewItem.OnClick := SelectOneClick;
  482.        14: NewItem.OnClick := SelectAllClick;
  483.        16: NewItem.OnClick := UnSelectOneClick;
  484.        17: NewItem.OnClick := UnSelectAllClick;
  485.  
  486.        19: NewItem.OnClick := SaveLayoutClick;
  487.        20: NewItem.OnClick := RestoreLayoutClick;
  488.  
  489.        22: NewItem.OnClick := SetupGridClick;
  490.       end;
  491.       if j in [13, 14, 15, 16, 17] then
  492.         FDBPopUpMenu.Items[12].Add(NewItem)
  493.       else
  494.         FDBPopUpMenu.Items.Add(NewItem);
  495.     end;
  496.   end;
  497. //  PopUpMenu := FDBPopUpMenu;
  498.  
  499.   GetCheckBoxSize;
  500.   FWidthOfIndicator := IndicatorWidth;
  501.  
  502.   FExOptions := [eoENTERlikeTAB, eoKeepSelection, eoStandardPopup];
  503. //  ScrollBars := ssBoth;
  504. //  Color := clInfoBk;
  505. end;
  506.  
  507. destructor TSMDBGrid.Destroy;
  508. begin
  509.   if Assigned(StartOfSelect) then
  510.     DataLink.DataSet.FreeBookmark(StartOfSelect);
  511.  
  512.   SortColumns.Free;
  513.   FDBPopUpMenu.Free;
  514.  
  515.   FMsIndicators.Free;
  516.  
  517.   inherited Destroy;
  518. end;
  519.  
  520. {procedure TSMDBGrid.Paint;
  521. begin
  522.   if ScrollBars in [ssNone, ssHorizontal] then
  523.     SetScrollRange(Self.Handle, SB_VERT, 0, 0, False);
  524.   if ScrollBars in [ssNone, ssVertical] then
  525.     SetScrollRange(Self.Handle, SB_HORZ, 0, 0, False);
  526.  
  527.   inherited Paint;
  528. end;
  529. }
  530.  
  531. {Standard popup menu events}
  532. procedure TSMDBGrid.AppendClick(Sender: TObject);
  533. begin
  534.   if Assigned(FOnAppendRecord) then
  535.     FOnAppendRecord(Sender)
  536.   else
  537.     Datalink.DataSet.Append;
  538. end;
  539.  
  540. procedure TSMDBGrid.InsertClick(Sender: TObject);
  541. begin
  542.   if Assigned(FOnInsertRecord) then
  543.     FOnInsertRecord(Self)
  544.   else
  545.     Datalink.DataSet.Insert;
  546. end;
  547.  
  548. procedure TSMDBGrid.EditClick(Sender: TObject);
  549. begin
  550.   if Assigned(FOnEditRecord) then
  551.     FOnEditRecord(Sender)
  552.   else
  553.     Datalink.DataSet.Edit;
  554. end;
  555.  
  556. procedure TSMDBGrid.DeleteClick(Sender: TObject);
  557. begin
  558.   if Assigned(FOnDeleteRecord) then
  559.     FOnDeleteRecord(Sender)
  560.   else
  561.     DeleteData;
  562. end;
  563.  
  564. procedure TSMDBGrid.PrintClick(Sender: TObject);
  565. begin
  566.   if Assigned(FOnPrintData) then
  567.     FOnPrintData(Sender)
  568. end;
  569.  
  570. procedure TSMDBGrid.ExportClick(Sender: TObject);
  571. begin
  572.   if Assigned(FOnexportData) then
  573.     FOnExportData(Sender)
  574. end;
  575.  
  576. procedure TSMDBGrid.PostClick(Sender: TObject);
  577. begin
  578.   if Assigned(FOnPostData) then
  579.     FOnPostData(Sender)
  580.   else
  581.     Datalink.DataSet.Post;
  582. end;
  583.  
  584. procedure TSMDBGrid.CancelClick(Sender: TObject);
  585. begin
  586.   if Assigned(FOnCancelData) then
  587.     FOnCancelData(Sender)
  588.   else
  589.     Datalink.DataSet.Cancel;
  590. end;
  591.  
  592. procedure TSMDBGrid.RefreshClick(Sender: TObject);
  593. begin
  594.   if Assigned(FOnRefreshData) then
  595.     FOnRefreshData(Sender)
  596.   else
  597.     RefreshData;
  598. end;
  599.  
  600. procedure TSMDBGrid.SetupGridClick(Sender: TObject);
  601. begin
  602.   if Assigned(FOnSetupGrid) then
  603.     FOnSetupGrid(Sender)
  604. end;
  605.  
  606. function TSMDBGrid.GetImageIndex(Field: TField): Integer;
  607. var
  608.   AOnGetText: TFieldGetTextEvent;
  609.   AOnSetText: TFieldSetTextEvent;
  610. begin
  611.   Result := -1;
  612.   if (eoShowGlyphs in FExOptions) and Assigned(Field) then
  613.   begin
  614.     if (not ReadOnly) and Field.CanModify then
  615.     begin
  616.       { Allow editing of memo fields if OnSetText and OnGetText
  617.         events are assigned }
  618.       AOnGetText := Field.OnGetText;
  619.       AOnSetText := Field.OnSetText;
  620.       if Assigned(AOnSetText) and Assigned(AOnGetText) then Exit;
  621.     end;
  622.     case Field.DataType of
  623.       ftBytes, ftVarBytes, ftBlob: Result := Integer(gpBlob);
  624.       ftMemo: Result := Integer(gpMemo);
  625.       ftGraphic: Result := Integer(gpPicture);
  626.       ftTypedBinary: Result := Integer(gpBlob);
  627.       ftFmtMemo: Result := Integer(gpMemo);
  628.       ftParadoxOle, ftDBaseOle: Result := Integer(gpOle);
  629.     end;
  630.   end;
  631. end;
  632.  
  633. function TSMDBGrid.ActiveRowSelected: Boolean;
  634. var Index: Integer;
  635. begin
  636.   Result := False;
  637.   if (dgMultiSelect in Options) and Datalink.Active then
  638.     Result := SelectedRows.Find(Datalink.DataSet.Bookmark, Index);
  639. end;
  640.  
  641. function TSMDBGrid.HighlightCell(DataCol, DataRow: Integer;
  642.   const Value: string; AState: TGridDrawState): Boolean;
  643. begin
  644.   Result := ActiveRowSelected;
  645.   if not Result then
  646.     Result := inherited HighlightCell(DataCol, DataRow, Value, AState);
  647. end;
  648.  
  649. procedure TSMDBGrid.ToggleRowSelection;
  650. begin
  651.   if (dgMultiSelect in Options) and Datalink.Active then
  652.   begin
  653.     with SelectedRows do
  654.       CurrentRowSelected := not CurrentRowSelected;
  655.     if Assigned(FOnChangeSelection) then
  656.       FOnChangeSelection(Self);
  657.   end;
  658. end;
  659.  
  660. procedure TSMDBGrid.GotoSelection(Index: Longint);
  661. begin
  662.   if (dgMultiSelect in Options) and DataLink.Active and (Index < SelectedRows.Count) and (Index >= 0) then
  663.     Datalink.DataSet.GotoBookmark(Pointer(SelectedRows[Index]));
  664. end;
  665.  
  666. {partly is transfered from TBitDBGrid:
  667.  Ilya Andreev, ilya_andreev@geocities.com
  668.  FIDONet: 2:5030/55.28 AKA 2:5030/402.17}
  669. procedure TSMDBGrid.SetTitlesHeight;
  670. var
  671.   i, MaxHeight: Integer;
  672.   RRect: TRect;
  673.   pt: Integer;
  674.   s: string;
  675. begin
  676.   if (dgTitles in Options) then
  677.   begin
  678.     {recalculate a title height}
  679.     MaxHeight := 0;
  680.     for i := 0 to Columns.Count - 1 do
  681.     begin
  682.       RRect := CellRect(0, 0);
  683.       RRect.Right := Columns[i].Width - 1;
  684.       RRect.Left := 0;
  685.       RRect := CellRectForDraw(RRect, i);
  686.  
  687.       Canvas.Font := Columns[i].Title.Font;
  688.       s := Columns[i].Title.Caption;
  689.       pt := Pos('|', s);
  690.       if pt > 0 then
  691.       begin
  692.         while pt <> 0 do
  693.         begin
  694.           s[pt] := #13;
  695.           pt := Pos('|', s);
  696.         end;
  697.         Columns[i].Title.Caption := s;
  698.       end;
  699.  
  700.       MaxHeight := Max(MaxHeight, DrawText(Canvas.Handle,
  701.                        PChar(s),
  702.                        Length(s),
  703.                        RRect,
  704.                        DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK));
  705.     end;
  706.  
  707.     if (MaxHeight <> 0) then
  708.     begin
  709.       if (dgRowLines in Options) then
  710.         Inc(MaxHeight, 3)
  711.       else
  712.         Inc(MaxHeight, 2);
  713.       if (eoTitleButtons in ExOptions) then
  714.         Inc(MaxHeight, 2);
  715.       RowHeights[0] := MaxHeight+4
  716.     end;
  717.   end;
  718. end;
  719. {end of transfered}
  720.  
  721. procedure TSMDBGrid.LayoutChanged;
  722. var ACol: Longint;
  723. begin
  724.   ACol := Col;
  725.   inherited LayoutChanged;
  726.   if Datalink.Active and (FixedCols > 0) then
  727.     Col := Min(Max(inherited FixedCols, ACol), ColCount - 1);
  728.  
  729.   {recalculate a title height}
  730.   SetTitlesHeight;
  731. end;
  732.  
  733. procedure TSMDBGrid.ColWidthsChanged;
  734. var
  735.   ACol: Longint;
  736. begin
  737.   ACol := Col;
  738.   inherited ColWidthsChanged;
  739.   if Datalink.Active and (FixedCols > 0) then
  740.     Col := Min(Max(inherited FixedCols, ACol), ColCount - 1);
  741. end;
  742.  
  743. procedure TSMDBGrid.SetIndicatorWidth(Value: Integer);
  744. var FrameOffs: Byte;
  745. begin
  746.   if (Value <> FWidthOfIndicator) then
  747.   begin
  748.     if ([dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines]) then
  749.       FrameOffs := 1
  750.     else
  751.       FrameOffs := 2;
  752.  
  753.     if (eoCheckBoxSelect in ExOptions) and
  754.        (Value < FCheckWidth + 4*FrameOffs + FMsIndicators.Width) then
  755.       Value := FCheckWidth + 4*FrameOffs + FMsIndicators.Width;
  756.  
  757.     if Value < IndicatorWidth then
  758.       Value := IndicatorWidth;
  759.     FWidthOfIndicator := Value;
  760.  
  761.     SetColumnAttributes
  762.   end;
  763. end;
  764.  
  765. procedure TSMDBGrid.SetColumnAttributes;
  766. begin
  767.   inherited SetColumnAttributes;
  768.  
  769.   if (dgIndicator in Options) then
  770.     ColWidths[0] := WidthOfIndicator;
  771.  
  772.   SetFixedCols(FFixedCols);
  773. end;
  774.  
  775. function TSMDBGrid.GetTitleOffset: Byte;
  776. begin
  777.   Result := 0;
  778.   if dgTitles in Options then
  779.     Inc(Result);
  780. end;
  781.  
  782. procedure TSMDBGrid.SetFixedCols(Value: Integer);
  783. var FixCount, i: Integer;
  784. begin
  785.   FixCount := Max(Value, 0) + IndicatorOffset;
  786.   if DataLink.Active and not (csLoading in ComponentState) and
  787.     (ColCount > IndicatorOffset + 1) then
  788.   begin
  789.     FixCount := Min(FixCount, ColCount - 1);
  790.     inherited FixedCols := FixCount;
  791.     for i := 1 to Min(FixedCols, ColCount - 1) do
  792.       TabStops[i] := False;
  793.   end;
  794.   FFixedCols := FixCount - IndicatorOffset;
  795. end;
  796.  
  797. function TSMDBGrid.GetFixedCols: Integer;
  798. begin
  799.   if DataLink.Active then
  800.     Result := inherited FixedCols - IndicatorOffset
  801.   else
  802.     Result := FFixedCols;
  803. end;
  804.  
  805. procedure TSMDBGrid.SelectOneClick(Sender: TObject);
  806. begin
  807.   if (dgMultiSelect in Options) and Datalink.Active then
  808.   begin
  809.     SelectedRows.CurrentRowSelected := True;
  810.     if Assigned(FOnChangeSelection) then
  811.       FOnChangeSelection(Self);
  812.   end
  813. end;
  814.  
  815. procedure TSMDBGrid.SelectAllClick(Sender: TObject);
  816. var ABookmark: TBookmark;
  817. begin
  818.   if (dgMultiSelect in Options) and DataLink.Active then
  819.   begin
  820.     with Datalink.Dataset do
  821.     begin
  822.       if (BOF and EOF) then Exit;
  823.       DisableControls;
  824.       try
  825.         ABookmark := GetBookmark;
  826.         try
  827.           First;
  828.           while not EOF do
  829.           begin
  830.             SelectedRows.CurrentRowSelected := True;
  831.             Next;
  832.           end;
  833.         finally
  834.           try
  835.             GotoBookmark(ABookmark);
  836.           except
  837.           end;
  838.           FreeBookmark(ABookmark);
  839.         end;
  840.       finally
  841.         if Assigned(FOnChangeSelection) then
  842.           FOnChangeSelection(Self);
  843.         EnableControls;
  844.       end;
  845.     end;
  846.   end;
  847. end;
  848.  
  849. procedure TSMDBGrid.UnSelectOneClick(Sender: TObject);
  850. begin
  851.   if (dgMultiSelect in Options) and Datalink.Active then
  852.   begin
  853.     SelectedRows.CurrentRowSelected := False;
  854.     if Assigned(FOnChangeSelection) then
  855.       FOnChangeSelection(Self);
  856.   end
  857. end;
  858.  
  859. procedure TSMDBGrid.UnSelectAllClick(Sender: TObject);
  860. begin
  861.   if (dgMultiSelect in Options) then
  862.   begin
  863.     SelectedRows.Clear;
  864.     FSelecting := False;
  865.     if Assigned(FOnChangeSelection) then
  866.       FOnChangeSelection(Self);
  867.   end;
  868. end;
  869.  
  870. procedure TSMDBGrid.SaveLayoutClick(Sender: TObject);
  871. begin
  872.   SaveLayoutToRegistry;
  873. end;
  874.  
  875. procedure TSMDBGrid.RestoreLayoutClick(Sender: TObject);
  876. begin
  877.   RestoreLayoutFromRegistry;
  878. end;
  879.  
  880. procedure TSMDBGrid.DeleteData;
  881.  
  882.   function DeletePrompt: Boolean;
  883.   var S: string;
  884.   begin
  885.     if (SelectedRows.Count > 1) then
  886.       S := SDeleteMultipleRecordsQuestion
  887.     else
  888.       S := SDeleteRecordQuestion;
  889.     Result := not (dgConfirmDelete in Options) or
  890.       (MessageDlg(S, mtConfirmation, [mbYes, mbNo], 0) = mrYes);
  891.   end;
  892.  
  893. begin
  894.   if DeletePrompt then
  895.   begin
  896.     if SelectedRows.Count > 0 then
  897.       SelectedRows.Delete
  898.     else
  899.       Datalink.DataSet.Delete;
  900.   end;
  901. end;
  902.  
  903. procedure TSMDBGrid.RefreshData;
  904. var bookPosition: TBookMark;
  905.     boolContinue: Boolean;
  906. begin
  907.   boolContinue := True;
  908.  
  909.   {if needs, save the changed data}
  910.   if Assigned(Datalink.DataSet) then
  911.   begin
  912.      with Datalink.DataSet do
  913.      begin
  914.        if (State in [dsInsert, dsEdit]) and CanModify then Post;
  915.        if (Datalink.DataSet is TBDEDataSet) then
  916.          with (Datalink.DataSet as TBDEDataSet) do
  917.          begin
  918.            if CachedUpdates and UpdatesPending then
  919.              try
  920.                case MessageDlg(strSaveChanges, mtConfirmation, [mbYes, mbNo, mbCancel], 0) of
  921.                  mrYes: ApplyUpdates;
  922.                  mrNo: CancelUpdates;
  923.                  else
  924.                    boolContinue := False;
  925.                end;
  926.              except
  927.                MessageDlg(strErrSaveChanges, mtError, [mbOk], 0);
  928.                boolContinue := False;
  929.              end;
  930.            end;
  931.  
  932.        if boolContinue then
  933.        begin
  934.          {save a current position}
  935.          bookPosition := GetBookmark;
  936.  
  937.          {close and open a dataset}
  938.          Active := False;
  939.          Active := True;
  940.  
  941.          {restore a saved position}
  942.          try
  943.            GotoBookmark(bookPosition);
  944.          except
  945.            First;
  946.          end;
  947.          FreeBookmark(bookPosition);
  948.        end;
  949.      end;
  950.   end;
  951. end;
  952.  
  953. procedure TSMDBGrid.SetExOptions(Val: TExOptions);
  954. var FrameOffs: Byte;
  955. begin
  956.   if (FExOptions <> Val) then
  957.   begin
  958.     FExOptions := Val;
  959.  
  960.  
  961.     if ([dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines]) then
  962.       FrameOffs := 1
  963.     else
  964.       FrameOffs := 2;
  965.  
  966.     if (eoCheckBoxSelect in Val) then
  967.     begin
  968.       if (WidthOfIndicator = IndicatorWidth) then
  969.         WidthOfIndicator := FCheckWidth + 4*FrameOffs + FMsIndicators.Width;
  970.     end
  971.     else
  972.     begin
  973.       if (WidthOfIndicator = FCheckWidth + 4*FrameOffs + FMsIndicators.Width) then
  974.         WidthOfIndicator := IndicatorWidth;
  975.     end;
  976.     Invalidate;
  977.   end;
  978. end;
  979.  
  980. function TSMDBGrid.CanEditShow: Boolean;
  981. begin
  982.   Result := inherited CanEditShow;
  983.  
  984.   if Result and
  985.      (Datalink <> nil) and
  986.      Datalink.Active and
  987.      (FieldCount > 0) and
  988.      (SelectedIndex < FieldCount) and
  989.      (SelectedIndex >= 0) and
  990.      (FieldCount <= DataSource.DataSet.FieldCount) and
  991.      (Fields[SelectedIndex] <> nil) then
  992.     Result := GetImageIndex(Fields[SelectedIndex]) < 0;
  993.   if Result and
  994.      (eoBooleanAsCheckBox in FExOptions) and
  995.      Assigned(Fields[SelectedIndex]) and
  996.      (Fields[SelectedIndex].DataType = ftBoolean) then
  997.     Result := False
  998. end;
  999.  
  1000. function TSMDBGrid.AcquireFocus: Boolean;
  1001. begin
  1002.   Result := True;
  1003.   if FAcquireFocus and CanFocus and not (csDesigning in ComponentState) then
  1004.   begin
  1005.     SetFocus;
  1006.     Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
  1007.   end;
  1008. end;
  1009.  
  1010. function TSMDBGrid.GetOptions: TDBGridOptions;
  1011. begin
  1012.   Result := inherited Options;
  1013.   if FMultiSelect then
  1014.     Result := Result + [dgMultiSelect]
  1015.   else
  1016.     Result := Result - [dgMultiSelect];
  1017. end;
  1018.  
  1019. procedure TSMDBGrid.SetOptions(Value: TDBGridOptions);
  1020. begin
  1021.   inherited Options := Value - [dgMultiSelect];
  1022.  
  1023.   if FMultiSelect <> (dgMultiSelect in Value) then
  1024.   begin
  1025.     FMultiSelect := (dgMultiSelect in Value);
  1026.     if not FMultiSelect then
  1027.       SelectedRows.Clear;
  1028.   end;
  1029. end;
  1030.  
  1031. procedure TSMDBGrid.GetCellProps(Field: TField; AFont: TFont;
  1032.   var Background: TColor; Highlight: Boolean);
  1033. begin
  1034.   if Assigned(FOnGetCellParams) then
  1035.     FOnGetCellParams(Self, Field, AFont, Background, Highlight)
  1036. end;
  1037.  
  1038. procedure TSMDBGrid.CheckTitleButton(ACol: Longint; var Enabled: Boolean);
  1039. begin
  1040.   if (ACol >= 0) and (ACol < Columns.Count) then
  1041.   begin
  1042.     if Assigned(FOnCheckButton) then
  1043.       FOnCheckButton(Self, ACol, Columns[ACol].Field, Enabled);
  1044.   end
  1045.   else
  1046.     Enabled := False;
  1047. end;
  1048.  
  1049. procedure TSMDBGrid.DisableScroll;
  1050. begin
  1051.   Inc(FDisableCount);
  1052. end;
  1053.  
  1054. type
  1055.   THackLink = class(TGridDataLink);
  1056.  
  1057. procedure TSMDBGrid.EnableScroll;
  1058. begin
  1059.   if FDisableCount <> 0 then
  1060.   begin
  1061.     Dec(FDisableCount);
  1062.     if FDisableCount = 0 then
  1063.       THackLink(DataLink).DataSetScrolled(0);
  1064.   end;
  1065. end;
  1066.  
  1067. function TSMDBGrid.ScrollDisabled: Boolean;
  1068. begin
  1069.   Result := FDisableCount <> 0;
  1070. end;
  1071.  
  1072. procedure TSMDBGrid.Scroll(Distance: Integer);
  1073. var IndicatorRect: TRect;
  1074. begin
  1075.   if FDisableCount = 0 then
  1076.   begin
  1077.     inherited Scroll(Distance);
  1078.  
  1079.     if (dgIndicator in Options) and
  1080.        HandleAllocated and
  1081.        (dgMultiSelect in Options) then
  1082.     begin
  1083.       IndicatorRect := BoxRect(0, 0, 0, RowCount - 1);
  1084.       InvalidateRect(Handle, @IndicatorRect, False);
  1085.     end;
  1086.   end;
  1087. end;
  1088.  
  1089. procedure TSMDBGrid.KeyDown(var Key: Word; Shift: TShiftState);
  1090. var
  1091.   KeyDownEvent: TKeyEvent;
  1092.  
  1093.   function ItAddLastRecord: Boolean;
  1094.   begin
  1095.     Result := (eoDisableInsert in FExOptions) and
  1096.               (Datalink.ActiveRecord >= Datalink.RecordCount-1);
  1097.   end;
  1098.  
  1099.   procedure ClearSelections;
  1100.   begin
  1101.     if (dgMultiSelect in Options) then
  1102.     begin
  1103.       if not (eoKeepSelection in ExOptions) then
  1104.       begin
  1105.         SelectedRows.Clear;
  1106.         if Assigned(FOnChangeSelection) then
  1107.           FOnChangeSelection(Self);
  1108.       end;
  1109.       FSelecting := False;
  1110.     end;
  1111.   end;
  1112.  
  1113.   procedure DoSelection(Select: Boolean; Direction: Integer);
  1114.   var
  1115.     AddAfter: Boolean;
  1116.   begin
  1117.     AddAfter := False;
  1118.     BeginUpdate;
  1119.     try
  1120.       if (dgMultiSelect in Options) and DataLink.Active then
  1121.         if Select and (ssShift in Shift) then
  1122.         begin
  1123.           if not FSelecting then
  1124.           begin
  1125.             FSelectionAnchor := TBookmarks(SelectedRows).CurrentRow;
  1126.             SelectedRows.CurrentRowSelected := True;
  1127.             if Assigned(FOnChangeSelection) then
  1128.               FOnChangeSelection(Self);
  1129.             FSelecting := True;
  1130.             AddAfter := True;
  1131.           end
  1132.           else
  1133.             with TBookmarks(SelectedRows) do
  1134.             begin
  1135.               AddAfter := Compare(CurrentRow, FSelectionAnchor) <> -Direction;
  1136.               if not AddAfter then
  1137.               begin
  1138.                 CurrentRowSelected := False;
  1139.                 if Assigned(FOnChangeSelection) then
  1140.                   FOnChangeSelection(Self);
  1141.               end
  1142.             end
  1143.         end
  1144.         else
  1145.           ClearSelections;
  1146.       if Direction <> 0 then
  1147.         Datalink.DataSet.MoveBy(Direction);
  1148.       if AddAfter then
  1149.       begin
  1150.         SelectedRows.CurrentRowSelected := True;
  1151.         if Assigned(FOnChangeSelection) then
  1152.           FOnChangeSelection(Self);
  1153.       end;
  1154.     finally
  1155.       EndUpdate;
  1156.     end;
  1157.   end;
  1158.  
  1159.   procedure NextRow(Select: Boolean);
  1160.   begin
  1161.     with Datalink.Dataset do begin
  1162.       DoSelection(Select, 1);
  1163.       if EOF and CanModify and (not ReadOnly) and (dgEditing in Options) and
  1164.          not ItAddLastRecord then
  1165.         AppendClick(Self);
  1166.     end;
  1167.   end;
  1168.  
  1169.   procedure PriorRow(Select: Boolean);
  1170.   begin
  1171.     DoSelection(Select, -1);
  1172.   end;
  1173.  
  1174.   procedure CheckTab(GoForward: Boolean);
  1175.   var ACol, Original: Integer;
  1176.   begin
  1177.     ACol := Col;
  1178.     Original := ACol;
  1179.     if (dgMultiSelect in Options) and DataLink.Active then
  1180.       while True do
  1181.       begin
  1182.         if GoForward then
  1183.           Inc(ACol)
  1184.         else
  1185.           Dec(ACol);
  1186.         if ACol >= ColCount then
  1187.         begin
  1188.           ClearSelections;
  1189.           ACol := IndicatorOffset;
  1190.         end
  1191.         else
  1192.           if ACol < IndicatorOffset then
  1193.           begin
  1194.             ClearSelections;
  1195.             ACol := ColCount;
  1196.           end;
  1197.         if ACol = Original then Exit;
  1198.         if TabStops[ACol] then Exit;
  1199.       end;
  1200.   end;
  1201.  
  1202. const
  1203.   RowMovementKeys = [VK_UP, VK_PRIOR, VK_DOWN, VK_NEXT, VK_HOME, VK_END];
  1204.  
  1205. begin
  1206.   KeyDownEvent := OnKeyDown;
  1207.   if Assigned(KeyDownEvent) then
  1208.     KeyDownEvent(Self, Key, Shift);
  1209.   if not Datalink.Active or not CanGridAcceptKey(Key, Shift) then Exit;
  1210.   with Datalink.DataSet do
  1211.     if ssCtrl in Shift then
  1212.     begin
  1213.       if (Key in RowMovementKeys) then
  1214.         ClearSelections;
  1215.  
  1216.       case Key of
  1217.         VK_LEFT: if FixedCols > 0 then
  1218.                  begin
  1219.                    SelectedIndex := FixedCols;
  1220.                    Exit;
  1221.                  end;
  1222.         VK_DELETE: begin
  1223.                      if (eoDisableDelete in FExOptions) then Exit;
  1224.                      if not ReadOnly and CanModify then
  1225.                      begin
  1226.                        DeleteClick(nil);
  1227.                        Exit;
  1228.                      end;
  1229.                    end;
  1230.       end
  1231.     end
  1232.     else
  1233.     begin
  1234.       case Key of
  1235.         VK_LEFT: if (FixedCols > 0) and not (dgRowSelect in Options) then
  1236.                  begin
  1237.                    if SelectedIndex <= FFixedCols then Exit;
  1238.                  end;
  1239.         VK_HOME: if (FixedCols > 0) and (ColCount <> IndicatorOffset + 1) and
  1240.                     not (dgRowSelect in Options) then
  1241.                  begin
  1242.                    SelectedIndex := FixedCols;
  1243.                    Exit;
  1244.                  end;
  1245.         VK_SPACE: if (eoBooleanAsCheckbox in FExOptions) and
  1246.                      (Datalink <> nil) and Datalink.Active and
  1247.                      (Columns[SelectedIndex].Field.DataType = ftBoolean) then
  1248.                     CellClick(Columns[SelectedIndex]);
  1249.       end;
  1250.       case Key of
  1251.         VK_DOWN: begin
  1252.                    NextRow(True);
  1253.                    Exit;
  1254.                  end;
  1255.         VK_INSERT: if (eoDisableInsert in FExOptions) then Exit;
  1256.         VK_UP: begin
  1257.                  PriorRow(True);
  1258.                  Exit;
  1259.                end;
  1260.         13:  if (eoENTERlikeTAB in FExOptions)  then
  1261.                  {going on next column}
  1262.                if (SelectedIndex < Columns.Count-1) then
  1263.                  SelectedIndex := SelectedIndex + 1
  1264.                else
  1265.                  SelectedIndex := 0;
  1266.       end;
  1267.       if ((Key in [VK_LEFT, VK_RIGHT]) and (dgRowSelect in Options)) or
  1268.          ((Key in [VK_HOME, VK_END]) and ((ColCount = IndicatorOffset + 1)
  1269.           or (dgRowSelect in Options))) or (Key in [VK_ESCAPE, VK_NEXT,
  1270.           VK_PRIOR]) or ((Key = VK_INSERT) and (CanModify and
  1271.           (not ReadOnly) and (dgEditing in Options))) then
  1272.         ClearSelections
  1273.       else
  1274.         if ((Key = VK_TAB) and not (ssAlt in Shift)) then
  1275.           CheckTab(not (ssShift in Shift));
  1276.     end;
  1277.   OnKeyDown := nil;
  1278. //  try
  1279.     inherited KeyDown(Key, Shift);
  1280. //  except
  1281. //  end;
  1282.   OnKeyDown := KeyDownEvent;
  1283. end;
  1284.  
  1285. procedure TSMDBGrid.TopLeftChanged;
  1286. begin
  1287.   if (dgRowSelect in Options) and DefaultDrawing then
  1288.     GridInvalidateRow(Self, Self.Row);
  1289.  
  1290.   inherited TopLeftChanged;
  1291.   if FTracking then StopTracking;
  1292. end;
  1293.  
  1294. procedure TSMDBGrid.StopTracking;
  1295. begin
  1296.   if FTracking then
  1297.   begin
  1298.     TrackButton(-1, -1);
  1299.     FTracking := False;
  1300.     MouseCapture := False;
  1301.   end;
  1302. end;
  1303.  
  1304. procedure TSMDBGrid.TrackButton(X, Y: Integer);
  1305. var
  1306.   Cell: TGridCoord;
  1307.   NewPressed: Boolean;
  1308. begin
  1309.   Cell := MouseCoord(X, Y);
  1310.   NewPressed := PtInRect(Rect(0, 0, ClientWidth, ClientHeight), Point(X, Y))
  1311.     and (FPressedCol = Cell.X) and (Cell.Y = 0);
  1312.   if FPressed <> NewPressed then
  1313.   begin
  1314.     FPressed := NewPressed;
  1315.     GridInvalidateRow(Self, 0);
  1316.   end;
  1317. end;
  1318.  
  1319. procedure TSMDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1320.  
  1321.   procedure SetEnabledItems;
  1322.   begin
  1323.     with FDBPopUpMenu do
  1324.     begin
  1325.       {Append}
  1326.       if Assigned(Datalink.DataSet) then
  1327.         Items[0].Enabled := not (eoDisableInsert in FExOptions) and
  1328.                             (not ReadOnly) and
  1329.                             Datalink.DataSet.CanModify and
  1330.                             (Datalink.DataSet.State = dsBrowse)
  1331.       else
  1332.         Items[0].Enabled := False;
  1333.  
  1334.       {Insert}
  1335.       Items[1].Enabled := Items[0].Enabled;
  1336.  
  1337.       {Edit}
  1338.       if Assigned(Datalink.DataSet) then
  1339.         Items[2].Enabled := not ReadOnly and
  1340.                             Datalink.DataSet.CanModify and
  1341.                             (Datalink.DataSet.State = dsBrowse)
  1342. //                          and (Datalink.DataSet.RecordCount > 0)
  1343.       else
  1344.         Items[2].Enabled := False;
  1345.  
  1346.       {Delete}
  1347.       if Assigned(Datalink.DataSet) then
  1348.         Items[3].Enabled := (not (eoDisableDelete in FExOptions)) and
  1349.                             (not ReadOnly) and
  1350.                             Datalink.DataSet.CanModify and
  1351.                             (Datalink.DataSet.State = dsBrowse)
  1352. //                             and (Datalink.DataSet.RecordCount > 0)
  1353.       else
  1354.         Items[3].Enabled := False;
  1355.  
  1356.       {Print}
  1357.       Items[5].Enabled := True;
  1358.       Items[5].Visible := Assigned(FOnPrintData);
  1359.       if Assigned(Datalink.DataSet) then
  1360.         Items[5].Enabled := (Datalink.DataSet.State = dsBrowse) and Assigned(FOnPrintData)
  1361.       else
  1362.         Items[5].Enabled := False;
  1363.  
  1364.       {Export}
  1365.       Items[6].Enabled := True;
  1366.       Items[6].Visible := Assigned(FOnExportData);
  1367.       if Assigned(Datalink.DataSet) then
  1368.         Items[6].Enabled := (Datalink.DataSet.State = dsBrowse) and Assigned(FOnExportData)
  1369.       else
  1370.         Items[6].Enabled := False;
  1371.  
  1372.       Items[7].Visible := Items[5].Visible or Items[6].Visible;
  1373.  
  1374.       {Post}
  1375.       if Assigned(Datalink.DataSet) then
  1376.         Items[8].Enabled := (not ReadOnly) and
  1377.                             (Datalink.DataSet.State in [dsInsert, dsEdit]) and
  1378.                             Datalink.DataSet.CanModify
  1379.       else
  1380.         Items[8].Enabled := False;
  1381.  
  1382.       {Cancel}
  1383.       if Assigned(Datalink.DataSet) then
  1384.         Items[9].Enabled := (not ReadOnly) and
  1385.                             (Datalink.DataSet.State in [dsInsert, dsEdit])
  1386.       else
  1387.         Items[9].Enabled := False;
  1388.  
  1389.       {Refresh}
  1390.       if Assigned(Datalink.DataSet) then
  1391.         Items[10].Enabled := (Datalink.DataSet.State = dsBrowse)
  1392.       else
  1393.         Items[10].Enabled := False;
  1394.  
  1395.       {select/unselect}
  1396.       Items[12].Enabled := Assigned(Datalink.DataSet) and
  1397.                            Datalink.DataSet.Active and
  1398.                            (dgMultiSelect in Options);
  1399.  
  1400.       {save/restore layout}
  1401.       Items[14].Enabled := True;
  1402.       Items[15].Enabled := True;
  1403.  
  1404.       Items[13].Visible := (eoLayout in ExOptions);
  1405.       Items[14].Visible := (eoLayout in ExOptions);
  1406.       Items[15].Visible := (eoLayout in ExOptions);
  1407.       Items[14].Enabled := (eoLayout in ExOptions);
  1408.       Items[15].Enabled := (eoLayout in ExOptions);
  1409.  
  1410.       {setup of the grid}
  1411.       Items[17].Enabled := True;
  1412.       Items[17].Visible := Assigned(FOnSetupGrid);
  1413.       if Assigned(Datalink.DataSet) then
  1414.         Items[17].Enabled := Assigned(FOnSetupGrid)
  1415.       else
  1416.         Items[17].Enabled := False;
  1417.       Items[16].Visible := Items[17].Visible;
  1418.     end;
  1419.   end;
  1420.  
  1421. var
  1422.   Cell: TGridCoord;
  1423.   MouseDownEvent: TMouseEvent;
  1424.   EnableClick: Boolean;
  1425.   PopCoord: TPoint;
  1426. begin
  1427.   if not AcquireFocus then Exit;
  1428.   if (ssDouble in Shift) and (Button = mbLeft) then
  1429.   begin
  1430.     DblClick;
  1431.     Exit;
  1432.   end;
  1433.  
  1434.   if (dgMultiSelect in Options) then
  1435.     StartOfSelect := DataLink.DataSet.GetBookmark;
  1436.  
  1437.   if Sizing(X, Y) then
  1438.     inherited MouseDown(Button, Shift, X, Y)
  1439.   else
  1440.   begin
  1441.     Cell := MouseCoord(X, Y);
  1442.  
  1443.     if not (csDesigning in ComponentState) and
  1444.        (eoStandardPopup in FExOptions) and
  1445.        ((dgIndicator in Options) and
  1446.         (Cell.Y < TitleOffset) and
  1447.         (Cell.X < IndicatorOffset) or
  1448.         ((Button = mbRight) and (Cell.X >= IndicatorOffset) and not Assigned(PopupMenu))) then
  1449.     begin
  1450.       SetEnabledItems;
  1451.       PopCoord := ClientToScreen(Point(X, Y));
  1452.       FDBPopUpMenu.Popup(PopCoord.X, PopCoord.Y);
  1453.     end
  1454.     else
  1455.       if (eoTitleButtons in ExOptions) and
  1456.          (Datalink <> nil) and Datalink.Active and
  1457.          (Cell.Y < TitleOffset) and (Cell.X >= IndicatorOffset) and
  1458.           not (csDesigning in ComponentState) then
  1459.       begin
  1460.         if (dgColumnResize in Options) and (Button = mbRight) then
  1461.         begin
  1462.           Button := mbLeft;
  1463.           FSwapButtons := True;
  1464.           MouseCapture := True;
  1465.         end
  1466.         else
  1467.           if (Button = mbLeft) then
  1468.           begin
  1469.             EnableClick := True;
  1470.             CheckTitleButton(Cell.X - IndicatorOffset, EnableClick);
  1471.             if EnableClick then
  1472.             begin
  1473.               MouseCapture := True;
  1474.               FTracking := True;
  1475.               FPressedCol := Cell.X;
  1476.               TrackButton(X, Y);
  1477.             end
  1478.             else
  1479.               Beep;
  1480.             Exit;
  1481.           end;
  1482.       end;
  1483.     if (Cell.X < FixedCols + IndicatorOffset) and Datalink.Active then
  1484.     begin
  1485.       if (dgIndicator in Options) then
  1486.         inherited MouseDown(Button, Shift, 1, Y)
  1487.       else
  1488.         if Cell.Y >= TitleOffset then
  1489.           if Cell.Y - Row <> 0 then
  1490.             Datalink.Dataset.MoveBy(Cell.Y - Row);
  1491.     end
  1492.     else
  1493.       inherited MouseDown(Button, Shift, X, Y);
  1494.     MouseDownEvent := OnMouseDown;
  1495.     if Assigned(MouseDownEvent) then
  1496.       MouseDownEvent(Self, Button, Shift, X, Y);
  1497.     if not (((csDesigning in ComponentState) or (dgColumnResize in Options)) and
  1498.       (Cell.Y < TitleOffset)) and (Button = mbLeft) then
  1499.     begin
  1500.       if (dgMultiSelect in Options) and Datalink.Active then
  1501.         with SelectedRows do
  1502.         begin
  1503.           FSelecting := False;
  1504.           if ssCtrl in Shift then
  1505.           begin
  1506.             CurrentRowSelected := not CurrentRowSelected;
  1507.             if Assigned(FOnChangeSelection) then
  1508.               FOnChangeSelection(Self);
  1509.           end
  1510.           else
  1511.             if not (eoKeepSelection in ExOptions) then
  1512.             begin
  1513.               Clear;
  1514.               CurrentRowSelected := True;
  1515.               if Assigned(FOnChangeSelection) then
  1516.                 FOnChangeSelection(Self);
  1517.             end
  1518.         end;
  1519.     end;
  1520.   end;
  1521. end;
  1522.  
  1523. procedure TSMDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1524. var
  1525.   Cell: TGridCoord;
  1526.   ACol: Longint;
  1527.   DoClick: Boolean;
  1528.  
  1529.   EndOfSelect, Test: TBookmark;
  1530.   SelectForwards: Boolean;
  1531.   CompareStart: Integer;
  1532. begin
  1533.   {for shoft+click selection
  1534.   Thanks to Roy Lambert [roy.lambert@ntlworld.com]}
  1535.   if (dgMultiSelect in Options) and
  1536.      (ssShift in Shift) and
  1537.      Assigned(StartOfSelect) then
  1538.   begin
  1539.     DataLink.DataSet.DisableControls;
  1540.     EndOfSelect := DataLink.DataSet.GetBookmark;
  1541.     DataLink.DataSet.GotoBookmark(StartOfSelect);
  1542.     CompareStart := DataLink.DataSet.CompareBookmarks(EndOfSelect, StartOfSelect);
  1543.     if CompareStart <> 0 then
  1544.     begin
  1545.       SelectForwards := CompareStart > 0;
  1546.       repeat
  1547.         SelectedRows.CurrentRowSelected := True;
  1548.         Test := DataLink.DataSet.GetBookmark;
  1549.         if SelectForwards then
  1550.           DataLink.DataSet.Next
  1551.         else
  1552.           DataLink.DataSet.Prior;
  1553.       until (DataLink.DataSet.CompareBookmarks(EndOfSelect, Test) = 0) or DataLink.DataSet.Eof or DataLink.DataSet.Bof;
  1554.     end;
  1555.     DataLink.DataSet.GotoBookmark(EndOfSelect);
  1556.     if Assigned(EndOfSelect) then
  1557.       DataLink.DataSet.FreeBookmark(EndOfSelect);
  1558.     if Assigned(Test) then
  1559.       DataLink.DataSet.FreeBookmark(Test);
  1560.     DataLink.DataSet.EnableControls;
  1561.   end;
  1562.  
  1563.   Cell := MouseCoord(X, Y);
  1564.   ACol := Cell.X;
  1565.   if (dgIndicator in Options) then
  1566.     Dec(ACol);
  1567.  
  1568.   if FTracking and (FPressedCol >= 0) then
  1569.   begin
  1570.     DoClick := PtInRect(Rect(0, 0, ClientWidth, ClientHeight), Point(X, Y))
  1571.       and (Cell.Y = 0) and (Cell.X = FPressedCol);
  1572.     StopTracking;
  1573.     if DoClick then
  1574.     begin
  1575.       if (DataLink <> nil) and
  1576.          DataLink.Active and
  1577.          (ACol >= 0) and
  1578.          (ACol < Columns.Count) then
  1579.       else
  1580.         CellClick(Columns[ACol]);
  1581.     end;
  1582.   end
  1583.   else
  1584.     if FSwapButtons then
  1585.     begin
  1586.       FSwapButtons := False;
  1587.       MouseCapture := False;
  1588.       if Button = mbRight then
  1589.         Button := mbLeft;
  1590.     end;
  1591.  
  1592.   if (eoCheckBoxSelect in ExOptions) and
  1593.      (dgMultiSelect in Options) and
  1594.      (Cell.X < IndicatorOffset) and
  1595.      (Cell.Y >= 0) then
  1596.     ToggleRowSelection;
  1597.  
  1598.   if (Button = mbLeft) and
  1599.      (Cell.X >= IndicatorOffset) and
  1600.      (ACol <= FixedCols) and
  1601.      (Cell.Y > TitleOffset) then
  1602.     CellClick(Columns[ACol])
  1603.   else
  1604.     inherited MouseUp(Button, Shift, X, Y);
  1605. end;
  1606.  
  1607. {from Borland sources}
  1608. procedure WriteTitleText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
  1609.   const Text: string; Alignment: TAlignment);
  1610. const
  1611.   AlignFlags: array [TAlignment] of Integer =
  1612.      (DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
  1613.       DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
  1614.       DT_CENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX);
  1615. var
  1616.   B, R, rect1: TRect;
  1617.   txth: Integer;
  1618.   {$IFDEF VER120}
  1619.   I: TColorRef;
  1620.   {$ELSE}
  1621.     {$IFDEF VER130}
  1622.     I: TColorRef;
  1623.     {$ELSE}
  1624.       {$IFDEF VER140}
  1625.       I: TColorRef;
  1626.       {$ELSE}
  1627.         {$IFDEF VER150}
  1628.         I: TColorRef;
  1629.         {$ELSE}
  1630.         I: Integer;
  1631.         {$ENDIF}
  1632.       {$ENDIF}
  1633.     {$ENDIF}
  1634.   {$ENDIF}
  1635.  
  1636.   lpDTP: TDrawTextParams;
  1637.   DrawBitmap: TBitmap;
  1638. begin
  1639.   I := ColorToRGB(ACanvas.Brush.Color);
  1640.   if GetNearestColor(ACanvas.Handle, I) = I then
  1641.   begin
  1642.     ACanvas.FillRect(ARect);
  1643.  
  1644.     rect1.Left := 0;
  1645.     rect1.Top := 0;
  1646.     rect1.Right := 0;
  1647.     rect1.Bottom := 0;
  1648.     rect1 := ARect;
  1649.  
  1650.     lpDTP.cbSize := SizeOf(lpDTP);
  1651.     lpDTP.uiLengthDrawn := Length(Text);
  1652.     lpDTP.iLeftMargin := 0;
  1653.     lpDTP.iRightMargin := 0;
  1654.  
  1655.     InflateRect(rect1, -DX, -DY);
  1656.  
  1657.     txth := DrawTextEx(ACanvas.Handle,PChar(Text), Length(Text),
  1658.                        rect1, DT_WORDBREAK or DT_CALCRECT, @lpDTP);
  1659.  
  1660.     rect1 := ARect;
  1661.     InflateRect(rect1, -DX, -DY);
  1662.  
  1663.     rect1.top := rect1.top + ((rect1.Bottom-rect1.top) div 2) - (txth div 2);
  1664.     DrawTextEx(ACanvas.Handle, PChar(Text), Length(Text),
  1665.                rect1, AlignFlags[Alignment], @lpDTP);
  1666.   end
  1667.   else
  1668.   begin
  1669.     DrawBitmap := TBitmap.Create;
  1670.     DrawBitmap.Canvas.Lock;
  1671.     try
  1672.       with DrawBitmap, ARect do
  1673.       begin
  1674.         Width := Max(Width, Right - Left);
  1675.         Height := Max(Height, Bottom - Top);
  1676.         R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
  1677.         B := Rect(0, 0, Right - Left, Bottom - Top);
  1678.       end;
  1679.       with DrawBitmap.Canvas do
  1680.       begin
  1681.         Font := ACanvas.Font;
  1682.         Font.Color := ACanvas.Font.Color;
  1683.         Brush := ACanvas.Brush;
  1684.         Brush.Style := bsSolid;
  1685.         FillRect(B);
  1686.         SetBkMode(Handle, TRANSPARENT);
  1687.         DrawText(Handle, PChar(Text), Length(Text), R, AlignFlags[Alignment]);
  1688.       end;
  1689.       ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
  1690.     finally
  1691.       DrawBitmap.Canvas.Unlock;
  1692.       DrawBitmap.Free;
  1693.     end;
  1694.   end;
  1695. end;
  1696.  
  1697. procedure TSMDBGrid.CellClick(Column: TColumn);
  1698. var R: TRect;
  1699.     BCol: Integer;
  1700. begin
  1701.   inherited CellClick(Column);
  1702.  
  1703.   if (Datalink <> nil) and
  1704.      Datalink.Active and
  1705.      Assigned(Column.Field) and
  1706.      (Column.Field.DataType = ftBoolean) and
  1707.      (eoBooleanAsCheckBox in FExOptions) and
  1708.      CanEditModify then
  1709.   begin
  1710.     try
  1711.       Column.Field.AsBoolean := not Column.Field.AsBoolean;
  1712. //      Column.Field.Value := not Column.Field.Value;
  1713.     except
  1714.       Column.Field.Value := NULL;
  1715.     end;
  1716.  
  1717.     if (dgIndicator in Options) then
  1718.       BCol := Column.Index + 1
  1719.     else
  1720.       BCol := Column.Index;
  1721.     GetEditText(BCol, Row);
  1722.  
  1723.     R := CellRect(BCol, Row);
  1724.     DrawCell(BCol, Row, R, [{gdSelected, gdFocused}]);
  1725.   end
  1726.   else
  1727.     if (eoShowLookup in ExOptions) and
  1728.        (not ReadOnly) and
  1729.        (dgEditing in Options) and
  1730.        (not Column.ReadOnly) and
  1731.        Assigned(Column.Field) and
  1732.        (not Column.Field.ReadOnly) then
  1733.     begin
  1734.       if (Column.Field.FieldKind = fkLookup) or
  1735.           (Column.PickList.Count > 0) then
  1736.       begin {Open combobox quickly when lookup field}
  1737.         keybd_event(VK_F2, 0, 0, 0);
  1738.         keybd_event(VK_F2, 0, KEYEVENTF_KEYUP, 0);
  1739.         keybd_event(VK_MENU, 0, 0, 0);
  1740.         keybd_event(VK_DOWN, 0, 0, 0);
  1741.         keybd_event(VK_DOWN, 0, KEYEVENTF_KEYUP, 0);
  1742.         keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
  1743.       end
  1744.       else
  1745.         if (Column.ButtonStyle = cbsEllipsis) then
  1746.         begin {Click quickly when ButtonStyle property is cbsEllipsis}
  1747.           if not EditorMode then
  1748.             EditorMode := True;
  1749.           EditButtonClick;
  1750.         end;
  1751.     end;
  1752. end;
  1753.  
  1754. function TSMDBGrid.GetSortImageWidth: Integer;
  1755. begin
  1756.   Result := Max(GetGridBitmap(gpSortAsc).Width, GetGridBitmap(gpSortDesc).Width);
  1757. end;
  1758.  
  1759. function TSMDBGrid.CellRectForDraw(R: TRect; ACol: Longint): TRect;
  1760. var i, j: Integer;
  1761. begin
  1762.   Result := R;
  1763.  
  1764.   j := GetSortImageWidth;
  1765.   if (Result.Right-Result.Left > j+4) then
  1766.   begin
  1767.     for i := 0 to SortColumns.Count-1 do
  1768.       if (SortColumns[i].FieldName = Columns[ACol].FieldName) and
  1769.          (SortColumns[i].SortType <> stNone) then
  1770.         break;
  1771.     if (i < SortColumns.Count) then
  1772.       Result.Right := Result.Right-j-4;
  1773.   end;
  1774.   i := 2*(GridLineWidth+1)+1;
  1775.   Result.Right := Result.Right-i
  1776. end;
  1777.  
  1778. function TSMDBGrid.GetGlyph: TBitmap;
  1779. begin
  1780.   Result := nil;
  1781.   if Assigned(FOnGetGlyph) then
  1782.     FOnGetGlyph(Self, Result);
  1783. end;
  1784.  
  1785. procedure TSMDBGrid.DrawCheckBox(R: TRect; AState: TCheckBoxState; al: TAlignment);
  1786. var
  1787.   DrawState: Integer;
  1788.   DrawRect: TRect;
  1789. begin
  1790.   {draw CheckBox instead Bitmap indicator}
  1791. {        Canvas.Brush.Color := FixedColor;
  1792.         Canvas.Font.Name := 'Symbol';
  1793.         Canvas.Font.Color := clWindowText;
  1794.         Canvas.Font.Style := [fsBold];
  1795.         WriteTitleText(Canvas, FixRect, 0, 0, '╓', taCenter);
  1796. }
  1797.  
  1798.   case AState of
  1799.     cbChecked: DrawState := DFCS_BUTTONCHECK or DFCS_CHECKED;
  1800.     cbUnchecked: DrawState := DFCS_BUTTONCHECK;
  1801.     else // cbGrayed
  1802.       DrawState := DFCS_BUTTON3STATE or DFCS_CHECKED;
  1803.   end;
  1804.   case al of
  1805.     taRightJustify: begin
  1806.                       DrawRect.Left := R.Right - FCheckWidth;
  1807.                       DrawRect.Right := R.Right;
  1808.                     end;
  1809.     taCenter: begin
  1810.                 DrawRect.Left := R.Left + (R.Right - R.Left - FCheckWidth) div 2;
  1811.                 DrawRect.Right := DrawRect.Left + FCheckWidth;
  1812.               end;
  1813.   else // taLeftJustify
  1814.     DrawRect.Left := R.Left;
  1815.     DrawRect.Right := DrawRect.Left + FCheckWidth;
  1816.   end;
  1817.   DrawRect.Top := R.Top + (R.Bottom - R.Top - FCheckWidth) div 2;
  1818.   DrawRect.Bottom := DrawRect.Top + FCheckHeight;
  1819.  
  1820.   DrawFrameControl(Canvas.Handle, DrawRect, DFC_BUTTON, DrawState);
  1821. end;
  1822.  
  1823. procedure TSMDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
  1824. var
  1825.   TitleText: string;
  1826.   i, j, idxSort, BCol: LongInt;
  1827.   CheckState: TCheckBoxState;
  1828.  
  1829.   Down: Boolean;
  1830.   SavePen, BackColor: TColor;
  1831.   AField: TField;
  1832.   OldActive: Longint;
  1833.   FrameOffs: Byte;
  1834. //  Indicator: Integer;
  1835. //  MultiSelected: Boolean;
  1836.   BRect, FixRect: TRect;
  1837.   DrawColumn: TColumn;
  1838.   bmp: TBitmap;
  1839. const
  1840.   EdgeFlag: array[Boolean] of UINT = (BDR_RAISEDINNER, BDR_SUNKENINNER);
  1841.  
  1842. begin
  1843.   if (dgIndicator in Options) then
  1844.     BCol := ACol - 1
  1845.   else
  1846.     BCol := ACol;
  1847.  
  1848.   if (gdFixed in AState) and (ARow = 0) and (dgTitles in Options) and
  1849.      ((ACol <> 0) or ((ACol = 0) and (dgIndicator in Options) and (eoStandardPopup in FExOptions))) then
  1850.   begin
  1851.     // draw border
  1852.     if DefaultDrawing then
  1853.     begin
  1854.       if (ACol = 0) and (dgIndicator in Options) then
  1855.       begin
  1856.         Down := False;
  1857.         Canvas.Brush.Color := FixedColor
  1858.       end
  1859.       else
  1860.       begin
  1861.         Down := (eoSelectedTitle in FExOptions) and (BCol = SelectedIndex);
  1862.         if (BCol > -1) and Assigned(Columns[BCol]) then
  1863.           Canvas.Brush.Color := Columns[BCol].Title.Color;
  1864.       end;
  1865.       DrawEdge(Canvas.Handle, ARect, EdgeFlag[Down], BF_BOTTOMLEFT);
  1866.       DrawEdge(Canvas.Handle, ARect, EdgeFlag[Down], BF_TOPRIGHT);
  1867.  
  1868.       InflateRect(ARect, -1, -1);
  1869.       Canvas.FillRect(ARect);
  1870.     end;
  1871.  
  1872.     j := GetSortImageWidth;
  1873.     if (ACol = 0) and
  1874.        (dgIndicator in Options) and
  1875.        (eoStandardPopup in FExOptions) then
  1876.     begin
  1877.       Canvas.Brush.Color := clBlack;
  1878.       i := (ARect.Bottom - ARect.Top - 7) div 2;
  1879.       idxSort := (ARect.Right - ARect.Left - 7) div 2;
  1880.       Canvas.Polygon([Point(ARect.Left + idxSort, ARect.Top + i),
  1881.                       Point(ARect.Left + idxSort + 7, ARect.Top + i),
  1882.                       Point(ARect.Left + idxSort + (7 div 2), ARect.Bottom - i)]);
  1883.     end
  1884.     else
  1885.       if (BCol > -1) and Assigned(Columns[BCol]) then
  1886.       begin
  1887.         TitleText := Columns[BCol].Title.Caption;
  1888.  
  1889.         {draw a column sorted image}
  1890.         //look: whether there is a sorting according this column
  1891.         idxSort := -1;
  1892.         if (ARect.Right-ARect.Left > j) then
  1893.         begin
  1894.           for i := 0 to SortColumns.Count-1 do
  1895.             if (SortColumns[i].FieldName = Columns[BCol].FieldName) and
  1896.                (SortColumns[i].SortType <> stNone) then
  1897.             begin
  1898.               idxSort := i;
  1899.               break
  1900.             end;
  1901.           if idxSort > -1 then
  1902.             ARect.Right := ARect.Right-j;
  1903.         end;
  1904.  
  1905.         //draw title.caption
  1906.         if DefaultDrawing  and (TitleText <> '') then
  1907.         begin
  1908.           Canvas.Brush.Style := bsClear;
  1909.           Canvas.Font := Columns[BCol].Title.Font;
  1910.           Canvas.Brush.Color := Columns[BCol].Title.Color;
  1911.           WriteTitleText(Canvas, ARect, 2, 2, TitleText, Columns[BCol].Title.Alignment);
  1912.  
  1913.           if idxSort > -1 then
  1914.           begin
  1915.             ARect.Right := ARect.Right+j;
  1916.  
  1917.             i := (ARect.Bottom - ARect.Top - j) div 2;
  1918.             if (SortColumns[idxSort].SortType = stAscending) then
  1919.             begin
  1920.               Bmp := GetGridBitmap(gpSortAsc);
  1921. {              Canvas.Pen.Color := clBtnShadow;
  1922.               Canvas.MoveTo(ARect.Right - 4, ARect.Top + i);
  1923.               Canvas.LineTo(ARect.Right - 4 - j, ARect.Top + i);
  1924.               Canvas.LineTo(ARect.Right - 4 - (j div 2), ARect.Bottom - i);
  1925.  
  1926.               Canvas.Pen.Color := clBtnHighlight;
  1927.               Canvas.LineTo(ARect.Right - 4, ARect.Top + i);
  1928. }
  1929.             end
  1930.             else
  1931.             begin
  1932.               Bmp := GetGridBitmap(gpSortDesc);
  1933. {              Canvas.Pen.Color := clBtnHighlight;
  1934.               Canvas.MoveTo(ARect.Right - 4 - (j div 2), ARect.Top + i);
  1935.               Canvas.LineTo(ARect.Right - 4, ARect.Bottom - i);
  1936.               Canvas.LineTo(ARect.Right - 4 - j, ARect.Bottom - i);
  1937.  
  1938.               Canvas.Pen.Color := clBtnShadow;
  1939.               Canvas.LineTo(ARect.Right - 4 - (j div 2), ARect.Top + i);
  1940. }
  1941.             end;
  1942.             BRect := Bounds(ARect.Right - 4 - j, ARect.Top+i, j, j);
  1943.             Canvas.FillRect(BRect);
  1944.             DrawBitmapTransparent(Canvas, (BRect.Left + BRect.Right - Bmp.Width) div 2,
  1945.                                  (BRect.Top + BRect.Bottom - Bmp.Height) div 2, Bmp, clSilver);
  1946.  
  1947.             if (SortColumns[idxSort].SortCaption <> '') then
  1948.             begin
  1949.               BRect.Right := ARect.Right - 4;
  1950.               BRect.Left := BRect.Right - j;
  1951.               BRect.Top := ARect.Top + i;
  1952.               BRect.Bottom := ARect.Bottom;
  1953.               with Canvas.Font do
  1954.               begin
  1955.                 Name := 'Small Fonts';
  1956.                 Size := 5;
  1957.                 Style := [];
  1958.               end;
  1959.               Canvas.Brush.Style := bsClear;
  1960.               DrawText(Canvas.Handle,
  1961.                        PChar(SortColumns[idxSort].SortCaption),
  1962.                        Length(SortColumns[idxSort].SortCaption),
  1963.                        BRect,
  1964.                        DT_EXPANDTABS or DT_CENTER or DT_VCENTER or DT_NOPREFIX);
  1965.             end;
  1966.           end;
  1967.         end
  1968.       end;
  1969.  
  1970.     if (BCol > -1) and Assigned(FOnDrawColumnTitle) then
  1971.       FOnDrawColumnTitle(Self, ARect, ACol, Columns[BCol], AState);
  1972.   end
  1973.   else
  1974.   begin
  1975.     if (BCol > -1) and
  1976.        ((ACol > 0) or (not (dgIndicator in Options) and (ACol = 0))) and DefaultDrawing and
  1977.        (eoBooleanAsCheckBox in FExOptions) and
  1978.        (Datalink <> nil) and
  1979.        Datalink.Active and
  1980.        Assigned(Columns[BCol]) and
  1981.        Assigned(Columns[BCol].Field) and
  1982.        (Columns[BCol].Field.DataType = ftBoolean) and
  1983.        (((ARow > 0) and (dgTitles in Options)) or (not (dgTitles in Options))) then
  1984.     begin
  1985.       DrawColumn := Columns[BCol];
  1986.  
  1987.       if Assigned(DrawColumn.Field) then
  1988.         TitleText := DrawColumn.Field.DisplayText
  1989.       else
  1990.         TitleText := '';
  1991.       if (BCol <= FixedCols) and (FixedCols > 0) then
  1992.         Canvas.Brush.Color := FixedColor
  1993.       else
  1994.         if HighlightCell(ACol, ARow, TitleText, AState) then
  1995.           Canvas.Brush.Color := clHighlight
  1996.         else
  1997.           Canvas.Brush.Color := DrawColumn.Color;
  1998.       Canvas.FillRect(ARect);
  1999.       InflateRect(ARect, -2, -2);
  2000.  
  2001.       OldActive := DataLink.ActiveRecord;
  2002.       CheckState := cbUnChecked;
  2003.       try
  2004.         DataLink.ActiveRecord := ARow - TitleOffset;
  2005.  
  2006.         try
  2007.           if DrawColumn.Field.IsNull then
  2008.             CheckState := cbUnChecked
  2009.           else
  2010.             if DrawColumn.Field.Value then
  2011.               CheckState := cbChecked
  2012. //          TCheckBoxState(DrawColumn.Field.Value);
  2013.         except
  2014.         end
  2015.       finally
  2016.         DataLink.ActiveRecord := OldActive;
  2017.       end;
  2018.  
  2019.       DrawCheckBox(ARect, CheckState, taCenter);
  2020.       InflateRect(ARect, 2, 2);
  2021.     end
  2022.     else
  2023.     begin
  2024.       if (eoFixedLikeColumn in ExOptions) and
  2025.          (ACol > 0) and
  2026.          (ACol <= FixedCols) then
  2027.         AState := AState - [gdFixed];
  2028.       inherited DrawCell(ACol, ARow, ARect, AState)
  2029.     end;
  2030.   end;
  2031.  
  2032.   if (dgIndicator in Options) and (ACol = 0) and (ARow - TitleOffset >= 0) and
  2033.      (dgMultiSelect in Options) and (DataLink <> nil) and DataLink.Active {and
  2034.     (Datalink.DataSet.State = dsBrowse) }then
  2035.   begin
  2036.     { draw multiselect indicators if needed }
  2037.     FixRect := ARect;
  2038.     if ([dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines]) then
  2039.     begin
  2040.       InflateRect(FixRect, -1, -1);
  2041.       FrameOffs := 1;
  2042.     end
  2043.     else
  2044.       FrameOffs := 2;
  2045.     CheckState := cbUnChecked;
  2046.     OldActive := DataLink.ActiveRecord;
  2047.     try
  2048.       Datalink.ActiveRecord := ARow - TitleOffset;
  2049. //      MultiSelected := ActiveRowSelected;
  2050.       if ActiveRowSelected then
  2051.         CheckState := cbChecked;
  2052.  
  2053.       Bmp := GetGlyph;
  2054.     finally
  2055.       Datalink.ActiveRecord := OldActive;
  2056.     end;
  2057.  
  2058.     if (eoCheckBoxSelect in ExOptions) then
  2059.     begin
  2060.       BRect := FixRect;
  2061.       BRect.Right := BRect.Right - 2*FrameOffs - FMsIndicators.Width;
  2062.       DrawCheckBox(BRect, CheckState, taRightJustify);
  2063.     end;
  2064.  
  2065. {    if MultiSelected then
  2066.     begin
  2067.       if (ARow - TitleOffset <> Datalink.ActiveRecord) then
  2068.         Indicator := 0
  2069.       else //multiselected and current row
  2070.         Indicator := 1;
  2071.  
  2072.       FMsIndicators.BkColor := FixedColor;
  2073.       FMsIndicators.Draw(Self.Canvas, FixRect.Right - FMsIndicators.Width -
  2074.           FrameOffs, (FixRect.Top + FixRect.Bottom - FMsIndicators.Height)
  2075.           shr 1, Indicator);
  2076.     end;
  2077. }
  2078.     if (Bmp <> nil) then
  2079.     begin
  2080.       BRect.Left := FixRect.Left + FrameOffs;
  2081.       BRect.Top := FixRect.Top + FrameOffs;
  2082.       if (bmp.Width < FixRect.Right - FixRect.Left) then
  2083.         BRect.Right := BRect.Left + bmp.Width
  2084.       else
  2085.         if (eoCheckBoxSelect in ExOptions) then
  2086.           BRect.Right := FixRect.Right - FCheckWidth - FrameOffs
  2087.         else
  2088.           BRect.Right := FixRect.Right - FMsIndicators.Width - FrameOffs;
  2089.       BRect.Bottom := FixRect.Bottom - FrameOffs;
  2090.       Canvas.StretchDraw(BRect, bmp);
  2091.     end;
  2092.   end;
  2093.   if (eoTitleButtons in ExOptions) and
  2094.      not (csLoading in ComponentState) and
  2095.      (gdFixed in AState) and
  2096.      (dgTitles in Options) and (ARow = 0) then
  2097.   begin
  2098.     SavePen := Canvas.Pen.Color;
  2099.     try
  2100.       Down := (FPressedCol = ACol) and FPressed;
  2101.       Canvas.Pen.Color := clWindowFrame;
  2102.       if not (dgColLines in Options) then
  2103.       begin
  2104.         Canvas.MoveTo(ARect.Right - 1, ARect.Top);
  2105.         Canvas.LineTo(ARect.Right - 1, ARect.Bottom);
  2106.         Dec(ARect.Right);
  2107.       end;
  2108.       if not (dgRowLines in Options) then
  2109.       begin
  2110.         Canvas.MoveTo(ARect.Left, ARect.Bottom - 1);
  2111.         Canvas.LineTo(ARect.Right, ARect.Bottom - 1);
  2112.         Dec(ARect.Bottom);
  2113.       end;
  2114.       if (dgIndicator in Options) then Dec(ACol);
  2115.       AField := nil;
  2116.       if (DataLink <> nil) and DataLink.Active and (ACol >= 0) and
  2117.         (ACol < Columns.Count) then
  2118.       begin
  2119.         DrawColumn := Columns[ACol];
  2120.         AField := DrawColumn.Field;
  2121.       end
  2122.       else
  2123.         DrawColumn := nil;
  2124.  
  2125.       DrawEdge(Canvas.Handle, ARect, EdgeFlag[Down], BF_BOTTOMRIGHT);
  2126.       DrawEdge(Canvas.Handle, ARect, EdgeFlag[Down], BF_TOPLEFT);
  2127.       InflateRect(ARect, -1, -1);
  2128.       if Down then
  2129.       begin
  2130.         Inc(ARect.Left);
  2131.         Inc(ARect.Top);
  2132.       end;
  2133.       Canvas.Font := TitleFont;
  2134.       Canvas.Brush.Color := FixedColor;
  2135.       if (DrawColumn <> nil) then
  2136.       begin
  2137.         Canvas.Font := DrawColumn.Title.Font;
  2138.         Canvas.Brush.Color := DrawColumn.Title.Color;
  2139.       end;
  2140.       if (AField <> nil) and Assigned(FOnGetBtnParams) then
  2141.       begin
  2142.         BackColor := Canvas.Brush.Color;
  2143.         FOnGetBtnParams(Self, AField, Canvas.Font, BackColor, Down);
  2144.         Canvas.Brush.Color := BackColor;
  2145.       end;
  2146.       if (DataLink = nil) or not DataLink.Active then
  2147.         Canvas.FillRect(ARect)
  2148.       else
  2149.         if (BCol > -1) and (DrawColumn <> nil) then
  2150.           WriteTitleText(Canvas, ARect, 2, 2, DrawColumn.Title.Caption, Columns[BCol].Title.Alignment)
  2151.         else
  2152.           WriteTitleText(Canvas, ARect, 2, 2, '', taLeftJustify);
  2153.     finally
  2154.       Canvas.Pen.Color := SavePen;
  2155.     end;
  2156.   end;
  2157. end;
  2158.  
  2159. procedure TSMDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer;
  2160.   Column: TColumn; State: TGridDrawState);
  2161. var
  2162.   i: Integer;
  2163.   NewBackgrnd: TColor;
  2164.   Highlight: Boolean;
  2165.   Bmp: TBitmap;
  2166.   Field: TField;
  2167.  
  2168.   {the TRect for drawing simulated combobox}
  2169.   RectLookup: TRect;
  2170.   W, intMidX: Integer;
  2171. begin
  2172.   with RectLookup do
  2173.   begin
  2174.     Left := Rect.Right - (Rect.Bottom - Rect.Top)+1;
  2175.     Top := Rect.Top+1;
  2176.     Right := Rect.Right-1;
  2177.     Bottom := Rect.Bottom-1;
  2178.   end;
  2179.  
  2180.   Field := Column.Field;
  2181.   NewBackgrnd := Canvas.Brush.Color;
  2182.   Highlight := (gdSelected in State) and ((dgAlwaysShowSelection in Options) or Focused);
  2183.   GetCellProps(Field, Canvas.Font, NewBackgrnd, Highlight or ActiveRowSelected);
  2184.   Canvas.Brush.Color := NewBackgrnd;
  2185.   if DefaultDrawing then
  2186.   begin
  2187.     i := GetImageIndex(Field);
  2188.     if i >= 0 then
  2189.     begin
  2190.       Bmp := GetGridBitmap(TGridPicture(i));
  2191.       Canvas.FillRect(Rect);
  2192.       DrawBitmapTransparent(Canvas, (Rect.Left + Rect.Right - Bmp.Width) div 2,
  2193.         (Rect.Top + Rect.Bottom - Bmp.Height) div 2, Bmp, clOlive);
  2194.     end
  2195.     else
  2196.       DefaultDrawColumnCell(Rect, DataCol, Column, State);
  2197.  
  2198.     if (eoDrawGraphicField in FExOptions) and
  2199.        (Column.Field is TBlobField) and
  2200.        (Column.Field.DataType = ftGraphic) then
  2201.     begin
  2202.       bmp := TBitmap.Create;
  2203.       try
  2204.         bmp.Assign(Field);
  2205.         Canvas.StretchDraw(Rect, bmp);
  2206.       finally
  2207.         bmp.Free;
  2208.       end;
  2209.     end;
  2210.   end;
  2211.  
  2212.   if Columns.State = csDefault then
  2213.     inherited DrawDataCell(Rect, Field, State);
  2214.  
  2215.   inherited DrawColumnCell(Rect, DataCol, Column, State);
  2216.  
  2217.   if DefaultDrawing and Highlight and not (csDesigning in ComponentState)
  2218.      and not (dgRowSelect in Options)
  2219.      and (ValidParentForm(Self).ActiveControl = Self) then
  2220.     Canvas.DrawFocusRect(Rect);
  2221.  
  2222.  
  2223.   if (eoShowLookup in ExOptions) then
  2224.   begin
  2225.     if (Column.Field.FieldKind = fkLookup) or
  2226.        (Column.PickList.Count > 0) then
  2227.     begin //Drawing combobox if FieldKind is lookup
  2228.       Canvas.FillRect(Rect);
  2229.       DefaultDrawColumnCell(Rect, DataCol, Column, State);
  2230.       {Drawing combobox-area }
  2231.       DrawFrameControl(Canvas.Handle, RectLookup, DFC_SCROLL, DFCS_SCROLLCOMBOBOX);
  2232.     end
  2233.     else
  2234.       if Column.ButtonStyle = cbsEllipsis then
  2235.       begin
  2236.         {Show "?" when ButtonStyle Property is cbsEllipsis }
  2237. //        DrawFrameControl(Canvas.Handle, RectLookup, DFC_CAPTION, DFCS_CAPTIONHELP)
  2238.  
  2239.         Canvas.FillRect(RectLookup);
  2240.         DrawEdge(Canvas.Handle, RectLookup, EDGE_RAISED, BF_RECT or BF_MIDDLE);
  2241.         intMidX := (RectLookup.Right - RectLookup.Left) shr 1;
  2242.         W := (RectLookup.Bottom - RectLookup.Top) shr 3;
  2243.         if W = 0 then W := 1;
  2244.         PatBlt(Canvas.Handle, RectLookup.Left + intMidX, RectLookup.Top + intMidX, W, W, BLACKNESS);
  2245.         PatBlt(Canvas.Handle, RectLookup.Left + intMidX - (W * 2), RectLookup.Top + intMidX, W, W, BLACKNESS);
  2246.         PatBlt(Canvas.Handle, RectLookup.Left + intMidX + (W * 2), RectLookup.Top + intMidX, W, W, BLACKNESS);
  2247.  
  2248.       end
  2249.       else
  2250.         {Draw in default except above conditions}
  2251.         DefaultDrawColumnCell(Rect, DataCol, Column, State);
  2252.   end;
  2253.  
  2254.   {draw title}
  2255. //  DrawCell(SelectedIndex+1, 0, Rect, [gdFixed]);
  2256. end;
  2257.  
  2258. {is transferred from TBitDBGrid:
  2259.   Ilya Andreev, ilya_andreev@geocities.com
  2260.   FIDONet: 2:5030/55.28 AKA 2:5030/402.17}
  2261. procedure TSMDBGrid.CMHintShow(var Msg: TMessage);
  2262. var ACol, ARow: Integer;
  2263.     OldActive: Integer;
  2264. begin
  2265.  if eoCellHint in FExOptions then
  2266.    with PHintInfo(Msg.LParam)^  do
  2267.      try
  2268.        HintStr := Hint;
  2269.  
  2270.        Msg.Result := 1;
  2271.        if not DataLink.Active then Exit;
  2272.        TDrawGrid(Self).MouseToCell(CursorPos.X, CursorPos.Y, ACol, ARow);
  2273.        CursorRect := CellRect(ACol, ARow);
  2274.        ACol := ACol - IndicatorOffset;
  2275.        if (ACol < 0) then Exit;
  2276.        ARow := ARow - TitleOffset;
  2277.        HintPos := ClientToScreen(CursorRect.TopLeft);
  2278.        InflateRect(CursorRect, 1, 1);
  2279.        if (ARow = -1) then
  2280.        begin
  2281.          HintStr := Columns[ACol].Title.Caption;
  2282.          if Canvas.TextWidth(HintStr) < Columns[ACol].Width then Exit;
  2283.          Msg.Result := 0;
  2284.          Exit;
  2285.       end;
  2286.       if ARow < 0 then exit;
  2287.       OldActive := DataLink.ActiveRecord;
  2288.       DataLink.ActiveRecord := ARow;
  2289.       if Columns[ACol].Field <> nil then
  2290.         if Columns[ACol].Field.IsBlob then
  2291.           HintStr := Columns[ACol].Field.AsString
  2292.         else
  2293.           HintStr := Columns[ACol].Field.DisplayText;
  2294.       DataLink.ActiveRecord := OldActive;
  2295.       if (((CursorRect.Right - CursorRect.Left) >=  Columns[ACol].Width) and
  2296.           (Canvas.TextWidth(HintStr) < Columns[ACol].Width)) or
  2297.          ((Canvas.TextWidth(HintStr) < (CursorRect.Right - CursorRect.Left)) and
  2298.           (Columns[ACol].Alignment = taLeftJustify)) then exit;
  2299.         Msg.Result := 0;
  2300.     except
  2301.       Msg.Result := 1;
  2302.     end;
  2303. end;
  2304. {end of transfered}
  2305.  
  2306. procedure TSMDBGrid.SaveLayoutToRegistry;
  2307. var RegIniFile: TRegIniFile;
  2308.     i: Integer;
  2309. begin
  2310.   RegIniFile := TRegIniFile.Create(FRegistryKey);
  2311.   RegIniFile.WriteInteger(FRegistrySection, 'Count', Columns.Count);
  2312.   for i := 0 to (Columns.Count-1) do
  2313.   begin
  2314.     with Columns.Items[i] do
  2315.       RegIniFile.WriteString(FRegistrySection, IntToStr(i),
  2316.                              Format('%s,%d,%s', [FieldName, Width, Title.Caption]));
  2317.   end;
  2318.   RegIniFile.Free;
  2319. end;
  2320.  
  2321. procedure TSMDBGrid.RestoreLayoutFromRegistry;
  2322.  
  2323.   function GetValueFromKey(var strValues: string): string;
  2324.   var j: Integer;
  2325.   begin
  2326.     j := Pos(',', strValues);
  2327.     Result := Copy(strValues, 1, j-1);
  2328.     Delete(strValues, 1, j);
  2329.   end;
  2330.  
  2331. var RegIniFile: TRegIniFile;
  2332.     i, Count: Integer;
  2333.     s: string;
  2334. begin
  2335. { disable DBGrid-repaint while not will executed EndLayout
  2336.   Because I donn't want to repaint of the grid after each
  2337.   addition and after Columns.Clear }
  2338.   BeginLayout;
  2339.  
  2340.   RegIniFile := TRegIniFile.Create(FRegistryKey);
  2341.   Count := RegIniFile.ReadInteger(FRegistrySection, 'Count', 0);
  2342.   if (Count > 0) then
  2343.   begin
  2344.     Columns.Clear;
  2345.     for i := 0 to (Count-1) do
  2346.     begin
  2347.       S := RegIniFile.ReadString(FRegistrySection, IntToStr(i), '');
  2348.       if (S <> '') then
  2349.       begin
  2350.         with Columns.Add do
  2351.         begin
  2352.           FieldName := GetValueFromKey(S);
  2353.           Width := StrToIntDef(GetValueFromKey(S), 64);
  2354.           Title.Caption := S;
  2355.         end;
  2356.       end;
  2357.     end;
  2358.   end;
  2359.  
  2360.   RegIniFile.Free;
  2361.   EndLayout;
  2362. end;
  2363.  
  2364. initialization
  2365. finalization
  2366.   DestroyLocals;
  2367.  
  2368. end.
  2369.