lazarus/lcl/grids.pas
2004-08-01 14:21:47 +00:00

4990 lines
143 KiB
ObjectPascal

{ $Id$}
{
/***************************************************************************
Grids.pas
---------
An interface to DB aware Controls
Initial Revision : Sun Sep 14 2003
***************************************************************************/
*****************************************************************************
* *
* This file is part of the Lazarus Component Library (LCL) *
* *
* See the file COPYING.LCL, included in this distribution, *
* for details about the copyright. *
* *
* This program 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. *
* *
*****************************************************************************
}
{
TCustomGrid, TDrawGrid and TStringGrid for Lazarus
Copyright (C) 2002 Jesus Reyes Aguilar.
email: jesusrmx@yahoo.com.mx
Cur version: 0.8.5
The log was moved to end of file, search for: The_Log
}
{$Define UseClipRect}
unit Grids;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LCLStrConsts, LCLProc, LCLType, LCLIntf, Controls,
GraphType, Graphics, Forms, VCLGlobals, DynamicArray, LMessages,
XMLCfg, StdCtrls, LResources, MaskEdit;
const
//GRIDFILEVERSION = 1; // Original
//GRIDFILEVERSION = 2; // Introduced goSmoothScroll
GRIDFILEVERSION = 3; // Introduced Col/Row FixedAttr and NormalAttr
const
GM_SETVALUE = LM_USER + 100;
GM_GETVALUE = LM_USER + 101;
GM_SETGRID = LM_USER + 102;
GM_SETPOS = LM_USER + 103;
GM_SELECTALL = LM_USER + 104;
GM_SETMASK = LM_USER + 105;
const
CA_LEFT = $1;
CA_CENTER = $2;
CA_RIGHT = $4;
CL_TOP = $8;
CL_CENTER = $10;
CL_BOTTOM = $20;
const
EO_AUTOSIZE = $1;
EO_HOOKKEYS = $2;
EO_HOOKEXIT = $4;
EO_SELECTALL = $8;
EO_WANTCHAR = $10;
type
EGridException = class(Exception);
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)
);
TGridOptions = set of TGridOption;
TGridSaveOptions = (
soDesign, // Save grid structure (col/row count and Options)
soAttributes, // Save grid attributes (Font,Brush,TextStyle)
soContent, // Save Grid Content (Text in stringgrid)
soPosition // Save Grid cursor and selection position
);
TSaveOptions = Set of TGridSaveOptions;
TGridDrawState = set of (gdSelected, gdFocused, gdFixed);
TGridState =
(gsNormal, gsSelecting, gsRowSizing, gsColSizing,gsRowMoving,gsColMoving);
TGridZone = (gzNormal, gzFixedCols, gzFixedRows, gzFixedCells);
TUpdateOption = (uoNone, uoQuick, uoFull);
TAutoAdvance = (aaDown,aaRight,aaLeft);
TGridStatus = (stNormal, stEditorHiding, stEditorShowing, stFocusing);
TItemType = (itNormal,itCell,itColumn,itRow,itFixed,itFixedColumn,itFixedRow,itSelected);
const
soAll: TSaveOptions = [soDesign, soAttributes, soContent, soPosition];
type
TCustomGrid = class;
PCellProps= ^TCellProps;
TCellProps=record
Attr: pointer;
Data: TObject;
Text: pchar;
end;
PColRowProps= ^TColRowProps;
TColRowProps=record
Size: Integer;
FixedAttr: pointer;
NormalAttr: pointer;
end;
PGridMessage=^TGridMessage;
TGridMessage=record
MsgID: Cardinal;
Grid: TCustomGrid;
Col,Row: Integer;
Value: string;
CellRect: TRect;
Options: Integer;
end;
type
{ Default cell editor for TStringGrid }
TStringCellEditor=class(TCustomMaskEdit)
private
FGrid: TCustomGrid;
protected
//procedure WndProc(var TheMessage : TLMessage); override;
procedure Change; override;
procedure KeyDown(var Key : Word; Shift : TShiftState); override;
procedure msg_SetMask(var Msg: TGridMessage); message GM_SETMASK;
procedure msg_SetValue(var Msg: TGridMessage); message GM_SETVALUE;
procedure msg_GetValue(var Msg: TGridMessage); message GM_GETVALUE;
procedure msg_SetGrid(var Msg: TGridMessage); message GM_SETGRID;
procedure msg_SelectAll(var Msg: TGridMessage); message GM_SELECTALL;
end;
TOnDrawCell =
procedure(Sender: TObject; Col, Row: Integer; aRect: TRect;
aState:TGridDrawState) of object;
TOnSelectCellEvent =
procedure(Sender: TObject; Col, Row: Integer;
var CanSelect: Boolean) of object;
TOnSelectEvent =
procedure(Sender: TObject; Col,Row: Integer) 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;
TSelectEditorEvent =
procedure(Sender: TObject; Col,Row: Integer;
var Editor: TWinControl) of object;
TOnPrepareCanvasEvent =
procedure(sender: TObject; Col,Row: Integer;
aState:TGridDrawState) of object;
TVirtualGrid=class
private
FColCount: Integer;
FRowCount: Integer;
FCells, FCols, FRows: TArray;
function GetCells(Col, Row: Integer): PCellProps;
function Getrows(Row: Integer): PColRowprops;
function Getcols(Col: Integer): PColRowprops;
procedure SetCells(Col, Row: Integer; const AValue: PCellProps);
procedure Setrows(Row: Integer; const Avalue: PColRowprops);
procedure Setcolcount(const Avalue: Integer);
procedure Setrowcount(const Avalue: Integer);
procedure Setcols(Col: Integer; const Avalue: PColRowprops);
protected
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);
procedure DisposeCell(var P: PCellProps); virtual;
procedure DisposeColRow(var p: PColRowProps); virtual;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function GetDefaultCell: PcellProps;
function GetDefaultColRow: PColRowProps;
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]: PColRowProps read GetCols write SetCols;
property Rows[Row: Integer]: PColRowProps read GetRows write SetRows;
end;
type
TGridCoord = TPoint;
TGridRect = 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 (pixel) coordinates
ValidGrid: Boolean; // true if there is something to show
AccumWidth: TList; // Accumulated width per column
AccumHeight: TList; // Accumulated Height per row
HScrDiv,VScrDiv: Double; // Transform const for ThumbTracking
TLColOff,TLRowOff: Integer; // TopLeft Offset in pixels
MaxTopLeft: TPoint; // Max Top left ( cell coorditates)
end;
type
TCustomGrid=class(TCustomControl)
private
FAutoAdvance: TAutoAdvance;
FDefaultDrawing: Boolean;
FEditor: TWinControl;
FEditorHiding: Boolean;
FEditorMode: Boolean;
FEditorShowing: Boolean;
FEditorKey: Boolean;
FEditorOptions: Integer;
FFlat: Boolean;
FOnCompareCells: TOnCompareCells;
FGridLineStyle: TPenStyle;
FGridLineWidth: Integer;
FDefColWidth, FDefRowHeight: Integer;
FCol,FRow, FFixedCols, FFixedRows: Integer;
FOnPrepareCanvas: TOnPrepareCanvasEvent;
FOnSelectEditor: TSelectEditorEvent;
FGridLineColor: TColor;
FFixedcolor, FFocusColor, FSelectedColor: TColor;
FFocusRectVisible: boolean;
FCols,FRows: TList;
FsaveOptions: TSaveOptions;
FScrollBars: TScrollStyle;
FSelectActive: Boolean;
FTopLeft: TPoint;
FSplitter, FPivot: TPoint;
FRange: TRect;
FDragDx: Integer;
FMoveLast: TPoint;
FUpdateCount: Integer;
FUpdateScrollBarsCount: Integer;
FGCache: TGridDataCache;
FOptions: TGridOptions;
FOnDrawCell: TOnDrawcell;
FOnBeforeSelection: TOnSelectEvent;
FOnSelection: TOnSelectEvent;
FOnTopLeftChanged: TNotifyEvent;
FGSMHBar, FGSMVBar: Integer; // Scrollbar's metrics
FVSbVisible, FHSbVisible: boolean;
FDefaultTextStyle: TTextStyle;
procedure AdjustCount(IsColumn:Boolean; OldValue, NewValue:Integer);
procedure CacheVisibleGrid;
procedure CheckFixedCount(aCol,aRow,aFCol,aFRow: Integer);
procedure CheckCount(aNewColCount, aNewRowCount: Integer);
function CheckTopLeft(aCol,aRow: Integer; CheckCols,CheckRows: boolean): boolean;
procedure SetFlat(const AValue: Boolean);
procedure SetFocusRectVisible(const AValue: Boolean);
function doColSizing(X,Y: Integer): Boolean;
function doRowSizing(X,Y: Integer): Boolean;
procedure doColMoving(X,Y: Integer);
procedure doRowMoving(X,Y: Integer);
procedure doTopleftChange(DimChg: Boolean);
procedure EditorGetValue;
procedure EditorHide;
procedure EditorPos;
procedure EditorSelectAll;
procedure EditorShowChar(Ch: Char);
procedure EditorSetMode(const AValue: Boolean);
procedure EditorSetValue;
function EditorShouldEdit: Boolean;
procedure EditorShow;
function GetLeftCol: Integer;
function GetColCount: Integer;
function GetColWidths(Acol: Integer): Integer;
function GetRowCount: Integer;
function GetRowHeights(Arow: Integer): Integer;
function GetSelection: TGridRect;
function GetSystemMetricsGapSize(const Index: Integer): Integer;
function GetTopRow: Longint;
function GetVisibleColCount: Integer;
function GetVisibleGrid: TRect;
function GetVisibleRowCount: Integer;
procedure MyTextRect(R: TRect; Offx,Offy:Integer; S:string; Clipping: boolean);
procedure ReadColWidths(Reader: TReader);
procedure ReadRowHeights(Reader: TReader);
function ScrollToCell(const aCol,aRow: Integer): Boolean;
function ScrollGrid(Relative:Boolean; DCol,DRow: Integer): TPoint;
procedure SetCol(Valor: Integer);
procedure SetColwidths(Acol: Integer; Avalue: Integer);
procedure SetColCount(Valor: Integer);
procedure SetDefColWidth(Valor: Integer);
procedure SetDefRowHeight(Valor: Integer);
procedure SetDefaultDrawing(const AValue: Boolean);
procedure SetEditor(AValue: TWinControl);
procedure SetFixedCols(const AValue: Integer);
procedure SetFixedRows(const AValue: Integer);
procedure SetFocusColor(const AValue: TColor);
procedure SetGridLineColor(const AValue: TColor);
procedure SetGridLineStyle(const AValue: TPenStyle);
procedure SetGridLineWidth(const AValue: Integer);
procedure SetLeftCol(const AValue: Integer);
procedure SetOptions(const AValue: TGridOptions);
procedure SetRow(Valor: Integer);
procedure SetRowCount(Valor: Integer);
procedure SetRowheights(Arow: Integer; Avalue: Integer);
procedure SetScrollBars(const AValue: TScrollStyle);
procedure SetSelectActive(const AValue: Boolean);
procedure SetSelection(const AValue: TGridRect);
procedure SetTopRow(const AValue: Integer);
procedure TryScrollTo(aCol,aRow: integer);
procedure UpdateScrollBarPos(Which: TScrollStyle);
procedure UpdateSelectionRange;
procedure WriteColWidths(Writer: TWriter);
procedure WriteRowHeights(Writer: TWriter);
procedure WMEraseBkgnd(var message: TLMEraseBkgnd); message LM_ERASEBKGND;
procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE;
procedure WMSize(var Msg: TLMSize); message LM_SIZE;
procedure WMChar(var message: TLMChar); message LM_CHAR;
protected
fGridState: TGridState;
procedure AutoAdjustColumn(aCol: Integer); virtual;
procedure BeforeMoveSelection(const DCol,DRow: Integer); virtual;
procedure CheckLimits(var aCol,aRow: Integer);
procedure ColRowDeleted(IsColumn: Boolean; index: Integer); dynamic;
procedure ColRowExchanged(IsColumn: Boolean; index,WithIndex: Integer); dynamic;
procedure ColRowMoved(IsColumn: Boolean; FromIndex,ToIndex: Integer); dynamic;
function ColRowToOffset(IsCol,Fisical:Boolean; index: Integer; var Ini,Fin:Integer): Boolean;
procedure ColWidthsChanged; dynamic;
procedure CreateWnd; override;
procedure CreateParams(var Params: TCreateParams); override;
procedure DblClick; override;
procedure DefineProperties(Filer: TFiler); override;
procedure DestroyHandle; override;
procedure DoExit; override;
procedure DoEnter; override;
procedure DrawBackGround; virtual;
procedure DrawBorder;
procedure DrawByRows; virtual;
procedure DrawCell(aCol,aRow:Integer; aRect:TRect; aState:TGridDrawState); virtual;
procedure DrawCellGrid(aCol,aRow: Integer; aRect: TRect; astate: TGridDrawState);
procedure DrawColRowMoving;
procedure DrawEdges;
//procedure DrawFixedCells; virtual;
//procedure DrawFocused; virtual;
procedure DrawFocusRect(aCol,aRow:Integer; ARect:TRect); virtual;
//procedure DrawInteriorCells; virtual;
procedure DrawRow(aRow: Integer); virtual;
procedure EditordoGetValue; virtual;
procedure EditordoSetValue; virtual;
function GetFixedcolor: TColor; virtual;
function GetSelectedColor: TColor; virtual;
function GetEditMask(ACol, ARow: Longint): string; dynamic;
function GetEditText(ACol, ARow: Longint): string; dynamic;
procedure SetEditText(ACol, ARow: Longint; const Value: string); dynamic;
procedure HeaderClick(IsColumn: Boolean; index: Integer); dynamic;
procedure HeaderSized(IsColumn: Boolean; index: Integer); dynamic;
procedure InvalidateCell(aCol, aRow: Integer); overload;
procedure InvalidateCell(aCol, aRow: Integer; Redraw: Boolean); overload;
procedure InvalidateCol(ACol: Integer);
procedure InvalidateGrid;
procedure InvalidateRow(ARow: Integer);
procedure KeyDown(var Key : Word; Shift : TShiftState); override;
procedure KeyUp(var Key : Word; Shift : TShiftState); override;
procedure LoadContent(cfg: TXMLConfig; Version: Integer); virtual;
procedure Loaded; override;
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;
function MoveNextSelectable(Relative:Boolean; DCol, DRow: Integer): Boolean;
procedure MoveSelection; virtual;
function OffsetToColRow(IsCol,Fisical:Boolean; Offset:Integer; var Rest:Integer): Integer;
procedure Paint; override;
procedure PrepareCanvas(aCol,aRow: Integer; aState:TGridDrawState); virtual;
procedure ProcessEditor(LastEditor:TWinControl; DCol,DRow: Integer; WasVis: Boolean);
procedure ResetOffset(chkCol, ChkRow: Boolean);
procedure RowHeightsChanged; dynamic;
procedure SaveContent(cfg: TXMLConfig); virtual;
procedure ScrollBarRange(Which:Integer; {IsVisible:boolean; }aRange: Integer);
procedure ScrollBarPosition(Which, Value: integer);
//function ScrollBarIsVisible(Which:Integer): Boolean;
procedure ScrollBarPage(Which: Integer; aPage: Integer);
procedure ScrollBarShow(Which: Integer; aValue: boolean);
function ScrollBarAutomatic(Which: TScrollStyle): boolean; virtual;
procedure SelectEditor; virtual;
function SelectCell(ACol, ARow: Integer): Boolean; virtual;
procedure SetBorderStyle(NewStyle: TBorderStyle); override;
procedure SetFixedcolor(const AValue: TColor); virtual;
procedure SetSelectedColor(const AValue: TColor); virtual;
procedure SizeChanged(OldColCount, OldRowCount: Integer); dynamic;
procedure Sort(ColSorting: Boolean; index,IndxFrom,IndxTo:Integer); virtual;
procedure TopLeftChanged; dynamic;
function TryMoveSelection(Relative: Boolean; var DCol, DRow: Integer): Boolean;
procedure VisualChange; virtual;
procedure WMHScroll(var message : TLMHScroll); message LM_HScroll;
procedure WMVScroll(var message : TLMVScroll); message LM_VScroll;
procedure WndProc(var TheMessage : TLMessage); override;
property AutoAdvance: TAutoAdvance read FAutoAdvance write FAutoAdvance default aaRight;
property BorderStyle default bsSingle;
property Col: Integer read FCol write SetCol;
property ColCount: Integer read GetColCount write SetColCount;
property ColWidths[aCol: Integer]: Integer read GetColWidths write SetColWidths;
property DefaultColWidth: Integer read FDefColWidth write SetDefColWidth;
property DefaultRowHeight: Integer read FDefRowHeight write SetDefRowHeight;
property DefaultDrawing: Boolean read FDefaultDrawing write SetDefaultDrawing default True;
property DefaultTextStyle: TTextStyle read FDefaultTextStyle write FDefaultTextStyle;
property DragDx: Integer read FDragDx write FDragDx;
property Editor: TWinControl read FEditor write SetEditor;
property EditorMode: Boolean read FEditorMode write EditorSetMode;
property FixedCols: Integer read FFixedCols write SetFixedCols default 1;
property FixedRows: Integer read FFixedRows write SetFixedRows default 1;
property FixedColor: TColor read GetFixedColor write SetFixedcolor;
property Flat: Boolean read FFlat write SetFlat default false;
property FocusColor: TColor read FFocusColor write SetFocusColor;
property FocusRectVisible: Boolean read FFocusRectVisible write SetFocusRectVisible;
property GCache: TGridDataCache read FGCAChe;
property GridHeight: Integer read FGCache.GridHeight;
property GridLineColor: TColor read FGridLineColor write SetGridLineColor;
property GridLineStyle: TPenStyle read FGridLineStyle write SetGridLineStyle;
property GridLineWidth: Integer read FGridLineWidth write SetGridLineWidth default 1;
property GridWidth: Integer read FGCache.GridWidth;
property LeftCol:Integer read GetLeftCol write SetLeftCol;
property Options: TGridOptions read FOptions write SetOptions;
property Row: Integer read FRow write SetRow;
property RowCount: Integer read GetRowCount write SetRowCount;
property RowHeights[aRow: Integer]: Integer read GetRowHeights write SetRowHeights;
property SaveOptions: TSaveOptions read FsaveOptions write FSaveOptions;
property SelectActive: Boolean read FSelectActive write SetSelectActive;
property SelectedColor: TColor read GetSelectedColor write SetSelectedColor;
property Selection: TGridRect read GetSelection write SetSelection;
property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars;
property TopRow: Integer read GetTopRow write SetTopRow;
property VisibleColCount: Integer read GetVisibleColCount;
property VisibleRowCount: Integer read GetVisibleRowCount;
property OnBeforeSelection: TOnSelectEvent read FOnBeforeSelection write FOnBeforeSelection;
property OnCompareCells: TOnCompareCells read FOnCompareCells write FOnCompareCells;
property OnPrepareCanvas: TOnPrepareCanvasEvent read FOnPrepareCanvas write FOnPrepareCanvas;
property OnDrawCell: TOnDrawCell read FOnDrawCell write FOnDrawCell;
property OnSelection: TOnSelectEvent read fOnSelection write fOnSelection;
property OnSelectEditor: TSelectEditorEvent read FOnSelectEditor write FOnSelectEditor;
property OnTopLeftChanged: TNotifyEvent read FOnTopLeftChanged write FOnTopLeftChanged;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Invalidate; override;
{ Exposed procs }
procedure AutoAdjustColumns;
procedure BeginUpdate;
function CellRect(ACol, ARow: Integer): TRect;
procedure Clear;
procedure DeleteColRow(IsColumn: Boolean; index: Integer);
procedure EditorExit(Sender: TObject);
procedure EditorKeyDown(Sender: TObject; var Key:Word; Shift:TShiftState);
procedure EndUpdate(UO: TUpdateOption); overload;
procedure EndUpdate(FullUpdate: Boolean); overload;
procedure ExchangeColRow(IsColumn: Boolean; index, WithIndex: Integer);
function IscellSelected(aCol,aRow: Integer): Boolean;
function IscellVisible(aCol, aRow: Integer): Boolean;
procedure LoadFromFile(FileName: string);
function MouseToCell(Mouse: TPoint): TPoint;
function MouseToLogcell(Mouse: TPoint): TPoint;
function MouseToGridZone(X,Y: Integer; CellCoords: Boolean): TGridZone;
procedure MoveColRow(IsColumn: Boolean; FromIndex, ToIndex: Integer);
procedure SaveToFile(FileName: string);
procedure SortColRow(IsColumn: Boolean; index:Integer); overload;
procedure SortColRow(IsColumn: Boolean; index,FromIndex,ToIndex: Integer); overload;
end;
TGetEditEvent = procedure (Sender: TObject; ACol, ARow: Integer; var Value: string) of object;
TSetEditEvent = procedure (Sender: TObject; ACol, ARow: Integer; const Value: string) of object;
TDrawGrid=class(TCustomGrid)
private
FOnColRowDeleted: TgridOperationEvent;
FOnColRowExchanged: TgridOperationEvent;
FOnColRowMoved: TgridOperationEvent;
FOnGetEditMask: TGetEditEvent;
FOnGetEditText: TGetEditEvent;
FOnHeaderClick, FOnHeaderSized: THdrEvent;
FOnSelectCell: TOnSelectcellEvent;
FOnSetEditText: TSetEditEvent;
protected
FGrid: TVirtualGrid;
procedure CalcCellExtent(acol, aRow: Integer; var aRect: TRect); virtual;
procedure ColRowDeleted(IsColumn: Boolean; index: Integer); override;
procedure ColRowExchanged(IsColumn: Boolean; index,WithIndex: Integer); override;
procedure ColRowMoved(IsColumn: Boolean; FromIndex,ToIndex: Integer); override;
function CreateVirtualGrid: TVirtualGrid; virtual;
procedure DrawCell(aCol,aRow: Integer; aRect: TRect; aState:TGridDrawState); override;
procedure DrawFocusRect(aCol,aRow: Integer; ARect: TRect); override;
procedure HeaderClick(IsColumn: Boolean; index: Integer); override;
procedure HeaderSized(IsColumn: Boolean; index: Integer); override;
function GetEditMask(aCol, aRow: Longint): string; override;
function GetEditText(aCol, aRow: Longint): string; override;
function SelectCell(aCol,aRow: Integer): boolean; override;
procedure SetColor(Value: TColor); override;
procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
procedure SizeChanged(OldColCount, OldRowCount: Integer); override;
public
// to easy user call
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DefaultDrawCell(aCol,aRow: Integer; var aRect: TRect; aState:TGridDrawState); virtual;
// properties
property Canvas;
property Col;
property ColWidths;
property Editor;
property EditorMode;
property FocusColor;
property FocusRectVisible;
property GridHeight;
property GridLineColor;
property GridLineStyle;
property GridWidth;
property LeftCol;
property Row;
property RowHeights;
property SaveOptions;
property SelectedColor;
property Selection;
//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; // Deprecated
property DefaultColWidth;
property DefaultDrawing;
property DefaultRowHeight;
//property DragCursor;
//property DragKind;
//property DragMode;
property Enabled;
property FixedColor;
property FixedCols;
property FixedRows;
property Flat;
property Font;
property GridLineWidth;
property Options;
//property ParentBiDiMode;
//property ParentColor;
//property ParentCtl3D; // Deprecated
//property ParentFont;
property ParentShowHint;
property PopupMenu;
property RowCount;
property ScrollBars;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property VisibleColCount;
property VisibleRowCount;
property OnBeforeSelection;
property OnClick;
property OnColRowDeleted: TgridOperationEvent read FOnColRowDeleted write FOnColRowDeleted;
property OnColRowExchanged: TgridOperationEvent read FOnColRowExchanged write FOnColRowExchanged;
property OnColRowMoved: TgridOperationEvent read FOnColRowMoved write FOnColRowMoved;
property OnCompareCells;
property OnDblClick;
property OnDrawCell;
property OnEnter;
property OnExit;
property OnGetEditMask: TGetEditEvent read FOnGetEditMask write FOnGetEditMask;
property OnGetEditText: TGetEditEvent read FOnGetEditText write FOnGetEditText;
property OnHeaderClick: THdrEvent read FOnHeaderClick write FOnHeaderClick;
property OnHeaderSized: THdrEvent read FOnHeaderSized write FOnHeaderSized;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnPrepareCanvas;
property OnSelectEditor;
property OnSelection;
property OnSelectCell: TOnSelectCellEvent read FOnSelectCell write FOnSelectCell;
property OnSetEditText: TSetEditEvent read FOnSetEditText write FOnSetEditText;
property OnTopleftChanged;
{
property OnContextPopup;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnStartDock;
property OnStartDrag;
property OnMouseWheelDown;
property OnMouseWheelUp;
}
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 ReadCells(Reader: TReader);
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);
procedure WriteCells(Writer: TWriter);
protected
procedure AutoAdjustColumn(aCol: Integer); override;
procedure CalcCellExtent(acol, aRow: Integer; var aRect: TRect); override;
procedure DefineProperties(Filer: TFiler); override;
procedure DrawCell(aCol,aRow: Integer; aRect: TRect; aState:TGridDrawState); override;
procedure EditordoGetValue; override;
procedure EditordoSetValue; override;
function GetEditText(aCol, aRow: Integer): string; override;
procedure LoadContent(cfg: TXMLConfig; Version: Integer); override;
procedure SaveContent(cfg: TXMLConfig); override;
//procedure DrawInteriorCells; override;
procedure SelectEditor; override;
procedure SetEditText(aCol, aRow: Longint; const aValue: string); override;
public
constructor Create(AOWner: TComponent); override;
destructor Destroy; override;
procedure AutoSizeColumns;
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);
procedure register;
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 RndStr:string;
var
i: Integer;
begin
Result:='';
For i:=1 to 10 do begin
Result:=Result+ Char(Ord('A')+Random(20));
end;
end;}
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;
procedure SwapInt(var I1,I2: Integer);
var
Tmp: Integer;
begin
Tmp:=I1;
I1:=I2;
I2:=Tmp;
end;
{$ifdef GridTraceMsg}
function TransMsg(const S: String; const TheMsg: TLMessage): String;
var
hex: string;
begin
with TheMsg do begin
hex:= S + '['+IntToHex(msg, 8)+'] W='+IntToHex(WParam,8)+' L='+IntToHex(LParam,8)+' ';
case Msg of
CM_BASE..CM_MOUSEWHEEL:
case Msg of
CM_MOUSEENTER: DebugLn(hex, 'CM_MOUSEENTER');
CM_MOUSELEAVE: DebugLn(hex, 'CM_MOUSELEAVE');
CM_TEXTCHANGED: DebugLn(hex, 'CM_TEXTCHANGED');
CM_PARENTCTL3DCHANGED: DebugLn(hex, 'CM_PARENTCTL3DCHANGED');
CM_UIACTIVATE: DebugLn(hex, 'CM_UIACTIVATE');
CM_CONTROLLISTCHANGE: DebugLn(hex, 'CM_CONTROLLISTCHANGE');
CM_PARENTCOLORCHANGED: DebugLn(hex, 'CM_PARENTCOLORCHANGED');
CM_PARENTFONTCHANGED: DebugLn(hex, 'CM_PARENTFONTCHANGED');
CM_PARENTSHOWHINTCHANGED: DebugLn(hex, 'CM_PARENTSHOWHINTCHANGED');
CM_PARENTBIDIMODECHANGED: DebugLn(hex, 'CM_PARENTBIDIMODECHANGED');
CM_CONTROLCHANGE: DebugLn(Hex, 'CM_CONTROLCHANGE');
CM_SHOWINGCHANGED: DebugLn(Hex, 'CM_SHOWINGCHANGED');
CM_VISIBLECHANGED: DebugLn(Hex, 'CM_VISIBLECHANGED');
else DebugLn(Hex, 'CM_BASE + ', IntToStr(Msg - CM_BASE));
end;
else
case Msg of
//CN_BASE MESSAGES
CN_COMMAND: DebugLn(hex, 'LM_CNCOMMAND');
// NORMAL MESSAGES
LM_SETFOCUS: DebugLn(hex, 'LM_SetFocus');
LM_LBUTTONDOWN: DebugLn(hex, 'LM_MOUSEDOWN');
LM_LBUTTONUP: DebugLn(hex, 'LM_LBUTTONUP');
LM_RBUTTONDOWN: DebugLn(hex, 'LM_RBUTTONDOWN');
LM_RBUTTONUP: DebugLn(hex, 'LM_RBUTTONUP');
LM_GETDLGCODE: DebugLn(hex, 'LM_GETDLGCODE');
LM_KEYDOWN: DebugLn(hex, 'LM_KEYDOWN');
LM_KEYUP: DebugLn(hex, 'LM_KEYUP');
LM_CAPTURECHANGED: DebugLn(hex, 'LM_CAPTURECHANGED');
LM_ERASEBKGND: DebugLn(hex, 'LM_ERASEBKGND');
LM_KILLFOCUS: DebugLn(hex, 'LM_KILLFOCUS');
LM_CHAR: DebugLn(hex, 'LM_CHAR');
LM_SHOWWINDOW: DebugLn(hex, 'LM_SHOWWINDOW');
LM_SIZE: DebugLn(hex, 'LM_SIZE');
LM_WINDOWPOSCHANGED: DebugLn(hex, 'LM_WINDOWPOSCHANGED');
LM_HSCROLL: DebugLn(hex, 'LM_HSCROLL');
LM_VSCROLL: DebugLn(hex, 'LM_VSCROLL');
LM_MOUSEMOVE: ;//DebugLn(hex, 'LM_MOUSEMOVE');
LM_MOUSEWHEEL: DebugLn(Hex, 'LM_MOUSEWHEEL');
else DebugLn(hex, GetMessageName(Msg));
end;
end;
end;
end;
{$Endif GridTraceMsg}
{ TCustomGrid }
function TCustomGrid.GetRowHeights(Arow: Integer): Integer;
begin
if (aRow<RowCount) and (aRow>=0) then
Result:=Integer(FRows[aRow])
else
Result:=-1;
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
if (aCol<ColCount) and (aCol>=0) then
Result:=Integer(FCols[aCol])
else
Result:=-1;
if result<0 then Result:=fDefColWidth;
end;
procedure TCustomGrid.SetEditor(AValue: TWinControl);
var
Msg: TGridMessage;
begin
if FEditor=AValue then exit;
FEditor:=AValue;
if FEditor<>nil then begin
if FEditor.Parent=nil then FEditor.Visible:=False;
if FEditor.Parent<>Self then FEditor.Parent:=Self;
FEditor.TabStop:=False;
Msg.MsgID:=GM_SETGRID;
Msg.Grid:=Self;
Msg.Options:=0;
FEditor.Dispatch(Msg);
FEditorOptions:=Msg.Options;
if Msg.Options and EO_HOOKKEYS = EO_HOOKKEYS then begin
FEditor.OnKeyDown:=@EditorKeyDown;
end;
if Msg.Options and EO_HOOKEXIT = EO_HOOKEXIT then begin
FEditor.OnExit:=@EditorExit;
end;
{$IfDef EditorDbg}
DBGOut('SetEditor-> Editor=',FEditor.Name,' ');
if FEditorOptions and EO_AUTOSIZE = EO_AUTOSIZE then DBGOut('EO_AUTOSIZE ');
if FEditorOptions and EO_HOOKKEYS = EO_HOOKKEYS then DBGOut('EO_HOOKKEYS ');
if FEditorOptions and EO_HOOKEXIT = EO_HOOKEXIT then DBGOut('EO_HOOKEXIT ');
if FEditorOptions and EO_SELECTALL= EO_SELECTALL then DBGOut('EO_SELECTALL ');
if FEditorOptions and EO_WANTCHAR = EO_WANTCHAR then DBGOut('EO_WANTCHAR ');
DebugLn;
{$Endif}
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;
if not (csLoading in componentState) then 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;
UpdateSelectionRange;
if not (csLoading in ComponentState) Then 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 goRangeSelect in Options then
FOptions:=FOptions - [goAlwaysShowEditor];
UpdateSelectionRange;
if goAlwaysShowEditor in Options then begin
EditorShow;
end else begin
EditorHide;
end;
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;
if (FEditor<>nil)and(Feditor.Visible)and(ARow<=FRow) then EditorPos;
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;
if (FEditor<>nil)and(Feditor.Visible)and(ACol<=FCol) then EditorPos;
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;
procedure FixSelection;
begin
if FRow > FRows.Count - 1 then FRow := FRows.Count - 1;
if FCol > FCols.Count - 1 then FCol := FCols.Count - 1;
UpdateSelectionRange;
end;
var
OldCount: integer;
begin
if IsColumn then begin
AddDel(FCols, NewValue);
FGCache.AccumWidth.Count:=NewValue;
OldCount:=RowCount;
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, OldCount);
end else begin
AddDel(FRows, NewValue);
FGCache.AccumHeight.Count:=NewValue;
OldCount:=ColCount;
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(OldCount, OldValue);
end;
FixSelection;
VisualChange;
end;
procedure TCustomGrid.SetColCount(Valor: Integer);
var
OldC: Integer;
begin
if Valor=FCols.Count then Exit;
if Valor<1 then
Clear
else begin
OldC:=FCols.Count;
CheckFixedCount(Valor, RowCount, FFixedCols, FFixedRows);
CheckCount(Valor, RowCount);
AdjustCount(True, OldC, Valor);
end;
end;
procedure TCustomGrid.SetRowCount(Valor: Integer);
var
OldR: Integer;
begin
if Valor=FRows.Count then Exit;
if Valor<1 then
clear
else begin
OldR:=FRows.Count;
CheckFixedCount(ColCount, Valor, FFixedCols, FFixedRows);
CheckCount(ColCount, Valor);
AdjustCount(False, OldR, Valor);
end;
end;
procedure TCustomGrid.SetDefColWidth(Valor: Integer);
var
i: Integer;
begin
if Valor=fDefColwidth then Exit;
FDefColWidth:=Valor;
for i:=0 to ColCount-1 do FCols[i] := Pointer(-1);
VisualChange;
end;
procedure TCustomGrid.SetDefRowHeight(Valor: Integer);
var
i: Integer;
begin
if Valor=fDefRowHeight then Exit;
FDefRowheight:=Valor;
for i:=0 to RowCount-1 do FRows[i] := Pointer(-1);
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);
updateScrollBarPos(ssBoth);
end;
procedure TCustomGrid.VisualChange;
var
Tw,Th: Integer;
Dh,DV: Integer;
function CalcMaxTopLeft: 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}
HsbVisible, VsbVisible: boolean;
HsbRange, VsbRange: Integer;
begin
if FCols=nil then exit; // not yet initialized or already destroyed
// Calculate New Cached Values
FGCache.GridWidth:=0;
FGCache.FixedWidth:=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 dbgVisualChange}
DebugLn('FGCache.AccumWidth[',Tw,']=',Integer(FGCache.AccumWidth[Tw]));
{$Endif}
end;
FGCache.Gridheight:=0;
FGCache.FixedHeight:=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 dbgVisualChange}
DebugLn('FGCache.AccumHeight[',Tw,']=',Integer(FGCache.AccumHeight[Tw]));
{$Endif}
end;
if not(goSmoothScroll in Options) then begin
FGCache.TLColOff:=0;
FGCache.TLRowOff:=0;
end;
Dh:=FGSMHBar;
DV:=FGSMVBar;
TW:=FGCache.GridWidth;
TH:=FGCache.GridHeight;
FGCache.ClientWidth:= Width - Integer(BorderStyle);
FGCache.ClientHeight := Height - Integer(BorderStyle);
HsbRange:=Width - Dv;
VsbRange:=Height - Dh;
HsbVisible := (FScrollBars in [ssHorizontal, ssBoth]) or (FGCache.GridWidth > FGCache.ClientWidth);
VsbVisible := (FScrollBars in [ssVertical, ssBoth]) or (FGCache.GridHeight > FGCache.ClientHeight);
if ScrollBarAutomatic(ssHorizontal) then
HsbVisible := HsbVisible or (VsbVisible and (TW>HsbRange));
if ScrollBarAutomatic(ssVertical) then
VsbVisible := VsbVisible or (HsbVisible and (TH>VsbRange));
{
HSbVisible:=
((FScrollbars in [ssHorizontal, ssBoth]) or
(ScrollBarAutomatic(ssHorizontal)) and (VsbVisible And (TW>HsbRange)));
VSbVisible:=
((FScrollbars in [ssVertical, ssBoth]) or
(ScrollBarAutomatic(ssVertical)) and (Hsbvisible And (TH>VsbRange)));
}
if not HSBVisible then DH:=0;
if not VSbVisible then DV:=0;
Dec(FGCache.ClientWidth, DV);
Dec(FGCache.ClientHeight, DH);
{$Ifdef DbgVisualChange}
DbgOut('Width=',IntTostr(Width));
DbgOut(' Height=',IntToStr(height));
DbgOut(' GWidth=',IntTostr(TW));
DbgOut(' GHeight=',IntToStr(TH));
DbgOut(' HsbRange=',IntToStr(HsbRange));
DbgOut(' VsbRange=',IntToStr(VSbRange));
DbgOut(' Vbar=',IntToStr(VSbVisible));
DebugLn(' HSb=',IntToStr(HsbVisible));
DbgOut('ClientWidth=', IntToStr(FGCAche.ClientWidth));
DebugLn(' ClientHeight=', IntToStr(FGCache.ClientHeight));
{$endif}
//FGCache.ClientWidth:= Width - DV;
//FGCache.ClientHeight:=Height - DH;
FGCache.ScrollWidth:=FGCache.ClientWidth-FGCache.FixedWidth;
FGCache.ScrollHeight:=FGCache.ClientHeight-FGCache.FixedHeight;
FGCache.MaxTopLeft:=CalcMaxTopLeft;
{$Ifdef DbgVisualChange}
DebugPoint('MaxTopLeft',FGCache.MaxTopLeft);
{$Endif}
FGCache.HScrDiv:=0;
FGCache.VScrDiv:=0;
with FGCache do
if ScrollBarAutomatic(ssHorizontal) then begin
if HSbVisible then begin
HsbRange:=GridWidth + 2 - Integer(BorderStyle){+ dv};
if not (goSmoothScroll in Options) then begin
TW:= Integer(AccumWidth[MaxTopLeft.X])-(HsbRange-ClientWidth);
HsbRange:=HsbRange + TW - FixedWidth + 1;
end;
if HsbRange>ClientWidth then
HscrDiv := Double(ColCount-FixedCols-1)/(HsbRange-ClientWidth);
end;
end else
if FScrollBars in [ssHorizontal, ssBoth] then HsbRange:=0;
ScrollBarShow(SB_HORZ, HsbVisible);
If HsbVisible then ScrollBarRange(SB_HORZ, {HsbVisible, }HsbRange );
with FGCache do
if ScrollBarAutomatic(ssVertical) then begin
if VSbVisible then begin
VSbRange:= GridHeight + 2 - Integer(BorderStyle){ + dh};
if not (goSmoothScroll in Options) then begin
TH:= Integer(accumHeight[MaxTopLeft.Y])-(VsbRange-ClientHeight);
VsbRange:=VsbRange + TH -FixedHeight + 1;
end;
if VSbRange>ClientHeight then
VScrDiv:= Double(RowCount-FixedRows-1)/(VsbRange-ClientHeight);
end;
end else
if FScrollBars in [ssVertical, ssBoth] then VsbRange:= 0;
ScrollBarShow(SB_VERT, VsbVisible);
if VsbVisible then ScrollbarRange(SB_VERT, {VsbVisible, }VsbRange );
CacheVisibleGrid;
Invalidate;
end;
procedure TCustomGrid.CreateParams(var Params: TCreateParams);
const
ClassStylesOff = CS_VREDRAW or CS_HREDRAW;
begin
inherited CreateParams(Params);
with Params do begin
WindowClass.Style := WindowClass.Style and DWORD(not ClassStylesOff);
Style := Style or WS_VSCROLL or WS_HSCROLL or WS_CLIPCHILDREN;
end;
end;
procedure TCustomGrid.ScrollBarRange(Which: Integer; aRange: Integer);
var
ScrollInfo: TScrollInfo;
begin
if HandleAllocated then begin
{$Ifdef DbgScroll}
DebugLn('ScrollbarRange: Which=',IntToStr(Which),' Range=',IntToStr(aRange));
{$endif}
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_RANGE or SIF_PAGE or SIF_DISABLENOSCROLL;
ScrollInfo.nMin := 0;
ScrollInfo.nMax := ARange;
if Which = SB_VERT then
ScrollInfo.nPage := ClientHeight
else
ScrollInfo.nPage := ClientWidth;
if ScrollInfo.nPage<1 then ScrollInfo.nPage:=1;
SetScrollInfo(Handle, Which, ScrollInfo, True);
end;
end;
procedure TCustomGrid.ScrollBarPosition(Which, Value: integer);
var
ScrollInfo: TScrollInfo;
Vis: Boolean;
begin
if HandleAllocated then begin
{$Ifdef DbgScroll}
DebugLn('ScrollbarPosition: Which=',IntToStr(Which), ' Value= ',IntToStr(Value));
{$endif}
if Which = SB_VERT then Vis := FVSbVisible else
if Which = SB_HORZ then Vis := FHSbVisible
else vis := false;
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_POS;
ScrollInfo.nPos:= Value;
SetScrollInfo(Handle, Which, ScrollInfo, Vis);
end;
end;
{
function TCustomGrid.ScrollBarIsVisible(Which: Integer): Boolean;
begin
Result:=false;
if HandleAllocated then begin
Result:= getScrollbarVisible(handle, Which);
end;
end;
}
procedure TCustomGrid.ScrollBarPage(Which: Integer; aPage: Integer);
var
ScrollInfo: TScrollInfo;
begin
if HandleAllocated then begin
ScrollInfo.cbSize := SizeOf(ScrollInfo);
ScrollInfo.fMask := SIF_PAGE;
ScrollInfo.nPage:= aPage;
SetScrollInfo(Handle, Which, ScrollInfo, True);
end;
end;
procedure TCustomGrid.ScrollBarShow(Which: Integer; aValue: boolean);
begin
if HandleAllocated then begin
{$Ifdef DbgScroll}
DebugLn('ScrollbarShow: Which=',IntToStr(Which), ' Avalue=',BoolToStr(AValue));
{$endif}
ShowScrollBar(Handle,Which,aValue);
if Which in [SB_BOTH, SB_VERT] then FVSbVisible := AValue else
if Which in [SB_BOTH, SB_HORZ] then FHSbVisible := AValue;
end;
end;
function TCustomGrid.ScrollBarAutomatic(Which: TScrollStyle): boolean;
begin
result:=false;
if (Which=ssVertical)or(Which=ssHorizontal) then begin
if Which=ssVertical then Which:=ssAutoVertical
else Which:=ssAutoHorizontal;
Result:= FScrollBars in [Which, ssAutoBoth];
end;
end;
{ Returns a reactagle corresponding to a fisical cell[aCol,aRow] }
function TCustomGrid.CellRect(ACol, ARow: Integer): TRect;
begin
//Result:=ColRowToClientCellRect(aCol,aRow);
ColRowToOffset(True, True, ACol, Result.Left, Result.Right);
ColRowToOffSet(False,True, ARow, Result.Top, Result.Bottom);
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;
OldTopLeft:TPoint;
Xinc,YInc: Integer;
begin
OldTopLeft:=fTopLeft;
while (fTopLeft.x>=0) and
(fTopLeft.x<ColCount)and
(fTopLeft.y>=0) and
(fTopLeft.y<RowCount) do begin
RNew:=CellRect(aCol,aRow);
Xinc:=0;
if Rnew.Left + FGCache.TLColOff < FGCache.FixedWidth then Xinc:=-1
else if RNew.Right + FGCache.TLColOff > FGCache.ClientWidth then XInc:=1;
Yinc:=0;
if RNew.Top + FGCAche.TLRowOff < FGcache.FixedHeight then Yinc:=-1
else if RNew.Bottom + FGCache.TLRowOff > FGCache.ClientHeight 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)
else ResetOffset(True, True);
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(OnTopLeftChanged) and not (csDesigning in ComponentState) then
OnTopLeftChanged(Self);
end;
procedure TCustomGrid.HeaderClick(IsColumn: Boolean; index: Integer);
begin
end;
procedure TCustomGrid.HeaderSized(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);
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;
procedure TCustomGrid.Paint;
begin
Inherited Paint;
if FUpdateCount=0 then begin
//DebugLn('Paint: FGCache.ValidGrid=',FGCache.ValidGrid );
//DebugRect('Paint.ClipRect=',Canvas.ClipRect);
DrawEdges;
DrawBackGround;
if FGCache.ValidGrid then begin
{
DrawFixedCells;
DrawInteriorCells;
DrawFocused;
}
DrawByRows;
DrawColRowMoving;
end;
DrawBorder;
end;
end;
procedure TCustomGrid.PrepareCanvas(aCol, aRow: Integer; aState: TGridDrawState
);
begin
Canvas.TextStyle := DefaultTextStyle;
if DefaultDrawing then begin
if gdSelected in aState then Canvas.Brush.color:= SelectedColor else
if gdFixed in aState then Canvas.Brush.color:= FixedColor
else Canvas.Brush.color:= Color;
if gdSelected in aState then Canvas.Font.Color := clWindow
else Canvas.Font.Color := Self.Font.Color; //clWindowText;
end else begin
Canvas.Brush.Color := clWindow;
Canvas.Font.Color := clWindowText;
end;
if Assigned(OnPrepareCanvas) then
OnPrepareCanvas(Self, aCol, aRow, aState);
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(ssHorizontal);//UpdateScrollBarPos(HorzScrollBar);
if ChkRow then updateScrollBarPos(ssVertical);//UpdateScrolLBarPos(VertScrollBar);
end;
end;
end;
function TCustomGrid.SelectCell(ACol, ARow: Integer): Boolean;
begin
Result:=true;
//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.DrawBorder;
var
R: TRect;
begin
if BorderStyle = bsSingle then begin
R := Rect(0,0,FGCache.ClientWidth, FGCache.Clientheight);
with R, Canvas do begin
Pen.Color := cl3DDKShadow;
MoveTo(0,0);
LineTo(0,Bottom);
LineTo(Right, Bottom);
LineTo(Right, 0);
LineTo(0,0);
end;
end;
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, CellRect(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, CellRect(i,j), gds);
// Draw fixed row headers
For i:=0 to FFixedCols-1 do
For j:=Top to Bottom do
DrawCell(i,j, CellRect(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, CellRect(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
PrepareCanvas(aCol, aRow, aState);
Canvas.FillRect(aRect);
DrawCellGrid(aCol,aRow,aRect,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;
function VerticalIntersect(const aRect,bRect: TRect): boolean;
begin
result := (aRect.Top < bRect.Bottom) and (aRect.Bottom > bRect.Top);
end;
function HorizontalIntersect(const aRect,bRect: TRect): boolean;
begin
result := (aRect.Left < bRect.Right) and (aRect.Right > bRect.Left);
end;
procedure TCustomGrid.DrawRow(aRow: Integer);
var
Gds: TGridDrawState;
i: Integer;
Rs: Boolean;
R: TRect;
{$IFDEF UseClipRect}
ClipArea: Trect;
{$ENDIF}
begin
// Upper and Lower bounds for this row
ColRowToOffSet(False, True, aRow, R.Top, R.Bottom);
{$IFDEF UseClipRect}
// is this row within the ClipRect
ClipArea := Canvas.ClipRect;
if not VerticalIntersect( R, ClipArea) then exit;
{$ENDIF}
// 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);
{$IFDEF UseClipRect}
// is this column within the ClipRect?
if HorizontalIntersect( R, ClipArea) then
{$ENDIF}
DrawCell(i,aRow, R,gds)
end;
end else begin
Rs:=(goRowSelect in Options);
For i:=Left To Right do begin
ColRowToOffset(True, True, i, R.Left, R.Right);
{$IFDEF UseClipRect}
// is this column within the ClipRect?
if Not HorizontalIntersect( R, ClipArea) then
Continue;
{$ENDIF}
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);
DrawCell(i,aRow, R, gds);
end;
// Draw the focus Rect
if FFocusRectVisible and (ARow=FRow) and
((Rs and (ARow>=Top) and (ARow<=Bottom)) or IsCellVisible(FCol,ARow))
then begin
if EditorShouldEdit and (FEditor<>nil) and FEditor.Visible then begin
//DebugLn('No Draw Focus Rect');
end else begin
ColRowToOffset(True, True, FCol, R.Left, R.Right);
{$IFDEF UseClipRect}
// is this column within the ClipRect?
if HorizontalIntersect( R, ClipArea) then
{$ENDIF}
DrawFocusRect(FCol,FRow, R);
end;
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);
{$IFDEF UseClipRect}
// is this column within the ClipRect?
if HorizontalIntersect( R, ClipArea) then
{$ENDIF}
DrawCell(i,aRow, R,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:=CellRect(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:=CellRect(fCol,fRow);
DrawFocusRect(fcol,fRow, R, gds);
end;
end;
}
procedure DebugRect(S:string; R:TRect);
begin
DebugLn(S,dbgs(r));
end;
procedure DebugPoint(S:string; P:TPoint);
begin
DebugLn(S,dbgs(p));
end;
procedure TCustomGrid.DrawCellGrid(aCol,aRow: Integer; aRect: TRect; aState: TGridDrawState);
var
dv,dh: Boolean;
begin
// Draw Cell Grid or Maybe in the future Borders..
with Canvas, aRect do begin
if (gdFixed in aState) then begin
Dv := goFixedVertLine in Options;
Dh := goFixedHorzLine in Options;
Pen.Style := psSolid;
if Not FFlat Then begin
Pen.Color := cl3DHilight;
MoveTo(Right - 1, Top);
LineTo(Left, Top);
LineTo(Left, Bottom);
end;
Pen.Color := cl3DDKShadow;
end else begin
Dv := goVertLine in Options;
Dh := goHorzLine in Options;
Pen.Style := fGridLineStyle;
Pen.Color := fGridLineColor;
end;
if Dh then begin
MoveTo(Left, Bottom - 1);
LineTo(Right, Bottom - 1);
end;
if Dv then begin
MoveTo(Right - 1, Top);
LineTo(Right - 1, Bottom);
end;
end;
end;
procedure TCustomGrid.MyTextRect(R: TRect; Offx, Offy: Integer; S: string;
Clipping: boolean);
var
Rorg: TRect;
tmpRgn: HRGN;
begin
if 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 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.ReadColWidths(Reader: TReader);
var
i: integer;
begin
with Reader do begin
ReadListBegin;
for i:=0 to ColCount-1 do
ColWidths[I] := ReadInteger;
ReadListEnd;
end;
end;
procedure TCustomGrid.ReadRowHeights(Reader: TReader);
var
i: integer;
begin
with Reader do begin
ReadListBegin;
for i:=0 to RowCount-1 do
RowHeights[I] := ReadInteger;
ReadListEnd;
end;
end;
procedure TCustomGrid.WMEraseBkgnd(var message: TLMEraseBkgnd);
begin
message.Result:=1;
//DebugLn('TCustomGrid.WMEraseBkgnd');
end;
procedure TCustomGrid.WMGetDlgCode(var Msg: TLMNoParams);
begin
Msg.Result := DLGC_WANTARROWS or DLGC_WANTCHARS or DLGC_WANTALLKEYS;
if goTabs in Options then Msg.Result:= Msg.Result or DLGC_WANTTAB;
end;
//
// NOTE: WMHScroll and VMHScroll
// This methods are used to pre-calculate the scroll position
//
procedure TCustomGrid.WMHScroll(var message: TLMHScroll);
var
C,TL,CTL: Integer;
begin
// Avoid invalidating right know, just let the scrollbar
// calculate its position
{
BeginUpdate;
Inherited;
message.Result:=1;
EndUpdate(uoNone);
}
{$IfDef dbgScroll}
DebugLn('HSCROLL: Code=',IntToStr(message.ScrollCode),' Position=', IntToStr(message.Pos));
{$Endif}
if FGCache.HScrDiv<=0 then Exit;
if FEditor<>nil then
EditorGetValue;
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
TL:= Integer(FGCache.AccumWidth[ FGCache.MaxTopLeft.X ]) - FGCAche.FixedWidth;
CTL:= Integer(FGCache.AccumWidth[ FtopLeft.X ]) - FGCache.FixedWidth;
case message.ScrollCode of
// Scrolls to start / end of the text
SB_TOP: C := 0;
SB_BOTTOM: C := TL;
// Scrolls one line up / down
SB_LINEDOWN: C := CTL + GetColWidths( FTopLeft.X );
SB_LINEUP: C := CTL - GetColWidths( FTopLeft.X - 1);
// Scrolls one page of lines up / down
SB_PAGEDOWN: C := CTL + FGCache.ClientWidth;
SB_PAGEUP: C := CTL - FGCache.ClientWidth;
// Scrolls to the current scroll bar position
SB_THUMBPOSITION,
SB_THUMBTRACK: C := message.Pos;
// Ends scrolling
SB_ENDSCROLL: Exit;
end;
if C > TL then C := TL else
if C < 0 then C := 0;
{$Ifdef dbgScroll}
DebugLn('---- Position=',IntToStr(C), ' FixedWidth=',IntToStr(FGCache.FixedWidth));
{$Endif}
ScrollBarPosition(SB_HORZ, C);
C:= C + FGCache.FixedWidth + Integer(BorderStyle);
{$Ifdef dbgScroll}
DebugLn('---- Position=',IntToStr(C), ' FixedWidth=',IntToStr(FGCache.FixedWidth));
{$Endif}
TL:=OffsetToColRow(True, False, C, FGCache.TLColOff);
{$Ifdef dbgScroll}
DebugLn('---- Offset=',IntToStr(C), ' TL=',IntToStr(TL),' TLColOFf=', IntToStr(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;
{
R.Topleft:=Point(FGCache.FixedWidth, 0);
R.BottomRight:= FGCache.MaxClientXY;
InvalidateRect(Handle, @R, false);
}
Invalidate;
end;
end;
end;
procedure TCustomGrid.WMVScroll(var message: TLMVScroll);
var
C, TL, CTL: Integer;
begin
// Avoid invalidating right know, just let the scrollbar
// calculate its position
{
BeginUpdate;
Inherited;
message.Result:=1;
EndUpdate(uoNone);
}
{$IfDef dbgScroll}
DebugLn('VSCROLL: Code=',IntToStr(message.ScrollCode),' Position=', IntToStr(message.Pos));
{$Endif}
if FGCache.VScrDiv<=0 then Exit;
if FEditor<>nil then EditorGetValue;
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
TL:= Integer(FGCache.AccumHeight[ FGCache.MaxTopLeft.Y ]) - FGCache.FixedHeight;
CTL:= Integer(FGCache.AccumHeight[ FtopLeft.Y ]) - FGCache.FixedHeight;
case message.ScrollCode of
// Scrolls to start / end of the text
SB_TOP: C := 0;
SB_BOTTOM: C := TL;
// Scrolls one line up / down
SB_LINEDOWN: C := CTL + GetRowHeights( FTopleft.Y );
SB_LINEUP: C := CTL - GetRowHeights( FTopleft.Y - 1 );
// Scrolls one page of lines up / down
SB_PAGEDOWN: C := CTL + FGCache.ClientHeight;
SB_PAGEUP: C := CTL - FGCache.ClientHeight;
// Scrolls to the current scroll bar position
SB_THUMBPOSITION,
SB_THUMBTRACK: C := message.Pos;
// Ends scrolling
SB_ENDSCROLL: Exit;
end;
if C > Tl then C := TL else
if C < 0 then C := 0;
{$Ifdef dbgScroll}
DebugLn('---- Position=',IntToStr(C), ' FixedHeight=',IntToStr(FGCache.FixedHeight));
{$Endif}
ScrollBarPosition(SB_VERT, C);
C:= C + FGCache.FixedHeight + Integer(BorderStyle);
{$Ifdef dbgScroll}
DebugLn('---- NewPosition=',IntToStr(C));
{$Endif}
TL:=OffsetToColRow(False, False, C, FGCache.TLRowOff);
{$Ifdef dbgScroll}
DebugLn('---- Offset=',IntToStr(C), ' TL=',IntToStr(TL), ' TLRowOFf=', IntToStr(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;
{
R.TopLeft:=Point(0, FGCache.FixedHeight);
R.BottomRight:=FGCache.MaxClientXY;
InvalidateRect(Handle, @R, false);
}
Invalidate;
end;
end;
end;
procedure TCustomGrid.WMSize(var Msg: TLMSize);
begin
Inherited;
visualChange;
end;
procedure TCustomGrid.WMChar(var message: TLMChar);
var
Ch: Char;
begin
inherited;
Ch:=Char(message.CharCode);
{$Ifdef GridTraceMsg}
DebugLn(ClassName,'.WMchar CharCode= ', IntToStr(message.CharCode));
{$Endif}
if (goEditing in Options) and (Ch in [^H, #32..#255]) then
EditorShowChar(Ch);
{
else
inherited;
}
end;
procedure TCustomGrid.WndProc(var TheMessage: TLMessage);
begin
{$IfDef GridTraceMsg}
TransMsg('GRID: ', TheMessage);
{$Endif}
with TheMessage do
if (csDesigning in ComponentState) and
((Msg = LM_HSCROLL)or(Msg = LM_VSCROLL))
then
Exit;
inherited WndProc(TheMessage);
end;
procedure TCustomGrid.CreateWnd;
begin
inherited CreateWnd;
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: TScrollStyle);
begin
// Adjust ScrollBar Positions
// Special condition only When scrolling by draging
// the scrollbars see: WMHScroll and WVHScroll
if FUpdateScrollBarsCount=0 then begin
if Which in [ssHorizontal, ssBoth] then begin
if ScrollBarAutomatic(ssHorizontal) Then begin
with FGCache do
ScrollBarPosition(SB_HORZ,
Integer(AccumWidth[FTopLeft.x])-TLColOff-FixedWidth );
end;
end;
if Which in [ssVertical, ssBoth] then begin
if ScrollBarAutomatic(ssVertical) then begin
with FGCache do
ScrollBarPosition(SB_VERT,
Integer(AccumHeight[FTopLeft.y])-TLRowOff-FixedHeight);
end;
end;
end; {if FUpd...}
end;
procedure TCustomGrid.UpdateSelectionRange;
begin
if goRowSelect in Options then begin
FRange:=Rect(FFixedCols, FRow, ColCount-1, FRow);
end
else
FRange:=Rect(FCol,FRow,FCol,FRow);
end;
procedure TCustomGrid.WriteColWidths(Writer: TWriter);
var
i: Integer;
begin
with writer do begin
WriteListBegin;
for i:=0 to ColCount-1 do
WriteInteger(ColWidths[i]);
WriteListEnd;
end;
end;
procedure TCustomGrid.WriteRowHeights(Writer: TWriter);
var
i: integer;
begin
with writer do begin
WriteListBegin;
for i:=0 to RowCount-1 do
WriteInteger(RowHeights[i]);
WriteListEnd;
end;
end;
procedure TCustomGrid.CheckFixedCount(aCol,aRow,aFCol,aFRow: Integer);
begin
if AFRow<0 then
Raise EGridException.Create('FixedRows<0');
if AFCol<0 then
Raise EGridException.Create('FixedCols<0');
if (aCol=0)And(aFCol=0) then // invalid grid, ok
else if (aFCol>=aCol) and not (csLoading in componentState) then
raise EGridException.Create(rsFixedColsTooBig);
if (aRow=0)and(aFRow=0) then // Invalid grid, ok
else if (aFRow>=aRow) and not (csLoading in ComponentState) then
raise EGridException.Create(rsFixedRowsTooBig);
end;
procedure TCustomGrid.CheckCount(aNewColCount, aNewRowCount: Integer);
var
NewCol,NewRow: Integer;
begin
if HandleAllocated then begin
if Col >= aNewColCount then NewCol := aNewColCount-1
else NewCol := Col;
if Row >= aNewRowCount then NewRow := aNewRowCount-1
else NewRow := Row;
if (NewCol>=0) and (NewRow>=0) and ((NewCol <> Col) or (NewRow <> Row)) then
begin
CheckTopleft(NewCol, NewRow , NewCol<>Col, NewRow<>Row);
MoveNextSelectable(false, NewCol, NewRow);
end;
end;
end;
function TCustomGrid.CheckTopLeft(aCol,aRow: Integer; CheckCols, CheckRows: boolean): boolean;
var
OldTopLeft: TPoint;
W: Integer;
begin
OldTopLeft := FTopLeft;
Result:= False;
with FTopleft do
if CheckCols and (X>FixedCols) then begin
W := FGCache.ScrollWidth-ColWidths[aCol]-Integer(FGCache.AccumWidth[aCol]);
while (x>FixedCols)and(W+Integer(FGCache.AccumWidth[x])>=ColWidths[x-1]) do
begin
Dec(x);
end;
end;
with FTopleft do
if CheckRows and (Y > FixedRows) then begin
W := FGCache.ScrollHeight-RowHeights[aRow]-Integer(FGCache.AccumHeight[aRow]);
while (y>FixedRows)and(W+Integer(FGCache.AccumHeight[y])>=RowHeights[y-1]) do
begin
Dec(y);
end;
end;
Result := Not PointIgual(OldTopleft,FTopLeft);
if Result then
doTopleftChange(False)
end;
procedure TCustomGrid.SetFlat(const AValue: Boolean);
begin
if FFlat=AValue then exit;
FFlat:=AValue;
Invalidate;
end;
procedure TCustomGrid.SetFocusRectVisible(const AValue: Boolean);
begin
if FFocusRectVisible<>AValue then begin
FFocusRectVisible := AValue;
Invalidate;
end;
end;
procedure TCustomGrid.SetBorderStyle(NewStyle: TBorderStyle);
begin
if BorderStyle<>NewStyle then
begin
inherited;
if HandleAllocated and ([csDestroying,csLoading]*ComponentState=[]) then
begin
VisualChange;
if CheckTopLeft(Col, Row, True, True) then
VisualChange;
end;
end;
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:=CellRect(VisibleGrid.Right, VisibleGrid.Bottom);
MaxClientXY:=R.BottomRight;
end;
end;
end;
function TCustomGrid.GetSelection: TGridRect;
begin
Result:=FRange;
end;
function TCustomGrid.GetSystemMetricsGapSize(const Index: Integer): Integer;
begin
{$ifdef Win32}
result := 0;
{$else}
result := 3;
{$endif}
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 and not(goEditing in Options);
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:=CellRect(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
OffTop,OffBottom: 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, OffTop{dummy});
if Fsplitter.Y>=0 then begin
ColRowToOffset(False, True, FSplitter.Y, OffTop, OffBottom);
FSplitter.X:=Y;
if (OffBottom-Y)<(Y-OffTop) then SwapInt(OffTop, OffBottom)
else Dec(FSplitter.y);
IF (Abs(OffTop-y)<=2)and(FSplitter.Y>=FFixedRows) then Cursor:=crVSplit
else Cursor:=crDefault;
Result:=True;
end;
end
else
if Cursor=crVSplit then Cursor:=crDefault;
end;
procedure TCustomGrid.doColMoving(X, Y: Integer);
var
P: TPoint;
R: TRect;
begin
//debugLn('DoColMoving: FDragDX=',IntToStr(FDragDX), ' Sp.x= ', IntTOStr(FSplitter.X), 'Sp.y= ', IntToStr(FSplitter.y));
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:=CellRect(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:=CellRect(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;
Offset := Offset - Integer(BorderStyle);
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;
// ex: IsCol=true, Index:=100, TopLeft.x:=98, FixedCols:=1, all ColWidths:=20
// Fisical = Relative => Ini := WidthfixedCols+WidthCol98+WidthCol99
// Not Fisical = Absolute => Ini := WidthCols(0..99)
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;
Ini := Ini + Integer(BorderStyle);
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;
Result:=true;
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;
if csDesigning in componentState then Exit;
{$IfDef dbgFocus} DebugLn('MouseDown INIT'); {$Endif}
Gz:=MouseToGridZone(X,Y, False);
case Gz of
gzFixedCols:
begin
if (goColSizing in Options)and(Cursor=crHSplit) then begin
R:=CellRect(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:=CellRect(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:
if Not (csDesigning in componentState) then begin
fGridState:=gsSelecting;
FSplitter:=MouseToCell(Point(X,Y));
if Not Focused then setFocus;
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;
end;
if not MoveExtend(False, FSplitter.X, FSplitter.Y) then begin
if EditorShouldEdit then begin
SelectEditor;
EditorShow;
end;
// user clicked on selected cell
// -> fire an OnSelection event
MoveSelection;
// Click();
end;
(*
if (GoEditing in Options)and(FEditor=nil) and not Focused then begin
{$IfDef dbgFocus} DebugLn(' AUTO-FOCUSING '); {$Endif}
LCLIntf.SetFocus(Self.Handle);
end;
*)
end;
end;
{$ifDef dbgFocus} DebugLn('MouseDown END'); {$Endif}
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
if not (goEditing in Options) then begin
P:=MouseToLogcell(Point(X,Y));
MoveExtend(False, P.x, P.y);
end;
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;
{$IfDef dbgFocus}DebugLn('MouseUP INIT');{$Endif}
Cur:=MouseToCell(Point(x,y));
case fGridState of
gsSelecting:
begin
if SelectActive then begin
MoveExtend(False, Cur.x, Cur.y);
SelectActive:=False;
end;
end;
gsColMoving:
begin
//DebugLn('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
//DebugLn('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;
gsColSizing:
begin
HeaderSized( True, FSplitter.X);
end;
gsRowSizing:
begin
HeaderSized( False, FSplitter.Y);
end;
end;
fGridState:=gsNormal;
{$IfDef dbgFocus}DebugLn('MouseUP END RND=',Random);{$Endif}
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
DebugLn('Got Doubleclick on Col Resizing: AutoAdjust?');}
end else
if (goDblClickAutoSize in Options) and
(goRowSizing in Options) and
(Cursor=crVSplit) then begin
{
DebugLn('Got DoubleClick on Row Resizing: AutoAdjust?');
}
end
else
Inherited DblClick;
end;
procedure TCustomGrid.DefineProperties(Filer: TFiler);
function SonIguales(L1,L2: TList): boolean;
var
i: Integer;
begin
Result:=False; // store by default
for i:=0 to L1.Count-1 do begin
Result:=L1[i]=L2[i];
if not Result then break;
end;
end;
function SonDefault(IsColumn: Boolean; L1: TList): boolean;
var
i: Integer;
begin
Result := True;
for i:=0 to L1.Count-1 do begin
if IsColumn then
Result := Integer(L1[i]) = DefaultColWidth
else
Result := Integer(L1[i]) = DefaultRowHeight;
if not Result then break;
end;
end;
function NeedWidths: boolean;
begin
if Filer.Ancestor <> nil then
Result := not SonIguales(TCustomGrid(Filer.Ancestor).FCols, FCols)
else
Result := not SonDefault(True, FCols);
end;
function NeedHeights: boolean;
begin
if Filer.Ancestor <> nil then
Result := not SonIguales(TCustomGrid(Filer.Ancestor).FRows, FRows)
else
Result := not SonDefault(false, FRows);
end;
begin
inherited DefineProperties(Filer);
with Filer do begin
DefineProperty('ColWidths', @ReadColWidths, @WriteColWidths, NeedWidths);
DefineProperty('RowHeights', @ReadRowHeights, @WriteRowHeights, NeedHeights);
end;
end;
procedure TCustomGrid.DestroyHandle;
begin
editorGetValue;
inherited DestroyHandle;
end;
procedure TCustomGrid.doExit;
begin
if FEditorShowing then begin
{$IfDef dbgFocus}DebugLn('DoExit - EditorShowing');{$Endif}
end else begin
{$IfDef dbgFocus}DebugLn('DoExit - Ext');{$Endif}
Invalidate;
end;
inherited DoExit;
end;
procedure TCustomGrid.DoEnter;
begin
inherited DoEnter;
if FEditorHiding then begin
{$IfDef dbgFocus}DebugLn('DoEnter - EditorHiding');{$Endif}
end else begin
{$IfDef dbgFocus}DebugLn('DoEnter - Ext');{$Endif}
if EditorShouldEdit then begin
SelectEditor;
if Feditor=nil then Invalidate
else EditorShow;
end else Invalidate;
end;
end;
procedure TCustomGrid.KeyDown(var Key: Word; Shift: TShiftState);
var
Sh: Boolean;
procedure MoveSel(Rel: Boolean; aCol,aRow: Integer);
begin
// Always reset Offset in kerboard Events
FGCache.TLColOff:=0;
FGCache.TLRowOff:=0;
SelectActive:=Sh;
MoveNextSelectable(Rel, aCol, aRow);
Key:=0;
end;
var
R: TRect;
Relaxed: Boolean;
//PF: TCustomForm;
begin
inherited KeyDown(Key, Shift);
if not FGCache.ValidGrid then Exit;
Sh:=(ssShift in Shift);
Relaxed:=not (goRowSelect in Options) or (goRelaxedRowSelect in Options);
if (Key=Vk_TAB) then begin
if (goTabs in Options) then begin
case FAutoAdvance of
aaRight:
if Sh then Key:=VK_LEFT
else Key:=VK_RIGHT;
aaDown:
if Sh then Key:=VK_UP
else Key:=VK_DOWN;
aaLeft:
if sh then Key:=VK_RIGHT
else Key:=VK_LEFT;
end;
end else begin
// TODO
(*
Pf:=GetParentForm(Self);
if (Pf<>nil) then Pf.FocusControl(Self);
PerformTab;
*)
end;
end;
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, VK_RETURN:
begin
EditorShow;
if Key=VK_RETURN then EditorSelectAll;
Key:=0;
end;
VK_BACK:
begin
// Workaround: LM_CHAR doesnt trigger with BACKSPACE
EditorShowChar(^H);
key:=0;
end;
{$IfDef Dbg}
else DebugLn(ClassName,'.KeyDown: ', Key);
{$Endif}
end;
end;
procedure TCustomGrid.KeyUp(var Key: Word; Shift: TShiftState);
begin
inherited KeyUp(Key, Shift);
end;
{ Convert a fisical Mouse coordinate into fisical a cell coordinate }
function TCustomGrid.MouseToCell(Mouse: TPoint): TPoint;
var
d: Integer;
begin
Result.X:= OffsetToColRow(True, True, Mouse.x, d);
Result.Y:= OffsetToColRow(False,True, Mouse.y, d);
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);
Result:=MouseToCell(Mouse);
//if gz=gzNormal then Result:=MouseToCell(Mouse)
//else begin
if gz<>gzNormal then 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} DebugLn('InvalidateCol Col=',aCol); {$Endif}
R:=CellRect(aCol, FTopLeft.y);
R.Top:=0; // Full Column
R.Bottom:=FGCache.MaxClientXY.Y;
InvalidateRect(Handle, @R, True);
end;
procedure TCustomGrid.InvalidateRow(ARow: Integer);
var
R: TRect;
begin
{$ifdef dbg} DebugLn('InvalidateRow Row=',aRow); {$Endif}
R:=CellRect(fTopLeft.x, aRow);
R.Left:=0; // Full row
R.Right:=FGCache.MaxClientXY.X;
InvalidateRect(Handle, @R, True);
end;
function TCustomGrid.MoveExtend(Relative: Boolean; DCol, DRow: Integer): Boolean;
var
InvalidateAll: Boolean;
LastEditor: TWinControl;
WasVis: Boolean;
begin
Result:=TryMoveSelection(Relative,DCol,DRow);
if (not Result) then Exit;
BeforeMoveSelection(DCol,DRow);
{$IfDef dbgFocus}DebugLn(' MoveExtend INIT FCol= ',FCol, ' FRow= ',FRow);{$Endif}
LastEditor:=Editor;
WasVis:=(LastEditor<>nil)and(LastEditor.Visible);
InvalidateAll:=False;
// default range
if goRowSelect in Options then FRange:=Rect(FFixedCols, DRow, Colcount-1, DRow)
else begin
// Just after selectActive=false and Selection Area is more than one cell
InvalidateAll := Not SelectActive And (
(FRange.Right-FRange.Left > 0) or
(Frange.Bottom-FRange.Top > 0) );
FRange:=Rect(DCol,DRow,DCol,DRow);
end;
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
if goRowSelect in Options then begin
InvalidateRow(FRow);
InvalidateRow(DRow);
end else begin
InvalidateCell(FCol, FRow);
InvalidateCell(DCol, DRow);
end;
end;
SwapInt(DCol,FCol);
SwapInt(DRow,FRow);
MoveSelection;
SelectEditor;
ProcessEditor(LastEditor,DCol,DRow,WasVis);
{$IfDef dbgFocus}DebugLn(' MoveExtend FIN FCol= ',FCol, ' FRow= ',FRow);{$Endif}
end;
function TCustomGrid.MoveNextSelectable(Relative: Boolean; DCol, DRow: Integer
): Boolean;
var
CInc,RInc: Integer;
NCol,NRow: Integer;
SelOk: Boolean;
begin
// Reference
if not Relative then begin
NCol:=DCol;
NRow:=DRow;
DCol:=NCol-FCol;
DRow:=NRow-FRow;
end else begin
NCol:=FCol + DCol;
NRow:=FRow + DRow;
end;
Checklimits(NCol, NRow);
// Increment
if DCol<0 then CInc:=-1 else
if DCol>0 then CInc:= 1
else CInc:= 0;
if DRow<0 then RInc:=-1 else
if DRow>0 then RInc:= 1
else RInc:= 0;
// Calculation
SelOk:=SelectCell(NCol,NRow);
Result:=False;
while not SelOk do begin
if (NRow>RowCount-1)or(NRow<FFixedRows) or
(NCol>ColCount-1)or(NCol<FFixedCols) then Exit;
Inc(NCol, CInc);
Inc(NRow, RInc);
SelOk:=SelectCell(NCol, NRow);
end;
Result:=MoveExtend(False, NCol, NRow);
end;
function TCustomGrid.TryMoveSelection(Relative: Boolean; var DCol, DRow: Integer
): Boolean;
begin
Result:=False;
dCol:=FCol*(1-Byte(not Relative))+DCol;
dRow:=FRow*(1-Byte(not Relative))+DRow;
CheckLimits( dCol, dRow );
// Change on Focused cell?
if (Dcol=FCol)and(DRow=FRow) then begin
end else begin
Result:=SelectCell(DCol,DRow);
end;
end;
procedure TCustomGrid.ProcessEditor(LastEditor: TWinControl; DCol, DRow: Integer; WasVis: Boolean);
procedure RestoreEditor;
begin
SwapInt(Integer(FEditor),Integer(LastEditor));
SwapInt(FCol,DCol);
SwapInt(FRow,DRow);
end;
procedure HideLastEditor;
begin
RestoreEditor;
EditorGetValue;
RestoreEditor;
end;
var
WillVis: Boolean;
begin
WillVis:=(FEditor<>nil)and EditorShouldEdit;
if WillVis or WasVis then begin
if not WillVis then HideLastEditor else
if not WasVis then EditorShow
else begin
{
LastEditor.Visible:=False;
lastEditor.Parent:=nil;
FEditorMode:=False;
EditorShow;
}
HideLastEditor;
EditorShow;
{
if LastEditor=FEditor then begin
// only to swap DCol<->FCol and DRow<->FRow
// Hide editor in old position
RestoreEditor;
EditordoGetValue;
RestoreEditor;
// Move Editor to new position and set its value
EditorPos;
EditordoSetValue;
end else begin
// Hide old editor type a
LastEditor.Visible:=False;
lastEditor.Parent:=nil;
// Show new editor type b
EditorShow;
end;
}
end;
end;
end;
procedure TCustomGrid.BeforeMoveSelection(const DCol,DRow: Integer);
begin
if Assigned(OnBeforeSelection) then OnBeforeSelection(Self, DCol, DRow);
end;
procedure TCustomGrid.CheckLimits(var aCol, aRow: Integer);
begin
if aCol<FFixedCols then aCol:=FFixedCols else
if aCol>ColCount-1 then acol:=ColCount-1;
if aRow<FFixedRows then aRow:=FFixedRows else
if aRow>RowCount-1 then aRow:=RowCount-1;
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
if FullUpdate then
EndUpdate(uoFull)
else
EndUpdate(uoQuick);
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);
begin
InvalidateCell(ACol,ARow, False);
end;
procedure TCustomGrid.InvalidateCell(aCol, aRow: Integer; Redraw: Boolean);
var
R: TRect;
begin
{$IfDef dbgPaint}
DebugLn('InvalidateCell Col=',aCol, ' Row=',aRow,' Redraw=',Redraw);
{$Endif}
R:=CellRect(aCol, aRow);
InvalidateRect(Handle, @R, Redraw);
end;
procedure TCustomGrid.InvalidateGrid;
begin
if FUpdateCount=0 then Invalidate;
end;
procedure TCustomGrid.Invalidate;
begin
if FUpdateCount=0 then
inherited Invalidate;
end;
procedure TCustomGrid.EditorGetValue;
begin
if not (csDesigning in ComponentState) then begin
EditordoGetValue;
EditorHide;
end;
end;
procedure TCustomGrid.EditorSetValue;
begin
if not (csDesigning in ComponentState) then begin
EditordoSetValue;
EditorPos;
end;
end;
procedure TCustomGrid.EditorHide;
begin
if not FEditorHiding and (Editor<>nil) and Editor.HandleAllocated and Editor.Visible then
begin
FEditorMode:=False;
{$IfDef dbgFocus} DebugLn('EditorHide INIT FCol=',FCol,' FRow=',FRow);{$Endif}
FEditorHiding:=True;
Editor.Visible:=False;
Editor.Parent:=nil;
LCLIntf.SetFocus(Self.Handle);
FEDitorHiding:=False;
{$IfDef dbgFocus} DebugLn('EditorHide FIN'); {$Endif}
end;
end;
procedure TCustomGrid.EditorShow;
begin
if csDesigning in ComponentState then exit;
if not HandleAllocated then
Exit;
if (goEditing in Options) and
not FEditorShowing and (Editor<>nil) and not Editor.Visible then
begin
{$IfDef dbgFocus} DebugLn('EditorShow INIT FCol=',FCol,' FRow=',FRow);{$Endif}
FEditorMode:=True;
FEditorShowing:=True;
ScrollToCell(FCol,FRow);
EditorSetValue;
Editor.Parent:=Self;
Editor.Visible:=True;
LCLIntf.SetFocus(Editor.Handle);
InvalidateCell(FCol,FRow,True);
FEditorShowing:=False;
{$IfDef dbgFocus} DebugLn('EditorShow FIN');{$Endif}
end;
end;
procedure TCustomGrid.EditorPos;
var
msg: TGridMessage;
begin
if FEditor<>nil then begin
Msg.CellRect:=CellRect(FCol,FRow);
if FEditorOptions and EO_AUTOSIZE = EO_AUTOSIZE then begin
with Msg.CellRect do begin
Right:=Right-Left;
Bottom:=Bottom-Top;
FEditor.SetBounds(Left, Top, Right, Bottom);
end;
end else begin
Msg.MsgID:=GM_SETPOS;
Msg.Grid:=Self;
Msg.Col:=FCol;
Msg.Row:=FRow;
FEditor.Dispatch(Msg);
end;
end;
end;
procedure TCustomGrid.EditorSelectAll;
var
Msg: TGridMessage;
begin
if FEditor<>nil then
if FEditorOptions and EO_SELECTALL = EO_SELECTALL then begin
Msg.MsgID:=GM_SELECTALL;
FEditor.Dispatch(Msg);
end;
end;
procedure TCustomGrid.EditordoGetValue;
begin
//
end;
procedure TCustomGrid.EditordoSetValue;
begin
//
end;
procedure TCustomGrid.EditorExit(Sender: TObject);
begin
if not FEditorHiding then begin
{$IfDef dbgFocus} DebugLn('EditorExit INIT');{$Endif}
FEditorHiding:=True;
EditorGetValue;
if Editor<>nil then begin
Editor.Visible:=False;
Editor.Parent:=nil;
//InvalidateCell(FCol,FRow, True);
end;
FEditorHiding:=False;
{$IfDef dbgFocus} DebugLn('EditorExit FIN'); {$Endif}
end;
end;
procedure TCustomGrid.EditorKeyDown(Sender: TObject; 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
KeyDown(Key, Shift);
//DebugLn('Editor KeyTab Pressed, Focus Should leave the grid');
Exit;
end;
Key:=0;
case FAutoAdvance of
aaRight: Key:=VK_RIGHT * Integer( FCol<ColCount-1 );
aaDown : Key:=VK_DOWN * Integer( FRow<RowCount-1 );
aaLeft : Key:=VK_LEFT * Integer( FCol>FixedCols );
end;
if Key=0 then begin
EditorGetValue;
EditorShow;
// Select All !
end else
KeyDown(Key, Shift);
end;
end;
FEditorKey:=False;
end;
procedure TCustomGrid.SelectEditor;
var
aEditor: TWinControl;
begin
aEditor:= Editor;
if (goEditing in Options) and Assigned(OnSelectEditor) then
OnSelectEditor(Self, fCol,FRow, aEditor);
if aEditor<>Editor then Editor:=aEditor;
end;
function TCustomGrid.EditorShouldEdit: Boolean;
begin
Result:=(goEditing in Options)and(goAlwaysShowEditor in Options);
end;
procedure TCustomGrid.EditorShowChar(Ch: Char);
var
msg: TGridMessage;
begin
SelectEditor;
if FEditor<>nil then begin
EditorShow;
EditorSelectAll;
//DebugLn('Posting editor LM_CHAR, ch=',ch, ' ', InttoStr(Ord(ch)));
{$ifdef WIN32}
PostMessage(FEditor.Handle, LM_CHAR, Word(Ch), 0);
{$else}
///
// Note. this is a workaround because the call above doesn't work
///
Msg.MsgID:=GM_SETVALUE;
Msg.Grid:=Self;
Msg.Col:=FCol;
Msg.Row:=FRow;
if Ch=^H then Msg.Value:=''
else Msg.Value:=ch;
FEditor.Dispatch(Msg);
{$endif}
end;
end;
procedure TCustomGrid.EditorSetMode(const AValue: Boolean);
begin
if not AValue then begin
EditorHide;
//SetFocus;
end else
begin
EditorShow;
end;
end;
function TCustomGrid.GetSelectedColor: TColor;
begin
Result:=FSelectedColor;
end;
function TCustomGrid.GetEditMask(ACol, ARow: Longint): string;
begin
result:='';
end;
function TCustomGrid.GetEditText(ACol, ARow: Longint): string;
begin
result:='';
end;
procedure TCustomGrid.SetEditText(ACol, ARow: Longint; const Value: string);
begin
end;
procedure TCustomGrid.SetSelectedColor(const AValue: TColor);
begin
if FSelectedColor<>AValue then begin
FSelectedColor:=AValue;
Invalidate;
end;
end;
procedure TCustomGrid.SetFixedcolor(const AValue: TColor);
begin
if FFixedColor<>AValue then begin
FFixedColor:=Avalue;
Invalidate;
end;
end;
function TCustomGrid.GetFixedcolor: TColor;
begin
result:=FFixedColor;
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; Version: Integer);
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 Version>=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;
procedure TCustomGrid.Loaded;
begin
inherited Loaded;
VisualChange;
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;
FGSMHBar := GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetricsGapSize(SM_CYHSCROLL);
FGSMVBar := GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetricsGapSize(SM_CXVSCROLL);
//DebugLn('FGSMHBar= ', FGSMHBar, ' FGSMVBar= ', FGSMVBar);
inherited Create(AOwner);
FFocusRectVisible := True;
FDefaultDrawing := True;
FOptions:=
[goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect,
goSmoothScroll ];
FScrollbars:=ssAutoBoth;
fGridState:=gsNormal;
fDefColWidth:=64;//40;
fDefRowHeight:=24;//18;
fGridLineColor:=clGray;
FGridLineStyle:=psSolid;
fFocusColor:=clRed;
FFixedColor:=clBtnFace;
FSelectedColor:= clBlack;
FRange:=Rect(-1,-1,-1,-1);
FDragDx:=3;
SetBounds(0,0,200,100);
ColCount:=5;
RowCount:=5;
FixedCols:=1;
FixedRows:=1;
Editor:=nil;
BorderStyle := bsSingle;
Color:=clWhite;
FDefaultTextStyle := Canvas.TextStyle;
end;
destructor TCustomGrid.Destroy;
begin
{$Ifdef dbg}DebugLn('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(rsGridFileDoesNotExists);
Cfg:=TXMLConfig.Create(FileName);
Try
Version:=cfg.GetValue('grid/version',-1);
if Version=-1 then raise Exception.Create(rsNotAValidGridFile);
BeginUpdate;
LoadContent(Cfg, Version);
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);
FRange:=Rect(-1,-1,-1,-1);
FGCache.TLColOff := 0;
FGCache.TlRowOff := 0;
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;
if (Col<0) or (Row<0) or (Col>=ColCount) or (Row>=RowCount) then
raise EGridException.CreateFmt(rsIndexOutOfRange, [Col, Row]);
Result:=FCells[Col,Row];
end;
function Tvirtualgrid.Getrows(Row: Integer): PColRowprops;
begin
Result:= FRows[Row, 0];
end;
function Tvirtualgrid.Getcols(Col: Integer): PColRowProps;
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: PColRowProps);
var
C: PColRowProps;
begin
// todo: Check range
C:=FRows[Row,0];
if C<>nil then DisposeColRow(C);
FRows[Row,0]:=AValue;
end;
procedure Tvirtualgrid.Setcolcount(const Avalue: Integer);
begin
if FColCount=Avalue then Exit;
{$Ifdef dbgMem}
DebugLn('TVirtualGrid.SetColCount Value=',AValue);
{$Endif}
FColCount:=AValue;
{$Ifdef dbgMem}
DBGOut('TVirtualGrid.SetColCount->FCOLS: ');
{$Endif}
FCols.SetLength(FColCount, 1);
{$Ifdef dbgMem}
DBGOut('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}
DebugLn('TVirtualGrid.SetRowCount Value=',AValue);
{$Endif}
FRowCount:=AValue;
{$Ifdef dbgMem}
DBGOut('TVirtualGrid.SetRowCount->FROWS: ');
{$Endif}
FRows.SetLength(FRowCount,1);
{$Ifdef dbgMem}
DBGOut('TVirtualGrid.SetRowCount->FCELLS(',FColCount,',',FRowCount,'): ');
{$Endif}
FCells.SetLength(FColCount, FRowCount);
end;
procedure Tvirtualgrid.Setcols(Col: Integer; const Avalue: PColRowProps);
var
C: PColRowProps;
begin
// todo: Check range
C:=FCols[Col,0];
if C<>nil then DisposeColRow(C);
FCols[Col,0]:=AValue;
end;
procedure Tvirtualgrid.Clear;
begin
{$Ifdef dbgMem}DBGOut('FROWS: ');{$Endif}FRows.Clear;
{$Ifdef dbgMem}DBGOut('FCOLS: ');{$Endif}FCols.Clear;
{$Ifdef dbgMem}DBGOut('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 StrDispose(P^.Text);
Dispose(P);
P:=nil;
end;
end;
procedure TVirtualGrid.DisposeColRow(var p: PColRowProps);
begin
if P<>nil then begin
Dispose(P);
P:=nil;
end;
end;
function TVirtualGrid.GetDefaultCell: PcellProps;
begin
New(Result);
Result^.Text:=nil;
Result^.Attr:=nil;
end;
function TVirtualGrid.GetDefaultColRow: PColRowProps;
begin
New(Result);
Result^.FixedAttr:=nil;
Result^.NormalAttr:=nil;
Result^.Size:=-1;
end;
procedure Tvirtualgrid.Dodestroyitem (Sender: Tobject; Col,Row: Integer;
var Item: Pointer);
begin
{$Ifdef dbgMem}
DebugLn('TVirtualGrid.doDestroyItem Col=',Col,' Row= ',
Row,' Item=',Integer(Item));
{$endif}
if Item<>nil then begin
if (Sender=FCols)or(Sender=FRows) then begin
DisposeColRow(PColRowProps(Item));
end else begin
DisposeCell(PCellProps(Item));
end;
Item:=nil;
end;
end;
procedure Tvirtualgrid.doNewitem(Sender: Tobject; Col,Row:Integer;
var Item: Pointer);
begin
{$Ifdef dbgMem}
DebugLn('TVirtualGrid.doNewItem Col=',Col,' Row= ',
Row,' Item=',Integer(Item));
{$endif}
if Sender=FCols then begin
// Procesar Nueva Columna
Item:=GetDefaultColRow;
end else
if Sender=FRows then begin
// Procesar Nuevo Renglon
Item:=GetDefaultColRow;
end else begin
// Procesar Nueva Celda
Item:=nil;
end;
end;
constructor TVirtualGrid.Create;
begin
Inherited Create;
{$Ifdef dbg}DebugLn('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}DebugLn('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;
{
procedure TStringCellEditor.WndProc(var TheMessage: TLMessage);
begin
DbgOut(Name+'.WndProc msg= ');
case TheMessage.Msg of
LM_SHOWWINDOW: DebugLn('LM_SHOWWINDOW');
LM_SETFOCUS: DebugLn('LM_SETFOCUS');
LM_PAINT: DebugLn('LM_PAINT');
LM_KEYUP: DebugLn('LM_KEYUP');
LM_WINDOWPOSCHANGED: DebugLn('LM_WINDOWPOSCHANGED');
LM_MOVE: DebugLn('LM_MOVE');
LM_KILLFOCUS: DebugLn('LM_KILLFOCUS');
CM_BASE..CM_MOUSEWHEEL:
begin
case TheMessage.Msg of
CM_MOUSEENTER: DebugLn('CM_MOUSEENTER');
CM_MOUSELEAVE: DebugLn('CM_MOUSELEAVE');
CM_VISIBLECHANGED: DebugLn('CM_VISIBLECHANGED');
CM_TEXTCHANGED: DebugLn('CM_TEXTCHANGED');
CM_SHOWINGCHANGED: DebugLn('CM_SHOWINGCHANGED');
else DebugLn('CM_BASE + ',TheMessage.Msg-CM_BASE);
end
end;
CN_BASE..CN_NOTIFY:
begin
DebugLn('CN_BASE + ',TheMessage.Msg-CN_BASE);
end;
else
DebugLn(TheMessage.Msg,' (',IntToHex(TheMessage.Msg, 4),')');
end;
inherited WndProc(TheMessage);
end;
}
{ TStringCellEditor }
procedure TStringCellEditor.Change;
begin
inherited Change;
if FGrid<>nil then FGrid.SetEditText(FGrid.Col, FGrid.Row, Text);
end;
procedure TStringCellEditor.KeyDown(var Key: Word; Shift: TShiftState);
procedure doInherited;
begin
inherited keyDown(key, shift);
key:=0;
end;
function AtStart: Boolean;
begin
Result:= (SelStart=0);
end;
function AtEnd: Boolean;
begin
Result:= (SelStart+1)>Length(Text);
end;
begin
{$IfDef dbg}
DebugLn('INI: Key=',Key,' SelStart=',SelStart,' SelLenght=',SelLength);
{$Endif}
{
case Key of
VK_LEFT: if AtStart then doInherited;
VK_RIGHT: if AtEnd then doInherited;
end;
}
if FGrid<>nil then begin
Fgrid.EditorKeyDown(Self, Key, Shift);
end;
inherited keyDown(key, shift);
{$IfDef dbg}
DebugLn('FIN: Key=',Key,' SelStart=',SelStart,' SelLenght=',SelLength);
{$Endif}
end;
procedure TStringCellEditor.msg_SetMask(var Msg: TGridMessage);
begin
EditMask:=msg.Value;
end;
procedure TStringCellEditor.msg_SetValue(var Msg: TGridMessage);
begin
Text:=Msg.Value;
end;
procedure TStringCellEditor.msg_GetValue(var Msg: TGridMessage);
begin
Msg.Value:=Text;
end;
procedure TStringCellEditor.msg_SetGrid(var Msg: TGridMessage);
begin
FGrid:=Msg.Grid;
Msg.Options:=EO_AUTOSIZE or EO_HOOKEXIT or EO_SELECTALL;
end;
procedure TStringCellEditor.msg_SelectAll(var Msg: TGridMessage);
begin
SelectAll;
end;
{ TDrawGrid }
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) and not(CsDesigning in ComponentState) then begin
PrepareCanvas(aCol, aRow, aState);
if DefaultDrawing then
Canvas.FillRect(aRect);
OnDrawCell(Self,aCol,aRow,aRect,aState)
end else
DefaultDrawCell(aCol,aRow,aRect,aState);
inherited DrawCellGrid(aCol,aRow,aRect,aState);
end;
procedure TDrawGrid.DrawFocusRect(aCol, aRow: Integer; ARect: TRect);
begin
// Draw focused cell if we have the focus
if Self.Focused Or (EditorShouldEdit and ((Feditor=nil) or not Feditor.Focused)) then
begin
Canvas.Pen.Color:=FFocusColor;
Canvas.Pen.Style:=psDot;
if goRowSelect in Options then begin
Canvas.MoveTo(FGCache.FixedWidth+1, aRect.Top);
Canvas.LineTo(FGCache.MaxClientXY.x-2, aRect.Top);
Canvas.LineTo(FGCache.MaxClientXY.x-2, aRect.Bottom-2);
Canvas.LineTo(FGCache.FixedWidth+1, aRect.Bottom-2);
Canvas.LineTo(FGCache.FixedWidth+1, aRect.Top+1);
end else begin
Canvas.MoveTo(aRect.Left, aRect.Top);
Canvas.LineTo(ARect.Right-2,aRect.Top);
Canvas.LineTo(aRect.Right-2,aRect.bottom-2);
Canvas.LineTo(aRect.Left, aRect.Bottom-2);
Canvas.Lineto(aRect.left, aRect.top+1);
end;
Canvas.Pen.Style:=psSolid;
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.HeaderSized(IsColumn: Boolean; index: Integer);
begin
inherited HeaderSized(IsColumn, index);
If Assigned(OnHeaderSized) then OnHeaderSized(Self, IsColumn, index);
end;
function TDrawGrid.GetEditMask(aCol, aRow: Longint): string;
begin
result:='';
if assigned(OnGetEditMask) then OnGetEditMask(self, aCol, aRow, Result);
end;
function TDrawGrid.GetEditText(aCol, aRow: Longint): string;
begin
result:='';
if assigned(OnGetEditText) then OnGetEditText(self, aCol, aRow, Result);
end;
procedure TDrawGrid.SetEditText(ACol, ARow: Longint; const Value: string);
begin
if Assigned(OnSetEditText) then OnSetEditText(Self, aCol, aRow, Value);
end;
procedure TDrawGrid.SizeChanged(OldColCount, OldRowCount: Integer);
begin
if OldColCount<>ColCount then fGrid.ColCount:=ColCOunt;
if OldRowCount<>RowCount then fGrid.RowCount:=RowCount;
end;
function TDrawGrid.SelectCell(aCol, aRow: Integer): boolean;
begin
Result:= (ColWidths[aCol] > 0) and (RowHeights[aRow] > 0);
if Assigned(OnSelectCell) then OnSelectCell(Self, aCol, aRow, Result);
end;
procedure TDrawGrid.SetColor(Value: TColor);
begin
inherited SetColor(Value);
Invalidate;
end;
function TDrawGrid.CreateVirtualGrid: TVirtualGrid;
begin
Result:=TVirtualGrid.Create;
end;
constructor TDrawGrid.Create(AOwner: TComponent);
begin
fGrid:=CreateVirtualGrid; //TVirtualGrid.Create;
inherited Create(AOwner);
end;
destructor TDrawGrid.Destroy;
begin
{$Ifdef dbg}DebugLn('TDrawGrid.Destroy');{$Endif}
//DebugLn('Font.Name',Font.Name);
FreeThenNil(FGrid);
inherited Destroy;
end;
procedure TDrawGrid.DefaultDrawCell(aCol, aRow: Integer; var aRect: TRect;
aState: TGridDrawState);
var
OldDefaultDrawing: boolean;
begin
OldDefaultDrawing:=FDefaultDrawing;
FDefaultDrawing:=True;
try
PrepareCanvas(aCol, aRow, aState);
finally
FDefaultDrawing:=OldDefaultDrawing;
end;
if goColSpanning in Options then CalcCellExtent(acol, arow, aRect);
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: 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
Result.AddObject(Cells[Index, i], Objects[Index, i]);
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: 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
Result.AddObject(Cells[i, Index], Objects[i, Index]);
end;
end;
procedure TStringGrid.ReadCells(Reader: TReader);
var
aCol,aRow: Integer;
i, c: Integer;
begin
with Reader do begin
ReadListBegin;
c := ReadInteger;
for i:=1 to c do begin
aCol := ReadInteger;
aRow := ReadInteger;
Cells[aCol,aRow]:= ReadString;
end;
{
repeat
aCol := ReadInteger;
aRow := ReadInteger;
Cells[aCol,aRow] := ReadString;
until NextValue = vaNull;
}
ReadListEnd;
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;
C^.Data:=nil;
FGrid.Celda[aCol,aRow]:=C;
InvalidateCell(aCol, aRow);
end;
end;
end;
procedure TStringGrid.SetCols(index: Integer; const AValue: TStrings);
var
i: Integer;
begin
if Avalue=nil then exit;
for i:=0 to AValue.Count-1 do begin
Cells[index, i]:= AValue[i];
Objects[Index, i]:= AValue.Objects[i];
end;
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);
var
i: Integer;
begin
if Avalue=nil then exit;
for i:=0 to AValue.Count-1 do begin
Cells[i, index]:= AValue[i];
Objects[i, Index]:= AValue.Objects[i];
end;
end;
procedure TStringGrid.WriteCells(Writer: TWriter);
var
i,j: Integer;
c: Integer;
begin
with writer do begin
WriteListBegin;
//cell count
c:=0;
for i:=0 to ColCount-1 do
for j:=0 to RowCount-1 do
if Cells[i,j]<>'' then Inc(c);
WriteInteger(c);
for i:=0 to ColCount-1 do
for j:=0 to RowCount-1 do
if Cells[i,j]<>'' then begin
WriteInteger(i);
WriteInteger(j);
WriteString(Cells[i,j]);
end;
WriteListEnd;
end;
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 Canvas.TextStyle.Clipping then begin
//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;
Canvas.TextStyle.clipping:=i<>aCol;
end;
end;
procedure TStringGrid.DefineProperties(Filer: TFiler);
function NeedCells: boolean;
var
i,j: integer;
AntGrid: TStringGrid;
begin
AntGrid := TStringGrid(Filer.Ancestor);
//DebugLn('TStringGrid.DefineProperties: Ancestor=',Integer(AntGrid));
if AntGrid<>nil then begin
result:=false;
for i:=0 to AntGrid.ColCount-1 do
for j:=0 to AntGrid.RowCount-1 do
if Cells[i,j]<>AntGrid.Cells[i,j] then begin
result:=true;
break;
end;
end else
result:=true;
end;
begin
inherited DefineProperties(Filer);
with Filer do begin
DefineProperty('Cells', @ReadCells, @WriteCells, NeedCells);
end;
end;
procedure TStringGrid.DrawCell(aCol, aRow: Integer; aRect: TRect;
aState: TGridDrawState);
//var
// ts: TTextStyle;
begin
inherited DrawCell(aCol, aRow, aRect, aState);
if DefaultDrawing then begin
Canvas.TextRect(aRect, 3, 0, Cells[aCol,aRow]);
//MyTExtRect(aRect, 3, 0, Cells[aCol,aRow], Canvas.Textstyle.Clipping);
end;
end;
procedure TStringGrid.EditordoGetValue;
var
msg: TGridMessage;
begin
if (FEditor<>nil) and FEditor.Visible then begin
Msg.MsgID:=GM_GETVALUE;
Msg.grid:=Self;
Msg.Col:=FCol;
Msg.Row:=FRow;
Msg.Value:=Cells[FCol,FRow]; // default value
FEditor.Dispatch(Msg);
SetEditText(FCol, FRow, msg.Value);
//Cells[FCol,FRow]:=msg.Value;
end;
end;
procedure TStringGrid.EditordoSetValue;
var
msg: TGridMessage;
begin
if FEditor<>nil then begin
// Set the editor mask
Msg.MsgID:=GM_SETMASK;
Msg.Grid:=Self;
Msg.Col:=FCol;
Msg.Row:=FRow;
Msg.Value:=GetEditMask(FCol, FRow);
FEditor.Dispatch(Msg);
// Set the editor value
Msg.MsgID:=GM_SETVALUE;
Msg.Grid:=Self;
Msg.Col:=FCol;
Msg.Row:=FRow;
Msg.Value:=GetEditText(Fcol, FRow); //Cells[FCol,FRow];
FEditor.Dispatch(Msg);
end;
end;
function TStringGrid.GetEditText(aCol, aRow: Integer): string;
begin
Result:=Cells[aCol, aRow];
if Assigned(OnGetEditText) then OnGetEditText(Self, aCol, aRow, result);
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; Version:Integer);
var
ContentSaved: Boolean;
i,j,k: Integer;
begin
inherited LoadContent(Cfg, Version);
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, CellRect(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, CellRect(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, CellRect(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, CellRect(i,j), gds);
end;
end else inherited DrawInteriorCells;
end;
*)
procedure TStringGrid.SelectEditor;
begin
if goEditing in Options then Editor:=fDefEditor;
inherited SelectEditor;
end;
procedure TStringGrid.SetEditText(aCol, aRow: Longint; const aValue: string);
begin
if Cells[aCol, aRow]<>aValue Then Cells[aCol, aRow]:= aValue;
inherited SetEditText(aCol, aRow, aValue);
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.Text:='';
FDefEditor.Visible:=False;
FDefEditor.Align:=alNone;
end else begin
FDefEditor:=nil;
end;
with DefaultTextStyle do begin
Alignment := taLeftJustify;
Layout := tlCenter;
Clipping := True;
//WordBreak := False
end;
end;
destructor TStringGrid.Destroy;
begin
{$Ifdef dbg}DebugLn('TStringGrid.Destroy');{$Endif}
if FdefEditor<>nil then begin
FDefEDitor.Parent:=nil;
FreeThenNil(FDefEditor);
end;
inherited Destroy;
end;
procedure TStringGrid.AutoSizeColumns;
var
i: Integer;
begin
for i:=0 to ColCount-1 do
AutoAdjustColumn(i)
end;
procedure Register;
begin
RegisterComponents('Additional',[TStringGrid,TDrawGrid]);
end;
end.
{ The_Log
VERSION: 0.8.6:
----------------
Date: 20-Dic-2003
- Added GetEditText, GetEditMask, SetEditText and events OnGetEditText, OnGetEditMask, OnSetEditText
- Added ColWidths and RowHeights lfm storing
- Changed Default CellEditor from TCustomEdit to TCustomMaskEdit
- Added Test StringGridEditor (enabled with -dWithGridEditor)
VERSION: 0.8.5:
----------------
Date: 15-Sept-2003
- TCustomGrid is derived from TCustomControl instead of TScrollingWinControl
means that:
* No more transparent grid at design time
* No more HorzScrolLBar and VertScrollbar in Object inspector
* HorzScrollbar and VertScrollbar doesn't exists anymore
* Scrollbar is handled with setscrollinfo or through the new ScrollbarXXXX
protected methods.
- TDrawGrid attribute support was removed and added to a new TStringGrid derivated
component.
- Removed CanSelect, OnCanSelect, TOnCanSelectEvent now it uses SelectCell
OnSelectCell and TOnSelectCell.
- Implemented Auto edit mode (Typing something will show editor)
- Implemented EditorMode
VERSION: 0.8.4:
---------------
Date: 21-JAN-2003
- Moved log to the end of file
- Editor should be set in OnSelectEditor or SelectEditor in descendants.
- Added SkipUnselectable, this allow the seleccion [using UP,DOWN,LEFT,TOP,
TABS (if goTabs)] select the next selectable cell.
- Fixed goAlwaysShowEditor
- Fixed bug (gtk-CRITICAL) when destroying the grid and the editor is visible
- Fixed bug selecting a partial visible cell while the grid is scrolled
- missing: tabb from the grid, and Shift-Tab in goTabs mode.
VERSION: 0.8.3
---------------
CHANGES - Better Editor Support
Renamed Editor functions
Editors uses .Dispatch instead of .Perform
Introduced EditorOptions:
EO_AUTOSIZE = Let the grid automatically resize the editor
EO_HOOKKEYS = Let the grid process known keydows first
EO_HOOKEXIT = Let the grid handle the focus
EO_SELECTALL = Editor wants to receive SelectAll msg on Key RETURN
EO_WANTCHAR = Editor wants to Preview Keys on the grid (soon)
EO_GETSETVAL = Editor wants to receive GetValue,SetValue msgs (soon)
This Options should be set in GM_SETGRID message (msg.Options:= ..)
- Deleted Scr1 Conditional
FIXES Painting and Crashes at desing time
TODOS Better editor Support
TCustomgrid Inherited from TCustomControl to get rid of
- published VertScrollBar
- published HorzScrollBar
- published AutoScroll
- translucid look at design time?
Detect ReadOnly grid in editors
Detect changes in the grid.
Column Resizing at design time
...
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.
}