bsSkinGrids.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:155k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************************}
  2. {                                                                   }
  3. {       Almediadev Visual Component Library                         }
  4. {       BusinessSkinForm                                            }
  5. {       Version 1.98                                                }
  6. {                                                                   }
  7. {       Copyright (c) 2000-2003 Almediadev                          }
  8. {       ALL RIGHTS RESERVED                                         }
  9. {                                                                   }
  10. {       Home:  http://www.almdev.com                                }
  11. {       Support: support@almdev.com                                 }
  12. {                                                                   }
  13. {*******************************************************************}
  14. unit bsSkinGrids;
  15. {$P+,S-,W-,R-}
  16. {$WARNINGS OFF}
  17. {$HINTS OFF}
  18. interface
  19. uses Messages, Windows, SysUtils, Classes, Graphics, Menus, Controls, Forms,
  20.      StdCtrls, Mask, bsSkinData, bsSkinCtrls;
  21. const
  22.   MaxCustomExtents = MaxListSize;
  23.   MaxShortInt = High(ShortInt);
  24. type
  25.   bsEInvalidGridOperation = class(Exception);
  26.   { Internal grid types }
  27.   TbsGetExtentsFunc = function(Index: Longint): Integer of object;
  28.   TbsGridAxisDrawInfo = record
  29.     EffectiveLineWidth: Integer;
  30.     FixedBoundary: Integer;
  31.     GridBoundary: Integer;
  32.     GridExtent: Integer;
  33.     LastFullVisibleCell: Longint;
  34.     FullVisBoundary: Integer;
  35.     FixedCellCount: Integer;
  36.     FirstGridCell: Integer;
  37.     GridCellCount: Integer;
  38.     GetExtent: TbsGetExtentsFunc;
  39.   end;
  40.   TbsGridDrawInfo = record
  41.     Horz, Vert: TbsGridAxisDrawInfo;
  42.   end;
  43.   TbsGridState = (gsNormal, gsSelecting, gsRowSizing, gsColSizing,
  44.     gsRowMoving, gsColMoving);
  45.   TbsGridMovement = gsRowMoving..gsColMoving;
  46.   { TInplaceEdit }
  47.   { The inplace editor is not intended to be used outside the grid }
  48.   TbsSkinCustomGrid = class;
  49.   
  50.   TbsSkinInplaceEdit = class(TCustomMaskEdit)
  51.   private
  52.     FGrid: TbsSkinCustomGrid;
  53.     FClickTime: Longint;
  54.     procedure InternalMove(const Loc: TRect; Redraw: Boolean);
  55.     procedure SetGrid(Value: TbsSkinCustomGrid);
  56.     procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  57.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  58.     procedure WMPaste(var Message); message WM_PASTE;
  59.     procedure WMCut(var Message); message WM_CUT;
  60.     procedure WMClear(var Message); message WM_CLEAR;
  61.   protected
  62.     procedure CreateParams(var Params: TCreateParams); override;
  63.     procedure DblClick; override;
  64.     function EditCanModify: Boolean; override;
  65.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  66.     procedure KeyPress(var Key: Char); override;
  67.     procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  68.     procedure BoundsChanged; virtual;
  69.     procedure UpdateContents; virtual;
  70.     procedure WndProc(var Message: TMessage); override;
  71.     property  Grid: TbsSkinCustomGrid read FGrid;
  72.   public
  73.     constructor Create(AOwner: TComponent); override;
  74.     procedure Deselect;
  75.     procedure Hide;
  76.     procedure Invalidate;
  77.     procedure Move(const Loc: TRect);
  78.     function PosEqual(const Rect: TRect): Boolean;
  79.     procedure SetFocus;
  80.     procedure UpdateLoc(const Loc: TRect);
  81.     function Visible: Boolean;
  82.   end;
  83.   { TbsSkinCustomGrid }
  84.   TGridOption = (goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  85.     goRangeSelect, goDrawFocusSelected, goRowSizing, goColSizing, goRowMoving,
  86.     goColMoving, goEditing, goTabs, goRowSelect,
  87.     goAlwaysShowEditor, goThumbTracking);
  88.   TGridOptions = set of TGridOption;
  89.   TGridDrawState = set of (gdSelected, gdFocused, gdFixed);
  90.   TGridScrollDirection = set of (sdLeft, sdRight, sdUp, sdDown);
  91.   TGridCoord = record
  92.     X: Longint;
  93.     Y: Longint;
  94.   end;
  95.   TGridRect = record
  96.     case Integer of
  97.       0: (Left, Top, Right, Bottom: Longint);
  98.       1: (TopLeft, BottomRight: TGridCoord);
  99.   end;
  100.   TSelectCellEvent = procedure (Sender: TObject; ACol, ARow: Longint;
  101.     var CanSelect: Boolean) of object;
  102.   TDrawCellEvent = procedure (Sender: TObject; ACol, ARow: Longint;
  103.     Rect: TRect; State: TGridDrawState) of object;
  104.   TbsSkinCustomGrid = class(TbsSkinControl)
  105.   private
  106.     FGridLineColor: TColor;
  107.     FHScrollBar: TbsSkinScrollBar;
  108.     FVScrollBar: TbsSkinScrollBar;
  109.     FAnchor: TGridCoord;
  110.     FBorderStyle: TBorderStyle;
  111.     FCanEditModify: Boolean;
  112.     FColCount: Longint;
  113.     FColWidths: Pointer;
  114.     FTabStops: Pointer;
  115.     FCurrent: TGridCoord;
  116.     FDefaultColWidth: Integer;
  117.     FDefaultRowHeight: Integer;
  118.     FDefaultCellHeight: Integer;
  119.     FFixedCols: Integer;
  120.     FFixedRows: Integer;
  121.     FFixedColor: TColor;
  122.     FGridLineWidth: Integer;
  123.     FOptions: TGridOptions;
  124.     FRowCount: Longint;
  125.     FRowHeights: Pointer;
  126.     FTopLeft: TGridCoord;
  127.     FSizingIndex: Longint;
  128.     FSizingPos, FSizingOfs: Integer;
  129.     FMoveIndex, FMovePos: Longint;
  130.     FHitTest: TPoint;
  131.     FInplaceEdit: TbsSkinInplaceEdit;
  132.     FInplaceCol, FInplaceRow: Longint;
  133.     FColOffset: Integer;
  134.     FDefaultDrawing: Boolean;
  135.     FEditorMode: Boolean;
  136.     procedure SetGridLineColor(Value: TColor);
  137.     procedure SetDefaultCellHeight(Value: Integer);
  138.     procedure OnVScrollBarChange(Sender: TObject);
  139.     procedure OnHScrollBarChange(Sender: TObject);
  140.     procedure OnVScrollBarUpButtonClick(Sender: TObject);
  141.     procedure OnVScrollBarDownButtonClick(Sender: TObject);
  142.     procedure OnHScrollBarUpButtonClick(Sender: TObject);
  143.     procedure OnHScrollBarDownButtonClick(Sender: TObject);
  144.     function CalcCoordFromPoint(X, Y: Integer;
  145.       const DrawInfo: TbsGridDrawInfo): TGridCoord;
  146.     procedure CalcDrawInfoXY(var DrawInfo: TbsGridDrawInfo;
  147.       UseWidth, UseHeight: Integer);
  148.     function CalcMaxTopLeft(const Coord: TGridCoord;
  149.       const DrawInfo: TbsGridDrawInfo): TGridCoord;
  150.     procedure CancelMode;
  151.     procedure ChangeGridOrientation(RightToLeftOrientation: Boolean);
  152.     procedure ChangeSize(NewColCount, NewRowCount: Longint);
  153.     procedure ClampInView(const Coord: TGridCoord);
  154.     procedure DrawSizingLine(const DrawInfo: TbsGridDrawInfo);
  155.     procedure DrawMove;
  156.     procedure FocusCell(ACol, ARow: Longint; MoveAnchor: Boolean);
  157.     procedure GridRectToScreenRect(GridRect: TGridRect;
  158.       var ScreenRect: TRect; IncludeLine: Boolean);
  159.     procedure HideEdit;
  160.     procedure Initialize;
  161.     procedure InvalidateGrid;
  162.     procedure InvalidateRect(ARect: TGridRect);
  163.     procedure ModifyScrollBar(ScrollBar, ScrollCode, Pos: Cardinal;
  164.       UseRightToLeft: Boolean);
  165.     procedure MoveAdjust(var CellPos: Longint; FromIndex, ToIndex: Longint);
  166.     procedure MoveAnchor(const NewAnchor: TGridCoord);
  167.     procedure MoveAndScroll(Mouse, CellHit: Integer; var DrawInfo: TbsGridDrawInfo;
  168.       var Axis: TbsGridAxisDrawInfo; Scrollbar: Integer; const MousePt: TPoint);
  169.     procedure MoveCurrent(ACol, ARow: Longint; MoveAnchor, Show: Boolean);
  170.     procedure MoveTopLeft(ALeft, ATop: Longint);
  171.     procedure ResizeCol(Index: Longint; OldSize, NewSize: Integer);
  172.     procedure ResizeRow(Index: Longint; OldSize, NewSize: Integer);
  173.     procedure SelectionMoved(const OldSel: TGridRect);
  174.     procedure ScrollDataInfo(DX, DY: Integer; var DrawInfo: TbsGridDrawInfo);
  175.     procedure TopLeftMoved(const OldTopLeft: TGridCoord);
  176.     function GetColWidths(Index: Longint): Integer;
  177.     function GetRowHeights(Index: Longint): Integer;
  178.     function GetSelection: TGridRect;
  179.     function GetTabStops(Index: Longint): Boolean;
  180.     function GetVisibleRowCount: Integer;
  181.     function GetVisibleColCount: Integer;
  182.     function IsActiveControl: Boolean;
  183.     procedure ReadColWidths(Reader: TReader);
  184.     procedure ReadRowHeights(Reader: TReader);
  185.     procedure SetBorderStyle(Value: TBorderStyle);
  186.     procedure SetCol(Value: Longint);
  187.     procedure SetColCount(Value: Longint);
  188.     procedure SetColWidths(Index: Longint; Value: Integer);
  189.     procedure SetDefaultColWidth(Value: Integer);
  190.     procedure SetDefaultRowHeight(Value: Integer);
  191.     procedure SetEditorMode(Value: Boolean);
  192.     procedure SetFixedColor(Value: TColor);
  193.     procedure SetFixedCols(Value: Integer);
  194.     procedure SetFixedRows(Value: Integer);
  195.     procedure SetGridLineWidth(Value: Integer);
  196.     procedure SetLeftCol(Value: Longint);
  197.     procedure SetOptions(Value: TGridOptions);
  198.     procedure SetRow(Value: Longint);
  199.     procedure SetRowCount(Value: Longint);
  200.     procedure SetRowHeights(Index: Longint; Value: Integer);
  201.     procedure SetSelection(Value: TGridRect);
  202.     procedure SetTabStops(Index: Longint; Value: Boolean);
  203.     procedure SetTopRow(Value: Longint);
  204.     procedure UpdateEdit;
  205.     procedure UpdateText;
  206.     procedure WriteColWidths(Writer: TWriter);
  207.     procedure WriteRowHeights(Writer: TWriter);
  208.     procedure CMCancelMode(var Msg: TMessage); message CM_CANCELMODE;
  209.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  210.     procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
  211.     procedure CMWanTbsecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
  212.     procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  213.     procedure WMChar(var Msg: TWMChar); message WM_CHAR;
  214.     procedure WMCancelMode(var Msg: TWMCancelMode); message WM_CANCELMODE;
  215.     procedure WMCommand(var Message: TWMCommand); message WM_COMMAND;
  216.     procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
  217.     procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL;
  218.     procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
  219.     procedure WMLButtonDown(var Message: TMessage); message WM_LBUTTONDOWN;
  220.     procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
  221.     procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
  222.     procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
  223.     procedure WMSize(var Msg: TWMSize); message WM_SIZE;
  224.     procedure WMTimer(var Msg: TWMTimer); message WM_TIMER;
  225.     procedure WMPAINT(var Msg: TWMPAINT); message WM_PAINT;
  226.     procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL;
  227.   protected
  228.     FInCheckScrollBars: Boolean;
  229.     FGridState: TbsGridState;
  230.     FSaveCellExtents: Boolean;
  231.     DesignOptionsBoost: TGridOptions;
  232.     VirtualView: Boolean;
  233.     procedure SetHScrollBar(Value: TbsSkinScrollBar); virtual;
  234.     procedure SetVScrollBar(Value: TbsSkinScrollBar); virtual;
  235.     procedure UpdateScrollPos(UpDateVert: Boolean); virtual;
  236.     procedure UpdateScrollRange(UpDateVert: Boolean); virtual;
  237.     procedure GetSkinData; override;
  238.     procedure CalcDrawInfo(var DrawInfo: TbsGridDrawInfo);
  239.     procedure CalcFixedInfo(var DrawInfo: TbsGridDrawInfo);
  240.     procedure CalcSizingState(X, Y: Integer; var State: TbsGridState;
  241.       var Index: Longint; var SizingPos, SizingOfs: Integer;
  242.       var FixedInfo: TbsGridDrawInfo); virtual;
  243.     function CreateEditor: TbsSkinInplaceEdit; virtual;
  244.     procedure CreateParams(var Params: TCreateParams); override;
  245.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  246.     procedure KeyPress(var Key: Char); override;
  247.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  248.       X, Y: Integer); override;
  249.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  250.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  251.       X, Y: Integer); override;
  252.     procedure AdjustSize(Index, Amount: Longint; Rows: Boolean); reintroduce; dynamic;
  253.     function BoxRect(ALeft, ATop, ARight, ABottom: Longint): TRect;
  254.     procedure DoExit; override;
  255.     function CellRect(ACol, ARow: Longint): TRect;
  256.     function CanEditAcceptKey(Key: Char): Boolean; dynamic;
  257.     function CanGridAcceptKey(Key: Word; Shift: TShiftState): Boolean; dynamic;
  258.     function CanEditModify: Boolean; dynamic;
  259.     function CanEditShow: Boolean; virtual;
  260.     function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  261.     function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  262.     function GetEditText(ACol, ARow: Longint): string; dynamic;
  263.     procedure SetEditText(ACol, ARow: Longint; const Value: string); dynamic;
  264.     function GetEditMask(ACol, ARow: Longint): string; dynamic;
  265.     function GetEditLimit: Integer; dynamic;
  266.     function GetGridWidth: Integer;
  267.     function GetGridHeight: Integer;
  268.     procedure HideEditor;
  269.     procedure ShowEditor;
  270.     procedure ShowEditorChar(Ch: Char);
  271.     procedure InvalidateEditor;
  272.     procedure MoveColumn(FromIndex, ToIndex: Longint);
  273.     procedure ColumnMoved(FromIndex, ToIndex: Longint); dynamic;
  274.     procedure MoveRow(FromIndex, ToIndex: Longint);
  275.     procedure RowMoved(FromIndex, ToIndex: Longint); dynamic;
  276.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
  277.       AState: TGridDrawState); virtual; abstract;
  278.     procedure DefineProperties(Filer: TFiler); override;
  279.     procedure MoveColRow(ACol, ARow: Longint; MoveAnchor, Show: Boolean);
  280.     function SelectCell(ACol, ARow: Longint): Boolean; virtual;
  281.     procedure SizeChanged(OldColCount, OldRowCount: Longint); dynamic;
  282.     function Sizing(X, Y: Integer): Boolean;
  283.     procedure ScrollData(DX, DY: Integer);
  284.     procedure InvalidateCell(ACol, ARow: Longint);
  285.     procedure InvalidateCol(ACol: Longint);
  286.     procedure InvalidateRow(ARow: Longint);
  287.     procedure TopLeftChanged; dynamic;
  288.     procedure TimedScroll(Direction: TGridScrollDirection); dynamic;
  289.     procedure Paint; override;
  290.     procedure ColWidthsChanged; dynamic;
  291.     procedure RowHeightsChanged; dynamic;
  292.     procedure DeleteColumn(ACol: Longint); virtual;
  293.     procedure DeleteRow(ARow: Longint); virtual;
  294.     procedure UpdateDesigner;
  295.     function BeginColumnDrag(var Origin, Destination: Integer;
  296.       const MousePt: TPoint): Boolean; dynamic;
  297.     function BeginRowDrag(var Origin, Destination: Integer;
  298.       const MousePt: TPoint): Boolean; dynamic;
  299.     function CheckColumnDrag(var Origin, Destination: Integer;
  300.       const MousePt: TPoint): Boolean; dynamic;
  301.     function CheckRowDrag(var Origin, Destination: Integer;
  302.       const MousePt: TPoint): Boolean; dynamic;
  303.     function EndColumnDrag(var Origin, Destination: Integer;
  304.       const MousePt: TPoint): Boolean; dynamic;
  305.     function EndRowDrag(var Origin, Destination: Integer;
  306.       const MousePt: TPoint): Boolean; dynamic;
  307.     property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
  308.     property Col: Longint read FCurrent.X write SetCol;
  309.     property Color default clWindow;
  310.     property ColCount: Longint read FColCount write SetColCount default 5;
  311.     property ColWidths[Index: Longint]: Integer read GetColWidths write SetColWidths;
  312.     property DefaultColWidth: Integer read FDefaultColWidth write SetDefaultColWidth default 64;
  313.     property DefaultDrawing: Boolean read FDefaultDrawing write FDefaultDrawing default True;
  314.     property DefaultRowHeight: Integer read FDefaultRowHeight write SetDefaultRowHeight default 24;
  315.     property EditorMode: Boolean read FEditorMode write SetEditorMode;
  316.     property FixedColor: TColor read FFixedColor write SetFixedColor default clBtnFace;
  317.     property FixedCols: Integer read FFixedCols write SetFixedCols default 1;
  318.     property FixedRows: Integer read FFixedRows write SetFixedRows default 1;
  319.     property GridHeight: Integer read GetGridHeight;
  320.     property GridLineWidth: Integer read FGridLineWidth write SetGridLineWidth default 1;
  321.     property GridWidth: Integer read GetGridWidth;
  322.     property HitTest: TPoint read FHitTest;
  323.     property InplaceEditor: TbsSkinInplaceEdit read FInplaceEdit;
  324.     property LeftCol: Longint read FTopLeft.X write SetLeftCol;
  325.     property Options: TGridOptions read FOptions write SetOptions
  326.       default [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  327.       goRangeSelect];
  328.     property ParentColor default False;
  329.     property Row: Longint read FCurrent.Y write SetRow;
  330.     property RowCount: Longint read FRowCount write SetRowCount default 5;
  331.     property RowHeights[Index: Longint]: Integer read GetRowHeights write SetRowHeights;
  332.     property Selection: TGridRect read GetSelection write SetSelection;
  333.     property TabStops[Index: Longint]: Boolean read GetTabStops write SetTabStops;
  334.     property TopRow: Longint read FTopLeft.Y write SetTopRow;
  335.     property VisibleColCount: Integer read GetVisibleColCount;
  336.     property VisibleRowCount: Integer read GetVisibleRowCount;
  337.     procedure Notification(AComponent: TComponent;
  338.       Operation: TOperation); override;
  339.     procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED;
  340.   public
  341.     // skin properties
  342.     FixedCellRect, SelectCellRect, FocusCellRect: TRect;
  343.     FixedCellLeftOffset, FixedCellRightOffset: Integer;
  344.     FixedCellTextRect: TRect;
  345.     CellLeftOffset, CellRightOffset: Integer;
  346.     CellTextRect: TRect;
  347.     LinesColor, BGColor: TColor;
  348.     FontName: String;
  349.     FontStyle: TFontStyles;
  350.     FontHeight: Integer;
  351.     FontColor, SelectFontColor, FocusFontColor: TColor;
  352.     FixedFontName: String;
  353.     FixedFontStyle: TFontStyles;
  354.     FixedFontHeight: Integer;
  355.     FixedFontColor: TColor;
  356.     Picture: TBitMap;
  357.     procedure ChangeSkinData; override;
  358.     function GetNewTextRect(CellR: TRect; AState: TGridDrawState): TRect;
  359.     //
  360.     constructor Create(AOwner: TComponent); override;
  361.     destructor Destroy; override;
  362.     function MouseCoord(X, Y: Integer): TGridCoord;
  363.   published
  364.     property TabStop default True;
  365.     property HScrollBar: TbsSkinScrollBar read FHScrollBar
  366.                                           write SetHScrollBar;
  367.     property VScrollBar: TbsSkinScrollBar read FVScrollBar
  368.                                           write SetVScrollBar;
  369.     property GridLineColor: TColor read FGridLineColor write SetGridLineColor;
  370.     property DefaultCellHeight: Integer read FDefaultCellHeight
  371.                                         write SetDefaultCellHeight;
  372.   end;
  373.   { TbsSkinDrawGrid }
  374.   TGetEditEvent = procedure (Sender: TObject; ACol, ARow: Longint; var Value: string) of object;
  375.   TSetEditEvent = procedure (Sender: TObject; ACol, ARow: Longint; const Value: string) of object;
  376.   TMovedEvent = procedure (Sender: TObject; FromIndex, ToIndex: Longint) of object;
  377.   TbsSkinDrawGrid = class(TbsSkinCustomGrid)
  378.   private
  379.     FOnColumnMoved: TMovedEvent;
  380.     FOnDrawCell: TDrawCellEvent;
  381.     FOnGetEditMask: TGetEditEvent;
  382.     FOnGetEditText: TGetEditEvent;
  383.     FOnRowMoved: TMovedEvent;
  384.     FOnSelectCell: TSelectCellEvent;
  385.     FOnSetEditText: TSetEditEvent;
  386.     FOnTopLeftChanged: TNotifyEvent;
  387.   protected
  388.     procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
  389.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
  390.       AState: TGridDrawState); override;
  391.     function GetEditMask(ACol, ARow: Longint): string; override;
  392.     function GetEditText(ACol, ARow: Longint): string; override;
  393.     procedure RowMoved(FromIndex, ToIndex: Longint); override;
  394.     function SelectCell(ACol, ARow: Longint): Boolean; override;
  395.     procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
  396.     procedure TopLeftChanged; override;
  397.   public
  398.     function CellRect(ACol, ARow: Longint): TRect;
  399.     procedure MouseToCell(X, Y: Integer; var ACol, ARow: Longint);
  400.     property Canvas;
  401.     property Col;
  402.     property ColWidths;
  403.     property EditorMode;
  404.     property GridHeight;
  405.     property GridWidth;
  406.     property LeftCol;
  407.     property Selection;
  408.     property Row;
  409.     property RowHeights;
  410.     property TabStops;
  411.     property TopRow;
  412.   published
  413.     property Align;
  414.     property Anchors;
  415.     property BiDiMode;
  416.     property BorderStyle;
  417.     property Color;
  418.     property ColCount;
  419.     property Constraints;
  420.     property DefaultColWidth;
  421.     property DefaultRowHeight;
  422.     property DefaultDrawing;
  423.     property DragCursor;
  424.     property DragKind;
  425.     property DragMode;
  426.     property Enabled;
  427.     property FixedColor;
  428.     property FixedCols;
  429.     property RowCount;
  430.     property FixedRows;
  431.     property Font;
  432.     property GridLineWidth;
  433.     property Options;
  434.     property ParentBiDiMode;
  435.     property ParentColor;
  436.     property ParentFont;
  437.     property ParentShowHint;
  438.     property PopupMenu;
  439.     property ShowHint;
  440.     property TabOrder;
  441.     property TabStop;
  442.     property Visible;
  443.     property VisibleColCount;
  444.     property VisibleRowCount;
  445.     property OnClick;
  446.     property OnColumnMoved: TMovedEvent read FOnColumnMoved write FOnColumnMoved;
  447.     property OnDblClick;
  448.     property OnDragDrop;
  449.     property OnDragOver;
  450.     property OnDrawCell: TDrawCellEvent read FOnDrawCell write FOnDrawCell;
  451.     property OnEndDock;
  452.     property OnEndDrag;
  453.     property OnEnter;
  454.     property OnExit;
  455.     property OnGetEditMask: TGetEditEvent read FOnGetEditMask write FOnGetEditMask;
  456.     property OnGetEditText: TGetEditEvent read FOnGetEditText write FOnGetEditText;
  457.     property OnKeyDown;
  458.     property OnKeyPress;
  459.     property OnKeyUp;
  460.     property OnMouseDown;
  461.     property OnMouseMove;
  462.     property OnMouseUp;
  463.     property OnMouseWheelDown;
  464.     property OnMouseWheelUp;
  465.     property OnRowMoved: TMovedEvent read FOnRowMoved write FOnRowMoved;
  466.     property OnSelectCell: TSelectCellEvent read FOnSelectCell write FOnSelectCell;
  467.     property OnSetEditText: TSetEditEvent read FOnSetEditText write FOnSetEditText;
  468.     property OnStartDock;
  469.     property OnStartDrag;
  470.     property OnTopLeftChanged: TNotifyEvent read FOnTopLeftChanged write FOnTopLeftChanged;
  471.   end;
  472.   { TbsSkinStringGrid }
  473.   TbsSkinStringGrid = class;
  474.   TbsSkinStringGridStrings = class(TStrings)
  475.   private
  476.     FGrid: TbsSkinStringGrid;
  477.     FIndex: Integer;
  478.     procedure CalcXY(Index: Integer; var X, Y: Integer);
  479.   protected
  480.     function Get(Index: Integer): string; override;
  481.     function GetCount: Integer; override;
  482.     function GetObject(Index: Integer): TObject; override;
  483.     procedure Put(Index: Integer; const S: string); override;
  484.     procedure PutObject(Index: Integer; AObject: TObject); override;
  485.     procedure SetUpdateState(Updating: Boolean); override;
  486.   public
  487.     constructor Create(AGrid: TbsSkinStringGrid; AIndex: Longint);
  488.     function Add(const S: string): Integer; override;
  489.     procedure Assign(Source: TPersistent); override;
  490.     procedure Clear; override;
  491.     procedure Delete(Index: Integer); override;
  492.     procedure Insert(Index: Integer; const S: string); override;
  493.   end;
  494.   TbsSkinStringGrid = class(TbsSkinDrawGrid)
  495.   private
  496.     FData: Pointer;
  497.     FRows: Pointer;
  498.     FCols: Pointer;
  499.     FUpdating: Boolean;
  500.     FNeedsUpdating: Boolean;
  501.     FEditUpdate: Integer;
  502.     procedure DisableEditUpdate;
  503.     procedure EnableEditUpdate;
  504.     procedure Initialize;
  505.     procedure Update(ACol, ARow: Integer); reintroduce;
  506.     procedure SetUpdateState(Updating: Boolean);
  507.     function GetCells(ACol, ARow: Integer): string;
  508.     function GetCols(Index: Integer): TStrings;
  509.     function GetObjects(ACol, ARow: Integer): TObject;
  510.     function GetRows(Index: Integer): TStrings;
  511.     procedure SetCells(ACol, ARow: Integer; const Value: string);
  512.     procedure SetCols(Index: Integer; Value: TStrings);
  513.     procedure SetObjects(ACol, ARow: Integer; Value: TObject);
  514.     procedure SetRows(Index: Integer; Value: TStrings);
  515.     function EnsureColRow(Index: Integer; IsCol: Boolean): TbsSkinStringGridStrings;
  516.     function EnsureDataRow(ARow: Integer): Pointer;
  517.   protected
  518.     procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
  519.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
  520.       AState: TGridDrawState); override;
  521.     function GetEditText(ACol, ARow: Longint): string; override;
  522.     procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
  523.     procedure RowMoved(FromIndex, ToIndex: Longint); override;
  524.   public
  525.     constructor Create(AOwner: TComponent); override;
  526.     destructor Destroy; override;
  527.     property Cells[ACol, ARow: Integer]: string read GetCells write SetCells;
  528.     property Cols[Index: Integer]: TStrings read GetCols write SetCols;
  529.     property Objects[ACol, ARow: Integer]: TObject read GetObjects write SetObjects;
  530.     property Rows[Index: Integer]: TStrings read GetRows write SetRows;
  531.   end;
  532. implementation
  533. uses Math, Consts, bsUtils;
  534. type
  535.   PIntArray = ^TIntArray;
  536.   TIntArray = array[0..MaxCustomExtents] of Integer;
  537. procedure InvalidOp(const id: string);
  538. begin
  539.   raise bsEInvalidGridOperation.Create(id);
  540. end;
  541. function GridRect(Coord1, Coord2: TGridCoord): TGridRect;
  542. begin
  543.   with Result do
  544.   begin
  545.     Left := Coord2.X;
  546.     if Coord1.X < Coord2.X then Left := Coord1.X;
  547.     Right := Coord1.X;
  548.     if Coord1.X < Coord2.X then Right := Coord2.X;
  549.     Top := Coord2.Y;
  550.     if Coord1.Y < Coord2.Y then Top := Coord1.Y;
  551.     Bottom := Coord1.Y;
  552.     if Coord1.Y < Coord2.Y then Bottom := Coord2.Y;
  553.   end;
  554. end;
  555. function PointInGridRect(Col, Row: Longint; const Rect: TGridRect): Boolean;
  556. begin
  557.   Result := (Col >= Rect.Left) and (Col <= Rect.Right) and (Row >= Rect.Top)
  558.     and (Row <= Rect.Bottom);
  559. end;
  560. type
  561.   TXorRects = array[0..3] of TRect;
  562. procedure XorRects(const R1, R2: TRect; var XorRects: TXorRects);
  563. var
  564.   Intersect, Union: TRect;
  565.   function PtInRect(X, Y: Integer; const Rect: TRect): Boolean;
  566.   begin
  567.     with Rect do Result := (X >= Left) and (X <= Right) and (Y >= Top) and
  568.       (Y <= Bottom);
  569.   end;
  570.   function Includes(const P1: TPoint; var P2: TPoint): Boolean;
  571.   begin
  572.     with P1 do
  573.     begin
  574.       Result := PtInRect(X, Y, R1) or PtInRect(X, Y, R2);
  575.       if Result then P2 := P1;
  576.     end;
  577.   end;
  578.   function Build(var R: TRect; const P1, P2, P3: TPoint): Boolean;
  579.   begin
  580.     Build := True;
  581.     with R do
  582.       if Includes(P1, TopLeft) then
  583.       begin
  584.         if not Includes(P3, BottomRight) then BottomRight := P2;
  585.       end
  586.       else if Includes(P2, TopLeft) then BottomRight := P3
  587.       else Build := False;
  588.   end;
  589. begin
  590.   FillChar(XorRects, SizeOf(XorRects), 0);
  591.   if not Bool(IntersectRect(Intersect, R1, R2)) then
  592.   begin
  593.     { Don't intersect so its simple }
  594.     XorRects[0] := R1;
  595.     XorRects[1] := R2;
  596.   end
  597.   else
  598.   begin
  599.     UnionRect(Union, R1, R2);
  600.     if Build(XorRects[0],
  601.       Point(Union.Left, Union.Top),
  602.       Point(Union.Left, Intersect.Top),
  603.       Point(Union.Left, Intersect.Bottom)) then
  604.       XorRects[0].Right := Intersect.Left;
  605.     if Build(XorRects[1],
  606.       Point(Intersect.Left, Union.Top),
  607.       Point(Intersect.Right, Union.Top),
  608.       Point(Union.Right, Union.Top)) then
  609.       XorRects[1].Bottom := Intersect.Top;
  610.     if Build(XorRects[2],
  611.       Point(Union.Right, Intersect.Top),
  612.       Point(Union.Right, Intersect.Bottom),
  613.       Point(Union.Right, Union.Bottom)) then
  614.       XorRects[2].Left := Intersect.Right;
  615.     if Build(XorRects[3],
  616.       Point(Union.Left, Union.Bottom),
  617.       Point(Intersect.Left, Union.Bottom),
  618.       Point(Intersect.Right, Union.Bottom)) then
  619.       XorRects[3].Top := Intersect.Bottom;
  620.   end;
  621. end;
  622. procedure ModifyExtents(var Extents: Pointer; Index, Amount: Longint;
  623.   Default: Integer);
  624. var
  625.   LongSize, OldSize: LongInt;
  626.   NewSize: Integer;
  627.   I: Integer;
  628. begin
  629.   if Amount <> 0 then
  630.   begin
  631.     if not Assigned(Extents) then OldSize := 0
  632.     else OldSize := PIntArray(Extents)^[0];
  633.     if (Index < 0) or (OldSize < Index) then InvalidOp(SIndexOutOfRange);
  634.     LongSize := OldSize + Amount;
  635.     if LongSize < 0 then InvalidOp(STooManyDeleted)
  636.     else if LongSize >= MaxListSize - 1 then InvalidOp(SGridTooLarge);
  637.     NewSize := Cardinal(LongSize);
  638.     if NewSize > 0 then Inc(NewSize);
  639.     ReallocMem(Extents, NewSize * SizeOf(Integer));
  640.     if Assigned(Extents) then
  641.     begin
  642.       I := Index + 1;
  643.       while I < NewSize do
  644.       begin
  645.         PIntArray(Extents)^[I] := Default;
  646.         Inc(I);
  647.       end;
  648.       PIntArray(Extents)^[0] := NewSize-1;
  649.     end;
  650.   end;
  651. end;
  652. procedure UpdateExtents(var Extents: Pointer; NewSize: Longint;
  653.   Default: Integer);
  654. var
  655.   OldSize: Integer;
  656. begin
  657.   OldSize := 0;
  658.   if Assigned(Extents) then OldSize := PIntArray(Extents)^[0];
  659.   ModifyExtents(Extents, OldSize, NewSize - OldSize, Default);
  660. end;
  661. procedure MoveExtent(var Extents: Pointer; FromIndex, ToIndex: Longint);
  662. var
  663.   Extent: Integer;
  664. begin
  665.   if Assigned(Extents) then
  666.   begin
  667.     Extent := PIntArray(Extents)^[FromIndex];
  668.     if FromIndex < ToIndex then
  669.       Move(PIntArray(Extents)^[FromIndex + 1], PIntArray(Extents)^[FromIndex],
  670.         (ToIndex - FromIndex) * SizeOf(Integer))
  671.     else if FromIndex > ToIndex then
  672.       Move(PIntArray(Extents)^[ToIndex], PIntArray(Extents)^[ToIndex + 1],
  673.         (FromIndex - ToIndex) * SizeOf(Integer));
  674.     PIntArray(Extents)^[ToIndex] := Extent;
  675.   end;
  676. end;
  677. function CompareExtents(E1, E2: Pointer): Boolean;
  678. var
  679.   I: Integer;
  680. begin
  681.   Result := False;
  682.   if E1 <> nil then
  683.   begin
  684.     if E2 <> nil then
  685.     begin
  686.       for I := 0 to PIntArray(E1)^[0] do
  687.         if PIntArray(E1)^[I] <> PIntArray(E2)^[I] then Exit;
  688.       Result := True;
  689.     end
  690.   end
  691.   else Result := E2 = nil;
  692. end;
  693. { Private. LongMulDiv multiplys the first two arguments and then
  694.   divides by the third.  This is used so that real number
  695.   (floating point) arithmetic is not necessary.  This routine saves
  696.   the possible 64-bit value in a temp before doing the divide.  Does
  697.   not do error checking like divide by zero.  Also assumes that the
  698.   result is in the 32-bit range (Actually 31-bit, since this algorithm
  699.   is for unsigned). }
  700. function LongMulDiv(Mult1, Mult2, Div1: Longint): Longint; stdcall;
  701.   external 'kernel32.dll' name 'MulDiv';
  702. type
  703.   TSelection = record
  704.     StartPos, EndPos: Integer;
  705.   end;
  706. constructor TbsSkinInplaceEdit.Create(AOwner: TComponent);
  707. begin
  708.   inherited Create(AOwner);
  709.   ParentCtl3D := False;
  710.   Ctl3D := False;
  711.   TabStop := False;
  712.   BorderStyle := bsNone;
  713. end;
  714. procedure TbsSkinInplaceEdit.CreateParams(var Params: TCreateParams);
  715. begin
  716.   inherited CreateParams(Params);
  717.   Params.Style := Params.Style or ES_MULTILINE;
  718. end;
  719. procedure TbsSkinInplaceEdit.SetGrid(Value: TbsSkinCustomGrid);
  720. begin
  721.   FGrid := Value;
  722. end;
  723. procedure TbsSkinInplaceEdit.CMShowingChanged(var Message: TMessage);
  724. begin
  725. end;
  726. procedure TbsSkinInplaceEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
  727. begin
  728.   inherited;
  729.   if goTabs in Grid.Options then
  730.     Message.Result := Message.Result or DLGC_WANTTAB;
  731. end;
  732. procedure TbsSkinInplaceEdit.WMPaste(var Message);
  733. begin
  734.   if not EditCanModify then Exit;
  735.   inherited
  736. end;
  737. procedure TbsSkinInplaceEdit.WMClear(var Message);
  738. begin
  739.   if not EditCanModify then Exit;
  740.   inherited;
  741. end;
  742. procedure TbsSkinInplaceEdit.WMCut(var Message);
  743. begin
  744.   if not EditCanModify then Exit;
  745.   inherited;
  746. end;
  747. procedure TbsSkinInplaceEdit.DblClick;
  748. begin
  749.   Grid.DblClick;
  750. end;
  751. function TbsSkinInplaceEdit.EditCanModify: Boolean;
  752. begin
  753.   Result := Grid.CanEditModify;
  754. end;
  755. procedure TbsSkinInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
  756.   procedure SendToParent;
  757.   begin
  758.     Grid.KeyDown(Key, Shift);
  759.     Key := 0;
  760.   end;
  761.   procedure ParentEvent;
  762.   var
  763.     GridKeyDown: TKeyEvent;
  764.   begin
  765.     GridKeyDown := Grid.OnKeyDown;
  766.     if Assigned(GridKeyDown) then GridKeyDown(Grid, Key, Shift);
  767.   end;
  768.   function ForwardMovement: Boolean;
  769.   begin
  770.     Result := goAlwaysShowEditor in Grid.Options;
  771.   end;
  772.   function Ctrl: Boolean;
  773.   begin
  774.     Result := ssCtrl in Shift;
  775.   end;
  776.   function Selection: TSelection;
  777.   begin
  778.     SendMessage(Handle, EM_GETSEL, Longint(@Result.StartPos), Longint(@Result.EndPos));
  779.   end;
  780.   function RightSide: Boolean;
  781.   begin
  782.     with Selection do
  783.       Result := ((StartPos = 0) or (EndPos = StartPos)) and
  784.         (EndPos = GetTextLen);
  785.    end;
  786.   function LeftSide: Boolean;
  787.   begin
  788.     with Selection do
  789.       Result := (StartPos = 0) and ((EndPos = 0) or (EndPos = GetTextLen));
  790.   end;
  791. begin
  792.   case Key of
  793.     VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_ESCAPE: SendToParent;
  794.     VK_INSERT:
  795.       if Shift = [] then SendToParent
  796.       else if (Shift = [ssShift]) and not Grid.CanEditModify then Key := 0;
  797.     VK_LEFT: if ForwardMovement and (Ctrl or LeftSide) then SendToParent;
  798.     VK_RIGHT: if ForwardMovement and (Ctrl or RightSide) then SendToParent;
  799.     VK_HOME: if ForwardMovement and (Ctrl or LeftSide) then SendToParent;
  800.     VK_END: if ForwardMovement and (Ctrl or RightSide) then SendToParent;
  801.     VK_F2:
  802.       begin
  803.         ParentEvent;
  804.         if Key = VK_F2 then
  805.         begin
  806.           Deselect;
  807.           Exit;
  808.         end;
  809.       end;
  810.     VK_TAB: if not (ssAlt in Shift) then SendToParent;
  811.   end;
  812.   if (Key = VK_DELETE) and not Grid.CanEditModify then Key := 0;
  813.   if Key <> 0 then
  814.   begin
  815.     ParentEvent;
  816.     inherited KeyDown(Key, Shift);
  817.   end;
  818. end;
  819. procedure TbsSkinInplaceEdit.KeyPress(var Key: Char);
  820. var
  821.   Selection: TSelection;
  822. begin
  823.   Grid.KeyPress(Key);
  824.   if (Key in [#32..#255]) and not Grid.CanEditAcceptKey(Key) then
  825.   begin
  826.     Key := #0;
  827.     MessageBeep(0);
  828.   end;
  829.   case Key of
  830.     #9, #27: Key := #0;
  831.     #13:
  832.       begin
  833.         SendMessage(Handle, EM_GETSEL, Longint(@Selection.StartPos), Longint(@Selection.EndPos));
  834.         if (Selection.StartPos = 0) and (Selection.EndPos = GetTextLen) then
  835.           Deselect else
  836.           SelectAll;
  837.         Key := #0;
  838.       end;
  839.     ^H, ^V, ^X, #32..#255:
  840.       if not Grid.CanEditModify then Key := #0;
  841.   end;
  842.   if Key <> #0 then inherited KeyPress(Key);
  843. end;
  844. procedure TbsSkinInplaceEdit.KeyUp(var Key: Word; Shift: TShiftState);
  845. begin
  846.   Grid.KeyUp(Key, Shift);
  847. end;
  848. procedure TbsSkinInplaceEdit.WndProc(var Message: TMessage);
  849. begin
  850.   case Message.Msg of
  851.     WM_SETFOCUS:
  852.       begin
  853.         if (GetParentForm(Self) = nil) or GetParentForm(Self).SetFocusedControl(Grid) then Dispatch(Message);
  854.         Exit;
  855.       end;
  856.     WM_LBUTTONDOWN:
  857.       begin
  858.         if ((GetMessageTime - FClickTime) < GetDoubleClickTime) then
  859.           Message.Msg := WM_LBUTTONDBLCLK;
  860.         FClickTime := 0;
  861.       end;
  862.   end;
  863.   inherited WndProc(Message);
  864. end;
  865. procedure TbsSkinInplaceEdit.Deselect;
  866. begin
  867.   SendMessage(Handle, EM_SETSEL, $7FFFFFFF, Longint($FFFFFFFF));
  868. end;
  869. procedure TbsSkinInplaceEdit.Invalidate;
  870. var
  871.   Cur: TRect;
  872. begin
  873.   ValidateRect(Handle, nil);
  874.   InvalidateRect(Handle, nil, True);
  875.   Windows.GetClientRect(Handle, Cur);
  876.   MapWindowPoints(Handle, Grid.Handle, Cur, 2);
  877.   ValidateRect(Grid.Handle, @Cur);
  878.   InvalidateRect(Grid.Handle, @Cur, False);
  879. end;
  880. procedure TbsSkinInplaceEdit.Hide;
  881. begin
  882.   if HandleAllocated and IsWindowVisible(Handle) then
  883.   begin
  884.     Invalidate;
  885.     SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_HIDEWINDOW or SWP_NOZORDER or
  886.       SWP_NOREDRAW);
  887.     if Focused then Windows.SetFocus(Grid.Handle);
  888.   end;
  889. end;
  890. function TbsSkinInplaceEdit.PosEqual(const Rect: TRect): Boolean;
  891. var
  892.   Cur: TRect;
  893. begin
  894.   GetWindowRect(Handle, Cur);
  895.   MapWindowPoints(HWND_DESKTOP, Grid.Handle, Cur, 2);
  896.   Result := EqualRect(Rect, Cur);
  897. end;
  898. procedure TbsSkinInplaceEdit.InternalMove(const Loc: TRect; Redraw: Boolean);
  899. begin
  900.   if IsRectEmpty(Loc) then Hide
  901.   else
  902.   begin
  903.     CreateHandle;
  904.     Redraw := Redraw or not IsWindowVisible(Handle);
  905.     Invalidate;
  906.     with Loc do
  907.       SetWindowPos(Handle, HWND_TOP, Left, Top, Right - Left, Bottom - Top,
  908.         SWP_SHOWWINDOW or SWP_NOREDRAW);
  909.     BoundsChanged;
  910.     if Redraw then Invalidate;
  911.     if Grid.Focused then
  912.       Windows.SetFocus(Handle);
  913.   end;
  914. end;
  915. procedure TbsSkinInplaceEdit.BoundsChanged;
  916. var
  917.   R: TRect;
  918. begin
  919.   R := Rect(2, 2, Width - 2, Height);
  920.   SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@R));
  921.   SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  922. end;
  923. procedure TbsSkinInplaceEdit.UpdateLoc(const Loc: TRect);
  924. begin
  925.   InternalMove(Loc, False);
  926. end;
  927. function TbsSkinInplaceEdit.Visible: Boolean;
  928. begin
  929.   Result := IsWindowVisible(Handle);
  930. end;
  931. procedure TbsSkinInplaceEdit.Move(const Loc: TRect);
  932. begin
  933.   InternalMove(Loc, True);
  934. end;
  935. procedure TbsSkinInplaceEdit.SetFocus;
  936. begin
  937.   if IsWindowVisible(Handle) then
  938.     Windows.SetFocus(Handle);
  939. end;
  940. procedure TbsSkinInplaceEdit.UpdateContents;
  941. begin
  942.   Text := '';
  943.   EditMask := Grid.GetEditMask(Grid.Col, Grid.Row);
  944.   Text := Grid.GetEditText(Grid.Col, Grid.Row);
  945.   MaxLength := Grid.GetEditLimit;
  946. end;
  947. { TbsSkinCustomGrid }
  948. constructor TbsSkinCustomGrid.Create(AOwner: TComponent);
  949. const
  950.   GridStyle = [csCaptureMouse, csOpaque, csDoubleClicks];
  951. begin
  952.   inherited Create(AOwner);
  953.   FHScrollBar := nil;
  954.   FVScrollBar := nil;
  955.   Ctl3D := False;
  956.   if NewStyleControls then
  957.     ControlStyle := GridStyle else
  958.     ControlStyle := GridStyle + [csFramed];
  959.   FCanEditModify := True;
  960.   FColCount := 5;
  961.   FRowCount := 5;
  962.   FFixedCols := 1;
  963.   FFixedRows := 1;
  964.   FGridLineWidth := 1;
  965.   FOptions := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
  966.     goRangeSelect];
  967.   DesignOptionsBoost := [goColSizing, goRowSizing];
  968.   FFixedColor := clBtnFace;
  969.   FBorderStyle := bsSingle;
  970.   FDefaultColWidth := 64;
  971.   FDefaultRowHeight := 20;
  972.   FDefaultCellHeight := 20;
  973.   FDefaultDrawing := True;
  974.   FSaveCellExtents := True;
  975.   FEditorMode := False;
  976.   Picture := nil;
  977.   Color := clWindow;
  978.   ParentColor := False;
  979.   TabStop := True;
  980.   SetBounds(Left, Top, FColCount * FDefaultColWidth,
  981.     FRowCount * FDefaultRowHeight);
  982.   Initialize;
  983.   FSkinDataName := 'grid';
  984.   FGridLineColor := clWindowText;
  985.   FInCheckScrollBars := False;
  986. end;
  987. destructor TbsSkinCustomGrid.Destroy;
  988. begin
  989.   FInplaceEdit.Free;
  990.   inherited Destroy;
  991.   FreeMem(FColWidths);
  992.   FreeMem(FRowHeights);
  993.   FreeMem(FTabStops);
  994. end;
  995. procedure TbsSkinCustomGrid.CMVisibleChanged;
  996. begin
  997.   inherited;
  998.   if FVScrollBar <> nil then FVScrollBar.Visible := Self.Visible;
  999.   if FHScrollBar <> nil then FHScrollBar.Visible := Self.Visible; 
  1000. end;
  1001. procedure TbsSkinCustomGrid.SetDefaultCellHeight(Value: Integer);
  1002. begin
  1003.   FDefaultCellHeight := Value;
  1004.   if FIndex = -1 then DefaultRowHeight := FDefaultCellHeight;
  1005. end;
  1006. procedure TbsSkinCustomGrid.SetGridLineColor;
  1007. begin
  1008.   FGridLineColor := Value;
  1009.   if FIndex = -1 then RePaint; 
  1010. end;
  1011. procedure TbsSkinCustomGrid.Notification;
  1012. begin
  1013.   inherited Notification(AComponent, Operation);
  1014.   if (Operation = opRemove) and (AComponent = FHScrollBar)
  1015.   then FHScrollBar := nil;
  1016.   if (Operation = opRemove) and (AComponent = FVScrollBar)
  1017.   then FVScrollBar := nil;
  1018. end;
  1019. procedure TbsSkinCustomGrid.SetHScrollBar;
  1020. begin
  1021.   FHScrollBar := Value;
  1022.   FHScrollBar.Enabled := True;
  1023.   FHScrollBar.Visible := False;
  1024.   FHScrollBar.OnLastChange := OnHScrollBarChange;
  1025.   FHScrollBar.OnUpButtonClick := OnHScrollBarUpButtonClick;
  1026.   FHScrollBar.OnDownButtonClick := OnHScrollBarDownButtonClick;
  1027.   UpdateScrollRange(True);
  1028. end;
  1029. procedure TbsSkinCustomGrid.SetVScrollBar;
  1030. begin
  1031.   FVScrollBar := Value;
  1032.   FVScrollBar.Enabled := True;
  1033.   FVScrollBar.Visible := False;
  1034.   FVScrollBar.OnLastChange := OnVScrollBarChange;
  1035.   FVScrollBar.OnUpButtonClick := OnVScrollBarUpButtonClick;
  1036.   FVScrollBar.OnDownButtonClick := OnVScrollBarDownButtonClick;
  1037.   UpdateScrollRange(True);
  1038. end;
  1039. procedure TbsSkinCustomGrid.OnVScrollBarUpButtonClick(Sender: TObject);
  1040. begin
  1041.   SendMessage(Handle, WM_VSCROLL,
  1042.     MakeWParam(SB_LINEDOWN, VScrollBar.Position), 0);
  1043. end;
  1044. procedure TbsSkinCustomGrid.OnVScrollBarDownButtonClick(Sender: TObject);
  1045. begin
  1046.   SendMessage(Handle, WM_VSCROLL,
  1047.     MakeWParam(SB_LINEUP, VScrollBar.Position), 0);
  1048. end;
  1049. procedure TbsSkinCustomGrid.OnHScrollBarUpButtonClick(Sender: TObject);
  1050. begin
  1051.   FHScrollBar.Position := FHScrollBar.Position + FHScrollBar.SmallChange;
  1052.   SendMessage(Handle, WM_HSCROLL,
  1053.     MakeWParam(SB_THUMBPOSITION, FHScrollBar.Position), 0);
  1054. end;
  1055. procedure TbsSkinCustomGrid.OnHScrollBarDownButtonClick(Sender: TObject);
  1056. begin
  1057.   FHScrollBar.Position := FHScrollBar.Position - FHScrollBar.SmallChange;
  1058.   SendMessage(Handle, WM_HSCROLL,
  1059.     MakeWParam(SB_THUMBPOSITION, FHScrollBar.Position), 0);
  1060. end;
  1061. procedure TbsSkinCustomGrid.OnVScrollBarChange(Sender: TObject);
  1062. begin
  1063.   SendMessage(Handle, WM_VSCROLL,
  1064.   MakeWParam(SB_THUMBPOSITION, FVScrollBar.Position), 0);
  1065. end;
  1066. procedure TbsSkinCustomGrid.OnHScrollBarChange(Sender: TObject);
  1067. begin
  1068.   SendMessage(Handle, WM_HSCROLL,
  1069.   MakeWParam(SB_THUMBPOSITION, FHScrollBar.Position), 0);
  1070. end;
  1071. function TbsSkinCustomGrid.GetNewTextRect;
  1072. var
  1073.   SR1, SR2, R: TRect;
  1074.   OX: Integer;
  1075. begin
  1076.   if FIndex < 0
  1077.   then
  1078.     begin
  1079.       Result := CellR;
  1080.       Exit;
  1081.     end
  1082.   else
  1083.     begin
  1084.       R := CellR;
  1085.       if gdFixed in AState
  1086.       then
  1087.         begin
  1088.           SR1 := FixedCellRect;
  1089.           SR2 := FixedCellTextRect;
  1090.         end
  1091.       else
  1092.         begin
  1093.           SR1 := SelectCellRect;
  1094.           SR2 := CellTextRect;
  1095.         end;
  1096.       if not IsNullRect(SR2)
  1097.       then
  1098.         begin
  1099.           OX := RectWidth(CellR) - RectWidth(SR1);
  1100.           Inc(R.Left, SR2.Left);
  1101.           Inc(R.Top, SR2.Top);
  1102.           R.Right := R.Left + RectWidth(SR2) + OX;
  1103.           R.Bottom := R.Top + RectHeight(SR2);
  1104.         end;
  1105.       Result := R;
  1106.     end
  1107. end;
  1108. procedure TbsSkinCustomGrid.ChangeSkinData;
  1109. var
  1110.   i, Old: Integer;
  1111. begin
  1112.   GetSkinData;
  1113.   if FIndex > -1
  1114.   then
  1115.     begin
  1116.       Old := DefaultRowHeight;
  1117.       i := RectHeight(SelectCellRect);
  1118.       if i <> Old
  1119.       then
  1120.         DefaultRowHeight := i
  1121.       else
  1122.         Invalidate;
  1123.     end
  1124.   else
  1125.     begin
  1126.       DefaultRowHeight := FDefaultCellHeight;
  1127.       Invalidate;
  1128.     end;
  1129.   UpDateScrollRange(True);
  1130.   if FVScrollBar <> nil then FVScrollBar.Align := FVScrollBar.Align;
  1131.   if FHScrollBar <> nil then FHScrollBar.Align := FHScrollBar.Align;
  1132. end;
  1133. procedure TbsSkinCustomGrid.GetSkinData;
  1134. begin
  1135.   Picture := nil;
  1136.   FIndex := -1;
  1137.   inherited;
  1138.   if FIndex > -1
  1139.   then
  1140.     if TbsDataSkinControl(FSD.CtrlList.Items[FIndex]) is TbsDataSkinGridControl
  1141.     then
  1142.       with TbsDataSkinGridControl(FSD.CtrlList.Items[FIndex]) do
  1143.       begin
  1144.         //
  1145.         if (PictureIndex <> -1) and (PictureIndex < FSD.FActivePictures.Count)
  1146.         then
  1147.           Picture := TBitMap(FSD.FActivePictures.Items[PictureIndex])
  1148.         else
  1149.           Picture := nil;
  1150.         //
  1151.         Self.FixedCellRect := FixedCellRect;
  1152.         Self.SelectCellRect := SelectCellRect;
  1153.         Self.FocusCellRect := FocusCellRect;
  1154.         Self.FixedCellLeftOffset := FixedCellLeftOffset;
  1155.         Self.FixedCellRightOffset := FixedCellRightOffset;
  1156.         Self.FixedCellTextRect := FixedCellTextRect;
  1157.         Self.CellLeftOffset := CellLeftOffset;
  1158.         Self.CellRightOffset := CellRightOffset;
  1159.         Self.CellTextRect := CellTextRect;
  1160.         Self.LinesColor := LinesColor;
  1161.         Self.BGColor := BGColor;
  1162.         //
  1163.         Self.FontName := FontName;
  1164.         Self.FontStyle := FontStyle;
  1165.         Self.FontHeight := FontHeight;
  1166.         Self.FontColor := FontColor;
  1167.         Self.SelectFontColor := SelectFontColor;
  1168.         Self.FocusFontColor := FocusFontColor;
  1169.         Self.FixedFontName := FixedFontName;
  1170.         Self.FixedFontStyle := FixedFontStyle;
  1171.         Self.FixedFontHeight := FixedFontHeight;
  1172.         Self.FixedFontColor := FixedFontColor;
  1173.         if IsNullRect(Self.SelectCellRect)
  1174.         then
  1175.           Self.SelectCellRect := Self.FocusCellRect; 
  1176.         if IsNullRect(Self.FocusCellRect)
  1177.         then
  1178.           Self.FocusCellRect := Self.SelectCellRect;
  1179.         if IsNullRect(Self.FixedCellRect)
  1180.         then
  1181.           begin
  1182.             FIndex := -1;
  1183.             Picture := nil;
  1184.           end;
  1185.           
  1186.       end;
  1187. end;
  1188. procedure TbsSkinCustomGrid.AdjustSize(Index, Amount: Longint; Rows: Boolean);
  1189. var
  1190.   NewCur: TGridCoord;
  1191.   OldRows, OldCols: Longint;
  1192.   MovementX, MovementY: Longint;
  1193.   MoveRect: TGridRect;
  1194.   ScrollArea: TRect;
  1195.   AbsAmount: Longint;
  1196.   function DoSizeAdjust(var Count: Longint; var Extents: Pointer;
  1197.     DefaultExtent: Integer; var Current: Longint): Longint;
  1198.   var
  1199.     I: Integer;
  1200.     NewCount: Longint;
  1201.   begin
  1202.     NewCount := Count + Amount;
  1203.     if NewCount < Index then InvalidOp(STooManyDeleted);
  1204.     if (Amount < 0) and Assigned(Extents) then
  1205.     begin
  1206.       Result := 0;
  1207.       for I := Index to Index - Amount - 1 do
  1208.         Inc(Result, PIntArray(Extents)^[I]);
  1209.     end
  1210.     else
  1211.       Result := Amount * DefaultExtent;
  1212.     if Extents <> nil then
  1213.       ModifyExtents(Extents, Index, Amount, DefaultExtent);
  1214.     Count := NewCount;
  1215.     if Current >= Index then
  1216.       if (Amount < 0) and (Current < Index - Amount) then Current := Index
  1217.       else Inc(Current, Amount);
  1218.   end;
  1219. begin
  1220.   if Amount = 0 then Exit;
  1221.   NewCur := FCurrent;
  1222.   OldCols := ColCount;
  1223.   OldRows := RowCount;
  1224.   MoveRect.Left := FixedCols;
  1225.   MoveRect.Right := ColCount - 1;
  1226.   MoveRect.Top := FixedRows;
  1227.   MoveRect.Bottom := RowCount - 1;
  1228.   MovementX := 0;
  1229.   MovementY := 0;
  1230.   AbsAmount := Amount;
  1231.   if AbsAmount < 0 then AbsAmount := -AbsAmount;
  1232.   if Rows then
  1233.   begin
  1234.     MovementY := DoSizeAdjust(FRowCount, FRowHeights, DefaultRowHeight, NewCur.Y);
  1235.     MoveRect.Top := Index;
  1236.     if Index + AbsAmount <= TopRow then MoveRect.Bottom := TopRow - 1;
  1237.   end
  1238.   else
  1239.   begin
  1240.     MovementX := DoSizeAdjust(FColCount, FColWidths, DefaultColWidth, NewCur.X);
  1241.     MoveRect.Left := Index;
  1242.     if Index + AbsAmount <= LeftCol then MoveRect.Right := LeftCol - 1;
  1243.   end;
  1244.   GridRectToScreenRect(MoveRect, ScrollArea, True);
  1245.   if not IsRectEmpty(ScrollArea) then
  1246.   begin
  1247.     ScrollWindow(Handle, MovementX, MovementY, @ScrollArea, @ScrollArea);
  1248.     UpdateWindow(Handle);
  1249.   end;
  1250.   SizeChanged(OldCols, OldRows);
  1251.   if (NewCur.X <> FCurrent.X) or (NewCur.Y <> FCurrent.Y) then
  1252.     MoveCurrent(NewCur.X, NewCur.Y, True, True);
  1253. end;
  1254. function TbsSkinCustomGrid.BoxRect(ALeft, ATop, ARight, ABottom: Longint): TRect;
  1255. var
  1256.   GridRect: TGridRect;
  1257. begin
  1258.   GridRect.Left := ALeft;
  1259.   GridRect.Right := ARight;
  1260.   GridRect.Top := ATop;
  1261.   GridRect.Bottom := ABottom;
  1262.   GridRectToScreenRect(GridRect, Result, False);
  1263. end;
  1264. procedure TbsSkinCustomGrid.DoExit;
  1265. begin
  1266.   inherited DoExit;
  1267.   if not (goAlwaysShowEditor in Options) then HideEditor;
  1268. end;
  1269. function TbsSkinCustomGrid.CellRect(ACol, ARow: Longint): TRect;
  1270. begin
  1271.   Result := BoxRect(ACol, ARow, ACol, ARow);
  1272. end;
  1273. function TbsSkinCustomGrid.CanEditAcceptKey(Key: Char): Boolean;
  1274. begin
  1275.   Result := True;
  1276. end;
  1277. function TbsSkinCustomGrid.CanGridAcceptKey(Key: Word; Shift: TShiftState): Boolean;
  1278. begin
  1279.   Result := True;
  1280. end;
  1281. function TbsSkinCustomGrid.CanEditModify: Boolean;
  1282. begin
  1283.   Result := FCanEditModify;
  1284. end;
  1285. function TbsSkinCustomGrid.CanEditShow: Boolean;
  1286. begin
  1287.   Result := ([goRowSelect, goEditing] * Options = [goEditing]) and
  1288.     FEditorMode and not (csDesigning in ComponentState) and HandleAllocated and
  1289.     ((goAlwaysShowEditor in Options) or IsActiveControl);
  1290. end;
  1291. function TbsSkinCustomGrid.IsActiveControl: Boolean;
  1292. var
  1293.   H: Hwnd;
  1294.   ParentForm: TCustomForm;
  1295. begin
  1296.   Result := False;
  1297.   ParentForm := GetParentForm(Self);
  1298.   if Assigned(ParentForm) then
  1299.   begin
  1300.     if (ParentForm.ActiveControl = Self) then
  1301.       Result := True
  1302.   end
  1303.   else
  1304.   begin
  1305.     H := GetFocus;
  1306.     while IsWindow(H) and (Result = False) do
  1307.     begin
  1308.       if H = WindowHandle then
  1309.         Result := True
  1310.       else
  1311.         H := GetParent(H);
  1312.     end;
  1313.   end;
  1314. end;
  1315. function TbsSkinCustomGrid.GetEditMask(ACol, ARow: Longint): string;
  1316. begin
  1317.   Result := '';
  1318. end;
  1319. function TbsSkinCustomGrid.GetEditText(ACol, ARow: Longint): string;
  1320. begin
  1321.   Result := '';
  1322. end;
  1323. procedure TbsSkinCustomGrid.SetEditText(ACol, ARow: Longint; const Value: string);
  1324. begin
  1325. end;
  1326. function TbsSkinCustomGrid.GetEditLimit: Integer;
  1327. begin
  1328.   Result := 0;
  1329. end;
  1330. procedure TbsSkinCustomGrid.HideEditor;
  1331. begin
  1332.   FEditorMode := False;
  1333.   HideEdit;
  1334. end;
  1335. procedure TbsSkinCustomGrid.ShowEditor;
  1336. begin
  1337.   FEditorMode := True;
  1338.   UpdateEdit;
  1339. end;
  1340. procedure TbsSkinCustomGrid.ShowEditorChar(Ch: Char);
  1341. begin
  1342.   ShowEditor;
  1343.   if FInplaceEdit <> nil then
  1344.     PostMessage(FInplaceEdit.Handle, WM_CHAR, Word(Ch), 0);
  1345. end;
  1346. procedure TbsSkinCustomGrid.InvalidateEditor;
  1347. begin
  1348.   FInplaceCol := -1;
  1349.   FInplaceRow := -1;
  1350.   UpdateEdit;
  1351. end;
  1352. procedure TbsSkinCustomGrid.ReadColWidths(Reader: TReader);
  1353. var
  1354.   I: Integer;
  1355. begin
  1356.   with Reader do
  1357.   begin
  1358.     ReadListBegin;
  1359.     for I := 0 to ColCount - 1 do ColWidths[I] := ReadInteger;
  1360.     ReadListEnd;
  1361.   end;
  1362. end;
  1363. procedure TbsSkinCustomGrid.ReadRowHeights(Reader: TReader);
  1364. var
  1365.   I: Integer;
  1366. begin
  1367.   with Reader do
  1368.   begin
  1369.     ReadListBegin;
  1370.     for I := 0 to RowCount - 1 do RowHeights[I] := ReadInteger;
  1371.     ReadListEnd;
  1372.   end;
  1373. end;
  1374. procedure TbsSkinCustomGrid.WriteColWidths(Writer: TWriter);
  1375. var
  1376.   I: Integer;
  1377. begin
  1378.   with Writer do
  1379.   begin
  1380.     WriteListBegin;
  1381.     for I := 0 to ColCount - 1 do WriteInteger(ColWidths[I]);
  1382.     WriteListEnd;
  1383.   end;
  1384. end;
  1385. procedure TbsSkinCustomGrid.WriteRowHeights(Writer: TWriter);
  1386. var
  1387.   I: Integer;
  1388. begin
  1389.   with Writer do
  1390.   begin
  1391.     WriteListBegin;
  1392.     for I := 0 to RowCount - 1 do WriteInteger(RowHeights[I]);
  1393.     WriteListEnd;
  1394.   end;
  1395. end;
  1396. procedure TbsSkinCustomGrid.DefineProperties(Filer: TFiler);
  1397.   function DoColWidths: Boolean;
  1398.   begin
  1399.     if Filer.Ancestor <> nil then
  1400.       Result := not CompareExtents(TbsSkinCustomGrid(Filer.Ancestor).FColWidths, FColWidths)
  1401.     else
  1402.       Result := FColWidths <> nil;
  1403.   end;
  1404.   function DoRowHeights: Boolean;
  1405.   begin
  1406.     if Filer.Ancestor <> nil then
  1407.       Result := not CompareExtents(TbsSkinCustomGrid(Filer.Ancestor).FRowHeights, FRowHeights)
  1408.     else
  1409.       Result := FRowHeights <> nil;
  1410.   end;
  1411. begin
  1412.   inherited DefineProperties(Filer);
  1413.   if FSaveCellExtents then
  1414.     with Filer do
  1415.     begin
  1416.       DefineProperty('ColWidths', ReadColWidths, WriteColWidths, DoColWidths);
  1417.       DefineProperty('RowHeights', ReadRowHeights, WriteRowHeights, DoRowHeights);
  1418.     end;
  1419. end;
  1420. procedure TbsSkinCustomGrid.MoveColumn(FromIndex, ToIndex: Longint);
  1421. var
  1422.   Rect: TGridRect;
  1423. begin
  1424.   if FromIndex = ToIndex then Exit;
  1425.   if Assigned(FColWidths) then
  1426.   begin
  1427.     MoveExtent(FColWidths, FromIndex + 1, ToIndex + 1);
  1428.     MoveExtent(FTabStops, FromIndex + 1, ToIndex + 1);
  1429.   end;
  1430.   MoveAdjust(FCurrent.X, FromIndex, ToIndex);
  1431.   MoveAdjust(FAnchor.X, FromIndex, ToIndex);
  1432.   MoveAdjust(FInplaceCol, FromIndex, ToIndex);
  1433.   Rect.Top := 0;
  1434.   Rect.Bottom := VisibleRowCount;
  1435.   if FromIndex < ToIndex then
  1436.   begin
  1437.     Rect.Left := FromIndex;
  1438.     Rect.Right := ToIndex;
  1439.   end
  1440.   else
  1441.   begin
  1442.     Rect.Left := ToIndex;
  1443.     Rect.Right := FromIndex;
  1444.   end;
  1445.   InvalidateRect(Rect);
  1446.   ColumnMoved(FromIndex, ToIndex);
  1447.   if Assigned(FColWidths) then
  1448.     ColWidthsChanged;
  1449.   UpdateEdit;
  1450. end;
  1451. procedure TbsSkinCustomGrid.ColumnMoved(FromIndex, ToIndex: Longint);
  1452. begin
  1453. end;
  1454. procedure TbsSkinCustomGrid.MoveRow(FromIndex, ToIndex: Longint);
  1455. begin
  1456.   if Assigned(FRowHeights) then
  1457.     MoveExtent(FRowHeights, FromIndex + 1, ToIndex + 1);
  1458.   MoveAdjust(FCurrent.Y, FromIndex, ToIndex);
  1459.   MoveAdjust(FAnchor.Y, FromIndex, ToIndex);
  1460.   MoveAdjust(FInplaceRow, FromIndex, ToIndex);
  1461.   RowMoved(FromIndex, ToIndex);
  1462.   if Assigned(FRowHeights) then
  1463.     RowHeightsChanged;
  1464.   UpdateEdit;
  1465. end;
  1466. procedure TbsSkinCustomGrid.RowMoved(FromIndex, ToIndex: Longint);
  1467. begin
  1468. end;
  1469. function TbsSkinCustomGrid.MouseCoord(X, Y: Integer): TGridCoord;
  1470. var
  1471.   DrawInfo: TbsGridDrawInfo;
  1472. begin
  1473.   CalcDrawInfo(DrawInfo);
  1474.   Result := CalcCoordFromPoint(X, Y, DrawInfo);
  1475.   if Result.X < 0 then Result.Y := -1
  1476.   else if Result.Y < 0 then Result.X := -1;
  1477. end;
  1478. procedure TbsSkinCustomGrid.MoveColRow(ACol, ARow: Longint; MoveAnchor,
  1479.   Show: Boolean);
  1480. begin
  1481.   MoveCurrent(ACol, ARow, MoveAnchor, Show);
  1482. end;
  1483. function TbsSkinCustomGrid.SelectCell(ACol, ARow: Longint): Boolean;
  1484. begin
  1485.   Result := True;
  1486. end;
  1487. procedure TbsSkinCustomGrid.SizeChanged(OldColCount, OldRowCount: Longint);
  1488. begin
  1489. end;
  1490. function TbsSkinCustomGrid.Sizing(X, Y: Integer): Boolean;
  1491. var
  1492.   DrawInfo: TbsGridDrawInfo;
  1493.   State: TbsGridState;
  1494.   Index: Longint;
  1495.   Pos, Ofs: Integer;
  1496. begin
  1497.   State := FGridState;
  1498.   if State = gsNormal then
  1499.   begin
  1500.     CalcDrawInfo(DrawInfo);
  1501.     CalcSizingState(X, Y, State, Index, Pos, Ofs, DrawInfo);
  1502.   end;
  1503.   Result := State <> gsNormal;
  1504. end;
  1505. procedure TbsSkinCustomGrid.TopLeftChanged;
  1506. begin
  1507.   if FEditorMode and (FInplaceEdit <> nil) then FInplaceEdit.UpdateLoc(CellRect(Col, Row));
  1508. end;
  1509. procedure FillDWord(var Dest; Count, Value: Integer); register;
  1510. asm
  1511.   XCHG  EDX, ECX
  1512.   PUSH  EDI
  1513.   MOV   EDI, EAX
  1514.   MOV   EAX, EDX
  1515.   REP   STOSD
  1516.   POP   EDI
  1517. end;
  1518. function StackAlloc(Size: Integer): Pointer; register;
  1519. asm
  1520.   POP   ECX          { return address }
  1521.   MOV   EDX, ESP
  1522.   ADD   EAX, 3
  1523.   AND   EAX, not 3   // round up to keep ESP dword aligned
  1524.   CMP   EAX, 4092
  1525.   JLE   @@2
  1526. @@1:
  1527.   SUB   ESP, 4092
  1528.   PUSH  EAX          { make sure we touch guard page, to grow stack }
  1529.   SUB   EAX, 4096
  1530.   JNS   @@1
  1531.   ADD   EAX, 4096
  1532. @@2:
  1533.   SUB   ESP, EAX
  1534.   MOV   EAX, ESP     { function result = low memory address of block }
  1535.   PUSH  EDX          { save original SP, for cleanup }
  1536.   MOV   EDX, ESP
  1537.   SUB   EDX, 4
  1538.   PUSH  EDX          { save current SP, for sanity check  (sp = [sp]) }
  1539.   PUSH  ECX          { return to caller }
  1540. end;
  1541. procedure StackFree(P: Pointer); register;
  1542. asm
  1543.   POP   ECX                     { return address }
  1544.   MOV   EDX, DWORD PTR [ESP]
  1545.   SUB   EAX, 8
  1546.   CMP   EDX, ESP                { sanity check #1 (SP = [SP]) }
  1547.   JNE   @@1
  1548.   CMP   EDX, EAX                { sanity check #2 (P = this stack block) }
  1549.   JNE   @@1
  1550.   MOV   ESP, DWORD PTR [ESP+4]  { restore previous SP  }
  1551. @@1:
  1552.   PUSH  ECX                     { return to caller }
  1553. end;
  1554. procedure TbsSkinCustomGrid.Paint;
  1555. var
  1556.   LineColor: TColor;
  1557.   DrawInfo: TbsGridDrawInfo;
  1558.   Sel: TGridRect;
  1559.   UpdateRect: TRect;
  1560.   R, AFocRect, FocRect: TRect;
  1561.   PointsList: PIntArray;
  1562.   StrokeList: PIntArray;
  1563.   MaxStroke: Integer;
  1564.   FrameFlags1, FrameFlags2: DWORD;
  1565.   B: TBitMap;
  1566.   procedure DrawLines(DoHorz, DoVert: Boolean; Col, Row: Longint;
  1567.     const CellBounds: array of Integer; OnColor, OffColor: TColor);
  1568.   const
  1569.     FlatPenStyle = PS_Geometric or PS_Solid or PS_EndCap_Flat or PS_Join_Miter;
  1570.     procedure DrawAxisLines(const AxisInfo: TbsGridAxisDrawInfo;
  1571.       Cell, MajorIndex: Integer; UseOnColor: Boolean);
  1572.     var
  1573.       Line: Integer;
  1574.       LogBrush: TLOGBRUSH;
  1575.       Index: Integer;
  1576.       Points: PIntArray;
  1577.       StopMajor, StartMinor, StopMinor: Integer;
  1578.     begin
  1579.       with Canvas, AxisInfo do
  1580.       begin
  1581.         if EffectiveLineWidth <> 0 then
  1582.         begin
  1583.           Pen.Width := GridLineWidth;
  1584.           if UseOnColor then
  1585.             Pen.Color := OnColor
  1586.           else
  1587.             Pen.Color := OffColor;
  1588.           if Pen.Width > 1 then
  1589.           begin
  1590.             LogBrush.lbStyle := BS_Solid;
  1591.             LogBrush.lbColor := Pen.Color;
  1592.             LogBrush.lbHatch := 0;
  1593.             Pen.Handle := ExtCreatePen(FlatPenStyle, Pen.Width, LogBrush, 0, nil);
  1594.           end;
  1595.           Points := PointsList;
  1596.           Line := CellBounds[MajorIndex] + EffectiveLineWidth shr 1 +
  1597.             GetExtent(Cell);
  1598.           //!!! ??? Line needs to be incremented for RightToLeftAlignment ???
  1599.           if UseRightToLeftAlignment and (MajorIndex = 0) then Inc(Line);
  1600.           StartMinor := CellBounds[MajorIndex xor 1];
  1601.           StopMinor := CellBounds[2 + (MajorIndex xor 1)];
  1602.           StopMajor := CellBounds[2 + MajorIndex] + EffectiveLineWidth;
  1603.           Index := 0;
  1604.           repeat
  1605.             Points^[Index + MajorIndex] := Line;         { MoveTo }
  1606.             Points^[Index + (MajorIndex xor 1)] := StartMinor;
  1607.             Inc(Index, 2);
  1608.             Points^[Index + MajorIndex] := Line;         { LineTo }
  1609.             Points^[Index + (MajorIndex xor 1)] := StopMinor;
  1610.             Inc(Index, 2);
  1611.             Inc(Cell);
  1612.             Inc(Line, GetExtent(Cell) + EffectiveLineWidth);
  1613.           until Line > StopMajor;
  1614.            { 2 integers per point, 2 points per line -> Index div 4 }
  1615.           PolyPolyLine(Canvas.Handle, Points^, StrokeList^, Index shr 2);
  1616.         end;
  1617.       end;
  1618.     end;
  1619.   begin
  1620.     if (CellBounds[0] = CellBounds[2]) or (CellBounds[1] = CellBounds[3]) then Exit;
  1621.     if not DoHorz then
  1622.     begin
  1623.       DrawAxisLines(DrawInfo.Vert, Row, 1, DoHorz);
  1624.       DrawAxisLines(DrawInfo.Horz, Col, 0, DoVert);
  1625.     end
  1626.     else
  1627.     begin
  1628.       DrawAxisLines(DrawInfo.Horz, Col, 0, DoVert);
  1629.       DrawAxisLines(DrawInfo.Vert, Row, 1, DoHorz);
  1630.     end;
  1631.   end;
  1632.   procedure DrawSkinCell(B: TBitMap; AState: TGridDrawState; W, H: Integer);
  1633.   begin
  1634.     if (gdFixed in AState)
  1635.     then
  1636.       begin
  1637.         CreateHSkinImage(FixedCellLeftOffset, FixedCellRightOffset,
  1638.           B, Picture, FixedCellRect, W, H);
  1639.         with Canvas do
  1640.         begin
  1641.           Font.Name := FixedFontName;
  1642.           Font.Height := FixedFontHeight;
  1643.           Font.Color := FixedFontColor;
  1644.           Font.Style := FixedFontStyle;
  1645.           Font.CharSet := Self.Font.CharSet;
  1646.         end;
  1647.       end
  1648.     else
  1649.     if (gdFocused in AState) or (goRowSelect in Options)
  1650.     then 
  1651.       begin
  1652.         CreateHSkinImage(CellLeftOffset, CellRightOffset,
  1653.            B, Picture, FocusCellRect, W, H);
  1654.         with Canvas do
  1655.         begin
  1656.           Font.Name := FontName;
  1657.           Font.Height := FontHeight;
  1658.           Font.Color := FocusFontColor;
  1659.           Font.Style := FontStyle;
  1660.           Font.CharSet := Self.Font.CharSet;
  1661.         end;
  1662.       end
  1663.     else
  1664.     if (gdSelected in AState)
  1665.     then
  1666.       begin
  1667.         CreateHSkinImage(CellLeftOffset, CellRightOffset,
  1668.           B, Picture, SelectCellRect, W, H);
  1669.         with Canvas do
  1670.         begin
  1671.           Font.Name := FontName;
  1672.           Font.Height := FontHeight;
  1673.           Font.Color := SelectFontColor;
  1674.           Font.Style := FontStyle;
  1675.           Font.CharSet := Self.Font.CharSet;
  1676.         end;
  1677.       end;
  1678.   end;
  1679.   procedure DrawCells(ACol, ARow: Longint; StartX, StartY, StopX, StopY: Integer;
  1680.     Color: TColor; IncludeDrawState: TGridDrawState);
  1681.   var
  1682.     CurCol, CurRow: Longint;
  1683.     AWhere, Where, TempRect: TRect;
  1684.     DrawState: TGridDrawState;
  1685.     Focused: Boolean;
  1686.   begin
  1687.     CurRow := ARow;
  1688.     Where.Top := StartY;
  1689.     while (Where.Top < StopY) and (CurRow < RowCount) do
  1690.     begin
  1691.       CurCol := ACol;
  1692.       Where.Left := StartX;
  1693.       Where.Bottom := Where.Top + RowHeights[CurRow];
  1694.       while (Where.Left < StopX) and (CurCol < ColCount) do
  1695.       begin
  1696.         Where.Right := Where.Left + ColWidths[CurCol];
  1697.         if (Where.Right > Where.Left) and RectVisible(Canvas.Handle, Where) then
  1698.         begin
  1699.           DrawState := IncludeDrawState;
  1700.           Focused := IsActiveControl;
  1701.           if Focused and (CurRow = Row) and (CurCol = Col)  then
  1702.             Include(DrawState, gdFocused);
  1703.           if PointInGridRect(CurCol, CurRow, Sel) then
  1704.             Include(DrawState, gdSelected);
  1705.           if not (gdFocused in DrawState) or not (goEditing in Options) or
  1706.             not FEditorMode or (csDesigning in ComponentState) then
  1707.           begin
  1708.             if DefaultDrawing or (csDesigning in ComponentState) then
  1709.               with Canvas do
  1710.               begin
  1711.                 if FIndex < 0
  1712.                 then
  1713.                   begin
  1714.                     Font := Self.Font;
  1715.                     if (gdSelected in DrawState) and
  1716.                        (not (gdFocused in DrawState) or
  1717.                        ([goDrawFocusSelected, goRowSelect] * Options <> []))
  1718.                     then
  1719.                       begin
  1720.                         Brush.Color := clHighlight;
  1721.                         Font.Color := clHighlightText;
  1722.                         FillRect(Where)
  1723.                       end
  1724.                     else
  1725.                       begin
  1726.                         Brush.Color := Color;
  1727.                         FillRect(Where);
  1728.                         if gdFixed in DrawState
  1729.                         then
  1730.                           begin
  1731.                             R := Where;
  1732.                             Frm3D(Canvas, R, clBtnHighLight, clBtnShadow);
  1733.                           end;
  1734.                       end;
  1735.                   end
  1736.                 else
  1737.                   if not (gdSelected in DrawState) and
  1738.                      not (gdFocused in DrawState) and
  1739.                      not (gdFixed in DrawState)
  1740.                   then
  1741.                     begin
  1742.                       Font.Name := FontName;
  1743.                       Font.Height := FontHeight;
  1744.                       Font.Color := FontColor;
  1745.                       Font.Style := FontStyle;
  1746.                       Font.CharSet := Self.Font.CharSet;
  1747.                       Brush.Color := BGColor;
  1748.                       FillRect(Where);
  1749.                     end
  1750.                   else
  1751.                     begin
  1752.                       B := TBitMap.Create;
  1753.                       DrawSkinCell(B, DrawState,
  1754.                       RectWidth(Where), RectHeight(Where));
  1755.                       Draw(Where.Left, Where.Top, B);
  1756.                       B.Free;
  1757.                     end;
  1758.               end;
  1759.             DrawCell(CurCol, CurRow, Where, DrawState);
  1760.             if FIndex < 0
  1761.             then
  1762.             if DefaultDrawing and not (csDesigning in ComponentState) and
  1763.               (gdFocused in DrawState) and
  1764.               ([goEditing, goAlwaysShowEditor] * Options <> [goEditing, goAlwaysShowEditor])
  1765.               and not (goRowSelect in Options)
  1766.             then
  1767.             begin
  1768.               if not UseRightToLeftAlignment
  1769.               then
  1770.                 DrawFocusRect(Canvas.Handle, Where)
  1771.               else
  1772.                 begin
  1773.                   AWhere := Where;
  1774.                   AWhere.Left := Where.Right;
  1775.                   AWhere.Right := Where.Left;
  1776.                   DrawFocusRect(Canvas.Handle, AWhere)
  1777.                 end;
  1778.             end;
  1779.           end;
  1780.         end;
  1781.         Where.Left := Where.Right + DrawInfo.Horz.EffectiveLineWidth;
  1782.         Inc(CurCol);
  1783.       end;
  1784.       Where.Top := Where.Bottom + DrawInfo.Vert.EffectiveLineWidth;
  1785.       Inc(CurRow);
  1786.     end;
  1787.   end;
  1788. begin
  1789.   if (Width <= 0) or (Height <=0) then Exit;
  1790.   GetSkinData;
  1791.   
  1792.   if UseRightToLeftAlignment then ChangeGridOrientation(True);
  1793.   UpdateRect := Canvas.ClipRect;
  1794.   CalcDrawInfo(DrawInfo);
  1795.   with DrawInfo do
  1796.   begin
  1797.     if (Horz.EffectiveLineWidth > 0) or (Vert.EffectiveLineWidth > 0) then
  1798.     begin
  1799.       { Draw the grid line in the four areas (fixed, fixed), (variable, fixed),
  1800.         (fixed, variable) and (variable, variable) }
  1801.       if FIndex > -1
  1802.       then
  1803.         LineColor := LinesColor
  1804.       else
  1805.         LineColor := FGridLineColor;
  1806.       MaxStroke := Max(Horz.LastFullVisibleCell - LeftCol + FixedCols,
  1807.                         Vert.LastFullVisibleCell - TopRow + FixedRows) + 3;
  1808.       PointsList := StackAlloc(MaxStroke * sizeof(TPoint) * 2);
  1809.       StrokeList := StackAlloc(MaxStroke * sizeof(Integer));
  1810.       FillDWord(StrokeList^, MaxStroke, 2);
  1811.       if ColorToRGB(Color) = clSilver then LineColor := clGray;
  1812.       DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options,
  1813.         0, 0, [0, 0, Horz.FixedBoundary, Vert.FixedBoundary], LineColor{clBlack}, FixedColor);
  1814.       DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options,
  1815.         LeftCol, 0, [Horz.FixedBoundary, 0, Horz.GridBoundary,
  1816.         Vert.FixedBoundary], LineColor{clBlack}, FixedColor);
  1817.       DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options,
  1818.         0, TopRow, [0, Vert.FixedBoundary, Horz.FixedBoundary,
  1819.         Vert.GridBoundary], LineColor{clBlack}, FixedColor);
  1820.       // skin
  1821.       DrawLines(goHorzLine in Options, goVertLine in Options, LeftCol,
  1822.         TopRow, [Horz.FixedBoundary, Vert.FixedBoundary, Horz.GridBoundary,
  1823.         Vert.GridBoundary], LineColor, Color);
  1824.       //
  1825.       StackFree(StrokeList);
  1826.       StackFree(PointsList);
  1827.     end;
  1828.     { Draw the cells in the four areas }
  1829.     Sel := Selection;
  1830.     FrameFlags1 := 0;
  1831.     FrameFlags2 := 0;
  1832.     if goFixedVertLine in Options then
  1833.     begin
  1834.       FrameFlags1 := BF_RIGHT;
  1835.       FrameFlags2 := BF_LEFT;
  1836.     end;
  1837.     if goFixedHorzLine in Options then
  1838.     begin
  1839.       FrameFlags1 := FrameFlags1 or BF_BOTTOM;
  1840.       FrameFlags2 := FrameFlags2 or BF_TOP;
  1841.     end;
  1842.     DrawCells(0, 0, 0, 0, Horz.FixedBoundary, Vert.FixedBoundary, FixedColor,
  1843.       [gdFixed]);
  1844.     DrawCells(LeftCol, 0, Horz.FixedBoundary - FColOffset, 0, Horz.GridBoundary,  //!! clip
  1845.       Vert.FixedBoundary, FixedColor, [gdFixed]);
  1846.     DrawCells(0, TopRow, 0, Vert.FixedBoundary, Horz.FixedBoundary,
  1847.       Vert.GridBoundary, FixedColor, [gdFixed]);
  1848.     DrawCells(LeftCol, TopRow, Horz.FixedBoundary - FColOffset,                   //!! clip
  1849.       Vert.FixedBoundary, Horz.GridBoundary, Vert.GridBoundary, Color, []);
  1850.     if not (csDesigning in ComponentState) and
  1851.       (goRowSelect in Options) and DefaultDrawing and Focused then
  1852.     begin
  1853.       GridRectToScreenRect(GetSelection, FocRect, False);
  1854.       if FIndex < 0
  1855.       then
  1856.         if not UseRightToLeftAlignment
  1857.         then
  1858.           Canvas.DrawFocusRect(FocRect)
  1859.         else
  1860.           begin
  1861.             AFocRect := FocRect;
  1862.             AFocRect.Left := FocRect.Right;
  1863.             AFocRect.Right := FocRect.Left;
  1864.             Canvas.DrawFocusRect(AFocRect)
  1865.           end;
  1866.     end;
  1867.     { Fill in area not occupied by cells }
  1868.      if Horz.GridBoundary < Horz.GridExtent then
  1869.         begin
  1870.           if FIndex > -1
  1871.           then
  1872.             Canvas.Brush.Color := BGColor
  1873.           else
  1874.             Canvas.Brush.Color := Color;
  1875.           Canvas.FillRect(Rect(Horz.GridBoundary, 0, Horz.GridExtent + 1, Vert.GridBoundary));
  1876.         end;
  1877.         if Vert.GridBoundary < Vert.GridExtent then
  1878.         begin
  1879.           if FIndex > -1
  1880.           then
  1881.             Canvas.Brush.Color := BGColor
  1882.           else
  1883.             Canvas.Brush.Color := Color;
  1884.           Canvas.FillRect(Rect(0, Vert.GridBoundary, Horz.GridExtent, Vert.GridExtent));
  1885.          end;
  1886.       end;
  1887.    if UseRightToLeftAlignment then ChangeGridOrientation(False);
  1888. end;
  1889. function TbsSkinCustomGrid.CalcCoordFromPoint(X, Y: Integer;
  1890.   const DrawInfo: TbsGridDrawInfo): TGridCoord;
  1891.   function DoCalc(const AxisInfo: TbsGridAxisDrawInfo; N: Integer): Integer;
  1892.   var
  1893.     I, Start, Stop: Longint;
  1894.     Line: Integer;
  1895.   begin
  1896.     with AxisInfo do
  1897.     begin
  1898.       if N < FixedBoundary then
  1899.       begin
  1900.         Start := 0;
  1901.         Stop :=  FixedCellCount - 1;
  1902.         Line := 0;
  1903.       end
  1904.       else
  1905.       begin
  1906.         Start := FirstGridCell;
  1907.         Stop := GridCellCount - 1;
  1908.         Line := FixedBoundary;
  1909.       end;
  1910.       Result := -1;
  1911.       for I := Start to Stop do
  1912.       begin
  1913.         Inc(Line, GetExtent(I) + EffectiveLineWidth);
  1914.         if N < Line then
  1915.         begin
  1916.           Result := I;
  1917.           Exit;
  1918.         end;
  1919.       end;
  1920.     end;
  1921.   end;
  1922.   function DoCalcRightToLeft(const AxisInfo: TbsGridAxisDrawInfo; N: Integer): Integer;
  1923.   var
  1924.     I, Start, Stop: Longint;
  1925.     Line: Integer;
  1926.   begin
  1927.     N := ClientWidth - N;
  1928.     with AxisInfo do
  1929.     begin
  1930.       if N < FixedBoundary then
  1931.       begin
  1932.         Start := 0;
  1933.         Stop :=  FixedCellCount - 1;
  1934.         Line := ClientWidth;
  1935.       end
  1936.       else
  1937.       begin
  1938.         Start := FirstGridCell;
  1939.         Stop := GridCellCount - 1;
  1940.         Line := FixedBoundary;
  1941.       end;
  1942.       Result := -1;
  1943.       for I := Start to Stop do
  1944.       begin
  1945.         Inc(Line, GetExtent(I) + EffectiveLineWidth);
  1946.         if N < Line then
  1947.         begin
  1948.           Result := I;
  1949.           Exit;
  1950.         end;
  1951.       end;
  1952.     end;
  1953.   end;
  1954. begin
  1955.   if not UseRightToLeftAlignment then
  1956.     Result.X := DoCalc(DrawInfo.Horz, X)
  1957.   else
  1958.     Result.X := DoCalcRightToLeft(DrawInfo.Horz, X);
  1959.   Result.Y := DoCalc(DrawInfo.Vert, Y);
  1960. end;
  1961. procedure TbsSkinCustomGrid.CalcDrawInfo(var DrawInfo: TbsGridDrawInfo);
  1962. begin
  1963.   CalcDrawInfoXY(DrawInfo, ClientWidth, ClientHeight);
  1964. end;
  1965. procedure TbsSkinCustomGrid.CalcDrawInfoXY(var DrawInfo: TbsGridDrawInfo;
  1966.   UseWidth, UseHeight: Integer);
  1967.   procedure CalcAxis(var AxisInfo: TbsGridAxisDrawInfo; UseExtent: Integer);
  1968.   var
  1969.     I: Integer;
  1970.   begin
  1971.     with AxisInfo do
  1972.     begin
  1973.       GridExtent := UseExtent;
  1974.       GridBoundary := FixedBoundary;
  1975.       FullVisBoundary := FixedBoundary;
  1976.       LastFullVisibleCell := FirstGridCell;
  1977.       for I := FirstGridCell to GridCellCount - 1 do
  1978.       begin
  1979.         Inc(GridBoundary, GetExtent(I) + EffectiveLineWidth);
  1980.         if GridBoundary > GridExtent + EffectiveLineWidth then
  1981.         begin
  1982.           GridBoundary := GridExtent;
  1983.           Break;
  1984.         end;
  1985.         LastFullVisibleCell := I;
  1986.         FullVisBoundary := GridBoundary;
  1987.       end;
  1988.     end;
  1989.   end;
  1990. begin
  1991.   CalcFixedInfo(DrawInfo);
  1992.   CalcAxis(DrawInfo.Horz, UseWidth);
  1993.   CalcAxis(DrawInfo.Vert, UseHeight);
  1994. end;
  1995. procedure TbsSkinCustomGrid.CalcFixedInfo(var DrawInfo: TbsGridDrawInfo);
  1996.   procedure CalcFixedAxis(var Axis: TbsGridAxisDrawInfo; LineOptions: TGridOptions;
  1997.     FixedCount, FirstCell, CellCount: Integer; GetExtentFunc: TbsGetExtentsFunc);
  1998.   var
  1999.     I: Integer;
  2000.   begin
  2001.     with Axis do
  2002.     begin
  2003.       if LineOptions * Options = [] then
  2004.         EffectiveLineWidth := 0
  2005.       else
  2006.         EffectiveLineWidth := GridLineWidth;
  2007.       FixedBoundary := 0;
  2008.       for I := 0 to FixedCount - 1 do
  2009.         Inc(FixedBoundary, GetExtentFunc(I) + EffectiveLineWidth);
  2010.       FixedCellCount := FixedCount;
  2011.       FirstGridCell := FirstCell;
  2012.       GridCellCount := CellCount;
  2013.       GetExtent := GetExtentFunc;
  2014.     end;
  2015.   end;
  2016. begin
  2017.   CalcFixedAxis(DrawInfo.Horz, [goFixedVertLine, goVertLine], FixedCols,
  2018.     LeftCol, ColCount, GetColWidths);
  2019.   CalcFixedAxis(DrawInfo.Vert, [goFixedHorzLine, goHorzLine], FixedRows,
  2020.     TopRow, RowCount, GetRowHeights);
  2021. end;
  2022. { Calculates the TopLeft that will put the given Coord in view }
  2023. function TbsSkinCustomGrid.CalcMaxTopLeft(const Coord: TGridCoord;
  2024.   const DrawInfo: TbsGridDrawInfo): TGridCoord;
  2025.   function CalcMaxCell(const Axis: TbsGridAxisDrawInfo; Start: Integer): Integer;
  2026.   var
  2027.     Line: Integer;
  2028.     I, Extent: Longint;
  2029.   begin
  2030.     Result := Start;
  2031.     with Axis do
  2032.     begin
  2033.       Line := GridExtent + EffectiveLineWidth;
  2034.       for I := Start downto FixedCellCount do
  2035.       begin
  2036.         Extent := GetExtent(I);
  2037.         Dec(Line, Extent);
  2038.         Dec(Line, EffectiveLineWidth);
  2039.         if Line < FixedBoundary then Break;
  2040.         if Extent > 0 then Result := I;
  2041.       end;
  2042.     end;
  2043.   end;
  2044. begin
  2045.   Result.X := CalcMaxCell(DrawInfo.Horz, Coord.X);
  2046.   Result.Y := CalcMaxCell(DrawInfo.Vert, Coord.Y);
  2047. end;
  2048. procedure TbsSkinCustomGrid.CalcSizingState(X, Y: Integer; var State: TbsGridState;
  2049.   var Index: Longint; var SizingPos, SizingOfs: Integer;
  2050.   var FixedInfo: TbsGridDrawInfo);
  2051.   procedure CalcAxisState(const AxisInfo: TbsGridAxisDrawInfo; Pos: Integer;
  2052.     NewState: TbsGridState);
  2053.   var
  2054.     I, Line, Back, Range: Integer;
  2055.   begin
  2056.     if UseRightToLeftAlignment then
  2057.       Pos := ClientWidth - Pos;
  2058.     with AxisInfo do
  2059.     begin
  2060.       Line := FixedBoundary;
  2061.       Range := EffectiveLineWidth;
  2062.       Back := 0;
  2063.       if Range < 7 then
  2064.       begin
  2065.         Range := 7;
  2066.         Back := (Range - EffectiveLineWidth) shr 1;
  2067.       end;
  2068.       for I := FirstGridCell to GridCellCount - 1 do
  2069.       begin
  2070.         Inc(Line, GetExtent(I));
  2071.         if Line > GridBoundary then Break;
  2072.         if (Pos >= Line - Back) and (Pos <= Line - Back + Range) then
  2073.         begin
  2074.           State := NewState;
  2075.           SizingPos := Line;
  2076.           SizingOfs := Line - Pos;
  2077.           Index := I;
  2078.           Exit;
  2079.         end;
  2080.         Inc(Line, EffectiveLineWidth);
  2081.       end;
  2082.       if (GridBoundary = GridExtent) and (Pos >= GridExtent - Back)
  2083.         and (Pos <= GridExtent) then
  2084.       begin
  2085.         State := NewState;
  2086.         SizingPos := GridExtent;
  2087.         SizingOfs := GridExtent - Pos;
  2088.         Index := LastFullVisibleCell + 1;
  2089.       end;
  2090.     end;
  2091.   end;
  2092.   function XOutsideHorzFixedBoundary: Boolean;
  2093.   begin
  2094.     with FixedInfo do
  2095.       if not UseRightToLeftAlignment then
  2096.         Result := X > Horz.FixedBoundary
  2097.       else
  2098.         Result := X < ClientWidth - Horz.FixedBoundary;
  2099.   end;
  2100.   function XOutsideOrEqualHorzFixedBoundary: Boolean;
  2101.   begin
  2102.     with FixedInfo do
  2103.       if not UseRightToLeftAlignment then
  2104.         Result := X >= Horz.FixedBoundary
  2105.       else
  2106.         Result := X <= ClientWidth - Horz.FixedBoundary;
  2107.   end;
  2108. var
  2109.   EffectiveOptions: TGridOptions;
  2110. begin
  2111.   State := gsNormal;
  2112.   Index := -1;
  2113.   EffectiveOptions := Options;
  2114.   if csDesigning in ComponentState then
  2115.     EffectiveOptions := EffectiveOptions + DesignOptionsBoost;
  2116.   if [goColSizing, goRowSizing] * EffectiveOptions <> [] then
  2117.     with FixedInfo do
  2118.     begin
  2119.       Vert.GridExtent := ClientHeight;
  2120.       Horz.GridExtent := ClientWidth;
  2121.       if (XOutsideHorzFixedBoundary) and (goColSizing in EffectiveOptions) then
  2122.       begin
  2123.         if Y >= Vert.FixedBoundary then Exit;
  2124.         CalcAxisState(Horz, X, gsColSizing);
  2125.       end
  2126.       else if (Y > Vert.FixedBoundary) and (goRowSizing in EffectiveOptions) then
  2127.       begin
  2128.         if XOutsideOrEqualHorzFixedBoundary then Exit;
  2129.         CalcAxisState(Vert, Y, gsRowSizing);
  2130.       end;
  2131.     end;
  2132. end;
  2133. procedure TbsSkinCustomGrid.ChangeGridOrientation(RightToLeftOrientation: Boolean);
  2134. var
  2135.   Org: TPoint;
  2136.   Ext: TPoint;
  2137. begin
  2138.   if RightToLeftOrientation then
  2139.   begin
  2140.     Org := Point(ClientWidth,0);
  2141.     Ext := Point(-1,1);
  2142.     SetMapMode(Canvas.Handle, mm_Anisotropic);
  2143.     SetWindowOrgEx(Canvas.Handle, Org.X, Org.Y, nil);
  2144.     SetViewportExtEx(Canvas.Handle, ClientWidth, ClientHeight, nil);
  2145.     SetWindowExtEx(Canvas.Handle, Ext.X*ClientWidth, Ext.Y*ClientHeight, nil);
  2146.   end
  2147.   else
  2148.   begin
  2149.     Org := Point(0,0);
  2150.     Ext := Point(1,1);
  2151.     SetMapMode(Canvas.Handle, mm_Anisotropic);
  2152.     SetWindowOrgEx(Canvas.Handle, Org.X, Org.Y, nil);
  2153.     SetViewportExtEx(Canvas.Handle, ClientWidth, ClientHeight, nil);
  2154.     SetWindowExtEx(Canvas.Handle, Ext.X*ClientWidth, Ext.Y*ClientHeight, nil);
  2155.   end;
  2156. end;
  2157. procedure TbsSkinCustomGrid.ChangeSize(NewColCount, NewRowCount: Longint);
  2158. var
  2159.   OldColCount, OldRowCount: Longint;
  2160.   OldDrawInfo: TbsGridDrawInfo;
  2161.   procedure MinRedraw(const OldInfo, NewInfo: TbsGridAxisDrawInfo; Axis: Integer);
  2162.   var
  2163.     R: TRect;
  2164.     First: Integer;
  2165.   begin
  2166.     First := Min(OldInfo.LastFullVisibleCell, NewInfo.LastFullVisibleCell);
  2167.     // Get the rectangle around the leftmost or topmost cell in the target range.
  2168.     R := CellRect(First and not Axis, First and Axis);
  2169.     R.Bottom := Height;
  2170.     R.Right := Width;
  2171.     Windows.InvalidateRect(Handle, @R, False);
  2172.   end;
  2173.   procedure DoChange;
  2174.   var
  2175.     Coord: TGridCoord;
  2176.     NewDrawInfo: TbsGridDrawInfo;
  2177.   begin
  2178.     if FColWidths <> nil then
  2179.     begin
  2180.       UpdateExtents(FColWidths, ColCount, DefaultColWidth);
  2181.       UpdateExtents(FTabStops, ColCount, Integer(True));
  2182.     end;
  2183.     if FRowHeights <> nil then
  2184.       UpdateExtents(FRowHeights, RowCount, DefaultRowHeight);
  2185.     Coord := FCurrent;
  2186.     if Row >= RowCount then Coord.Y := RowCount - 1;
  2187.     if Col >= ColCount then Coord.X := ColCount - 1;
  2188.     if (FCurrent.X <> Coord.X) or (FCurrent.Y <> Coord.Y) then
  2189.       MoveCurrent(Coord.X, Coord.Y, True, True);
  2190.     if (FAnchor.X <> Coord.X) or (FAnchor.Y <> Coord.Y) then
  2191.       MoveAnchor(Coord);
  2192.     if VirtualView or
  2193.       (LeftCol <> OldDrawInfo.Horz.FirstGridCell) or
  2194.       (TopRow <> OldDrawInfo.Vert.FirstGridCell) then
  2195.       InvalidateGrid
  2196.     else if HandleAllocated then
  2197.     begin
  2198.       CalcDrawInfo(NewDrawInfo);
  2199.       MinRedraw(OldDrawInfo.Horz, NewDrawInfo.Horz, 0);
  2200.       MinRedraw(OldDrawInfo.Vert, NewDrawInfo.Vert, -1);
  2201.     end;
  2202.     UpdateScrollRange(True);
  2203.     SizeChanged(OldColCount, OldRowCount);
  2204.   end;
  2205. begin
  2206.   if HandleAllocated then
  2207.     CalcDrawInfo(OldDrawInfo);
  2208.   OldColCount := FColCount;
  2209.   OldRowCount := FRowCount;
  2210.   FColCount := NewColCount;
  2211.   FRowCount := NewRowCount;
  2212.   if FixedCols > NewColCount then FFixedCols := NewColCount - 1;
  2213.   if FixedRows > NewRowCount then FFixedRows := NewRowCount - 1;
  2214.   try
  2215.     DoChange;
  2216.   except
  2217.     { Could not change size so try to clean up by setting the size back }
  2218.     FColCount := OldColCount;
  2219.     FRowCount := OldRowCount;
  2220.     DoChange;
  2221.     InvalidateGrid;
  2222.     raise;
  2223.   end;
  2224. end;
  2225. { Will move TopLeft so that Coord is in view }
  2226. procedure TbsSkinCustomGrid.ClampInView(const Coord: TGridCoord);
  2227. var
  2228.   DrawInfo: TbsGridDrawInfo;
  2229.   MaxTopLeft: TGridCoord;
  2230.   OldTopLeft: TGridCoord;
  2231. begin
  2232.   if not HandleAllocated then Exit;
  2233.   CalcDrawInfo(DrawInfo);
  2234.   with DrawInfo, Coord do
  2235.   begin
  2236.     if (X > Horz.LastFullVisibleCell) or
  2237.       (Y > Vert.LastFullVisibleCell) or (X < LeftCol) or (Y < TopRow) then
  2238.     begin
  2239.       OldTopLeft := FTopLeft;
  2240.       MaxTopLeft := CalcMaxTopLeft(Coord, DrawInfo);
  2241.       Update;
  2242.       if X < LeftCol then FTopLeft.X := X
  2243.       else if X > Horz.LastFullVisibleCell then FTopLeft.X := MaxTopLeft.X;
  2244.       if Y < TopRow then FTopLeft.Y := Y
  2245.       else if Y > Vert.LastFullVisibleCell then FTopLeft.Y := MaxTopLeft.Y;
  2246.       TopLeftMoved(OldTopLeft);
  2247.     end;
  2248.   end;
  2249. end;
  2250. procedure TbsSkinCustomGrid.DrawSizingLine(const DrawInfo: TbsGridDrawInfo);
  2251. var
  2252.   OldPen: TPen;
  2253. begin
  2254.   OldPen := TPen.Create;
  2255.   try
  2256.     with Canvas, DrawInfo do
  2257.     begin
  2258.       OldPen.Assign(Pen);
  2259.       Pen.Style := psDot;
  2260.       Pen.Mode := pmXor;
  2261.       Pen.Width := 1;
  2262.       try
  2263.         if FGridState = gsRowSizing then
  2264.         begin
  2265.           MoveTo(0, FSizingPos);
  2266.           LineTo(Horz.GridBoundary, FSizingPos);
  2267.         end
  2268.         else
  2269.         begin
  2270.           MoveTo(FSizingPos, 0);
  2271.           LineTo(FSizingPos, Vert.GridBoundary);
  2272.         end;
  2273.       finally
  2274.         Pen := OldPen;
  2275.       end;
  2276.     end;
  2277.   finally
  2278.     OldPen.Free;
  2279.   end;
  2280. end;
  2281. procedure TbsSkinCustomGrid.DrawMove;
  2282. var
  2283.   OldPen: TPen;
  2284.   Pos: Integer;
  2285.   R: TRect;
  2286. begin
  2287.   OldPen := TPen.Create;
  2288.   try
  2289.     with Canvas do
  2290.     begin
  2291.       OldPen.Assign(Pen);
  2292.       try
  2293.         Pen.Style := psDot;
  2294.         Pen.Mode := pmXor;
  2295.         Pen.Width := 5;
  2296.         if FGridState = gsRowMoving then
  2297.         begin
  2298.           R := CellRect(0, FMovePos);
  2299.           if FMovePos > FMoveIndex then
  2300.             Pos := R.Bottom else
  2301.             Pos := R.Top;
  2302.           MoveTo(0, Pos);
  2303.           LineTo(ClientWidth, Pos);
  2304.         end
  2305.         else
  2306.         begin
  2307.           R := CellRect(FMovePos, 0);
  2308.           if FMovePos > FMoveIndex then
  2309.             if not UseRightToLeftAlignment then
  2310.               Pos := R.Right
  2311.             else
  2312.               Pos := R.Left
  2313.           else
  2314.             if not UseRightToLeftAlignment then
  2315.               Pos := R.Left
  2316.             else
  2317.               Pos := R.Right;
  2318.           MoveTo(Pos, 0);
  2319.           LineTo(Pos, ClientHeight);
  2320.         end;
  2321.       finally
  2322.         Canvas.Pen := OldPen;
  2323.       end;
  2324.     end;
  2325.   finally
  2326.     OldPen.Free;
  2327.   end;
  2328. end;
  2329. procedure TbsSkinCustomGrid.FocusCell(ACol, ARow: Longint; MoveAnchor: Boolean);
  2330. begin
  2331.   MoveCurrent(ACol, ARow, MoveAnchor, True);
  2332.   UpdateEdit;
  2333.   Click;
  2334. end;
  2335. procedure TbsSkinCustomGrid.GridRectToScreenRect(GridRect: TGridRect;
  2336.   var ScreenRect: TRect; IncludeLine: Boolean);
  2337.   function LinePos(const AxisInfo: TbsGridAxisDrawInfo; Line: Integer): Integer;
  2338.   var
  2339.     Start, I: Longint;
  2340.   begin
  2341.     with AxisInfo do
  2342.     begin
  2343.       Result := 0;
  2344.       if Line < FixedCellCount then
  2345.         Start := 0
  2346.       else
  2347.       begin
  2348.         if Line >= FirstGridCell then
  2349.           Result := FixedBoundary;
  2350.         Start := FirstGridCell;
  2351.       end;
  2352.       for I := Start to Line - 1 do
  2353.       begin
  2354.         Inc(Result, GetExtent(I) + EffectiveLineWidth);
  2355.         if Result > GridExtent then
  2356.         begin
  2357.           Result := 0;
  2358.           Exit;
  2359.         end;
  2360.       end;
  2361.     end;
  2362.   end;
  2363.   function CalcAxis(const AxisInfo: TbsGridAxisDrawInfo;
  2364.     GridRectMin, GridRectMax: Integer;
  2365.     var ScreenRectMin, ScreenRectMax: Integer): Boolean;
  2366.   begin
  2367.     Result := False;
  2368.     with AxisInfo do
  2369.     begin
  2370.       if (GridRectMin >= FixedCellCount) and (GridRectMin < FirstGridCell) then
  2371.         if GridRectMax < FirstGridCell then
  2372.         begin
  2373.           FillChar(ScreenRect, SizeOf(ScreenRect), 0); { erase partial results }
  2374.           Exit;
  2375.         end
  2376.         else
  2377.           GridRectMin := FirstGridCell;
  2378.       if GridRectMax > LastFullVisibleCell then
  2379.       begin
  2380.         GridRectMax := LastFullVisibleCell;
  2381.         if GridRectMax < GridCellCount - 1 then Inc(GridRectMax);
  2382.         if LinePos(AxisInfo, GridRectMax) = 0 then
  2383.           Dec(GridRectMax);
  2384.       end;
  2385.       ScreenRectMin := LinePos(AxisInfo, GridRectMin);
  2386.       ScreenRectMax := LinePos(AxisInfo, GridRectMax);
  2387.       if ScreenRectMax = 0 then
  2388.         ScreenRectMax := ScreenRectMin + GetExtent(GridRectMin)
  2389.       else
  2390.         Inc(ScreenRectMax, GetExtent(GridRectMax));
  2391.       if ScreenRectMax > GridExtent then
  2392.         ScreenRectMax := GridExtent;
  2393.       if IncludeLine then Inc(ScreenRectMax, EffectiveLineWidth);
  2394.     end;
  2395.     Result := True;
  2396.   end;
  2397. var
  2398.   DrawInfo: TbsGridDrawInfo;
  2399.   Hold: Integer;
  2400. begin
  2401.   FillChar(ScreenRect, SizeOf(ScreenRect), 0);
  2402.   if (GridRect.Left > GridRect.Right) or (GridRect.Top > GridRect.Bottom) then
  2403.     Exit;
  2404.   CalcDrawInfo(DrawInfo);
  2405.   with DrawInfo do
  2406.   begin
  2407.     if GridRect.Left > Horz.LastFullVisibleCell + 1 then Exit;
  2408.     if GridRect.Top > Vert.LastFullVisibleCell + 1 then Exit;
  2409.     if CalcAxis(Horz, GridRect.Left, GridRect.Right, ScreenRect.Left,
  2410.       ScreenRect.Right) then
  2411.     begin
  2412.       CalcAxis(Vert, GridRect.Top, GridRect.Bottom, ScreenRect.Top,
  2413.         ScreenRect.Bottom);
  2414.     end;
  2415.   end;
  2416.   if UseRightToLeftAlignment and (Canvas.CanvasOrientation = coLeftToRight) then
  2417.   begin
  2418.     Hold := ScreenRect.Left;
  2419.     ScreenRect.Left := ClientWidth - ScreenRect.Right;
  2420.     ScreenRect.Right := ClientWidth - Hold;
  2421.   end;
  2422. end;
  2423. procedure TbsSkinCustomGrid.Initialize;
  2424. begin
  2425.   FTopLeft.X := FixedCols;
  2426.   FTopLeft.Y := FixedRows;
  2427.   FCurrent := FTopLeft;
  2428.   FAnchor := FCurrent;
  2429.   if goRowSelect in Options then FAnchor.X := ColCount - 1;
  2430. end;
  2431. procedure TbsSkinCustomGrid.InvalidateCell(ACol, ARow: Longint);
  2432. var
  2433.   Rect: TGridRect;
  2434. begin
  2435.   Rect.Top := ARow;
  2436.   Rect.Left := ACol;
  2437.   Rect.Bottom := ARow;
  2438.   Rect.Right := ACol;
  2439.   InvalidateRect(Rect);
  2440. end;
  2441. procedure TbsSkinCustomGrid.InvalidateCol(ACol: Longint);
  2442. var
  2443.   Rect: TGridRect;
  2444. begin
  2445.   if not HandleAllocated then Exit;
  2446.   Rect.Top := 0;
  2447.   Rect.Left := ACol;
  2448.   Rect.Bottom := VisibleRowCount+1;
  2449.   Rect.Right := ACol;
  2450.   InvalidateRect(Rect);
  2451. end;
  2452. procedure TbsSkinCustomGrid.InvalidateRow(ARow: Longint);
  2453. var
  2454.   Rect: TGridRect;
  2455. begin
  2456.   if not HandleAllocated then Exit;
  2457.   Rect.Top := ARow;
  2458.   Rect.Left := 0;
  2459.   Rect.Bottom := ARow;
  2460.   Rect.Right := VisibleColCount+1;
  2461.   InvalidateRect(Rect);
  2462. end;
  2463. procedure TbsSkinCustomGrid.InvalidateGrid;
  2464. begin
  2465.   Invalidate;
  2466. end;
  2467. procedure TbsSkinCustomGrid.InvalidateRect(ARect: TGridRect);
  2468. var
  2469.   InvalidRect: TRect;
  2470. begin
  2471.   if not HandleAllocated then Exit;
  2472.   GridRectToScreenRect(ARect, InvalidRect, True);
  2473.   Windows.InvalidateRect(Handle, @InvalidRect, False);