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

Delphi控件源码

开发平台:

Delphi

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