mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 19:33:49 +02:00
4180 lines
120 KiB
ObjectPascal
4180 lines
120 KiB
ObjectPascal
{
|
|
|
|
TCustomGrid, TDrawGrid and TStringGrid for Lazarus
|
|
Copyright (C) 2002 Jesus Reyes Aguilar.
|
|
email: jesusrmx@yahoo.com.mx
|
|
|
|
THIS CONTROL IS FREEWARE - USE AS YOU WILL
|
|
|
|
If you release sourcecode that uses this control, please credit me
|
|
or leave this header intact. If you release a compiled application
|
|
that uses this code, please credit me somewhere in a little bitty
|
|
location so I can at least get bragging rights!
|
|
(Extract: from Tony's checkbook tracker, http://tony.maro.net)
|
|
|
|
This code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
VERSION: 0.8.2
|
|
---------------
|
|
CHANGES Demo Program
|
|
|
|
Too many internal changes to be listed, scrollbars are now
|
|
proportional to client/grid sizes (with goSmoothScroll option
|
|
and almost proptional without it), removed OnEditor, etc.
|
|
|
|
ADDED goSmoothScroll. (default) allows scroll the grid by pixel basis
|
|
goThumbTracking. The grid acts always as if this is set, the
|
|
value is ignored due to current implementation, however if
|
|
the user set it explicitly then, when the user is scrolling,
|
|
the focused cell will be following the scroll position.
|
|
goTabs.
|
|
goAlwaysShowEditor. Still need some working
|
|
|
|
NEW AutoAdvance. Choose where the next cell position should go
|
|
if a RETURN or TABS(if enabled) is pressed
|
|
|
|
aaRight. Selected cell will go to the right
|
|
aaDown. Selected cell will go to down
|
|
|
|
BUGS goEditing:
|
|
- pressing RETURN doesn't edit the current cell
|
|
- pressing other keys doesn't start editing (need F2)
|
|
goTabs:
|
|
- Shift-TAB doesn't work
|
|
goAlwaysShowEditor:
|
|
- Still working :)
|
|
...
|
|
|
|
|
|
VERSION: 0.8.1
|
|
---------------
|
|
DATE: 28-DEC-2002
|
|
|
|
CHANGES -- Continued migrating properties from TCustomGrid to TDrawGrid
|
|
(onCellAttr, DefaultCellAttr, FixedColor, etc.)
|
|
|
|
FIXES -- FGrid in TDrawGrid was not destroyed
|
|
-- goEditing now works. I mean, you can now stop showing the
|
|
editor at F2 (although editor needs more work)
|
|
Default cell editor
|
|
-- DefaultEditor parent is now TStringGrid
|
|
-- Some fpc 1.1 issues (Mattias)
|
|
|
|
|
|
VERSION: 0.8.0
|
|
---------------
|
|
DATE: 20-DEC-2002
|
|
|
|
CHANGES Many internal changes (width,height removed from pcellsprop,
|
|
fgrid removed from tcustomgrid, colRowToClientCellRect now
|
|
uses col,row instead of point(col,row), cleaned DynamicArray,
|
|
drawcells splitted in DrawFixedCells, DrawInteriorCells, DrawFocused
|
|
so TStringGrid can implement ordered cell drawin and TCustomGrid
|
|
draw cells is simpler, etc).
|
|
|
|
ADDED ExchangeColRow(IsColumn: Boolean; Index, WithIndex: Integer);
|
|
DeleteColRow(IsColumn:Boolea; Index:Integer);
|
|
MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer);
|
|
SortColRow(IsColumn: Boolean; Index: Integer);
|
|
SortColRow(IsColumn: Boolean; Index,FromIndex,ToIndex: Integer);
|
|
Property OnColRowMoved: TgridOperationEvent
|
|
Property OnColRowDeleted: TgridOperationEvents
|
|
Property OnColRowExchanged: TgridOperationEvents
|
|
|
|
ADDED TcustomGrid derivatives can now replace sort algorithm overriding
|
|
Sort method and using exchangeColRow as needed.
|
|
|
|
|
|
VERSION: 0.7.3
|
|
-----------------
|
|
DATE: 10-DIC-2002
|
|
|
|
ADDED goDblClickAutoSize to grid Options, Doubleclicking col's right edge
|
|
automatically adjust column width (in TStringGrid).
|
|
Implemented AutoAdjustColumn() and AutoAdjustColumns.
|
|
|
|
FIXED col, row increment after grid.clear don't show the grid ( if
|
|
fixed rows-cols = 0 )
|
|
|
|
ADDED version info to saved grid files.
|
|
|
|
ADDED NEW DEMO: mysql_query. A program that connects to MySQL and shows query
|
|
results in a grid which you can save and load.
|
|
|
|
|
|
VERSION: 0.7.2
|
|
-----------------
|
|
DATE: 5-DIC-2002
|
|
FIXED a bug that prevents col, and row sizing. MouseDown uses only Left clicks
|
|
|
|
VERSION: 0.7.1
|
|
-----------------
|
|
DATE: 3-DIC-2002
|
|
ADDED LoadFromFile and SaveToFile to XML file.
|
|
SaveOptions (soDesign,soPosition,soAttributes,soContent);
|
|
soDesign: Save & Load ColCount,RowCount,FixedCols,FixedRows,
|
|
ColWidths, RowHeights and Options (TCustomGrid)
|
|
soPosition: Save & Load Scroll Position, Row, Col and Selection (TCustomGrid)
|
|
soAttributes: Save & Load Colors, Text Alignment & Layout, etc. (TDrawGrid)
|
|
soContent: Save & Load Text (TStringGrid)
|
|
|
|
ADDED TCustomgrid.Clear.
|
|
Wipe completly the grid.
|
|
ADDED goRelaxedRowSelect option
|
|
You can see focused cell and navigate freely if goRowSelect is
|
|
set.
|
|
FIXED Crash on reducing Rowcount
|
|
|
|
|
|
VERSION: 0.7.0
|
|
-----------------
|
|
RELEASE DATE: 30-NOV-2002
|
|
|
|
This unit version provides TCustomGrid, TDrawGrid and TStringGrid for lazarus
|
|
from the component user perpective there should be to much differences.
|
|
This release has only basic editing support.
|
|
|
|
Old Features:
|
|
Almost all that T*Grid can do.
|
|
|
|
New Features :
|
|
|
|
OnHeaderClick:
|
|
Detect clicks on Row(Column) Headers, it uses a property: DragDx
|
|
as a threshold in order to detect Col(Row) moving or clicking.
|
|
|
|
OnCellAttr: In this Event You can easily customize the grid.
|
|
OnDrawCell: Draw your specific cells here and then call .DefaultDrawCell
|
|
to let the grid draw other cells.
|
|
SortColumn,
|
|
SortRow: Sorting capabilities are built! you need only write one
|
|
OnCompareCells handler to do your custom sorting needs.
|
|
|
|
Exposed: DeleteColumn, DeleteRow, MoveColumn, MoveRow.
|
|
|
|
RowAttr[],RowColor[],RowFontColor[],RowAlign[]
|
|
ColAttr[],ColColor[],ColFontColor[],ColAlign[]
|
|
CellAttr[],CellColor[],CellFontColor[],CellAlign[]
|
|
|
|
GridLineStyle, FocusColor, etc.
|
|
|
|
Bugs:
|
|
|
|
+ Editor: it has a unneeded feature "auto cell filling" :)
|
|
|
|
others.
|
|
}
|
|
|
|
{.$Define dbgScroll}
|
|
|
|
unit Grids;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LCLProc, LCLType, LCLLinux, Controls, GraphType, Graphics,
|
|
Forms, VCLGlobals, DynamicArray, LMessages, Messages, XMLCfg, StdCtrls,
|
|
LResources;
|
|
|
|
Const
|
|
//GRIDFILEVERSION = 1; // Original
|
|
GRIDFILEVERSION = 2; // Introduced goSmoothScroll
|
|
|
|
Const
|
|
GM_SETVALUE = LM_USER + 100;
|
|
GM_GETVALUE = LM_USER + 101;
|
|
GM_SETGRID = LM_USER + 102;
|
|
|
|
Const
|
|
CA_LEFT = $1;
|
|
CA_CENTER = $2;
|
|
CA_RIGHT = $4;
|
|
CL_TOP = $8;
|
|
CL_CENTER = $10;
|
|
CL_BOTTOM = $20;
|
|
|
|
|
|
Type
|
|
TGridOption = (
|
|
goFixedVertLine, // Ya
|
|
goFixedHorzLine, // Ya
|
|
goVertLine, // Ya
|
|
goHorzLine, // Ya
|
|
goRangeSelect, // Ya
|
|
goDrawFocusSelected, // Ya
|
|
goRowSizing, // Ya
|
|
goColSizing, // Ya
|
|
goRowMoving, // Ya
|
|
goColMoving, // Ya
|
|
goEditing, // Ya
|
|
goTabs, // Ya
|
|
goRowSelect, // Ya
|
|
goAlwaysShowEditor, // Ya
|
|
goThumbTracking, // ya
|
|
// Additional Options
|
|
goColSpanning, // Enable cellextent calcs
|
|
goRelaxedRowSelect, // User can see focused cell on goRowSelect
|
|
goDblClickAutoSize, // dblclicking columns borders (on hdrs) resize col.
|
|
goSmoothScroll // Switch scrolling mode (pixel scroll is by default)
|
|
);
|
|
TGridSaveOptions = (
|
|
soDesign,
|
|
soAttributes,
|
|
soContent,
|
|
soPosition
|
|
);
|
|
|
|
TGridOptions = set of TGridOption;
|
|
TGridDrawState = set of (gdSelected, gdFocused, gdFixed);
|
|
TGridState =
|
|
(gsNormal, gsSelecting, gsRowSizing, gsColSizing,gsRowMoving,gsColMoving);
|
|
TGridZone = (gzNormal, gzFixedCols, gzFixedRows, gzFixedCells);
|
|
TSaveOptions = Set of TGridSaveOptions;
|
|
|
|
TUpdateOption = (uoNone, uoQuick, uoFull);
|
|
TAutoAdvance = (aaDown,aaRight);
|
|
|
|
|
|
Type
|
|
PCellAttr=^TCellAttr;
|
|
TCellAttr=Record
|
|
Color: TColor;
|
|
FontColor: TColor;
|
|
FontFace: Pchar;
|
|
TextStyle: TTextStyle;
|
|
End;
|
|
|
|
PCellProps= ^TCellProps;
|
|
TCellProps=Record
|
|
Attr: PCellAttr;
|
|
Data: TObject;
|
|
Text: pchar;
|
|
End;
|
|
|
|
Type
|
|
TCustomGrid = Class;
|
|
|
|
PGridMessage=^TGridMessage;
|
|
TGridMessage=Record
|
|
Grid: TCustomGrid;
|
|
Col,Row: Integer;
|
|
Value: String;
|
|
End;
|
|
|
|
{ Default cell editor for TStringGrid }
|
|
TStringCellEditor=Class(TCustomEdit)
|
|
Private
|
|
FGrid: TCustomGrid;
|
|
FLeaving: Boolean;
|
|
Protected
|
|
Procedure doExit; Override;
|
|
procedure KeyDown(var Key : Word; Shift : TShiftState); Override;
|
|
Procedure msg_SetValue(Var Msg: TLMessage); Message GM_SETVALUE;
|
|
Procedure msg_GetValue(Var Msg: TLMessage); Message GM_GETVALUE;
|
|
Procedure msg_SetGrid(Var Msg: TLMessage); Message GM_SETGRID;
|
|
End;
|
|
|
|
|
|
TOnDrawCell =
|
|
Procedure(Sender: TObject; Col, Row: Integer; Rect: TRect;
|
|
aState:TGridDrawState) of Object;
|
|
TOnBeforeSelectionEvent =
|
|
Procedure(Sender: TObject; Col, Row: Integer;
|
|
Var CanChange: Boolean) of Object;
|
|
TOnSelectEvent =
|
|
Procedure(Sender: TObject; Col,Row: Integer) of Object;
|
|
TOnCellAttrEvent =
|
|
Procedure(Sender:TObject; const Col, Row:Integer; aState: TGridDrawState;
|
|
Var CellProps: TCellAttr) of Object;
|
|
TGridOperationEvent =
|
|
Procedure (Sender: TObject; IsColumn:Boolean;
|
|
sIndex,tIndex: Integer) of object;
|
|
THdrEvent =
|
|
Procedure(Sender: TObject; IsColumn: Boolean; Index: Integer) of Object;
|
|
TOnCompareCells =
|
|
Function (Sender: TObject; Acol,ARow,Bcol,BRow: Integer): Integer of Object;
|
|
|
|
TVirtualGrid=Class
|
|
Private
|
|
FColCount: Integer;
|
|
FRowCount: Integer;
|
|
FCells, FCols, FRows: TArray;
|
|
function GetCells(Col, Row: Integer): PCellProps;
|
|
Function Getrows(Row: Integer): Pcellprops;
|
|
Function Getcols(Col: Integer): Pcellprops;
|
|
procedure SetCells(Col, Row: Integer; const AValue: PCellProps);
|
|
Procedure Setrows(Row: Integer; Const Avalue: Pcellprops);
|
|
Procedure Setcolcount(Const Avalue: Integer);
|
|
Procedure Setrowcount(Const Avalue: Integer);
|
|
Procedure Setcols(Col: Integer; Const Avalue: Pcellprops);
|
|
Procedure DisposeCell(Var P: PcellProps);
|
|
Protected
|
|
Function GetDefaultCell: PcellProps;
|
|
Procedure doDestroyItem(Sender: TObject; Col,Row:Integer; Var Item: Pointer);
|
|
Procedure doNewItem(Sender: TObject; Col,Row:Integer; Var Item: Pointer);
|
|
Procedure DeleteColRow(IsColumn: Boolean; Index: Integer);
|
|
Procedure MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer);
|
|
Procedure ExchangeColRow(IsColumn:Boolean; Index,WithIndex: Integer);
|
|
Public
|
|
Constructor Create;
|
|
Destructor Destroy; Override;
|
|
Procedure Clear;
|
|
Property ColCount: Integer Read FColCount Write SetColCount;
|
|
Property RowCount: Integer Read FRowCount Write SetRowCount;
|
|
|
|
Property Celda[Col,Row: Integer]: PCellProps Read GetCells Write SetCells;
|
|
Property Cols[Col: Integer]: PCellProps Read GetCols Write SetCols;
|
|
property Rows[Row: Integer]: PCellProps Read GetRows Write SetRows;
|
|
End;
|
|
|
|
|
|
Type
|
|
TGridCoord = Type TPoint;
|
|
TGridRect = Type TRect;
|
|
|
|
TGridDataCache=Record
|
|
FixedWidth: Integer; // Sum( Fixed ColsWidths[i] )
|
|
FixedHeight: Integer; // Sum( Fixed RowsHeights[i] )
|
|
GridWidth: Integer; // Sum( ColWidths[i] )
|
|
GridHeight: Integer; // Sum( RowHeights[i] )
|
|
ClientWidth: Integer; // Width-VertScrollbar.Size
|
|
ClientHeight: Integer; // Height-HorzScrollbar.Size
|
|
ScrollWidth: Integer; // ClientWidth-FixedWidth
|
|
ScrollHeight: Integer; // ClientHeight-FixedHeight
|
|
VisibleGrid: TRect; // Visible non fixed rectagle of cells
|
|
MaxClientXY: Tpoint; // VisibleGrid.BottomRight coordinates
|
|
ValidGrid: Boolean; // true if there is something to show
|
|
AccumWidth: TList; // Accumulated width per column
|
|
AccumHeight: TList; // Accumulated Height per column
|
|
HScrDiv,VScrDiv: Double; // Tx const for ThumbTracking
|
|
TLColOff,TLRowOff: Integer; // TopLeft Offset in pixels
|
|
End;
|
|
|
|
|
|
Type
|
|
//TCustomGrid=Class(TScrollBox)
|
|
//TCustomGrid=Class(TCustomControl)
|
|
TCustomGrid=Class(TScrollingWinControl)
|
|
Private
|
|
FAutoAdvance: TAutoAdvance;
|
|
FDefaultDrawing: Boolean;
|
|
FEditor: TWinControl;
|
|
FOnCompareCells: TOnCompareCells;
|
|
FGridLineStyle: TPenStyle;
|
|
FGridLineWidth: Integer;
|
|
FDefColWidth, FDefRowHeight: Integer;
|
|
FCol,FRow, FFixedCols, FFixedRows: Integer;
|
|
FGridLineColor: TColor;
|
|
|
|
FFocusColor: TColor;
|
|
FCols,FRows: TList;
|
|
|
|
FsaveOptions: TSaveOptions;
|
|
FScrollBars: TScrollStyle;
|
|
FSelectActive: Boolean;
|
|
FTopLeft: TPoint;
|
|
FSplitter, FPivot: TPoint;
|
|
FRange: TRect;
|
|
FDragDx: Integer;
|
|
FMoveLast: TPoint;
|
|
|
|
FUpdateCount: Integer;
|
|
FUpdateScrollBarsCount: Integer;
|
|
|
|
|
|
// Cached Values
|
|
FGCache: TGridDataCache;
|
|
// Options
|
|
FOptions: TGridOptions;
|
|
|
|
FOnDrawCell: TOnDrawcell;
|
|
FOnBeforeSelection: TOnBeforeSelectionEvent;
|
|
FOnSelection: TOnSelectEvent;
|
|
FOnTopLeftChange: TNotifyEvent;
|
|
|
|
Procedure AdjustCount(IsColumn:Boolean; OldValue, NewValue:Integer);
|
|
Procedure CheckFixedCount(aCol,aRow,aFCol,aFRow: Integer);
|
|
Procedure CacheVisibleGrid;
|
|
function GetSelection: TGridRect;
|
|
Function doColSizing(X,Y: Integer): Boolean;
|
|
Function doRowSizing(X,Y: Integer): Boolean;
|
|
Procedure doColMoving(X,Y: Integer);
|
|
Procedure doRowMoving(X,Y: Integer);
|
|
|
|
Function OffsetToColRow(IsCol,Fisical:Boolean; Offset:Integer; Var Rest:Integer): Integer;
|
|
Function ColRowToOffset(IsCol,Fisical:Boolean; Index: Integer; Var Ini,Fin:Integer): Boolean;
|
|
|
|
function GetLeftCol: Integer;
|
|
function GetTopRow: Longint;
|
|
function GetVisibleColCount: Integer;
|
|
function GetVisibleRowCount: Integer;
|
|
Function Getrowheights(Arow: Integer): Integer;
|
|
Function Getcolcount: Integer;
|
|
Function Getrowcount: Integer;
|
|
Function Getcolwidths(Acol: Integer): Integer;
|
|
Function GetVisibleGrid: TRect;
|
|
Procedure MyTextRect(R: TRect; Offx,Offy:Integer; S:String; Ts: TTextStyle);
|
|
Function ScrollToCell(Const aCol,aRow: Integer): Boolean;
|
|
Function ScrollGrid(Relative:Boolean; DCol,DRow: Integer): TPoint;
|
|
procedure SetDefaultDrawing(const AValue: Boolean);
|
|
procedure SetEditor(const AValue: TWinControl);
|
|
procedure SetFocusColor(const AValue: TColor);
|
|
procedure SetGridLineStyle(const AValue: TPenStyle);
|
|
procedure SetSelectActive(const AValue: Boolean);
|
|
procedure SetSelection(const AValue: TGridRect);
|
|
procedure SetFixedCols(const AValue: Integer);
|
|
procedure SetFixedRows(const AValue: Integer);
|
|
procedure SetGridLineColor(const AValue: TColor);
|
|
procedure SetGridLineWidth(const AValue: Integer);
|
|
procedure SetLeftCol(const AValue: Integer);
|
|
procedure SetOptions(const AValue: TGridOptions);
|
|
procedure SetScrollBars(const AValue: TScrollStyle);
|
|
procedure SetTopRow(const AValue: Integer);
|
|
Procedure Setrowheights(Arow: Integer; Avalue: Integer);
|
|
Procedure Setcolwidths(Acol: Integer; Avalue: Integer);
|
|
Procedure SetColCount(Valor: Integer);
|
|
Procedure SetRowCount(Valor: Integer);
|
|
Procedure SetDefColWidth(Valor: Integer);
|
|
Procedure SetDefRowHeight(Valor: Integer);
|
|
Procedure SetCol(Valor: Integer);
|
|
Procedure SetRow(Valor: Integer);
|
|
Procedure doTopleftChange(DimChg: Boolean);
|
|
Procedure TryScrollTo(aCol,aRow: integer);
|
|
Procedure UpdateScrollBarPos(Which: TControlScrollbar);
|
|
procedure VisualChange;
|
|
Procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message LM_ERASEBKGND;
|
|
Procedure WMHScroll(var Message : TLMHScroll); message LM_HScroll;
|
|
Procedure WMVScroll(var Message : TLMVScroll); message LM_VScroll;
|
|
procedure WMSize(var Msg: TWMSize); message WM_SIZE;
|
|
|
|
protected
|
|
fGridState: TGridState;
|
|
Procedure AutoAdjustColumn(aCol: Integer); Virtual;
|
|
function CellRect(ACol, ARow: Integer): TRect;
|
|
|
|
Procedure ColRowDeleted(IsColumn: Boolean; Index: Integer); Dynamic;
|
|
Procedure ColRowExchanged(IsColumn: Boolean; Index,WithIndex: Integer); Dynamic;
|
|
Procedure ColRowMoved(IsColumn: Boolean; FromIndex,ToIndex: Integer); Dynamic;
|
|
|
|
procedure ColWidthsChanged; dynamic;
|
|
procedure DblClick; Override;
|
|
Procedure doExit; Override;
|
|
Procedure doEnter; Override;
|
|
|
|
Procedure DrawEdges;
|
|
Procedure DrawBackGround; Virtual;
|
|
Procedure DrawFixedCells; Virtual;
|
|
Procedure DrawInteriorCells; Virtual;
|
|
Procedure DrawFocused; Virtual;
|
|
Procedure DrawFocusRect(aCol,aRow:Integer; ARect:TRect; aState:TGridDrawstate); Virtual;
|
|
Procedure DrawColRowMoving;
|
|
procedure DrawCell(aCol,aRow:Integer; aRect:TRect; aState:TGridDrawState); Virtual;
|
|
|
|
Procedure DrawByRows; Virtual;
|
|
Procedure DrawRow(aRow: Integer); Virtual;
|
|
|
|
Procedure HeaderClick(IsColumn: Boolean; Index: Integer); Dynamic;
|
|
procedure InvalidateCol(ACol: Integer);
|
|
procedure InvalidateRow(ARow: Integer);
|
|
Procedure InvalidateCell(aCol, aRow: Integer);
|
|
Procedure InvalidateGrid;
|
|
procedure KeyDown(var Key : Word; Shift : TShiftState); Override;
|
|
procedure KeyUp(var Key : Word; Shift : TShiftState); Override;
|
|
Procedure LoadContent(cfg: TXMLConfig); Virtual;
|
|
Procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
|
|
Procedure MouseMove(Shift: TShiftState; X,Y: Integer);Override;
|
|
Procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
|
|
Function MoveExtend(Relative: Boolean; DCol, DRow: Integer): Boolean;
|
|
Procedure MoveSelection; Virtual;
|
|
Procedure DrawCellGrid(Rect: TRect; aCol,aRow: Integer; astate: TGridDrawState);
|
|
Procedure Paint; override;
|
|
Procedure ResetOffset(chkCol, ChkRow: Boolean);
|
|
procedure RowHeightsChanged; dynamic;
|
|
function SelectCell(ACol, ARow: Integer): Boolean; virtual;
|
|
procedure SizeChanged(OldColCount, OldRowCount: Integer); dynamic;
|
|
Procedure Sort(ColSorting: Boolean; Index,IndxFrom,IndxTo:Integer); virtual;
|
|
Procedure TopLeftChanged; dynamic;
|
|
Procedure SaveContent(cfg: TXMLConfig); Virtual;
|
|
|
|
// Editor support
|
|
Protected
|
|
FEditorHiding: Boolean;
|
|
FEditorKey: Boolean;
|
|
Procedure CancelEditor; Virtual;
|
|
Procedure GetEditorValue; Virtual;
|
|
Procedure HideEditor;
|
|
Procedure SetEditorValue; Virtual;
|
|
Procedure ShowEditor;
|
|
Procedure PosEditor;
|
|
Procedure ExitEditor(Sender: TWinControl);
|
|
procedure EditorKeyDown(var Key : Word; Shift : TShiftState);
|
|
|
|
|
|
Property AutoAdvance: TAutoAdvance Read FAutoAdvance Write FAutoAdvance default aaRight;
|
|
Property ColWidths[aCol: Integer]: Integer Read GetColWidths Write SetColWidths;
|
|
Property ColCount: Integer Read GetColCount Write SetColCount;
|
|
Property Col: Integer Read FCol Write SetCol;
|
|
Property DefaultColWidth: Integer Read FDefColWidth Write SetDefColWidth;
|
|
Property DefaultRowHeight: Integer Read FDefRowHeight write SetDefRowHeight;
|
|
property DefaultDrawing: Boolean read FDefaultDrawing write SetDefaultDrawing default True;
|
|
Property DragDx: Integer read FDragDx Write FDragDx;
|
|
Property Editor: TWinControl Read FEditor Write SetEditor;
|
|
Property FixedCols: Integer read FFixedCols write SetFixedCols;
|
|
Property FixedRows: Integer read FFixedRows write SetFixedRows;
|
|
Property FocusColor: TColor read FFocusColor write SetFocusColor;
|
|
Property GridLineColor: TColor read FGridLineColor write SetGridLineColor;
|
|
Property GridLineStyle: TPenStyle read FGridLineStyle write SetGridLineStyle;
|
|
property GridWidth: Integer read FGCache.GridWidth;
|
|
property GridHeight: Integer read FGCache.GridHeight;
|
|
property GridLineWidth: Integer read FGridLineWidth write SetGridLineWidth default 1;
|
|
property LeftCol:Integer read GetLeftCol write SetLeftCol;
|
|
property Options: TGridOptions read FOptions write SetOptions;
|
|
property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars;
|
|
Property RowCount: Integer Read GetRowCount Write SetRowCount;
|
|
Property Row: Integer Read FRow Write SetRow;
|
|
Property SaveOptions: TSaveOptions Read FsaveOptions Write FSaveOptions;
|
|
Property SelectActive: Boolean read FSelectActive write SetSelectActive;
|
|
property Selection: TGridRect read GetSelection write SetSelection;
|
|
property TopRow: Integer read GetTopRow write SetTopRow;
|
|
Property RowHeights[aRow: Integer]: Integer Read GetRowHeights Write SetRowHeights;
|
|
property VisibleColCount: Integer read GetVisibleColCount;
|
|
property VisibleRowCount: Integer read GetVisibleRowCount;
|
|
|
|
Property OnDrawCell: TOnDrawCell Read FOnDrawCell Write FOnDrawCell;
|
|
Property OnBeforeSelection: TOnBeforeSelectionEvent Read fOnBeforeSelection Write fOnBeforeSelection;
|
|
Property OnSelection: TOnSelectEvent Read fOnSelection Write fOnSelection;
|
|
Property OnTopLeftChange: TNotifyEvent Read FOnTopLeftChange Write FOnTopLeftChange;
|
|
Property OnCompareCells: TOnCompareItem Read FOnCompareCells Write FOnCompareCells;
|
|
|
|
Public
|
|
Constructor Create(AOwner: TComponent); Override;
|
|
Destructor Destroy; override;
|
|
Procedure Invalidate; Override;
|
|
|
|
{ Exposed procs }
|
|
Procedure DeleteColRow(IsColumn: Boolean; Index: Integer);
|
|
Procedure ExchangeColRow(IsColumn: Boolean; Index, WithIndex: Integer);
|
|
Procedure MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer);
|
|
Procedure SortColRow(IsColumn: Boolean; Index:Integer); Overload;
|
|
Procedure SortColRow(IsColumn: Boolean; Index,FromIndex,ToIndex: Integer); Overload;
|
|
|
|
Procedure BeginUpdate;
|
|
Procedure AutoAdjustColumns;
|
|
Procedure Clear;
|
|
Procedure EndUpdate(UO: TUpdateOption); Overload;
|
|
Procedure EndUpdate(FullUpdate: Boolean); Overload;
|
|
Procedure LoadFromFile(FileName: String);
|
|
Procedure SaveToFile(FileName: String);
|
|
|
|
Function ColRowToClientCellRect(aCol, aRow: Integer): TRect;
|
|
Function MouseToCell(Mouse: TPoint): TPoint;
|
|
Function MouseToLogcell(Mouse: TPoint): TPoint;
|
|
Function MouseToGridZone(X,Y: Integer; CellCoords: Boolean): TGridZone;
|
|
Function IsCellVisible(aCol, aRow: Integer): Boolean;
|
|
Function IscellSelected(aCol,aRow: Integer): Boolean;
|
|
End;
|
|
|
|
|
|
TDrawGrid=Class(TCustomGrid)
|
|
Private
|
|
FCellAttr: TCellAttr; // Attibute used to render Cell
|
|
FOnColRowDeleted: TgridOperationEvent;
|
|
FOnColRowExchanged: TgridOperationEvent;
|
|
FOnColRowMoved: TgridOperationEvent;
|
|
FOnHeaderClick: THdrEvent;
|
|
FGrid: TVirtualGrid;
|
|
FDefCellAttr, FdefSelCellAttr, FdefFixedCellAttr: TCellAttr;
|
|
FOnCellAttr: TOnCellAttrEvent;
|
|
|
|
|
|
function GetCellAlign(ACol, ARow: Integer): Integer;
|
|
function GetCellAttr(ACol, ARow: Integer): TCellAttr;
|
|
function GetCellColor(ACol, ARow: Integer): TColor;
|
|
function GetCellFontCOlor(ACol, ARow: Integer): TColor;
|
|
function GetColAlign(aCol: Integer): Integer;
|
|
function GetColAttr(aCol: Integer): TCellAttr;
|
|
function GetColColor(aCol: Integer): TColor;
|
|
function GetColFontColor(aCol: Integer): TColor;
|
|
function GetFixedColor: TColor;
|
|
function GetRowAlign(aRow: Integer): Integer;
|
|
function GetRowAttr(aRow: Integer): TCellAttr;
|
|
function GetRowColor(aRow: Integer): TColor;
|
|
function GetRowFontColor(aRow: Integer): TColor;
|
|
procedure SetCellAlign(ACol, ARow: Integer; const AValue: Integer);
|
|
procedure SetCellAttr(ACol, ARow: Integer; const AValue: TCellAttr);
|
|
procedure SetCellColor(ACol, ARow: Integer; const AValue: TColor);
|
|
procedure SetCellFontCOlor(ACol, ARow: Integer; const AValue: TColor);
|
|
procedure SetColAlign(aCol: Integer; const AValue: Integer);
|
|
procedure SetColAttr(aCol: Integer; const AValue: TCellAttr);
|
|
procedure SetColColor(aCol: Integer; const AValue: TColor);
|
|
procedure SetColFontColor(aCol: Integer; const AValue: TColor);
|
|
procedure SetDefaultCellAttr(const AValue: TCellAttr);
|
|
procedure SetFixedColor(const AValue: TColor);
|
|
procedure SetRowAlign(aRow: Integer; const AValue: Integer);
|
|
procedure SetRowAttr(aRow: Integer; const AValue: TCellAttr);
|
|
procedure SetRowColor(aRow: Integer; const AValue: TColor);
|
|
procedure SetRowFontColor(aRow: Integer; const AValue: TColor);
|
|
|
|
Protected
|
|
Procedure CalcCellExtent(acol, aRow: Integer; Var aRect: TRect); Virtual;
|
|
Procedure DrawCell(aCol,aRow: Integer; aRect: TRect; aState:TGridDrawState); Override;
|
|
Procedure DrawFocusRect(aCol,aRow: Integer; ARect: TRect; aState: TGridDrawstate); Override;
|
|
Procedure ColRowExchanged(IsColumn: Boolean; Index,WithIndex: Integer); Override;
|
|
Procedure ColRowDeleted(IsColumn: Boolean; Index: Integer); Override;
|
|
Procedure ColRowMoved(IsColumn: Boolean; FromIndex,ToIndex: Integer); Override;
|
|
Procedure HeaderClick(IsColumn: Boolean; Index: Integer); Override;
|
|
procedure SizeChanged(OldColCount, OldRowCount: Integer); Override;
|
|
Procedure SaveContent(cfg: TXMLConfig); Override;
|
|
Procedure LoadContent(Cfg: TXMLConfig); Override;
|
|
Public
|
|
// to easy user call
|
|
Constructor Create(AOwner: TComponent); Override;
|
|
Destructor Destroy; override;
|
|
|
|
Procedure DefaultDrawCell(aCol,aRow: Integer; Var aRect: TRect; aState:TGridDrawState);
|
|
property Canvas;
|
|
|
|
Property ColAttr[aCol: Integer]: TCellAttr read GetColAttr write SetColAttr;
|
|
Property ColColor[aCol: Integer]: TColor read GetColColor write SetColColor;
|
|
Property ColFontColor[aCol: Integer]: TColor read GetColFontColor write SetColFontColor;
|
|
Property ColAlign[aCol: Integer]: Integer read GetColAlign write SetColAlign;
|
|
|
|
property FixedColor: TColor read GetFixedColor write SetFixedColor default clBtnFace;
|
|
|
|
Property RowAttr[aRow: Integer]: TCellAttr read GetRowAttr write SetRowAttr;
|
|
Property RowColor[aRow: Integer]: TColor read GetRowColor write SetRowColor;
|
|
Property RowFontColor[aRow: Integer]: TColor read GetRowFontColor write SetRowFontColor;
|
|
Property RowAlign[aRow: Integer]: Integer read GetRowAlign write SetRowAlign;
|
|
|
|
Property CellAttr[ACol,ARow:Integer]: TCellAttr read GetCellAttr write SetCellAttr;
|
|
property CellColor[ACol, ARow:Integer]: TColor read GetCellColor write SetCellColor;
|
|
Property CellFontCOlor[ACol,ARow:Integer]: TColor read GetCellFontCOlor write SetCellFontCOlor;
|
|
Property CellAlign[ACol,ARow: Integer]: Integer read GetCellAlign write SetCellAlign;
|
|
Property DefaultCellAttr: TCellAttr read fDefCellAttr write SetDefaultCellAttr;
|
|
|
|
property Col;
|
|
property ColWidths;
|
|
//property EditorMode;
|
|
property GridHeight;
|
|
property GridWidth;
|
|
property LeftCol;
|
|
property Selection;
|
|
property Row;
|
|
property RowHeights;
|
|
Property GridLineColor;
|
|
Property GridLineStyle;
|
|
Property FocusColor;
|
|
Property SaveOptions;
|
|
//property TabStops;
|
|
property TopRow;
|
|
Published
|
|
property Align;
|
|
property Anchors;
|
|
Property AutoAdvance;
|
|
//property BiDiMode;
|
|
//property BorderStyle;
|
|
property Color default clWindow;
|
|
property ColCount;
|
|
//property Constraints;
|
|
property Ctl3D;
|
|
property DefaultColWidth;
|
|
property DefaultRowHeight;
|
|
property DefaultDrawing;
|
|
//property DragCursor;
|
|
//property DragKind;
|
|
//property DragMode;
|
|
property Enabled;
|
|
property FixedCols;
|
|
property RowCount;
|
|
property FixedRows;
|
|
property Font;
|
|
property GridLineWidth;
|
|
property Options;
|
|
//property ParentBiDiMode;
|
|
//property ParentColor;
|
|
//property ParentCtl3D;
|
|
//property ParentFont;
|
|
//property ParentShowHint;
|
|
//property PopupMenu;
|
|
//property ScrollBars;
|
|
//property ShowHint;
|
|
//property TabOrder;
|
|
//property TabStop;
|
|
property Visible;
|
|
property VisibleColCount;
|
|
property VisibleRowCount;
|
|
|
|
Property OnDrawCell;
|
|
Property OnBeforeSelection;
|
|
Property OnSelection;
|
|
Property OnCellAttr: TOnCellAttrEvent read fonCellAttr Write fOnCellAttr;
|
|
Property OnTopleftChange;
|
|
Property OnCompareCells;
|
|
Property OnColRowMoved: TgridOperationEvent Read FOnColRowMoved Write FOnColRowMoved;
|
|
Property OnColRowDeleted: TgridOperationEvent Read FOnColRowDeleted Write FOnColRowDeleted;
|
|
Property OnColRowExchanged: TgridOperationEvent Read FOnColRowExchanged Write FOnColRowExchanged;
|
|
Property OnHeaderClick: THdrEvent Read FOnHeaderClick Write FOnHeaderClick;
|
|
End;
|
|
|
|
TStringGrid = class(TDrawGrid)
|
|
private
|
|
FDefEditor: TStringCellEditor;
|
|
function GetCells(ACol, ARow: Integer): string;
|
|
function GetCols(Index: Integer): TStrings;
|
|
function GetObjects(ACol, ARow: Integer): TObject;
|
|
function GetRows(Index: Integer): TStrings;
|
|
procedure SetCells(ACol, ARow: Integer; const AValue: string);
|
|
procedure SetCols(Index: Integer; const AValue: TStrings);
|
|
procedure SetObjects(ACol, ARow: Integer; AValue: TObject);
|
|
procedure SetRows(Index: Integer; const AValue: TStrings);
|
|
protected
|
|
Procedure AutoAdjustColumn(aCol: Integer); Override;
|
|
Procedure CalcCellExtent(acol, aRow: Integer; Var aRect: TRect); Override;
|
|
Procedure DrawCell(aCol,aRow: Integer; aRect: TRect; aState:TGridDrawState); Override;
|
|
Procedure GetEditorValue; Override;
|
|
Procedure SetEditorValue; Override;
|
|
Procedure SaveContent(cfg: TXMLConfig); Override;
|
|
Procedure LoadContent(cfg: TXMLConfig); Override;
|
|
Procedure DrawInteriorCells; Override;
|
|
Procedure MoveSelection; Override;
|
|
public
|
|
Constructor Create(AOWner: TComponent); Override;
|
|
Destructor Destroy; Override;
|
|
property Cells[ACol, ARow: Integer]: string read GetCells write SetCells;
|
|
property Cols[Index: Integer]: TStrings read GetCols write SetCols;
|
|
property Objects[ACol, ARow: Integer]: TObject read GetObjects write SetObjects;
|
|
property Rows[Index: Integer]: TStrings read GetRows write SetRows;
|
|
End;
|
|
|
|
Procedure DebugRect(S:String; R:TRect);
|
|
Procedure DebugPoint(S:String; P:TPoint);
|
|
|
|
|
|
implementation
|
|
|
|
{
|
|
// Dibujar una linea en el borde izquierdo de esta celda
|
|
Dc:=GetDC(handle);
|
|
Pen:=CreatePen(PS_SOLID, 3, clRed);
|
|
OldPen:=SelectObject(Dc, Pen);
|
|
MoveToEx(Dc, R.left, 0, nil);
|
|
LineTo(Dc, R.Left, FGCache.MaxClientXY.Y);
|
|
SelectObject(Dc, OldPen);
|
|
DeleteObject(Pen);
|
|
ReleaseDC(Handle, Dc);
|
|
FMoveLast:=P;
|
|
}
|
|
|
|
Function PointIgual(Const P1,P2: TPoint): Boolean;
|
|
begin
|
|
result:=(P1.X=P2.X)And(P1.Y=P2.Y);
|
|
End;
|
|
Function RectIgual(Const R1,R2: TRect): Boolean;
|
|
begin
|
|
Result:=CompareMem(@R1,@R2, SizeOf(R1));
|
|
|
|
End;
|
|
Function Min(Const I,J: Integer): Integer;
|
|
begin
|
|
If I<J then Result:=I
|
|
|
|
Else Result:=J;
|
|
End;
|
|
Function Max(Const I,J: Integer): Integer;
|
|
begin
|
|
If I>J then Result:=I
|
|
|
|
Else Result:=J;
|
|
End;
|
|
Function NormalizarRect(Const R:TRect): TRect;
|
|
Begin
|
|
Result.Left:=Min(R.Left, R.Right);
|
|
|
|
Result.Top:=Min(R.Top, R.Bottom);
|
|
Result.Right:=Max(R.Left, R.Right);
|
|
Result.Bottom:=Max(R.Top, R.Bottom);
|
|
End;
|
|
|
|
function GetDefaultCellAttr: TCellAttr;
|
|
begin
|
|
With Result do begin
|
|
FontColor:=clBlack;
|
|
Color:=clWindow;
|
|
FontFace:=nil;
|
|
With TextStyle do Begin
|
|
Alignment:=taLeftJustify;
|
|
Layout:=tlCenter;
|
|
SingleLine:=False;
|
|
WordBreak:=False;
|
|
Opaque:=False;
|
|
Clipping:=False;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure DebugAttr(Msg: String; Attr: TCellAttr);
|
|
Begin
|
|
With Attr do begin
|
|
WriteLn(Msg);
|
|
WriteLn('Color=',ColorToString(Attr.Color));
|
|
WriteLn('FontColor=',ColorToString(Attr.FontColor));
|
|
With TextStyle do begin
|
|
WriteLn('Textstyle.Alignment=', Ord(Alignment));
|
|
WriteLn('TextStyle.Layout=',Ord(Layout));
|
|
WriteLn('TextStyle.SingleLine=',Singleline);
|
|
WriteLn('TextStyle.Clipping=',Clipping);
|
|
WriteLn('TextStyle.Wordbreak=',WordBreak);
|
|
WriteLn('TextStyle.Opaque=',Opaque);
|
|
WriteLn('TextStyle.SystemFont',systemFont);
|
|
End;
|
|
End;
|
|
End;
|
|
Function LoadCellAttrFromXMLPath(Cfg: TXMLConfig; Path: String): TCellAttr;
|
|
begin
|
|
Result:=GetDefaultCellAttr;
|
|
|
|
With Result do begin
|
|
Color:=StringToColor(Cfg.GetValue(Path+'/color', ColorToString(Color)));
|
|
FontColor:=
|
|
StringToColor(Cfg.GetValue(Path+'/fontcolor',ColorToString(FontColor)));
|
|
with TextStyle do begin
|
|
Alignment:=
|
|
TAlignment(cfg.GetValue(Path+'/textstyle/alignment/value',
|
|
Integer(Alignment)));
|
|
Layout:=
|
|
TTextLayout( cfg.GetValue(Path+'/textstyle/layout/value',
|
|
Integer(layout)));
|
|
SingleLine:= cfg.GetValue(Path+'/textstyle/SingleLine/value',SingleLine);
|
|
Clipping:= cfg.GetValue(Path+'/textstyle/clipping/value',Clipping);
|
|
WordBreak:= cfg.GetValue(Path+'/textStyle/wordbreak/value',WordBreak);
|
|
Opaque:= cfg.GetValue(Path+'/textstyle/opaque/value',Opaque);
|
|
SystemFont:= cfg.GetValue(Path+'/textstyle/systemfont/value',SystemFont);
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
Function CellAttrIgual(Const Ca1,Ca2: TCellAttr): Boolean;
|
|
begin
|
|
Result:=CompareMem(@Ca1,@Ca2,SizeOf(Ca1));
|
|
End;
|
|
|
|
Procedure CellAlignToAttr(Align: Integer; Var Attr: TCellAttr);
|
|
begin
|
|
With Attr.TextStyle do Begin
|
|
If Align And CA_LEFT = CA_LEFT Then Alignment:=taLeftJustify Else
|
|
If Align And CA_CENTER = CA_CENTER Then Alignment:=taCenter
|
|
Else Alignment:=taRightJustify;
|
|
If Align And CL_TOP = CL_TOP Then Layout:=tlTop Else
|
|
If Align AND CL_CENTER = CL_CENTER Then Layout:=tlCenter
|
|
Else Layout:=tlBottom;
|
|
End;
|
|
End;
|
|
|
|
Procedure AttrToCellAlign(Attr: TCellAttr; Var Align: Integer);
|
|
begin
|
|
With Attr.TextStyle do Begin
|
|
Align:=0;
|
|
Case Alignment of
|
|
taCenter: Align:=CA_CENTER;
|
|
taRightJustify: Align:=CA_RIGHT;
|
|
Else Align:=CA_LEFT;
|
|
End;
|
|
Case Layout of
|
|
tlTop: Align:=Align or CL_TOP;
|
|
tlBottom: Align:=Align or CL_BOTTOM;
|
|
Else Align:=ALign or CL_CENTER;
|
|
end;
|
|
End;
|
|
End;
|
|
|
|
|
|
Function TCustomGrid.Getrowheights(Arow: Integer): Integer;
|
|
Begin
|
|
Result:=Integer(FRows[aRow]);
|
|
if Result<0 Then Result:=fDefRowHeight;
|
|
End;
|
|
|
|
function TCustomGrid.GetTopRow: Longint;
|
|
begin
|
|
Result:=fTopLeft.y;
|
|
end;
|
|
|
|
function TCustomGrid.GetVisibleColCount: Integer;
|
|
Var
|
|
R: TRect;
|
|
begin
|
|
R:=FGCache.VisibleGrid;
|
|
Result:=r.Right-r.left+1+FFixedCols;
|
|
end;
|
|
|
|
function TCustomGrid.GetVisibleRowCount: Integer;
|
|
Var
|
|
R: TRect;
|
|
begin
|
|
R:=FGCache.VisibleGrid;
|
|
Result:=r.bottom-r.top+1+FFixedRows;
|
|
end;
|
|
|
|
function TCustomGrid.GetLeftCol: Integer;
|
|
begin
|
|
result:=fTopLeft.x;
|
|
end;
|
|
|
|
Function TCustomGrid.Getcolcount: Integer;
|
|
Begin
|
|
Result:=FCols.Count;
|
|
End;
|
|
|
|
Function TCustomGrid.Getrowcount: Integer;
|
|
Begin
|
|
Result:=FRows.Count;
|
|
End;
|
|
|
|
Function TCustomGrid.Getcolwidths(Acol: Integer): Integer;
|
|
Begin
|
|
Result:=Integer(FCols[aCol]);
|
|
if result<0 then Result:=fDefColWidth;
|
|
End;
|
|
|
|
procedure TCustomGrid.SetEditor(const AValue: TWinControl);
|
|
begin
|
|
if FEditor=AValue then exit;
|
|
FEditor:=AValue;
|
|
if FEditor<>nil Then Begin
|
|
FEditor.Perform(GM_SETGRID, LongInt(Self), 0);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetFixedCols(const AValue: Integer);
|
|
begin
|
|
if FFixedCols=AValue then exit;
|
|
CheckFixedCount(ColCount, RowCount, AValue, FFixedRows);
|
|
FFixedCols:=AValue;
|
|
fTopLeft.x:=AValue;
|
|
fCol:=Avalue;
|
|
doTopleftChange(true);
|
|
end;
|
|
|
|
procedure TCustomGrid.SetFixedRows(const AValue: Integer);
|
|
begin
|
|
if FFixedRows=AValue then exit;
|
|
CheckFixedCount(ColCount, RowCount, FFixedCols, AValue);
|
|
FFixedRows:=AValue;
|
|
fTopLeft.y:=AValue;
|
|
FRow:=AValue;
|
|
doTopleftChange(true);
|
|
end;
|
|
|
|
procedure TCustomGrid.SetGridLineColor(const AValue: TColor);
|
|
begin
|
|
if FGridLineColor=AValue then exit;
|
|
FGridLineColor:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetLeftCol(const AValue: Integer);
|
|
begin
|
|
TryScrollTo(AValue, FTopLeft.Y);
|
|
end;
|
|
|
|
procedure TCustomGrid.SetOptions(const AValue: TGridOptions);
|
|
begin
|
|
if FOptions=AValue then exit;
|
|
FOptions:=AValue;
|
|
If goRowSelect in Options Then Begin
|
|
FRange:=Rect(FFixedCols, FRow, ColCount-1, FRow);
|
|
FOptions:=FOptions - [goAlwaysShowEditor];
|
|
End
|
|
Else FRange:=Rect(FCol,FRow,FCol,FRow);
|
|
VisualChange;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetScrollBars(const AValue: TScrollStyle);
|
|
begin
|
|
if FScrollBars=AValue then exit;
|
|
FScrollBars:=AValue;
|
|
VisualChange;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetTopRow(const AValue: Integer);
|
|
begin
|
|
TryScrollTo(FTopLeft.X, Avalue);
|
|
end;
|
|
|
|
Procedure TCustomGrid.Setrowheights(Arow: Integer; Avalue: Integer);
|
|
Begin
|
|
If AValue<0 Then AValue:=-1;
|
|
if AValue<>Integer(FRows[ARow]) Then begin
|
|
FRows[ARow]:=Pointer(AValue);
|
|
VisualChange;
|
|
RowHeightsChanged;
|
|
End;
|
|
End;
|
|
|
|
Procedure TCustomGrid.Setcolwidths(Acol: Integer; Avalue: Integer);
|
|
Begin
|
|
If AValue<0 Then Avalue:=-1;
|
|
If Avalue<>Integer(FCols[ACol]) Then begin
|
|
FCols[ACol]:=Pointer(AValue);
|
|
VisualChange;
|
|
ColWidthsChanged;
|
|
end;
|
|
End;
|
|
|
|
Procedure TCustomGrid.AdjustCount(IsColumn: Boolean; OldValue, newValue: Integer);
|
|
Procedure AddDel(Lst: TList; aCount: Integer);
|
|
Begin
|
|
While lst.Count<aCount do Lst.Add(Pointer(-1)); // default width/height
|
|
Lst.Count:=aCount;
|
|
End;
|
|
Begin
|
|
If IsColumn Then begin
|
|
AddDel(FCols, NewValue);
|
|
FGCache.AccumWidth.Count:=NewValue;
|
|
If (OldValue=0)And(NewValue>=0) Then Begin
|
|
FTopLeft.X:=FFixedCols;
|
|
If RowCount=0 then begin
|
|
FFixedRows:=0;
|
|
FTopLeft.Y:=0;
|
|
AddDel(FRows, 1); FGCache.AccumHeight.Count:=1;
|
|
End;
|
|
End;
|
|
SizeChanged(OldValue, FRows.Count);
|
|
End else begin
|
|
AddDel(fRows, NewValue);
|
|
FGCache.AccumHeight.Count:=NewValue;
|
|
If (OldValue=0)And(NewValue>=0) then Begin
|
|
FTopleft.Y:=FFixedRows;
|
|
If FCols.Count=0 then begin
|
|
FFixedCols:=0;
|
|
FTopLeft.X:=0;
|
|
AddDel(FCols, 1); FGCache.AccumWidth.Count:=1;
|
|
End;
|
|
End;
|
|
SizeChanged(FCols.Count, OldValue);
|
|
End;
|
|
VisualChange;
|
|
End;
|
|
|
|
Procedure TCustomGrid.SetColCount(Valor: Integer);
|
|
Var
|
|
OldC: Integer;
|
|
begin
|
|
If Valor=FCols.Count Then Exit;
|
|
OldC:=FCols.Count;
|
|
CheckFixedCount(Valor, RowCount, FFixedCols, FFixedRows);
|
|
AdjustCount(True, OldC, Valor);
|
|
End;
|
|
|
|
Procedure TCustomGrid.SetRowCount(Valor: Integer);
|
|
Var
|
|
OldR: Integer;
|
|
begin
|
|
If Valor=FRows.Count Then Exit;
|
|
OldR:=FRows.Count;
|
|
CheckFixedCount(ColCount, Valor, FFixedCols, FFixedRows);
|
|
AdjustCount(False, OldR, Valor);
|
|
End;
|
|
|
|
Procedure TCustomGrid.SetDefColWidth(Valor: Integer);
|
|
begin
|
|
If Valor=fDefColwidth Then Exit;
|
|
FDefColWidth:=Valor;
|
|
VisualChange;
|
|
End;
|
|
|
|
Procedure TCustomGrid.SetDefRowHeight(Valor: Integer);
|
|
begin
|
|
If Valor=fDefRowHeight Then Exit;
|
|
FDefRowheight:=Valor;
|
|
VisualChange;
|
|
End;
|
|
|
|
procedure TCustomGrid.SetCol(Valor: Integer);
|
|
begin
|
|
If Valor=FCol Then Exit;
|
|
MoveExtend(False, Valor, FRow);
|
|
end;
|
|
|
|
procedure TCustomGrid.SetRow(Valor: Integer);
|
|
begin
|
|
If Valor=FRow Then Exit;
|
|
MoveExtend(False, FCol, Valor);
|
|
end;
|
|
|
|
procedure TCustomGrid.Sort(ColSorting: Boolean; Index, IndxFrom, IndxTo: Integer);
|
|
Procedure QuickSort(L,R: Integer);
|
|
Var
|
|
i,j: Integer;
|
|
P{,Q}: Integer;
|
|
begin
|
|
Repeat
|
|
I:=L;
|
|
J:=R;
|
|
P:=(L+R)Div 2;
|
|
Repeat
|
|
If ColSorting Then begin
|
|
While OnCompareCells(Self, Index, P, Index, i)>0 do I:=I+1;
|
|
While OnCompareCells(Self, Index, P, Index, j)<0 do J:=J-1;
|
|
end Else begin
|
|
While OnCompareCells(Self, P, Index, i, Index)>0 do I:=I+1;
|
|
While OnCompareCells(Self, P, Index, j, Index)<0 do J:=J-1;
|
|
End;
|
|
If I<=J Then Begin
|
|
ExchangeColRow(Not ColSorting, i,j);
|
|
I:=I+1;
|
|
J:=j-1;
|
|
End;
|
|
Until I>J;
|
|
If L<J Then QuickSort(L,J);
|
|
L:=I;
|
|
Until I>=R;
|
|
End;
|
|
begin
|
|
BeginUpdate;
|
|
QuickSort(IndxFrom, IndxTo);
|
|
EndUpdate(True);
|
|
end;
|
|
|
|
procedure TCustomGrid.doTopleftChange(dimChg: Boolean);
|
|
begin
|
|
TopLeftChanged;
|
|
If dimchg then Begin
|
|
VisualChange;
|
|
End Else begin
|
|
CacheVisibleGrid;
|
|
Invalidate;
|
|
End;
|
|
UpdateScrollBarPos(nil);
|
|
end;
|
|
|
|
procedure TCustomGrid.VisualChange;
|
|
Var
|
|
Tw,Th: Integer;
|
|
Dh,DV: Integer;
|
|
|
|
Function MaxTopLeft: TPoint;
|
|
Var
|
|
i: Integer;
|
|
W,H: Integer;
|
|
begin
|
|
Result:=Point(ColCount-1, RowCount-1);
|
|
W:=0;
|
|
For i:=ColCount-1 downTo FFixedCols Do begin
|
|
W:=W+GetColWidths(i);
|
|
If W<FGCache.ScrollWidth Then Result.x:=i
|
|
Else Break;
|
|
End;
|
|
H:=0;
|
|
For i:=RowCount-1 downto FFixedRows do begin
|
|
H:=H+GetRowHeights(i);
|
|
If H<FGCache.ScrollHeight Then Result.y:=i
|
|
Else Break;
|
|
End;
|
|
End;
|
|
Var
|
|
Mtl: TPoint;
|
|
{$Ifdef TestSbars} vs,hs: Boolean; {$Endif}
|
|
begin
|
|
// Calculate New Cached Values
|
|
FGCache.GridWidth:=0;
|
|
For Tw:=0 To ColCount-1 do begin
|
|
FGCache.AccumWidth[Tw]:=Pointer(FGCache.GridWidth);
|
|
FGCache.GridWidth:=FGCache.GridWidth + GetColWidths(Tw);
|
|
If Tw<FixedCols Then FGCache.FixedWidth:=FGCache.GridWidth;
|
|
{$IfDef dbgScroll}
|
|
WriteLn('FGCache.AccumWidth[',Tw,']=',Integer(FGCache.AccumWidth[Tw]));
|
|
{$Endif}
|
|
End;
|
|
FGCache.Gridheight:=0;
|
|
For Tw:=0 To RowCount-1 do begin
|
|
FGCache.AccumHeight[Tw]:=Pointer(FGCache.Gridheight);
|
|
FGCache.Gridheight:=FGCache.Gridheight+GetRowHeights(Tw);
|
|
If Tw<FixedRows Then FGCache.FixedHeight:=FGCache.GridHeight;
|
|
{$IfDef dbgScroll}
|
|
WriteLn('FGCache.AccumHeight[',Tw,']=',Integer(FGCache.AccumHeight[Tw]));
|
|
{$Endif}
|
|
End;
|
|
|
|
Dh:=18{GetSystemMetrics(SM_CYHSCROLL)};
|
|
DV:=18{GetSystemMetrics(SM_CXVSCROLL)};
|
|
TW:=FGCache.GridWidth;
|
|
TH:=FGCache.GridHeight;
|
|
|
|
If Not(goSmoothScroll in Options) Then begin
|
|
FGCache.TLColOff:=0;
|
|
FGCache.TLRowOff:=0;
|
|
End;
|
|
|
|
{$Ifdef TestSBars}
|
|
vs:=VertScrollBar.Visible;
|
|
hs:=HorzScrollBar.Visible;
|
|
{$Endif}
|
|
|
|
HorzScrollBar.Visible:=
|
|
(FScrollbars in [ssHorizontal, ssBoth]) or
|
|
((FScrollbars in [ssAutoHorizontal,ssAutoBoth]) and (TW>Width-Dv));
|
|
|
|
VertScrollBar.Visible:=
|
|
(FScrollbars in [ssVertical, ssBoth]) or
|
|
((FScrollbars in [ssAutoVertical, ssAutoBoth]) and (TH>height-Dh));
|
|
|
|
If Not HorzScrollBar.Visible Then DH:=0;
|
|
If Not VertScrollBar.Visible Then DV:=0;
|
|
|
|
{$IfDef TestSBars}
|
|
If (vs<VertScrollBar.Visible) Then
|
|
WriteLn('Vertical Scrollbar Visible=', VertScrollBar.visible);
|
|
if (hs<>HorzScrollBar.Visible) Then
|
|
WriteLn('Horizontal Scrollbar Visible=', HorzScrollBar.Visible );
|
|
{$Endif}
|
|
|
|
FGCache.ClientWidth:=Width - DV;
|
|
FGCache.ClientHeight:=Height - DH;
|
|
FGCache.ScrollWidth:=FGCache.ClientWidth-FGCache.FixedWidth;
|
|
FGCache.ScrollHeight:=FGCache.ClientHeight-FGCache.FixedHeight;
|
|
|
|
Mtl:=MaxTopLeft;
|
|
{$Ifdef DbgScroll}
|
|
DebugPoint('MaxTopLeft',MaxTopLeft);
|
|
{$Endif}
|
|
FGCache.HScrDiv:=0;
|
|
FGCache.VScrDiv:=0;
|
|
|
|
With FGCache do
|
|
If FScrollBars in [ssAutoHorizontal, ssAutoBoth] then begin
|
|
If HorzScrollBar.Visible Then begin
|
|
HorzScrollBar.Range:= GridWidth+2;
|
|
|
|
If NOt (goSmoothScroll in Options) Then Begin
|
|
TW:= Integer(AccumWidth[Mtl.X])-(HorzScrollBar.Range-ClientWidth);
|
|
HorzScrollBar.Range:= HorzScrollBar.Range + TW - FixedWidth + 1;
|
|
End;
|
|
|
|
If HorzScrollBar.Range>ClientWidth Then
|
|
HScrDiv:= (ColCount-FixedRows-1)/(HorzScrollBar.range-ClientWidth);
|
|
|
|
{$Ifdef dbgScroll}
|
|
Writeln('TotWidth=',GridWidth,'ClientWidth=',ClientWidth,' Horz Range=',HorzScrolLBar.Range);
|
|
{$Endif}
|
|
End
|
|
End Else
|
|
If FScrollBars in [ssHorizontal, ssBoth] Then HorzScrolLBar.Range:=0;
|
|
|
|
With FGCache do
|
|
If FScrollBars in [ssAutoVertical, ssAutoBoth] Then Begin
|
|
If VertScrollBar.Visible Then begin
|
|
VertScrollBar.Range:=GridHeight + 2;
|
|
|
|
If Not (goSmoothScroll in Options) Then begin
|
|
TH:= Integer(accumHeight[Mtl.Y])-(VertScrollBar.Range-ClientHeight);
|
|
VertScrollBar.Range:= VertScrollBar.Range + TH - FixedHeight + 1;
|
|
End;
|
|
|
|
If VertScrolLBar.Range>ClientHeight Then
|
|
VScrDiv:= (RowCount-FixedRows-1)/(VertScrollBar.Range-ClientHeight);
|
|
|
|
{$Ifdef dbgScroll}
|
|
Writeln('TotHeight=',GridHeight,'ClientHeight=',ClientHeight,' Vert Range=',VertScrolLBar.Range);
|
|
{$Endif}
|
|
End
|
|
End Else
|
|
If FScrollBars in [ssVertical, ssBoth] then VertScrollbar.Range:=0;
|
|
|
|
CacheVisibleGrid;
|
|
Invalidate;
|
|
end;
|
|
|
|
function TCustomGrid.CellRect(ACol, ARow: Integer): TRect;
|
|
begin
|
|
Result:=ColRowToClientCellRect(aCol,aRow);
|
|
end;
|
|
|
|
// The visible grid Depends on TopLeft and ClientWidht,ClientHeight,
|
|
// Col/Row Count, So it Should be called inmediately after any change
|
|
// like that
|
|
function TCustomGrid.GetVisibleGrid: TRect;
|
|
Var
|
|
w: Integer;
|
|
MaxRight: Integer;
|
|
MaxBottom: Integer;
|
|
begin
|
|
If (FTopLeft.X<0)or(FTopLeft.y<0) then begin
|
|
Result:=Rect(-1,-1,-1,-1);
|
|
Exit;
|
|
End;
|
|
// visible TopLeft Cell
|
|
Result.TopLeft:=fTopLeft;
|
|
Result.BottomRight:=Result.TopLeft;
|
|
|
|
// Max visible coordinates
|
|
MaxRight:= FGCache.ClientWidth;
|
|
MaxBottom:=FGCache.ClientHeight;
|
|
|
|
// Left Margin of next visible Column and Rightmost visible cell
|
|
w:=GetColWidths(Result.Left) + FGCache.FixedWidth- FGCache.TLColOff;
|
|
While (Result.Right<ColCount-1)And(W<MaxRight) do begin
|
|
Inc(Result.Right);
|
|
W:=W+GetColWidths(Result.Right);
|
|
End;
|
|
|
|
// Top Margin of next visible Row and Bottom most visible cell
|
|
w:=GetRowheights(Result.Top) + FGCache.FixedHeight - FGCache.TLRowOff;
|
|
While (Result.Bottom<RowCount-1)And(W<MaxBottom) do begin
|
|
Inc(Result.Bottom);
|
|
W:=W+GetRowHeights(Result.Bottom);
|
|
End;
|
|
end;
|
|
|
|
{Calculate the TopLeft needed to show cell[aCol,aRow]}
|
|
Function TCustomGrid.ScrollToCell(Const aCol,aRow: Integer): Boolean;
|
|
Var
|
|
RNew: TRect;
|
|
Fw,Fh,Cw,Ch: Integer;
|
|
OldTopLeft:TPoint;
|
|
Xinc,YInc: Integer;
|
|
begin
|
|
Cw:=FGCache.ClientWidth; //ClientWidth;
|
|
Ch:=FGCache.ClientHeight; //ClientHeight;
|
|
|
|
Fw:=FGCache.FixedWidth; //GetFixedWidth;
|
|
Fh:=FGcache.FixedWidth; //GetFixedHeight;
|
|
|
|
OldTopLeft:=fTopLeft;
|
|
While (fTopLeft.x>=0) And
|
|
(fTopLeft.x<ColCount)And
|
|
(fTopLeft.y>=0) And
|
|
(fTopLeft.y<RowCount) do begin
|
|
|
|
RNew:=ColRowToClientCellRect(aCol,aRow);
|
|
|
|
Xinc:=0;
|
|
if Rnew.Left<fw then Xinc:=-1
|
|
Else If RNew.Right>Cw Then XInc:=1;
|
|
Yinc:=0;
|
|
if RNew.Top<fh Then Yinc:=-1
|
|
Else If RNew.Bottom>Ch Then YInc:=1;
|
|
|
|
With FTopLeft do
|
|
If ((XInc=0)And(Yinc=0)) or
|
|
((X=aCol)and(y=aRow)) Or // Only Perfect fit !
|
|
((X+XInc>=ColCount)or(Y+Yinc>=RowCount)) Or // Last Posible
|
|
((X+XInc<0)Or(Y+Yinc<0)) // Least Posible
|
|
Then Break;
|
|
|
|
Inc(FTopLeft.x, XInc);
|
|
Inc(FTopLeft.y, Yinc);
|
|
end;
|
|
|
|
Result:=Not PointIgual(OldTopleft,FTopLeft);
|
|
If result Then doTopleftChange(False);
|
|
End;
|
|
|
|
{Returns a valid TopLeft from a proposed TopLeft[DCol,DRow] which are
|
|
relative or absolute coordinates }
|
|
function TCustomGrid.ScrollGrid(Relative: Boolean; DCol, DRow: Integer): TPoint;
|
|
begin
|
|
Result:=FTopLeft;
|
|
If Not Relative Then begin
|
|
DCol:=DCol-Result.x;
|
|
DRow:=DRow-Result.y;
|
|
End;
|
|
|
|
If DCol+Result.x<FFixedCols Then DCol:=Result.x-FFixedCols Else
|
|
If DCol+Result.x>ColCount-1 Then DCol:=ColCount-1-Result.x;
|
|
If DRow+Result.y<FFixedRows Then DRow:=Result.y-FFixedRows Else
|
|
If DRow+Result.y>RowCount-1 Then DRow:=RowCount-1-Result.y;
|
|
|
|
Inc(Result.x, DCol);
|
|
Inc(Result.y, DRow);
|
|
end;
|
|
|
|
procedure TCustomGrid.TopLeftChanged;
|
|
begin
|
|
If Assigned(OnTopLeftChange) Then OnTopLeftChange(Self);
|
|
end;
|
|
|
|
{$hints off}
|
|
procedure TCustomGrid.HeaderClick(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
end;
|
|
procedure TCustomGrid.ColRowMoved(IsColumn: Boolean; FromIndex,ToIndex: Integer);
|
|
begin
|
|
end;
|
|
procedure TCustomGrid.ColRowExchanged(isColumn: Boolean; Index, WithIndex: Integer);
|
|
begin
|
|
end;
|
|
procedure TCustomGrid.DrawFocusRect(aCol, aRow: Integer; ARect: TRect;
|
|
aState: TGridDrawstate);
|
|
begin
|
|
end;
|
|
procedure TCustomGrid.AutoAdjustColumn(aCol: Integer);
|
|
begin
|
|
end;
|
|
procedure TCustomGrid.SizeChanged(OldColCount, OldRowCount: Integer);
|
|
begin
|
|
end;
|
|
procedure TCustomGrid.ColRowDeleted(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
end;
|
|
{$hints on}
|
|
|
|
|
|
procedure TCustomGrid.Paint;
|
|
begin
|
|
Inherited Paint;
|
|
If Not (csDesigning in ComponentState) Then begin
|
|
If FUpdateCount=0 Then begin
|
|
//WriteLn('Paint: FGCache.ValidGrid=',FGCache.ValidGrid );
|
|
DrawEdges;
|
|
DrawBackGround;
|
|
If FGCache.ValidGrid Then begin
|
|
{
|
|
DrawFixedCells;
|
|
DrawInteriorCells;
|
|
DrawFocused;
|
|
}
|
|
DrawByRows;
|
|
DrawColRowMoving;
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
procedure TCustomGrid.ResetOffset(chkCol, ChkRow: Boolean);
|
|
begin
|
|
With FGCache do begin
|
|
If ChkCol Then ChkCol:=TLColOff<>0;
|
|
If ChkCol Then TlColOff:=0;
|
|
If ChkRow Then ChkRow:=TLRowOff<>0;
|
|
If ChkRow Then TlRowOff:=0;
|
|
If ChkRow or ChkCol Then begin
|
|
CacheVisibleGrid;
|
|
Invalidate;
|
|
If ChkCol Then UpdateScrollBarPos(HorzScrollBar);
|
|
If ChkRow Then UpdateScrolLBarPos(VertScrollBar);
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
|
|
function TCustomGrid.SelectCell(ACol, ARow: Integer): Boolean;
|
|
begin
|
|
Result:=MoveExtend(False, aCol, aRow);
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawBackGround;
|
|
begin
|
|
{
|
|
The user can draw a something here :)
|
|
|
|
Canvas.Brush.Color:=Color;
|
|
Canvas.FillRect(Parent.ClientRect);
|
|
}
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawFixedCells;
|
|
Var
|
|
Gds: TGridDrawState;
|
|
i,j: Integer;
|
|
begin
|
|
Gds:=[gdFixed];
|
|
// Draw fixed fixed Cells
|
|
For i:=0 to FFixedCols-1 do
|
|
For j:=0 to fFixedRows-1 do
|
|
DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
|
|
With FGCache.VisibleGrid do begin
|
|
// Draw fixed column headers
|
|
For i:=left to Right do
|
|
For j:=0 to fFixedRows-1 do
|
|
DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
// Draw fixed row headers
|
|
For i:=0 to FFixedCols-1 do
|
|
For j:=Top to Bottom do
|
|
DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawInteriorCells;
|
|
Var
|
|
Gds: TGridDrawState;
|
|
i,j: Integer;
|
|
begin
|
|
With FGCache.VisibleGrid do Begin
|
|
For i:=Left to Right do
|
|
For j:=Top to Bottom do begin
|
|
Gds:=[];
|
|
if (i=FCol)And(J=FRow) Then Continue;
|
|
If IsCellSelected(i,j) Then Include(gds, gdSelected);
|
|
DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawColRowMoving;
|
|
begin
|
|
If (FGridState=gsColMoving)And(fMoveLast.x>=0) Then begin
|
|
Canvas.Pen.Width:=3;
|
|
Canvas.Pen.Color:=clRed;
|
|
Canvas.MoveTo(fMoveLast.y, 0);
|
|
Canvas.Lineto(fMovelast.y, FGCache.MaxClientXY.Y);
|
|
Canvas.Pen.Width:=1;
|
|
end Else
|
|
If (FGridState=gsRowMoving)And(FMoveLast.y>=0) then begin
|
|
Canvas.Pen.Width:=3;
|
|
Canvas.Pen.Color:=clRed;
|
|
Canvas.MoveTo(0, FMoveLast.X);
|
|
Canvas.LineTo(FGCache.MaxClientXY.X, FMoveLast.X);
|
|
Canvas.Pen.Width:=1;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawCell(aCol, aRow: Integer; aRect: TRect;
|
|
aState: TGridDrawState);
|
|
begin
|
|
DrawCellGrid(aRect,aCol,aRow,aState);
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawByRows;
|
|
Var
|
|
i: Integer;
|
|
begin
|
|
// Draw Rows
|
|
With FGCache.VisibleGrid do
|
|
For i:=Top To Bottom do DrawRow(i);
|
|
// Draw Fixed Rows
|
|
For i:=0 to FFixedRows-1 Do DrawRow(i);
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawRow(aRow: Integer);
|
|
Var
|
|
Gds: TGridDrawState;
|
|
i: Integer;
|
|
Rs: Boolean;
|
|
R: TRect;
|
|
begin
|
|
|
|
ColRowToOffSet(False, True, aRow, R.Top, R.Bottom);
|
|
|
|
// Draw columns in this row
|
|
With FGCache.VisibleGrid do
|
|
If ARow<FFixedRows Then Begin
|
|
gds:=[gdFixed];
|
|
For i:=Left to Right do Begin
|
|
ColRowToOffset(true, True, i, R.Left, R.Right);
|
|
DrawCell(i,aRow, R{ColRowToClientCellRect(i,aRow)},gds)
|
|
End;
|
|
End Else begin
|
|
Rs:=(goRowSelect in Options);
|
|
For i:=Left To Right do begin
|
|
Gds:=[];
|
|
If (i=Fcol)And(FRow=ARow) Then begin
|
|
// Focused Cell
|
|
Include(gds, gdFocused);
|
|
// Check if need to be selected
|
|
If (goDrawFocusSelected in Options) or
|
|
(Rs And Not(goRelaxedRowSelect in Options)) Then Include(gds, gdSelected);
|
|
End Else
|
|
If IsCellSelected(i, ARow) Then Include(gds, gdSelected);
|
|
ColRowToOffset(True, True, i, R.Left, R.Right);
|
|
DrawCell(i,aRow, R{ColRowToClientCellRect(i,aRow)}, gds);
|
|
End;
|
|
// Draw the focus Rect
|
|
If (ARow=FRow) And
|
|
(IsCellVisible(FCol,ARow) Or (Rs And (ARow>=Top) And (ARow<=Bottom)))
|
|
Then Begin
|
|
ColRowToOffset(True, True, FCol, R.Left, R.Right);
|
|
DrawFocusRect(FCol,FRow, R{ColRowToClienTCellRect(FCol,FRow)}, [gdFocused]);
|
|
End;
|
|
End; // Else Begin
|
|
|
|
// Draw Fixed Columns
|
|
gds:=[gdFixed];
|
|
For i:=0 to FFixedCols-1 do begin
|
|
ColRowToOffset(True, True, i, R.Left, R.Right);
|
|
DrawCell(i,aRow, R{ColRowToClientCellRect(i,aRow)},gds);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawEdges;
|
|
Var
|
|
P: TPoint;
|
|
Cr: TRect;
|
|
begin
|
|
P:=FGCache.MaxClientXY;
|
|
Cr:=Bounds(0,0, FGCache.ClientWidth, FGCache.ClientHeight);
|
|
If P.x<Cr.Right Then begin
|
|
Cr.Left:=P.x;
|
|
Canvas.Brush.Color:=Color;
|
|
Canvas.FillRect(cr);
|
|
Cr.Left:=0;
|
|
Cr.Right:=p.x;
|
|
End;
|
|
If P.y<Cr.Bottom Then begin
|
|
Cr.Top:=p.y;
|
|
Canvas.Brush.Color:=Color;
|
|
Canvas.FillRect(cr);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.DrawFocused;
|
|
Var
|
|
R: TRect;
|
|
gds: TGridDrawState;
|
|
begin
|
|
gds:=[gdFocused];
|
|
If IsCellVisible(FCol,FRow) Then begin
|
|
If goDrawFocusSelected in Options Then Include(gds,gdSelected);
|
|
If (goRowSelect in Options) And Not (goRelaxedRowSelect in Options) Then
|
|
Include(gds, gdSelected);
|
|
R:=colrowToClientCellRect(fCol,fRow);
|
|
DrawCell(fCol,fRow,R, gds);
|
|
DrawFocusRect(fCol,fRow, R, gds);
|
|
End Else
|
|
If ((goRowSelect in Options) And
|
|
(Frow>=FGCache.VisibleGrid.Top) And
|
|
(Frow<=FGCache.VisibleGrid.Bottom))
|
|
Then begin
|
|
R:=colrowToClientCellRect(fCol,fRow);
|
|
DrawFocusRect(fcol,fRow, R, gds);
|
|
End;
|
|
end;
|
|
|
|
Procedure DebugRect(S:String; R:TRect);
|
|
begin
|
|
WriteLn(S, 'L=',R.Left, ' T=',R.Top, ' R=',R.Right,' B=',R.Bottom);
|
|
End;
|
|
Procedure DebugPoint(S:String; P:TPoint);
|
|
begin
|
|
WriteLn(S, 'X=',P.X,' Y=',P.Y);
|
|
End;
|
|
|
|
procedure TCustomGrid.DrawCellGrid(Rect: TRect; aCol,aRow: Integer; aState: TGridDrawState);
|
|
Var
|
|
dv,dh: Boolean;
|
|
begin
|
|
// Draw Cell Grid or Maybe in the future Borders..
|
|
Dv:= goVertLine in Options;
|
|
Dh:= goHorzLine In Options;
|
|
If (gdFixed in aState) Then begin
|
|
With Canvas, Rect do Begin
|
|
Pen.Style:=psSolid;
|
|
Pen.Color:=cl3DDkShadow;
|
|
MoveTo(Left,Bottom-1);
|
|
LineTo(Right-1,Bottom-1);
|
|
LineTo(Right-1,Top-1);
|
|
//if ARow=FItemIndex then begin
|
|
Pen.Color:=cl3DDkShadow;
|
|
MoveTo(Left,Bottom-1);
|
|
LineTo(Left,Top);
|
|
LineTo(Right-1,Top);
|
|
Pen.Color:=cl3DLight;
|
|
MoveTo(Left+1,Bottom-2);
|
|
LineTo(Right-1,Bottom-2);
|
|
//End;
|
|
End;
|
|
//Canvas.Frame3d(Rect, 1, bvLowered{bvNone}{bvRaised});
|
|
Dh:=Dh and (goFixedHorzLine in Options);
|
|
Dv:=Dv and (goFixedVertLine in Options);
|
|
End;
|
|
|
|
Canvas.Pen.Style:=fGridLineStyle;
|
|
Canvas.Pen.Color:=fGridLineColor;
|
|
If Dh Then begin
|
|
//If fDrawHorzGrid then begin
|
|
Canvas.MoveTo(Rect.Left,Rect.Top);
|
|
Canvas.LineTo(Rect.Right,Rect.Top);
|
|
If aRow=RowCount-1 Then begin
|
|
Canvas.MoveTo(Rect.Left,Rect.Bottom);
|
|
Canvas.LineTo(Rect.Right,Rect.Bottom);
|
|
End;
|
|
End;
|
|
|
|
If Dv Then begin
|
|
//If FDrawVertGrid Then begin
|
|
Canvas.MoveTo(Rect.Left,Rect.Top);
|
|
Canvas.LineTo(Rect.Left,Rect.Bottom);
|
|
If aCol=ColCount-1 Then begin
|
|
Canvas.Moveto(Rect.Right, Rect.Top);
|
|
Canvas.LineTo(Rect.Right, Rect.bottom);
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
|
|
procedure TCustomGrid.MyTextRect(R: TRect; Offx, Offy: Integer; S: String;
|
|
Ts: TTextStyle);
|
|
Var
|
|
Rorg: TRect;
|
|
tmpRgn: HRGN;
|
|
begin
|
|
If Ts.Clipping Then begin
|
|
//IntersectClipRect(Canvas.handle, R.Left,R.Top,R.Right,R.Bottom);
|
|
|
|
GetClipBox(Canvas.Handle, @ROrg);
|
|
//DebugRect('Ini Rect = ', ROrg);
|
|
tmpRGN:=CreateRectRgn(R.Left, R.Top, R.Right, R.Bottom);
|
|
SelectClipRgn(Canvas.Handle, tmpRGN);
|
|
//GetClipBox(Canvas.Handle, @Rtmp);
|
|
//DebugRect('Set Rect = ', Rtmp);
|
|
DeleteObject(tmpRGN);
|
|
End;
|
|
|
|
//If Ts.Opaque Then Canvas.FillRect(R);
|
|
Canvas.TextOut(R.Left+Offx, R.Top+Offy, S);
|
|
|
|
If Ts.Clipping Then begin
|
|
tmpRGN:=CreateRectRgn(Rorg.Left, Rorg.Top, Rorg.Right, Rorg.Bottom);
|
|
SelectClipRgn(Canvas.Handle, tmpRGN);
|
|
//GetClipBox(Canvas.Handle, @Rtmp);
|
|
//DebugRect('End Rect = ', Rtmp);
|
|
DeleteObject(tmpRGN);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.WMEraseBkgnd(var Message: TLMEraseBkgnd);
|
|
begin
|
|
Message.Result:=1;
|
|
WriteLn('TCustomGrid.WMEraseBkgnd');
|
|
end;
|
|
|
|
|
|
//
|
|
// NOTE: WMHScroll and VMHScroll
|
|
// This methods are used to pre-calculate the scroll position
|
|
//
|
|
{$IFDEF Scr1}
|
|
{
|
|
-- This is the original 'row' scroll method
|
|
-- in WMHScroll.Pos arrives a value from 0 .. [Max TopLeft Column]-FixedCols
|
|
-- in WMVScroll.Pos arrives a value from 0 .. [Max TopLeft Row ]-FixedRows
|
|
-- Scrollbar sizes are not proportional :(
|
|
}
|
|
{$ELSE}
|
|
{
|
|
-- This is the new 'not so pixel' scroll method,
|
|
}
|
|
{$Endif}
|
|
|
|
procedure TCustomGrid.WMHScroll(var Message: TLMHScroll);
|
|
Var
|
|
C,Tl: Integer;
|
|
begin
|
|
// Avoid invalidating right know, just let the scrollbar
|
|
// calculate its position
|
|
BeginUpdate;
|
|
Inherited;
|
|
Message.Result:=1;
|
|
EndUpdate(uoNone);
|
|
|
|
{$IfDef dbgScroll}
|
|
WriteLn('HSCROLL: Code=',Message.ScrollCode,' Position=', Message.Pos);
|
|
{$Endif}
|
|
|
|
|
|
{$IfDef Scr1}
|
|
TL:=FFixedCols+ Message.Pos;
|
|
If FEditor<>nil then getEditorValue;
|
|
Inc(FUpdateScrollBarsCount);
|
|
TryScrollTo(Tl, FTopLeft.Y);
|
|
Dec(FUpdateScrollBarsCount);
|
|
Message.Result:=1;
|
|
{$Else}
|
|
|
|
If FGCache.HScrDiv<=0 Then Exit;
|
|
If FEditor<>nil then getEditorValue;
|
|
|
|
If goThumbTracking in Options Then Begin
|
|
C:=FFixedCols + Round( Message.Pos * FGCache.HScrDiv );
|
|
If (FCol<>C) Then begin
|
|
Inc(FUpdateScrollBarsCount);
|
|
MoveExtend(False, C, FRow);
|
|
Dec(FUpdateScrollBarsCount);
|
|
End;
|
|
End Else begin
|
|
|
|
C:=Message.Pos+FGCache.FixedWidth;
|
|
TL:=OffsetToColRow(True, False, C, FGCache.TLColOff);
|
|
{$Ifdef dbgScroll}
|
|
WriteLn('---- Offset=',C, ' TL=',TL, ' TLColOFf=', FGCache.TLColOff);
|
|
{$Endif}
|
|
If Not (goSmoothScroll in Options) then FGCache.TLColOff:=0;
|
|
|
|
If TL<>FTopLeft.X Then begin
|
|
Inc(FUpdateScrollBarsCount);
|
|
TryScrollTo(Tl, FTopLeft.Y);
|
|
Dec(FUpdateScrollBarsCount);
|
|
End Else
|
|
If goSmoothScroll in Options Then begin
|
|
CacheVisibleGrid;
|
|
Invalidate;
|
|
End;
|
|
|
|
End;
|
|
{$Endif}
|
|
end;
|
|
|
|
procedure TCustomGrid.WMVScroll(var Message: TLMVScroll);
|
|
Var
|
|
C: Integer;
|
|
TL: Integer;
|
|
begin
|
|
// Avoid invalidating right know, just let the scrollbar
|
|
// calculate its position
|
|
BeginUpdate;
|
|
Inherited;
|
|
Message.Result:=1;
|
|
EndUpdate(uoNone);
|
|
|
|
{$IfDef dbgScroll}
|
|
WriteLn('VSCROLL: Code=',Message.ScrollCode,' Position=', Message.Pos);
|
|
{$Endif}
|
|
|
|
|
|
{$IfDef Scr1}
|
|
TL:= Message.pos+FFixedRows;
|
|
If FEditor<>nil then getEditorValue;
|
|
Inc(FUpdateScrollBarsCount);
|
|
TryScrollTo(FtopLeft.x, TL);
|
|
Dec(FUpdateScrollBarsCount);
|
|
{$Else}
|
|
If FGCache.VScrDiv<=0 Then Exit;
|
|
If FEditor<>nil then getEditorValue;
|
|
If goThumbTracking in Options Then begin
|
|
C:=FFixedRows + Round( Message.Pos * FGCache.VScrDiv );
|
|
If (C<>FRow) Then begin
|
|
Inc(FUpdateScrollBarsCount);
|
|
MoveExtend(False, FCol, C);
|
|
Dec(FUpdateScrollBarsCount);
|
|
End;
|
|
End Else begin
|
|
C:=Message.Pos+FGCache.Fixedheight;
|
|
TL:=OffsetToColRow(False, False, C, FGCache.TLRowOff);
|
|
|
|
{$Ifdef dbgScroll}
|
|
WriteLn('---- Offset=',C, ' TL=',TL, ' TLRowOFf=', FGCache.TLRowOff);
|
|
{$Endif}
|
|
If Not (goSmoothScroll in Options) Then FGCache.TLRowOff:=0;
|
|
|
|
If TL<>FTopLeft.Y Then begin
|
|
Inc(FUpdateScrollBarsCount);
|
|
TryScrollTo(FTopLeft.X, Tl);
|
|
Dec(FUpdateScrollBarsCount);
|
|
End Else
|
|
If goSmoothScroll in Options Then begin
|
|
CacheVisibleGrid;
|
|
Invalidate;
|
|
End;
|
|
End;
|
|
{$Endif}
|
|
end;
|
|
|
|
procedure TCustomGrid.WMSize(var Msg: TWMSize);
|
|
begin
|
|
Inherited;
|
|
visualChange;
|
|
end;
|
|
|
|
{ Scroll grid to the given Topleft[aCol,aRow] as needed }
|
|
procedure TCustomGrid.TryScrollTo(aCol, aRow: Integer);
|
|
Var
|
|
TryTL: TPoint;
|
|
begin
|
|
TryTL:=ScrollGrid(False,aCol, aRow);
|
|
if Not PointIgual(TryTL, FTopLeft) Then begin
|
|
FTopLeft:=TryTL;
|
|
doTopleftChange(False);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetGridLineWidth(const AValue: Integer);
|
|
begin
|
|
// Todo
|
|
if FGridLineWidth=AValue then exit;
|
|
FGridLineWidth:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
{ Reposition the scrollbars according to the current TopLeft }
|
|
procedure TCustomGrid.UpdateScrollbarPos(Which: TControlScrollbar);
|
|
Var
|
|
I: Integer;
|
|
begin
|
|
// Adjust ScrollBar Positions
|
|
{$IfDef Scr1}
|
|
Write('UptateScrollbarPos: Scr1 - ');
|
|
If (FScrollBars in [ssAutoHorizontal, ssAutoBoth]) And
|
|
HorzScrolLBar.Visible Then begin
|
|
I:=fTopLeft.X-FFixedCols;
|
|
{$IfDef dbgScroll}
|
|
Write('HorzScrollBar Pos=', I);
|
|
{$Endif}
|
|
HorzScrolLBar.Position:=I;
|
|
End;
|
|
If (FScrolLBars in [ssAutoVertical, ssAutoBoth]) And
|
|
VertScrolLBar.Visible Then Begin
|
|
I:=fTopLeft.Y-FFixedRows;
|
|
{$IfDef dbgScroll}
|
|
Write(' VertScrollBar Pos=', I);
|
|
{$Endif}
|
|
VertScrolLBar.Position:=I;
|
|
End;
|
|
WriteLn(' Done');
|
|
{$Else Scr1}
|
|
// Special condition only When scrolling by draging
|
|
// the scrollbars see: WMHScroll and WVHScroll
|
|
If FUpdateScrollBarsCount=0 Then begin
|
|
|
|
if (Which=HorzScrollBar)or(Which=nil) Then
|
|
If (FScrollBars in [ssAutoHorizontal, ssAutoBoth]) And
|
|
HorzScrolLBar.Visible Then begin
|
|
With FGCache do
|
|
HorzScrollBar.Position:=
|
|
Integer(AccumWidth[FTopLeft.x])-TLColOff-FixedWidth;
|
|
End;
|
|
|
|
If (Which=VertScrollBar)Or(Which=nil) Then
|
|
If (FScrolLBars in [ssAutoVertical, ssAutoBoth]) And
|
|
VertScrolLBar.Visible Then begin
|
|
With FGCache do
|
|
VertScrollBar.Position:=
|
|
Integer(AccumHeight[FTopLeft.y])-TLRowOff-FixedHeight;
|
|
End;
|
|
End; {If FUpd...}
|
|
{$Endif}
|
|
end;
|
|
|
|
procedure TCustomGrid.CheckFixedCount(aCol,aRow,aFCol,aFRow: Integer);
|
|
begin
|
|
If (aFCol<>0)And (aFCol>=aCol) Then
|
|
Raise Exception.Create('FixedCols can''t be <= than ColCount');
|
|
If (aFRow<>0)And (aFRow>=aRow) Then
|
|
Raise Exception.Create('FixedRows can''t be <= than RowCount');
|
|
end;
|
|
|
|
{ Save to the cache the current visible grid (excluding fixed cells) }
|
|
procedure TCustomGrid.CacheVisibleGrid;
|
|
Var
|
|
R: TRect;
|
|
begin
|
|
With FGCache do begin
|
|
VisibleGrid:=GetVisibleGrid;
|
|
With VisibleGrid do
|
|
ValidGrid:=(Left>=0)And(Top>=0)And(Right>=Left)And(Bottom>=Top);
|
|
If Not ValidGrid Then MaxClientXY:=Point(0,0)
|
|
Else begin
|
|
R:=ColRowToClientCellrect(VisibleGrid.Right, VisibleGrid.Bottom);
|
|
MaxClientXY:=R.BottomRight;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
function TCustomGrid.GetSelection: TGridRect;
|
|
begin
|
|
Result:=FRange;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetDefaultDrawing(const AValue: Boolean);
|
|
begin
|
|
if FDefaultDrawing=AValue then exit;
|
|
FDefaultDrawing:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetFocusColor(const AValue: TColor);
|
|
begin
|
|
if FFocusColor=AValue then exit;
|
|
FFocusColor:=AValue;
|
|
InvalidateCell(FCol,FRow);
|
|
end;
|
|
|
|
procedure TCustomGrid.SetGridLineStyle(const AValue: TPenStyle);
|
|
begin
|
|
if FGridLineStyle=AValue then exit;
|
|
FGridLineStyle:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetSelectActive(const AValue: Boolean);
|
|
begin
|
|
if FSelectActive=AValue then exit;
|
|
FSelectActive:=AValue;
|
|
If FSelectActive Then FPivot:=Point(FCol,FRow);
|
|
end;
|
|
|
|
procedure TCustomGrid.SetSelection(const AValue: TGridRect);
|
|
begin
|
|
If goRangeSelect in Options Then begin
|
|
fRange:=NormalizarRect(aValue);
|
|
Invalidate;
|
|
End;
|
|
end;
|
|
|
|
function TCustomGrid.doColSizing(X, Y: Integer): Boolean;
|
|
Var
|
|
R: TRect;
|
|
Loc: Integer;
|
|
begin
|
|
Result:=False;
|
|
If gsColSizing = fGridState Then begin
|
|
If x>FSplitter.y Then
|
|
ColWidths[FSplitter.x]:=x-FSplitter.y
|
|
Else
|
|
if ColWidths[FSplitter.x]>0 Then ColWidths[FSplitter.X]:=0;
|
|
Result:=True;
|
|
End Else
|
|
If (fGridState=gsNormal)And(Y<FGCache.FixedHeight)And(X>FGCache.FixedWidth) Then
|
|
begin
|
|
FSplitter.X:= OffsetToColRow(True, True, X, Loc);
|
|
FSplitter.Y:=0;
|
|
If FSplitter.X>=0 Then begin
|
|
R:=ColRowToClientCellRect(FSplitter.x, FSplitter.y);
|
|
FSplitter.y:=X; // Resizing X reference
|
|
If (R.Right-X)<(X-R.Left) then Loc:=R.Right
|
|
Else begin
|
|
Loc:=R.Left;
|
|
Dec(FSplitter.x); // Resizing col is the previous
|
|
End;
|
|
IF (Abs(Loc-x)<=2)And(FSplitter.X>=FFixedCols) then Cursor:=crHSplit
|
|
Else Cursor:=crDefault;
|
|
Result:=True;
|
|
End;
|
|
End
|
|
Else
|
|
If (cursor=crHSplit) Then Cursor:=crDefault;
|
|
end;
|
|
|
|
function TCustomGrid.doRowSizing(X, Y: Integer): Boolean;
|
|
Var
|
|
R: TRect;
|
|
Loc: Integer;
|
|
begin
|
|
Result:=False;
|
|
If gsRowSizing = fGridState Then begin
|
|
If y>FSplitter.x Then
|
|
RowHeights[FSplitter.y]:=y-FSplitter.x
|
|
Else
|
|
if RowHeights[FSplitter.y]>0 Then RowHeights[FSplitter.Y]:=0;
|
|
Result:=True;
|
|
End Else
|
|
If (fGridState=gsNormal)And(X<FGCache.FixedWidth)And(Y>FGCache.FixedHeight) Then
|
|
begin
|
|
fSplitter.Y:=OffsetToColRow(False, True, Y, Loc);
|
|
If Fsplitter.Y>=0 Then begin
|
|
ColRowToOffset(False, True, FSplitter.Y, R.Top, R.Bottom);
|
|
FSplitter.X:=Y;
|
|
If (R.Bottom-Y)<(Y-R.Top) Then Loc:=R.Bottom
|
|
Else begin
|
|
Loc:=R.Top;
|
|
Dec(FSplitter.y);
|
|
End;
|
|
IF (Abs(Loc-y)<=2)And(FSplitter.Y>=FFixedRows) then Cursor:=crVSplit
|
|
Else Cursor:=crDefault;
|
|
Result:=True;
|
|
End;
|
|
{
|
|
FSplitter:=MouseToCell(Point(X,Y)); // Resizing Row
|
|
R:=ColRowToClientCellRect(FSplitter.x, FSplitter.y);
|
|
Fsplitter.x:=y; // Resizing y reference
|
|
If (R.Bottom-Y)<(Y-R.Top) Then Loc:=R.Bottom
|
|
Else Begin
|
|
Loc:=R.Top;
|
|
Dec(FSplitter.y); // Resizing row is the previous
|
|
End;
|
|
IF (Abs(Loc-y)<=2)And(FSplitter.Y>=FFixedRows) then Cursor:=crVSplit
|
|
Else Cursor:=crDefault;
|
|
Result:=True;
|
|
}
|
|
End
|
|
Else
|
|
If Cursor=crVSplit Then Cursor:=crDefault;
|
|
end;
|
|
|
|
procedure TCustomGrid.doColMoving(X, Y: Integer);
|
|
Var
|
|
P: TPoint;
|
|
R: TRect;
|
|
begin
|
|
P:=MouseToCell(Point(X,Y));
|
|
If (Abs(FSplitter.Y-X)>fDragDx)And(Cursor<>crMultiDrag) Then begin
|
|
Cursor:=crMultiDrag;
|
|
FMoveLast:=Point(-1,-1);
|
|
ResetOffset(True, False);
|
|
End;
|
|
if (Cursor=crMultiDrag)And
|
|
(P.x>=FFixedCols) And
|
|
((P.X<=FSplitter.X)or(P.X>FSplitter.X))And
|
|
(P.X<>FMoveLast.X) Then begin
|
|
R:=ColRowToClientCellRect(P.x, P.y);
|
|
If P.x<=FSplitter.X Then fMoveLast.Y:=R.left
|
|
Else FMoveLast.Y:=R.Right;
|
|
fMoveLast.X:=P.X;
|
|
Invalidate;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.doRowMoving(X, Y: Integer);
|
|
Var
|
|
P: TPoint;
|
|
R: TRect;
|
|
begin
|
|
P:=MouseToCell(Point(X,Y));
|
|
If (Cursor<>crMultiDrag)And(Abs(FSplitter.X-Y)>fDragDx) Then begin
|
|
Cursor:=crMultiDrag;
|
|
FMoveLast:=Point(-1,-1);
|
|
ResetOffset(False, True);
|
|
End;
|
|
if (Cursor=crMultiDrag)And
|
|
(P.y>=FFixedRows) And
|
|
((P.y<=FSplitter.Y)or(P.Y>FSplitter.Y))And
|
|
(P.y<>FMoveLast.Y) Then begin
|
|
R:=ColRowToClientCellRect(P.x, P.y);
|
|
If P.y<=FSplitter.y Then fMoveLast.X:=R.Top
|
|
Else FMoveLast.X:=R.Bottom;
|
|
fMoveLast.Y:=P.Y;
|
|
Invalidate;
|
|
End;
|
|
end;
|
|
|
|
|
|
Function TCustomGrid.OffsetToColRow(IsCol, Fisical: Boolean; Offset: Integer;
|
|
var Rest: Integer): Integer;
|
|
begin
|
|
Result:=0; //Result:=-1;
|
|
Rest:=0;
|
|
If Offset<0 Then Exit; // Out of Range;
|
|
With FGCache do
|
|
If IsCol Then begin
|
|
|
|
// Begin to count Cols from 0 but ...
|
|
If Fisical And (Offset>FixedWidth-1) Then begin
|
|
Result:=FTopLeft.X; // In scrolled view, then Begin from FtopLeft col
|
|
Offset:=Offset-FixedWidth+Integer(AccumWidth[Result])+TLColOff;
|
|
If Offset>GridWidth-1 Then Begin
|
|
Result:=ColCount-1;
|
|
Exit;
|
|
End;
|
|
End;
|
|
While Offset>(Integer(AccumWidth[Result])+GetColWidths(Result)-1) do Inc(Result);
|
|
Rest:=Offset;
|
|
If Result<>0 Then Rest:=Offset-Integer(AccumWidth[Result]);
|
|
|
|
End Else Begin
|
|
|
|
If Fisical And (Offset>FixedHeight-1) Then begin
|
|
Result:=FTopLeft.Y;
|
|
Offset:=Offset-FixedHeight+Integer(AccumHeight[Result])+TLRowOff;
|
|
If Offset>GridHeight-1 Then Begin
|
|
Result:=RowCount-1;
|
|
Exit; // Out of Range
|
|
End;
|
|
End;
|
|
While Offset>(Integer(AccumHeight[Result])+GetRowHeights(Result)-1) do Inc(Result);
|
|
Rest:=Offset;
|
|
If Result<>0 Then Rest:=Offset-Integer(AccumHeight[Result]);
|
|
|
|
End;
|
|
end;
|
|
|
|
function TCustomGrid.ColRowToOffset(IsCol,Fisical:Boolean; Index:Integer; Var Ini,Fin:Integer): Boolean;
|
|
Var
|
|
Dim: Integer;
|
|
begin
|
|
With FGCache do begin
|
|
If IsCol Then begin
|
|
Ini:=Integer(AccumWidth[Index]);
|
|
Dim:=GetColWidths(Index);
|
|
End Else begin
|
|
Ini:=Integer(AccumHeight[Index]);
|
|
Dim:= GetRowheights(Index);
|
|
End;
|
|
if Not Fisical Then begin
|
|
Fin:=Ini + Dim;
|
|
Exit;
|
|
End;
|
|
If IsCol Then Begin
|
|
If index>=FFixedCols Then
|
|
Ini:=Ini-Integer(AccumWidth[FTopLeft.X]) + FixedWidth - TLColOff;
|
|
End Else begin
|
|
if Index>=FFixedRows then
|
|
Ini:=Ini-Integer(AccumHeight[FTopLeft.Y]) + FixedHeight - TLRowOff;
|
|
End;
|
|
Fin:=Ini + Dim;
|
|
End;
|
|
end;
|
|
|
|
{
|
|
Function TCustomGrid.GetColRowOffset(IsCol, Fisical: Boolean; Offset: Integer;
|
|
var Rest: Integer): Integer;
|
|
Var
|
|
i,j,k: Integer;
|
|
L: TList;
|
|
begin
|
|
Result:=-1;
|
|
If Offset<0 Then Exit; // Out of Range;
|
|
j:=0; k:=0;
|
|
If IsCol Then begin
|
|
If Offset>FGCache.GridWidth Then Exit; // Out of Range;
|
|
If Fisical Then
|
|
If Offset>FGCache.FixedWidth Then begin
|
|
k:=FTopLeft.X;
|
|
Offset:=Offset - FGCache.FixedWidth;
|
|
End;
|
|
for i:=k to ColCount-1 do begin
|
|
if Offset<j Then Break;
|
|
j:=j+getColWidths(i);
|
|
Result:=i;
|
|
End;
|
|
End Else Begin
|
|
If Offset>FGCache.GridHeight Then Exit; // Out of Range
|
|
If Fisical Then
|
|
If Offset>FGCache.FixedHeight Then begin
|
|
k:=FTopLeft.Y;
|
|
Offset:=Offset - FGCache.FixedHeight;
|
|
End;
|
|
For i:=k to RowCount-1 do begin
|
|
If Offset<j Then Break;
|
|
j:=j+GetRowheights(i);
|
|
Result:=i;
|
|
End;
|
|
|
|
End;
|
|
Rest:=Offset;
|
|
end;
|
|
}
|
|
function TCustomGrid.MouseToGridZone(X, Y: Integer; CellCoords: Boolean): TGridZone;
|
|
begin
|
|
Result:=gzNormal;
|
|
If CellCoords Then Begin
|
|
If (X<fFixedCols) then
|
|
If Y<FFixedRows Then Result:= gzFixedCells
|
|
Else Result:= gzFixedRows
|
|
Else
|
|
If (Y<fFixedRows) Then
|
|
If X<FFixedCols Then Result:= gzFixedCells
|
|
Else Result:= gzFixedCols;
|
|
End Else begin
|
|
If X<=FGCache.FixedWidth Then
|
|
If Y<=FGcache.FixedHeight Then Result:=gzFixedCells
|
|
Else Result:=gzFixedRows
|
|
Else
|
|
If Y<=FGCache.FixedHeight Then
|
|
if X<=FGCache.FixedWidth Then Result:=gzFixedCells
|
|
Else Result:=gzFixedCols;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.ExchangeColRow(IsColumn: Boolean; Index, WithIndex: Integer
|
|
);
|
|
begin
|
|
If IsColumn Then FCols.Exchange(Index, WithIndex)
|
|
Else FRows.Exchange(Index, WithIndex);
|
|
ColRowExchanged(IsColumn, Index, WithIndex);
|
|
VisualChange;
|
|
end;
|
|
|
|
procedure TCustomGrid.MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer);
|
|
begin
|
|
If IsColumn then FCols.Move(FromIndex, ToIndex)
|
|
Else FRows.Move(FromIndex, ToIndex);
|
|
ColRowMoved(IsColumn, FromIndex, ToIndex);
|
|
VisualChange;
|
|
End;
|
|
|
|
procedure TCustomGrid.SortColRow(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
If IsColumn Then SortColRow(IsColumn, Index, FFixedRows, RowCount-1)
|
|
Else SortColRow(IsColumn, Index, FFixedCols, ColCount-1);
|
|
end;
|
|
|
|
procedure TCustomGrid.SortColRow(IsColumn: Boolean; Index, FromIndex,
|
|
ToIndex: Integer);
|
|
begin
|
|
If Assigned(OnCompareCells) Then begin
|
|
BeginUpdate;
|
|
Sort(IsColumn, Index, FromIndex, ToIndex);
|
|
EndUpdate(true);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.DeleteColRow(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
If IsColumn Then FCols.Delete(Index)
|
|
Else FRows.Delete(Index);
|
|
ColRowDeleted(IsColumn, Index);
|
|
VisualChange;
|
|
end;
|
|
|
|
procedure TCustomGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
Var
|
|
Gz: TGridZone;
|
|
R: TRect;
|
|
begin
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
If Not FGCache.ValidGrid Then Exit;
|
|
If Not (ssLeft in Shift) Then Exit;
|
|
|
|
Gz:=MouseToGridZone(X,Y, False);
|
|
Case Gz of
|
|
gzFixedCols:
|
|
begin
|
|
if (goColSizing in Options)And(Cursor=crHSplit) then Begin
|
|
R:=ColRowToClientCellRect(FSplitter.x, FTopLeft.y);
|
|
FSplitter.y:=R.Left;
|
|
fGridState:= gsColSizing;
|
|
End Else begin
|
|
// ColMoving or Clicking
|
|
fGridState:=gsColMoving;
|
|
FSplitter:=MouseToCell(Point(X,Y));
|
|
FMoveLast:=Point(-1,-1);
|
|
FSplitter.Y:=X;
|
|
End;
|
|
End;
|
|
gzFixedRows:
|
|
If (goRowSizing in Options)And(Cursor=crVSplit) Then begin
|
|
R:=ColRowToClientcellRect(FTopLeft.X, FSplitter.y);
|
|
FSplitter.x:=R.top;
|
|
fGridState:= gsRowSizing;
|
|
End Else begin
|
|
// RowMoving or Clicking
|
|
fGridState:=gsRowMoving;
|
|
fSplitter:=MouseToCell(Point(X,Y));
|
|
FMoveLast:=Point(-1,-1);
|
|
FSplitter.X:=Y;
|
|
End;
|
|
gzNormal:
|
|
Begin
|
|
if csDesigning in ComponentState Then Exit;
|
|
|
|
// is user clicking on a selection?
|
|
// is user dragging the selection?
|
|
// is user only selecting a new cell range?
|
|
fGridState:=gsSelecting;
|
|
FSplitter:=MouseToCell(Point(X,Y));
|
|
|
|
If Not (goEditing in Options) Then begin
|
|
If ssShift in Shift Then begin
|
|
SelectActive:=(goRangeSelect in Options);
|
|
End Else begin
|
|
If Not SelectACtive Then Begin
|
|
FPivot:=FSplitter;
|
|
FSelectActive:=true;
|
|
End;
|
|
End;
|
|
MoveExtend(False, fsplitter.X, fSplitter.y);
|
|
End;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
Var
|
|
p: TPoint;
|
|
begin
|
|
inherited MouseMove(Shift, X, Y);
|
|
If Not FGCache.ValidGrid Then Exit;
|
|
|
|
Case fGridState of
|
|
gsSelecting:
|
|
begin
|
|
P:=MouseToLogcell(Point(X,Y));
|
|
MoveExtend(False, P.x, P.y);
|
|
End;
|
|
gsColMoving: If goColMoving in Options Then doColMoving(X,Y);
|
|
gsRowMoving: If goRowMoving in Options Then doRowMoving(X,Y);
|
|
Else
|
|
begin
|
|
If goColSizing in Options Then doColSizing(X,Y);
|
|
If goRowSizing in Options Then doRowSizing(X,Y);
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
var
|
|
Cur: TPoint;
|
|
begin
|
|
inherited MouseUp(Button, Shift, X, Y);
|
|
If Not FGCache.ValidGrid Then Exit;
|
|
Cur:=MouseToCell(Point(x,y));
|
|
|
|
Case fGridState of
|
|
gsSelecting:
|
|
Begin
|
|
MoveExtend(False, Cur.x, Cur.y);
|
|
SelectActive:=False;
|
|
End;
|
|
gsColMoving:
|
|
begin
|
|
//WriteLn('Move Col From ',Fsplitter.x,' to ', FMoveLast.x);
|
|
If FMoveLast.X>=0 Then Begin
|
|
MoveColRow(True, Fsplitter.X, FMoveLast.X);
|
|
Cursor:=crDefault;
|
|
End Else
|
|
If Cur.X=FSplitter.X Then HeaderClick(True, FSplitter.X);
|
|
End;
|
|
gsRowMoving:
|
|
Begin
|
|
//WriteLn('Move Row From ',Fsplitter.Y,' to ', FMoveLast.Y);
|
|
If FMoveLast.Y>=0 Then begin
|
|
MoveColRow(False, Fsplitter.Y, FMoveLast.Y);
|
|
Cursor:=crDefault;
|
|
End Else
|
|
If Cur.Y=FSplitter.Y Then HeaderClick(False, FSplitter.Y);
|
|
End;
|
|
End;
|
|
fGridState:=gsNormal;
|
|
end;
|
|
|
|
procedure TCustomGrid.DblClick;
|
|
begin
|
|
If (goColSizing in Options) And (Cursor=crHSplit) Then begin
|
|
If (goDblClickAutoSize in Options) Then begin
|
|
AutoAdjustColumn( FSplitter.X );
|
|
End Else
|
|
WriteLn('Got Doubleclick on Col Resizing: AutoAdjust?');
|
|
End Else
|
|
If (goDblClickAutoSize in Options) And
|
|
(goRowSizing in Options) And
|
|
(Cursor=crVSplit) Then begin
|
|
WriteLn('Got DoubleClick on Row Resizing: AutoAdjust?');
|
|
End
|
|
Else
|
|
Inherited DblClick;
|
|
end;
|
|
|
|
procedure TCustomGrid.doExit;
|
|
begin
|
|
inherited doExit;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TCustomGrid.doEnter;
|
|
begin
|
|
inherited doEnter;
|
|
//If (goEditing in Options)And(goAlwaysShowEditor in Options) Then ShowEditor;
|
|
end;
|
|
|
|
procedure TCustomGrid.KeyDown(var Key: Word; Shift: TShiftState);
|
|
Procedure MoveSel(Rel: Boolean; aCol,aRow: Integer);
|
|
begin
|
|
// Always reset Offset in kerboard Events
|
|
FGCache.TLColOff:=0;
|
|
FGCache.TLRowOff:=0;
|
|
SelectActive:=(ssShift in Shift);
|
|
If MoveExtend(Rel, aCol, aRow) Then Key:=0;
|
|
End;
|
|
Var
|
|
R: TRect;
|
|
Relaxed: Boolean;
|
|
begin
|
|
inherited KeyDown(Key, Shift);
|
|
If Not FGCache.ValidGrid Then Exit;
|
|
|
|
Relaxed:=Not (goRowSelect in Options) or (goRelaxedRowSelect in Options);
|
|
|
|
Case Key of
|
|
VK_LEFT:
|
|
Begin
|
|
If Relaxed Then MoveSel(True,-1, 0)
|
|
Else MoveSel(true, 0,-1);
|
|
End;
|
|
VK_RIGHT:
|
|
begin
|
|
If Relaxed Then MoveSel(True, 1, 0)
|
|
Else MoveSel(True, 0, 1);
|
|
End;
|
|
VK_UP:
|
|
Begin
|
|
MoveSel(True, 0, -1);
|
|
End;
|
|
VK_DOWN:
|
|
begin
|
|
MoveSel(True, 0, 1);
|
|
End;
|
|
VK_PRIOR:
|
|
begin
|
|
R:=FGCache.Visiblegrid;
|
|
MoveSel(True, 0, R.Top-R.Bottom);
|
|
End;
|
|
VK_NEXT:
|
|
Begin
|
|
R:=FGCache.VisibleGrid;
|
|
MoveSel(True, 0, R.Bottom-R.Top);
|
|
End;
|
|
VK_HOME:
|
|
begin
|
|
If ssCtrl in Shift Then MoveSel(False, FCol, FFixedRows)
|
|
Else
|
|
if Relaxed Then MoveSel(False, FFixedCols, FRow)
|
|
Else MoveSel(False, FCol, FFixedRows);
|
|
End;
|
|
VK_END:
|
|
Begin
|
|
If ssCtrl in Shift Then MoveSel(False, FCol, RowCount-1)
|
|
Else
|
|
if Relaxed Then MoveSel(False, ColCount-1, FRow)
|
|
Else MoveSel(False, FCol, RowCount-1);
|
|
End;
|
|
VK_F2:
|
|
begin
|
|
ShowEditor;
|
|
Key:=0;
|
|
End;
|
|
{$IfDef Dbg}
|
|
Else WriteLn('KeyDown: ', Key);
|
|
{$Endif}
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.KeyUp(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
inherited KeyUp(Key, Shift);
|
|
end;
|
|
|
|
|
|
{ Returns a reactagle corresponding to a fisical cell[aCol,aRow] }
|
|
function TCustomGrid.ColRowToClientCellRect(aCol, aRow: Integer): TRect;
|
|
begin
|
|
ColRowToOffset(True, True, ACol, Result.Left, Result.Right);
|
|
ColRowToOffSet(False,True, ARow, Result.Top, Result.Bottom);
|
|
end;
|
|
|
|
{ Convert a fisical Mouse coordinate into fisical a cell coordinate }
|
|
function TCustomGrid.MouseToCell(Mouse: TPoint): TPoint;
|
|
|
|
Var
|
|
//i,j: Integer;
|
|
//P: TPoint;
|
|
d: Integer;
|
|
begin
|
|
Result.X:= OffsetToColRow(True, True, Mouse.x, d);
|
|
Result.Y:= OffsetToColRow(False,True, Mouse.y, d);
|
|
{ Exit;
|
|
P:=Point(0,0);
|
|
If Mouse.x>FGCache.FixedWidth Then begin
|
|
P.x:=fTopLeft.x;
|
|
Mouse.X:=Mouse.X-FGCache.FixedWidth;
|
|
End;
|
|
If Mouse.y>FGCache.FixedHeight Then begin
|
|
p.y:=fTopLeft.y;
|
|
Mouse.Y:=Mouse.Y-FGCache.Fixedheight;
|
|
End;
|
|
|
|
Result.x:=-1; Result.y:=-1;
|
|
j:=0;
|
|
for i:=P.x to ColCount-1 do begin
|
|
if Mouse.x<j Then Break;
|
|
j:=j+getColWidths(i);
|
|
Result.x:=i;
|
|
End;
|
|
j:=0;
|
|
For i:=P.y to RowCount-1 do begin
|
|
if Mouse.y<j then break;
|
|
j:=j+getRowheights(i);
|
|
Result.y:=i;
|
|
End;
|
|
}
|
|
end;
|
|
|
|
{ Convert a fisical Mouse coordinate into logical a cell coordinate }
|
|
function TCustomGrid.MouseToLogcell(Mouse: TPoint): TPoint;
|
|
Var
|
|
gz: TGridZone;
|
|
begin
|
|
Gz:=MouseToGridZone(Mouse.x, Mouse.y, False);
|
|
If gz=gzNormal Then Result:=MouseToCell(Mouse)
|
|
Else begin
|
|
Result:=MouseToCell(Mouse);
|
|
If (gz=gzFixedRows)or(gz=gzFixedCells) then begin
|
|
Result.x:= fTopLeft.x-1;
|
|
If Result.x<FFixedCols Then Result.x:=FFixedCols;
|
|
End;
|
|
If (gz=gzFixedCols)or(gz=gzFixedCells) Then begin
|
|
Result.y:=fTopleft.y-1;
|
|
If Result.y<fFixedRows Then Result.y:=FFixedRows;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
function TCustomGrid.ISCellVisible(aCol, aRow: Integer): Boolean;
|
|
begin
|
|
With FGCache.VisibleGrid do
|
|
Result:= (Left<=ACol)And(aCol<=Right)And(Top<=aRow)And(aRow<=Bottom);
|
|
end;
|
|
|
|
procedure TCustomGrid.InvalidateCol(ACol: Integer);
|
|
Var
|
|
R: TRect;
|
|
begin
|
|
{$ifdef dbg} WriteLn('InvalidateCol Col=',aCol); {$Endif}
|
|
R:=ColRowToClientCellRect(aCol, FTopLeft.y);
|
|
R.Bottom:=FGCache.MaxClientXY.Y;
|
|
InvalidateRect(Handle, @R, True);
|
|
End;
|
|
|
|
procedure TCustomGrid.InvalidateRow(ARow: Integer);
|
|
Var
|
|
R: TRect;
|
|
begin
|
|
{$ifdef dbg} WriteLn('InvalidateRow Row=',aRow); {$Endif}
|
|
R:=ColRowToClientCellRect(fTopLeft.x, aRow);
|
|
R.Right:=FGCache.MaxClientXY.X;
|
|
InvalidateRect(Handle, @R, True);
|
|
End;
|
|
|
|
|
|
Function TCustomGrid.MoveExtend(Relative: Boolean; DCol, DRow: Integer): Boolean;
|
|
Var
|
|
InvalidateAll: Boolean;
|
|
begin
|
|
Result:=False;
|
|
|
|
dCol:=FCol*(1-Byte(Not Relative))+DCol;
|
|
dRow:=FRow*(1-Byte(Not Relative))+DRow;
|
|
If dCol<FFixedCols Then dCol:=FFixedCols Else
|
|
If dCol>ColCount-1 Then dcol:=ColCount-1;
|
|
If dRow<FFixedRows Then dRow:=FFixedRows Else
|
|
If dRow>RowCount-1 Then dRow:=RowCount-1;
|
|
|
|
// Change on Focused cell?
|
|
If (Dcol=FCol)And(DRow=FRow) Then Exit;
|
|
|
|
Result:=True;
|
|
if Assigned(OnBeforeSelection) Then OnBeforeSelection(Self, DCol, DRow, Result);
|
|
If Not Result Then Exit;
|
|
|
|
// Going to change selection, get editor value before that
|
|
GetEditorValue;
|
|
|
|
// default range
|
|
If goRowSelect in Options Then FRange:=Rect(FFixedCols, DRow, Colcount-1, DRow)
|
|
Else FRange:=Rect(DCol,DRow,DCol,DRow);
|
|
|
|
InvalidateAll:=False;
|
|
If SelectActive Then
|
|
if goRangeSelect in Options Then begin
|
|
If goRowSelect in Options Then Begin
|
|
FRange.Top:=Min(fPivot.y, DRow);
|
|
FRange.Bottom:=Max(fPivot.y, DRow);
|
|
End Else begin
|
|
FRange:=NormalizarRect(Rect(Fpivot.x,FPivot.y, DCol, DRow));
|
|
End;
|
|
InvalidateAll:=True;
|
|
End;
|
|
|
|
If Not ScrollToCell(DCol, DRow) Then
|
|
If InvalidateAll Then Begin
|
|
//InvalidateSelection;
|
|
Invalidate
|
|
End Else begin
|
|
//InvalidateCell(FCol, FRow);
|
|
InvalidateCell(DCol, DRow);
|
|
End;
|
|
|
|
fCol:=DCol;
|
|
fRow:=DRow;
|
|
Editor:=nil;
|
|
|
|
MoveSelection;
|
|
|
|
if //Not SelectActive And
|
|
(goEditing in Options) And
|
|
(goAlwaysShowEditor in Options) And
|
|
Not(goRowSelect in Options) Then ShowEditor;
|
|
end;
|
|
|
|
procedure TCustomGrid.MoveSelection;
|
|
begin
|
|
if Assigned(onSelection) Then OnSelection(Self, FCol, FRow);
|
|
end;
|
|
|
|
procedure TCustomGrid.BeginUpdate;
|
|
begin
|
|
Inc(FUpdateCount);
|
|
end;
|
|
|
|
procedure TCustomGrid.EndUpdate(UO: TUpdateOption);
|
|
begin
|
|
Dec(FUpdateCount);
|
|
If FUpdateCount=0 Then
|
|
Case UO of
|
|
uoQuick: Invalidate;
|
|
uoFull: VisualChange;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.EndUpdate(FullUpdate: Boolean);
|
|
begin
|
|
EndUpdate(uoFull);
|
|
end;
|
|
|
|
function TCustomGrid.IsCellSelected(aCol, aRow: Integer): Boolean;
|
|
begin
|
|
Result:= (FRange.Left<=aCol) And
|
|
(aCol<=FRange.Right) And
|
|
(FRange.Top<=aRow) And
|
|
(aRow<=FRange.Bottom);
|
|
end;
|
|
|
|
procedure TCustomGrid.InvalidateCell(aCol, aRow: Integer);
|
|
Var
|
|
R: TRect;
|
|
begin
|
|
{$IfDef dbgPaint}
|
|
WriteLn('InvalidateCell Col=',aCol, ' Row=',aRow);
|
|
{$Endif}
|
|
R:=ColRowToClientCellRect(aCol, aRow);
|
|
InvalidateRect(Handle, @R, False);
|
|
//InvalidateRect(Handle, @R, True);
|
|
End;
|
|
|
|
procedure TCustomGrid.InvalidateGrid;
|
|
begin
|
|
If FUpdateCount=0 Then Invalidate;
|
|
end;
|
|
|
|
procedure TCustomGrid.Invalidate;
|
|
begin
|
|
If FUpdateCount=0 Then
|
|
inherited Invalidate;
|
|
end;
|
|
|
|
procedure TCustomGrid.GetEditorValue;
|
|
begin
|
|
If Not (csDesigning in ComponentState) Then begin
|
|
HideEditor;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.SetEditorValue;
|
|
begin
|
|
If Not (csDesigning in ComponentState) Then
|
|
PosEditor;
|
|
end;
|
|
|
|
procedure TCustomGrid.HideEditor;
|
|
begin
|
|
if (Editor<>nil) And Editor.HandleAllocated And Editor.Visible Then begin
|
|
If Not FEditorHiding Then begin
|
|
FEditorHiding:=True;
|
|
Editor.Visible:=False;
|
|
Editor.Parent:=nil;
|
|
LCLLinux.SetFocus(Self.Handle);
|
|
FEDitorHiding:=False;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.ShowEditor;
|
|
begin
|
|
If Not (csDesigning in ComponentState)And(goEditing in Options) Then
|
|
If (Editor<>nil) And Not Editor.Visible Then Begin
|
|
ResetOffset(True, True);
|
|
Editor.Parent:=Self;
|
|
SetEditorValue;
|
|
Editor.Visible:=True;
|
|
LCLLinux.SetFocus(Editor.Handle);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.PosEditor;
|
|
Var
|
|
R: TRect;
|
|
CurVisible: Boolean;
|
|
begin
|
|
If fEditor<>nil Then begin
|
|
R:=ColRowToClientCellRect(FCol,FRow);
|
|
FEditor.SetBounds(R.Left, R.Top, R.Right-R.Left, R.Bottom-R.Top);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.ExitEditor(Sender: TWinControl);
|
|
begin
|
|
//WriteLn('Editor is losing the focus..');
|
|
If Not FEditorHiding Then begin
|
|
// Editor losing focus for any reason
|
|
//WriteLn('Hey, What is happening here?');
|
|
FEditorHiding:=True;
|
|
GetEditorValue;
|
|
If Editor<>nil Then Begin
|
|
Editor.Visible:=False;
|
|
Editor.Parent:=nil;
|
|
End;
|
|
FEditorHiding:=False;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.EditorKeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
FEditorKey:=True; // Just a flag to see from where the event comes
|
|
Case Key of
|
|
VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN,
|
|
VK_PRIOR, VK_NEXT:
|
|
Begin
|
|
If Not(ssShift in Shift) Then KeyDown(Key, Shift);
|
|
End;
|
|
VK_RETURN, VK_TAB:
|
|
Begin
|
|
If (Key=VK_TAB) And Not (goTabs in Options) Then begin
|
|
// let the focus go
|
|
Exit;
|
|
End;
|
|
Key:=0;
|
|
Case FAutoAdvance of
|
|
aaRight: Key:=VK_RIGHT * Integer( FCol<ColCount-1 );
|
|
aaDown : Key:=VK_DOWN * Integer( FRow<RowCount-1 );
|
|
End;
|
|
If Key=0 Then begin
|
|
GetEditorValue;
|
|
ShowEditor;
|
|
// Select All !
|
|
End Else KeyDown(Key, Shift);
|
|
End;
|
|
End;
|
|
FEditorKey:=False;
|
|
end;
|
|
|
|
procedure TCustomGrid.CancelEditor;
|
|
begin
|
|
HideEditor;
|
|
SetFocus;
|
|
end;
|
|
|
|
procedure TCustomGrid.ColWidthsChanged;
|
|
begin
|
|
//
|
|
end;
|
|
procedure TCustomGrid.RowHeightsChanged;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TCustomGrid.SaveContent(cfg: TXMLConfig);
|
|
Var
|
|
i,j,k: Integer;
|
|
Path: String;
|
|
begin
|
|
cfg.SetValue('grid/version', GRIDFILEVERSION);
|
|
|
|
Cfg.SetValue('grid/saveoptions/create', soDesign in SaveOptions);
|
|
If soDesign in SaveOptions then begin
|
|
Cfg.SetValue('grid/design/columncount', ColCount);
|
|
Cfg.SetValue('grid/design/rowcount', RowCount);
|
|
Cfg.SetValue('grid/design/fixedcols', FixedCols);
|
|
Cfg.SetValue('grid/design/fixedrows', Fixedrows);
|
|
Cfg.SetValue('grid/design/defaultcolwidth', DefaultColWidth);
|
|
Cfg.SetValue('grid/design/defaultRowHeight',DefaultRowHeight);
|
|
|
|
j:=0;
|
|
For i:=0 to ColCount-1 do begin
|
|
k:=Integer(FCols[i]);
|
|
If (k>=0)And(k<>DefaultColWidth) Then Begin
|
|
inc(j);
|
|
cfg.SetValue('grid/design/columns/columncount',j);
|
|
cfg.SetValue('grid/design/columns/column'+IntToStr(j)+'/index', i);
|
|
cfg.SetValue('grid/design/columns/column'+IntToStr(j)+'/width', k);
|
|
End;
|
|
End;
|
|
j:=0;
|
|
For i:=0 to RowCount-1 do begin
|
|
k:=Integer(FRows[i]);
|
|
If (k>=0)And(k<>DefaultRowHeight) Then begin
|
|
inc(j);
|
|
cfg.SetValue('grid/design/rows/rowcount',j);
|
|
cfg.SetValue('grid/design/rows/row'+IntToStr(j)+'/index', i);
|
|
cfg.SetValue('grid/design/rows/row'+IntToStr(j)+'/height',k);
|
|
End;
|
|
End;
|
|
|
|
|
|
Path:='grid/design/options/';
|
|
Cfg.SetValue(Path+'goFixedVertLine/value', goFixedVertLine in options);
|
|
Cfg.SetValue(Path+'goFixedHorzLine/value', goFixedHorzLine in options);
|
|
Cfg.SetValue(Path+'goVertLine/value', goVertLine in options);
|
|
Cfg.SetValue(Path+'goHorzLine/value', goHorzLine in options);
|
|
Cfg.SetValue(Path+'goRangeSelect/value', goRangeSelect in options);
|
|
Cfg.SetValue(Path+'goDrawFocusSelected/value', goDrawFocusSelected in options);
|
|
Cfg.SetValue(Path+'goRowSizing/value', goRowSizing in options);
|
|
Cfg.SetValue(Path+'goColSizing/value', goColSizing in options);
|
|
Cfg.SetValue(Path+'goRowMoving/value', goRowMoving in options);
|
|
Cfg.SetValue(Path+'goColMoving/value', goColMoving in options);
|
|
Cfg.SetValue(Path+'goEditing/value', goEditing in options);
|
|
Cfg.SetValue(Path+'goTabs/value', goTabs in options);
|
|
Cfg.SetValue(Path+'goRowSelect/value', goRowSelect in options);
|
|
Cfg.SetValue(Path+'goAlwaysShowEditor/value', goAlwaysShowEditor in options);
|
|
Cfg.SetValue(Path+'goThumbTracking/value', goThumbTracking in options);
|
|
Cfg.SetValue(Path+'goColSpanning/value', goColSpanning in options);
|
|
cfg.SetValue(Path+'goRelaxedRowSelect/value', goRelaxedRowSelect in options);
|
|
cfg.SetValue(Path+'goDblClickAutoSize/value', goDblClickAutoSize in options);
|
|
Cfg.SetValue(Path+'goSmoothScroll/value', goSmoothScroll in Options);
|
|
End;
|
|
|
|
Cfg.SetValue('grid/saveoptions/position', soPosition in SaveOptions);
|
|
If soPosition in SaveOptions then begin
|
|
Cfg.SetValue('grid/position/topleftcol',ftopleft.x);
|
|
Cfg.SetValue('grid/position/topleftrow',ftopleft.y);
|
|
Cfg.SetValue('grid/position/col',fCol);
|
|
Cfg.SetValue('grid/position/row',fRow);
|
|
if goRangeSelect in Options Then begin
|
|
Cfg.SetValue('grid/position/selection/left',Selection.left);
|
|
Cfg.SetValue('grid/position/selection/top',Selection.top);
|
|
Cfg.SetValue('grid/position/selection/right',Selection.right);
|
|
Cfg.SetValue('grid/position/selection/bottom',Selection.bottom);
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.LoadContent(cfg: TXMLConfig);
|
|
Var
|
|
CreateSaved: Boolean;
|
|
Opt: TGridOptions;
|
|
i,j,k: Integer;
|
|
path: String;
|
|
|
|
Procedure GetValue(optStr:String; aOpt:TGridOption);
|
|
begin
|
|
If Cfg.GetValue(Path+OptStr+'/value', False) Then Opt:=Opt+[aOpt];
|
|
End;
|
|
|
|
begin
|
|
If soDesign in FSaveOptions Then begin
|
|
CreateSaved:=Cfg.GetValue('grid/saveoptions/create', false);
|
|
If CreateSaved Then begin
|
|
Clear;
|
|
FixedCols:=0;
|
|
FixedRows:=0;
|
|
ColCount:=Cfg.GetValue('grid/design/columncount', 5);
|
|
RowCount:=Cfg.GetValue('grid/design/rowcount', 5);
|
|
FixedCols:=Cfg.GetValue('grid/design/fixedcols', 1);
|
|
FixedRows:=Cfg.GetValue('grid/design/fixedrows', 1);
|
|
DefaultRowheight:=Cfg.GetValue('grid/design/defaultrowheight', 24);
|
|
DefaultColWidth:=Cfg.getValue('grid/design/defaultcolwidth', 64);
|
|
|
|
Path:='grid/design/columns/';
|
|
k:=cfg.getValue(Path+'columncount',0);
|
|
For i:=1 to k do begin
|
|
j:=cfg.getValue(Path+'column'+IntToStr(i)+'/index',-1);
|
|
If (j>=0)And(j<=ColCount-1) Then begin
|
|
ColWidths[j]:=cfg.getValue(Path+'column'+IntToStr(i)+'/width',-1);
|
|
End;
|
|
End;
|
|
Path:='grid/design/rows/';
|
|
k:=cfg.getValue(Path+'rowcount',0);
|
|
For i:=1 to k do begin
|
|
j:=cfg.getValue(Path+'row'+IntToStr(i)+'/index',-1);
|
|
If (j>=0)And(j<=ColCount-1) Then begin
|
|
RowHeights[j]:=cfg.getValue(Path+'row'+IntToStr(i)+'/height',-1);
|
|
End;
|
|
End;
|
|
|
|
Opt:=[];
|
|
Path:='grid/design/options/';
|
|
GetValue('goFixedVertLine', goFixedVertLine);
|
|
GetValue('goFixedHorzLine', goFixedHorzLine);
|
|
GetValue('goVertLine',goVertLine);
|
|
GetValue('goHorzLine',goHorzLine);
|
|
GetValue('goRangeSelect',goRangeSelect);
|
|
GetValue('goDrawFocusSelected',goDrawFocusSelected);
|
|
GetValue('goRowSizing',goRowSizing);
|
|
GetValue('goColSizing',goColSizing);
|
|
GetValue('goRowMoving',goRowMoving);
|
|
GetValue('goColMoving',goColMoving);
|
|
GetValue('goEditing',goEditing);
|
|
GetValue('goRowSelect',goRowSelect);
|
|
GetValue('goTabs',goTabs);
|
|
GetValue('goAlwaysShowEditor',goAlwaysShowEditor);
|
|
GetValue('goThumbTracking',goThumbTracking);
|
|
GetValue('goColSpanning', goColSpanning);
|
|
GetValue('goRelaxedRowSelect',goRelaxedRowSelect);
|
|
GetValue('goDblClickAutoSize',goDblClickAutoSize);
|
|
If GRIDFILEVERSION>=2 Then begin
|
|
GetValue('goSmoothScroll',goSmoothScroll);
|
|
End;
|
|
|
|
Options:=Opt;
|
|
End;
|
|
|
|
CreateSaved:=Cfg.GetValue('grid/saveoptions/position', false);
|
|
If CreateSaved Then begin
|
|
i:=Cfg.GetValue('grid/position/topleftcol',-1);
|
|
j:=Cfg.GetValue('grid/position/topleftrow',-1);
|
|
if MouseToGridZone(i,j,true)=gzNormal Then Begin
|
|
tryScrollto(i,j);
|
|
End;
|
|
i:=Cfg.GetValue('grid/position/col',-1);
|
|
j:=Cfg.GetValue('grid/position/row',-1);
|
|
If (i>=FFixedCols)And(i<=ColCount-1) And
|
|
(j>=FFixedRows)And(j<=RowCount-1) Then Begin
|
|
MoveExtend(false, i,j);
|
|
End;
|
|
if goRangeSelect in Options Then begin
|
|
FRange.left:=Cfg.getValue('grid/position/selection/left',FCol);
|
|
FRange.Top:=Cfg.getValue('grid/position/selection/top',FRow);
|
|
FRange.Right:=Cfg.getValue('grid/position/selection/right',FCol);
|
|
FRange.Bottom:=Cfg.getValue('grid/position/selection/bottom',FRow);
|
|
End;
|
|
End;
|
|
end;
|
|
end;
|
|
|
|
constructor TCustomGrid.Create(AOwner: TComponent);
|
|
begin
|
|
// Inherited create Calls SetBounds->WM_SIZE->VisualChange so
|
|
// fGrid needs to be created before that
|
|
FCols:=TList.Create;
|
|
FRows:=TList.Create;
|
|
FGCache.AccumWidth:=TList.Create;
|
|
FGCache.AccumHeight:=TList.Create;
|
|
inherited Create(AOwner);
|
|
AutoScroll:=False;
|
|
FOptions:=
|
|
[goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect,
|
|
goSmoothScroll ];
|
|
FScrollbars:=ssAutoBoth;
|
|
fGridState:=gsNormal;
|
|
fDefColWidth:=64;//40;
|
|
fDefRowHeight:=24;//18;
|
|
fGridLineColor:=clGray;
|
|
FGridLineStyle:=psSolid;
|
|
fFocusColor:=clRed;
|
|
|
|
FRange:=Rect(-1,-1,-1,-1);
|
|
FDragDx:=3;
|
|
|
|
SetBounds(0,0,200,100);
|
|
ColCount:=5;
|
|
RowCount:=5;
|
|
FixedCols:=1;
|
|
FixedRows:=1;
|
|
Editor:=nil;
|
|
end;
|
|
|
|
destructor TCustomGrid.Destroy;
|
|
begin
|
|
{$Ifdef dbg}WriteLn('TCustomGrid.Destroy');{$Endif}
|
|
FreeThenNil(FGCache.AccumWidth);
|
|
FreeThenNil(FGCache.AccumHeight);
|
|
FreeThenNil(FCols);
|
|
FreeThenNil(FRows);
|
|
inherited Destroy;
|
|
End;
|
|
|
|
procedure TCustomGrid.SaveToFile(FileName: String);
|
|
Var
|
|
Cfg: TXMLConfig;
|
|
begin
|
|
If FileExists(FileName) then DeleteFile(FileName);
|
|
|
|
Cfg:=TXMLConfig.Create(FileName);
|
|
Try
|
|
SaveContent(Cfg);
|
|
Finally
|
|
Cfg.Flush;
|
|
FreeThenNil(Cfg);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.LoadFromFile(FileName: String);
|
|
Var
|
|
Cfg: TXMLConfig;
|
|
Version: Integer;
|
|
begin
|
|
If Not FileExists(FileName) Then
|
|
Raise Exception.Create('Grid file doesn''t exists');
|
|
|
|
Cfg:=TXMLConfig.Create(FileName);
|
|
Try
|
|
Version:=cfg.GetValue('grid/version',-1);
|
|
if Version=-1 Then Raise Exception.Create('Not a valid grid file');
|
|
BeginUpdate;
|
|
LoadContent(Cfg);
|
|
EndUpdate(True);
|
|
Finally
|
|
FreeThenNil(Cfg);
|
|
End;
|
|
end;
|
|
|
|
procedure TCustomGrid.Clear;
|
|
Var
|
|
OldR,OldC: Integer;
|
|
begin
|
|
OldR:=RowCount;
|
|
OldC:=ColCount;
|
|
FFixedCols:=0;
|
|
FFixedRows:=0;
|
|
FRows.Count:=0;
|
|
FCols.Count:=0;
|
|
FTopLeft:=Point(-1,-1);
|
|
VisualChange;
|
|
SizeChanged(OldR,OldC);
|
|
end;
|
|
|
|
procedure TCustomGrid.AutoAdjustColumns;
|
|
Var
|
|
i: Integer;
|
|
begin
|
|
For i:=0 to ColCount do
|
|
AutoAdjustColumn(i);
|
|
end;
|
|
|
|
{ TVirtualGrid }
|
|
|
|
function TVirtualGrid.GetCells(Col, Row: Integer): PCellProps;
|
|
begin
|
|
// todo: Check range
|
|
Result:=nil;
|
|
try
|
|
Result:=FCells[Col,Row];
|
|
Except
|
|
WriteLn('GetCell: Index Out of range Cell[Col=',Col,' Row=',Row,']');
|
|
End;
|
|
end;
|
|
|
|
Function Tvirtualgrid.Getrows(Row: Integer): Pcellprops;
|
|
Begin
|
|
Result:= FRows[Row, 0];
|
|
End;
|
|
|
|
Function Tvirtualgrid.Getcols(Col: Integer): Pcellprops;
|
|
Begin
|
|
result:=FCols[Col, 0];
|
|
End;
|
|
|
|
procedure TVirtualGrid.SetCells(Col, Row: Integer; const AValue: PCellProps);
|
|
Var
|
|
Cell: PCellProps;
|
|
begin
|
|
// todo: Check range
|
|
Cell:=FCells[Col,Row];
|
|
If Cell<>nil Then DisposeCell(Cell);
|
|
Cell:=AValue;
|
|
FCells[Col,Row]:=Cell;
|
|
end;
|
|
|
|
Procedure Tvirtualgrid.Setrows(Row: Integer; Const Avalue: Pcellprops);
|
|
Var
|
|
Cell: PCellProps;
|
|
begin
|
|
// todo: Check range
|
|
Cell:=FRows[Row,0];
|
|
If Cell<>nil Then DisposeCell(Cell);
|
|
FCells[Row,0]:=AValue;
|
|
end;
|
|
|
|
Procedure Tvirtualgrid.Setcolcount(Const Avalue: Integer);
|
|
Begin
|
|
If FColCount=Avalue then Exit;
|
|
{$Ifdef dbgMem}
|
|
WriteLn('TVirtualGrid.SetColCount Value=',AValue);
|
|
{$Endif}
|
|
FColCount:=AValue;
|
|
{$Ifdef dbgMem}
|
|
Write('TVirtualGrid.SetColCount->FCOLS: ');
|
|
{$Endif}
|
|
FCols.SetLength(FColCount, 1);
|
|
{$Ifdef dbgMem}
|
|
Write('TVirtualGrid.SetColCount->FCELLS(',FColCount,',',FRowCount,'): ');
|
|
{$Endif}
|
|
FCells.SetLength(FColCount, FRowCount);
|
|
End;
|
|
|
|
|
|
Procedure Tvirtualgrid.Setrowcount(Const Avalue: Integer);
|
|
Begin
|
|
If FRowCount=AValue Then Exit;
|
|
{$Ifdef dbgMem}
|
|
WriteLn('TVirtualGrid.SetRowCount Value=',AValue);
|
|
{$Endif}
|
|
FRowCount:=AValue;
|
|
{$Ifdef dbgMem}
|
|
Write('TVirtualGrid.SetRowCount->FROWS: ');
|
|
{$Endif}
|
|
FRows.SetLength(FRowCount,1);
|
|
{$Ifdef dbgMem}
|
|
Write('TVirtualGrid.SetRowCount->FCELLS(',FColCount,',',FRowCount,'): ');
|
|
{$Endif}
|
|
FCells.SetLength(FColCount, FRowCount);
|
|
End;
|
|
|
|
Procedure Tvirtualgrid.Setcols(Col: Integer; Const Avalue: Pcellprops);
|
|
Var
|
|
Cell: PCellProps;
|
|
begin
|
|
// todo: Check range
|
|
Cell:=FCols[Col,0];
|
|
If Cell<>nil Then DisposeCell(Cell);
|
|
FCols[Col,0]:=AValue;
|
|
End;
|
|
|
|
Procedure Tvirtualgrid.Clear;
|
|
Begin
|
|
{$Ifdef dbgMem}Write('FROWS: ');{$Endif}FRows.Clear;
|
|
{$Ifdef dbgMem}Write('FCOLS: ');{$Endif}FCols.Clear;
|
|
{$Ifdef dbgMem}Write('FCELLS: ');{$Endif}FCells.Clear;
|
|
FColCount:=0;
|
|
FRowCount:=0;
|
|
End;
|
|
|
|
Procedure Tvirtualgrid.Disposecell(Var P: Pcellprops);
|
|
Begin
|
|
If P<>nil then begin
|
|
If P^.Text<>nil Then begin
|
|
StrDispose(P^.Text);
|
|
End;
|
|
If P^.Attr<>nil Then Dispose(P^.Attr);
|
|
Dispose(P);
|
|
P:=nil;
|
|
End;
|
|
End;
|
|
|
|
function TVirtualGrid.GetDefaultCell: PcellProps;
|
|
begin
|
|
New(Result);
|
|
Result^.Text:=nil;
|
|
Result^.Attr:=nil;
|
|
end;
|
|
|
|
Procedure Tvirtualgrid.Dodestroyitem (Sender: Tobject; Col,Row: Integer;
|
|
Var Item: Pointer);
|
|
Begin
|
|
{$IFNDef LogNil} If Item<>nil then {$Endif}
|
|
{$Ifdef dbgMem}
|
|
WriteLn('TVirtualGrid.doDestroyItem Col=',Col,' Row= ',
|
|
Row,' Item=',Integer(Item));
|
|
{$endif}
|
|
If Item<>nil Then begin
|
|
DisposeCell(pCellProps(Item));
|
|
Item:=nil;
|
|
End;
|
|
End;
|
|
|
|
Procedure Tvirtualgrid.Donewitem(Sender: Tobject; Col,Row:Integer;
|
|
Var Item: Pointer);
|
|
Begin
|
|
{$Ifdef dbgMem}
|
|
WriteLn('TVirtualGrid.doNewItem Col=',Col,' Row= ',
|
|
Row,' Item=',Integer(Item));
|
|
{$endif}
|
|
If Sender=FCols Then begin
|
|
// Procesar Nueva Columna
|
|
Item:=GetDefaultCell;
|
|
End Else
|
|
if Sender=FRows Then begin
|
|
// Procesar Nuevo Renglon
|
|
Item:=GetDefaultCell;
|
|
End Else begin
|
|
// Procesar Nueva Celda
|
|
Item:=nil;
|
|
End;
|
|
End;
|
|
|
|
constructor TVirtualGrid.Create;
|
|
begin
|
|
Inherited Create;
|
|
{$Ifdef dbg}WriteLn('TVirtualGrid.Create');{$Endif}
|
|
FCells:=TArray.Create;
|
|
FCells.OnDestroyItem:=@doDestroyItem;
|
|
FCells.OnNewItem:=@doNewItem;
|
|
FCols:= TArray.Create;
|
|
FCols.OnDestroyItem:=@doDestroyItem;
|
|
FCols.OnNewItem:=@doNewItem;
|
|
FRows:=TArray.Create;
|
|
FRows.OnDestroyItem:=@doDestroyItem;
|
|
FRows.OnNewItem:=@doNewItem;
|
|
RowCount:=4;
|
|
ColCount:=4;
|
|
end;
|
|
|
|
destructor TVirtualGrid.Destroy;
|
|
begin
|
|
{$Ifdef dbg}WriteLn('TVirtualGrid.Destroy');{$Endif}
|
|
Clear;
|
|
FreeThenNil(FRows);
|
|
FreeThenNil(FCols);
|
|
FreeThenNil(FCells);
|
|
inherited Destroy;
|
|
end;
|
|
procedure TVirtualGrid.DeleteColRow(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
FCells.DeleteColRow(IsColumn, Index);
|
|
If IsColumn Then begin
|
|
FCols.DeleteColRow(True, Index);
|
|
Dec(FColCount);
|
|
End Else begin
|
|
FRows.DeleteColRow(True, Index);
|
|
Dec(fRowCount);
|
|
End;
|
|
end;
|
|
|
|
procedure TVirtualGrid.MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer
|
|
);
|
|
begin
|
|
FCells.MoveColRow(IsColumn, FromIndex, ToIndex);
|
|
If IsColumn then FCols.MoveColRow(True, FromIndex, ToIndex)
|
|
Else FRows.MoveColRow(True, FromIndex, ToIndex);
|
|
end;
|
|
|
|
procedure TVirtualGrid.ExchangeColRow(IsColumn: Boolean; Index,
|
|
WithIndex: Integer);
|
|
begin
|
|
FCells.ExchangeColRow(IsColumn, Index, WithIndex);
|
|
If IsColumn Then FCols.ExchangeColRow(true, Index, WithIndex)
|
|
Else FRows.ExchangeColRow(True, Index, WithIndex);
|
|
end;
|
|
|
|
{ TStringCellEditor }
|
|
|
|
procedure TStringCellEditor.doExit;
|
|
begin
|
|
inherited doExit;
|
|
FGrid.ExitEditor(Self);
|
|
end;
|
|
|
|
procedure TStringCellEditor.KeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
{$IfDef dbg}
|
|
WriteLn('INI: Key=',Key,' SelStart=',SelStart,' SelLenght=',SelLength);
|
|
{$Endif}
|
|
If FGrid<>nil then Fgrid.EditorKeyDown(Key, Shift);
|
|
{$IfDef dbg}
|
|
WriteLn('FIN: Key=',Key,' SelStart=',SelStart,' SelLenght=',SelLength);
|
|
{$Endif}
|
|
inherited KeyDown(Key, Shift);
|
|
end;
|
|
|
|
procedure TStringCellEditor.msg_SetValue(var Msg: TLMessage);
|
|
begin
|
|
With PGridMessage(Msg.LParam)^ do begin
|
|
Text:= Value;
|
|
End;
|
|
end;
|
|
|
|
procedure TStringCellEditor.msg_GetValue(var Msg: TLMessage);
|
|
begin
|
|
With PGridMessage(Msg.LParam)^ do begin
|
|
Value:=Text;
|
|
End;
|
|
end;
|
|
|
|
procedure TStringCellEditor.msg_SetGrid(var Msg: TLMessage);
|
|
begin
|
|
FGrid:=TCustomGrid(Msg.WParam);
|
|
end;
|
|
|
|
{ TDrawGrid }
|
|
|
|
function TDrawGrid.GetCellAttr(ACol, ARow: Integer): TCellAttr;
|
|
Var
|
|
c: PCellProps;
|
|
begin
|
|
C:=FGrid.Celda[ACol,ARow];
|
|
If (C<>nil)And(C^.Attr<>nil) then Result:=C^.Attr^
|
|
Else Result:=FDefCellAttr;
|
|
end;
|
|
|
|
function TDrawGrid.GetCellAlign(ACol, ARow: Integer): Integer;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetCellAttr(Acol,ARow);
|
|
AttrToCellAlign(Attr, Result);
|
|
end;
|
|
|
|
function TDrawGrid.GetCellColor(ACol, ARow: Integer): TColor;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetCellAttr(ACol,ARow);
|
|
Result:=Attr.Color;
|
|
end;
|
|
|
|
function TDrawGrid.GetCellFontCOlor(ACol, ARow: Integer): TColor;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetCellAttr(ACol,ARow);
|
|
Result:=Attr.FontColor;
|
|
end;
|
|
|
|
function TDrawGrid.GetColAlign(aCol: Integer): Integer;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(aCol);
|
|
AttrToCellAlign(Attr, Result);
|
|
end;
|
|
|
|
function TDrawGrid.GetColAttr(aCol: Integer): TCellAttr;
|
|
Var
|
|
c: PCellProps;
|
|
begin
|
|
C:=FGrid.Cols[ACol];
|
|
If (C<>nil)And(C^.Attr<>nil) then Result:=C^.Attr^
|
|
Else Result:=FDefCellAttr;
|
|
end;
|
|
|
|
function TDrawGrid.GetColColor(aCol: Integer): TColor;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ACol);
|
|
Result:=Attr.Color;
|
|
end;
|
|
|
|
function TDrawGrid.GetColFontColor(aCol: Integer): TColor;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ACol);
|
|
Result:=Attr.FontColor;
|
|
end;
|
|
|
|
function TDrawGrid.GetFixedColor: TColor;
|
|
begin
|
|
Result:=fDefFixedCellAttr.Color;
|
|
end;
|
|
|
|
function TDrawGrid.GetRowAlign(aRow: Integer): Integer;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetRowAttr(aRow);
|
|
AttrToCellAlign(Attr, Result);
|
|
end;
|
|
|
|
function TDrawGrid.GetRowAttr(aRow: Integer): TCellAttr;
|
|
Var
|
|
c: PCellProps;
|
|
begin
|
|
C:=FGrid.Rows[ARow];
|
|
If (C<>nil)And(C^.Attr<>nil) then Result:=C^.Attr^
|
|
Else Result:=FDefCellAttr;
|
|
end;
|
|
|
|
function TDrawGrid.GetRowColor(aRow: Integer): TColor;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ARow);
|
|
Result:=Attr.Color;
|
|
end;
|
|
|
|
function TDrawGrid.GetRowFontColor(aRow: Integer): TColor;
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ARow);
|
|
Result:=Attr.FontColor;
|
|
end;
|
|
|
|
procedure TDrawGrid.SetCellAlign(ACol, ARow: Integer; const AValue: Integer);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetCellAttr(ACol, Arow);
|
|
CellAlignToAttr(aValue, Attr);
|
|
SetCellAttr(ACol,ARow,Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetCellAttr(ACol, ARow: Integer; const AValue: TCellAttr);
|
|
Var
|
|
c: PCellProps;
|
|
IsNew: Boolean;
|
|
begin
|
|
C:=FGrid.Celda[ACol,ARow];
|
|
IsNew:=C=nil;
|
|
If IsNew Then C:=FGrid.GetDefaultCell;
|
|
if C^.Attr=nil Then New(C^.Attr);
|
|
C^.Attr^:=Avalue;
|
|
If IsNew then FGrid.Celda[aCol,ARow]:=C; // Celda takes care
|
|
end;
|
|
|
|
procedure TDrawGrid.SetCellColor(ACol, ARow: Integer; const AValue: TColor);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetCellAttr(ACol, Arow);
|
|
attr.Color:=AValue;
|
|
SetCellAttr(ACol,ARow,Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetCellFontCOlor(ACol, ARow: Integer; const AValue: TColor);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetCellAttr(ACol, Arow);
|
|
Attr.FontColor:=Avalue;
|
|
SetCellAttr(ACol,ARow,Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetColAlign(aCol: Integer; const AValue: Integer);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ACol);
|
|
CellAlignToAttr(aValue, Attr);
|
|
SetColAttr(aCol, Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetColAttr(aCol: Integer; const AValue: TCellAttr);
|
|
Var
|
|
c: PCellProps;
|
|
IsNew: Boolean;
|
|
begin
|
|
C:=FGrid.Cols[ACol];
|
|
IsNew:=C=nil;
|
|
If IsNew Then C:=FGrid.GetDefaultCell;
|
|
if C^.Attr=nil Then New(C^.Attr);
|
|
C^.Attr^:=Avalue;
|
|
If IsNew then FGrid.Cols[aCol]:=C; // Celda takes care
|
|
end;
|
|
|
|
procedure TDrawGrid.SetColColor(aCol: Integer; const AValue: TColor);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ACol);
|
|
Attr.Color:=AValue;
|
|
SetColAttr(aCol, Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetColFontColor(aCol: Integer; const AValue: TColor);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetColAttr(ACol);
|
|
Attr.FontColor:=AValue;
|
|
SetColAttr(aCol, Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetDefaultCellAttr(const AValue: TCellAttr);
|
|
begin
|
|
If CellAttrIgual(FDefCellAttr, AValue) Then Exit;
|
|
FDefCellAttr:=AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TDrawGrid.SetFixedColor(const AValue: TColor);
|
|
begin
|
|
if fDefFixedCellAttr.Color=AValue then exit;
|
|
fDefFixedCellAttr.Color:=aValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TDrawGrid.SetRowAlign(aRow: Integer; const AValue: Integer);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetRowAttr(ARow);
|
|
CellAlignToAttr(Avalue, Attr);
|
|
SetRowAttr(aRow, Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetRowAttr(aRow: Integer; const AValue: TCellAttr);
|
|
Var
|
|
c: PCellProps;
|
|
IsNew: Boolean;
|
|
begin
|
|
C:=FGrid.Rows[aRow];
|
|
IsNew:=C=nil;
|
|
If IsNew Then C:=FGrid.GetDefaultCell;
|
|
if C^.Attr=nil Then New(C^.Attr);
|
|
C^.Attr^:=Avalue;
|
|
If IsNew then FGrid.Rows[aRow]:=C; // Celda takes care
|
|
end;
|
|
|
|
procedure TDrawGrid.SetRowColor(aRow: Integer; const AValue: TColor);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetRowAttr(ARow);
|
|
Attr.Color:=AValue;
|
|
SetRowAttr(aRow, Attr);
|
|
end;
|
|
|
|
procedure TDrawGrid.SetRowFontColor(aRow: Integer; const AValue: TColor);
|
|
Var
|
|
Attr: TCellAttr;
|
|
begin
|
|
Attr:=GetRowAttr(ARow);
|
|
Attr.FontColor:=AValue;
|
|
SetRowAttr(aRow, Attr);
|
|
end;
|
|
|
|
|
|
procedure TDrawGrid.CalcCellExtent(acol, aRow: Integer; var aRect: TRect);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TDrawGrid.DrawCell(aCol,aRow: Integer; aRect: TRect;
|
|
aState:TGridDrawState);
|
|
Begin
|
|
If Assigned(OnDrawCell) Then OnDrawCell(Self,aCol,aRow,aRect,aState)
|
|
Else DefaultDrawCell(aCol,aRow,aRect,aState);
|
|
Inherited DrawCellGrid(aRect,aCol,aRow,aState); // Draw the grid
|
|
End;
|
|
|
|
procedure TDrawGrid.DrawFocusRect(aCol, aRow: Integer; ARect: TRect;
|
|
aState: TGridDrawstate);
|
|
begin
|
|
// Draw focused cell if we have the focus
|
|
If Self.Focused Then begin
|
|
If (gdFocused in aState)Then begin
|
|
Canvas.Pen.Color:=FFocusColor;
|
|
Canvas.Pen.Style:=psDot;
|
|
If goRowSelect in Options Then begin
|
|
Canvas.MoveTo(FGCache.FixedWidth+1, aRect.Top+1);
|
|
Canvas.LineTo(FGCache.MaxClientXY.x-1, aRect.Top+1);
|
|
Canvas.LineTo(FGCache.MaxClientXY.x-1, aRect.Bottom-1);
|
|
Canvas.LineTo(FGCache.FixedWidth+1, aRect.Bottom-1);
|
|
Canvas.LineTo(FGCache.FixedWidth+1, aRect.Top+1);
|
|
End Else begin
|
|
Canvas.MoveTo(aRect.Left+1, aRect.Top+1);
|
|
Canvas.LineTo(ARect.Right-1, ARect.Top+1);
|
|
Canvas.LineTo(aRect.Right-1, aRect.bottom-1);
|
|
Canvas.LineTo(aRect.Left+1, aRect.Bottom-1);
|
|
Canvas.Lineto(aRect.left+1, aRect.top+1);
|
|
End;
|
|
Canvas.Pen.Style:=psSolid;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TDrawGrid.ColRowExchanged(IsColumn:Boolean; Index, WithIndex: Integer);
|
|
begin
|
|
Fgrid.ExchangeColRow(IsColumn, Index, WithIndex);
|
|
if Assigned(OnColRowExchanged) Then
|
|
OnColRowExchanged(Self, IsColumn, Index, WithIndex);
|
|
end;
|
|
|
|
procedure TDrawGrid.ColRowDeleted(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
FGrid.DeleteColRow(IsColumn, Index);
|
|
If Assigned(OnColRowDeleted) Then
|
|
OnColRowDeleted(Self, IsColumn, Index, Index);
|
|
end;
|
|
|
|
procedure TDrawGrid.ColRowMoved(IsColumn: Boolean; FromIndex, ToIndex: Integer);
|
|
begin
|
|
FGrid.MoveColRow(IsColumn, FromIndex, ToIndex);
|
|
If Assigned(OnColRowMoved) Then
|
|
OnColRowMoved(Self, IsColumn, FromIndex, toIndex);
|
|
end;
|
|
|
|
procedure TDrawGrid.HeaderClick(IsColumn: Boolean; Index: Integer);
|
|
begin
|
|
inherited HeaderClick(IsColumn, Index);
|
|
If Assigned(OnHeaderClick) Then OnHeaderClick(Self, IsColumn, Index);
|
|
end;
|
|
|
|
procedure TDrawGrid.SizeChanged(OldColCount, OldRowCount: Integer);
|
|
begin
|
|
If OldColCount<>ColCount Then fGrid.ColCount:=ColCOunt;
|
|
If OldRowCount<>RowCount Then fGrid.RowCount:=RowCount;
|
|
end;
|
|
|
|
procedure TDrawGrid.SaveContent(cfg: TXMLConfig);
|
|
Var
|
|
i,j,k: Integer;
|
|
c: PCellProps;
|
|
path: String;
|
|
|
|
procedure SaveAttr;
|
|
begin
|
|
With c^.Attr^ do begin
|
|
Cfg.SetValue(Path+'/color', ColorToString(Color));
|
|
Cfg.SetValue(Path+'/fontcolor',ColorToString(FontColor));
|
|
Cfg.SetValue(Path+'/textstyle/alignment/value', Ord(TextStyle.Alignment));
|
|
cfg.SetValue(Path+'/textstyle/layout/value',Ord(TextStyle.Layout));
|
|
cfg.SetValue(Path+'/textstyle/singleLine/value',TextStyle.SingleLine);
|
|
cfg.SetValue(Path+'/textstyle/clipping/value',TextStyle.Clipping);
|
|
cfg.SetValue(Path+'/textstyle/wordbreak/value',TextStyle.WordBreak);
|
|
cfg.SetValue(Path+'/textstyle/opaque/value',TextStyle.Opaque);
|
|
cfg.SetValue(Path+'/textstyle/systemfont/value',TextStyle.SystemFont);
|
|
End;
|
|
End;
|
|
begin
|
|
Inherited SaveContent(cfg);
|
|
Cfg.SetValue('grid/saveoptions/attributes', soAttributes in SaveOptions);
|
|
if Not (soAttributes in SaveOptions) then Exit;
|
|
|
|
// Save Columns
|
|
j:=0;
|
|
For i:=0 to ColCount-1 do begin
|
|
c:=fGrid.Cols[i];
|
|
If (c<>nil)And(c^.Attr<>nil) Then begin
|
|
Inc(j);
|
|
Cfg.SetValue('grid/attributes/columns/columncount', j);
|
|
path:='grid/attributes/columns/column'+IntToStr(j);
|
|
Cfg.SetValue(Path+'/index', i);
|
|
SaveAttr;
|
|
End;
|
|
End;
|
|
// Save Rows
|
|
j:=0;
|
|
For i:=0 to RowCount-1 do begin
|
|
c:=fGrid.Rows[i];
|
|
If (c<>nil)And(c^.Attr<>nil) Then begin
|
|
Inc(j);
|
|
Path:='grid/attributes/rows/row'+IntToStr(j);
|
|
Cfg.SetValue(Path+'/index', i);
|
|
SaveAttr;
|
|
End;
|
|
End;
|
|
// Save attributtes of Cells
|
|
k:=0;
|
|
For i:=0 to ColCount-1 do
|
|
For j:=0 to RowCount-1 do begin
|
|
C:=fGrid.Celda[i,j];
|
|
If (c<>nil)And(c^.Attr<>nil) Then begin
|
|
Inc(k);
|
|
Cfg.SetValue('grid/attributes/cells/cellcount',k);
|
|
Path:='grid/attributes/cells/cell'+IntToStr(k);
|
|
cfg.SetValue(Path+'/column',i);
|
|
cfg.SetValue(Path+'/row',j);
|
|
SaveAttr;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TDrawGrid.LoadContent(Cfg: TXMLConfig);
|
|
Var
|
|
i,j,k: Integer;
|
|
B: Boolean;
|
|
path: String;
|
|
begin
|
|
|
|
Inherited LoadContent(Cfg);
|
|
|
|
If Not (soAttributes in SaveOptions) Then Exit;
|
|
B:=Cfg.GetValue('grid/saveoptions/attributes',false);
|
|
If Not B Then Exit;
|
|
|
|
// Load Columns
|
|
Path:='grid/attributes/columns/';
|
|
k:=cfg.getValue(Path+'columncount',0);
|
|
For i:=1 to k do begin
|
|
j:=cfg.getValue(Path+'column'+IntToStr(i)+'/index', -1);
|
|
if (j>=0)And(j<=Colcount-1) Then begin
|
|
ColAttr[j]:=LoadCellAttrFromXMLPath(cfg, Path+'column'+IntToStr(i));
|
|
End;
|
|
End;
|
|
// Load Rows
|
|
Path:='grid/attributes/rows/';
|
|
k:=cfg.getValue(Path+'rowcount',0);
|
|
For i:=1 to k do begin
|
|
j:=cfg.getValue(Path+'row'+IntToStr(i)+'/index', -1);
|
|
if (j>=0)and(j<=RowCount-1) Then begin
|
|
RowAttr[j]:=LoadCellAttrFromXMLPath(cfg, Path+'row'+IntToStr(i));
|
|
End;
|
|
End;
|
|
// Load Cells
|
|
Path:='grid/attributes/cells/';
|
|
k:=cfg.getValue(Path+'cellcount',0);
|
|
While k>0 do begin
|
|
i:=cfg.getValue(Path+'cell'+inttoStr(k)+'/column', -1);
|
|
j:=cfg.getValue(Path+'cell'+inttostr(k)+'/row', -1);
|
|
if (j>=0)And(j<=rowcount-1)and(i>=0)and(i<=Colcount-1) Then begin
|
|
CellAttr[i,j]:=LoadCellAttrFromXMLPath(cfg, Path+'cell'+IntToStr(k));
|
|
End;
|
|
dec(k);
|
|
End;
|
|
end;
|
|
|
|
constructor TDrawGrid.Create(AOwner: TComponent);
|
|
begin
|
|
fGrid:=TVirtualGrid.Create;
|
|
FDefCellAttr:=GetDefaultCellAttr;
|
|
FDefSelCellAttr:=FDefCellAttr;
|
|
With FDefSelCellAttr do begin
|
|
Color:=clBlack;
|
|
FontColor:=clWhite;
|
|
End;
|
|
fdefFixedCellAttr:=FDefCelLAttr;
|
|
fdefFixedCellAttr.Color:=clBtnFace;
|
|
inherited Create(AOwner);
|
|
end;
|
|
|
|
destructor TDrawGrid.Destroy;
|
|
begin
|
|
{$Ifdef dbg}WriteLn('TDrawGrid.Destroy');{$Endif}
|
|
FreeThenNil(FGrid);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TDrawGrid.DefaultDrawCell(aCol, aRow: Integer; Var aRect: TRect;
|
|
aState: TGridDrawState);
|
|
Var
|
|
c: PcellProps;
|
|
begin
|
|
// Set draw Cell Attributes
|
|
if DefaultDrawing then Begin
|
|
fCellAttr.Color:=Self.Color;
|
|
FCellAttr.FontColor:=Self.Font.Color;
|
|
FCellAttr.TextStyle.Clipping:=False;
|
|
End Else begin
|
|
// Column -> Row -> Cell Specific Attributtes
|
|
fCellAttr:=fDefCellAttr;
|
|
If gdSelected in aState then FCellAttr:=FDefSelCellAttr
|
|
Else begin
|
|
If gdFixed in aState Then begin
|
|
FCellAttr:=FDefFixedCellAttr;
|
|
Case MouseToGridZone(aCol, aRow, true) of
|
|
gzFixedRows: C:=FGrid.Cols[aCol];
|
|
gzFixedCols: C:=FGrid.Rows[aRow];
|
|
Else c:=nil;
|
|
End;
|
|
If (c<>nil)and(C^.Attr<>nil) Then FCellAttr:=C^.Attr^;
|
|
End
|
|
Else begin
|
|
C:=FGrid.Cols[aCol]; If (c<>nil)and(C^.Attr<>nil) Then FCellAttr:=C^.Attr^;
|
|
C:=FGrid.Rows[aRow]; If (c<>nil)And(C^.Attr<>nil) Then FCellAttr:=C^.Attr^;
|
|
End;
|
|
C:= FGrid.Celda[aCol,aRow];If (C<>nil)And(C^.Attr<>nil) Then FCellAttr:=C^.Attr^;
|
|
End;
|
|
if Assigned(fonCellAttr) Then fonCellAttr(Self, aCol,aRow, aState, FCellAttr);
|
|
If goColSpanning in Options Then CalcCellExtent(acol, arow, aRect);
|
|
End;
|
|
Canvas.Brush.Color:=fCellAttr.Color;
|
|
Canvas.Font.Color:=fCellAttr.FontColor;
|
|
Canvas.FillRect(aRect);
|
|
end;
|
|
|
|
{ TStringGrid }
|
|
|
|
Function TStringGrid.Getcells(aCol, aRow: Integer): String;
|
|
Var
|
|
C: PCellProps;
|
|
Begin
|
|
Result:='';
|
|
C:=FGrid.Celda[aCol,aRow];
|
|
If C<>nil Then Result:=C^ .Text;
|
|
End;
|
|
|
|
function TStringGrid.GetCols(Index: Integer): TStrings;
|
|
Var
|
|
i,j: Integer;
|
|
begin
|
|
Result:=nil;
|
|
If (ColCount>0)And(index>=0)and(Index<ColCount) Then begin
|
|
Result:=TStringList.Create;
|
|
For i:=0 to RowCount-1 do Begin
|
|
j:=Result.Add( Cells[Index, i] );
|
|
Result.Objects[j]:=Objects[Index, i];
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
function TStringGrid.GetObjects(ACol, ARow: Integer): TObject;
|
|
Var
|
|
C: PCellProps;
|
|
begin
|
|
Result:=nil;
|
|
C:=Fgrid.Celda[aCol,aRow];
|
|
If C<>nil Then Result:=C^.Data;
|
|
end;
|
|
|
|
function TStringGrid.GetRows(Index: Integer): TStrings;
|
|
Var
|
|
i,j: Integer;
|
|
begin
|
|
Result:=nil;
|
|
If (RowCount>0)And(index>=0)and(Index<RowCount) Then begin
|
|
Result:=TStringList.Create;
|
|
For i:=0 to ColCount-1 do Begin
|
|
j:=Result.Add( Cells[i, Index] );
|
|
Result.Objects[j]:=Objects[i, Index];
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
Procedure TStringGrid.Setcells(aCol, aRow: Integer; Const Avalue: String);
|
|
Var
|
|
C: PCellProps;
|
|
Begin
|
|
C:= FGrid.Celda[aCol,aRow];
|
|
If C<>nil Then begin
|
|
If C^.Text<>nil Then StrDispose(C^.Text);
|
|
C^.Text:=StrNew(pchar(aValue));
|
|
InvalidateCell(aCol, aRow);
|
|
End Else Begin
|
|
If AValue<>'' Then Begin
|
|
New(C);
|
|
C^.Text:=StrNew(pchar(Avalue));
|
|
C^.Attr:=nil;
|
|
FGrid.Celda[aCol,aRow]:=C;
|
|
InvalidateCell(aCol, aRow);
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
procedure TStringGrid.SetCols(Index: Integer; const AValue: TStrings);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TStringGrid.SetObjects(ACol, ARow: Integer; AValue: TObject);
|
|
Var
|
|
c: PCellProps;
|
|
begin
|
|
C:=FGrid.Celda[aCol,aRow];
|
|
If c<>nil Then C^.Data:=AValue
|
|
Else begin
|
|
c:=fGrid.GetDefaultCell;
|
|
c^.Data:=Avalue;
|
|
FGrid.Celda[aCol,aRow]:=c;
|
|
End;
|
|
end;
|
|
|
|
procedure TStringGrid.SetRows(Index: Integer; const AValue: TStrings);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TStringGrid.AutoAdjustColumn(aCol: Integer);
|
|
Var
|
|
i,W: Integer;
|
|
Ts: TSize;
|
|
begin
|
|
if (aCol<0)or(aCol>ColCount-1) Then Exit;
|
|
W:=0;
|
|
For i:=0 to RowCount-1 do begin
|
|
Ts:=Canvas.TextExtent(Cells[aCol, i]);
|
|
If Ts.Cx>W Then W:=Ts.Cx;
|
|
End;
|
|
If W=0 Then W:=DefaultColWidth
|
|
Else W:=W + 8;
|
|
ColWidths[aCol]:=W;
|
|
end;
|
|
|
|
procedure TStringGrid.CalcCellExtent(acol, aRow: Integer; var aRect: TRect);
|
|
Var
|
|
S: String;
|
|
Ts: Tsize;
|
|
nc: PcellProps;
|
|
i: integer;
|
|
begin
|
|
inherited CalcCellExtent(acol,arow, aRect);
|
|
S:=Cells[aCol,aRow];
|
|
If Not FCellAttr.TextStyle.Clipping Then begin
|
|
// Calcular el numero de celdas necesarias para contener todo
|
|
// El Texto
|
|
Ts:=Canvas.TextExtent(S);
|
|
i:=aCol;
|
|
While (Ts.Cx>(aRect.Right-aRect.Left))and(i<ColCount) do begin
|
|
inc(i);
|
|
Nc:=FGrid.Celda[i, aRow];
|
|
if (nc<>nil)And(Nc^.Text<>'')Then Break;
|
|
aRect.Right:=aRect.Right + getColWidths(i);
|
|
End;
|
|
fcellAttr.TextStyle.Clipping:=i<>aCol;
|
|
End;
|
|
end;
|
|
|
|
procedure TStringGrid.DrawCell(aCol, aRow: Integer; aRect: TRect;
|
|
aState: TGridDrawState);
|
|
Var
|
|
S: String;
|
|
begin
|
|
inherited DrawCell(aCol, aRow, aRect, aState);
|
|
S:=Cells[aCol,aRow];
|
|
If S<>'' Then begin
|
|
Canvas.TextRect(aRect, 3, 0, S, FCellAttr.TextStyle);
|
|
End;
|
|
end;
|
|
|
|
procedure TStringGrid.GetEditorValue;
|
|
Var
|
|
msg: TGridMessage;
|
|
begin
|
|
If (FEditor<>nil) And FEditor.Visible Then Begin
|
|
Msg.grid:=Self;
|
|
Msg.Col:=FCol;
|
|
msg.Row:=FRow;
|
|
msg.Value:='';
|
|
FEditor.Perform(GM_GETVALUE, Integer(Self), Integer(@Msg));
|
|
Cells[FCol,FRow]:=msg.Value;
|
|
End;
|
|
inherited GetEditorValue;
|
|
end;
|
|
|
|
procedure TStringGrid.SetEditorValue;
|
|
Var
|
|
msg: TGridMessage;
|
|
begin
|
|
if FEditor<>nil Then begin
|
|
Msg.Grid:=Self;
|
|
Msg.Col:=FCol;
|
|
Msg.Row:=FRow;
|
|
Msg.Value:=Cells[FCol,FRow];
|
|
FEditor.Perform(GM_SETVALUE, Integer(Self), Integer(@msg));
|
|
End;
|
|
inherited SetEditorValue;
|
|
end;
|
|
|
|
procedure TStringGrid.SaveContent(cfg: TXMLConfig);
|
|
Var
|
|
i,j,k: Integer;
|
|
c: PCellProps;
|
|
begin
|
|
inherited SaveContent(cfg);
|
|
cfg.SetValue('grid/saveoptions/content', soContent in SaveOptions);
|
|
If soContent in SaveOptions Then begin
|
|
// Save Cell Contents
|
|
k:=0;
|
|
For i:=0 to ColCount-1 do
|
|
For j:=0 to RowCount-1 do begin
|
|
C:=fGrid.Celda[i,j];
|
|
If (c<>nil) And (C^.Text<>'') Then begin
|
|
Inc(k);
|
|
Cfg.SetValue('grid/content/cells/cellcount',k);
|
|
cfg.SetValue('grid/content/cells/cell'+IntToStr(k)+'/column',i);
|
|
cfg.SetValue('grid/content/cells/cell'+IntToStr(k)+'/row',j);
|
|
cfg.SetValue('grid/content/cells/cell'+IntToStr(k)+'/text', c^.Text);
|
|
End;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TStringGrid.LoadContent(Cfg: TXMLConfig);
|
|
Var
|
|
ContentSaved: Boolean;
|
|
i,j,k: Integer;
|
|
begin
|
|
inherited LoadContent(Cfg);
|
|
If soContent in FSaveOptions Then begin
|
|
ContentSaved:=Cfg.GetValue('grid/saveoptions/content', false);
|
|
If ContentSaved Then begin
|
|
k:=cfg.getValue('grid/content/cells/cellcount', 0);
|
|
While k>0 do begin
|
|
i:=cfg.GetValue('grid/content/cells/cell'+IntToStr(k)+'/column', -1);
|
|
j:=cfg.GetValue('grid/content/cells/cell'+IntTostr(k)+'/row',-1);
|
|
if (j>=0)And(j<=rowcount-1)and(i>=0)and(i<=Colcount-1) Then
|
|
Cells[i,j]:=cfg.GetValue('grid/content/cells/cell'+IntToStr(k)+'/text','');
|
|
Dec(k);
|
|
End;
|
|
End;
|
|
End;
|
|
end;
|
|
|
|
procedure TStringGrid.DrawInteriorCells;
|
|
Var
|
|
i,j: Integer;
|
|
gds: TGridDrawState;
|
|
c: PCellProps;
|
|
begin
|
|
With FGCache.VisibleGrid do
|
|
if goColSpanning in Options Then begin
|
|
//
|
|
// Ordered draw should be done in order to this work
|
|
//
|
|
Gds:=[];
|
|
// Draw Empty (nil) cells First
|
|
For i:=Left to Right do
|
|
For j:=Top to Bottom do begin
|
|
if IsCellSelected(i,j) Then Continue;
|
|
C:=Fgrid.Celda[i,j];
|
|
If (c=nil) Then DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
End;
|
|
// Draw Cells Empty Cells (Text='') With Attribute
|
|
For i:=Left to Right do
|
|
For j:=Top to Bottom do begin
|
|
if IsCellSelected(i,j) Then Continue;
|
|
If (i=FCol)or(j=FRow) Then Continue;
|
|
C:=Fgrid.Celda[i,j];
|
|
If (c<>nil)And(C^.Text='') Then
|
|
DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
End;
|
|
// Draw Cells Not Empty (Text<>'')
|
|
For i:=Left to Right do
|
|
For j:=Top to Bottom do begin
|
|
if IsCellSelected(i,j) Then Continue;
|
|
C:=Fgrid.Celda[i,j];
|
|
If (C<>nil)And(C^.Text<>'') Then
|
|
DrawCell(i,j, ColRowToClientCellRect(i,j), gds);
|
|
End;
|
|
|
|
gds:=[gdSelected];
|
|
For i:=Left To Right do
|
|
For j:=Top to Bottom do
|
|
If IsCellSelected(i,j) Then begin
|
|
DrawCell(i,j, colRowToClientCellRect(i,j), gds);
|
|
End;
|
|
|
|
End else inherited DrawInteriorCells;
|
|
end;
|
|
|
|
procedure TStringGrid.MoveSelection;
|
|
begin
|
|
If goEditing in Options Then Editor:=fDefEditor;
|
|
inherited MoveSelection;
|
|
end;
|
|
|
|
constructor TStringGrid.Create(AOWner: TComponent);
|
|
begin
|
|
inherited Create(AOWner);
|
|
if Not (csDesigning in componentState) Then begin
|
|
FDefEditor:=TStringCellEditor.Create(nil);
|
|
FDefEditor.Name:='Default_StringCellEditor';
|
|
FDefEditor.Visible:=False;
|
|
FDefEditor.Align:=alNone;
|
|
End Else Begin
|
|
FDefEditor:=nil;
|
|
End;
|
|
end;
|
|
|
|
destructor TStringGrid.Destroy;
|
|
begin
|
|
{$Ifdef dbg}WriteLn('TStringGrid.Destroy');{$Endif}
|
|
if FdefEditor<>nil Then begin
|
|
FDefEDitor.Parent:=nil;
|
|
FreeThenNil(FDefEditor);
|
|
End;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
|
|
LazarusResources.Add('tdrawgrid','XPM',[
|
|
'/* XPM */'#10'static char *tdrawgrid[]={'#10'"23 23 8 1",'#10'"# c #000000",'
|
|
+#10'"f c #0000c0",'#10'"b c #808080",'#10'". c #a0a0a0",'#10'"c c #ff0000",'
|
|
+#10'"d c #ff00ff",'#10'"a c #ffffc0",'#10'"e c #ffffff",'#10'"....#.....#...'
|
|
+'..#.....#",'#10'"....#.....#.....#.....#",'#10'"....#.....#.....#.....#",'
|
|
+#10'"....#.....#.....#.....#",'#10'"#######################",'#10'"....#aaaa'
|
|
+'abaaaaabaaaaaa",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"....#aaacccccccabaaaaa'
|
|
+'a",'#10'"....#aaacccccccabaadaaa",'#10'"#####bbbcccccccbbbdddbb",'#10'"....'
|
|
+'#eeecccccccebedddee",'#10'"....#eeecccccccebddddde",'#10'"....#eeecccccffff'
|
|
+'ddddde",'#10'"....#eeeccccffffffddddd",'#10'"#####bbbbbbbffffffddddd",'#10
|
|
+'"....#aaaaabaffffffaaaaa",'#10'"....#aaaaabaffffffaaaaa",'#10'"....#aaaaaba'
|
|
+'affffaaaaaa",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"#####bbbbbbbbbbbbbbbbbb",'
|
|
+#10'"....#eeeeebeeeeebeeeeee",'#10'"....#eeeeebeeeeebeeeeee",'#10'"....#eeee'
|
|
+'ebeeeeebeeeeee"};'#10
|
|
]);
|
|
LazarusResources.Add('tstringgrid','XPM',[
|
|
'/* XPM */'#10'static char *tstringgrid[]={'#10'"23 23 5 1",'#10'"# c #000000'
|
|
+'",'#10'"b c #808080",'#10'". c #a0a0a0",'#10'"a c #ffffc0",'#10'"c c #fffff'
|
|
+'f",'#10'"....#.....#.....#.....#",'#10'"....#.....#.....#.....#",'#10'"....'
|
|
+'#.....#.....#.....#",'#10'"....#.....#.....#.....#",'#10'"#################'
|
|
+'######",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"....#aaaaabaaaaabaaaaaa",'#10
|
|
+'"....#aaaaabaaaaabaaaaaa",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"#####bbbbbbb'
|
|
+'bbbbbbbbbbb",'#10'"....#cccccbcccccbcccccc",'#10'"....#cccccbcccccbcccccc",'
|
|
+#10'"....#cccccbcccccbcccccc",'#10'"....#cccccbcccccbcccccc",'#10'"#####bbbb'
|
|
+'bbbbbbbbbbbbbb",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"....#aaaaabaaaaabaaaaa'
|
|
+'a",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"....#aaaaabaaaaabaaaaaa",'#10'"####'
|
|
+'#bbbbbbbbbbbbbbbbbb",'#10'"....#cccccbcccccbcccccc",'#10'"....#cccccbcccccb'
|
|
+'cccccc",'#10'"....#cccccbcccccbcccccc"};'#10
|
|
]);
|
|
|
|
end.
|