
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1732 8e941d3f-bd1b-0410-a28a-d453659cc2b4
12828 lines
466 KiB
ObjectPascal
Executable File
12828 lines
466 KiB
ObjectPascal
Executable File
{ @abstract(This unit contains the TKGrid component and all supporting classes)
|
|
@author(Tomas Krysl (tk@tkweb.eu))
|
|
@created(15 Oct 2006)
|
|
@lastmod(07 Dec 2010)
|
|
|
|
Copyright © 2006 Tomas Krysl (tk@@tkweb.eu)<BR><BR>
|
|
|
|
This unit provides an enhanced replacement for components contained
|
|
in Grids.pas. Major features:
|
|
<UL>
|
|
<LI><I>95% compatible with TDraw(String)Grid</I></LI>
|
|
<LI><I>any TWinControl descendant can be used as inplace editor</I></LI>
|
|
<LI><I>cell clipping and double buffering</I></LI>
|
|
<LI><I>cell merging/splitting</I></LI>
|
|
<LI><I>column/row/grid autosizing</I></LI>
|
|
<LI><I>cross platform control in Lazarus</I></LI>
|
|
<LI><I>index mapping - current column/row indexes can be mapped to their initial values</I></LI>
|
|
<LI><I>last row/column aligning (no scrollbar)</I></LI>
|
|
<LI><I>printing and previewing</I></LI>
|
|
<LI><I>row/column hiding with optional visual indication</I></LI>
|
|
<LI><I>rows, columns and cells are classes</I></LI>
|
|
<LI><I>several styles possible when moving/sizing cells</I></LI>
|
|
<LI><I>sorting interface</I></LI>
|
|
<LI><I>Unicode control</I></LI>
|
|
<LI><I>various text output attributes (multiline text, end ellipsis etc.)</I></LI>
|
|
<LI><I>versatile cell painting interface</I></LI>
|
|
<LI><I>virtual grid option</I></LI>
|
|
</UL>
|
|
|
|
<B>License:</B><BR>
|
|
This code is distributed as a freeware. You are free to use it as part
|
|
of your application for any purpose including freeware, commercial and
|
|
shareware applications. The origin of this source code must not be
|
|
misrepresented; you must not claim your authorship. You may modify this code
|
|
solely for your own purpose. Please feel free to contact the author if you
|
|
think your changes might be useful for other users. You may distribute only
|
|
the original package. The author accepts no liability for any damage
|
|
that may result from using this code. }
|
|
|
|
unit KGrids;
|
|
|
|
{$include kcontrols.inc}
|
|
{$WEAKPACKAGEUNIT ON}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF FPC}
|
|
LCLType, LCLIntf, LMessages, LCLProc, LResources,
|
|
{$ELSE}
|
|
Windows, Messages,
|
|
{$ENDIF}
|
|
SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, ExtCtrls,
|
|
KFunctions, KGraphics, KControls, Types
|
|
{$IFDEF TKGRID_USE_JCL}
|
|
, JclUnicode
|
|
{$ENDIF}
|
|
;
|
|
|
|
type
|
|
{ Declares possible values for the Mask parameter in the @link(TKCustomGrid.GetAxisInfoHorz)
|
|
or @link(TKCustomGrid.GetAxisInfoVert) functions. }
|
|
TKGridAxisInfoMaskMembers = (
|
|
{ The FixedBoundary field in the @link(TKGridAxisInfo) structure will be evaluated. }
|
|
aiFixedParams,
|
|
{ The GridExtent field in the @link(TKGridAxisInfo) structure will be evaluated. }
|
|
aiGridExtent,
|
|
{ The GridBoundary and GridCells fields in the @link(TKGridAxisInfo) structure will be evaluated. }
|
|
aiGridBoundary,
|
|
{ The FullVisBoundary and FullVisCells fields in the @link(TKGridAxisInfo) structure will be evaluated. }
|
|
aiFullVisBoundary
|
|
);
|
|
|
|
{ Set type for @link(TKGridAxisInfoMaskMembers) enumeration. }
|
|
TKGridAxisInfoMask = set of TKGridAxisInfoMaskMembers;
|
|
|
|
{ Method type for the CellExtent field in the @link(TKGridAxisInfo) structure. }
|
|
TKGridGetExtentFunc = function(Index: Integer): Integer of object;
|
|
|
|
{ Method type for the CanResize field in the @link(TKGridAxisInfo) structure. }
|
|
TKGridCanResizeFunc = function(var Index, Pos: Integer): Boolean of object;
|
|
|
|
{ @abstract(Declares a structure returned by the @link(TKCustomGrid.GetAxisInfoHorz)
|
|
or @link(TKCustomGrid.GetAxisInfoVert) functions)
|
|
This structure contains information either about columns or rows, depending on what
|
|
function returned the structure.
|
|
<UL>
|
|
<LH>Members:</LH>
|
|
<LI><I>InfoMask</I> - set of parameters that specify what fields in this structure
|
|
need to be evaluated.</LI>
|
|
<LI><I>AlignLastCell</I> - specifies if the last cell is aligned to client
|
|
area extent - see @link(goAlignLastCol) or @link(goAlignLastRow) for details.</LI>
|
|
<LI><I>FixedSelectable</I> - reflects the gxEditFixedCols or gxEditFixedRows.</LI>
|
|
<LI><I>CanResize</I> - this is the pointer to a function that determines
|
|
if a column or row can be resized - i.e. either BeginColSizing or BeginRowSizing methods.</LI>
|
|
<LI><I>CellExtent</I> - this is the pointer to a function that evaluates cell
|
|
width or height - i.e. either GetColWidths or GetColHeights (private members).</LI>
|
|
<LI><I>EffectiveSpacing</I> - specifies the effective space between cells
|
|
as returned by @link(TKCustomGrid.EffectiveColSpacing) or
|
|
@link(TKCustomGrid.EffectiveRowSpacing).</LI>
|
|
<LI><I>FixedCellCount</I> - specifies the amount of fixed columns or rows -
|
|
see @link(TKCustomGrid.FixedCols) or @link(TKCustomGrid.FixedRows) for details.</LI>
|
|
<LI><I>FirstGridCell</I> - specifies the first visible non-fixed cell as given
|
|
by @link(TKCustomGrid.LeftCol) or @link(TKCustomGrid.TopRow).</LI>
|
|
<LI><I>FirstGridCellExtent</I> - specifies the maximum value for the first visible
|
|
non-fixed cell as given by TKCustomGrid.FTopLeftExtent.</LI>
|
|
<LI><I>ClientExtent</I> - this is either the TControl.ClientWidth or
|
|
TControl.ClientHeight value.</LI>
|
|
<LI><I>MinCellExtent</I> - specifies the minimum cell extent as given by
|
|
@link(TKCustomGrid.InternalGetMinColWidth) or @link(TKCustomGrid.InternalGetMinRowHeight).</LI>
|
|
<LI><I>MaxCellExtent</I> - specifies the maximum cell extent as given by
|
|
@link(TKCustomGrid.InternalGetMaxColWidth) or @link(TKCustomGrid.InternalGetMaxRowHeight).</LI>
|
|
<LI><I>TotalCellCount</I> - specifies the total cell amount in desired direction
|
|
as given by @link(TKCustomGrid.ColCount) or @link(TKCustomGrid.RowCount).</LI>
|
|
<LI><I>FixedBoundary</I> - specifies the point in pixels where the
|
|
first non-fixed cell begins.</LI>
|
|
<LI><I>GridBoundary</I> - specifies the grid extent as returned by the
|
|
@link(TKCustomGrid.GridWidth) or @link(TKCustomGrid.GridHeight) properties.</LI>
|
|
<LI><I>GridCells</I> - gives the amount of cells that correspond to GridBoundary.</LI>
|
|
<LI><I>FullVisBoundary</I> - specifies the point in pixels where the
|
|
last fully visible cell ends.</LI>
|
|
<LI><I>FullVisCells</I> - gives the amount of cells that correspond to FullVisBoundary.</LI>
|
|
<LI><I>GridExtent</I> - returns the extent of all cells in the grid.</LI>
|
|
</UL> }
|
|
TKGridAxisInfo = record
|
|
InfoMask: TKGridAxisInfoMask;
|
|
// col/row independent parameters
|
|
AlignLastCell: Boolean;
|
|
FixedSelectable: Boolean;
|
|
CanResize: TKGridCanResizeFunc;
|
|
CellExtent: TKGridGetExtentFunc;
|
|
EffectiveSpacing: TKGridGetExtentFunc;
|
|
FixedCellCount: Integer;
|
|
FirstGridCell: Integer;
|
|
FirstGridCellExtent: Integer;
|
|
ClientExtent: Integer;
|
|
MinCellExtent: TKGridGetExtentFunc;
|
|
MaxCellExtent: TKGridGetExtentFunc;
|
|
TotalCellCount: Integer;
|
|
ScrollOffset: Integer;
|
|
// calculated parameters
|
|
FixedBoundary: Integer;
|
|
GridBoundary: Integer;
|
|
GridCells: Integer;
|
|
FullVisBoundary: Integer;
|
|
FullVisCells: Integer;
|
|
GridExtent: Int64;
|
|
end;
|
|
|
|
{ @abstract(Declares a structure returned by the
|
|
@link(TKCustomGrid.GetAxisInfoBoth) function)
|
|
<UL>
|
|
<LH>Members:</LH>
|
|
<LI><I>Horz</I> - structure as returned by @link(TKCustomGrid.GetAxisInfoHorz).</LI>
|
|
<LI><I>Vert</I> - structure as returned by @link(TKCustomGrid.GetAxisInfoVert).</LI>
|
|
</UL> }
|
|
TKGridAxisInfoBoth = record
|
|
Horz, Vert: TKGridAxisInfo;
|
|
end;
|
|
|
|
{ Declares possible values for the Flags parameter in the
|
|
@link(TKCustomGrid.UpdateAxes) method. }
|
|
TKGridAxisUpdateFlag = (
|
|
{ Forces the @link(TKCustomGrid.OnColWidthsChanged) and/or
|
|
@link(TKCustomGrid.OnRowHeightsChanged) to be called even if no column width/
|
|
row height has been modified by this call of UpdateAxes. }
|
|
afCallEvent,
|
|
{ Ensures all columns/rows have at least the minimum width/height as specified
|
|
by @link(TKCustomGrid.MinColWidth)/@link(TKCustomGrid.MinRowHeight). }
|
|
afCheckMinExtent
|
|
);
|
|
|
|
{ Set type for @link(TKGridAxisUpdateFlags) enumeration. }
|
|
TKGridAxisUpdateFlags = set of TKGridAxisUpdateFlag;
|
|
|
|
{ Declares possible values for the State parameter in the
|
|
@link(TKCustomGrid.SuggestDrag) or @link(TKCustomGrid.SuggestSizing)
|
|
functions. }
|
|
TKGridCaptureState = (
|
|
{ Suggestion is about to start - e.g. user clicked the movable column by mouse. }
|
|
csStart,
|
|
{ Suggestion is about to temporarily hide - e.g. user drags a column by mouse
|
|
and the grid needs to be updated. }
|
|
csHide,
|
|
{ Suggestion is about to show again - e.g. user drags a column by mouse
|
|
and the grid was updated. }
|
|
csShow,
|
|
{ Suggestion is about to stop - e.g. user released the mouse button
|
|
and the dragged column need to be actually moved. }
|
|
csStop
|
|
);
|
|
|
|
{ @abstract(Declares a structure that holds both column and row span of a cell)
|
|
<UL>
|
|
<LH>Members:</LH>
|
|
<LI><I>ColSpan</I> - column span.</LI>
|
|
<LI><I>RowSpan</I> - row span.</LI>
|
|
</UL> }
|
|
TKGridCellSpan = record
|
|
ColSpan: Integer;
|
|
RowSpan: Integer;
|
|
end;
|
|
|
|
{ @abstract(Declares a structure that hold both column and row index of a cell)
|
|
<UL>
|
|
<LH>Members:</LH>
|
|
<LI><I>Col</I> - coordinate or index of a column.</LI>
|
|
<LI><I>Row</I> - coordinate or index of a row.</LI>
|
|
</UL> }
|
|
TKGridCoord = record
|
|
Col: Integer;
|
|
Row: Integer;
|
|
end;
|
|
|
|
{ Declares possible indexes e.g. for the @link(TKGridColors.Color) property. }
|
|
TKGridColorIndex = Integer;
|
|
|
|
{ Declares possible values for the @link(TKGridColors.ColorScheme) property. }
|
|
TKGridColorScheme = (
|
|
{ GetColor returns normal color currently defined for each item. }
|
|
csNormal,
|
|
{ GetColor returns gray for text. }
|
|
csGrayed,
|
|
{ GetColor returns brighter version of normal color. }
|
|
csBright,
|
|
{ GetColor returns grayscaled color versions. }
|
|
csGrayScale
|
|
);
|
|
|
|
{ Method type for the Compare parameter e.g. in the
|
|
@link(TKCustomGrid.InternalQuickSortNR) method. }
|
|
TKGridCompareProc = function(ByIndex, Index1, Index2: Integer): Integer of object;
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.DisabledDrawStyle) property. }
|
|
TKGridDisabledDrawStyle = (
|
|
{ The lines will be painted with brighter colors when control is disabled. }
|
|
ddBright,
|
|
{ The lines will be painted with gray text and white background when control is disabled. }
|
|
ddGrayed,
|
|
{ The lines will be painted normally when control is disabled. }
|
|
ddNormal
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.DragStyle) property. }
|
|
TKGridDragStyle = (
|
|
{ The moved column or row is displayed beneath mouse cursor in a layered window (Win2k+)
|
|
or white window (other OS) with fading opacity. }
|
|
dsLayeredConst,
|
|
{ The moved column or row is displayed beneath mouse cursor in a layered window (Win2k+)
|
|
or white window (other OS) with constant opacity. }
|
|
dsLayeredFaded,
|
|
{ The moved column or row is not displayed, behavior of original TCustomGrid
|
|
but line has red color. }
|
|
dsLine,
|
|
{ The moved column or row is not displayed, behavior of original TCustomGrid. }
|
|
dsXORLine
|
|
);
|
|
|
|
{ Declares possible values for the State parameter in the
|
|
@link(TKGridDrawCellEvent) event handler or @link(TKGridCell.DrawCell) method. }
|
|
TKGridDrawStateMembers = (
|
|
{ The cell has input focus and is currently edited. This is always 1 cell
|
|
that correspond to @link(TKCustomGrid.Col) and @link(TKCustomGrid.Row)
|
|
properties. Painting of the cell is automatically invoked to allow e.g.
|
|
background filling for inplace editors that don't fill the entire cell area. }
|
|
gdEdited,
|
|
{ The cell is in the fixed region of the grid. }
|
|
gdFixed,
|
|
{ The cell has input focus. This is always 1 cell that correspond to
|
|
@link(TKCustomGrid.Col) and @link(TKCustomGrid.Row) properties. }
|
|
gdFocused,
|
|
{ Left mouse button is pressed. Cell repainting
|
|
is automatically invoked when mouse cursor is over the cell and the left
|
|
button is pressed. The cell is repainter if mouse button is released, either. }
|
|
gdMouseDown,
|
|
{ Mouse cursor is over the cell in @link(goMouseOverCells) mode. Cell repainting
|
|
is automatically invoked when mouse cursor enters or leaves the cell.
|
|
Furthermore, if @link(TKCustomGrid.EditorMode) is True, the inplace editor will
|
|
be invalidated to allow proper editor underpainting, either. }
|
|
gdMouseOver,
|
|
{ The cell is currently selected. This includes all cells that appear with
|
|
different default background color in either @link(goRangeSelect) or
|
|
@link(goRowSelect) mode. }
|
|
gdSelected,
|
|
{ The cell belongs to the sorted column or row. }
|
|
gdSorted,
|
|
{ Applies to the left most fixed column (if any).
|
|
The cell should paint visual shape like arrow to indicate that the
|
|
columns are sorted from lowest to highest value, like 'A' to 'Z'. }
|
|
gdColsSortedUp,
|
|
{ Applies to the left most fixed column (if any).
|
|
The cell should paint visual shape like arrow to indicate that the
|
|
columns are sorted from highest to lowest value, like 'Z' to 'A'. }
|
|
gdColsSortedDown,
|
|
{ Applies to the top most fixed row (if any).
|
|
The cell should paint visual shape like arrow to indicate that the
|
|
rows are sorted from lowest to highest value, like 'A' to 'Z'. }
|
|
gdRowsSortedUp,
|
|
{ Applies to the top most fixed row (if any).
|
|
The cell should paint visual shape like arrow to indicate that the
|
|
rows are sorted from highest to lowest value, like 'Z' to 'A'. }
|
|
gdRowsSortedDown
|
|
);
|
|
|
|
{ Set type for @link(TKGridDrawStateMembers) enumeration. }
|
|
TKGridDrawState = set of TKGridDrawStateMembers;
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.EditorTransparency) property. }
|
|
TKGridEditorTransparency = (
|
|
{ The grid decides which inplace editor should be treated as a transparent
|
|
control. This method works for all standard VCL controls. }
|
|
etDefault,
|
|
{ Current inplace editor should be treated as opaque, i.e. not transparent. }
|
|
etNormal,
|
|
{ Current inplace editor should be treated as transparent. }
|
|
etTransparent
|
|
);
|
|
|
|
{ Method type for the Exchange parameter e.g. in the
|
|
@link(TKCustomGrid.InternalQuickSortNR) method. }
|
|
TKGridExchangeProc = procedure(Index1, Index2: Integer) of object;
|
|
|
|
{ Declares possible values for the InvisibleCells parameter in the
|
|
@link(TKCustomGrid.PointToCell) method. }
|
|
TKGridInvisibleCells = (
|
|
{ No invisible cells will be taken into account. Invisible cells are those
|
|
that are hidden (non-fixed) to the left or top. }
|
|
icNone,
|
|
{ Invisible cells to the left will be taken into account at the expense of
|
|
the (possible) fixed cells. }
|
|
icFixedCols,
|
|
{ Invisible cells to the top will be taken into account at the expense of
|
|
the (possible) fixed cells. }
|
|
icFixedRows,
|
|
{ All invisible cells will be taken into account at the expense of
|
|
the (possible) fixed cells. }
|
|
icCells
|
|
);
|
|
|
|
{ Declares a structure for hidden cell indicator glyphs. }
|
|
TKGridHCIBitmaps = record
|
|
HBegin, HCenter, HEnd,
|
|
VBegin, VCenter, VEnd: TKAlphaBitmap;
|
|
end;
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.Options) property. }
|
|
TKGridOption = (
|
|
{ Tries to put all columns to the visible area of the grid and omit free space
|
|
to the right of the last cell. No horizontal scrollbar appears. }
|
|
goAlignLastCol,
|
|
{ Tries to put all rows to the visible area of the grid and omit free space
|
|
below the last cell. No vertical scrollbar appears. }
|
|
goAlignLastRow,
|
|
{ The grid is locked into edit mode. The user does not need to use Enter or F2
|
|
to turn on EditorMode everytime he moves to another cell. The behavior is
|
|
slightly different as in TCustomGrid. }
|
|
goAlwaysShowEditor,
|
|
{ Enables the WM_ERASEBKGND message to be handled if True. This can be used
|
|
to avoid grid flickering for the case the grid is placed into a container
|
|
that requires repainting itself and all of its children after resizing.
|
|
This behavior is typical for nested TPanels. If you don't use these you
|
|
can set this option True to erase the background. The grid does not need
|
|
the background to be erased as it fills the entire client area through
|
|
WM_PAINT. But some users might need to erase the background due to the
|
|
strange behavior when activating an application by clicking the main form's
|
|
title bar. }
|
|
goEraseBackground,
|
|
{ No painting is allowed beyond the cell outline. }
|
|
goClippedCells,
|
|
{ Scrollable columns can be moved using the mouse. }
|
|
goColMoving,
|
|
{ Scrollable columns can be individually resized. }
|
|
goColSizing,
|
|
{ Scrollable columns can be sorted by mouse click at the first fixed row. The
|
|
sorted column is visually indicated by arrow at the first fixed row. }
|
|
goColSorting,
|
|
{ Instructs the cell painter to draw each cell with double buffering to
|
|
avoid cell flickering. }
|
|
goDoubleBufferedCells,
|
|
{ Selected cells are drawn with with a focus rectangle if the grid (not the
|
|
inplace editor) has the input focus. The behavior is slightly different
|
|
as in TCustomGrid. }
|
|
goDrawFocusSelected,
|
|
{ Users can edit the contents of cells. No another limitation applicable. }
|
|
goEditing,
|
|
{ If included, Enter does not turn on EditorMode, but causes another cell to
|
|
be focused. What cell it is depends on @link(TKCustomGrid.MoveDirection). }
|
|
goEnterMoves,
|
|
{ Horizontal lines are drawn to separate the fixed (nonscrolling) rows
|
|
in the grid. }
|
|
goFixedHorzLine,
|
|
{ Vertical lines are drawn to separate the fixed (nonscrolling) columns
|
|
in the grid. If @link(TKCustomGrid.ThemedCells) is True, these are not
|
|
drawn for fixed rows by default, as these are meant as a grid header. }
|
|
goFixedVertLine,
|
|
{ Draws cells in the first fixed row in standard Win-API header style. }
|
|
goHeader,
|
|
{ Terminates the first fixed row drawn in standard Win-API header style
|
|
by drawing a standard Win-API header terminator in an area not occupied by cells. }
|
|
goHeaderAlignment,
|
|
{ Horizontal lines are drawn to separate the scrollable rows in the grid. }
|
|
goHorzLine,
|
|
{ Hidden columns or rows are indicated in fixed cell area. }
|
|
goIndicateHiddenCells,
|
|
{ Selection is indicated in the fixed cells by a specific color. }
|
|
goIndicateSelection,
|
|
{ Columns or rows can be hidden with the mouse while being resized. Set to
|
|
False to enforce KGrid 1.2 behavior. }
|
|
goMouseCanHideCells,
|
|
{ If included, then if the mouse enters or leaves a cell, these cells
|
|
will be invalidated and the cell under the mouse pointer gets a
|
|
@link(gdMouseOver) state. }
|
|
goMouseOverCells,
|
|
{ If included, no text will be selected in the inplace editor upon its creation.
|
|
This applies only to inplace editors having a selectable text, of course.
|
|
The default behavior works only for editors responding to EM_SETSEL message.
|
|
For another editors, the behavior can be maintained by the
|
|
@link(TKCustomGrid.OnEditorSelect) event handler. }
|
|
goNoSelEditText,
|
|
{ Users can select ranges of cells at one time. No another limitation applicable. }
|
|
goRangeSelect,
|
|
{ Scrollable rows can be moved using the mouse. }
|
|
goRowMoving,
|
|
{ Entire rows are selected rather than individual cells. No another limitation applicable. }
|
|
goRowSelect,
|
|
{ Scrollable rows can be individually resized. Caution: Some inplace editors
|
|
cannot be resized in height - for example TComboBox. }
|
|
goRowSizing,
|
|
{ Scrollable rows can be sorted by mouse click at the first fixed column. The
|
|
sorted row is visually indicated by arrow at the first fixed column. }
|
|
goRowSorting,
|
|
{ Users can navigate through the cells in the grid using Tab and Shift+Tab. }
|
|
goTabs,
|
|
{ Enables OS themes for both non-client and cells. }
|
|
goThemes,
|
|
{ Enables OS themes for cells. }
|
|
goThemedCells,
|
|
{ Vertical lines are drawn to separate the scrollable columns in the grid. }
|
|
goVertLine,
|
|
{ If included, the grid becomes virtual grid. In this mode, data for the cells
|
|
must be supplied externally. No cell class instances are allocated.
|
|
@link(TKCustomGrid.Cell) property cannot be set and returns always nil.
|
|
@link(TKCustomGrid.Cells) property cannot be set and returns always empty string.
|
|
@link(TKCustomGrid.FCells) field is always nil - no grid structure is allocated.
|
|
Column and Row structures (@link(TKCustomGrid.FCols) and
|
|
@link(TKCustomGrid.FRows)) remain always allocated. }
|
|
goVirtualGrid
|
|
);
|
|
|
|
{ Set type for @link(TKGridOption) enumeration. }
|
|
TKGridOptions = set of TKGridOption;
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.OptionsEx) property. }
|
|
TKGridOptionEx = (
|
|
{ When Inplace editor has horizontal constraint it will be horizontally centered. }
|
|
gxEditorHCenter,
|
|
{ When Inplace editor has vertical constraint it will be vertically centered. }
|
|
gxEditorVCenter,
|
|
{ Pressing Enter at the last cell appends a row. }
|
|
gxEnterAppendsRow,
|
|
{ Pressing Enter wraps selection to next column/row. }
|
|
gxEnterWraps,
|
|
{ Clicking fixed cells together with Shift key selects/unselects respective columns/rows. }
|
|
gxFixedCellClickSelect,
|
|
{ All fixed cells will be painted with header theme (looks bad e.g. with classic WinXP). }
|
|
gxFixedThemedCells,
|
|
{ Pressing TAB at the last cell appends a row. }
|
|
gxTabAppendsRow,
|
|
{ Pressing TAB wraps selection to next column/row. }
|
|
gxTabWraps,
|
|
// aki:
|
|
{ Allow edit fixed rows}
|
|
gxEditFixedRows,
|
|
{ Allow edit fixed cols}
|
|
gxEditFixedCols
|
|
);
|
|
|
|
{ Set type for @link(TKGridOptionEx) enumeration. }
|
|
TKGridOptionsEx = set of TKGridOptionEx;
|
|
|
|
{ Declares possible values for the Priority parameter in the @link(TKCustomGrid.MeasureCell) method. }
|
|
TKGridMeasureCellPriority = (
|
|
{ Row height stays, column width is adjusted. }
|
|
mpColWidth,
|
|
{ Column width stays, row height is adjusted. }
|
|
mpRowHeight,
|
|
{ Default cell extent adjustment. }
|
|
mpCellExtent
|
|
);
|
|
|
|
{ Declares possible values for the Command parameter in the @link(TKCustomGrid.InternalMove) method. }
|
|
TKGridMoveCommand = (
|
|
{ No command. }
|
|
mcNone,
|
|
{ Move to last row. }
|
|
mcBottom,
|
|
{ Move to next row. }
|
|
mcDown,
|
|
{ Move to last column. }
|
|
mcEnd,
|
|
{ Move to first column. }
|
|
mcHome,
|
|
{ Move to previous column. }
|
|
mcLeft,
|
|
{ Move to bottom row on current page. }
|
|
mcMoveDown,
|
|
{ Move to top row on current page. }
|
|
mcMoveUp,
|
|
{ Move to next vertical page. }
|
|
mcPageDown,
|
|
{ Move to next horizontal page. }
|
|
mcPageLeft,
|
|
{ Move to previous horizontal page. }
|
|
mcPageRight,
|
|
{ Move to previous vertical page. }
|
|
mcPageUp,
|
|
{ Move to next column. }
|
|
mcRight,
|
|
{ Move to first row. }
|
|
mcTop,
|
|
{ Move to previous row. }
|
|
mcUp
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.MoveDirection) property. }
|
|
TKGridMoveDirection = (
|
|
{ By pressing Enter, the cell below the currently focused cell will be focused. }
|
|
mdDown,
|
|
{ By pressing Enter, the cell to the left of the currently focused cell will be focused. }
|
|
mdLeft,
|
|
{ By pressing Enter, the cell to the right of the currently focused cell will be focused. }
|
|
mdRight,
|
|
{ By pressing Enter, the cell above the currently focused cell will be focused. }
|
|
mdUp
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.RangeSelectStyle) property. }
|
|
TKGridRangeSelectStyle = (
|
|
{ The focused cell is not the base cell and expands the selection. }
|
|
rsDefault,
|
|
{ The focused cell is the base cell and does not expand the selection. }
|
|
rsMS_Excel
|
|
);
|
|
|
|
{ @abstract(Declares the type e.g. for the @link(TKCustomGrid.Selection) property)
|
|
Declares the type for grid rectangle. A grid rectangle is a structure of
|
|
two independent grid points.
|
|
<UL>
|
|
<LH>Members:</LH>
|
|
<LI><I>Col1, Row1, Col2, Row2</I> - rectangle of grid cells given by indexes.</LI>
|
|
<LI><I>Cell1, Cell2</I> - rectangle of grid cells given e.g. by top-left and bottom-right cells.</LI>
|
|
</UL> }
|
|
TKGridRect = record
|
|
case Integer of
|
|
0: (Col1, Row1, Col2, Row2: Integer);
|
|
1: (Cell1, Cell2: TKGridCoord);
|
|
end;
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.ScrollModeHorz) and @link(TKCustomGrid.ScrollModeVert) properties. }
|
|
TKGridScrollMode = (
|
|
{ The trackbar scrolls per pixel. }
|
|
smSmooth,
|
|
{ The trackbar scrolls per cell. }
|
|
smCell
|
|
);
|
|
|
|
{ Declares possible values for the Stage parameter in the @link(TKGridSelectionExpandEvent)
|
|
event handler or @link(TKCustomGrid.SelectionMove) method. }
|
|
TKGridSelectionStage = (
|
|
{ The selection moves entirely - the selection base cell changes. }
|
|
ssInit,
|
|
{ The selection expands - the selection base cell remains unchanged. }
|
|
ssExpand
|
|
);
|
|
|
|
{ Declares possible values for the Flags parameter in the
|
|
@link(TKCustomGrid.SelectionMove) method. }
|
|
TKGridSelectionFlag = (
|
|
{ Do not call the @link(TKCustomGrid.SelectCell) method. }
|
|
sfDontCallSelectCell,
|
|
{ Force invalidation of the old and new selection. }
|
|
sfMustUpdate,
|
|
{ Force calling of the @link(TKCustomGrid.ClampInView) method. }
|
|
sfClampInView,
|
|
{ Do not set @link(TKCustomGrid.FMemCol) and @link(TKCustomGrid.FMemRow) fields. }
|
|
sfNoMemPos
|
|
);
|
|
|
|
{ Set type for @link(TKGridSelectionFlag) enumeration. }
|
|
TKGridSelectionFlags = set of TKGridSelectionFlag;
|
|
|
|
{ Declares possible values for the Change parameter in the
|
|
@link(TKGridSizeChangedEvent) event handler. }
|
|
TKGridSizeChange = (
|
|
{ Columns have been deleted. }
|
|
scColDeleted,
|
|
{ Columns have been inserted. }
|
|
scColInserted,
|
|
{ Rows have been deleted. }
|
|
scRowDeleted,
|
|
{ Rows have been inserted. }
|
|
scRowInserted
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.SizingStyle) property. }
|
|
TKGridSizingStyle = (
|
|
{ Column widths or row heights update after the mouse button is released.
|
|
Old TCustomGrid behavior but line has red color. }
|
|
ssLine,
|
|
{ Column widths or row heights update immediately. }
|
|
ssUpdate,
|
|
{ Column widths or row heights update after the mouse button is released.
|
|
Old TCustomGrid behavior. }
|
|
ssXORLine
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKGridAxisItem.SortMode) property. }
|
|
TKGridSortMode = (
|
|
{ Corresponding column or row is not sorted. }
|
|
smNone,
|
|
{ Corresponding column or row is sorted from lowest to highest value. }
|
|
smDown,
|
|
{ Corresponding column or row is sorted from highest to lowest value. }
|
|
smUp
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.SortStyle) property. }
|
|
TKGridSortStyle = (
|
|
{ First click sorts from lowest to highest value, second click sorts from highest to lowest value. }
|
|
ssDownUp,
|
|
{ First click sorts from lowest to highest value, second click sorts from highest to lowest value, third click turns sorting off. }
|
|
ssDownUpNone,
|
|
{ First click sorts from highest to lowest value, second click sorts from lowest to highest value, third click turns sorting off. }
|
|
ssUpDownNone
|
|
);
|
|
|
|
{ Declares possible values for the @link(TKCustomGrid.FGridState) field. }
|
|
TKGridState = (
|
|
{ The mouse button has been pressed on a fixed cell that triggers
|
|
mouse click event. }
|
|
gsClickWaiting,
|
|
{ The mouse button has been pressed on a fixed cell that triggers
|
|
column dragging. }
|
|
gsColMoveWaiting,
|
|
{ The user is dragging a column to a new position. }
|
|
gsColMoving,
|
|
{ The user is changing the width of a column. }
|
|
gsColSizing,
|
|
{ The mouse button has been pressed on a fixed cell that triggers
|
|
column sorting. }
|
|
gsColSortWaiting,
|
|
{ The grid layout is not changing. }
|
|
gsNormal,
|
|
{ The mouse button has been pressed on a fixed cell that triggers
|
|
row dragging. }
|
|
gsRowMoveWaiting,
|
|
{ The user is dragging a row to a new position. }
|
|
gsRowMoving,
|
|
{ The user is changing the height of a row. }
|
|
gsRowSizing,
|
|
{ The mouse button has been pressed on a fixed cell that triggers
|
|
row sorting. }
|
|
gsRowSortWaiting,
|
|
{ The user is selecting a cell or row. }
|
|
gsSelecting
|
|
);
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnBeginColDrag) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Origin</I> - row or column index where dragging should be started.</LI>
|
|
<LI><I>MousePt</I> - position of mouse cursor.</LI>
|
|
<LI><I>CanBeginDrag</I> - True by default to allow the dragging to be started.</LI>
|
|
</UL> }
|
|
TKGridBeginDragEvent = procedure(Sender: TObject; var Origin: Integer;
|
|
const MousePt: TPoint; var CanBeginDrag: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnBeginColSizing) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Index</I> - index of a row or column that should be resized.</LI>
|
|
<LI><I>Pos</I> - position of the sizing line
|
|
(even if it actually doesn't exist in @link(ssUpdate) sizing mode).</LI>
|
|
<LI><I>CanBeginSizing</I> - True by default to allow the sizing to be started.</LI>
|
|
</UL> }
|
|
TKGridBeginSizingEvent = procedure(Sender: TObject; var Index, Pos: Integer;
|
|
var CanBeginSizing: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for any cell notification events)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the corresponding cell.</LI>
|
|
</UL> }
|
|
TKGridCellEvent = procedure(Sender: TObject; ACol, ARow: Integer) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnMouseCellHint) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the corresponding cell.</LI>
|
|
<LI><I>AShow</I> - True if hint should be displayed, otherwise False.</LI>
|
|
</UL> }
|
|
TKGridCellHintEvent = procedure(Sender: TObject; ACol, ARow: Integer; AShow: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnCellSpan) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the cell whose span data is to be retrieved.</LI>
|
|
<LI><I>Span</I> - resulting span data for that cell.</LI>
|
|
</UL> }
|
|
TKGridCellSpanEvent = procedure(Sender: TObject; ACol, ARow: Integer; var Span: TKGridCellSpan) of object;
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnCheckColDrag) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Origin</I> - row or column index where dragging was started.</LI>
|
|
<LI><I>Destination</I> - row or column index where dragging is about to end at this moment.</LI>
|
|
<LI><I>MousePt</I> - position of mouse cursor.</LI>
|
|
<LI><I>CanDrop</I> - True by default to allow the dropping to Destination.</LI>
|
|
</UL> }
|
|
TKGridCheckDragEvent = procedure(Sender: TObject; Origin: Integer;
|
|
var Destination: Integer; const MousePt: TPoint; var CanDrop: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnCompareCells))
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Col1</I> - column index of the first cell or @link(cInvalidIndex) -
|
|
see @link(TKCustomGrid.InsertSortedCol).</LI>
|
|
<LI><I>Row1</I> - row index of the first cell or @link(cInvalidIndex) -
|
|
see @link(TKCustomGrid.InsertSortedRow).</LI>
|
|
<LI><I>Col2</I> - column index of the second cell.</LI>
|
|
<LI><I>Row2</I> - row index of the second cell.</LI>
|
|
</UL>
|
|
<UL>
|
|
<LH>Returns:</LH>
|
|
<LI>Negative value (<0) if the value of the first cell is lower than
|
|
the value of the second cell.</LI>
|
|
<LI>Positive value (>0) if the value of the first cell is greater than
|
|
the value of the second cell.</LI>
|
|
<LI>Zero if values of both cells are the same.</LI>
|
|
</UL> }
|
|
TKGridCompareCellsEvent = function(Sender: TObject; Col1, Row1, Col2, Row2: Integer):
|
|
Integer of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnCustomSortCols) or
|
|
@link(TKCustomGrid.OnCustomSortRows) events)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ByIndex</I> - column or row index to sort rows or columns by.</LI>
|
|
<LI><I>SortMode</I> - the sorting mode to sort rows or columns.</LI>
|
|
<LI><I>Sorted</I> - set to True to avoid default sorting to be called.</LI>
|
|
</UL> }
|
|
TKGridCustomSortEvent = procedure(Sender: TObject; ByIndex: Integer;
|
|
SortMode: TKGridSortMode; var Sorted: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnDrawCell) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the cell being drawn.</LI>
|
|
<LI><I>R</I> - location of cell on the canvas.</LI>
|
|
<LI><I>State</I> - indicates the state of the cell.</LI>
|
|
</UL> }
|
|
TKGridDrawCellEvent = procedure(Sender: TObject; ACol, ARow: Integer;
|
|
R: TRect; State: TKGridDrawState) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorCreate) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the focused cell that
|
|
is about to become edited cell.</LI>
|
|
<LI><I>AEditor</I> - nil by default to indicate that no inplace editor is
|
|
wanted for the cell. Assign any TWinControl instance to this Parameter
|
|
to create a custom inplace editor for the cell. Always create new
|
|
instance because it is owned by the grid and destroyed automatically
|
|
if no longer needed.</LI>
|
|
</UL> }
|
|
TKGridEditorCreateEvent = procedure(Sender: TObject; ACol, ARow: Integer;
|
|
var AEditor: TWinControl) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorDataFromGrid)
|
|
or @link(TKCustomGrid.OnEditorDataToGrid) events)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>AEditor</I> - identifies the inplace editor.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the edited cell.</LI>
|
|
<LI><I>AssignText</I> - Allows to automatically set the cell text
|
|
to or from inplace editor. Set to False to disable this behavior.</LI>
|
|
</UL> }
|
|
TKGridEditorDataEvent = procedure(Sender: TObject; AEditor: TWinControl;
|
|
ACol, ARow: Integer; var AssignText: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorDestroy) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>AEditor</I> - identifies the inplace editor.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the edited cell.</LI>
|
|
</UL> }
|
|
TKGridEditorDestroyEvent = procedure(Sender: TObject; var AEditor: TWinControl;
|
|
ACol, ARow: Integer) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorKeyPreview) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>AEditor</I> - identifies the inplace editor.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the edited cell.</LI>
|
|
<LI><I>Key</I> - key code as passed to OnKeyDown, can be modified.</LI>
|
|
<LI><I>Shift</I> - state of the control keys as passed to OnKeyDown.</LI>
|
|
<LI><I>IsGridKey</I> - True by default to indicate that the key will be handled
|
|
by the grid. Set to False to let the inplace editor handle the key.</LI>
|
|
</UL> }
|
|
TKGridEditorKeyPreviewEvent = procedure(Sender: TObject; AEditor: TWinControl;
|
|
ACol, ARow: Integer; var Key: Word; Shift: TShiftState; var IsGridKey: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorResize) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>AEditor</I> - identifies the inplace editor.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the edited cell.</LI>
|
|
<LI><I>ARect</I> - initial bounding rectangle of the inplace editor.
|
|
You can modify it in order to place the editor somewhere else within the cell.
|
|
The inplace editor is always clipped within the cell.</LI>
|
|
</UL> }
|
|
TKGridEditorResizeEvent = procedure(Sender: TObject; AEditor: TWinControl;
|
|
ACol, ARow: Integer; var ARect: TRect) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnEditorSelect) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>AEditor</I> - identifies the inplace editor.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the edited cell.</LI>
|
|
<LI><I>SelectAll</I> - all the text should be selected in the inplace editor.</LI>
|
|
<LI><I>CaretToLeft</I> - caret should be positioned to the left.</LI>
|
|
<LI><I>SelectedByMouse</I> - the cell has been selected by mouse.</LI>
|
|
</UL> }
|
|
TKGridEditorSelectEvent = procedure(Sender: TObject; AEditor: TWinControl;
|
|
ACol, ARow: Integer; SelectAll, CaretToLeft, SelectedByMouse: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnEndColDrag) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Origin</I> - row or column index where dragging was started.</LI>
|
|
<LI><I>Destination</I> - row or column index where dragging ends.</LI>
|
|
<LI><I>MousePt</I> - position of mouse cursor.</LI>
|
|
<LI><I>CanEndDrag</I> - True by default to allow the dragging to be ended.</LI>
|
|
</UL> }
|
|
TKGridEndDragEvent = procedure(Sender: TObject; Origin: Integer;
|
|
Destination: Integer; const MousePt: TPoint; var CanEndDrag: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnEndColSizing) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Index</I> - index of a row or column that is being resized.</LI>
|
|
<LI><I>Pos</I> - current position of the sizing line
|
|
(even if it actually doesn't exist in @link(ssUpdate) sizing mode).</LI>
|
|
<LI><I>CanEndSizing</I> - True by default to allow the resizing to be ended.</LI>
|
|
</UL> }
|
|
TKGridEndSizingEvent = procedure(Sender: TObject; Index, Pos: Integer;
|
|
var CanEndSizing: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnExchangeCols) or
|
|
@link(TKCustomGrid.OnExchangeRows) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Index1</I> - index of the first column or row.</LI>
|
|
<LI><I>Index2</I> - index of the second column or row.</LI>
|
|
</UL> }
|
|
TKGridExchangeEvent = procedure(Sender: TObject;
|
|
Index1, Index2: Integer) of object;
|
|
|
|
{ @abstract(Declares event handler for any cell extent notification events)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>AIndex</I> - column or row index.</LI>
|
|
</UL> }
|
|
TKGridExtentEvent = procedure(Sender: TObject; AIndex: Integer) of object;
|
|
|
|
{ @abstract(Declares event handler e.g. for the @link(TKCustomGrid.OnMeasureCell) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the cell being drawn.</LI>
|
|
<LI><I>R</I> - location of cell on the canvas.</LI>
|
|
<LI><I>State</I> - indicates the state of the cell.</LI>
|
|
<LI><I>Priority</I> - specifies the cell measurement priority.</LI>
|
|
<LI><I>Extent</I> - returns calculated cell extent.</LI>
|
|
</UL> }
|
|
TKGridMeasureCellEvent = procedure(Sender: TObject; ACol, ARow: Integer;
|
|
R: TRect; State: TKGridDrawState; Priority: TKGridMeasureCellPriority;
|
|
var Extent: TPoint) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnColumnMoved) or
|
|
@link(TKCustomGrid.OnRowMoved) events)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>FromIndex</I> - initial position of the column or row being moved.</LI>
|
|
<LI><I>ToIndex</I> - final position of the column or row being moved.</LI>
|
|
</UL> }
|
|
TKGridMovedEvent = procedure(Sender: TObject; FromIndex, ToIndex: Integer) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnSizeChanged) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Change</I> - identifies the change type.</LI>
|
|
<LI><I>At</I> - index where column(s) or row(s) have been inserted or deleted.</LI>
|
|
<LI><I>Count</I> - number of column(s) or row(s) that have been inserted or deleted.</LI>
|
|
</UL> }
|
|
TKGridSizeChangedEvent = procedure(Sender: TObject;
|
|
Change: TKGridSizeChange; At, Count: Integer) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnSelectCell) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the cell that is about to be selected.</LI>
|
|
<LI><I>CanSelect</I> - True by default to indicate that the cell can be selected.
|
|
Set to False to inhibit selecting of this cell.</LI>
|
|
</UL> }
|
|
TKGridSelectCellEvent = procedure(Sender: TObject; ACol, ARow: Integer;
|
|
var CanSelect: Boolean) of object;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnSelectCell) event)
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>ACol, ARow</I> - column and row indexes of the cell that is about to
|
|
expand the current selection.</LI>
|
|
<LI><I>CanExpand</I> - True by default to indicate that the cell
|
|
can the selection. Set to False to inhibit further selection expanding.</LI>
|
|
</UL> }
|
|
TKGridSelectionExpandEvent = procedure(Sender: TObject; ACol, ARow: Integer;
|
|
var CanExpand: Boolean) of object;
|
|
|
|
const
|
|
{ Constant for invalid column or row indexes. Currently, it is used internally.
|
|
Functions @link(TKCustomGrid.InitialCol) and @link(TKCustomGrid.InitialRow)
|
|
return this value in case of invalid parameters. }
|
|
cInvalidIndex = -1;
|
|
|
|
{ This constant can be passed into the FirstCol or FirstRow parameter of the
|
|
@link(TKCustomGrid.UpdateAxes) method. }
|
|
cAll = -1;
|
|
|
|
{ Default value for the @link(TKCustomGrid.ColCount) property. }
|
|
cColCountDef = 5;
|
|
|
|
{ Default value for the @link(TKCustomGrid.DefaultColWidth) property. }
|
|
cDefaultColWidthDef = 64;
|
|
|
|
{ Default value for the @link(TKCustomGrid.DefaultRowHeight) property. }
|
|
cDefaultRowHeightDef = 21;
|
|
|
|
{ Default value for the @link(TKCustomGrid.DisabledDrawStyle) property. }
|
|
cDisabledDrawStyleDef = ddBright;
|
|
|
|
{ Default value for the @link(TKCustomGrid.DragStyle) property. }
|
|
cDragStyleDef = dsLayeredFaded;
|
|
|
|
{ Default value for the @link(TKCustomGrid.EditorTransparency) property. }
|
|
cEditorTransparencyDef = etDefault;
|
|
|
|
{ Default value for the @link(TKCustomGrid.FixedCols) property. }
|
|
cFixedColsDef = 1;
|
|
|
|
{ Default value for the @link(TKCustomGrid.FixedRows) property. }
|
|
cFixedRowsDef = 1;
|
|
|
|
{ Default value for the @link(TKCustomGrid.GridLineWidth) property. }
|
|
cGridLineWidthDef = 1;
|
|
|
|
{ Minimum value for the @link(TKCustomGrid.MinColWidth) property. }
|
|
cMinColWidthMin = 5;
|
|
{ Default value for the @link(TKCustomGrid.MinColWidth) property. }
|
|
cMinColWidthDef = 10;
|
|
|
|
{ Minimum value for the @link(TKCustomGrid.MinRowHeight) property. }
|
|
cMinRowHeightMin = 5;
|
|
{ Default value for the @link(TKCustomGrid.MinRowHeight) property. }
|
|
cMinRowHeightDef = 10;
|
|
|
|
{ Minimum value for the @link(TKCustomGrid.MouseCellHintTime) property. }
|
|
cMouseCellHintTimeMin = 100;
|
|
{ Maximum value for the @link(TKCustomGrid.MouseCellHintTime) property. }
|
|
cMouseCellHintTimeMax = 10000;
|
|
{ Default value for the @link(TKCustomGrid.MouseCellHintTime) property. }
|
|
cMouseCellHintTimeDef = 800;
|
|
|
|
{ Default value for the @link(TKCustomGrid.MoveDirection) property. }
|
|
cMoveDirectionDef = mdRight;
|
|
|
|
{ Default value for the @link(TKCustomGrid.Options) property. }
|
|
cOptionsDef = [goAlwaysShowEditor, goDrawFocusSelected,
|
|
goEnterMoves, goFixedVertLine, goFixedHorzLine, goIndicateHiddenCells,
|
|
goHeader, goHeaderAlignment, goHorzLine, goMouseCanHideCells,
|
|
goMouseOverCells, goRangeSelect, goThemes, goThemedCells, goVertLine];
|
|
|
|
{ Default value for the @link(TKCustomGrid.OptionsEx) property. }
|
|
cOptionsExDef = [gxEnterWraps, gxTABWraps];
|
|
|
|
{ Default value for the @link(TKCustomGrid.RangeSelectStyle) property. }
|
|
cRangeSelectStyleDef = rsDefault;
|
|
|
|
{ Default value for the @link(TKCustomGrid.RowCount) property. }
|
|
cRowCountDef = 5;
|
|
|
|
{ Default value for the @link(TKCustomGrid.ScrollBars) property. }
|
|
cScrollBarsDef = ssBoth;
|
|
|
|
{ Minimum value for the @link(TKCustomGrid.ScrollSpeed) property. }
|
|
cScrollSpeedMin = 50;
|
|
{ Maximum value for the @link(TKCustomGrid.ScrollSpeed) property. }
|
|
cScrollSpeedMax = 1000;
|
|
{ Default value for the @link(TKCustomGrid.ScrollSpeed) property. }
|
|
cScrollSpeedDef = 100;
|
|
|
|
{ Default value for the @link(TKCustomGrid.ScrollModeHorz) and @link(TKCustomGrid.ScrollModeVert) properties. }
|
|
cScrollModeDef = smSmooth;
|
|
|
|
{ Default value for the @link(TKCustomGrid.SizingStyle) property. }
|
|
cSizingStyleDef = ssUpdate;
|
|
|
|
{ Default value for the @link(TKCustomGrid.SortStyle) property. }
|
|
cSortStyleDef = ssDownUp;
|
|
|
|
{ Default value for the @link(TKGridColors.CellBkGnd) color property. }
|
|
cCellBkGndDef = clWindow;
|
|
{ Default value for the @link(TKGridColors.CellLines) color property. }
|
|
cCellLinesDef = clBtnFace;
|
|
{ Default value for the @link(TKGridColors.CellText) color property. }
|
|
cCellTextDef = clWindowText;
|
|
{ Default value for the @link(TKGridColors.DragSuggestionBkGnd) color property. }
|
|
cDragSuggestionBkGndDef = clLime;
|
|
{ Default value for the @link(TKGridColors.DragSuggestionLine) color property. }
|
|
cDragSuggestionLineDef = clBlack;
|
|
{ Default value for the @link(TKGridColors.FixedCellBkGnd) color property. }
|
|
cFixedCellBkGndDef = clBtnFace;
|
|
{ Default value for the @link(TKGridColors.FixedCellIndication) color property. }
|
|
cFixedCellIndicationDef = clCream;
|
|
{ Default value for the @link(TKGridColors.FixedCellLines) color property. }
|
|
cFixedCellLinesDef = clWindowText;
|
|
{ Default value for the @link(TKGridColors.FixedCellText) color property. }
|
|
cFixedCellTextDef = clBtnText;
|
|
{ Default value for the @link(TKGridColors.FixedThemedCellLines) color property. }
|
|
cFixedThemedCellLinesDef = {$IFDEF USE_WINAPI}clBtnShadow{$ELSE}clWindowText{$ENDIF};
|
|
{ Default value for the @link(TKGridColors.FixedThemedCellHighlight) color property. }
|
|
cFixedThemedCellHighlightDef = clBtnHighlight;
|
|
{ Default value for the @link(TKGridColors.FixedThemedCellShadow) color property. }
|
|
cFixedThemedCellShadowDef = clBtnFace;
|
|
{ Default value for the @link(TKGridColors.FocusedCellBkGnd) color property. }
|
|
cFocusedCellBkGndDef = clHighlight;
|
|
{ Default value for the @link(TKGridColors.FocusedCellText) color property. }
|
|
cFocusedCellTextDef = clHighlightText;
|
|
{ Default value for the @link(TKGridColors.FocusedRangeBkgnd) color property. }
|
|
cFocusedRangeBkGndDef = clHighlight; // to be brigtened
|
|
{ Default value for the @link(TKGridColors.FocusedRangeText) color property. }
|
|
cFocusedRangeTextDef = clHighlightText;
|
|
{ Default value for the @link(TKGridColors.SelectedCellBkGnd) color property. }
|
|
cSelectedCellBkGndDef = clBtnFace;
|
|
{ Default value for the @link(TKGridColors.SelectedCellText) color property. }
|
|
cSelectedCellTextDef = clBtnText;
|
|
{ Default value for the @link(TKGridColors.SelectedRangeBkGnd) color property. }
|
|
cSelectedRangeBkGndDef = clBtnFace; // to be brigtened
|
|
{ Default value for the @link(TKGridColors.SelectedRangeText) color property. }
|
|
cSelectedRangeTextDef = clBtnText;
|
|
// aki:
|
|
{ Default value for then @link(TKGridColors.SelectedFixedCell) color property. }
|
|
cSelectedFixedCellBkGndDef = clCream;
|
|
{ Index for the @link(TKGridColors.CellBkGnd) property. }
|
|
ciCellBkGnd = TKGridColorIndex(0);
|
|
{ Index for the @link(TKGridColors.CellLines) property. }
|
|
ciCellLines = TKGridColorIndex(1);
|
|
{ Index for the @link(TKGridColors.CellText) property. }
|
|
ciCellText = TKGridColorIndex(2);
|
|
{ Index for the @link(TKGridColors.DragSuggestionBkGnd) property. }
|
|
ciDragSuggestionBkGnd = TKGridColorIndex(3);
|
|
{ Index for the @link(TKGridColors.DragSuggestionLine) property. }
|
|
ciDragSuggestionLine = TKGridColorIndex(4);
|
|
{ Index for the @link(TKGridColors.FixedCellBkGnd) property. }
|
|
ciFixedCellBkGnd = TKGridColorIndex(5);
|
|
{ Index for the @link(TKGridColors.FixedCellIndication) property. }
|
|
ciFixedCellIndication = TKGridColorIndex(6);
|
|
{ Index for the @link(TKGridColors.FixedCellLines) property. }
|
|
ciFixedCellLines = TKGridColorIndex(7);
|
|
{ Index for the @link(TKGridColors.FixedCellText) property. }
|
|
ciFixedCellText = TKGridColorIndex(8);
|
|
{ Index for the @link(TKGridColors.FixedThemedCellLines) property. }
|
|
ciFixedThemedCellLines = TKGridColorIndex(9);
|
|
{ Index for the @link(TKGridColors.FixedThemedCellHighlight) property. }
|
|
ciFixedThemedCellHighlight = TKGridColorIndex(10);
|
|
{ Index for the @link(TKGridColors.FixedThemedCellShadow) property. }
|
|
ciFixedThemedCellShadow = TKGridColorIndex(11);
|
|
{ Index for the @link(TKGridColors.FocusedCellBkGnd) property. }
|
|
ciFocusedCellBkGnd = TKGridColorIndex(12);
|
|
{ Index for the @link(TKGridColors.FocusedCellText) property. }
|
|
ciFocusedCellText = TKGridColorIndex(13);
|
|
{ Index for the @link(TKGridColors.FocusedRangeBkGnd) property. }
|
|
ciFocusedRangeBkGnd = TKGridColorIndex(14);
|
|
{ Index for the @link(TKGridColors.FocusedRangeText) property. }
|
|
ciFocusedRangeText = TKGridColorIndex(15);
|
|
{ Index for the @link(TKGridColors.SelectedCellBkGnd) property. }
|
|
ciSelectedCellBkGnd = TKGridColorIndex(16);
|
|
{ Index for the @link(TKGridColors.SelectedCellText) property. }
|
|
ciSelectedCellText = TKGridColorIndex(17);
|
|
{ Index for the @link(TKGridColors.SelectedRangeBkGnd) property. }
|
|
ciSelectedRangeBkGnd = TKGridColorIndex(18);
|
|
{ Index for the @link(TKGridColors.SelectedRangeText) property. }
|
|
ciSelectedRangeText = TKGridColorIndex(19);
|
|
// aki:
|
|
{ Index for the @link(TKGridColors.SelectedFixedCell) property. }
|
|
ciSelectedFixedCellBkGnd = TKGridColorIndex(20);
|
|
// aki:
|
|
{ Maximum color array index }
|
|
ciGridColorsMax = ciSelectedFixedCellBkGnd;
|
|
|
|
{ This internal flag is set if caret should be moved to the left side of the inplace editor. }
|
|
cGF_CaretToLeft = $00000001;
|
|
{ This internal flag is set if the Set.. methods in @link(TKGridAxisItem) and
|
|
@link(TKGridCell) and their descendants must not call any grid methods that
|
|
could cause infinite recursion. }
|
|
cGF_GridUpdates = $00000002;
|
|
{ This internal flag is set to allow column or row sizing at design time. }
|
|
cGF_DesignHitTest = $00000004;
|
|
{ This internal flag is set to prevent recursive calls while inplace editor is being updated. }
|
|
cGF_EditorUpdating = $00000008;
|
|
{ This internal flag is set to remember inplace editor state if the grid
|
|
has no input focus. }
|
|
cGF_EditorModeActive = $00000010;
|
|
{ This internal flag is set if a cell is selected by mouse click. }
|
|
cGF_SelectedByMouse = $00000020;
|
|
{ This internal flag is set if a cell is 'through-clicked'. }
|
|
cGF_ThroughClick = $00000040;
|
|
{ This internal flag is set if a selectable grid area contains at least 1 merged cell. }
|
|
cGF_SelCellsMerged = $00000080;
|
|
{ This internal flag is set if enter key has been pressed and handled by the grid. }
|
|
cGF_EnterPressed = $00000100;
|
|
|
|
type
|
|
TKCustomGrid = class;
|
|
TKGridCell = class;
|
|
|
|
{ @abstract(Declares event handler for the @link(TKCustomGrid.OnCompareCellInstances))
|
|
<UL>
|
|
<LH>Parameters:</LH>
|
|
<LI><I>Sender</I> - identifies the event caller.</LI>
|
|
<LI><I>Cell1</I> - pointer to the first cell</LI>
|
|
<LI><I>Cell2</I> - pointer to the second cell</LI>
|
|
</UL>
|
|
<UL>
|
|
<LH>Returns:</LH>
|
|
<LI>Negative value (<0) if the value of the first cell is lower than
|
|
the value of the second cell.</LI>
|
|
<LI>Positive value (>0) if the value of the first cell is greater than
|
|
the value of the second cell.</LI>
|
|
<LI>Zero if values of both cells are the same.</LI>
|
|
</UL> }
|
|
TKGridCompareCellInstancesEvent = function(Sender: TObject; Cell1, Cell2: TKGridCell):
|
|
Integer of object;
|
|
|
|
{ @abstract(Base class to store column or row properties)
|
|
This is the base class for storing column or row properties.
|
|
It implements properties and methods that are common for columns and rows. }
|
|
TKGridAxisItem = class(TObject)
|
|
private
|
|
FCanResize: Boolean;
|
|
FExtent: Integer;
|
|
FGrid: TKCustomGrid;
|
|
FInitialPos: Integer;
|
|
FMaxExtent: Integer;
|
|
FMinExtent: Integer;
|
|
FSortArrowIndex: Integer;
|
|
FSortMode: TKGridSortMode;
|
|
FTag: TObject;
|
|
procedure SetMaxExtent(AValue: Integer);
|
|
procedure SetMinExtent(AValue: Integer);
|
|
protected
|
|
FBackExtent: Integer;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnBeginColDrag) or @link(TKCustomGrid.OnBeginRowDrag)
|
|
events. See the @link(TKGridBeginDragEvent) type for parameter interpretation. }
|
|
procedure BeginDrag(var Origin: Integer; const MousePt: TPoint;
|
|
var CanBeginDrag: Boolean); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnCheckColDrag) or @link(TKCustomGrid.OnCheckRowDrag)
|
|
events. See the @link(TKGridCheckDragEvent) type for parameter interpretation. }
|
|
procedure CheckDrag(Origin: Integer; var Destination: Integer;
|
|
const MousePt: TPoint; var CanDrop: Boolean); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEndColDrag) or @link(TKCustomGrid.OnEndRowDrag)
|
|
events. See the @link(TKGridEndDragEvent) type for parameter interpretation. }
|
|
procedure EndDrag(Origin, Destination: Integer; const MousePt: TPoint;
|
|
var CanEndDrag: Boolean); virtual;
|
|
{ Read method for the @link(TKGridAxisItem.Objects) property. Without implementation. }
|
|
function GetObjects(Index: Integer): TObject; virtual; abstract;
|
|
{ Read method for the @link(TKGridAxisItem.Strings) property. Without implementation. }
|
|
function GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; virtual; abstract;
|
|
{ Read method for the @link(TKGridAxisItem.Visible) property. Without implementation. }
|
|
function GetVisible: Boolean; virtual;
|
|
{ Write method for the @link(TKGridAxisItem.Extent) property. Without implementation. }
|
|
procedure SetExtent(const Value: Integer); virtual; abstract;
|
|
{ Write method for the @link(TKGridAxisItem.Objects) property. Without implementation. }
|
|
procedure SetObjects(Index: Integer; const Value: TObject); virtual; abstract;
|
|
{ Write method for the @link(TKGridAxisItem.SortArrowIndex) property. Without implementation. }
|
|
procedure SetSortArrowIndex(Value: Integer); virtual; abstract;
|
|
{ Write method for the @link(TKGridAxisItem.SortMode) property. Without implementation. }
|
|
procedure SetSortMode(const Value: TKGridSortMode); virtual; abstract;
|
|
{ Write method for the @link(TKGridAxisItem.Strings) property. Without implementation. }
|
|
procedure SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); virtual; abstract;
|
|
{ Write method for the @link(TKGridAxisItem.Visible) property. Without implementation. }
|
|
procedure SetVisible(Value: Boolean); virtual; abstract;
|
|
public
|
|
{ Creates the instance. Do not create custom instances. All necessary
|
|
TKGridAxisItem instances are created automatically by TKCustomGrid. }
|
|
constructor Create(AGrid: TKCustomGrid); virtual;
|
|
{ Copies shareable properties of another TKGridAxisItem instances into this
|
|
TKGridAxisItem instance. }
|
|
procedure Assign(Source: TKGridAxisItem); overload; virtual;
|
|
{ Makes it possible to assign a list of strings contained in TStrings
|
|
to the grid. This method is provided to retain compatibility with
|
|
TStringGrid. It behaves exactly the same way as the corresponding method
|
|
in TStringGrid. Without implementation. }
|
|
procedure Assign(Source: TStrings); overload; virtual; abstract;
|
|
{$IFDEF TKGRID_USE_JCL}
|
|
{ Makes it possible to assign a list of strings contained in TWideStrings
|
|
to the grid. Without implementation. }
|
|
procedure Assign(Source: TWideStrings); overload; virtual; abstract;
|
|
{$ENDIF}
|
|
{ Abstract prototype. Sets text of all cells corresponding to this column or row to empty string. }
|
|
procedure Clear; virtual; abstract;
|
|
{ Returns True if shareable properties of this TKGridAxisItem instance have
|
|
the same value as those in Item. }
|
|
function {$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean; virtual;
|
|
{ Shareable property. Determines if this column or row can be resized.
|
|
This property virtually covers the @link(TKCustomGrid.OnBeginColSizing) or
|
|
@link(TKCustomGrid.OnBeginRowSizing) events. }
|
|
property CanResize: Boolean read FCanResize write FCanResize;
|
|
{ Shareable property. Determines the column width or row height.
|
|
Do not write this property unless you write a TKCustomGrid descendant. }
|
|
property Extent: Integer read FExtent write SetExtent;
|
|
{ Pointer to the grid. You will probably need it when implementing application
|
|
specific behavior. }
|
|
property Grid: TKCustomgrid read FGrid;
|
|
{ Non-shareable property. Determines the initial column or row position
|
|
just after it was inserted into the grid. Do not write this property
|
|
unless you write a TKCustomGrid descendant. }
|
|
property InitialPos: Integer read FInitialPos write FInitialPos;
|
|
{ Specifies the maximum extent of this column or row. Set zero to disable check.
|
|
Does not work (cannot work) in goAlignLast... mode. }
|
|
property MaxExtent: Integer read FMaxExtent write SetMaxExtent;
|
|
{ Specifies the minimum extent of this column or row. Set zero to disable check.
|
|
This setting overrides the @link(TKCustomGrid.MinColWidth) or
|
|
@link(TKCustomGrid.MinRowHeight) setting. }
|
|
property MinExtent: Integer read FMinExtent write SetMinExtent;
|
|
{ Provides access to the object cell instances corresponding to the column or
|
|
row referred by this TKGridAxisItem instance. Provided to retain compatibility
|
|
with TStringGrid. }
|
|
property Objects[Index: Integer]: TObject read GetObjects write SetObjects;
|
|
{ Specifies the index of the fixed column or row where the sorting can be
|
|
initiated/changed by mouse click and where the sorting arrow will be displayed.
|
|
This applies only for multiline column or row headers, i.e. if there are
|
|
two or more fixed columns or rows defined. }
|
|
property SortArrowIndex: Integer read FSortArrowIndex write SetSortArrowIndex;
|
|
{ Makes it possible to sort column or row referred by this TKGridAxisItem
|
|
instance. }
|
|
property SortMode: TKGridSortMode read FSortMode write SetSortMode;
|
|
{ Provides access to the obj cell instances corresponding to the column or
|
|
row referred by this TKGridAxisItem instance. }
|
|
property Strings[Index: Integer]: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read GetStrings write SetStrings; default;
|
|
{ Shareable property. Determines if the column or row is visible. }
|
|
property Visible: Boolean read GetVisible write SetVisible;
|
|
{ Provides access to custom object for Row }
|
|
property Tag: TObject read FTag write FTag;
|
|
end;
|
|
|
|
{ @abstract(Metaclass for @link(TKGridAxisItem)) This type is used internally. }
|
|
TKGridAxisItemClass = class of TKGridAxisItem;
|
|
|
|
{ @abstract(Dynamic array type to store @link(TKGridAxisItem) instances)
|
|
There are always two arrays of this type in TKCustomGrid. First of them
|
|
stores column properties - @link(TKCustomGrid.FCols) - and the second stores
|
|
row properties - @link(TKCustomGrid.FRows). }
|
|
TKGridAxisItems = array of TKGridAxisItem;
|
|
|
|
{ @abstract(Class to store column properties)
|
|
This class implements properties and methods specific to columns. }
|
|
TKGridCol = class(TKGridAxisItem)
|
|
private
|
|
FCellHint: Boolean;
|
|
FTabStop: Boolean;
|
|
function FindCol(out Index: Integer): Boolean;
|
|
protected
|
|
{ Read method for the @link(TKGridAxisItem.Objects) property. Implementation for columns. }
|
|
function GetObjects(Index: Integer): TObject; override;
|
|
{ Read method for the @link(TKGridAxisItem.Strings) property. Implementation for columns. }
|
|
function GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; override;
|
|
{ Write method for the @link(TKGridAxisItem.Extent) property. Implementation for columns. }
|
|
procedure SetExtent(const Value: Integer); override;
|
|
{ Write method for the @link(TKGridAxisItem.Objects) property. Implementation for columns. }
|
|
procedure SetObjects(Index: Integer; const Value: TObject); override;
|
|
{ Write method for the @link(TKGridAxisItem.SortArrowIndex) property. Implementation for columns. }
|
|
procedure SetSortArrowIndex(Value: Integer); override;
|
|
{ Write method for the @link(TKGridAxisItem.SortMode) property. Implementation for columns. }
|
|
procedure SetSortMode(const Value: TKGridSortMode); override;
|
|
{ Write method for the @link(TKGridAxisItem.Strings) property. Implementation for columns. }
|
|
procedure SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); override;
|
|
{ Write method for the @link(TKGridAxisItem.Visible) property. Implementation for columns. }
|
|
procedure SetVisible(Value: Boolean); override;
|
|
public
|
|
{ Creates the instance. Do not create custom instances. All necessary
|
|
TKGridCol instances are created automatically by TKCustomGrid. }
|
|
constructor Create(AGrid: TKCustomGrid); override;
|
|
{ Copies the properties of another TKGridAxisItem instances into this
|
|
TKGridCol instance. }
|
|
procedure Assign(Source: TKGridAxisItem); override;
|
|
{ Makes it possible to assign a list of strings contained in TStrings
|
|
to the grid. It behaves exactly the same way as the corresponding method
|
|
in TStringGrid. Implementation for columns, i.e. the strings contained
|
|
in Source are copied to the text cells corresponding to the column
|
|
referred by this TKGridCol instance. }
|
|
procedure Assign(Source: TStrings); override;
|
|
{$IFDEF TKGRID_USE_JCL}
|
|
{ Makes it possible to assign a list of strings contained in TWideStrings
|
|
to the grid. Implementation for columns, i.e. the strings contained
|
|
in Source are copied to the text cells corresponding to the column
|
|
referred by this TKGridCol instance. }
|
|
procedure Assign(Source: TWideStrings); override;
|
|
{$ENDIF}
|
|
{ Sets text of all cells corresponding to this column to empty string. }
|
|
procedure Clear; override;
|
|
{ Returns True if shareable properties of this TKGridAxisItem instance have
|
|
the same value as those in Item. }
|
|
function {$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean; override;
|
|
{ Shareable property. Determines if cell hint is enabled for this column. }
|
|
property CellHint: Boolean read FCellHint write FCellHint;
|
|
{ Shareable property. Determines if pressing the TAB or Shift+TAB key can
|
|
move the input focus at a cell that belongs to this column. This property
|
|
has effect only if goTabs is present under @link(TKCustomGrid.Options). }
|
|
property TabStop: Boolean read FTabStop write FTabStop;
|
|
end;
|
|
|
|
{ @abstract(Metaclass for @link(TKGridCol)) This type is used in
|
|
@link(TKCustomGrid.ColClass) property. }
|
|
TKGridColClass = class of TKGridCol;
|
|
|
|
{ @abstract(Class to store row properties)
|
|
This class implements properties and methods specific to rows. }
|
|
TKGridRow = class(TKGridAxisItem)
|
|
private
|
|
function FindRow(out Index: Integer): Boolean;
|
|
protected
|
|
{ Read method for the @link(TKGridAxisItem.Objects) property. Implementation for rows. }
|
|
function GetObjects(Index: Integer): TObject; override;
|
|
{ Read method for the @link(TKGridAxisItem.Strings) property. Implementation for rows. }
|
|
function GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; override;
|
|
{ Write method for the @link(TKGridAxisItem.Extent) property. Implementation for rows. }
|
|
procedure SetExtent(const Value: Integer); override;
|
|
{ Write method for the @link(TKGridAxisItem.Objects) property. Implementation for rows. }
|
|
procedure SetObjects(Index: Integer; const Value: TObject); override;
|
|
{ Write method for the @link(TKGridAxisItem.SortArrowIndex) property. Implementation for rows. }
|
|
procedure SetSortArrowIndex(Value: Integer); override;
|
|
{ Write method for the @link(TKGridAxisItem.SortMode) property. Implementation for rows. }
|
|
procedure SetSortMode(const Value: TKGridSortMode); override;
|
|
{ Write method for the @link(TKGridAxisItem.Strings) property. Implementation for rows. }
|
|
procedure SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); override;
|
|
{ Write method for the @link(TKGridAxisItem.Visible) property. Implementation for rows. }
|
|
procedure SetVisible(Value: Boolean); override;
|
|
public
|
|
{ Creates the instance. Do not create custom instances. All necessary
|
|
TKGridRow instances are created automatically by TKCustomGrid. }
|
|
constructor Create(AGrid: TKCustomGrid); override;
|
|
{ Sets text of all cells corresponding to this row to empty string. }
|
|
procedure Clear; override;
|
|
{ Makes it possible to assign a list of strings contained in TStrings
|
|
to the grid. It behaves exactly the same way as the corresponding method
|
|
in TStringGrid. Implementation for rows, i.e. the strings contained
|
|
in Source are copied to the text cells corresponding to the row
|
|
referred by this TKGridRow instance. }
|
|
procedure Assign(Source: TStrings); override;
|
|
{$IFDEF TKGRID_USE_JCL}
|
|
{ Makes it possible to assign a list of strings contained in TWideStrings
|
|
to the grid. Implementation for rows, i.e. the strings contained
|
|
in Source are copied to the text cells corresponding to the row
|
|
referred by this TKGridRow instance. }
|
|
procedure Assign(Source: TWideStrings); override;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{ @abstract(Metaclass for @link(TKGridRow)) This type is used in
|
|
@link(TKCustomGrid.RowClass) property. }
|
|
TKGridRowClass = class of TKGridRow;
|
|
|
|
{ @abstract(Base class to store cell properties)
|
|
This class implements properties and methods common to all cell classes. }
|
|
TKGridCell = class(TObject)
|
|
private
|
|
FGrid: TKCustomGrid;
|
|
FSpan: TKGridCellSpan;
|
|
procedure SetColSpan(const Value: Integer);
|
|
procedure SetRowSpan(const Value: Integer);
|
|
procedure SetSpan(const Value: TKGridCellSpan);
|
|
protected
|
|
{ Called after specific property has been updated. Default behavioor:
|
|
Searches the cell in the parent grid and invalidates the cell. You can
|
|
override this method to extend behavior. }
|
|
procedure AfterUpdate; virtual; // formerly UpdateCell
|
|
{ Called before specific property is to be updated. }
|
|
procedure BeforeUpdate; virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnDrawCell).
|
|
Fills ARect with predefined Brush. }
|
|
procedure DrawCell(ACol, ARow: Integer; const ARect: TRect;
|
|
State: TKGridDrawState); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorCreate).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorCreate). }
|
|
procedure EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorDataFromGrid).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorDataFromGrid). }
|
|
procedure EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var AssignText: Boolean); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorDataToGrid).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorDataToGrid). }
|
|
procedure EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var AssignText: Boolean); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorDestroy).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorDestroy). }
|
|
procedure EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorKeyPreview).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorKeyPreview). }
|
|
procedure EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var Key: Word; Shift: TShiftState; var IsGridKey: Boolean); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorResize).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorResize). }
|
|
procedure EditorResize(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var ARect: TRect); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorSelect).
|
|
The TKGridCell's implementation calls @link(TKCustomGrid.DefaultEditorSelect). }
|
|
procedure EditorSelect(AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean); virtual;
|
|
{ Searches the cell in the parent grid. }
|
|
function FindCell(out ACol, ARow: Integer): Boolean; virtual;
|
|
{ Initializes the cell data. }
|
|
procedure Initialize; virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnMeasureCell). }
|
|
procedure MeasureCell(ACol, ARow: Integer; const ARect: TRect;
|
|
State: TKGridDrawState; Priority: TKGridMeasureCellPriority;
|
|
var Extent: TPoint); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnSelectCell).
|
|
The TKGridCell's implementation does nothing. }
|
|
procedure SelectCell(ACol, ARow: Integer; var ACanSelect: Boolean);
|
|
virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnSelectionExpand).
|
|
The TKGridCell's implementation does nothing. }
|
|
procedure SelectionExpand(ACol, ARow: Integer; var ACanExpand: Boolean); virtual;
|
|
public
|
|
{ Creates the instance. You can create a custom instance and pass it
|
|
e.g. to a @link(TKCustomGrid.Cell) property. The AGrid parameter has no meaning
|
|
in this case and you may set it to nil. }
|
|
constructor Create(AGrid: TKCustomGrid); virtual;
|
|
{ Applies TKGridCell properties to the cell painter.
|
|
The TKGridCell's implementation does nothing. }
|
|
procedure ApplyDrawProperties; virtual;
|
|
{ Copies the properties of another TKGridCell instances into this
|
|
TKGridCell instance. }
|
|
procedure Assign(Source: TKGridCell); virtual;
|
|
{ Clears the cell data. }
|
|
procedure Clear;
|
|
{ Specifies the number of columns the cell should be spanned to. }
|
|
property ColSpan: Integer read FSpan.ColSpan write SetColSpan;
|
|
{ Pointer to the grid. You will probably need it when implementing application
|
|
specific behavior. }
|
|
property Grid: TKCustomgrid read FGrid;
|
|
{ Specifies the number of rows the cell should be spanned to. }
|
|
property RowSpan: Integer read FSpan.RowSpan write SetRowSpan;
|
|
{ Specifies both cell span parameters. }
|
|
property Span: TKGridCellSpan read FSpan write SetSpan;
|
|
end;
|
|
|
|
{ @abstract(Metaclass for @link(TKGridCell)) This type is used in the
|
|
@link(TKCustomGrid.CellClass) property. }
|
|
TKGridCellClass = class of TKGridCell;
|
|
|
|
{ @abstract(Dynamic array type to store row of @link(TKGridCell) instances)
|
|
This one-dimensional array stores cell properties. }
|
|
TKGridCellRow = array of TKGridCell;
|
|
|
|
{ @abstract(Dynamic array type to store the entire grid of @link(TKGridCell) instances)
|
|
This two-dimensional array stores cell properties - @link(TKCustomGrid.FCells). }
|
|
TKGridCells = array of TKGridCellRow;
|
|
|
|
{ @abstract(Class for simple textual cell)
|
|
This cell class implements properties and methods needed to display/edit a cell
|
|
with simple text. }
|
|
TKGridTextCell = class(TKGridCell)
|
|
private
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
FText: string;
|
|
function GetTextPtr: PChar;
|
|
{$ELSE}
|
|
FText: PWideChar; // WideString is slow as storage here
|
|
function GetText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
{$ENDIF}
|
|
procedure SetText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
protected
|
|
{ Assigns a new text string into this TKGridTextCell instance. The new
|
|
string will be assigned by a grow on demand method, i.e. the memory
|
|
allocated for the string can only grow within each assignment. It continues
|
|
to grow until the TKGridTextCell instance is destroyed. }
|
|
procedure AssignText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); virtual;
|
|
{ Cell class aware version of @link(TKCustomGrid.OnEditorCreate).
|
|
Creates a TEdit inplace editor. }
|
|
procedure EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl); override;
|
|
{ Initializes the cell data. }
|
|
procedure Initialize; override;
|
|
public
|
|
{ Creates the instance. See @link(TKGridCell.Create) for details. }
|
|
constructor Create(AGrid: TKCustomGrid); override;
|
|
{ Destroys the instance. See TObject.Destroy in Delphi help. }
|
|
destructor Destroy; override;
|
|
{ Applies TKGridTextCell properties to the cell painter. }
|
|
procedure ApplyDrawProperties; override;
|
|
{ Copies shareable properties of another instance that inherits from
|
|
TKGridCell into this TKGridTextCell instance. }
|
|
procedure Assign(Source: TKGridCell); override;
|
|
{ Readonly property. This is the editable text that appears in the cell -
|
|
published as pointer for fast read operations like sorting. }
|
|
property TextPtr: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF} read {$IFDEF STRING_IS_UNICODE}GetTextPtr{$ELSE}FText{$ENDIF};
|
|
{ Shareable property. This is the editable text that appears in the cell. }
|
|
property Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read {$IFDEF STRING_IS_UNICODE}FText{$ELSE}GetText{$ENDIF} write SetText;
|
|
end;
|
|
|
|
{ @abstract(Class for a textual cell with custom appearance)
|
|
This cell class implements properties and methods needed to display/edit
|
|
a textual cell with custom appearance. }
|
|
TKGridAttrTextCell = class(TKGridTextCell)
|
|
private
|
|
FAttributes: TKTextAttributes;
|
|
FBackColor: TColor;
|
|
FBrush: TBrush;
|
|
FBrushChanged: Boolean;
|
|
FFont: TFont;
|
|
FFontChanged: Boolean;
|
|
FHAlign: TKHAlign;
|
|
FHPadding: Integer;
|
|
FVAlign: TKVAlign;
|
|
FVPadding: Integer;
|
|
procedure SetAttributes(const AValue: TKTextAttributes);
|
|
procedure SetFHAlign(const Value: TKHAlign);
|
|
procedure SetFHPadding(const Value: Integer);
|
|
procedure SetFVAlign(const Value: TKVAlign);
|
|
procedure SetFVPadding(const Value: Integer);
|
|
procedure SetBackColor(const Value: TColor);
|
|
protected
|
|
{ Called from FFont.OnChange. Sets FontChanged to True. }
|
|
procedure FontChange(Sender: TObject);
|
|
{ Called from FBrush.OnChange. Sets BrushChanged to True. }
|
|
procedure BrushChange(Sender: TObject);
|
|
{ Initializes the cell data. }
|
|
procedure Initialize; override;
|
|
public
|
|
{ Creates the instance. See @link(TKGridCell.Create) for details. }
|
|
constructor Create(AGrid: TKCustomGrid); override;
|
|
{ Destroys the instance. See TObject.Destroy in Delphi help. }
|
|
destructor Destroy; override;
|
|
{ Applies TKGridAttrTextCell properties to the cell painter. }
|
|
procedure ApplyDrawProperties; override;
|
|
{ Copies shareable properties of another instance that inherits from
|
|
TKGridCell into this TKGridAttrTextCell instance. }
|
|
procedure Assign(Source: TKGridCell); override;
|
|
{ Shareable property. These are the text attributes to render the text. }
|
|
property Attributes: TKTextAttributes read FAttributes write SetAttributes;
|
|
{ Shareable property. This is the color used to fill the gaps between
|
|
a non solid @link(TKGridAttrTextCell.Brush). }
|
|
property BackColor: TColor read FBackColor write SetBackColor;
|
|
{ Shareable property. This is the brush that will be used to fill the cell background. }
|
|
property Brush: TBrush read FBrush;
|
|
{ Non-shareable property. Returns True if Brush.OnChange occured. }
|
|
property BrushChanged: Boolean read FBrushChanged;
|
|
{ Shareable property. This is the font that will be used to render the text. }
|
|
property Font: TFont read FFont;
|
|
{ Non-shareable property. Returns True if Font.OnChange occured. }
|
|
property FontChanged: Boolean read FFontChanged;
|
|
{ Shareable property. This is the horizontal alignment
|
|
that will be used to place the text within the cell rectangle. }
|
|
property HAlign: TKHAlign read FHAlign write SetFHAlign;
|
|
{ Shareable property. This is the horizontal padding
|
|
of the text from the cell rectangle. }
|
|
property HPadding: Integer read FHPadding write SetFHPadding;
|
|
{ Shareable property. This is the vertical alignment
|
|
that will be used to place the text within the cell rectangle. }
|
|
property VAlign: TKVAlign read FVAlign write SetFVAlign;
|
|
{ Shareable property. This is the vertical padding
|
|
of the text from the cell rectangle. }
|
|
property VPadding: Integer read FVPadding write SetFVPadding;
|
|
end;
|
|
|
|
{$IFDEF TKGRIDOBJECTCELL_IS_TKGRIDATTRTEXTCELL}
|
|
{ @exclude }
|
|
TKGridObjectCellAncestor = TKGridAttrTextCell;
|
|
{$ELSE}
|
|
{$IFDEF TKGRIDOBJECTCELL_IS_TKGRIDTEXTCELL}
|
|
{ @exclude }
|
|
TKGridObjectCellAncestor = TKGridTextCell;
|
|
{$ELSE}
|
|
{ @exclude }
|
|
TKGridObjectCellAncestor = TKGridCell;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
{ @abstract(Class for an object cell)
|
|
This cell class implements properties and methods needed to store a custom
|
|
object in a cell. This class is implemented for backward compatibility
|
|
with TStringGrid. You can implement different cell classes to store any user
|
|
defined data. }
|
|
TKGridObjectCell = class(TKGridObjectCellAncestor)
|
|
private
|
|
FCellObject: TObject;
|
|
procedure SetCellObject(Value: TObject);
|
|
protected
|
|
{ Initializes the cell data. }
|
|
procedure Initialize; override;
|
|
public
|
|
{ Creates the instance. See @link(TKGridCell.Create) for details. }
|
|
constructor Create(AGrid: TKCustomGrid); override;
|
|
{ Destroys the instance. See TObject.Destroy in Delphi help. }
|
|
destructor Destroy; override;
|
|
{ Copies shareable properties of another instance that inherits from
|
|
TKGridCell into this TKGridObjectCell instance. }
|
|
procedure Assign(Source: TKGridCell); override;
|
|
{ Shareable property. This is the object stored within the cell class.
|
|
A single object instance passed to CellObject cannot be shared among multiple
|
|
cell class instances. The reason is that TObject instances do not support
|
|
Assign method, more convenient it would be to store TPersistents. }
|
|
property CellObject: TObject read FCellObject write SetCellObject;
|
|
end;
|
|
|
|
{ @abstract(Wrapper for a versatile and easily extensible cell painting engine)
|
|
Properties and methods of this class provide standard cell painting.
|
|
To adapt cell painting, you can use combinations of elementary painting
|
|
methods in the @link(TKCustomGrid.OnDrawCell) event handler or
|
|
override and adapt some high level methods of TKGridCellPainter. }
|
|
TKGridCellPainter = class(TObject)
|
|
private
|
|
FAttributes: TKTextAttributes;
|
|
FBackColor: TColor;
|
|
FBlockRect: TRect;
|
|
FButton: Boolean;
|
|
FButtonPressed: Boolean;
|
|
FCanvas: TCanvas;
|
|
FCheckBox: Boolean;
|
|
FCheckBoxHAlign: TKHAlign;
|
|
FCheckBoxHPadding: Integer;
|
|
FCheckboxState: TCheckBoxState;
|
|
FCheckBoxVAlign: TKVAlign;
|
|
FCheckBoxVPadding: Integer;
|
|
FCellPos: TPoint;
|
|
FCellRect: TRect;
|
|
FClipLock: Integer;
|
|
FCol: Integer;
|
|
FGraphic: TGraphic;
|
|
FGraphicDrawText: Boolean;
|
|
FGraphicHAlign: TKHAlign;
|
|
FGraphicHPadding: Integer;
|
|
FGraphicStretchMode: TKStretchMode;
|
|
FGraphicVAlign: TKVAlign;
|
|
FGraphicVPadding: Integer;
|
|
FGrid: TKCustomGrid;
|
|
FHotFrameOnly: Boolean;
|
|
FHAlign: TKHAlign;
|
|
FHPadding: Integer;
|
|
FRgn: HRGN;
|
|
FRow: Integer;
|
|
FSortArrow: TKAlphaBitmap;
|
|
FSortArrowHAlign: TKHAlign;
|
|
FSortArrowHPadding: Integer;
|
|
FState: TKGridDrawState;
|
|
FText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
FValidClipping: Boolean;
|
|
FVAlign: TKVAlign;
|
|
FVPadding: Integer;
|
|
function GetCheckBoxChecked: Boolean;
|
|
procedure SetCheckBox(AValue: Boolean);
|
|
procedure SetCheckBoxChecked(const Value: Boolean);
|
|
protected
|
|
{ Returns True if the grid is being printed out. }
|
|
FPrinting: Boolean;
|
|
{ High level method. Provides default behavior needed to initialize painting
|
|
of a cell. It is called automatically in @link(TKCustomGrid.PaintCell). }
|
|
procedure BeginDraw; virtual;
|
|
{ High level method. Provides default behavior needed to finalize painting
|
|
of a cell. It is called automatically in @link(TKCustomGrid.PaintCell). }
|
|
procedure EndDraw; virtual;
|
|
{ Read method for the @link(TKGridCellPainter.SortArrowWidth) property. }
|
|
function GetSortArrowWidth: Integer; virtual;
|
|
{ Initializes all canvas independent attributes to default values. Called
|
|
from DefaultAttributes just before cell painting. }
|
|
procedure Initialize; virtual;
|
|
public
|
|
{ Creates the instance. Do not create custom instances. All necessary
|
|
TKGridCellPainter instances are created automatically by TKCustomGrid. }
|
|
constructor Create(AGrid: TKCustomGrid);
|
|
{ Destroys the instance. See TObject.Destroy in Delphi help. }
|
|
destructor Destroy; override;
|
|
{ Forces the drawing output to be clipped within @link(TKGridCellPainter.CellRect).
|
|
This behavior must be cancelled by @link(TKGridCellPainter.EndClip) when
|
|
no longer needed. You don't need to call BeginClip if the @link(TKCustomGrid.Options)
|
|
property already contains goClippedCells. }
|
|
function BeginClip: Boolean; virtual;
|
|
{ Calculates the checkbox position within BaseRect, if any. The position
|
|
is stored in Bounds (checkbox with padding) and Interior (checkbox without
|
|
padding). Bounds are excluded from BaseRect. }
|
|
function CellCheckBoxRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean;
|
|
{ Calculates the graphic position within BaseRect, if any. The position
|
|
is stored in Bounds (graphic with padding) and Interior (graphic without
|
|
padding). Bounds are excluded from BaseRect. }
|
|
function CellGraphicRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean;
|
|
{ Calculates the sorting arrow position within BaseRect, if any. The position
|
|
is stored in Bounds (sorting arrow with padding) and Interior (sorting arrow
|
|
without padding). Bounds are excluded from BaseRect. }
|
|
function CellSortArrowRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean;
|
|
{ Calculates the cell text horizontal and vertical extent, if any. }
|
|
function CellTextExtent(const BaseRect: TRect; out Extent: TPoint): Boolean;
|
|
{ Calculates the text position within BaseRect, if any. The position
|
|
is stored in Bounds (text with padding) and Interior (text without padding).
|
|
Bounds are excluded from BaseRect. }
|
|
function CellTextRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean;
|
|
{ Low level method. Prepares default painting attributes. Under current
|
|
implementation, DefaultAttributes applies default colors to the
|
|
@link(TKGridCellPainter.Canvas)'s Brush and Font properties. }
|
|
procedure DefaultAttributes; virtual;
|
|
{ Highest level method. Provides default painting of any cell. You should call
|
|
DefaultDraw when implementing the @link(TKCustomGrid.OnDrawCell) event handler
|
|
unless any specific cell painting is required. This method supersedes
|
|
the obsolete @link(DefaultDrawCell) function. }
|
|
procedure DefaultDraw; virtual;
|
|
{ Returns the combination of edge masks (BF_...) to paint a fixed cell
|
|
correctly in old TCustomGrid style or if no OS themes are available. }
|
|
function DefaultEdges: Cardinal; virtual;
|
|
{ Highest level method. Provides default cell extent calculation. }
|
|
function DefaultMeasure(Priority: TKGridMeasureCellPriority): TPoint; virtual;
|
|
{ Low level method. Paints common parts of a themed and non-themed cell. }
|
|
procedure DrawCellCommon; virtual;
|
|
{ Low level method. Paints button frame. }
|
|
procedure DrawCellButton(Bounds: TRect);
|
|
{ Low level method. Paints checkbox frame. }
|
|
procedure DrawCellCheckBox(const Bounds, Interior: TRect);
|
|
{ Low level method. Paints the graphic (if any) within the rectangle specified by Interior.
|
|
Fills the rectangle specified by Bounds with current brush. }
|
|
procedure DrawCellGraphic(const Bounds, Interior: TRect);
|
|
{ Low level method. Paints the sort arrow within the rectangle specified by Interior.
|
|
Fills the rectangle specified by Bounds with current brush. }
|
|
procedure DrawCellSortArrow(const Bounds, Interior: TRect);
|
|
{ Low level method. Paints a button frame. }
|
|
procedure DrawButtonFrame(const ARect: TRect); virtual;
|
|
{ Low level method. Paints a check box frame. }
|
|
procedure DrawCheckBoxFrame(const ARect: TRect); virtual;
|
|
{ Low level method. Paints cell text. }
|
|
procedure DrawCellText(var ARect: TRect); virtual;
|
|
{ Low level method. Paints a standard focus rectangle around the focused
|
|
cell. }
|
|
procedure DrawCellFocus(const ARect: TRect; SkipTest: Boolean = False); virtual;
|
|
{ High level method. Paints an empty cell, i.e. only fills the cell background. }
|
|
procedure DrawEmptyCell; virtual;
|
|
{ High level method. Paints a non themed fixed cell. }
|
|
procedure DrawFixedCell; virtual;
|
|
{ Low level method. Paints fixed cell background. }
|
|
procedure DrawFixedCellBackground(const ARect: TRect); virtual;
|
|
{ Low level method. Paints non-themed fixed cell background. }
|
|
procedure DrawFixedCellNonThemedBackground(const ARect: TRect); virtual;
|
|
{ High level method. Paints a fixed cell in Windows Header style. }
|
|
procedure DrawHeaderCell; virtual;
|
|
{ Low level method. Paints header background. }
|
|
procedure DrawHeaderCellBackground(const ARect: TRect);
|
|
{ Low level method. Paints selection background frame. }
|
|
procedure DrawNormalCellBackground(const ARect: TRect); virtual;
|
|
{ High level method. Paints a selectable cell. }
|
|
procedure DrawSelectableCell; virtual;
|
|
{ Low level method. Paints selection background frame. }
|
|
procedure DrawSelectedCellBackground(const ARect: TRect; RClip: PRect = nil); virtual;
|
|
{ High level method. Paints a themed fixed cell. }
|
|
procedure DrawThemedFixedCell; virtual;
|
|
{ High level method. Paints a themed fixed cell in Windows Header style. }
|
|
procedure DrawThemedHeaderCell; virtual;
|
|
{ Restores normal drawing output after previous
|
|
@link(TKGridCellPainter.BeginClip) call. }
|
|
procedure EndClip; virtual;
|
|
{ Specifies the text attributes used to render the cell text. }
|
|
property Attributes: TKTextAttributes read FAttributes write FAttributes;
|
|
{ Specifies the color used to fill the gaps if the Brush
|
|
referred by @link(TKGridCellPainter.Canvas) is not solid brush. }
|
|
property BackColor: TColor read FBackColor write FBackColor;
|
|
{ Specifies the bounding rectangle of block of cells. This value can be given
|
|
either in TKCustomGrid's client coordinates or, in @link(goDoubleBufferedCells)
|
|
mode, relative to @link(TKGridCellPainter.CellPos). }
|
|
property BlockRect: TRect read FBlockRect write FBlockRect;
|
|
{ Determines if a standard button frame should be painted for a selectable
|
|
cell. To paint a button frame, you need to implement the @link(OnDrawCell)
|
|
event handler, set Button to True and call @link(TKGridCellPainter.DefaultDraw),
|
|
which ensures correct painting of a button frame. }
|
|
property Button: Boolean read FButton write FButton;
|
|
{ Specifies if the button frame should be painted in pressed or released (normal)
|
|
state. This property has no effect unless @link(TKGridCellPainter.Button)
|
|
is True. }
|
|
property ButtonChecked: Boolean read FButtonPressed write FButtonPressed;
|
|
{ Identifies the Canvas where the cell will be painted to. The value of this
|
|
property is either equal to TKCustomGrid.@link(TKCustomGrid.Canvas) or, in
|
|
@link(goDoubleBufferedCells) mode, equal to a memory device context whose
|
|
dimensions correspond to the size of the cell. When implementing the
|
|
@link(OnDrawCell) event handler, you can paint to TKCustomGrid.Canvas as
|
|
usual in TStringGrid. However, if you wish to use goDoubleBufferedCells,
|
|
you must paint to TKGridCellPainter.Canvas. }
|
|
property Canvas: TCanvas read FCanvas write FCanvas;
|
|
{ Determines if a standard check box frame should be painted for a selectable
|
|
cell. To paint a check box frame, you need to implement the @link(OnDrawCell)
|
|
event handler, set CheckBox to True and call @link(TKGridCellPainter.DefaultDraw),
|
|
which ensures correct painting of a check box frame. }
|
|
property CheckBox: Boolean read FCheckBox write SetCheckBox;
|
|
{ Specifies if the check box frame should be painted in checked or unchecked
|
|
state. This property is for backward compatibility and has no effect unless
|
|
@link(TKGridCellPainter.CheckBox) is True. For new designs use the CheckBoxState property. }
|
|
property CheckBoxChecked: Boolean read GetCheckBoxChecked write SetCheckBoxChecked;
|
|
{ Specifies the horizontal padding for the sorting arrow. }
|
|
property CheckBoxHAlign: TKHAlign read FCheckBoxHAlign write FCheckBoxHAlign;
|
|
{ Specifies the horizontal padding for the sorting arrow. }
|
|
property CheckBoxHPadding: Integer read FCheckBoxHPadding write FCheckBoxHPadding;
|
|
{ Specifies if the check box frame should be painted in checked, grayed
|
|
or unchecked state. This property has no effect unless
|
|
@link(TKGridCellPainter.CheckBox) is True. Added by Karol Schmidt }
|
|
property CheckboxState: TCheckBoxState read FCheckboxState write FCheckboxState;
|
|
{ Specifies the vertical padding for the sorting arrow. }
|
|
property CheckBoxVAlign: TKVAlign read FCheckBoxVAlign write FCheckBoxVAlign;
|
|
{ Specifies the vertical padding for the sorting arrow. }
|
|
property CheckBoxVPadding: Integer read FCheckBoxVPadding write FCheckBoxVPadding;
|
|
{ Specifies the left and top position/origin of the cell in TKCustomGrid's client
|
|
coordinates. }
|
|
property CellPos: TPoint read FCellPos write FCellPos;
|
|
{ Specifies the bounding rectangle of the cell. This value can be given
|
|
either in TKCustomGrid's client coordinates or, in @link(goDoubleBufferedCells)
|
|
mode, relative to @link(TKGridCellPainter.CellPos). }
|
|
property CellRect: TRect read FCellRect write FCellRect;
|
|
{ Specifies the column index of the cell. }
|
|
property Col: Integer read FCol write FCol;
|
|
{ Specifies the image that should be drawn in the cell. }
|
|
property Graphic: TGraphic read FGraphic write FGraphic;
|
|
{ Specifies if the text should appear next to the image. }
|
|
property GraphicDrawText: Boolean read FGraphicDrawText write FGraphicDrawText;
|
|
{ Specifies the horizontal alignment for the image. }
|
|
property GraphicHAlign: TKHAlign read FGraphicHAlign write FGraphicHAlign;
|
|
{ Specifies the horizontal padding for the image. }
|
|
property GraphicHPadding: Integer read FGraphicHPadding write FGraphicHPadding;
|
|
{ Specifies if the the image should be stretched within the cell (aspect ratio is preserved). }
|
|
property GraphicStretchMode: TKStretchMode read FGraphicStretchMode write FGraphicStretchMode;
|
|
{ Specifies the vertical alignment for the image. }
|
|
property GraphicVAlign: TKVAlign read FGraphicVAlign write FGraphicVAlign;
|
|
{ Specifies the vertical padding for the image. }
|
|
property GraphicVPadding: Integer read FGraphicVPadding write FGraphicVPadding;
|
|
{ Specifies the calling grid. }
|
|
property Grid: TKCustomGrid read FGrid;
|
|
{ This is the default horizontal alignment that will be used to place the text
|
|
within the cell rectangle. }
|
|
property HAlign: TKHAlign read FHAlign write FHAlign;
|
|
{ When true, a check box frame etc. is only painted "hot" when mouse cursor is
|
|
over that frame. When false, it is painted "hot" when mouse cursor is over
|
|
entire cell. }
|
|
property HotFrameOnly: Boolean read FHotFrameOnly write FHotFrameOnly;
|
|
{ This is the default horizontal padding for the text. }
|
|
property HPadding: Integer read FHPadding write FHPadding;
|
|
{ Returns True if the grid is being printed out. Needed e.g. for font height
|
|
adjstment while printing. }
|
|
property Printing: Boolean read FPrinting;
|
|
{ Specifies the row index of the cell. }
|
|
property Row: Integer read FRow write FRow;
|
|
{ Returns the width of the sorting arrow glyph. This value can be either zero
|
|
if no sorting arrow should be drawn for the cell (most cases), or a width
|
|
of the glyph for column/row sorting. }
|
|
property SortArrowWidth: Integer read GetSortArrowWidth;
|
|
{ Specifies the horizontal padding for the check box. }
|
|
property SortArrowHAlign: TKHAlign read FSortArrowHAlign write FSortArrowHAlign;
|
|
{ Specifies the horizontal padding for the sorting arrow. }
|
|
property SortArrowHPadding: Integer read FSortArrowHPadding write FSortArrowHPadding;
|
|
{ Specifies the draw state of the cell. }
|
|
property State: TKGridDrawState read FState write FState;
|
|
{ Specifies the text that appears in the cell. }
|
|
property Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read FText write FText;
|
|
{ This is the default vertical alignment that will be used to place the text
|
|
within the cell rectangle. }
|
|
property VAlign: TKVAlign read FVAlign write FVAlign;
|
|
{ This is the default vertical padding for the text. }
|
|
property VPadding: Integer read FVPadding write FVPadding;
|
|
end;
|
|
|
|
{ @abstract(Metaclass for @link(TKGridCellPainter)) This type is used in the
|
|
@link(TKCustomGrid.CellPainterClass) property. }
|
|
TKGridCellPainterClass = class of TKGridCellPainter;
|
|
|
|
{ @abstract(Container for all colors used by @link(TKCustomGrid) class)
|
|
This container allows to group many colors into one item in object inspector.
|
|
Colors are accessible via published properties or several public Color*
|
|
properties. }
|
|
TKGridColors = class(TPersistent)
|
|
private
|
|
FGrid: TKCustomGrid;
|
|
FBrightRangeBkGnd: Boolean;
|
|
FColorScheme: TKGridColorScheme;
|
|
function GetColor(Index: TKGridColorIndex): TColor;
|
|
function GetColorEx(Index: TKGridColorIndex): TColor;
|
|
procedure SetColor(Index: TKGridColorIndex; Value: TColor);
|
|
procedure SetColorEx(Index: TKGridColorIndex; Value: TColor);
|
|
procedure SetColors(const Value: TKColorArray);
|
|
protected
|
|
FBrightColors: TKColorArray;
|
|
FColors: TKColorArray;
|
|
{ Initializes the color array. }
|
|
procedure Initialize; virtual;
|
|
{ Returns the specific color according to ColorScheme. }
|
|
function InternalGetColor(Index: TKGridColorIndex): TColor; virtual;
|
|
{ Replaces the specific color. }
|
|
procedure InternalSetColor(Index: TKGridColorIndex; Value: TColor); virtual;
|
|
public
|
|
{ Creates the instance. You can create a custom instance and pass it
|
|
e.g. to a @link(TKCustomGrid.Colors) property. The AGrid parameter has no meaning
|
|
in this case and you may set it to nil. }
|
|
constructor Create(AGrid: TKCustomGrid);
|
|
{ Copies the properties of another instance that inherits from
|
|
TPersistent into this TKGridColors instance. }
|
|
procedure Assign(Source: TPersistent); override;
|
|
{ Ensures cell range background colors will be brightened if specified by
|
|
@link(TKGridColors.BrightRangeBkGnd). }
|
|
procedure BrightRangeBkGnds;
|
|
{ Clears cached brighter colors. }
|
|
procedure ClearBrightColors;
|
|
{ Specifies color scheme for reading of published properties - see GetColor in source code}
|
|
property ColorScheme: TKGridColorScheme read FColorScheme write FColorScheme;
|
|
{ Returns always normal color - regardless of the ColorScheme setting. }
|
|
property Color[Index: TKGridColorIndex]: TColor read GetColorEx write SetColorEx;
|
|
{ Returns array of normal colors. }
|
|
property Colors: TKColorArray read FColors write SetColors;
|
|
published
|
|
{ Specifies if cell range colors should be brightened from focused cell colors. }
|
|
property BrightRangeBkGnd: Boolean read FBrightRangeBkGnd write FBrightRangeBkGnd default True;
|
|
{ Background color for non-fixed cells. }
|
|
property CellBkGnd: TColor index ciCellBkGnd read GetColor write SetColor default cCellBkGndDef;
|
|
{ Color for lines around non-fixed cells. }
|
|
property CellLines: TColor index ciCellLines read GetColor write SetColor default cCellLinesDef;
|
|
{ Text color for non-fixed cells. }
|
|
property CellText: TColor index ciCellText read GetColor write SetColor default cCellTextDef;
|
|
{ Background color for drag suggestion stroke. }
|
|
property DragSuggestionBkGnd: TColor index ciDragSuggestionBkGnd read GetColor write SetColor default cDragSuggestionBkGndDef;
|
|
{ Line color for drag suggestion stroke. }
|
|
property DragSuggestionLine: TColor index ciDragSuggestionLine read GetColor write SetColor default cDragSuggestionLineDef;
|
|
{ Background color for fixed cells. }
|
|
property FixedCellBkGnd: TColor index ciFixedCellBkGnd read GetColor write SetColor default cFixedCellBkGndDef;
|
|
{ Background color for fixed cells that currently indicate selection. }
|
|
property FixedCellIndication: TColor index ciFixedCellIndication read GetColor write SetColor default cFixedCellIndicationDef;
|
|
{ Color for lines around fixed cells. }
|
|
property FixedCellLines: TColor index ciFixedCellLines read GetColor write SetColor default cFixedCellLinesDef;
|
|
{ Text color for fixed cells. }
|
|
property FixedCellText: TColor index ciFixedCellText read GetColor write SetColor default cFixedCellTextDef;
|
|
{ Color for lines around fixed cells if goThemedCells is True}
|
|
property FixedThemedCellLines: TColor index ciFixedThemedCellLines read GetColor write SetColor default cFixedThemedCellLinesDef;
|
|
{ Color for 3D highlight effects for fixed cells if goThemedCells is True}
|
|
property FixedThemedCellHighlight: TColor index ciFixedThemedCellHighlight read GetColor write SetColor default cFixedThemedCellHighlightDef;
|
|
{ Color for 3D shadow effects for fixed cells if goThemedCells is True}
|
|
property FixedThemedCellShadow: TColor index ciFixedThemedCellShadow read GetColor write SetColor default cFixedThemedCellShadowDef;
|
|
{ Background color for focused cell defined by Selection.Cell1. }
|
|
property FocusedCellBkGnd: TColor index ciFocusedCellBkGnd read GetColor write SetColor default cFocusedCellBkGndDef;
|
|
{ Text color for focused cell defined by Selection.Cell1. }
|
|
property FocusedCellText: TColor index ciFocusedCellText read GetColor write SetColor default cFocusedCellTextDef;
|
|
{ Background color for another focused cells within the range or full row selection. }
|
|
property FocusedRangeBkGnd: TColor index ciFocusedRangeBkGnd read GetColor write SetColor default cFocusedRangeBkGndDef;
|
|
{ Text color for another focused cells within the range or full row selection. }
|
|
property FocusedRangeText: TColor index ciFocusedRangeText read GetColor write SetColor default cFocusedRangeTextDef;
|
|
{ Background color for selected cells defined by Selection.Cell1. }
|
|
property SelectedCellBkGnd: TColor index ciSelectedCellBkGnd read GetColor write SetColor default cSelectedCellBkGndDef;
|
|
{ Text color for selected cells defined by Selection.Cell1. }
|
|
property SelectedCellText: TColor index ciSelectedCellText read GetColor write SetColor default cSelectedCellTextDef;
|
|
{ Background color for another selected cells within the range or full row selection. }
|
|
property SelectedRangeBkGnd: TColor index ciSelectedRangeBkGnd read GetColor write SetColor default cSelectedRangeBkGndDef;
|
|
{ Text color for another selected cells within the range or full row selection. }
|
|
property SelectedRangeText: TColor index ciSelectedRangeText read GetColor write SetColor default cSelectedRangeTextDef;
|
|
// aki:
|
|
{ Background color for selected cells defined by Selection.Cell1. }
|
|
property SelectedFixedCellBkGnd: TColor index ciSelectedFixedCellBkGnd read GetColor write SetColor default cSelectedFixedCellBkGndDef;
|
|
end;
|
|
|
|
{ @abstract(KGrid base component) This is the class that you use
|
|
as the ancestor for your TKCustomGrid overrides. }
|
|
TKCustomGrid = class(TKCustomControl)
|
|
private
|
|
{$IFDEF FPC}
|
|
FFlat: Boolean;
|
|
{$ENDIF}
|
|
FCellClass: TKGridCellClass;
|
|
FCellPainter: TKGridCellPainter;
|
|
FCellPainterClass: TKGridCellPainterClass;
|
|
FColClass: TKGridColClass;
|
|
FColCount: Integer;
|
|
FDefaultColWidth: Integer;
|
|
FDefaultRowHeight: Integer;
|
|
FDisabledDrawStyle: TKGridDisabledDrawStyle;
|
|
FDragDest: Integer;
|
|
FDragOrigin: Integer;
|
|
FDragStyle: TKGridDragStyle;
|
|
FEditorTransparency: TKGridEditorTransparency;
|
|
FFixedCols: Integer;
|
|
FFixedRows: Integer;
|
|
FGridLineWidth: Integer;
|
|
FMinColWidth: Integer;
|
|
FMinRowHeight: Integer;
|
|
FMouseCellHintTime: Cardinal;
|
|
FMoveDirection: TKGridMoveDirection;
|
|
FOptions: TKGridOptions;
|
|
FOptionsEx: TKGridOptionsEx;
|
|
FRowClass: TKGridRowClass;
|
|
FRowCount: Integer;
|
|
FRangeSelectStyle: TKGridRangeSelectStyle;
|
|
FScrollBars: TScrollStyle;
|
|
FScrollModeVert: TKGridScrollMode;
|
|
FScrollModeHorz: TKGridScrollMode;
|
|
FScrollSpeed: Cardinal;
|
|
FScrollTimer: TTimer;
|
|
FSizingIndex: Integer;
|
|
FSizingDest: Integer;
|
|
FSizingStyle: TKGridSizingStyle;
|
|
FSortModeLock: Integer;
|
|
FSortStyle: TKGridSortStyle;
|
|
FThroughClick: Boolean;
|
|
FTopLeft: TKGridCoord;
|
|
FTopLeftExtent: TKGridCoord;
|
|
FOnBeginColDrag: TKGridBeginDragEvent;
|
|
FOnBeginColSizing: TKGridBeginSizingEvent;
|
|
FOnBeginRowDrag: TKGridBeginDragEvent;
|
|
FOnBeginRowSizing: TKGridBeginSizingEvent;
|
|
FOnCellSpan: TKGridCellSpanEvent;
|
|
FOnChanged: TKGridCellEvent;
|
|
FOnCheckColDrag: TKGridCheckDragEvent;
|
|
FOnCheckRowDrag: TKGridCheckDragEvent;
|
|
FOnColMoved: TKGridMovedEvent;
|
|
FOnColWidthsChanged: TNotifyEvent;
|
|
FOnColWidthsChangedEx: TKGridExtentEvent;
|
|
FOnCompareCellInstances: TKGridCompareCellInstancesEvent;
|
|
FOnCompareCells: TKGridCompareCellsEvent;
|
|
FOnCustomSortCols: TKGridCustomSortEvent;
|
|
FOnCustomSortRows: TKGridCustomSortEvent;
|
|
FOnDrawCell: TKGridDrawCellEvent;
|
|
FOnEditorCreate: TKGridEditorCreateEvent;
|
|
FOnEditorDataFromGrid: TKGridEditorDataEvent;
|
|
FOnEditorDataToGrid: TKGridEditorDataEvent;
|
|
FOnEditorDestroy: TKGridEditorDestroyEvent;
|
|
FOnEditorKeyPreview: TKGridEditorKeyPreviewEvent;
|
|
FOnEditorResize: TKGridEditorResizeEvent;
|
|
FOnEditorSelect: TKGridEditorSelectEvent;
|
|
FOnEndColDrag: TKGridEndDragEvent;
|
|
FOnEndColSizing: TKGridEndSizingEvent;
|
|
FOnEndRowDrag: TKGridEndDragEvent;
|
|
FOnEndRowSizing: TKGridEndSizingEvent;
|
|
FOnExchangeCols: TKGridExchangeEvent;
|
|
FOnExchangeRows: TKGridExchangeEvent;
|
|
FOnMeasureCell: TKGridMeasureCellEvent;
|
|
FOnMouseCellHint: TKGridCellHintEvent;
|
|
FOnMouseClickCell: TKGridCellEvent;
|
|
FOnMouseDblClickCell: TKGridCellEvent;
|
|
FOnMouseEnterCell: TKGridCellEvent;
|
|
FOnMouseLeaveCell: TKGridCellEvent;
|
|
FOnRowMoved: TKGridMovedEvent;
|
|
FOnRowHeightsChanged: TNotifyEvent;
|
|
FOnRowHeightsChangedEx: TKGridExtentEvent;
|
|
FOnSelectCell: TKGridSelectCellEvent;
|
|
FOnSelectionExpand: TKGridSelectionExpandEvent;
|
|
FOnSizeChanged: TKGridSizeChangedEvent;
|
|
FOnTopLeftChanged: TNotifyEvent;
|
|
function GetAllCellsSelected: Boolean;
|
|
function GetAllRowsSelected: Boolean;
|
|
function GetAllColsSelected: Boolean;
|
|
function GetCell(ACol, ARow: Integer): TKGridCell;
|
|
function GetCells(ACol, ARow: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
function GetCellSpan(ACol, ARow: Integer): TKGridCellSpan;
|
|
function GetCols(Index: Integer): TKGridCol;
|
|
function GetColWidths(Index: Integer): Integer;
|
|
function GetDefaultDrawing: Boolean;
|
|
function GetEditorMode: Boolean;
|
|
function GetEffectiveColSpacing(ACol: Integer): Integer;
|
|
function GetEffectiveRowSpacing(ARow: Integer): Integer;
|
|
function GetEntireColSelected(Index: Integer): Boolean;
|
|
function GetEntireSelectedColCount: Integer;
|
|
function GetEntireRowSelected(Index: Integer): Boolean;
|
|
function GetEntireSelectedRowCount: Integer;
|
|
function GetGridHeight: Integer;
|
|
function GetGridWidth: Integer;
|
|
function GetLastVisibleCol: Integer;
|
|
function GetLastVisibleRow: Integer;
|
|
function GetMoreCellsSelected: Boolean;
|
|
function GetObjects(ACol, ARow: Integer): TObject;
|
|
function GetRowHeights(Index: Integer): Integer;
|
|
function GetRows(Index: Integer): TKGridRow;
|
|
function GetSelection: TKGridRect;
|
|
function GetSelectionCount: Integer;
|
|
function GetSelectionRect: TRect;
|
|
function GetSelections(Index: Integer): TKGridRect;
|
|
function GetSortCol: Integer;
|
|
function GetSortRow: Integer;
|
|
function GetTabStops(Index: Integer): Boolean;
|
|
function GetThemedCells: Boolean;
|
|
function GetThemes: Boolean;
|
|
function GetVisibleColCount: Integer;
|
|
function GetVisibleGridRect: TKGridRect;
|
|
function GetVisibleRowCount: Integer;
|
|
procedure ReadColWidths(Reader: TReader);
|
|
procedure ReadRowHeights(Reader: TReader);
|
|
{$IFDEF FPC}
|
|
procedure SetFlat(Value: Boolean);
|
|
{$ENDIF}
|
|
procedure SetCell(ACol, ARow: Integer; Value: TKGridCell);
|
|
procedure SetCellPainterClass(Value: TKGridCellPainterClass);
|
|
procedure SetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
procedure SetCellSpan(ACol, ARow: Integer; Value: TKGridCellSpan);
|
|
procedure SetCol(Value: Integer);
|
|
procedure SetColCount(Value: Integer);
|
|
procedure SetColors(Value: TKGridColors);
|
|
procedure SetColWidths(Index: Integer; Value: Integer);
|
|
procedure SetDefaultColWidth(Value: Integer);
|
|
procedure SetDefaultDrawing(Value: Boolean);
|
|
procedure SetDefaultRowHeight(Value: Integer);
|
|
procedure SetDisabledDrawStyle(Value: TKGridDisabledDrawStyle);
|
|
procedure SetDragStyle(Value: TKGridDragStyle);
|
|
procedure SetEditorMode(Value: Boolean);
|
|
procedure SetEditorTransparency(Value: TKGridEditorTransparency);
|
|
procedure SetFixedCols(Value: Integer);
|
|
procedure SetFixedRows(Value: Integer);
|
|
procedure SetGridLineWidth(Value: Integer);
|
|
procedure SetLeftCol(Value: Integer);
|
|
procedure SetMinColWidth(Value: Integer);
|
|
procedure SetMinRowHeight(Value: Integer);
|
|
procedure SetMouseCellHintTime(const AValue: Cardinal);
|
|
procedure SetObjects(ACol, ARow: Integer; Value: TObject);
|
|
procedure SetOptions(Value: TKGridOptions);
|
|
procedure SetOptionsEx(Value: TKGridOptionsEx);
|
|
procedure SetRow(Value: Integer);
|
|
procedure SetRowCount(Value: Integer);
|
|
procedure SetRowHeights(Index: Integer; Value: Integer);
|
|
procedure SetScrollBars(Value: TScrollStyle);
|
|
procedure SetScrollModeHorz(const Value: TKGridScrollMode);
|
|
procedure SetScrollModeVert(const Value: TKGridScrollMode);
|
|
procedure SetScrollSpeed(Value: Cardinal);
|
|
procedure SetSelection(const Value: TKGridRect);
|
|
procedure SetSelections(Index: Integer; const Value: TKGridRect);
|
|
procedure SetSizingStyle(Value: TKGridSizingStyle);
|
|
procedure SetTabStops(Index: Integer; Value: Boolean);
|
|
procedure SetTopRow(Value: Integer);
|
|
procedure WriteColWidths(Writer: TWriter);
|
|
procedure WriteRowHeights(Writer: TWriter);
|
|
procedure CMDesignHitTest(var Msg: TLMMouse); message CM_DESIGNHITTEST;
|
|
procedure CMEnabledChanged(var Msg: TLMessage); message CM_ENABLEDCHANGED;
|
|
procedure CMShowingChanged(var Msg: TLMessage); message CM_SHOWINGCHANGED;
|
|
procedure CMSysColorChange(var Msg: TLMessage); message CM_SYSCOLORCHANGE;
|
|
procedure CMVisibleChanged(var Msg: TLMessage); message CM_VISIBLECHANGED;
|
|
procedure CMWantSpecialKey(var Msg: TLMKey); message CM_WANTSPECIALKEY;
|
|
procedure WMChar(var Msg: TLMChar); message LM_CHAR;
|
|
procedure WMEraseBkGnd(var Msg: TLMEraseBkGnd); message LM_ERASEBKGND;
|
|
procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE;
|
|
procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL;
|
|
procedure WMKillFocus(var Msg: TLMKillFocus); message LM_KILLFOCUS;
|
|
procedure WMSetFocus(var Msg: TLMSetFocus); message LM_SETFOCUS;
|
|
procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL;
|
|
protected
|
|
{ Gains access to the cell hint timer. }
|
|
FCellHintTimer: TTimer;
|
|
{ Two-dimensional dynamic array to store cell instances. Different cell
|
|
classes can be used for cell instances. }
|
|
FCells: TKGridCells;
|
|
{ Provides direct access to the color class for TKCustomGrid descendants }
|
|
FColors: TKGridColors;
|
|
{ Dynamic array to store column instances. Different column classes can
|
|
be used for column instances. }
|
|
FCols: TKGridAxisItems;
|
|
{ Icon for column/row moving suggestion arrow. }
|
|
FDragArrow: TKAlphaBitmap;
|
|
{ Wrapper for the window used to visually indicate a dragged column or row.
|
|
Under Win2K or later system, this is a layered window. Under Win98SE or older
|
|
system, it is a normal popup window. }
|
|
FDragWindow: TKDragWindow;
|
|
{ Copy of the cell being currently edited. }
|
|
FEditedCell: TKGridCell;
|
|
{ Provides direct access to the inplace editor instance for TKCustomGrid descendants. }
|
|
FEditor: TWinControl;
|
|
{ Specifies the current bounding rectangle of inplace editor. }
|
|
FEditorRect: TRect;
|
|
{ Specifies the current position of inplace editor. If @link(TKCustomGrid.Selection).Cell1
|
|
is different from FEditorCell, the editor needs to be updated immediatelly
|
|
to make these two values equal again. }
|
|
FEditorCell: TKGridCoord;
|
|
{ Pointer to the original WindowProc property of the inplace editor. }
|
|
FEditorWindowProc: TWndMethod;
|
|
{ Holds the mutually exclusive grid state. }
|
|
FGridState: TKGridState;
|
|
{ Glyphs for hidden cell indicators. }
|
|
FHCI: TKGridHCIBitmaps;
|
|
{ Specifies the cell hint window. }
|
|
FHint: TKHintWindow;
|
|
{ Specifies the cell where hint timer has been started. }
|
|
FHintCell: TKGridCoord;
|
|
{ Specifies the cell where left mouse button has been pressed. }
|
|
FHitCell: TKGridCoord;
|
|
{ Specifies the point where left mouse button has been pressed. }
|
|
FHitPos: TPoint;
|
|
{ Field for @link(TKCustomGrid.MaxCol) property. Descendants can modify it. }
|
|
FMaxCol: Integer;
|
|
{ Field for @link(TKCustomGrid.MaxRow) property. Descendants can modify it. }
|
|
FMaxRow: Integer;
|
|
{ Field to remember current column position for keyboard commands. }
|
|
FMemCol: Integer;
|
|
{ Field to remember current row position for keyboard commands. }
|
|
FMemRow: Integer;
|
|
{ Specifies the cell where mouse is over. FMouseOver is valid if goMouseOverCells
|
|
is included in @link(TKCustomGrid.Options). }
|
|
FMouseOver: TKGridCoord;
|
|
{ Dynamic array to store row instances. Different row classes can
|
|
be used for row instances. }
|
|
FRows: TKGridAxisItems;
|
|
{ Specifies current(topmost) selection not affected by @link(goRowSelect) as
|
|
@link(TKCustomGrid.Selection). }
|
|
FSelection: TKGridRect;
|
|
{ Specifies all selections except FSelection. This separation is done for
|
|
backward compatibility. }
|
|
FSelections: array of TKGridRect;
|
|
{ Current scrolling position in pixels (bound to cell boundary). }
|
|
FScrollPos: TPoint;
|
|
{ Current scrolling offset in pixels for smSmooth mode (relative to cell boundary). }
|
|
FScrollOffset: TPoint;
|
|
{ Auxilliary bitmap for various tasks. }
|
|
FTmpBitmap: TBitmap;
|
|
{$IFDEF FPC}
|
|
{ Temporary mouse cursor. }
|
|
FTmpCursor: TCursor;
|
|
{$ENDIF}
|
|
{ Adjusts the page setup. Ensures the PrintingMapped property is always True. }
|
|
procedure AdjustPageSetup; override;
|
|
{ Adjusts any selection rectangle specified by ASelection to be valid
|
|
selection in @link(goRowSelect) mode, i.e. makes ASelection to span
|
|
the entire row(s). }
|
|
function AdjustSelection(const ASelection: TKGridRect): TKGridRect; virtual;
|
|
{ Calls @link(TKCustomGrid.OnBeginColDrag) event handler or column class aware equivalent.
|
|
See the @link(TKGridBeginDragEvent) type for parameter interpretation. }
|
|
function BeginColDrag(var Origin: Integer; const MousePt: TPoint): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnBeginColSizing) event handler or checks the
|
|
@link(TKGridAxisItem.CanResize) property to decide whether the column can
|
|
be resized. See the @link(TKGridBeginSizingEvent) type for parameter interpretation. }
|
|
function BeginColSizing(var Index, Pos: Integer): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnBeginRowDrag) event handler or row class aware equivalent.
|
|
See the @link(TKGridBeginDragEvent) type for parameter interpretation. }
|
|
function BeginRowDrag(var Origin: Integer; const MousePt: TPoint): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnBeginRowSizing) event handler or checks the
|
|
@link(TKGridAxisItem.CanResize) property to decide whether the row can
|
|
be resized. See the @link(TKGridBeginSizingEvent) type for parameter interpretation. }
|
|
function BeginRowSizing(var Index, Pos: Integer): Boolean; virtual;
|
|
{ Cancels any dragging or resizing operations performed by mouse. }
|
|
procedure CancelMode; override;
|
|
{ This method is called periodically from the cell hint timer. }
|
|
procedure CellHintTimerHandler(Sender: TObject); virtual;
|
|
{ In a non virtual grid, this method is called after @link(TKCustomGrid.OnEditorDestroy)
|
|
if the cell content has been modified. Changed calls @link(TKCustomGrid.OnChanged)
|
|
event handler. }
|
|
procedure Changed; virtual;
|
|
{ Modifies the size of @link(FCols), @link(FRows) and @link(FCells). Updates
|
|
@link(TKCustomGrid.FixedCols), @link(TKCustomGrid.ColCount), @link(TKCustomGrid.MaxCol),
|
|
@link(TKCustomGrid.FixedRows), @link(TKCustomGrid.RowCount), @link(TKCustomGrid.MaxRow). }
|
|
procedure ChangeDataSize(ColInsert: Boolean; ColAt, ColCnt: Integer;
|
|
RowInsert: Boolean; RowAt, RowCnt: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnCheckColDrag) event handler or column class aware equivalent.
|
|
See the @link(TKGridCheckDragEvent) type for parameter interpretation. }
|
|
function CheckColDrag(Origin: Integer; var Destination: Integer;
|
|
const MousePt: TPoint): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnCheckRowDrag) event handler or row class aware equivalent.
|
|
See the @link(TKGridCheckDragEvent) type for parameter interpretation. }
|
|
function CheckRowDrag(Origin: Integer; var Destination: Integer;
|
|
const MousePt: TPoint): Boolean; virtual;
|
|
{ Forces the scrollable cell specified by ACol and ARow to become visible. }
|
|
function ClampInView(ACol, ARow: Integer): Boolean;
|
|
{ Calls @link(TKCustomGrid.OnColumnMoved) event handler.
|
|
See the @link(TKGridMovedEvent) type for parameter interpretation. }
|
|
procedure ColMoved(FromIndex, ToIndex: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnColWidthsChanged) event handler. }
|
|
procedure ColWidthsChanged(ACol: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnCompareCells) event handler for the given two cell instances. }
|
|
function CompareCellInstances(ACell1, ACell2: TKGridCell): Integer; virtual;
|
|
{ Calls @link(TKCustomGrid.OnCompareCells) event handler for the given two cells. }
|
|
function CompareCells(ACol1, ARow1, ACol2, ARow2: Integer): Integer; virtual;
|
|
{ Calls @link(TKCustomGrid.OnCompareCells) event handler for two cells
|
|
belonging to the same row identified by ARow. ACol1 and ACol2 are column
|
|
indexes of these two cells. Method is used to compare grid rows. }
|
|
function CompareCols(ARow, ACol1, ACol2: Integer): Integer; virtual;
|
|
{ Calls @link(TKCustomGrid.OnCompareCells) event handler for two cells
|
|
belonging to the same column identified by ACol. ARow1 and ARow2 are row
|
|
indexes of these two cells. Method is used to compare grid columns. }
|
|
function CompareRows(ACol, ARow1, ARow2: Integer): Integer; virtual;
|
|
{ Overriden method - see Delphi help. CreateParams defines additional styles
|
|
for the KGrid window (scrollbars etc.)}
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
{ Calls @link(TKCustomGrid.OnCustomSortCols) event handler.
|
|
See the @link(TKGridCustomSortEvent) type for parameter interpretation. }
|
|
function CustomSortCols(ByRow: Integer; var SortMode: TKGridSortMode): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnCustomSortRows) event handler.
|
|
See the @link(TKGridCustomSortEvent) type for parameter interpretation. }
|
|
function CustomSortRows(ByCol: Integer; var SortMode: TKGridSortMode): Boolean; virtual;
|
|
{ Clears all user defined column widths. }
|
|
procedure DefaultColWidthChanged; virtual;
|
|
{ Clears all user defined row heights. }
|
|
procedure DefaultRowHeightChanged; virtual;
|
|
{ Provides default behavior for an inplace editor if it's caret should be
|
|
positioned to the left side. }
|
|
procedure DefaultSetCaretToLeft(Key: Word; ShiftState: TShiftState); virtual;
|
|
{ Defines the custom properties for *.dfm streaming. }
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
{ Overriden method - see Delphi help. Responds to mouse wheel events. }
|
|
function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
|
|
{ Overriden method - see Delphi help. Responds to mouse wheel events. }
|
|
function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
|
|
{ Updates column/row dragging state if mouse is moved or scrolling is initiated by mouse.
|
|
Called from @link(TKCustomGrid.MouseMove) and @link(TKCustomGrid.ScrollTimerHandler). }
|
|
procedure DragMove(ACol, ARow: Integer; MousePt: TPoint);
|
|
{ Calls @link(TKCustomGrid.OnDrawCell) event handler or cell class aware equivalent.
|
|
See the @link(TKGridDrawCellEvent) type for parameter interpretation. }
|
|
function DrawCell(ACol, ARow: Integer; ARect: TRect;
|
|
AState: TKGridDrawState): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorCreate) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorCreateEvent) type for parameter interpretation. }
|
|
function EditorCreate(ACol, ARow: Integer): TWinControl; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorDataFromGrid) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorDataEvent) type for parameter interpretation. }
|
|
procedure EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorDataToGrid) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorDataEvent) type for parameter interpretation. }
|
|
procedure EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorDestroy) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorDestroyEvent) type for parameter interpretation. }
|
|
procedure EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer); virtual;
|
|
{ Determines if the current inplace editor should be treated as transparent
|
|
control from the grid's point of view. @link(TKCustomGrid.EditorTransparency)
|
|
has higher priority than the default behavior implemented by this method. }
|
|
function EditorIsTransparent: Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorKeyPreview) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorDataEvent) type for parameter interpretation. }
|
|
function EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var Key: Word; Shift: TShiftState): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorResize) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorResizeEvent) type for parameter interpretation. }
|
|
procedure EditorResize(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var ARect: TRect); virtual;
|
|
{ Calls @link(TKCustomGrid.OnEditorSelect) event handler or cell class aware equivalent.
|
|
See the @link(TKGridEditorSelectEvent) type for parameter interpretation. }
|
|
procedure EditorSelect(AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean); virtual;
|
|
{ EditorWindowProc is the subclassed window procedure for inplace editor. }
|
|
procedure EditorWindowProc(var Msg: TLMessage); virtual;
|
|
{ Calls @link(TKCustomGrid.OnEndColDrag) event handler or column class aware equivalent.
|
|
See the @link(TKGridEndDragEvent) type for parameter interpretation. }
|
|
function EndColDrag(Origin, Destination: Integer;
|
|
const MousePt: TPoint): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEndColSizing) event handler.
|
|
See the @link(TKGridEndSizingEvent) type for parameter interpretation. }
|
|
function EndColSizing(var Index, Pos: Integer): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEndRowDrag) event handler or row class aware equivalent.
|
|
See the @link(TKGridEndDragEvent) type for parameter interpretation. }
|
|
function EndRowDrag(Origin, Destination: Integer;
|
|
const MousePt: TPoint): Boolean; virtual;
|
|
{ Calls @link(TKCustomGrid.OnEndRowSizing) event handler.
|
|
See the @link(TKGridEndSizingEvent) type for parameter interpretation. }
|
|
function EndRowSizing(var Index, Pos: Integer): Boolean; virtual;
|
|
{ Destroys all column, row and cell instances. }
|
|
procedure FreeData;
|
|
{ Returns information structure for column or row axis. Some fields of the
|
|
Info structure must be already defined before calling this function.
|
|
See @link(TKGridAxisInfo) for details. }
|
|
procedure GetAxisInfo(var Info: TKGridAxisInfo); virtual;
|
|
{ Returns bounding rectangle where dragged column or row should appear. }
|
|
function GetDragRect(Info: TKGridAxisInfoBoth; out DragRect: TRect): Boolean; virtual;
|
|
{ Returns the combination of invisible cells that must be taken into account
|
|
for the state indicated by GridState. }
|
|
function GridStateToInvisibleCells: TKGridInvisibleCells;
|
|
{ Determines if the grid can have a horizontal scrollbar. }
|
|
function HasHorzScrollBar: Boolean; virtual;
|
|
{ Determines if the grid can have a vertical scrollbar. }
|
|
function HasVertScrollBar: Boolean; virtual;
|
|
{ Used internally to physically exchange two distinct columns. }
|
|
procedure InternalExchangeCols(Index1, Index2: Integer); virtual;
|
|
{ Used internally to physically exchange two distinct rows. }
|
|
procedure InternalExchangeRows(Index1, Index2: Integer); virtual;
|
|
{ Used internally to check if the given grid rectangle contains any merged cell areas
|
|
and if so, then expand it so that the result encloses all respective merged cells. }
|
|
function InternalExpandGridRect(const GridRect: TKGridRect): TKGridRect; virtual;
|
|
{ Retrieves the base cell if the cell given by ACol and ARow belongs to a merged cell
|
|
or returns ACol and ARow if it is a non-merged cell. }
|
|
procedure InternalFindBaseCell(ACol, ARow: Integer; out BaseCol, BaseRow: Integer); virtual;
|
|
{ Used internally to reverse the order of previously sorted rows or columns
|
|
in a fast manner, without cell comparisons. }
|
|
procedure InternalFlip(Left, Right: Integer; Exchange: TKGridExchangeProc); virtual;
|
|
{ Used internally. Returns a cell instance for the cell identified by ACol and ARow. If the
|
|
cell instance is nil, creates a new instance for the cell using
|
|
@link(TKCustomGrid.CellClass). }
|
|
function InternalGetCell(ACol, ARow: Integer): TKGridCell; virtual;
|
|
{ Returns the column span and row span for given cell. Does not perform cell validity check. }
|
|
function InternalGetCellSpan(ACol, ARow: Integer): TKGridCellSpan; virtual;
|
|
{ Returns the column width. Does not perform column validity check. }
|
|
function InternalGetColWidths(Index: Integer): Integer; virtual;
|
|
{ Returns the effective column spacing. Does not perform column validity check. }
|
|
function InternalGetEffectiveColSpacing(ACol: Integer): Integer; virtual;
|
|
{ Returns the effective row spacing. Does not perform row validity check. }
|
|
function InternalGetEffectiveRowSpacing(ARow: Integer): Integer; virtual;
|
|
{ Returns width and spacing for several cells according to given parameters. }
|
|
procedure InternalGetHExtent(AIndex, AColSpan: Integer;
|
|
out DestExtent, DestSpacing: Integer); virtual;
|
|
{ Returns the maximum column width. Does not perform column validity check. }
|
|
function InternalGetMaxColWidth(Index: Integer): Integer; virtual;
|
|
{ Returns the maximum row height. Does not perform row validity check. }
|
|
function InternalGetMaxRowHeight(Index: Integer): Integer; virtual;
|
|
{ Returns the minimum column width. Does not perform column validity check. }
|
|
function InternalGetMinColWidth(Index: Integer): Integer; virtual;
|
|
{ Returns the minimum row height. Does not perform row validity check. }
|
|
function InternalGetMinRowHeight(Index: Integer): Integer; virtual;
|
|
{ Returns the row height. Does not perform row validity check. }
|
|
function InternalGetRowHeights(Index: Integer): Integer; virtual;
|
|
{ Returns always True. }
|
|
function InternalGetSelAvail: Boolean; override;
|
|
{ Returns height and spacing for several cells according to given parameters. }
|
|
procedure InternalGetVExtent(AIndex, ARowSpan: Integer;
|
|
out DestExtent, DestSpacing: Integer); virtual;
|
|
{ Used internally by e.g. @link(TKCustomGrid.InsertSortedRow) to insert
|
|
a new row/column into previously sorted rows/column in a fast manner,
|
|
using a binary tree search. }
|
|
function InternalInsertNR(ByIndex, Left, Right: Integer;
|
|
SortedUp: Boolean; Compare: TKGridCompareProc): Integer; virtual;
|
|
{ Used internally by @link(TKCustomGrid.KeyDown) or other methods.
|
|
Modifies ACol and ARow according to Command. }
|
|
function InternalMove(var ACol, ARow: Integer; Command: TKGridMoveCommand;
|
|
Wrap, Expanding: Boolean): Boolean; virtual;
|
|
{ Used internally by @link(TKCustomGrid.UpdateSortMode) to place a modified
|
|
cell into a correct location in a sorted row or column. This is performed
|
|
in a fast manner using a binary tree search. }
|
|
function InternalInsertIfCellModifiedNR(ByIndex, Index, Left,
|
|
Right: Integer; SortedUp: Boolean; Compare: TKGridCompareProc): Integer;
|
|
{ Paints a cell identified by ACol and ARow. The cell will be painted to
|
|
ACanvas according to the draw state specified by AState into a position
|
|
specified by ARect. If ADoubleBufferedCells is True, ACanvas must be
|
|
a memory device context. PaintCell ensures the correct memory bitmap for
|
|
cell double buffering will be selected to this device context. }
|
|
procedure InternalPaintCell(ACol, ARow: Integer; AState: TKGridDrawState;
|
|
const ARect, ABlockRect: TRect; ACanvas: TCanvas; Clip, Printing: Boolean); virtual;
|
|
{ Used internally by e.g. @link(TKCustomGrid.SortRows) to sort rows or columns
|
|
using a non recursive quick sort algorithm. }
|
|
procedure InternalQuickSortNR(ByIndex, Left, Right: Integer;
|
|
SortedDown: Boolean; Compare: TKGridCompareProc; Exchange: TKGridExchangeProc); virtual;
|
|
{ Used internally to assign new cell value. }
|
|
procedure InternalSetCell(ACol, ARow: Integer; Value: TKGridCell); virtual;
|
|
{ Used internally to assign new text to a cell. }
|
|
procedure InternalSetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}); virtual;
|
|
{ Sets the cell span paramters according to given parameters. Automatically
|
|
splits any existing overlapping areas. Returns a grid rectangle that can
|
|
be used to update all affected cells. }
|
|
function InternalSetCellSpan(ACol, ARow: Integer;
|
|
const Value: TKGridCellSpan): TKGridRect; virtual;
|
|
{ Used internally to set column count. }
|
|
procedure InternalSetColCount(Value: Integer); virtual;
|
|
{ Used internally to set fixed column count. }
|
|
procedure InternalSetFixedCols(Value: Integer); virtual;
|
|
{ Used internally to set fixed row count. }
|
|
procedure InternalSetFixedRows(Value: Integer); virtual;
|
|
{ Used internally to set row count. }
|
|
procedure InternalSetRowCount(Value: Integer); virtual;
|
|
{ Allows the descendant to decide whether the goVirtualGrid option can be modified. }
|
|
function InternalUpdateVirtualGrid: Boolean; virtual;
|
|
{ Allows the changes to be reflected. }
|
|
procedure InternalUnlockUpdate; override;
|
|
{ Determines if control can be painted with OS themes. }
|
|
function IsThemed: Boolean; override;
|
|
{ Overriden method - see Delphi help. Responds to keyboard events. Implements
|
|
TCustomGrid specific behavior when the user presses a key. }
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
{ Overriden method - performs late update. }
|
|
procedure LateUpdate(var Msg: TLMessage); override;
|
|
{ Overriden method - see Delphi help. Updates grid colors. }
|
|
procedure Loaded; override;
|
|
{ Calls @link(TKCustomGrid.OnMeasureCell) event handler or cell class aware equivalent.
|
|
See the @link(TKGridMeasureCellEvent) type for parameter interpretation. }
|
|
function MeasureCell(ACol, ARow: Integer; const ARect: TRect;
|
|
AState: TKGridDrawState; Priority: TKGridMeasureCellPriority): TPoint; virtual;
|
|
{ Measures the grid and updates information about printed shape. }
|
|
procedure MeasurePages(var Info: TKPrintMeasureInfo); override;
|
|
{ Calls @link(TKCustomGrid.OnMouseCellHint) event handler.
|
|
See the @link(TKGridCellEvent) type for parameter interpretation. }
|
|
procedure MouseCellHint(ACol, ARow: Integer; AShow: Boolean); virtual;
|
|
{ Calls @link(TKCustomGrid.OnMouseClickCell) event handler.
|
|
See the @link(TKGridCellEvent) type for parameter interpretation. }
|
|
procedure MouseClickCell(ACol, ARow: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnMouseDblClickCell) event handler.
|
|
See the @link(TKGridCellEvent) type for parameter interpretation. }
|
|
procedure MouseDblClickCell(ACol, ARow: Integer); virtual;
|
|
{ Overriden method - see Delphi help. Responds to mouse events. Implements
|
|
TCustomGrid specific behavior when the user presses a mouse button. }
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer); override;
|
|
{ Calls @link(TKCustomGrid.OnMouseEnterCell) event handler.
|
|
See the @link(TKGridCellEvent) type for parameter interpretation. }
|
|
procedure MouseEnterCell(ACol, ARow: Integer); virtual;
|
|
{ Overriden method. Responds to WM_MOUSELEAVE message. }
|
|
procedure MouseFormLeave; override;
|
|
{ Calls @link(TKCustomGrid.OnMouseLeaveCell) event handler.
|
|
See the @link(TKGridCellEvent) type for parameter interpretation. }
|
|
procedure MouseLeaveCell(ACol, ARow: Integer); virtual;
|
|
{ Overriden method - see Delphi help. Responds to mouse events. Implements
|
|
TCustomGrid specific behavior when the user moves the mouse cursor. }
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
|
{ Implements default behavior to visually indicate that the mouse cursor
|
|
enters or leaves the cell if goMouseOverCells is included in @link(TKCustomGrid.Options). }
|
|
procedure MouseOverCells; virtual;
|
|
{ Overriden method - see Delphi help. Responds to mouse events. Implements
|
|
TCustomGrid specific behavior when the user releases a mouse button. }
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer); override;
|
|
{ Returns the amount of rows in current page, minimum is 1. }
|
|
function PageHeight: Integer; virtual;
|
|
{ Returns the amount of columns in current page, minimum is 1. }
|
|
function PageWidth: Integer; virtual;
|
|
{ Paints a range of cells. }
|
|
function PaintCells(ACanvas: TCanvas; CellBitmap: TBitmap;
|
|
MainClipRgn: HRGN; FirstCol, LastCol, FirstRow, LastRow, X, Y, MaxX,
|
|
MaxY: Integer; Printing, PaintSelection: Boolean; const ABlockRect: TRect): TPoint;
|
|
{ Paints the suggestion for drop target when dragging a column or row. }
|
|
procedure PaintDragSuggestion(ACanvas: TCanvas); virtual;
|
|
{ Paints a header terminating rectangle to align the header with the right
|
|
client area edge. }
|
|
procedure PaintHeaderAlignment(ACanvas: TCanvas; ARect: TRect); virtual;
|
|
{ Paints a page to a printer/preview canvas. }
|
|
procedure PaintPage; override;
|
|
{ Paints the suggestion for new width/height of a column/row being resized. }
|
|
procedure PaintSizingSuggestion(ACanvas: TCanvas); virtual;
|
|
{ Determines which cell lies at client coordinates specified by Point.
|
|
Set OutSide to True to evaluate a cell that does not actually lie at Point
|
|
but is the closest. Such a cell always lies at the boundary of scrollable
|
|
cell area. This is used for scrolling by mouse. InvisibleCells specifies
|
|
if some invisible cells should be considered in some cases. Currently, this
|
|
is used for scrolling by mouse, either. This function returns True if the
|
|
corresponding cell has been found. In this case, ACol and ARow contain
|
|
column and row indexes of the returned cell. }
|
|
function PointToCell(Point: TPoint; OutSide: Boolean; InvisibleCells: TKGridInvisibleCells;
|
|
out HitCol, HitRow, SelCol, SelRow: Integer): Boolean; virtual;
|
|
{ Determines the possible column or row sizing state along with default sizing
|
|
parameters for client coordinates specified by Point. The possible sizing
|
|
state is returned in State and sizing parameters in Index and Pos. This
|
|
function returns True if Point is in an area where sizing of a column or
|
|
row can begin. }
|
|
function PointToSizing(Point: TPoint; var State: TKGridState;
|
|
var Index, Pos: Integer): Boolean; virtual;
|
|
{ Updates drag object's (layered) window used to visually indicate the dragged
|
|
column or row. This window is updated according to mouse cursor coordinates
|
|
in MousePt, column or row index specified by Index. The Hide parameter forces
|
|
the window to hide and thus visually indicate that column or row dragging has ended. }
|
|
procedure ProcessDragWindow(const PtIni, PtCur: TPoint; Index: Integer; ColDrag, Hide: Boolean); virtual;
|
|
{ Resets the @link(TKCustomGrid.LeftCol) and @link(TKCustomGrid.TopRow) property
|
|
after the @link(TKCustomGrid.FixedCols) or @link(TKCustomGrid.FixedRows)
|
|
properties have changed. }
|
|
procedure ResetTopLeft; virtual;
|
|
{ Calls @link(TKCustomGrid.OnRowMoved) event handler.
|
|
See the @link(TKGridMovedEvent) type for parameter interpretation. }
|
|
procedure RowMoved(FromIndex, ToIndex: Integer); virtual;
|
|
{ Calls @link(TKCustomGrid.OnRowHeightsChanged) event handler. }
|
|
procedure RowHeightsChanged(ARow: Integer); virtual;
|
|
{ Tries to set input focus to the grid if @link(TKCustomGrid.EditorMode)
|
|
is False or to the inplace editor if EditorMode is True. }
|
|
procedure SafeSetFocus; virtual;
|
|
{ Scrolls the scrollable cells either horizontally by DeltaHorz or vertically
|
|
by DeltaVert or in both directions. CodeHorz and CodeVert are the codes
|
|
coming from WM_HSCROLL or WM_VSCROLL messages. Set CallUpdateEditor to True
|
|
to call @link(TKCustomGrid.UpdateEditor) within this method to scroll
|
|
the inplace editor, either. Set CallUpdateEditor to False if you don't want
|
|
to scroll the inplace editor and update it by some other means, such as
|
|
@link(TKCustomgrid.SelectionMove). This method avoids inplace editor flickering
|
|
when scrolling with EditorMode = True. }
|
|
procedure Scroll(CodeHorz, CodeVert, DeltaHorz, DeltaVert: Integer;
|
|
CallUpdateEditor: Boolean); virtual;
|
|
{ This method is called periodically from the timer used to automatically
|
|
scroll the scrollable cells while the mouse pointer is captured and
|
|
held outside the grid client area. }
|
|
procedure ScrollTimerHandler(Sender: TObject); virtual;
|
|
{ Calls @link(TKCustomGrid.OnSelectCell) event handler or cell class aware equivalent
|
|
See the @link(TKGridSelectCellEvent) type for parameter interpretation. }
|
|
function SelectCell(ACol, ARow: Integer): Boolean; virtual;
|
|
procedure SelectionChanged(NewSelection: TKGridRect;
|
|
Flags: TKGridSelectionFlags);
|
|
{ Calls @link(TKCustomGrid.OnSelectionExpand) event handler or cell class aware equivalent
|
|
See the @link(TKGridSelectionExpandEvent) type for parameter interpretation. }
|
|
function SelectionExpand(ACol, ARow: Integer): Boolean; virtual;
|
|
{ Adjusts the grid rectangle identified by Sel and makes it valid. This method
|
|
is intended to adjust FSelection or a rectangle assumed to be assigned
|
|
to FSelection later. }
|
|
procedure SelectionFix(var Sel: TKGridRect); virtual;
|
|
{ Initializes or expands the current selection and performs all necessary adjustments.
|
|
ACol and ARow are the indexes used to initialize or expand the selection.
|
|
Stage determines, if the selection should be initialized or expanded.
|
|
Flags forces various adjustments to be performed after the selection has been
|
|
initialized or expanded. Returns True if the selection could be changed or
|
|
would not be modified, either. }
|
|
function SelectionMove(ACol, ARow: Integer; Stage: TKGridSelectionStage;
|
|
Flags: TKGridSelectionFlags): Boolean; virtual;
|
|
{ Assigns new selection and performs all necessary adjustments. }
|
|
function SelectionSet(const NewSelection: TKGridRect): Boolean;
|
|
{$IFDEF FPC}
|
|
{ Overriden LCL method. This allows a custom mouse cursor to be assigned for the grid. }
|
|
procedure SetCursor(Value: TCursor); override;
|
|
{$ENDIF}
|
|
{ Updates mouse cursor according to the grid state determined from current mouse
|
|
position. Returns True if cursor has been changed. }
|
|
function SetMouseCursor(X, Y: Integer): Boolean; override;
|
|
{ Calls @link(TKCustomGrid.OnSizeChanged) event handler.
|
|
See the @link(TKGridSizeChangedEvent) type for parameter interpretation. }
|
|
procedure SizeChanged(Change: TKGridSizeChange; Index, Count: Integer); virtual;
|
|
{ Forces the column/row dragging suggestion to be created, destroyed or
|
|
temporarilly hidden and shown, depending on the State parameter. }
|
|
procedure SuggestDrag(State: TKGridCaptureState); virtual;
|
|
{ Forces the column/row sizing suggestion to be created, destroyed or
|
|
temporarilly hidden and shown, depending on the State parameter. }
|
|
procedure SuggestSizing(State: TKGridCaptureState); virtual;
|
|
{ Calls @link(TKCustomGrid.OnTopLeftChanged) event handler. }
|
|
procedure TopLeftChanged; virtual;
|
|
{ Updates the column axis if Horz is True and/or row axis if Vert is True.
|
|
Adjusts column widths/row heights if goAlignLastCol/goAlignLastRow
|
|
is included in @link(TKCustomGrid.Options). Adjusts scrolling range -
|
|
calls @link(TKCustomgrid.UpdateScrollRange). Invalidates columns/rows
|
|
as needed or starting by column/row index given by FirstCol/FirstRow.
|
|
Specify @link(cAll) as FirstCol/FirstRow to invalidate all columns/rows.
|
|
Performs additional actions as specified by Flags. }
|
|
procedure UpdateAxes(Horz: Boolean; FirstCol: Integer; Vert: Boolean;
|
|
FirstRow: Integer; Flags: TKGridAxisUpdateFlags); virtual;
|
|
{ Updates/re-calculates the column/row span paramteres of all cells
|
|
if necessary. Fixes all broken or incomplete merged cell areas, e.g. upon
|
|
column or row moving or grid resizing. }
|
|
procedure UpdateCellSpan; virtual;
|
|
{ Updates the grid size. }
|
|
procedure UpdateSize; override;
|
|
{ Updates the Delphi form designer if @link(TKCustomGrid.ColWidths) or
|
|
@link(TKCustomGrid.RowHeights) have been changed. }
|
|
procedure UpdateDesigner; virtual;
|
|
{ Updates the inplace editor state. Set Show to True to create and display
|
|
the inplace editor. Set Show to False to hide and destroy the inplace editor. }
|
|
procedure UpdateEditor(Show: Boolean); virtual;
|
|
{ Updates the scrolling range of the column axis if Horz is True and/or row
|
|
axis if Vert is True. Set UpdateNeeded to True to force the invalidation
|
|
of respective grid areas. Set UpdateNeeded to False to let UpdateScrollRange
|
|
decide whether these need to be invalidated. }
|
|
procedure UpdateScrollRange(Horz, Vert, UpdateNeeded: Boolean); virtual;
|
|
{$IFNDEF FPC}
|
|
{ Inherited method. Used to ensure correct painting for transparent inplace
|
|
editors. }
|
|
procedure WndProc(var Msg: TMessage); override;
|
|
{$ENDIF}
|
|
public
|
|
{ Creates the instance. Assigns default values to properties, allocates
|
|
default column, row and cell data. }
|
|
constructor Create(AOwner: TComponent); override;
|
|
{ Destroys the instance along with all allocated column, row and cell data. }
|
|
destructor Destroy; override;
|
|
{ Resizes the column automatically so that the cell contents fit horizontally.
|
|
Does include merged cell areas with their base cells located in this column.
|
|
Set FixedCells to True to include fixed cells into autosizing. }
|
|
procedure AutoSizeCol(ACol: Integer; FixedCells: Boolean = True);
|
|
{ Resizes the entire grid automatically so that the cell contents fit both
|
|
horizontally and vertically. Set FixedCells to True to include fixed cells
|
|
into autosizing. }
|
|
procedure AutoSizeGrid(Priority: TKGridMeasureCellPriority; FixedCells: Boolean = True);
|
|
{ Resizes the row automatically so that the cell contents fit vertically.
|
|
Does include merged cell areas with their base cells located in this row.
|
|
Set FixedCells to True to include fixed cells into autosizing. }
|
|
procedure AutoSizeRow(ARow: Integer; FixedCells: Boolean = True);
|
|
{ Determines if a cell specified by ACol and ARow is selected. }
|
|
function CellSelected(ACol, ARow: Integer): Boolean; virtual;
|
|
{ Returns the bounding rectangle of a cell specified by ACol and ARow without the
|
|
column and row spacing areas defined by @link(TKCustomGrid.GridLineWidth).
|
|
The function returns False if the cell indexes are invalid. }
|
|
function CellRect(ACol, ARow: Integer; out R: TRect; VisibleOnly: Boolean = False): Boolean;
|
|
{ Returns the left and top coordinates of a cell specified by ACol and ARow.
|
|
The function returns False if the cell indexes are invalid. }
|
|
function CellToPoint(ACol, ARow: Integer; var Point: TPoint;
|
|
VisibleOnly: Boolean = False): Boolean; virtual;
|
|
{ Determines if a cell specified by ACol and ARow is visible. }
|
|
function CellVisible(ACol, ARow: Integer): Boolean; virtual;
|
|
{ Clears all cells in a column identified by ACol. }
|
|
procedure ClearCol(ACol: Integer); virtual;
|
|
{ Clears all cells. }
|
|
procedure ClearGrid; virtual;
|
|
{ Clears all cells in a row identified by ARow. }
|
|
procedure ClearRow(ARow: Integer); virtual;
|
|
{ Clears sorting mode of both rows and columns if grid sorting mode is not locked
|
|
by @link(TKCustomGrid.LockSortMode). }
|
|
procedure ClearSortMode;
|
|
{ Clears sorting mode of rows if grid sorting mode is not locked
|
|
by @link(TKCustomGrid.LockSortMode). Ensures that every column has it's
|
|
@link(TKGridAxisItem.SortMode) equal to smNone. }
|
|
procedure ClearSortModeHorz; virtual;
|
|
{ Clears sorting mode of columns if grid sorting mode is not locked
|
|
by @link(TKCustomGrid.LockSortMode). Ensures that every row has it's
|
|
@link(TKGridAxisItem.SortMode) equal to smNone. }
|
|
procedure ClearSortModeVert; virtual;
|
|
{ Determines if a column specified by ACol can be selected,
|
|
i.e. lies in non-fixed area. }
|
|
function ColSelectable(ACol: Integer): Boolean; virtual;
|
|
{ Determines if current selection includes a column specified by ACol. }
|
|
function ColSelected(ACol: Integer): Boolean; virtual;
|
|
{ Determines if a column specified by ACol is valid column. }
|
|
function ColValid(ACol: Integer): Boolean; virtual;
|
|
{ Decides whether a key stroke should be handled by inplace editor identified by
|
|
AEditor or by the grid. AEditor must be a descendant of
|
|
TCustomComboBox. See @link(TKGridEditorKeyPreviewEvent) for interpretation of
|
|
another parameters. }
|
|
procedure DefaultComboKeyPreview(AEditor: TComboBox; ACol, ARow: Integer;
|
|
var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); virtual;
|
|
{ This function allows you to correctly set the caret position within
|
|
inplace editor identified by AEditor. AEditor must be a descendant of TCustomComboBox.
|
|
See @link(TKGridEditorSelectEvent) for interpretation of another parameters. }
|
|
procedure DefaultComboSelect(AEditor: TComboBox; SelectAll, CaretToLeft: Boolean); virtual;
|
|
{ Provides default behavior while comparing two cells identified by
|
|
ACell1 and ACell2. Under current implementation, only text strings will be
|
|
compared if if any of the cells inherits @link(TKGridTextCell). }
|
|
function DefaultCompareCells(ACell1, ACell2: TKGridCell): Integer; virtual;
|
|
{ Decides whether a key stroke should be handled by inplace editor identified by
|
|
AEditor or by the grid. AEditor must be a descendant of
|
|
TCustomEdit. See @link(TKGridEditorKeyPreviewEvent) for interpretation of
|
|
another parameters. }
|
|
procedure DefaultEditKeyPreview(AEditor: TCustomEdit; ACol, ARow: Integer;
|
|
var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); virtual;
|
|
{ Provides default behavior for the @link(OnEditorCreate) event. }
|
|
procedure DefaultEditorCreate(ACol, ARow: Integer;
|
|
var AEditor: TWinControl); virtual;
|
|
{ Provides default behavior for the @link(OnEditorDataFromGrid) event. }
|
|
procedure DefaultEditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var AssignText: Boolean); virtual;
|
|
{ Provides default behavior for the @link(OnEditorDataToGrid) event. }
|
|
procedure DefaultEditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var AssignText: Boolean); virtual;
|
|
{ Provides default behavior for the @link(OnEditorCreate) event. }
|
|
procedure DefaultEditorDestroy(AEditor: TWinControl; ACol, ARow: Integer); virtual;
|
|
{ Decides whether a key stroke should be handled by inplace editor identified by
|
|
AEditor or by the grid. Calls all implemented DefaultxxKeyPreview methods
|
|
or nothing if no ancestor is found for given AEditor.
|
|
See @link(TKGridEditorKeyPreviewEvent) for interpretation of another parameters. }
|
|
procedure DefaultEditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean); virtual;
|
|
{ Provides default behavior for the @link(OnEditorResize) event. }
|
|
procedure DefaultEditorResize(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var ARect: TRect); virtual;
|
|
{ This function allows you to correctly set the caret position within
|
|
inplace editor identified by AEditor. Calls all implemented DefaultxxSelect methods
|
|
or nothing if no ancestor is found for given AEditor.
|
|
See @link(TKGridEditorSelectEvent) for interpretation of another parameters. }
|
|
procedure DefaultEditorSelect(AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean); virtual;
|
|
{ This function allows you to correctly set the caret position within
|
|
inplace editor identified by AEditor. AEditor must be a descendant of TCustomEdit.
|
|
See @link(TKGridEditorSelectEvent) for interpretation of another parameters. }
|
|
procedure DefaultEditSelect(AEditor: TCustomEdit; SelectAll, CaretToLeft: Boolean); virtual;
|
|
{ Provides default cell hint behavior. }
|
|
procedure DefaultMouseCellHint(ACol, ARow: Integer; AShow: Boolean); virtual;
|
|
{ Decides whether a key stroke should be handled by inplace editor identified by
|
|
AEditor or by the grid. AEditor must be a descendant of
|
|
TScrollBar. See @link(TKGridEditorKeyPreviewEvent) for interpretation of
|
|
another parameters. }
|
|
procedure DefaultScrollBarKeyPreview(AEditor: TScrollBar; ACol, ARow: Integer;
|
|
var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
{ Deletes a column specified by At. At must be valid column index and
|
|
@link(TKCustomGrid.ColCount) must be > 1. Otherwise, nothing happens. }
|
|
procedure DeleteCol(At: Integer); virtual;
|
|
{ Deletes Count columns starting at index At. At must be valid column index
|
|
and @link(TKCustomGrid.ColCount) must be > 1. Otherwise, nothing happens.
|
|
Count will be adapted so that no more but available columns will be deleted. }
|
|
procedure DeleteCols(At, Count: Integer); virtual;
|
|
{ Deletes a row specified by At. At must be valid row index and
|
|
@link(TKCustomGrid.RowCount) must be > 1. Otherwise, nothing happens. }
|
|
procedure DeleteRow(At: Integer); virtual;
|
|
{ Deletes Count rows starting at index At. At must be valid row index
|
|
and @link(TKCustomGrid.RowCount) must be > 1. Otherwise, nothing happens.
|
|
Count will be adapted so that no more but available rows will be deleted. }
|
|
procedure DeleteRows(At, Count: Integer); virtual;
|
|
{ Retrieves the base cell if the cell given by ACol and ARow belongs to a merged cell
|
|
or returns ACol and ARow if it is a non-merged cell. }
|
|
procedure FindBaseCell(ACol, ARow: Integer; out BaseCol, BaseRow: Integer); virtual;
|
|
{ Selects a cell specified by ACol and ARow. If the grid has input focus,
|
|
this cell becomes it automatically. }
|
|
procedure FocusCell(ACol, ARow: Integer);
|
|
{ Returns miscellaneous information about both grid axes, i.e. column axis and row axis. }
|
|
function GetAxisInfoBoth(Mask: TKGridAxisInfoMask): TKGridAxisInfoBoth;
|
|
{ Returns miscellaneous information about column axis. }
|
|
function GetAxisInfoHorz(Mask: TKGridAxisInfoMask): TKGridAxisInfo; virtual;
|
|
{ Returns miscellaneous information about row axis. }
|
|
function GetAxisInfoVert(Mask: TKGridAxisInfoMask): TKGridAxisInfo; virtual;
|
|
{ Returns default draw state for a cell identified by ACol and ARow.
|
|
Called by Paint - override to implement specific behavior. }
|
|
function GetDrawState(ACol, ARow: Integer; AFocused: Boolean): TKGridDrawState; virtual;
|
|
{ Determines if the entire grid rectangle lies within the non-fixed and thus
|
|
selectable area. }
|
|
function GridRectSelectable(const GridRect: TKGridRect): Boolean; virtual;
|
|
{ Converts a grid rectangle into client coordinates. Set VisibleOnly to True
|
|
to take only the visible part of the rectangle. Indexes in GridRect will be
|
|
automatically trimmed either to non-fixed area or to a fixed area depending
|
|
on top-left cell specified in GridRect. Set Merged to True to expand the grid
|
|
rectangle by possible merged cell areas. The returned coordinates include
|
|
column and row spacing areas defined by @link(TKCustomGrid.GridLineWidth). }
|
|
function GridRectToRect(GridRect: TKGridRect; var R: TRect;
|
|
VisibleOnly: Boolean = False; Merged: Boolean = True): Boolean; virtual;
|
|
{ Determines if all indexes in GridRect are valid column or row indexes. }
|
|
function GridRectValid(const GridRect: TKGridRect): Boolean; virtual;
|
|
{ Forces the cell hint to hide. }
|
|
procedure HideCellHint;
|
|
{ Determines the initial index of a column identified by ACol. This function
|
|
is a part of index mapping mechanism. Initial index is assigned to a column
|
|
immediately after it is inserted into the grid either by changing
|
|
@link(TKCustomGrid.ColCount) or @link(TKCustomGrid.InsertCols). }
|
|
function InitialCol(ACol: Integer): Integer; virtual;
|
|
{ Determines the current column index from initial column position given by ACol.
|
|
This function is a part of index mapping mechanism. }
|
|
function InitialColInv(ACol: Integer): Integer; virtual;
|
|
{ Determines the initial index of a row identified by ARow. This function
|
|
is a part of index mapping mechanism. Initial index is assigned to a row
|
|
immediately after it is inserted into the grid either by changing
|
|
@link(TKCustomGrid.RowCount) or @link(TKCustomGrid.InsertRows). }
|
|
function InitialRow(ARow: Integer): Integer; virtual;
|
|
{ Determines the current row index from initial row position given by ARow.
|
|
This function is a part of index mapping mechanism. }
|
|
function InitialRowInv(ARow: Integer): Integer; virtual;
|
|
{ Inserts a new column into the grid. The new column will be inserted before
|
|
the column identified by At. You can set this parameter greater or equal
|
|
@link(TKCustomGrid.ColCount) to insert a new column behind the last column. }
|
|
procedure InsertCol(At: Integer); virtual;
|
|
{ Inserts multiple new columns into the grid. The new columns will be inserted
|
|
before the column identified by At. You can set this parameter greater or equal
|
|
@link(TKCustomGrid.ColCount) to insert these after the last column. }
|
|
procedure InsertCols(At, Count: Integer); virtual;
|
|
{ Inserts a new row into the grid. The new row will be inserted before
|
|
the row identified by At. You can set this parameter greater or equal
|
|
@link(TKCustomGrid.RowCount) to insert a new row behind the last row. }
|
|
procedure InsertRow(At: Integer); virtual;
|
|
{ Inserts multiple new rows into the grid. The new rows will be inserted
|
|
before the row identified by At. You can set this parameter greater or equal
|
|
@link(TKCustomGrid.RowCount) to insert these after the last row. }
|
|
procedure InsertRows(At, Count: Integer); virtual;
|
|
{ Inserts an empty column at the corresponding position. If columns are not sorted
|
|
at this point, InsertSortedCol does nothing and returns False. During
|
|
InsertSortedCol, a non recursive binary tree search is performed and
|
|
the @link(TKCustomGrid.OnCompareCells) event handler is called several times
|
|
with slightly different parameters than e.g. during @link(TKCustomGrid.SortCols),
|
|
i.e. the ACol1 is always @link(cInvalidIndex). You can detect it to perform
|
|
custom comparisons with the new value. }
|
|
function InsertSortedCol(out ByRow, ACol: Integer): Boolean; virtual;
|
|
{ Inserts an empty row at the corresponding position. If rows are not sorted
|
|
at this point, InsertSortedRow does nothing and returns False. During
|
|
InsertSortedRow, a non recursive binary tree search is performed and
|
|
the @link(TKCustomGrid.OnCompareCells) event handler is called several times
|
|
with slightly different parameters than e.g. during @link(TKCustomGrid.SortRows),
|
|
i.e. the ARow1 is always @link(cInvalidIndex). You can detect it to perform
|
|
custom comparisons with the new value. }
|
|
function InsertSortedRow(out ByCol, ARow: Integer): Boolean; virtual;
|
|
{ Invalidates the cell specified by ACol and ARow if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateCell(ACol, ARow: Integer);
|
|
{ Invalidates the entire column specified by ACol if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateCol(ACol: Integer); virtual;
|
|
{ Invalidates all columns starting with FirstCol if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateCols(FirstCol: Integer); virtual;
|
|
{ Invalidates the current selection including the fixed cells in
|
|
@link(goIndicateSelection) mode if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateCurrentSelection; virtual;
|
|
{ Invalidates the grid rectangle specified by GridRect if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateGridRect(const GR: TKGridRect; Merged: Boolean = True); virtual;
|
|
{ Invalidates the entire row specified by ARow if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateRow(ARow: Integer); virtual;
|
|
{ Invalidates all rows starting with FirstRow if grid updating is not locked
|
|
by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateRows(FirstRow: Integer); virtual;
|
|
{ Invalidates any custom grid rectangle that should be treated as grid selection,
|
|
including the fixed cells in @link(goIndicateSelection) mode,
|
|
if grid updating is not locked by @link(TKCustomControl.LockUpdate). }
|
|
procedure InvalidateSelection(ASelection: TKGridRect); virtual;
|
|
{ Returns True either if the DoubleBuffered property is True
|
|
or if @link(goDoubleBufferedCells) is included in grid's @link(TKCustomGrid.Options).}
|
|
function IsDoubleBuffered: Boolean; virtual;
|
|
{ Locks sort mode updating so that all changes made to the cell data
|
|
will not affect the current sort status of any column or row. Every LockSortMode
|
|
call must have a corresponding @link(TKCustomGrid.UnlockSortMode) call, please use a
|
|
try-finally section. }
|
|
procedure LockSortMode; virtual;
|
|
{ Determines the cell that contains client area coordinates X and Y.
|
|
If there is such a cell, the function returns True and corresponding cell
|
|
indexes are returned in ACol and ARow. Otherwise, the function returns False. }
|
|
function MouseToCell(X, Y: Integer; var ACol, ARow: Integer): Boolean;
|
|
{ Moves a column from a position specified by FromIndex to a new
|
|
position specified by ToIndex. Both column indexes must be valid and
|
|
FromIndex must not equal to ToIndex. Otherwise, nothing happens. }
|
|
procedure MoveCol(FromIndex, ToIndex: Integer); virtual;
|
|
{ Moves a row from a position specified by FromIndex to a new
|
|
position specified by ToIndex. Both row indexes must be valid and
|
|
FromIndex must not equal to ToIndex. Otherwise, nothing happens. }
|
|
procedure MoveRow(FromIndex, ToIndex: Integer); virtual;
|
|
{ Forces to move the input focus to the next cell according to
|
|
@link(TKCustomGrid.MoveDirection) and calls OnClick event if that succeeds. }
|
|
procedure MoveToNextCell; virtual;
|
|
{ Paints a cell identified by ACol and ARow to ACanvas.
|
|
This is faster way than InvalidateCell but won't work under Qt.
|
|
Set ACanvas to nil to paint to grid's Canvas. Otherwise, set AX and AY
|
|
to specify painting origin on custom ACanvas. }
|
|
procedure PaintCell(ACanvas: TCanvas; ACol, ARow: Integer;
|
|
AX: Integer = 0; AY: Integer = 0; APrinting: Boolean = False;
|
|
ABlockRect: PRect = nil); virtual;
|
|
{ Paints the control to the specified canvas. }
|
|
procedure PaintToCanvas(ACanvas: TCanvas); override;
|
|
{ Forces the cell class specified by @link(TKCustomGrid.CellClass) to replace
|
|
all other cell classes that do not inherit from it. Call this method to
|
|
ensure that all the cells in the grid contain instances of CellClass or those
|
|
inherited from CellClass. All possible cell class properties are copied by
|
|
the @link(TKGridCell.Assign) method. }
|
|
procedure RealizeCellClass;
|
|
{ Forces the column class specified by @link(TKCustomGrid.ColClass) to replace
|
|
all other column classes that do not inherit from it. Call this method to
|
|
ensure that the entire horizontal grid axis contains instances of ColClass
|
|
or those inherited from ColClass. All possible column class properties are
|
|
copied by the @link(TKGridAxisItem.Assign) method. }
|
|
procedure RealizeColClass;
|
|
{ Forces the row class specified by @link(TKCustomGrid.RowClass) to replace
|
|
all other row classes that do not inherit from it. Call this method to
|
|
ensure that the entire vertical grid axis contains instances of RowClass
|
|
or those inherited from RowClass. All possible row class properties are
|
|
copied by the @link(TKGridAxisItem.Assign) method. }
|
|
procedure RealizeRowClass;
|
|
{ Determines if a row specified by ARow can be selected,
|
|
i.e. lies in non-fixed area. }
|
|
function RowSelectable(ARow: Integer): Boolean; virtual;
|
|
{ Determines if current selection includes a row specified by ARow. }
|
|
function RowSelected(ARow: Integer): Boolean; virtual;
|
|
{ Determines if a row specified by ARow is valid row. }
|
|
function RowValid(ARow: Integer): Boolean; virtual;
|
|
{ Scrolls the non-fixed cells horizontally by AColCount cells or vertically
|
|
by ARowCount cells. If the cells cannot be scrolled, nothing happens. }
|
|
procedure ScrollBy(AColCount, ARowCount: Integer);
|
|
{ Retrieves the amount of pixels corresponding to the amount of cells
|
|
specified by ADelta, relative from @link(TKCustomGrid.LeftCol) and
|
|
@link(TKCustomGrid.TopRow). }
|
|
function ScrollDeltaFromDelta(const Info: TKGridAxisInfo; ADelta: Integer): Integer; virtual;
|
|
{ Determines if a cell specified by ACol and ARow should be scrolled, i.e. is
|
|
not fully visible. }
|
|
function ScrollNeeded(ACol, ARow: Integer; out DeltaHorz, DeltaVert: Integer): Boolean; virtual;
|
|
{ Selects all cells. }
|
|
procedure SelectAll;
|
|
{ Selects a column. }
|
|
procedure SelectCol(ACol: Integer);
|
|
{ Select more columns. }
|
|
procedure SelectCols(FirstCol, Count: Integer);
|
|
{ Normalize current selection. }
|
|
procedure SelectionNormalize;
|
|
{ Selects a row. }
|
|
procedure SelectRow(ARow: Integer);
|
|
{ Selects more rows. }
|
|
procedure SelectRows(FirstRow, Count: Integer);
|
|
{ Forces the cell hint to show on screen. }
|
|
procedure ShowCellHint;
|
|
{ Sorts columns by values of a row if grid sorting mode is not locked
|
|
by @link(TKCustomGrid.LockSortMode). }
|
|
procedure SortCols(ByRow: Integer; SortMode: TKGridSortMode); virtual;
|
|
{ Returns True if sort mode updating is not locked, i.e. there is no open
|
|
LockSortMode and UnlockSortMode pair. }
|
|
function SortModeUnlocked: Boolean; virtual;
|
|
{ Sorts rows by values of a column if grid sorting mode is not locked
|
|
by @link(TKCustomGrid.LockSortMode). }
|
|
procedure SortRows(ByCol: Integer; SortMode: TKGridSortMode); virtual;
|
|
{ Unlocks sort mode updating so that all changes made to the cell data
|
|
will clear the current sort status of any column or row. }
|
|
procedure UnlockSortMode; virtual;
|
|
{ Unselects range of cells. }
|
|
procedure UnselectRange;
|
|
{ Updates column and row sorting mode (if there is one) if data has been
|
|
modified in a single cell. Must be called explicitly each time a cell data
|
|
has been modified if sorting interface is used. }
|
|
procedure UpdateSortMode(ACol, ARow: Integer); virtual;
|
|
{ Provides fast read only access to the cell array @link(TKCustomGrid.FCells).
|
|
Any cell can be directly accessed through ArrayOfCells[RowIndex, ColIndex].
|
|
In contrast with the @link(TKCustomGrid.Cell) property, row index
|
|
comes BEFORE column index here. It has been designed to speed up operations
|
|
with rows because most grids usually contain much more rows than colums. }
|
|
property ArrayOfCells: TKGridCells read FCells;
|
|
{ Provides fast read only access to column array @link(TKCustomGrid.FCols). }
|
|
property ArrayOfCols: TKGridAxisItems read FCols;
|
|
{ Provides fast read only access to row array @link(TKCustomGrid.FRows). }
|
|
property ArrayOfRows: TKGridAxisItems read FRows;
|
|
{$IFDEF FPC}
|
|
{ Specifies the same as Ctl3D in Delphi. }
|
|
property Flat: Boolean read FFlat write SetFlat default False;
|
|
{$ENDIF}
|
|
{ Determines if all cells are selected. }
|
|
property AllCellsSelected: Boolean read GetAllCellsSelected;
|
|
{ Determines if all columns are selected. }
|
|
property AllRowsSelected: Boolean read GetAllRowsSelected;
|
|
{ Determines if all columns are selected. }
|
|
property AllColsSelected: Boolean read GetAllColsSelected;
|
|
{ Inherited property - see Delphi help. }
|
|
property Canvas;
|
|
{ Gains access to the cell instances. New cell instances are always created
|
|
on demand by utilizing @link(TKCustomGrid.CellClass). To replace all other
|
|
cell instances with CellClass, call @link(TKCustomGrid.RealizeCellClass). }
|
|
property Cell[ACol, ARow: Integer]: TKGridCell read GetCell write SetCell;
|
|
{ Cell class used to create new cell instances. Cell instances are always
|
|
created on demand. }
|
|
property CellClass: TKGridCellClass read FCellClass write FCellClass;
|
|
{ Gains access to the active cell painter. }
|
|
property CellPainter: TKGridCellPainter read FCellPainter;
|
|
{ Specifies the cell painter class used to create new @link(TKCustomGrid.CellPainter).
|
|
The new cell painter instance will be created immediately. }
|
|
property CellPainterClass: TKGridCellPainterClass read FCellPainterClass write SetCellPainterClass;
|
|
{ Gains simplified access to the probably most used property of an textual
|
|
cell instance. If the cell instance at the position specified by ACol and ARow
|
|
does not inherit from a textual cell class @link(TKGridTextCell), it will be
|
|
created for this cell regardless of the current CellClass assignment. }
|
|
property Cells[ACol, ARow: Integer]: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF} read GetCells write SetCells;
|
|
{ Specifies the column span and row span for given cell. Always specify positive
|
|
values. Reading this property may return zero or negative values, which
|
|
are used internally to find base cell of the respective merged area. }
|
|
property CellSpan[ACol, ARow: Integer]: TKGridCellSpan read GetCellSpan write SetCellSpan;
|
|
{ Gains access to selection base cell. Setting Col discards the current selection
|
|
and moves focus to a new base cell in the current row that is in the new column.
|
|
The first column has an index of 0, the second column an index of 1, and so on.
|
|
If the index denotes a column that is not selectable, nothing happens. }
|
|
property Col: Integer read FSelection.Col1 write SetCol;
|
|
{ Column class used to create new column instances. Column instances are always
|
|
created when @link(TKCustomGrid.ColCount) grows. }
|
|
property ColClass: TKGridColClass read FColClass write FColClass;
|
|
{ Specifies the number of columns in the grid. Set ColCount to add or delete
|
|
columns at the righthand side of the grid. The value of ColCount includes
|
|
any fixed columns at the left of the grid as well as the scrollable columns
|
|
in the body of the grid. }
|
|
property ColCount: Integer read FColCount write SetColCount default cColCountDef;
|
|
{ Inherited property - see Delphi help. Specifies the default background color
|
|
for client area erasing and for parts of client area not occupied by cells. }
|
|
property Color default clWindow;
|
|
{ Specifies all colors used by TKCustomGrid's default painting. }
|
|
property Colors: TKGridColors read FColors write SetColors;
|
|
{ Gains access to the column instances. Column instances are always
|
|
created by utilizing @link(TKCustomGrid.ColClass) when @link(TKCustomGrid.ColCount)
|
|
grows. To replace all other column instances with ColClass, call
|
|
@link(TKCustomGrid.RealizeColClass). }
|
|
property Cols[Index: Integer]: TKGridCol read GetCols;
|
|
{ Indicates the width (in pixels) of all the columns in the grid. Set ColWidths
|
|
at runtime to change the width of an individual column. If the width of
|
|
a column has not been set explicitly by resizing with the mouse, or by using
|
|
the ColWidths property, its width is @link(TKCustomGrid.DefaultColWidth). }
|
|
property ColWidths[Index: Integer]: Integer read GetColWidths write SetColWidths;
|
|
{ Determines the width (in pixels) of all columns that have not been explicitly
|
|
resized. Set DefaultColWidth to change the size of all columns in the grid.
|
|
When DefaultColWidth is set, columns that have been resized using the mouse
|
|
or by setting the @link(TKCustomGrid.ColWidths) property are given the DefaultColWidth
|
|
as well. When new columns are added to the grid, they are created with
|
|
a width of DefaultColWidth. }
|
|
property DefaultColWidth: Integer read FDefaultColWidth write SetDefaultColWidth default cDefaultColWidthDef;
|
|
{ Dummy property - introduced for backward compatibility with TCustomGrid. }
|
|
property DefaultDrawing: Boolean read GetDefaultDrawing write SetDefaultDrawing default False;
|
|
{ Determines the height (in pixels) of all rows that have not been explicitly
|
|
resized. Set DefaultRowHeight to change the size of all rows in the grid.
|
|
When DefaultRowHeight is set, rows that have been resized using the mouse
|
|
or by setting the @link(TKCustomGrid.RowHeights) property are given the DefaultRowHeight
|
|
as well. When new rows are added to the grid, they are created with
|
|
a height of DefaultRowHeight. }
|
|
property DefaultRowHeight: Integer read FDefaultRowHeight write SetDefaultRowHeight default cDefaultRowHeightDef;
|
|
{ Specifies the style how the control is drawn while not enabled. }
|
|
property DisabledDrawStyle: TKGridDisabledDrawStyle read FDisabledDrawStyle write SetDisabledDrawStyle default cDisabledDrawStyleDef;
|
|
{ Specifies how a column or row appears while being moved by mouse. }
|
|
property DragStyle: TKGridDragStyle read FDragStyle write SetDragStyle default cDragStyleDef;
|
|
{ Returns reference to current inplace editor instance. }
|
|
property Editor: TWinControl read FEditor;
|
|
{ Determines if inplace editor is active. Set EditorMode to true, at runtime,
|
|
to put the grid in edit mode. When EditorMode is true, the user can edit cells
|
|
in the grid. When the user presses F2, EditorMode is set to true. When the
|
|
user presses Enter, the value of EditorMode is toggled or, depending on
|
|
@link(goEnterMoves) and @link(TKCustomGrid.MoveDirection) configuration,
|
|
another cell is focused. Inplace editor can be activated only if goEditing
|
|
is included in @link(TKCustomGrid.Options). }
|
|
property EditorMode: Boolean read GetEditorMode write SetEditorMode;
|
|
{ Determines if current inplace editor should be treated as a transparent
|
|
control from the grid's point of view. If a transparent inplace editor
|
|
needs to be painted, the cell background is painted
|
|
first to the inplace editor's Canvas/device context. Typically, check boxes
|
|
or radio buttons should appear as transparent controls in TKCustomGrid.
|
|
Unfortunatelly we must use a custom decision mechanism as there is no standard
|
|
VCL/LCL-based mechanism to design a control fully transparent in all cases.
|
|
The algorithm used to paint the cell background should work for a wide range
|
|
of controls either with or without OS themes. }
|
|
property EditorTransparency: TKGridEditorTransparency read FEditorTransparency write SetEditorTransparency default cEditorTransparencyDef;
|
|
{ Returns the effective spacing between columns. This is nonzero,
|
|
if goFixedVertLine or goVertLine is included in @link(TKCustomGrid.Options). }
|
|
property EffectiveColSpacing[Index: Integer]: Integer read GetEffectiveColSpacing;
|
|
{ Returns the effective spacing between rows. This is nonzero,
|
|
if goFixedHorzLine or goHorzLine is included in @link(TKCustomGrid.Options). }
|
|
property EffectiveRowSpacing[Index: Integer]: Integer read GetEffectiveRowSpacing;
|
|
{ Determines if an entire column is selected. }
|
|
property EntireColSelected[Index: Integer]: Boolean read GetEntireColSelected;
|
|
{ Determines number of entirely selected columns. }
|
|
property EntireSelectedColCount: Integer read GetEntireSelectedColCount;
|
|
{ Determines if an entire row is selected. }
|
|
property EntireRowSelected[Index: Integer]: Boolean read GetEntireRowSelected;
|
|
{ Determines number of entirely selected rows. }
|
|
property EntireSelectedRowCount: Integer read GetEntireSelectedRowCount;
|
|
{ Specifies the number of columns on the left of the grid that cannot be scrolled.
|
|
Set FixedCols to create or get rid of nonscrolling columns. Nonscrolling
|
|
columns appear at the left of the grid, and are always visible, even when
|
|
the user scrolls the other columns in the grid. Use nonscrolling columns
|
|
for displaying row titles or row numbers, or to implement a scroll lock that
|
|
the user can set. }
|
|
property FixedCols: Integer read FFixedCols write SetFixedCols default cFixedColsDef;
|
|
{ Specifies the number of rows on the top of the grid that cannot be scrolled.
|
|
Set FixedRows to create or get rid of nonscrolling rows. Nonscrolling rows
|
|
appear at the top of the grid, and are always visible, even when the user
|
|
scrolls the other rows in the grid. Use nonscrolling rows for displaying
|
|
column titles or column numbers. }
|
|
property FixedRows: Integer read FFixedRows write SetFixedRows default cFixedRowsDef;
|
|
{ Specifies the height of the grid in pixels. If GridHeight is less than
|
|
the value of ClientHeight, all of the rows of the grid appear in the control
|
|
with an empty region below the grid. If the underlying grid is too tall
|
|
to appear in the control, GridHeight is the same as ClientHeight,
|
|
and the user must scroll to see the entire contents of the grid. }
|
|
property GridHeight: Integer read GetGridHeight;
|
|
{ Specifies the width (in pixels) of the lines that separate the cells of the grid. }
|
|
property GridLineWidth: Integer read FGridLineWidth write SetGridLineWidth default cGridLineWidthDef;
|
|
{ Specifies the width of the grid in pixels. If GridWidth is less than the value
|
|
of ClientWidth, all of the columns of the grid appear in the control with
|
|
an empty region to the right of the grid. If the underlying grid is
|
|
too wide to appear in the control, GridWidth is the same as ClientWidth,
|
|
and the user must scroll to see the entire contents of the grid. }
|
|
property GridWidth: Integer read GetGridWidth;
|
|
{ Determines if the grid, inplace editor or any child window of inplace editor
|
|
has input focus. }
|
|
function HasFocus: Boolean; virtual;
|
|
{ Returns the last (even partially) visible column in the grid. }
|
|
property LastVisibleCol: Integer read GetLastVisibleCol;
|
|
{ Returns the last (even partially) visible row in the grid. }
|
|
property LastVisibleRow: Integer read GetLastVisibleRow;
|
|
{ Specifies the index of the first visible scrollable column in the grid.
|
|
Set LeftCol to scroll the columns in the grid so that the column with index
|
|
LeftCol is the first column after the fixed columns. }
|
|
property LeftCol: Integer read FTopLeft.Col write SetLeftCol;
|
|
{ Specifies the number of columns the grid would have if no columns would
|
|
have been deleted. }
|
|
property MaxCol: Integer read FMaxCol;
|
|
{ Specifies the number of rows the grid would have if no rows would
|
|
have been deleted. }
|
|
property MaxRow: Integer read FMaxRow;
|
|
{ Specifies the minimum width a column can have. }
|
|
property MinColWidth: Integer read FMinColWidth write SetMinColWidth default cMinColWidthDef;
|
|
{ Specifies the minimum height a row can have. }
|
|
property MinRowHeight: Integer read FMinRowHeight write SetMinRowHeight default cMinRowHeightDef;
|
|
{ Determines if more cells are selected (more than one cell). }
|
|
property MoreCellsSelected: Boolean read GetMoreCellsSelected;
|
|
{ Specifies how fast the mouse cell hint should be. }
|
|
property MouseCellHintTime: Cardinal read FMouseCellHintTime write SetMouseCellHintTime default cMouseCellHintTimeDef;
|
|
{ Specifies the behavior after the user presses Enter. This property has
|
|
no effect unless goEnterMoves is included in @link(TKCustomGrid.Options). }
|
|
property MoveDirection: TKGridMoveDirection read FMoveDirection write FMoveDirection default cMoveDirectionDef;
|
|
{ Lists the objects for each cell in the grid. Setting Objects forces a descendant
|
|
of @link(TKGridObjectCell) to be created for the related cell. If @link(TKCustomGrid.CellClass)
|
|
contains such a descendant, then it will be used instead of TKGridObjectCell.
|
|
TObject instance given to Objects will be then stored in @link(TKGridObjectCell.CellObject)
|
|
property. In contrast to TStringGrid, the passed TObject is owned by the
|
|
TKGridObjectCell instance. Override TKGridObjectCell to implement another
|
|
behavior. }
|
|
property Objects[ACol, ARow: Integer]: TObject read GetObjects write SetObjects;
|
|
{ Specifies basic display and behavioral properties of the grid. }
|
|
property Options: TKGridOptions read FOptions write SetOptions default cOptionsDef;
|
|
{ Specifies extended display and behavioral properties of the grid. }
|
|
property OptionsEx: TKGridOptionsEx read FOptionsEx write SetOptionsEx default cOptionsExDef;
|
|
{ Inherited property - see Delphi help. }
|
|
property ParentColor default False;
|
|
{ Specifies the style how multiple cells are selected. }
|
|
property RangeSelectStyle: TKGridRangeSelectStyle read FRangeSelectStyle write FRangeSelectStyle default cRangeSelectStyleDef;
|
|
{ Gains access to selection base cell. Setting Row discards the current selection
|
|
and moves focus to a new base cell in the current column that is in the new row.
|
|
The first row has an index of 0, the second row an index of 1, and so on.
|
|
If the index denotes a row that is not selectable, nothing happens. }
|
|
property Row: Integer read FSelection.Row1 write SetRow;
|
|
{ Row class used to create new row instances. Row instances are always
|
|
created when @link(TKCustomGrid.RowCount) grows. }
|
|
property RowClass: TKGridRowClass read FRowClass write FRowClass;
|
|
{ Specifies the number of rows in the grid. Set RowCount to add or delete rows
|
|
at the bottom of the grid. The value of RowCount includes any fixed rows at
|
|
the top of the grid as well as the scrollable rows in the body of the grid. }
|
|
property RowCount: Integer read FRowCount write SetRowCount default cRowCountDef;
|
|
{ Indicates the height (in pixels) of all the rows in the grid. Set RowHeights
|
|
at runtime to change the height of an individual row. If the height of
|
|
a row has not been set explicitly by resizing with the mouse, or by using
|
|
the RowHeights property, its height is @link(TKCustomGrid.DefaultRowHeight). }
|
|
property RowHeights[Index: Integer]: Integer read GetRowHeights write SetRowHeights;
|
|
{ Gains access to the row instances. Row instances are always
|
|
created by utilizing @link(TKCustomGrid.RowClass) when @link(TKCustomGrid.RowCount)
|
|
grows. To replace all other row instances with ColClass, call
|
|
@link(TKCustomGrid.RealizeRowClass). }
|
|
property Rows[Index: Integer]: TKGridRow read GetRows;
|
|
{ Specifies whether the grid includes horizontal and vertical scroll bars.
|
|
If all the cells in the grid fit in the ClientWidth, no horizontal scroll bar
|
|
appears, even if ScrollBars is ssHorizontal or ssBoth. If all the cells fit
|
|
in the ClientHeight, no vertical scroll bar appears, even if ScrollBars is
|
|
ssVertical or ssBoth. }
|
|
property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default cScrollBarsDef;
|
|
{ Specifies how horizontal scrollbar's trackbar scrolls the grid. }
|
|
property ScrollModeHorz: TKGridScrollMode read FScrollModeHorz write SetScrollModeHorz default cScrollModeDef;
|
|
{ Specifies how vertical scrollbar's trackbar scrolls the grid. }
|
|
property ScrollModeVert: TKGridScrollMode read FScrollModeVert write SetScrollModeVert default cScrollModeDef;
|
|
{ Specifies how fast the scrolling by timer should be. }
|
|
property ScrollSpeed: Cardinal read FScrollSpeed write SetScrollSpeed default cScrollSpeedDef;
|
|
{ Indicates the boundaries of the current selection. Set Selection to select
|
|
a range of cells in the grid. In the TKGridRect structure, the Cell1 parameter
|
|
always denotes base selection cell and Cell2 expanded selection cell.
|
|
A base cell is always the cell that has input focus and can be currently
|
|
edited. An expanded cell denotes the other selection corner. }
|
|
property Selection: TKGridRect read GetSelection write SetSelection;
|
|
{ Returns the current number of selections. Returns always a value greater or equal to 1. }
|
|
property SelectionCount: Integer read GetSelectionCount;
|
|
{ Returns the selection rectangle. }
|
|
property SelectionRect: TRect read GetSelectionRect;
|
|
{ Gains access to all currently existing selections. This property cannot be used
|
|
to add new selection. Please use @link(TKCustomGrid.SelectionAdd) instead. }
|
|
property Selections[Index: Integer]: TKGridRect read GetSelections write SetSelections;
|
|
{ Specifies how a column or row appears while being resized by mouse. }
|
|
property SizingStyle: TKGridSizingStyle read FSizingStyle write SetSizingStyle default cSizingStyleDef;
|
|
{ Returns index of the column having its SortMode property smDown or smUp.
|
|
There must be always one such column in the grid. }
|
|
property SortCol: Integer read GetSortCol;
|
|
{ Returns index of the row having its SortMode property smDown or smUp.
|
|
There must be always one such row in the grid. }
|
|
property SortRow: Integer read GetSortRow;
|
|
{ Specifies how sorting is performed when user clicks on clickable fixed cells
|
|
that normally indicate sorting by an arrow. }
|
|
property SortStyle: TKGridSortStyle read FSortStyle write FSortStyle default cSortStyleDef;
|
|
{ Indicates whether the user can tab to specified columns in the grid if
|
|
goTabs is included in @link(TKCustomGrid.Options). Set TabStops to False
|
|
to remove the column identified by Index from the tab order. The first column
|
|
in the grid is identified by an Index of 0. Setting TabStops for fixed
|
|
columns has no effect. }
|
|
property TabStops[Index: Integer]: Boolean read GetTabStops write SetTabStops;
|
|
{ Determines if cells can be painted with OS themes at the moment. Returns
|
|
True if OS themes are available and both goThemes and goThemedCells are
|
|
included in @link(TKCustomGrid.Options). }
|
|
property ThemedCells: Boolean read GetThemedCells;
|
|
{ Determines if OS themes are available to the grid. }
|
|
property Themes: Boolean read GetThemes;
|
|
{ If the SelectedByMouse parameter in @link(TKCustomGrid.OnEditorSelect) is True
|
|
you can set ThroughClick to True to click the inplace editor within the same
|
|
mouse click that selected this cell. }
|
|
property ThroughClick: Boolean read FThroughClick write FThroughClick;
|
|
{ Specifies the index of the first visible scrollable row in the grid.
|
|
Set TopRow to scroll the rows in the grid so that the row with index
|
|
TopRow is the first row after the fixed rows. }
|
|
property TopRow: Integer read FTopLeft.Row write SetTopRow;
|
|
{ Use VisibleColCount to determine the number of scrollable columns fully visible in the grid.
|
|
VisibleColCount does not include the fixed columns counted by the FixedCols property.
|
|
It does not include any partially visible columns on the right edge of the grid. }
|
|
property VisibleColCount: Integer read GetVisibleColCount;
|
|
{ Indicates the area of scrollable cells visible in the grid. VisibleGridRect does not
|
|
include any fixed cells or partially visible cells on the right or bottom side of the grid. }
|
|
property VisibleGridRect: TKGridRect read GetVisibleGridRect;
|
|
{ Use VisibleRowCount to determine the number of scrollable rows fully visible in the grid.
|
|
VisibleRowCount does not include the fixed rows counted by the FixedRows property.
|
|
It does not include any partially visible rows on the bottom of the grid. }
|
|
property VisibleRowCount: Integer read GetVisibleRowCount;
|
|
{ OnBeginColDrag is called when the user clicks on a column to start dragging.
|
|
It enables the grid to control whether the column can be repositioned and
|
|
if so, which column. Origin is the index of the column to be dragged.
|
|
When OnBeginColDrag occurs, this is the index of the column in which the mouse
|
|
was clicked. You can change this value for application specific behavior. }
|
|
property OnBeginColDrag: TKGridBeginDragEvent read FOnBeginColDrag write FOnBeginColDrag;
|
|
{ OnBeginColSizing is called when the user clicks between two columns to start
|
|
resizing. It enables the grid to control whether the column can be resized and
|
|
if so, which column. Index is the index of the column to be resized. Pos is
|
|
the X-coordinate of the sizing line. These values correspond with the default
|
|
processing initiated by mouse click. You can change both of these values
|
|
for application specific behavior. }
|
|
property OnBeginColSizing: TKGridBeginSizingEvent read FOnBeginColSizing write FOnBeginColSizing;
|
|
{ OnBeginRowDrag is called when the user clicks on a row to start dragging.
|
|
It enables the grid to control whether the row can be repositioned and
|
|
if so, which row. Origin is the index of the row to be dragged.
|
|
When OnBeginRowDrag occurs, this is the index of the row in which the mouse
|
|
was clicked. You can change this value for application specific behavior. }
|
|
property OnBeginRowDrag: TKGridBeginDragEvent read FOnBeginRowDrag write FOnBeginRowDrag;
|
|
{ OnBeginRowSizing is called when the user clicks between two rows to start
|
|
resizing. It enables the grid to control whether the row can be resized and
|
|
if so, which row. Index is the index of the row to be resized. Pos is
|
|
the Y-coordinate of the sizing line. These values correspond with the default
|
|
processing initiated by mouse click. You can change both of these values
|
|
for application specific behavior. }
|
|
property OnBeginRowSizing: TKGridBeginSizingEvent read FOnBeginRowSizing write FOnBeginRowSizing;
|
|
{ OnCellSpan is called whenever the grid needs to get information about column
|
|
or row span of current cell. Use this only in virtual grid mode and do not write
|
|
complex code here as this event is called really VERY frequently. You must provide
|
|
the same cell span information as the TKGridCell.@link(TKGridCell.Span) for
|
|
non-virtual mode. }
|
|
property OnCellSpan: TKGridCellSpanEvent read FOnCellSpan write FOnCellSpan;
|
|
{ OnChanged is called after @link(TKCustomGrid.OnEditorDataToGrid) only if
|
|
@link(TKCustomGrid.OnCompareCellInstances) returns different cells. Its purpose
|
|
is to notify the application about any changes the user made via inplace editors.
|
|
Does not work in virtual mode (if goVirtualGrid is included in @link(TKCustomGrid.Options)). }
|
|
property OnChanged: TKGridCellEvent read FOnChanged write FOnChanged;
|
|
{ OnCheckColDrag validates whether the column currently selected for dragging
|
|
can be dropped at the current location. Origin is the index of the column being
|
|
actually dragged. Destination represents the potential drop target. You can
|
|
modify Destination or set CanDrop to False for application specific behavior. }
|
|
property OnCheckColDrag: TKGridCheckDragEvent read FOnCheckColDrag write FOnCheckColDrag;
|
|
{ OnCheckRowDrag validates whether the row currently selected for dragging
|
|
can be dropped at the current location. Origin is the index of the row being
|
|
actually dragged. Destination represents the potential drop target. You can
|
|
modify Destination or set CanDrop to False for application specific behavior. }
|
|
property OnCheckRowDrag: TKGridCheckDragEvent read FOnCheckRowDrag write FOnCheckRowDrag;
|
|
{ OnColumnMoved is called after a column has been physically moved. }
|
|
property OnColumnMoved: TKGridMovedEvent read FOnColMoved write FOnColMoved;
|
|
{ OnColWidthsChanged is called whenever the width of a single or more columns changes. }
|
|
property OnColWidthsChanged: TNotifyEvent read FOnColWidthsChanged write FOnColWidthsChanged;
|
|
{ OnColWidthsChangedEx is called whenever the width of a single or more columns changes.
|
|
AIndex corresponds to the first column whose width has been modified. }
|
|
property OnColWidthsChangedEx: TKGridExtentEvent read FOnColWidthsChangedEx write FOnColWidthsChangedEx;
|
|
{ OnCompareCellInstances is currently called only if the grid needs to decide
|
|
whether to call the @link(TKCustomGrid.OnChanged) event handler. This event
|
|
is not called in virtual mode (if goVirtualGrid is included in @link(TKCustomGrid.Options)). }
|
|
property OnCompareCellInstances: TKGridCompareCellInstancesEvent read FOnCompareCellInstances write FOnCompareCellInstances;
|
|
{ OnCompareCells is called whenever the grid needs to compare contents of two
|
|
cells. This occurs if the @link(TKCustomGrid.SortCols), @link(TKCustomGrid.SortRows),
|
|
@link(TKCustomGrid.InsertSortedCol) and @link(TKCustomGrid.InsertSortedRow)
|
|
methods are called, either programmatically or by mouse click on the first
|
|
fixed column or row. Do not write complex code here as this event is called
|
|
VERY frequently. To speed up sorting, use properties introduced for fast
|
|
data access, such as @link(TKCustomGrid.ArrayOfCells) or
|
|
@link(TKGridTextCell.TextPtr). }
|
|
property OnCompareCells: TKGridCompareCellsEvent read FOnCompareCells write FOnCompareCells;
|
|
{ OnCustomSortCols is called whenever the grid needs to sort columns. Use this
|
|
event to override the default sorting algorithm. }
|
|
property OnCustomSortCols: TKGridCustomSortEvent read FOnCustomSortCols write FOnCustomSortCols;
|
|
{ OnCustomSortRows is called whenever the grid needs to sort rows. Use this
|
|
event to override the default sorting algorithm. }
|
|
property OnCustomSortRows: TKGridCustomSortEvent read FOnCustomSortRows write FOnCustomSortRows;
|
|
{ OnDrawCell is called whenever a cell in the grid needs to be drawn. Draw
|
|
on the cell using the methods of the Canvas property. If the OnDrawCell event
|
|
handler is not assigned, all cells in grid will be painted with the cell
|
|
class aware @link(TKGridCell.DrawCell) method. If the cell has no assigned
|
|
cell instance, it appears empty. }
|
|
property OnDrawCell: TKGridDrawCellEvent read FOnDrawCell write FOnDrawCell;
|
|
{ OnEditorCreate is called whenever a cell is about to be edited. This event
|
|
handler allows you to create a custom inplace editor for each cell. The editor
|
|
should only be created, such as by means of AEditor := TEdit.Create(nil).
|
|
Correct positioning within the grid, focusing, painting etc. is maintained
|
|
later by grid itself. No manipulation requiring the editor's Handle is allowed here. }
|
|
property OnEditorCreate: TKGridEditorCreateEvent read FOnEditorCreate write FOnEditorCreate;
|
|
{ OnEditorDataFromGrid is called after @link(TKCustomGrid.OnEditorCreate).
|
|
The inplace editor is correctly positioned, has a parent control, its Handle
|
|
is allocated but is still not visible. Set data from the grid to the inplace
|
|
editor in an user defined way here. Data can be set in EditorCreate but some
|
|
assignments need that the inplace editor has a parent control. Grid is always
|
|
parent control of inplace editor. }
|
|
property OnEditorDataFromGrid: TKGridEditorDataEvent read FOnEditorDataFromGrid write FOnEditorDataFromGrid;
|
|
{ OnEditorDataToGrid is called if the inplace editor is about to disappear.
|
|
The inplace editor is still visible here and has a parent control. Its Handle
|
|
is still allocated. Set data from the inplace editor to the grid in an user
|
|
defined way here. Data can be transferred in @link(TKCustomGrid.EditorDestroy)
|
|
but some assignments need that the inplace editor has a parent control. }
|
|
property OnEditorDataToGrid: TKGridEditorDataEvent read FOnEditorDataToGrid write FOnEditorDataToGrid;
|
|
{ OnEditorDestroy is called after @link(TKCustomGrid.OnEditorDataToGrid),
|
|
just before the inplace editor is destroyed. It is no longer visible here
|
|
and has no parent control. Its Handle is no more valid. Perform application
|
|
specific operations just before the editor is destroyed here. You need not
|
|
destroy the AEditor instance, but if so, set AEditor to nil after destroying it
|
|
<i>Example:</i> FreeAndNil(AEditor). }
|
|
property OnEditorDestroy: TKGridEditorDestroyEvent read FOnEditorDestroy write FOnEditorDestroy;
|
|
{ OnEditorKeyPreview is called whenever inplace editor is focused and the user
|
|
presses some key that is normally handled by the grid if no inplace editor
|
|
is visible. Sometimes this key needs to be handled by the grid instead of
|
|
the inplace editor. For example, the @link(EditKeyPreview) function decides
|
|
whether the key needs to be handled by the grid or by the inplace editor.
|
|
Write your own code that is specific for your custom inplace editors. }
|
|
property OnEditorKeyPreview: TKGridEditorKeyPreviewEvent read FOnEditorKeyPreview write FOnEditorKeyPreview;
|
|
{ OnEditorResize is called whenever the grid needs to relocate the inplace
|
|
editor (this might be quite often). By default, each inplace editor is always
|
|
located so that its bounding rectangle equals to the cell rectangle.
|
|
Write your own code to change this behavior. Inplace editors cannot appear
|
|
outside the edited cell, clipping is always present. <i>Note:</i> Not every
|
|
TWinControl instance intended as inplace editor can be arbitrary resized. }
|
|
property OnEditorResize: TKGridEditorResizeEvent read FOnEditorResize write FOnEditorResize;
|
|
{ OnEditorSelect is called immediately after @link(TKCustomGrid.OnEditorDataFromGrid).
|
|
This event handler allows you to correctly set the caret position within
|
|
your inplace editor. }
|
|
property OnEditorSelect: TKGridEditorSelectEvent read FOnEditorSelect write FOnEditorSelect;
|
|
{ Determines whether a particular column can be dropped immediately after
|
|
the user releases the mouse button but before the column is actually moved. }
|
|
property OnEndColDrag: TKGridEndDragEvent read FOnEndColDrag write FOnEndColDrag;
|
|
{ Determines whether a particular column can be resized immediately after
|
|
the user releases the mouse button but before the column is actually resized.
|
|
This event handler has no effect if @link(TKCustomGrid.SizingStyle) is ssUpdate. }
|
|
property OnEndColSizing: TKGridEndSizingEvent read FOnEndColSizing write FOnEndColSizing;
|
|
{ Determines whether a particular row can be dropped immediately after
|
|
the user releases the mouse button but before the row is actually moved. }
|
|
property OnEndRowDrag: TKGridEndDragEvent read FOnEndRowDrag write FOnEndRowDrag;
|
|
{ Determines whether a particular row can be resized immediately after
|
|
the user releases the mouse button but before the row is actually resized.
|
|
This event handler has no effect if @link(TKCustomGrid.SizingStyle) is ssUpdate. }
|
|
property OnEndRowSizing: TKGridEndSizingEvent read FOnEndRowSizing write FOnEndRowSizing;
|
|
{ OnExchangeCols is called whenever the grid sorts columns or needs to
|
|
exchange two columns. Typically you assign this event handler in virtual
|
|
grid mode @link(goVirtualGrid) to physically sort your data or when
|
|
implementing a custom behavior parallel to sorting cell instances owned
|
|
by the grid. This event is called from @link(TKCustomGrid.MoveCol), either. }
|
|
property OnExchangeCols: TKGridExchangeEvent read FOnExchangeCols write FOnExchangeCols;
|
|
{ OnExchangeRows is called whenever the grid sorts rows or needs to
|
|
exchange two rows. Typically you assign this event handler in virtual
|
|
grid mode @link(goVirtualGrid) to physically sort your data or when
|
|
implementing a custom behavior parallel to sorting cell instances owned
|
|
by the grid. This event is called from @link(TKCustomGrid.MoveRow), either. }
|
|
property OnExchangeRows: TKGridExchangeEvent read FOnExchangeRows write FOnExchangeRows;
|
|
{ OnMeasureCell is called whenever the grid needs to get the horizontal and vertical extent
|
|
of the data displayed in a cell. If the OnMeasureCell event
|
|
handler is not assigned, all cells in the grid will be measured by default. }
|
|
property OnMeasureCell: TKGridMeasureCellEvent read FOnMeasureCell write FOnMeasureCell;
|
|
{ OnMouseCellHint is called whenever a cell is clicked by left mouse button. }
|
|
property OnMouseCellHint: TKGridCellHintEvent read FOnMouseCellHint write FOnMouseCellHint;
|
|
{ OnMouseClickCell is called whenever a cell is clicked by left mouse button. }
|
|
property OnMouseClickCell: TKGridCellEvent read FOnMouseClickCell write FOnMouseClickCell;
|
|
{ OnMouseDblClickCell is called whenever a cell is clicked by left mouse button. }
|
|
property OnMouseDblClickCell: TKGridCellEvent read FOnMouseDblClickCell write FOnMouseDblClickCell;
|
|
{ OnMouseEnterCell is called whenever mouse enters a cell. }
|
|
property OnMouseEnterCell: TKGridCellEvent read FOnMouseEnterCell write FOnMouseEnterCell;
|
|
{ OnMouseLeaveCell is called whenever mouse leaves a cell. }
|
|
property OnMouseLeaveCell: TKGridCellEvent read FOnMouseLeaveCell write FOnMouseLeaveCell;
|
|
{ OnRowHeightsChanged is called whenever the height of a single or more rows changes. }
|
|
property OnRowHeightsChanged: TNotifyEvent read FOnRowHeightsChanged write FOnRowHeightsChanged;
|
|
{ OnRowHeightsChangedEx is called whenever the height of a single or more rows changes.
|
|
AIndex corresponds to the first row whose height has been modified. }
|
|
property OnRowHeightsChangedEx: TKGridExtentEvent read FOnRowHeightsChangedEx write FOnRowHeightsChangedEx;
|
|
{ OnRowMoved is called after a row has been physically moved. }
|
|
property OnRowMoved: TKGridMovedEvent read FOnRowMoved write FOnRowMoved;
|
|
{ OnSelectCell is called whenever a cell is about to be selected. A cell can
|
|
be selected either by mouse or keyboard, or programmatically e.g. by the
|
|
@link(TKCustomGrid.FocusCell) method. CanSelect is True by default to allow all
|
|
selectable cells to be selected. Change this parameter to False to disallow
|
|
cell selection. A cell that cannot be selected, cannot be edited as well.
|
|
Many times you need some cells not to become editable. In this case,
|
|
let @link(TKCustomGrid.OnEditorCreate) decide it rather than OnSelectCell. }
|
|
property OnSelectCell: TKGridSelectCellEvent read FOnSelectCell write FOnSelectCell;
|
|
{ OnSelectionExpand is called if the user expands the current selection.
|
|
The selection can be expanded either by mouse or keyboard, or programmatically
|
|
e.g. by the @link(TKCustomGrid.Selection) property. CanExpand is True by default
|
|
to allow all cells to become a target of selection expansion. Change this
|
|
parameter to False to disallow selection expansion.}
|
|
property OnSelectionExpand: TKGridSelectionExpandEvent read FOnSelectionExpand write FOnSelectionExpand;
|
|
{ OnSizeChanged is called whenever the @link(TKCustomGrid.ColCount) or
|
|
@link(TKCustomGrid.RowCount) properties change. }
|
|
property OnSizeChanged: TKGridSizeChangedEvent read FOnSizeChanged write FOnSizeChanged;
|
|
{ OnTopLeftChanged is called whenever the @link(TKCustomGrid.LeftCol) or
|
|
@link(TKCustomGrid.TopRow) properties change. }
|
|
property OnTopLeftChanged: TNotifyEvent read FOnTopLeftChanged write FOnTopLeftChanged;
|
|
end;
|
|
|
|
{ @abstract(KGrid design-time component) This is the class you use both
|
|
on run-time and design-time. }
|
|
TKGrid = class(TKCustomGrid)
|
|
published
|
|
{ Inherited property - see Delphi help. }
|
|
property Align;
|
|
{ Inherited property - see Delphi help. }
|
|
property Anchors;
|
|
{ See TKCustomControl.@link(TKCustomControl.BorderStyle) for details. }
|
|
property BorderStyle;
|
|
{ Inherited property - see Delphi help. }
|
|
property BorderWidth;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.ColCount) for details. }
|
|
property ColCount;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.Color) for details. }
|
|
property Color;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.Colors) for details. }
|
|
property Colors;
|
|
{ Inherited property - see Delphi help. }
|
|
property Constraints;
|
|
{$IFDEF FPC}
|
|
{ See TKCustomGrid.@link(TKCustomGrid.Flat) for details. }
|
|
property Flat;
|
|
{$ELSE}
|
|
{ Inherited property - see Delphi help. }
|
|
property Ctl3D;
|
|
{$ENDIF}
|
|
{ See TKCustomGrid.@link(TKCustomGrid.DefaultColWidth) for details. }
|
|
property DefaultColWidth;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.DefaultDrawing) for details. }
|
|
property DefaultDrawing;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.DefaultRowHeight) for details. }
|
|
property DefaultRowHeight;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.DisabledDrawStyle) for details. }
|
|
property DisabledDrawStyle;
|
|
{ Inherited property - see Delphi help. }
|
|
property DragCursor;
|
|
{ Inherited property - see Delphi help. }
|
|
property DragKind;
|
|
{ Inherited property - see Delphi help. }
|
|
property DragMode;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.DragStyle) for details. }
|
|
property DragStyle;
|
|
{ Inherited property - see Delphi help. }
|
|
property Enabled;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.FixedCols) for details. }
|
|
property FixedCols;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.FixedRows) for details. }
|
|
property FixedRows;
|
|
{ Inherited property - see Delphi help. }
|
|
property Font;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.GridLineWidth) for details. }
|
|
property GridLineWidth;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.MinColWidth) for details. }
|
|
property MinColWidth;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.MinRowHeight) for details. }
|
|
property MinRowHeight;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.MouseCellHintTime) for details. }
|
|
property MouseCellHintTime;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.MoveDirection) for details. }
|
|
property MoveDirection;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.Options) for details. }
|
|
property Options;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OptionsEx) for details. }
|
|
property OptionsEx;
|
|
{ Inherited property - see Delphi help. }
|
|
property ParentColor;
|
|
{ Inherited property - see Delphi help. }
|
|
property ParentFont;
|
|
{ Inherited property - see Delphi help. }
|
|
property ParentShowHint;
|
|
{ Inherited property - see Delphi help. }
|
|
property PopupMenu;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.RangeSelectStyle) for details. }
|
|
property RangeSelectStyle;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.RowCount) for details. }
|
|
property RowCount;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.ScrollBars) for details. }
|
|
property ScrollBars;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.ScrollModeHorz) for details. }
|
|
property ScrollModeHorz;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.ScrollModeVert) for details. }
|
|
property ScrollModeVert;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.ScrollSpeed) for details. }
|
|
property ScrollSpeed;
|
|
{ Inherited property - see Delphi help. }
|
|
property ShowHint;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.SizingStyle) for details. }
|
|
property SizingStyle;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.SortStyle) for details. }
|
|
property SortStyle;
|
|
{ Inherited property - see Delphi help. }
|
|
property TabOrder;
|
|
{ Inherited property - see Delphi help. }
|
|
property TabStop default True;
|
|
{ Inherited property - see Delphi help. }
|
|
property Visible;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnBeginColDrag) for details. }
|
|
property OnBeginColDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnBeginColSizing) for details. }
|
|
property OnBeginColSizing;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnBeginRowDrag) for details. }
|
|
property OnBeginRowDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnBeginRowSizing) for details. }
|
|
property OnBeginRowSizing;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCellSpan) for details. }
|
|
property OnCellSpan;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnChanged) for details. }
|
|
property OnChanged;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCheckColDrag) for details. }
|
|
property OnCheckColDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCheckRowDrag) for details. }
|
|
property OnCheckRowDrag;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnClick;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnColumnMoved) for details. }
|
|
property OnColumnMoved;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnColWidthsChanged) for details. }
|
|
property OnColWidthsChanged;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnColWidthsChangedEx) for details. }
|
|
property OnColWidthsChangedEx;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCompareCellInstances) for details. }
|
|
property OnCompareCellInstances;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCompareCells) for details. }
|
|
property OnCompareCells;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnContextPopup;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCustomSortCols) for details. }
|
|
property OnCustomSortCols;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnCustomSortRows) for details. }
|
|
property OnCustomSortRows;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnDblClick;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnDockDrop;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnDockOver;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnDragDrop;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnDragOver;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnDrawCell) for details. }
|
|
property OnDrawCell;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorCreate) for details. }
|
|
property OnEditorCreate;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorDataFromGrid) for details. }
|
|
property OnEditorDataFromGrid;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorDataToGrid) for details. }
|
|
property OnEditorDataToGrid;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorDestroy) for details. }
|
|
property OnEditorDestroy;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorKeyPreview) for details. }
|
|
property OnEditorKeyPreview;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorResize) for details. }
|
|
property OnEditorResize;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEditorSelect) for details. }
|
|
property OnEditorSelect;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEndColDrag) for details. }
|
|
property OnEndColDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEndColSizing) for details. }
|
|
property OnEndColSizing;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnEndDock;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnEndDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEndRowDrag) for details. }
|
|
property OnEndRowDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnEndRowSizing) for details. }
|
|
property OnEndRowSizing;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnEnter;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnExit;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnExchangeCols) for details. }
|
|
property OnExchangeCols;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnExchangeRows) for details. }
|
|
property OnExchangeRows;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnGetSiteInfo;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnKeyDown;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnKeyPress;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnKeyUp;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnMeasureCell) for details. }
|
|
property OnMeasureCell;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnMouseCellHint) for details. }
|
|
property OnMouseCellHint;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnMouseClickCell) for details. }
|
|
property OnMouseClickCell;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnMouseDblClickCell) for details. }
|
|
property OnMouseDblClickCell;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseDown;
|
|
{$IFDEF COMPILER9_UP}
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseEnter;
|
|
{$ENDIF}
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnMouseEnterCell) for details. }
|
|
property OnMouseEnterCell;
|
|
{$IFDEF COMPILER9_UP}
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseLeave;
|
|
{$ENDIF}
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnMouseLeaveCell) for details. }
|
|
property OnMouseLeaveCell;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseMove;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseUp;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseWheel;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseWheelDown;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnMouseWheelUp;
|
|
{ This event is called at certain phases of the actually running print job. }
|
|
property OnPrintNotify;
|
|
{ This event is called after the shape is drawn onto the printer canvas. }
|
|
property OnPrintPaint;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnResize;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnRowHeightsChanged) for details. }
|
|
property OnRowHeightsChanged;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnRowHeightsChangedEx) for details. }
|
|
property OnRowHeightsChangedEx;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnRowMoved) for details. }
|
|
property OnRowMoved;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnSelectCell) for details. }
|
|
property OnSelectCell;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnSelectionExpand) for details. }
|
|
property OnSelectionExpand;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnSizeChanged) for details. }
|
|
property OnSizeChanged;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnStartDock;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnStartDrag;
|
|
{ See TKCustomGrid.@link(TKCustomGrid.OnTopLeftChanged) for details. }
|
|
property OnTopLeftChanged;
|
|
{ Inherited property - see Delphi help. }
|
|
property OnUnDock;
|
|
end;
|
|
|
|
{ Determines if the Cell specified by ACol and ARow lies within grid rectangle R. }
|
|
function CellInGridRect(ACol, ARow: Integer; const R: TKGridRect): Boolean;
|
|
|
|
{ Determines if the grid rectangle contains a subset of cells belonging to the
|
|
column specified by ACol. }
|
|
function ColInGridRect(ACol: Integer; const R: TKGridRect): Boolean;
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultComboKeyPreview) instead. }
|
|
procedure ComboKeyPreview(AGrid: TKCustomGrid; AEditor: TComboBox;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultComboSelect) instead. }
|
|
procedure ComboSelect(AGrid: TKCustomGrid; AEditor: TComboBox; SelectAll,
|
|
CaretToLeft: Boolean);
|
|
|
|
{ Compares two TKGridAxisItems arrays. The function returns True if the arrays are
|
|
equal in length and all corresponding TKGridAxisItem instances within both arrays
|
|
have equal property values. }
|
|
function CompareAxisItems(AxisItems1, AxisItems2: TKGridAxisItems): Boolean;
|
|
|
|
{ Obsolete function. Implements default painting for TKCustomGrid cells.
|
|
Call TKCustomGrid.CellPainter.@link(TKGridCellPainter.DefaultDraw) instead. }
|
|
procedure DefaultDrawCell(AGrid: TKCustomGrid; ACol, ARow: Integer; ARect: TRect;
|
|
AState: TKGridDrawState; HAlign: TKHAlign; VAlign: TKVAlign;
|
|
HPadding, VPadding: Integer; const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditorKeyPreview) instead. }
|
|
procedure DefaultKeyPreview(AGrid: TKCustomGrid; AEditor: TWinControl;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditorSelect) instead. }
|
|
procedure DefaultSelect(AGrid: TKCustomGrid; AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean);
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditKeyPreview) instead. }
|
|
procedure EditKeyPreview(AGrid: TKCustomGrid; AEditor: TCustomEdit;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultEditSelect) instead. }
|
|
procedure EditSelect(AGrid: TKCustomGrid; AEditor: TCustomEdit; SelectAll,
|
|
CaretToLeft: Boolean);
|
|
|
|
{ Makes a @link(TKGridCoord) record from ACol and ARow. }
|
|
function GridPoint(ACol, ARow: Integer): TKGridCoord;
|
|
|
|
{ Makes a @link(TKGridRect) record from ACell. Cell will be copied both to Cell1 and
|
|
Cell2 fields of the resulting grid rectangle. }
|
|
function GridRect(ACell: TKGridCoord): TKGridRect; overload;
|
|
|
|
{ Makes a @link(TKGridRect) record from ACell1 and ACell2. All the input parameters
|
|
will be copied to the corresponding fields of the resulting grid rectangle. }
|
|
function GridRect(ACell1, ACell2: TKGridCoord): TKGridRect; overload;
|
|
|
|
{ Makes a @link(TKGridRect) record from ACol1, ARow1, ACol2 and ARow2. All the input
|
|
parameters will be copied to the corresponding fields of the resulting grid rectangle. }
|
|
function GridRect(ACol1, ARow1, ACol2, ARow2: Integer): TKGridRect; overload;
|
|
|
|
{ Compares two grid rectangles. Returns True if all the corresponding fields
|
|
in GridRect1 equal those in GridRect2. }
|
|
function GridRectEqual(const GridRect1, GridRect2: TKGridRect): Boolean;
|
|
|
|
{ Makes a @link(TKGridCellSpan) record from AColumns and ARows. }
|
|
function MakeCellSpan(AColumns, ARows: Integer): TKGridCellSpan;
|
|
|
|
{ Makes Cell1 field of GridRect always top-left cell and Cell2 field always
|
|
bottom-right cell. }
|
|
procedure NormalizeGridRect(var GridRect: TKGridRect);
|
|
|
|
{ Determines if the grid rectangle contains a subset of cells belonging to the
|
|
row specified by ARow. }
|
|
function RowInGridRect(ARow: Integer; const R: TKGridRect): Boolean;
|
|
|
|
{ Obsolete function. Call TKCustomGrid.@link(TKCustomGrid.DefaultScrollBarKeyPreview) instead. }
|
|
procedure ScrollBarKeyPreview(AGrid: TKCustomGrid; AEditor: TScrollBar;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math, TypInfo
|
|
{$IFDEF USE_THEMES}
|
|
, Themes
|
|
{$IFNDEF FPC}
|
|
, UxTheme
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
;
|
|
|
|
function CellInGridRect(ACol, ARow: Integer; const R: TKGridRect): Boolean;
|
|
begin
|
|
Result := (
|
|
(R.Col1 <= R.Col2) and (ACol >= R.Col1) and (ACol <= R.Col2) or
|
|
(R.Col1 > R.Col2) and (ACol >= R.Col2) and (ACol <= R.Col1)
|
|
) and (
|
|
(R.Row1 <= R.Row2) and (ARow >= R.Row1) and (ARow <= R.Row2) or
|
|
(R.Row1 > R.Row2) and (ARow >= R.Row2) and (ARow <= R.Row1)
|
|
)
|
|
end;
|
|
|
|
function ColInGridRect(ACol: Integer; const R: TKGridRect): Boolean;
|
|
begin
|
|
Result := (
|
|
(R.Col1 <= R.Col2) and (ACol >= R.Col1) and (ACol <= R.Col2) or
|
|
(R.Col1 > R.Col2) and (ACol >= R.Col2) and (ACol <= R.Col1)
|
|
);
|
|
end;
|
|
|
|
procedure ComboKeyPreview(AGrid: TKCustomGrid; AEditor: TComboBox;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
AGrid.DefaultComboKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey);
|
|
end;
|
|
|
|
procedure ComboSelect(AGrid: TKCustomGrid; AEditor: TComboBox; SelectAll,
|
|
CaretToLeft: Boolean);
|
|
begin
|
|
AGrid.DefaultComboSelect(AEditor, SelectAll, CaretToLeft);
|
|
end;
|
|
|
|
function CompareAxisItems(AxisItems1, AxisItems2: TKGridAxisItems): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := Length(AxisItems1) = Length(AxisItems2);
|
|
if Result then
|
|
for I := 0 to Length(AxisItems1) - 1 do
|
|
if not AxisItems1[I].Equals(AxisItems2[I]) then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
procedure DefaultDrawCell(AGrid: TKCustomGrid; ACol, ARow: Integer; ARect: TRect;
|
|
AState: TKGridDrawState; HAlign: TKHAlign; VAlign: TKVAlign;
|
|
HPadding, VPadding: Integer; const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
begin
|
|
with AGrid do
|
|
begin
|
|
CellPainter.Initialize;
|
|
CellPainter.Col := ACol;
|
|
CellPainter.Row := ARow;
|
|
CellPainter.CellRect := ARect;
|
|
CellPainter.State := AState;
|
|
CellPainter.HAlign := HAlign;
|
|
CellPainter.VAlign := VAlign;
|
|
CellPainter.HPadding := HPadding;
|
|
CellPainter.VPadding := VPadding;
|
|
CellPainter.Text := AText;
|
|
CellPainter.DefaultDraw;
|
|
end;
|
|
end;
|
|
|
|
procedure DefaultKeyPreview(AGrid: TKCustomGrid; AEditor: TWinControl;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
AGrid.DefaultEditorKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey);
|
|
end;
|
|
|
|
procedure DefaultSelect(AGrid: TKCustomGrid; AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean);
|
|
begin
|
|
AGrid.DefaultEditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse);
|
|
end;
|
|
|
|
function DirectionToCommand(Direction: TKGridMoveDirection): TKGridMoveCommand;
|
|
begin
|
|
case Direction of
|
|
mdDown: Result := mcDown;
|
|
mdLeft: Result := mcLeft;
|
|
mdRight: Result := mcRight;
|
|
else
|
|
Result := mcUp;
|
|
end;
|
|
end;
|
|
|
|
procedure DoEditKeyPreview(ATextLen, ASelStart, ASelLength, ALineCount: Integer;
|
|
AMultiLine, AStartLine, AEndLine: Boolean; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
if ((Key in [VK_LEFT, VK_HOME]) and ((ASelStart > 0) or (ASelLength > 1))) or // 1 to support TMaskEdit
|
|
((Key in [VK_RIGHT, VK_END]) and ((ASelStart < ATextLen) or (ASelLength > 0))) or
|
|
((Key in [VK_PRIOR, VK_UP]) and AMultiLine and (not AStartLine or (ASelLength > 0) and (ASelLength < ATextLen))) or
|
|
((Key in [VK_NEXT, VK_DOWN]) and AMultiLine and (not AEndLine or (ASelLength > 0) and (ASelLength < ATextLen))) or
|
|
(Key = VK_RETURN) and AMultiLine then
|
|
IsGridKey := False;
|
|
end;
|
|
|
|
procedure EditKeyPreview(AGrid: TKCustomGrid; AEditor: TCustomEdit;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
AGrid.DefaultEditKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey);
|
|
end;
|
|
|
|
procedure EditSelect(AGrid: TKCustomGrid; AEditor: TCustomEdit; SelectAll,
|
|
CaretToLeft: Boolean);
|
|
begin
|
|
AGrid.DefaultEditSelect(AEditor, SelectAll, CaretToLeft);
|
|
end;
|
|
|
|
function GridRectEqual(const GridRect1, GridRect2: TKGridRect): Boolean;
|
|
begin
|
|
Result := CompareMem(@GridRect1, @GridRect2, SizeOf(TKGridRect));
|
|
end;
|
|
|
|
function GridPoint(ACol, ARow: Integer): TKGridCoord;
|
|
begin
|
|
with Result do
|
|
begin
|
|
Col := ACol;
|
|
Row := ARow;
|
|
end;
|
|
end;
|
|
|
|
function GridRect(ACell: TKGridCoord): TKGridRect; overload;
|
|
begin
|
|
with Result do
|
|
begin
|
|
Col1 := ACell.Col;
|
|
Col2 := ACell.Col;
|
|
Row1 := ACell.Row;
|
|
Row2 := ACell.Row;
|
|
end;
|
|
end;
|
|
|
|
function GridRect(ACell1, ACell2: TKGridCoord): TKGridRect; overload;
|
|
begin
|
|
with Result do
|
|
begin
|
|
Cell1 := ACell1;
|
|
Cell2 := ACell2;
|
|
end;
|
|
end;
|
|
|
|
function GridRect(ACol1, ARow1, ACol2, ARow2: Integer): TKGridRect; overload;
|
|
begin
|
|
with Result do
|
|
begin
|
|
Col1 := ACol1;
|
|
Col2 := ACol2;
|
|
Row1 := ARow1;
|
|
Row2 := ARow2;
|
|
end;
|
|
end;
|
|
|
|
function MakeCellSpan(AColumns, ARows: Integer): TKGridCellSpan;
|
|
begin
|
|
Result.ColSpan := AColumns;
|
|
Result.RowSpan := ARows;
|
|
end;
|
|
|
|
procedure NormalizeGridRect(var GridRect: TKGridRect);
|
|
begin
|
|
if GridRect.Col1 > GridRect.Col2 then Exchange(GridRect.Col1, GridRect.Col2);
|
|
if GridRect.Row1 > GridRect.Row2 then Exchange(GridRect.Row1, GridRect.Row2);
|
|
end;
|
|
|
|
function RowInGridRect(ARow: Integer; const R: TKGridRect): Boolean;
|
|
begin
|
|
Result := (
|
|
(R.Row1 <= R.Row2) and (ARow >= R.Row1) and (ARow <= R.Row2) or
|
|
(R.Row1 > R.Row2) and (ARow >= R.Row2) and (ARow <= R.Row1)
|
|
);
|
|
end;
|
|
|
|
procedure ScrollBarKeyPreview(AGrid: TKCustomGrid; AEditor: TScrollBar;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
AGrid.DefaultScrollBarKeyPreview(AEditor, ACol, ARow, Key, ShiftState, IsGridKey);
|
|
end;
|
|
|
|
{ TKGridAxisItem }
|
|
|
|
constructor TKGridAxisItem.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
FGrid := AGrid;
|
|
FCanResize := True;
|
|
FExtent := 0;
|
|
FInitialPos := -1;
|
|
FMaxExtent := 0;
|
|
FMinExtent := 0;
|
|
FSortArrowIndex := 0;
|
|
end;
|
|
|
|
procedure TKGridAxisItem.Assign(Source: TKGridAxisItem);
|
|
begin
|
|
FCanResize := Source.CanResize;
|
|
FExtent := Source.Extent;
|
|
// FInitialPos := Source.InitialPos;
|
|
end;
|
|
|
|
procedure TKGridAxisItem.BeginDrag(var Origin: Integer;
|
|
const MousePt: TPoint; var CanBeginDrag: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TKGridAxisItem.CheckDrag(Origin: Integer; var Destination: Integer;
|
|
const MousePt: TPoint; var CanDrop: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TKGridAxisItem.EndDrag(Origin, Destination: Integer;
|
|
const MousePt: TPoint; var CanEndDrag: Boolean);
|
|
begin
|
|
end;
|
|
|
|
function TKGridAxisItem.{$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean;
|
|
begin
|
|
Result := (Item.Extent = FExtent) and
|
|
(Item.CanResize = FCanResize);
|
|
end;
|
|
|
|
procedure TKGridAxisItem.SetMaxExtent(AValue: Integer);
|
|
begin
|
|
if FMinExtent > 0 then
|
|
AValue := Max(AValue, FMinExtent);
|
|
if (AValue >= 0) and (FMaxExtent <> AValue) then
|
|
begin
|
|
FMaxExtent := AValue;
|
|
if (FMaxExtent > 0) and (FExtent > FMaxExtent) then
|
|
Extent := FMaxExtent;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAxisItem.SetMinExtent(AValue: Integer);
|
|
begin
|
|
if FMaxExtent > 0 then
|
|
AValue := Min(AValue, FMaxExtent);
|
|
if (AValue >= 0) and (FMinExtent <> AValue) then
|
|
begin
|
|
FMinExtent := AValue;
|
|
if (FMinExtent > 0) and Visible and (FExtent < FMinExtent) then
|
|
Extent := FMinExtent;
|
|
end;
|
|
end;
|
|
|
|
function TKGridAxisItem.GetVisible: Boolean;
|
|
begin
|
|
Result := FExtent > 0;
|
|
end;
|
|
|
|
{ TKGridCol }
|
|
|
|
constructor TKGridCol.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
inherited;
|
|
FExtent := FGrid.DefaultColWidth;
|
|
FCellHint := False;
|
|
FTabStop := True;
|
|
end;
|
|
|
|
procedure TKGridCol.Assign(Source: TKGridAxisItem);
|
|
begin
|
|
inherited;
|
|
if Source is TKGridCol then
|
|
begin
|
|
FCellHint := TKGridCol(Source).CellHint;
|
|
FTabStop := TKGridCol(Source).TabStop;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.Assign(Source: TStrings);
|
|
var
|
|
I, J: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and (Source.Count > 0) and FindCol(I) then
|
|
begin
|
|
FGrid.LockUpdate;
|
|
try
|
|
for J := 0 to Min(FGrid.RowCount, Source.Count) - 1 do
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[J, I];
|
|
if Cell is TKGridTextCell then
|
|
TKGridTextCell(Cell).Text := Source[J];
|
|
end;
|
|
finally
|
|
FGrid.UnlockUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF TKGRID_USE_JCL}
|
|
procedure TKGridCol.Assign(Source: TWideStrings);
|
|
var
|
|
I, J: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and (Source.Count > 0) and FindCol(I) then
|
|
begin
|
|
FGrid.LockUpdate;
|
|
try
|
|
for J := 0 to Min(FGrid.RowCount, Source.Count) - 1 do
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[J, I];
|
|
if Cell is TKGridTextCell then
|
|
TKGridTextCell(Cell).Text := Source[J];
|
|
end;
|
|
finally
|
|
FGrid.UnlockUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TKGridCol.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Assigned(FGrid) and FindCol(I) then
|
|
FGrid.ClearCol(I);
|
|
end;
|
|
|
|
function TKGridCol.{$ifdef COMPILER12_UP}EqualProperties{$ELSE}Equals{$ENDIF}(Item: TKGridAxisItem): Boolean;
|
|
begin
|
|
Result := inherited Equals(Item) and (Item is TKGridCol) and
|
|
(TKGridCol(Item).TabStop = FTabStop) and
|
|
(TKGridCol(Item).CellHint = FCellHint);
|
|
end;
|
|
|
|
function TKGridCol.FindCol(out Index: Integer): Boolean;
|
|
begin
|
|
Result := False;
|
|
Index := 0;
|
|
while Index < FGrid.ColCount do
|
|
begin
|
|
if FGrid.ArrayOfCols[Index] <> Self then
|
|
Inc(Index)
|
|
else
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKGridCol.GetObjects(Index: Integer): TObject;
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
Result := nil;
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[Index, I];
|
|
if Cell is TKGridObjectCell then
|
|
Result := TKGridObjectCell(Cell).CellObject;
|
|
end;
|
|
end;
|
|
|
|
function TKGridCol.GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
Result := '';
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[Index, I];
|
|
if Cell is TKGridTextCell then
|
|
Result := TKGridTextCell(Cell).Text;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.SetExtent(const Value: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Value >= 0) and (Value <> FExtent) then
|
|
begin
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindCol(I) then
|
|
FGrid.ColWidths[I] := Value
|
|
else
|
|
begin
|
|
if FExtent <> 0 then FBackExtent := FExtent;
|
|
FExtent := Value;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.SetObjects(Index: Integer; const Value: TObject);
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[Index, I];
|
|
if Cell is TKGridObjectCell then
|
|
TKGridObjectCell(Cell).CellObject := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.SetSortArrowIndex(Value: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Value := Max(Value, 0);
|
|
if Value <> FSortArrowIndex then
|
|
begin
|
|
FSortArrowIndex := Value;
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and
|
|
(FSortMode <> smNone) and (FGrid.FixedRows > 1) and FindCol(I) then
|
|
FGrid.InvalidateGridRect(GridRect(I, 0, I, FGrid.FixedRows - 1));
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.SetSortMode(const Value: TKGridSortMode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Value <> FSortMode) and FGrid.SortModeUnlocked then
|
|
begin
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindCol(I) then
|
|
FGrid.SortRows(I, Value)
|
|
else
|
|
FSortMode := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.RowValid(Index) and FindCol(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[Index, I];
|
|
if Cell is TKGridTextCell then
|
|
TKGridObjectCell(Cell).Text := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCol.SetVisible(Value: Boolean);
|
|
begin
|
|
if Value then
|
|
begin
|
|
if FBackExtent <= FGrid.MinColWidth then
|
|
Extent := FGrid.MinColWidth
|
|
else
|
|
Extent := FBackExtent;
|
|
end else
|
|
Extent := 0
|
|
end;
|
|
|
|
{ TKGridRow }
|
|
|
|
constructor TKGridRow.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
inherited;
|
|
FExtent := FGrid.DefaultRowHeight;
|
|
end;
|
|
|
|
procedure TKGridRow.Assign(Source: TStrings);
|
|
var
|
|
I, J: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and (Source.Count > 0) and FindRow(I) then
|
|
begin
|
|
FGrid.LockUpdate;
|
|
try
|
|
for J := 0 to Min(FGrid.ColCount, Source.Count) - 1 do
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[I, J];
|
|
if Cell is TKGridTextCell then
|
|
TKGridTextCell(Cell).Text := Source[J];
|
|
end;
|
|
finally
|
|
FGrid.UnlockUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF TKGRID_USE_JCL}
|
|
procedure TKGridRow.Assign(Source: TWideStrings);
|
|
var
|
|
I, J: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and (Source.Count > 0) and FindRow(I) then
|
|
begin
|
|
FGrid.LockUpdate;
|
|
try
|
|
for J := 0 to Min(FGrid.ColCount, Source.Count) - 1 do
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[I, J];
|
|
if Cell is TKGridTextCell then
|
|
TKGridTextCell(Cell).Text := Source[J];
|
|
end;
|
|
finally
|
|
FGrid.UnlockUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TKGridRow.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FGrid.RowCount - 1 do
|
|
if FGrid.Rows[I] = Self then
|
|
begin
|
|
FGrid.ClearRow(I);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function TKGridRow.FindRow(out Index: Integer): Boolean;
|
|
begin
|
|
Result := False;
|
|
Index := 0;
|
|
while Index < FGrid.RowCount do
|
|
begin
|
|
if FGrid.ArrayOfRows[Index] <> Self then
|
|
Inc(Index)
|
|
else
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKGridRow.GetObjects(Index: Integer): TObject;
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
Result := nil;
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[I, Index];
|
|
if Cell is TKGridObjectCell then
|
|
Result := TKGridObjectCell(Cell).CellObject;
|
|
end;
|
|
end;
|
|
|
|
function TKGridRow.GetStrings(Index: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
Result := '';
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[I, Index];
|
|
if Cell is TKGridTextCell then
|
|
Result := TKGridTextCell(Cell).Text;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridRow.SetExtent(const Value: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Value >= 0) and (Value <> FExtent) then
|
|
begin
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindRow(I) then
|
|
FGrid.RowHeights[I] := Value
|
|
else
|
|
begin
|
|
if FExtent <> 0 then FBackExtent := FExtent;
|
|
FExtent := Value;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridRow.SetObjects(Index: Integer; const Value: TObject);
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[I, Index];
|
|
if Cell is TKGridObjectCell then
|
|
TKGridObjectCell(Cell).CellObject := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridRow.SetSortArrowIndex(Value: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Value := Max(Value, 0);
|
|
if Value <> FSortArrowIndex then
|
|
begin
|
|
FSortArrowIndex := Value;
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and
|
|
(FSortMode <> smNone) and (FGrid.FixedCols > 1) and FindRow(I) then
|
|
FGrid.InvalidateGridRect(GridRect(0, I, FGrid.FixedCols - 1, I));
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridRow.SetSortMode(const Value: TKGridSortMode);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (Value <> FSortMode) and FGrid.SortModeUnlocked then
|
|
begin
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) and FindRow(I) then
|
|
FGrid.SortCols(I, Value)
|
|
else
|
|
FSortMode := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridRow.SetStrings(Index: Integer; const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
var
|
|
I: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
if Assigned(FGrid) and Assigned(FGrid.ArrayOfCells) and FGrid.ColValid(Index) and FindRow(I) then
|
|
begin
|
|
Cell := FGrid.ArrayOfCells[I, Index];
|
|
if Cell is TKGridTextCell then
|
|
TKGridTextCell(Cell).Text := Value;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TKGridRow.SetVisible(Value: Boolean);
|
|
begin
|
|
if Value then
|
|
begin
|
|
if FBackExtent <= FGrid.MinRowHeight then
|
|
Extent := FGrid.MinRowHeight
|
|
else
|
|
Extent := FBackExtent;
|
|
end else
|
|
Extent := 0
|
|
end;
|
|
|
|
{ TKGridCell }
|
|
|
|
constructor TKGridCell.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
FGrid := AGrid;
|
|
Initialize;
|
|
end;
|
|
|
|
procedure TKGridCell.Assign(Source: TKGridCell);
|
|
begin
|
|
BeforeUpdate;
|
|
FSpan := Source.Span;
|
|
AfterUpdate;
|
|
end;
|
|
|
|
procedure TKGridCell.Clear;
|
|
begin
|
|
BeforeUpdate;
|
|
try
|
|
Initialize;
|
|
finally
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCell.AfterUpdate;
|
|
var
|
|
Cells: TKGridCells;
|
|
Info: TKGridAxisInfoBoth;
|
|
I, J, HExtent, VExtent: Integer;
|
|
begin
|
|
if Assigned(FGrid) and FGrid.UpdateUnlocked and not FGrid.Flag(cGF_GridUpdates) then
|
|
begin
|
|
// invalidate cell, iterate only visible cells in a fast way
|
|
Cells := FGrid.ArrayOfCells;
|
|
Info := FGrid.GetAxisInfoBoth([]);
|
|
I := 0; HExtent := 0;
|
|
while (I < Info.Horz.TotalCellCount) and (HExtent < Info.Horz.ClientExtent) do
|
|
begin
|
|
if I = Info.Horz.FixedCellCount then
|
|
I := Info.Horz.FirstGridCell; // switch to first visible nonfixed cell
|
|
J := 0; VExtent := 0;
|
|
while (J < Info.Vert.TotalCellCount) and (VExtent < Info.Vert.ClientExtent) do
|
|
begin
|
|
if J = Info.Vert.FixedCellCount then
|
|
J := Info.Vert.FirstGridCell; // switch to first visible nonfixed cell
|
|
if Cells[J, I] = Self then
|
|
begin
|
|
FGrid.InvalidateCell(I, J);
|
|
Exit;
|
|
end;
|
|
Inc(VExtent, Info.Vert.CellExtent(J) + Info.Vert.EffectiveSpacing(J));
|
|
Inc(J);
|
|
end;
|
|
Inc(HExtent, Info.Horz.CellExtent(I) + Info.Horz.EffectiveSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCell.BeforeUpdate;
|
|
begin
|
|
// empty
|
|
end;
|
|
|
|
procedure TKGridCell.ApplyDrawProperties;
|
|
begin
|
|
end;
|
|
|
|
procedure TKGridCell.DrawCell(ACol, ARow: Integer; const ARect: TRect;
|
|
State: TKGridDrawState);
|
|
begin
|
|
FGrid.CellPainter.DefaultDraw;
|
|
end;
|
|
|
|
procedure TKGridCell.EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl);
|
|
begin
|
|
FGrid.DefaultEditorCreate(ACol, ARow, AEditor);
|
|
end;
|
|
|
|
procedure TKGridCell.EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var AssignText: Boolean);
|
|
begin
|
|
FGrid.DefaultEditorDataFromGrid(AEditor, ACol, ARow, AssignText);
|
|
end;
|
|
|
|
procedure TKGridCell.EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var AssignText: Boolean);
|
|
begin
|
|
FGrid.DefaultEditorDataToGrid(AEditor, ACol, ARow, AssignText);
|
|
end;
|
|
|
|
procedure TKGridCell.EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer);
|
|
begin
|
|
FGrid.DefaultEditorDestroy(AEditor, ACol, ARow);
|
|
end;
|
|
|
|
procedure TKGridCell.EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var Key: Word; Shift: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
FGrid.DefaultEditorKeyPreview(AEditor, ACol, ARow, Key, Shift, IsGridKey);
|
|
end;
|
|
|
|
procedure TKGridCell.EditorResize(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var ARect: TRect);
|
|
begin
|
|
FGrid.DefaultEditorResize(AEditor, ACol, ARow, ARect);
|
|
end;
|
|
|
|
procedure TKGridCell.EditorSelect(AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean);
|
|
begin
|
|
FGrid.DefaultEditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse);
|
|
end;
|
|
|
|
function TKGridCell.FindCell(out ACol, ARow: Integer): Boolean;
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
Result := False;
|
|
if Assigned(FGrid) then
|
|
for I := 0 to FGrid.ColCount - 1 do
|
|
for J := 0 to FGrid.RowCount - 1 do
|
|
if FGrid.ArrayOfCells[J, I] = Self then
|
|
begin
|
|
ACol := I;
|
|
ARow := J;
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCell.Initialize;
|
|
begin
|
|
FSpan := MakeCellSpan(1, 1);
|
|
end;
|
|
|
|
procedure TKGridCell.MeasureCell(ACol, ARow: Integer; const ARect: TRect;
|
|
State: TKGridDrawState; Priority: TKGridMeasureCellPriority; var Extent: TPoint);
|
|
begin
|
|
Extent := FGrid.CellPainter.DefaultMeasure(Priority);
|
|
end;
|
|
|
|
procedure TKGridCell.SelectCell(ACol, ARow: Integer; var ACanSelect: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TKGridCell.SelectionExpand(ACol, ARow: Integer; var ACanExpand: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TKGridCell.SetColSpan(const Value: Integer);
|
|
var
|
|
ACol, ARow: Integer;
|
|
begin
|
|
if Value <> FSpan.ColSpan then
|
|
begin
|
|
if Assigned(FGrid) and not FGrid.Flag(cGF_GridUpdates) then
|
|
begin
|
|
if FindCell(ACol, ARow) then
|
|
FGrid.CellSpan[ACol, ARow] := MakeCellSpan(Value, FSpan.RowSpan);
|
|
end else
|
|
FSpan.ColSpan := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCell.SetRowSpan(const Value: Integer);
|
|
var
|
|
ACol, ARow: Integer;
|
|
begin
|
|
if Value <> FSpan.RowSpan then
|
|
begin
|
|
if Assigned(FGrid) and not FGrid.Flag(cGF_GridUpdates) then
|
|
begin
|
|
if FindCell(ACol, ARow) then
|
|
FGrid.CellSpan[ACol, ARow] := MakeCellSpan(FSpan.ColSpan, Value);
|
|
end else
|
|
FSpan.RowSpan := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCell.SetSpan(const Value: TKGridCellSpan);
|
|
var
|
|
ACol, ARow: Integer;
|
|
begin
|
|
if (Value.ColSpan <> FSpan.ColSpan) or (Value.RowSpan <> FSpan.RowSpan) then
|
|
begin
|
|
if Assigned(FGrid) and not FGrid.Flag(cGF_GridUpdates) then
|
|
begin
|
|
if FindCell(ACol, ARow) then
|
|
FGrid.CellSpan[ACol, ARow] := Value;
|
|
end else
|
|
FSpan := Value;
|
|
end;
|
|
end;
|
|
|
|
{ TKGridTextCell }
|
|
|
|
constructor TKGridTextCell.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
FText := '';
|
|
{$ELSE}
|
|
FText := nil;
|
|
{$ENDIF}
|
|
inherited;
|
|
end;
|
|
|
|
destructor TKGridTextCell.Destroy;
|
|
begin
|
|
inherited;
|
|
{$IFNDEF STRING_IS_UNICODE}
|
|
FreeMem(FText);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKGridTextCell.ApplyDrawProperties;
|
|
begin
|
|
FGrid.CellPainter.Text := Text;
|
|
end;
|
|
|
|
procedure TKGridTextCell.Assign(Source: TKGridCell);
|
|
begin
|
|
inherited;
|
|
if Source is TKGridTextCell then
|
|
SetText(TKGridTextCell(Source).TextPtr);
|
|
end;
|
|
|
|
procedure TKGridTextCell.AssignText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
{$IFNDEF STRING_IS_UNICODE}
|
|
var
|
|
Len: Integer;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
FText := Value;
|
|
{$ELSE}
|
|
Len := (Length(Value) + 1) * SizeOf(WideChar);
|
|
ReallocMem(FText, Len);
|
|
if Value <> '' then
|
|
Move(Value[1], FText^, Len)
|
|
else if FText <> nil then
|
|
FText[0] := #0;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKGridTextCell.EditorCreate(ACol, ARow: Integer; var AEditor: TWinControl);
|
|
begin
|
|
AEditor := TEdit.Create(nil);
|
|
end;
|
|
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
function TKGridTextCell.GetTextPtr: PChar;
|
|
begin
|
|
Result := PChar(FText);
|
|
end;
|
|
{$ELSE}
|
|
function TKGridTextCell.GetText: WideString;
|
|
begin
|
|
Result := FText;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TKGridTextCell.Initialize;
|
|
begin
|
|
inherited;
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
FText := '';
|
|
{$ELSE}
|
|
FreeMem(FText);
|
|
FText := nil;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKGridTextCell.SetText(const Value: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
begin
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
if Value <> FText then
|
|
{$ELSE}
|
|
if CompareWideChars(PWideChar(Value), FText) <> 0 then
|
|
{$ENDIF}
|
|
begin
|
|
BeforeUpdate;
|
|
AssignText(Value);
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
{ TKGridAttrTextCell }
|
|
|
|
constructor TKGridAttrTextCell.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
inherited;
|
|
FBrush := TBrush.Create;
|
|
FBrush.OnChange := BrushChange;
|
|
FBrushChanged := False;
|
|
FFont := TFont.Create;
|
|
FFont.OnChange := FontChange;
|
|
FFontChanged := False;
|
|
Initialize;
|
|
end;
|
|
|
|
destructor TKGridAttrTextCell.Destroy;
|
|
begin
|
|
FBrush.Free;
|
|
FFont.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.ApplyDrawProperties;
|
|
var
|
|
AColor: TColor;
|
|
begin
|
|
inherited;
|
|
if FGrid.CellPainter.State * [gdSelected] <> [] then
|
|
begin
|
|
// Brush remains unaffected by default
|
|
if FFontChanged then
|
|
begin
|
|
// Font color remains unaffected by default
|
|
AColor := FGrid.CellPainter.Canvas.Font.Color;
|
|
FGrid.CellPainter.Canvas.Font := FFont;
|
|
FGrid.CellPainter.Canvas.Font.Color := AColor;
|
|
if FGrid.CellPainter.FPrinting then
|
|
FGrid.CellPainter.Canvas.Font.Height := Abs(FFont.Height);
|
|
end;
|
|
end else
|
|
begin
|
|
FGrid.CellPainter.BackColor := FBackColor;
|
|
if FBrushChanged then
|
|
begin
|
|
FGrid.CellPainter.Canvas.Brush := FBrush;
|
|
{$IFNDEF FPC}
|
|
SetBrushOrgEx(FGrid.CellPainter.Canvas.Handle, FGrid.CellPainter.CellRect.Left,
|
|
FGrid.CellPainter.CellRect.Top, nil);
|
|
{$ENDIF}
|
|
end;
|
|
if FFontChanged then
|
|
begin
|
|
FGrid.CellPainter.Canvas.Font := FFont;
|
|
if FGrid.CellPainter.FPrinting then
|
|
FGrid.CellPainter.Canvas.Font.Height := Abs(FFont.Height);
|
|
end;
|
|
end;
|
|
FGrid.CellPainter.HAlign := FHAlign;
|
|
FGrid.CellPainter.VAlign := FVAlign;
|
|
FGrid.CellPainter.HPadding := FHPadding;
|
|
FGrid.CellPainter.VPadding := FVPadding;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.Assign(Source: TKGridCell);
|
|
begin
|
|
inherited;
|
|
if Source is TKGridAttrTextCell then
|
|
begin
|
|
FBackColor := TKGridAttrTextCell(Source).BackColor;
|
|
FBrush.Assign(TKGridAttrTextCell(Source).Brush);
|
|
FBrushChanged := TKGridAttrTextCell(Source).BrushChanged;
|
|
FFont.Assign(TKGridAttrTextCell(Source).Font);
|
|
FFontChanged := TKGridAttrTextCell(Source).FontChanged;
|
|
FHAlign := TKGridAttrTextCell(Source).HAlign;
|
|
FHPadding := TKGridAttrTextCell(Source).HPadding;
|
|
FVAlign := TKGridAttrTextCell(Source).VAlign;
|
|
FVPadding := TKGridAttrTextCell(Source).VPadding;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.BrushChange(Sender: TObject);
|
|
begin
|
|
BeforeUpdate;
|
|
FBrushChanged := True;
|
|
AfterUpdate;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.FontChange(Sender: TObject);
|
|
begin
|
|
BeforeUpdate;
|
|
FFontChanged := True;
|
|
AfterUpdate;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.Initialize;
|
|
begin
|
|
inherited;
|
|
FBackColor := clWindow;
|
|
FHAlign := halLeft;
|
|
FHPadding := 2;
|
|
FVAlign := valCenter;
|
|
FVPadding := 0;
|
|
// no defaults for Brush and Font!
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.SetBackColor(const Value: TColor);
|
|
begin
|
|
if Value <> FBackColor then
|
|
begin
|
|
BeforeUpdate;
|
|
FBackColor := Value;
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.SetFHAlign(const Value: TKHAlign);
|
|
begin
|
|
if Value <> FHAlign then
|
|
begin
|
|
BeforeUpdate;
|
|
FHAlign := Value;
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.SetAttributes(const AValue: TKTextAttributes);
|
|
begin
|
|
if AValue <> FAttributes then
|
|
begin
|
|
BeforeUpdate;
|
|
FAttributes := AValue;
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.SetFHPadding(const Value: Integer);
|
|
begin
|
|
if Value <> FHPadding then
|
|
begin
|
|
BeforeUpdate;
|
|
FHPadding := Value;
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.SetFVAlign(const Value: TKVAlign);
|
|
begin
|
|
if Value <> FVAlign then
|
|
begin
|
|
BeforeUpdate;
|
|
FVAlign := Value;
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridAttrTextCell.SetFVPadding(const Value: Integer);
|
|
begin
|
|
if Value <> FVPadding then
|
|
begin
|
|
BeforeUpdate;
|
|
FVPadding := Value;
|
|
AfterUpdate;
|
|
end;
|
|
end;
|
|
|
|
{ TKGridObjectCell }
|
|
|
|
constructor TKGridObjectCell.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
FCellObject := nil;
|
|
inherited;
|
|
end;
|
|
|
|
destructor TKGridObjectCell.Destroy;
|
|
begin
|
|
inherited;
|
|
FCellObject.Free;
|
|
end;
|
|
|
|
procedure TKGridObjectCell.Assign(Source: TKGridCell);
|
|
var
|
|
Obj: TObject;
|
|
begin
|
|
inherited;
|
|
if Source is TKGridObjectCell then
|
|
begin
|
|
Obj := TKGridObjectCell(Source).CellObject;
|
|
if (Obj is TPersistent) and (FCellObject.ClassType = Obj.ClassType) then
|
|
TPersistent(FCellObject).Assign(TPersistent(Obj));
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridObjectCell.Initialize;
|
|
begin
|
|
inherited;
|
|
FreeAndNil(FCellObject);
|
|
end;
|
|
|
|
procedure TKGridObjectCell.SetCellObject(Value: TObject);
|
|
begin
|
|
if Value <> FCellObject then
|
|
begin
|
|
FCellObject.Free;
|
|
FCellObject := Value;
|
|
end;
|
|
end;
|
|
|
|
{ TKGridCellPainter }
|
|
|
|
constructor TKGridCellPainter.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
inherited Create;
|
|
FGrid := AGrid;
|
|
FCanvas := nil;
|
|
FCol := 0;
|
|
FClipLock := 0;
|
|
FRgn := 0;
|
|
FRow := 0;
|
|
FState := [];
|
|
FValidClipping := False;
|
|
FSortArrow := TKAlphaBitmap.CreateFromRes('KGRID_SORT_ARROW');
|
|
Initialize;
|
|
end;
|
|
|
|
destructor TKGridCellPainter.Destroy;
|
|
begin
|
|
FSortArrow.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TKGridCellPainter.BeginClip;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if FClipLock = 0 then with FCanvas do
|
|
begin
|
|
R := FCellRect;
|
|
TranslateRectToDevice(Handle, R);
|
|
FValidClipping := ExtSelectClipRect(Handle, R, RGN_AND, FRgn);
|
|
end;
|
|
Inc(FClipLock);
|
|
Result := FValidClipping;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.BeginDraw;
|
|
begin
|
|
DefaultAttributes;
|
|
end;
|
|
|
|
function TKGridCellPainter.CellCheckBoxRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean;
|
|
begin
|
|
if FCheckBox and not IsRectEmpty(BaseRect) then
|
|
begin
|
|
ExcludeShapeFromBaseRect(BaseRect, cCheckBoxFrameSize{$IFDEF LCLQT} + 1{$ENDIF}, cCheckBoxFrameSize, FCheckBoxHAlign,
|
|
FCheckBoxVAlign, FCheckBoxHPadding, FCheckBoxVPadding, StretchMode, Bounds, Interior);
|
|
Result := True;
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKGridCellPainter.CellGraphicRect(var BaseRect: TRect; out Bounds, Interior: TRect; StretchMode: TKStretchMode): Boolean;
|
|
begin
|
|
if Assigned(FGraphic) and not IsRectEmpty(BaseRect) then
|
|
begin
|
|
ExcludeShapeFromBaseRect(BaseRect, FGraphic.Width, FGraphic.Height, FGraphicHAlign,
|
|
FGraphicVAlign, FGraphicHPadding, FGraphicVPadding, StretchMode, Bounds, Interior);
|
|
Result := True;
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKGridCellPainter.CellSortArrowRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean;
|
|
var
|
|
ArrowWidth: Integer;
|
|
begin
|
|
ArrowWidth := SortArrowWidth;
|
|
if (ArrowWidth > 0) and not IsRectEmpty(BaseRect) then
|
|
begin
|
|
ExcludeShapeFromBaseRect(BaseRect, ArrowWidth, BaseRect.Bottom - BaseRect.Top, FSortArrowHAlign,
|
|
valCenter, FSortArrowHPadding, 0, stmNone, Bounds, Interior);
|
|
Result := True;
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKGridCellPainter.CellTextExtent(const BaseRect: TRect; out Extent: TPoint): Boolean;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if (FText <> '') and not IsRectEmpty(BaseRect) then
|
|
begin
|
|
R := BaseRect;
|
|
DrawAlignedText(FCanvas, R, FHAlign, FVAlign,
|
|
FHPadding, FVPadding, FText, FBackColor, FAttributes + [taCalcRect]);
|
|
Extent.X := R.Right - R.Left;
|
|
Extent.Y := R.Bottom - R.Top;
|
|
Result := True;
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKGridCellPainter.CellTextRect(var BaseRect: TRect; out Bounds, Interior: TRect): Boolean;
|
|
var
|
|
Extent: TPoint;
|
|
begin
|
|
if CellTextExtent(BaseRect, Extent) then
|
|
begin
|
|
ExcludeShapeFromBaseRect(BaseRect, Extent.X, Extent.Y, FHAlign,
|
|
FVAlign, FHPadding, FVPadding, stmNone, Bounds, Interior);
|
|
Result := True;
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DefaultAttributes;
|
|
var
|
|
Color: TColor;
|
|
begin
|
|
Initialize;
|
|
// prepare default brush and font style
|
|
with FCanvas do
|
|
begin
|
|
Brush.Style := bsSolid;
|
|
Pen.Style := psSolid;
|
|
Pen.Mode := pmCopy;
|
|
Font := FGrid.Font;
|
|
if FPrinting then
|
|
Font.Height := Abs(FGrid.Font.Height);
|
|
if gdFixed in FState then
|
|
begin
|
|
// aki:
|
|
if gdSelected in FState then
|
|
Color := FGrid.Colors.SelectedFixedCellBkGnd
|
|
else if (goIndicateSelection in FGrid.Options) and (FGrid.ColSelected(FCol) and
|
|
not (goRowSelect in FGrid.Options) or FGrid.RowSelected(FRow)) then
|
|
Color := FGrid.Colors.FixedCellIndication
|
|
else
|
|
Color := FGrid.Colors.FixedCellBkGnd;
|
|
if gdMouseDown in FState then
|
|
Brush.Color := BrightColor(Color, 0.6, bsOfTop)
|
|
else
|
|
Brush.Color := Color;
|
|
Font.Color := FGrid.Colors.FixedCellText;
|
|
end else if gdSelected in FState then
|
|
begin
|
|
if FPrinting or FGrid.HasFocus then
|
|
begin
|
|
if (FGrid.Col = FCol) and (FGrid.Row = FRow) then
|
|
begin
|
|
Brush.Color := FGrid.Colors.FocusedCellBkGnd;
|
|
Font.Color := FGrid.Colors.FocusedCellText;
|
|
end else
|
|
begin
|
|
Brush.Color := FGrid.Colors.FocusedRangeBkGnd;
|
|
Font.Color := FGrid.Colors.FocusedRangeText;
|
|
end;
|
|
end else
|
|
begin
|
|
if (FGrid.Col = FCol) and (FGrid.Row = FRow) then
|
|
begin
|
|
Brush.Color := FGrid.Colors.SelectedCellBkGnd;
|
|
Font.Color := FGrid.Colors.SelectedCellText;
|
|
end else
|
|
begin
|
|
Brush.Color := FGrid.Colors.SelectedRangeBkGnd;
|
|
Font.Color := FGrid.Colors.SelectedRangeText;
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
Brush.Color := FGrid.Colors.CellBkGnd;
|
|
Font.Color := FGrid.Colors.CellText;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DefaultDraw;
|
|
begin
|
|
if gdFixed in FState then
|
|
begin
|
|
if (FRow < FGrid.FixedRows) and (goHeader in FGrid.Options) then
|
|
DrawHeaderCellBackground(FCellRect)
|
|
else
|
|
DrawFixedCellBackground(FCellRect);
|
|
end
|
|
else if gdSelected in FState then
|
|
begin
|
|
if FGrid.Options * [goRowSelect, goRangeSelect] <> [] then
|
|
DrawSelectedCellBackground(FBlockRect, @FCellRect)
|
|
else
|
|
DrawSelectedCellBackground(FCellRect)
|
|
end else
|
|
DrawNormalCellBackground(FCellRect);
|
|
DrawCellCommon;
|
|
end;
|
|
|
|
function TKGridCellPainter.DefaultEdges: Cardinal;
|
|
begin
|
|
Result := 0;
|
|
if goFixedHorzLine in FGrid.Options then
|
|
begin
|
|
Result := BF_TOP;
|
|
if not (goAlignLastRow in FGrid.Options) or (FRow < FGrid.RowCount - 1) then
|
|
Result := Result or BF_BOTTOM;
|
|
end;
|
|
if goFixedVertLine in FGrid.Options then
|
|
begin
|
|
Result := Result or BF_LEFT;
|
|
if not (goAlignLastCol in FGrid.Options) or (FCol < FGrid.ColCount - 1) then
|
|
Result := Result or BF_RIGHT;
|
|
end;
|
|
end;
|
|
|
|
function TKGridCellPainter.DefaultMeasure(Priority: TKGridMeasureCellPriority): TPoint;
|
|
const
|
|
cMaxAutoSizeColWidth = 10000;
|
|
cMaxAutoSizeRowHeight = 10000;
|
|
cMaxAutoSizeStretchImageHeight = 1024;
|
|
var
|
|
BaseRect, Bounds, Interior: TRect;
|
|
begin
|
|
BaseRect := FCellRect;
|
|
case Priority of
|
|
mpColWidth: BaseRect.Right := cMaxAutoSizeColWidth;
|
|
mpRowHeight: BaseRect.Bottom := cMaxAutoSizeRowHeight;
|
|
else
|
|
BaseRect.Right := cMaxAutoSizeColWidth;
|
|
BaseRect.Bottom := cMaxAutoSizeRowHeight;
|
|
end;
|
|
if Assigned(FGraphic) and (FGraphicStretchMode in [stmZoom, stmZoomInOnly]) then
|
|
BaseRect.Bottom := Min(BaseRect.Bottom, BaseRect.Top + (FGraphicVPadding shl 1) + cMaxAutoSizeStretchImageHeight);
|
|
// BaseRect.Right := MaxInt; // keep cell height, maximize cell width and cut each object from BaseRect
|
|
Result.X := 0;
|
|
Result.Y := 0;
|
|
if CellSortArrowRect(BaseRect, Bounds, Interior) then
|
|
begin
|
|
Inc(Result.X, Bounds.Right - Bounds.Left);
|
|
Result.Y := Interior.Bottom - Interior.Top;
|
|
end;
|
|
if CellCheckBoxRect(BaseRect, Bounds, Interior, stmNone) then // for measuring always consider check box frame with original size
|
|
begin
|
|
Inc(Result.X, Bounds.Right - Bounds.Left);
|
|
Result.Y := Max(Result.Y, Interior.Bottom - Interior.Top + (FCheckBoxVPadding shl 1));
|
|
end;
|
|
if CellGraphicRect(BaseRect, Bounds, Interior, FGraphicStretchMode) then // for measuring consider stretched image as for drawing
|
|
begin
|
|
Inc(Result.X, Bounds.Right - Bounds.Left);
|
|
Result.Y := Max(Result.Y, Interior.Bottom - Interior.Top + (FGraphicVPadding shl 1));
|
|
end;
|
|
if CellTextExtent(BaseRect, Interior.TopLeft) then
|
|
begin
|
|
Inc(Result.X, Interior.Left + (FHPadding shl 1));
|
|
Result.Y := Max(Result.Y, Interior.Top + (FVPadding shl 1));
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellCommon;
|
|
var
|
|
BaseRect, Bounds, Interior, BoundsSA, InteriorSA: TRect;
|
|
IsSortArrow: Boolean;
|
|
begin
|
|
if not (gdEdited in FState) then
|
|
begin
|
|
BaseRect := FCellRect;
|
|
IsSortArrow := CellSortArrowRect(BaseRect, BoundsSA, InteriorSA);
|
|
if CellCheckBoxRect(BaseRect, Bounds, Interior, stmZoomOutOnly) then // disallow zoom in for check box frame
|
|
DrawCellCheckBox(Bounds, Interior);
|
|
if CellGraphicRect(BaseRect, Bounds, Interior, FGraphicStretchMode) then
|
|
DrawCellGraphic(Bounds, Interior);
|
|
if not IsRectEmpty(BaseRect) then
|
|
begin
|
|
if FButton then
|
|
DrawCellButton(BaseRect)
|
|
else
|
|
DrawCellText(BaseRect);
|
|
end;
|
|
if IsSortArrow then
|
|
DrawCellSortArrow(BoundsSA, InteriorSA);
|
|
if gdSelected in FState then
|
|
DrawCellFocus(FCellRect);
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawButtonFrame(const ARect: TRect);
|
|
var
|
|
BM: TBitmap;
|
|
TmpCanvas: TCanvas;
|
|
TmpRect: TRect;
|
|
ButtonState: Integer;
|
|
IsHot: Boolean;
|
|
MousePt: TPoint;
|
|
{$IFDEF USE_THEMES}
|
|
ButtonTheme: TThemedButton;
|
|
{$ENDIF}
|
|
begin
|
|
// a LOT of tweaking here...
|
|
{$IF DEFINED(USE_WINAPI) OR DEFINED(LCLQT) } // GTK2 cannot strech and paint on bitmap canvas, grrr..
|
|
if CanvasScaled(FCanvas) {$IFDEF USE_WINAPI}and FGrid.ThemedCells{$ENDIF} then
|
|
begin
|
|
BM := TBitmap.Create;
|
|
BM.Width := ARect.Right - ARect.Left;
|
|
BM.Height := ARect.Bottom - ARect.Top;
|
|
BM.Canvas.Brush.Assign(FCanvas.Brush);
|
|
TmpRect := Rect(0, 0, BM.Width, BM.Height);
|
|
BM.Canvas.FillRect(TmpRect);
|
|
TmpCanvas := BM.Canvas;
|
|
end else
|
|
{$IFEND}
|
|
begin
|
|
BM := nil;
|
|
TmpRect := ARect;
|
|
TmpCanvas := FCanvas;
|
|
end;
|
|
try
|
|
MousePt := FGrid.ScreenToClient(Mouse.CursorPos);
|
|
IsHot := (gdMouseOver in FState) and
|
|
(not FHotFrameOnly or PtInRect(ARect, MousePt));
|
|
{$IFDEF USE_THEMES}
|
|
if FGrid.ThemedCells then
|
|
begin
|
|
if FGrid.Enabled then
|
|
if FButtonPressed then
|
|
ButtonTheme := tbPushButtonPressed
|
|
else
|
|
if IsHot then
|
|
ButtonTheme := tbPushButtonHot
|
|
else
|
|
ButtonTheme := tbPushButtonNormal
|
|
else
|
|
ButtonTheme := tbPushButtonDisabled;
|
|
ThemeServices.DrawElement(TmpCanvas.Handle, ThemeServices.GetElementDetails(ButtonTheme), TmpRect);
|
|
end else
|
|
{$ENDIF}
|
|
begin
|
|
ButtonState := DFCS_BUTTONPUSH;
|
|
if FButtonPressed then ButtonState := ButtonState or DFCS_PUSHED;
|
|
if not FGrid.Enabled then ButtonState := ButtonState or DFCS_INACTIVE;
|
|
DrawFrameControl(TmpCanvas.Handle, TmpRect, DFC_BUTTON, ButtonState);
|
|
end;
|
|
if BM <> nil then
|
|
FCanvas.Draw(ARect.Left, ARect.Top, BM);
|
|
finally
|
|
BM.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellButton(Bounds: TRect);
|
|
begin
|
|
DrawButtonFrame(Bounds);
|
|
DrawCellText(Bounds);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellCheckBox(const Bounds, Interior: TRect);
|
|
begin
|
|
DrawCheckBoxFrame(Interior);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellGraphic(const Bounds, Interior: TRect);
|
|
begin
|
|
if Assigned(FGraphic) then
|
|
begin
|
|
if FGraphicStretchMode = stmZoom then
|
|
SafeStretchDraw(FCanvas, Interior, FGraphic, FBackColor)
|
|
else if BeginClip then
|
|
try
|
|
SafeStretchDraw(FCanvas, Interior, FGraphic, FBackColor);
|
|
finally
|
|
EndClip;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellFocus(const ARect: TRect; SkipTest: Boolean);
|
|
begin
|
|
if (gdFocused in FState) and (SkipTest or (FGrid.Options * [goRangeSelect, goRowSelect,
|
|
goDrawFocusSelected] = [goDrawFocusSelected])) then
|
|
begin
|
|
// to ensure coming DrawFocusRect will be painted correctly:
|
|
SetBkColor(FCanvas.Handle, $FFFFFF);
|
|
SetTextColor(FCanvas.Handle, 0);
|
|
FCanvas.DrawFocusRect(FCellRect);
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellSortArrow(const Bounds, Interior: TRect);
|
|
var
|
|
ArrowCopy: TKAlphaBitmap;
|
|
Mirror, Rotate: Boolean;
|
|
begin
|
|
if FSortArrow <> nil then
|
|
begin
|
|
if BeginClip then
|
|
try
|
|
Mirror := FState * [gdColsSortedDown, gdRowsSortedDown] <> [];
|
|
Rotate := FState * [gdColsSortedDown, gdColsSortedUp] <> [];
|
|
ArrowCopy := TKAlphaBitmap.Create;
|
|
try
|
|
if Rotate then
|
|
begin
|
|
ArrowCopy.CopyFromRotated(FSortArrow);
|
|
if Mirror then
|
|
ArrowCopy.MirrorHorz;
|
|
end else
|
|
begin
|
|
ArrowCopy.CopyFrom(FSortArrow);
|
|
if Mirror then
|
|
ArrowCopy.MirrorVert;
|
|
end;
|
|
ArrowCopy.AlphaDrawTo(FCanvas, Interior.Left, Interior.Top + (Interior.Bottom - Interior.Top - ArrowCopy.Height) div 2);
|
|
finally
|
|
ArrowCopy.Free;
|
|
end;
|
|
finally
|
|
EndClip;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCellText(var ARect: TRect);
|
|
var
|
|
TextAttributes: TKTextAttributes;
|
|
begin
|
|
TextAttributes := FAttributes;
|
|
{ if FFillCellBackground then
|
|
Include(TextAttributes, taFillRect)
|
|
else
|
|
Exclude(TextAttributes, taFillRect);}
|
|
DrawAlignedText(FCanvas, ARect, FHAlign, FVAlign,
|
|
FHPadding, FVPadding, FText, FBackColor, TextAttributes);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawCheckBoxFrame(const ARect: TRect);
|
|
var
|
|
BM: TBitmap;
|
|
TmpCanvas: TCanvas;
|
|
TmpRect: TRect;
|
|
State: Integer;
|
|
IsHot: Boolean;
|
|
MousePt: TPoint;
|
|
{$IFDEF USE_THEMES}
|
|
CheckBoxTheme: TThemedButton;
|
|
{$ENDIF}
|
|
begin
|
|
// a LOT of tweaking here...
|
|
{$IF DEFINED(USE_WINAPI) OR DEFINED(LCLQT) } // GTK2 cannot strech and paint on bitmap canvas, grrr..
|
|
if CanvasScaled(FCanvas) {$IFDEF USE_WINAPI}and FGrid.ThemedCells{$ENDIF} then
|
|
begin
|
|
BM := TBitmap.Create;
|
|
BM.Width := ARect.Right - ARect.Left;
|
|
BM.Height := ARect.Bottom - ARect.Top;
|
|
BM.Canvas.Brush.Assign(FCanvas.Brush);
|
|
TmpRect := Rect(0, 0, BM.Width, BM.Height);
|
|
BM.Canvas.FillRect(TmpRect);
|
|
TmpCanvas := BM.Canvas;
|
|
end else
|
|
{$IFEND}
|
|
begin
|
|
BM := nil;
|
|
TmpRect := ARect;
|
|
TmpCanvas := FCanvas;
|
|
end;
|
|
try
|
|
{$IFDEF USE_THEMES}
|
|
MousePt := FGrid.ScreenToClient(Mouse.CursorPos);
|
|
IsHot := (gdMouseOver in FState) and
|
|
(not FHotFrameOnly or PtInRect(ARect, MousePt));
|
|
if FGrid.ThemedCells then
|
|
begin
|
|
if FGrid.Enabled then
|
|
case FCheckBoxState of
|
|
cbChecked:
|
|
begin
|
|
if IsHot then
|
|
CheckBoxTheme := tbCheckBoxCheckedHot
|
|
else
|
|
CheckBoxTheme := tbCheckBoxCheckedNormal;
|
|
end;
|
|
cbUnchecked:
|
|
begin
|
|
if IsHot then
|
|
CheckBoxTheme := tbCheckBoxUncheckedHot
|
|
else
|
|
CheckBoxTheme := tbCheckBoxUncheckedNormal;
|
|
end;
|
|
else
|
|
if IsHot then
|
|
CheckBoxTheme := tbCheckBoxMixedHot
|
|
else
|
|
CheckBoxTheme := tbCheckBoxMixedNormal;
|
|
end
|
|
else
|
|
case FCheckboxState of
|
|
cbChecked:
|
|
CheckBoxTheme := tbCheckBoxCheckedDisabled;
|
|
cbUnchecked:
|
|
CheckBoxTheme := tbCheckBoxUncheckedDisabled;
|
|
else
|
|
CheckBoxTheme := tbCheckBoxMixedDisabled;
|
|
end;
|
|
ThemeServices.DrawElement(TmpCanvas.Handle, ThemeServices.GetElementDetails(CheckBoxTheme), TmpRect);
|
|
end else
|
|
{$ENDIF}
|
|
begin
|
|
State := DFCS_BUTTON3STATE;
|
|
case FCheckBoxState of
|
|
cbChecked:
|
|
State := State or DFCS_CHECKED;
|
|
// cbGrayed:
|
|
// State := State or DFCS_GRAYED;
|
|
end;
|
|
if not FGrid.Enabled then State := State or DFCS_INACTIVE;
|
|
DrawFrameControl(TmpCanvas.Handle, TmpRect, DFC_BUTTON, State);
|
|
end;
|
|
if BM <> nil then
|
|
FCanvas.Draw(ARect.Left, ARect.Top, BM);
|
|
finally
|
|
BM.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawHeaderCellBackground(const ARect: TRect);
|
|
{$IFDEF USE_THEMES}
|
|
var
|
|
Details: TThemedElementDetails;
|
|
Header: TThemedHeader;
|
|
TmpRect: TRect;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF USE_THEMES}
|
|
if FGrid.ThemedCells then with ThemeServices do
|
|
begin
|
|
if gdSelected in FState then
|
|
Header := thHeaderItemPressed
|
|
else if gdMouseDown in FState then
|
|
Header := thHeaderItemPressed
|
|
else if gdMouseOver in FState then
|
|
Header := thHeaderItemHot
|
|
else
|
|
Header := thHeaderItemNormal;
|
|
{ The background for the themed header is messy. HasTransparentParts returns
|
|
always True and we cannot call DrawParentBackground as this is wrong
|
|
approach here. So for this reason, thHeaderItemNormal is always supposed
|
|
to be visually not transparent. We paint it only if double buffering is
|
|
present because double buffer is a temporary memory and, of course,
|
|
the screen content is not copied back to the double buffer. }
|
|
TmpRect := ARect;
|
|
Inc(TmpRect.Bottom); // it is nicer
|
|
if FGrid.IsDoubleBuffered and (Header <> thHeaderItemNormal) then
|
|
DrawElement(FCanvas.Handle, GetElementDetails(thHeaderItemNormal), TmpRect);
|
|
Details := GetElementDetails(Header);
|
|
DrawElement(FCanvas.Handle, Details, TmpRect);
|
|
end else
|
|
{$ENDIF}
|
|
DrawFixedCellNonThemedBackground(ARect);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawEmptyCell;
|
|
begin
|
|
DrawNormalCellBackground(FCellRect);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawFixedCell;
|
|
begin
|
|
DrawFixedCellBackground(FCellRect);
|
|
DrawCellCommon;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawFixedCellBackground(const ARect: TRect);
|
|
{$IFDEF USE_THEMES}
|
|
var
|
|
Color1, Color2: TColor;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF USE_THEMES}
|
|
if FGrid.ThemedCells and (gxFixedThemedCells in FGrid.OptionsEx) then
|
|
DrawHeaderCellBackground(ARect)
|
|
else if FGrid.ThemedCells then
|
|
begin
|
|
DrawFilledRectangle(FCanvas, ARect, FBackColor);
|
|
if {$IFDEF FPC}not FGrid.Flat{$ELSE}FGrid.Ctl3D{$ENDIF} then
|
|
begin
|
|
if gdMouseDown in FState then
|
|
begin
|
|
Color1 := FGrid.Colors.FixedThemedCellShadow;
|
|
Color2 := FGrid.Colors.FixedThemedCellHighlight;
|
|
end else
|
|
begin
|
|
Color1 := FGrid.Colors.FixedThemedCellHighlight;
|
|
Color2 := FGrid.Colors.FixedThemedCellShadow;
|
|
end;
|
|
DrawEdges(FCanvas, ARect, Color1, Color2, DefaultEdges);
|
|
end;
|
|
end else
|
|
{$ENDIF}
|
|
DrawFixedCellNonThemedBackground(ARect);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawFixedCellNonThemedBackground(const ARect: TRect);
|
|
{$IFDEF USE_WINAPI}
|
|
var
|
|
R: TRect;
|
|
{$ENDIF}
|
|
begin
|
|
DrawFilledRectangle(FCanvas, ARect, FBackColor);
|
|
if {$IFDEF FPC}not FGrid.Flat{$ELSE}FGrid.Ctl3D{$ENDIF} and not (gdMouseDown in FState) then
|
|
begin
|
|
{$IFDEF USE_WINAPI}
|
|
// looks somewhat better though
|
|
R := ARect;
|
|
DrawEdge(FCanvas.Handle, R, BDR_RAISEDINNER, DefaultEdges);
|
|
{$ELSE}
|
|
DrawEdges(FCanvas, ARect, cl3DHilight, cl3DShadow, DefaultEdges);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawHeaderCell;
|
|
begin
|
|
DrawHeaderCellBackground(FCellRect);
|
|
DrawCellCommon;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawNormalCellBackground(const ARect: TRect);
|
|
begin
|
|
DrawFilledRectangle(FCanvas, ARect, FBackColor);
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawSelectableCell;
|
|
begin
|
|
if gdSelected in FState then
|
|
DrawSelectedCellBackground(FCellRect)
|
|
else
|
|
DrawNormalCellBackground(FCellRect);
|
|
DrawCellCommon;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawSelectedCellBackground(const ARect: TRect; RClip: PRect);
|
|
var
|
|
{$IFDEF USE_THEMES}
|
|
{$IF (DEFINED(COMPILER9_UP) OR DEFINED(FPC)) AND DEFINED(USE_WINAPI)}
|
|
{$IFDEF FPC}
|
|
Details: TThemedElementDetails;
|
|
{$ELSE}
|
|
SelectionTheme: HTHEME;
|
|
{$ENDIF}
|
|
Color: TColorRef;
|
|
{$IFEND}
|
|
{$ENDIF}
|
|
R: TRect;
|
|
begin
|
|
{$IFDEF USE_THEMES}
|
|
{$IF (DEFINED(COMPILER9_UP) OR DEFINED(FPC)) AND DEFINED(USE_WINAPI)}
|
|
if FGrid.ThemedCells and (Win32MajorVersion >= 6) then // Windows Vista and later
|
|
begin
|
|
// make the background brigther
|
|
if FPrinting or FGrid.HasFocus then
|
|
FCanvas.Brush.Color := BrightColor(FCanvas.Brush.Color, 0.8, bsOfTop)
|
|
else
|
|
FCanvas.Brush.Color := clWhite;
|
|
if RClip <> nil then
|
|
FCanvas.FillRect(RClip^)
|
|
else
|
|
FCanvas.FillRect(ARect);
|
|
{$IFDEF FPC}
|
|
Details := ThemeServices.GetElementDetails(tmPopupItemHot);
|
|
ThemeServices.DrawElement(FCanvas.Handle, Details, ARect, RClip);
|
|
Color := clWindowText; // getting text color not supported
|
|
{$ELSE}
|
|
SelectionTheme := ThemeServices.Theme[teMenu];
|
|
DrawThemeBackground(SelectionTheme, FCanvas.Handle, MENU_POPUPITEM, MPI_HOT, ARect, RClip);
|
|
GetThemeColor(SelectionTheme, MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR, Color);
|
|
{$ENDIF}
|
|
FCanvas.Font.Color := Color;
|
|
end else
|
|
{$IFEND}
|
|
{$ENDIF}
|
|
begin
|
|
if RClip <> nil then
|
|
R := RClip^
|
|
else
|
|
R := ARect;
|
|
DrawFilledRectangle(FCanvas, R, FBackColor);
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawThemedFixedCell;
|
|
begin
|
|
DrawFixedCellBackground(FCellRect);
|
|
DrawCellCommon;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.DrawThemedHeaderCell;
|
|
begin
|
|
DrawHeaderCellBackground(FCellRect);
|
|
DrawCellCommon;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.EndClip;
|
|
begin
|
|
if FClipLock > 0 then with FCanvas do
|
|
begin
|
|
Dec(FClipLock);
|
|
if FClipLock = 0 then
|
|
begin
|
|
FinalizePrevRgn(Handle, FRgn);
|
|
FValidClipping := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.EndDraw;
|
|
begin
|
|
end;
|
|
|
|
function TKGridCellPainter.GetCheckBoxChecked: Boolean;
|
|
begin
|
|
Result := FCheckBoxState = cbChecked;
|
|
end;
|
|
|
|
function TKGridCellPainter.GetSortArrowWidth: Integer;
|
|
begin
|
|
if FSortArrow <> nil then
|
|
begin
|
|
if FState * [gdColsSortedDown, gdColsSortedUp] <> [] then
|
|
Result := FSortArrow.Height + 3
|
|
else if FState * [gdRowsSortedDown, gdRowsSortedUp] <> [] then
|
|
Result := FSortArrow.Width + 3
|
|
else
|
|
Result := 0;
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.Initialize;
|
|
begin
|
|
FAttributes := [taEndEllipsis];
|
|
FBackColor := clWindow;
|
|
FButton := False;
|
|
FButtonPressed := False;
|
|
FCheckBox := False;
|
|
FCheckBoxHAlign := halLeft;
|
|
FCheckBoxHPadding := 2;
|
|
FCheckBoxVAlign := valCenter;
|
|
FCheckBoxVPadding := 2;
|
|
FCheckBoxState := cbUnchecked;
|
|
FGraphic := nil;
|
|
FGraphicDrawText := False;
|
|
FGraphicHAlign := halCenter;
|
|
FGraphicHPadding := 2;
|
|
FGraphicStretchMode := stmZoom;
|
|
FGraphicVAlign := valCenter;
|
|
FGraphicVPadding := 2;
|
|
FHAlign := halLeft;
|
|
FHotFrameOnly := False;
|
|
FHPadding := 2;
|
|
FSortArrowHAlign := halRight;
|
|
FSortArrowHPadding := 2;
|
|
FText := '';
|
|
FVAlign := valCenter;
|
|
FVPadding := 0;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.SetCheckBox(AValue: Boolean);
|
|
begin
|
|
if AValue <> FCheckBox then
|
|
begin
|
|
FCheckBox := AValue;
|
|
if AValue then
|
|
begin
|
|
// set default padding for check box text (not tested for Linux and MAC)
|
|
if FGrid.Themes then
|
|
FHPadding := 3
|
|
else
|
|
FHPadding := 4;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridCellPainter.SetCheckBoxChecked(const Value: Boolean);
|
|
begin
|
|
if Value then
|
|
FCheckBoxState := cbChecked
|
|
else
|
|
FCheckBoxState := cbUnchecked;
|
|
end;
|
|
|
|
{ TKGridColors }
|
|
|
|
constructor TKGridColors.Create(AGrid: TKCustomGrid);
|
|
begin
|
|
inherited Create;
|
|
FGrid := AGrid;
|
|
FBrightRangeBkgnd := True;
|
|
Initialize;
|
|
ClearBrightColors;
|
|
//BrightRangeBkGnds;
|
|
end;
|
|
|
|
procedure TKGridColors.Assign(Source: TPersistent);
|
|
begin
|
|
inherited;
|
|
if Source is TKGridColors then
|
|
begin
|
|
Colors := TKGridColors(Source).Colors;
|
|
FGrid.Invalidate;
|
|
end
|
|
end;
|
|
|
|
procedure TKGridColors.BrightRangeBkGnds;
|
|
procedure DoBright(Src: TColor; var Dest: TColor);
|
|
begin
|
|
Dest := BrightColor(Src, 0.4, bsOfTop);
|
|
end;
|
|
begin
|
|
if FBrightRangeBkGnd and (FGrid.ComponentState * [csDesigning, csLoading] = []) then
|
|
begin
|
|
DoBright(FColors[ciFocusedCellBkGnd], FColors[ciFocusedRangeBkGnd]);
|
|
DoBright(FColors[ciSelectedCellBkGnd], FColors[ciSelectedRangeBkGnd]);
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridColors.ClearBrightColors;
|
|
var
|
|
I: TKGridColorIndex;
|
|
begin
|
|
for I := 0 to Length(FBrightColors) - 1 do
|
|
FBrightColors[I] := clNone;
|
|
end;
|
|
|
|
function TKGridColors.GetColor(Index: TKGridColorIndex): TColor;
|
|
begin
|
|
Result := InternalGetColor(Index);
|
|
end;
|
|
|
|
function TKGridColors.GetColorEx(Index: TKGridColorIndex): TColor;
|
|
begin
|
|
Result := FColors[Index];
|
|
end;
|
|
|
|
procedure TKGridColors.Initialize;
|
|
begin
|
|
SetLength(FColors, ciGridColorsMax + 1);
|
|
SetLength(FBrightColors, ciGridColorsMax + 1);
|
|
FColors[ciCellBkGnd] := cCellBkGndDef;
|
|
FColors[ciCellLines] := cCellLinesDef;
|
|
FColors[ciCellText] := cCellTextDef;
|
|
FColors[ciDragSuggestionBkGnd] := cDragSuggestionBkGndDef;
|
|
FColors[ciDragSuggestionLine] := cDragSuggestionLineDef;
|
|
FColors[ciFixedCellBkGnd] := cFixedCellBkGndDef;
|
|
FColors[ciFixedCellIndication] := cFixedCellIndicationDef;
|
|
FColors[ciFixedCellLines] := cFixedCellLinesDef;
|
|
FColors[ciFixedCellText] := cFixedCellTextDef;
|
|
FColors[ciFixedThemedCellLines] := cFixedThemedCellLinesDef;
|
|
FColors[ciFixedThemedCellHighlight] := cFixedThemedCellHighlightDef;
|
|
FColors[ciFixedThemedCellShadow] := cFixedThemedCellShadowDef;
|
|
FColors[ciFocusedCellBkGnd] := cFocusedCellBkGndDef;
|
|
FColors[ciFocusedCellText] := cFocusedCellTextDef;
|
|
FColors[ciFocusedRangeBkGnd] := cFocusedRangeBkGndDef;
|
|
FColors[ciFocusedRangeText] := cFocusedRangeTextDef;
|
|
FColors[ciSelectedCellBkGnd] := cSelectedCellBkGndDef;
|
|
FColors[ciSelectedCellText] := cSelectedCellTextDef;
|
|
FColors[ciSelectedRangeBkGnd] := cSelectedRangeBkGndDef;
|
|
FColors[ciSelectedRangeText] := cSelectedRangeTextDef;
|
|
// aki:
|
|
FColors[ciSelectedFixedCellBkGnd] := cSelectedFixedCellBkGndDef;
|
|
end;
|
|
|
|
function TKGridColors.InternalGetColor(Index: TKGridColorIndex): TColor;
|
|
begin
|
|
case FColorScheme of
|
|
csBright:
|
|
begin
|
|
if FBrightColors[Index] = clNone then
|
|
FBrightColors[Index] := BrightColor(FColors[Index], 0.5, bsOfTop);
|
|
Result := FBrightColors[Index];
|
|
end;
|
|
csGrayed:
|
|
case Index of
|
|
ciCellBkGnd, ciFocusedCellText, ciSelectedCellText: Result := clWindow;
|
|
ciCellText, ciFixedCellText, ciFocusedCellBkGnd: Result := clGrayText;
|
|
else
|
|
Result := FColors[Index];
|
|
end;
|
|
csGrayScale:
|
|
Result := ColorToGrayScale(FColors[Index]);
|
|
else
|
|
Result := FColors[Index];
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridColors.InternalSetColor(Index: TKGridColorIndex; Value: TColor);
|
|
begin
|
|
if FColors[Index] <> Value then
|
|
begin
|
|
FColors[Index] := Value;
|
|
FBrightColors[Index] := clNone;
|
|
if not (csLoading in FGrid.ComponentState) then
|
|
FGrid.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridColors.SetColor(Index: TKGridColorIndex; Value: TColor);
|
|
begin
|
|
InternalSetColor(Index, Value);
|
|
end;
|
|
|
|
procedure TKGridColors.SetColorEx(Index: TKGridColorIndex; Value: TColor);
|
|
begin
|
|
if FColors[Index] <> Value then
|
|
begin
|
|
FColors[Index] := Value;
|
|
FBrightColors[Index] := clNone;
|
|
end;
|
|
end;
|
|
|
|
procedure TKGridColors.SetColors(const Value: TKColorArray);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Min(Length(FColors), Length(Value)) - 1 do
|
|
FColors[I] := Value[I];
|
|
ClearBrightColors;
|
|
BrightRangeBkGnds;
|
|
end;
|
|
|
|
{ TKCustomGrid }
|
|
|
|
constructor TKCustomGrid.Create(AOwner: TComponent);
|
|
const
|
|
GridStyle = [csCaptureMouse, csDoubleClicks, csOpaque];
|
|
begin
|
|
inherited;
|
|
if NewStyleControls then
|
|
ControlStyle := GridStyle
|
|
else
|
|
ControlStyle := GridStyle + [csFramed];
|
|
{$IFDEF FPC}
|
|
FFlat := False;
|
|
{$ENDIF}
|
|
FCellHintTimer := TTimer.Create(Self);
|
|
FCellHintTimer.Enabled := False;
|
|
FCellHintTimer.Interval := cMouseCellHintTimeDef;
|
|
FCellHintTimer.OnTimer := CellHintTimerHandler;
|
|
FCells := nil;
|
|
FCellClass := TKGridTextCell;
|
|
FCellPainterClass := TKGridCellPainter;
|
|
FCellPainter := FCellPainterClass.Create(Self);
|
|
FColClass := TKGridCol;
|
|
FColCount := cInvalidIndex;
|
|
FCols := nil;
|
|
FColors := TKGridColors.Create(Self);
|
|
FDefaultColWidth := cDefaultColWidthDef;
|
|
FDefaultRowHeight := cDefaultRowHeightDef;
|
|
FDisabledDrawStyle := cDisabledDrawStyleDef;
|
|
FDragArrow := TKAlphaBitmap.CreateFromRes('KGRID_DRAG_ARROW');
|
|
FDragWindow := nil;
|
|
FDragStyle := dsLayeredFaded;
|
|
FEditedCell := nil;
|
|
FEditor := nil;
|
|
FEditorCell := GridPoint(-1, -1);
|
|
FEditorTransparency := cEditorTransparencyDef;
|
|
FFixedCols := cInvalidIndex;
|
|
FFixedRows := cInvalidIndex;
|
|
FGridLineWidth := cGridLineWidthDef;
|
|
FGridState := gsNormal;
|
|
FHCI.HBegin := TKAlphaBitmap.CreateFromRes('KGRID_HCI_HBEGIN');
|
|
FHCI.HCenter := TKAlphaBitmap.CreateFromRes('KGRID_HCI_HCENTER');
|
|
FHCI.HEnd := TKAlphaBitmap.CreateFromRes('KGRID_HCI_HEND');
|
|
FHCI.VBegin := TKAlphaBitmap.CreateFromRes('KGRID_HCI_VBEGIN');
|
|
FHCI.VCenter := TKAlphaBitmap.CreateFromRes('KGRID_HCI_VCENTER');
|
|
FHCI.VEnd := TKAlphaBitmap.CreateFromRes('KGRID_HCI_VEND');
|
|
FMaxCol := cInvalidIndex;
|
|
FMaxRow := cInvalidIndex;
|
|
FMemCol := cInvalidIndex;
|
|
FMemRow := cInvalidIndex;
|
|
FMinColWidth := cMinColWidthDef;
|
|
FMinRowHeight := cMinRowHeightDef;
|
|
FMouseCellHintTime := cMouseCellHintTimeDef;
|
|
FMouseOver := GridPoint(-1, -1);
|
|
FMoveDirection := cMoveDirectionDef;
|
|
FOptions := cOptionsDef;
|
|
FOptionsEx := cOptionsExDef;
|
|
FRangeSelectStyle := cRangeSelectStyleDef;
|
|
FRowClass := TKGridRow;
|
|
FRowCount := cInvalidIndex;
|
|
FRows := nil;
|
|
FScrollBars := cScrollBarsDef;
|
|
FScrollModeHorz := cScrollModeDef;
|
|
FScrollModeVert := cScrollModeDef;
|
|
FScrollOffset := Point(0, 0);
|
|
FScrollSpeed := cScrollSpeedDef;
|
|
FScrollTimer := TTimer.Create(Self);
|
|
FScrollTimer.Enabled := False;
|
|
FScrollTimer.Interval := FScrollSpeed;
|
|
FScrollTimer.OnTimer := ScrollTimerHandler;
|
|
FSelections := nil;
|
|
FSizingStyle := cSizingStyleDef;
|
|
FSortStyle := cSortStyleDef;
|
|
FSortModeLock := 0;
|
|
FTmpBitmap := TBitmap.Create;
|
|
FTmpBitmap.Width := 1;
|
|
FTmpBitmap.Height := 1;
|
|
FTopLeft := GridPoint(cInvalidIndex, cInvalidIndex);
|
|
FOnBeginColDrag := nil;
|
|
FOnBeginColSizing := nil;
|
|
FOnBeginRowDrag := nil;
|
|
FOnBeginRowSizing := nil;
|
|
FOnCellSpan := nil;
|
|
FOnChanged := nil;
|
|
FOnCheckColDrag := nil;
|
|
FOnCheckRowDrag := nil;
|
|
FOnColMoved := nil;
|
|
FOnColWidthsChanged := nil;
|
|
FOnColWidthsChangedEx := nil;
|
|
FOnCompareCellInstances := nil;
|
|
FOnCompareCells := nil;
|
|
FOnCustomSortCols := nil;
|
|
FOnCustomSortRows := nil;
|
|
FOnDrawCell := nil;
|
|
FOnEditorCreate := nil;
|
|
FOnEditorDataFromGrid := nil;
|
|
FOnEditorDataToGrid := nil;
|
|
FOnEditorDestroy := nil;
|
|
FOnEditorKeyPreview := nil;
|
|
FOnEditorResize := nil;
|
|
FOnEndColDrag := nil;
|
|
FOnEndColSizing := nil;
|
|
FOnEndRowDrag := nil;
|
|
FOnEndRowSizing := nil;
|
|
FOnExchangeCols := nil;
|
|
FOnExchangeRows := nil;
|
|
FOnMeasureCell := nil;
|
|
FOnMouseCellHint := nil;
|
|
FOnMouseClickCell := nil;
|
|
FOnMouseDblClickCell := nil;
|
|
FOnMouseEnterCell := nil;
|
|
FOnMouseLeaveCell := nil;
|
|
FOnRowHeightsChanged := nil;
|
|
FOnRowMoved := nil;
|
|
FOnSelectCell := nil;
|
|
FOnSizeChanged := nil;
|
|
FOnTopLeftChanged := nil;
|
|
Color := clWindow;
|
|
LoadCustomCursor(crHResize, 'KGRID_CURSOR_HRESIZE');
|
|
LoadCustomCursor(crVResize, 'KGRID_CURSOR_VRESIZE');
|
|
ParentColor := False;
|
|
TabStop := True;
|
|
ChangeDataSize(True, 0, cColCountDef, True, 0, cRowCountDef);
|
|
SetBounds(Left, Top, FColCount * FDefaultColWidth,
|
|
FRowCount * FDefaultRowHeight);
|
|
end;
|
|
|
|
destructor TKCustomGrid.Destroy;
|
|
begin
|
|
EditorMode := False;
|
|
inherited Destroy;
|
|
FHint.Free;
|
|
FCellPainter.Free;
|
|
FColors.Free;
|
|
FEditedCell.Free;
|
|
FDragArrow.Free;
|
|
FDragWindow.Free;
|
|
FHCI.HBegin.Free;
|
|
FHCI.HCenter.Free;
|
|
FHCI.HEnd.Free;
|
|
FHCI.VBegin.Free;
|
|
FHCI.VCenter.Free;
|
|
FHCI.VEnd.Free;
|
|
FTmpBitmap.Free;
|
|
FreeData;
|
|
end;
|
|
|
|
procedure TKCustomGrid.AdjustPageSetup;
|
|
begin
|
|
inherited;
|
|
PageSetup.PrintingMapped := True;
|
|
end;
|
|
|
|
function TKCustomGrid.AdjustSelection(const ASelection: TKGridRect): TKGridRect;
|
|
begin
|
|
Result := ASelection;
|
|
if goRowSelect in FOptions then
|
|
begin
|
|
// aki:
|
|
if gxEditFixedCols in FOptionsEx then
|
|
begin
|
|
Result.Col1:=0;
|
|
Result.Col2:=FColCount - 1;
|
|
end else
|
|
begin
|
|
Result.Col1 := FFixedCols;
|
|
Result.Col2 := FColCount - 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.AutoSizeCol(ACol: Integer; FixedCells: Boolean);
|
|
var
|
|
R: TRect;
|
|
Dummy, Extent, FirstRow, I, MaxExtent: Integer;
|
|
Span: TKGridCellSpan;
|
|
GridFocused: Boolean;
|
|
begin
|
|
if ColValid(ACol) then
|
|
begin
|
|
GridFocused := HasFocus;
|
|
R.Left := 0;
|
|
R.Top := 0;
|
|
MaxExtent := FMinColWidth;
|
|
Extent := InternalGetColWidths(ACol);
|
|
if FixedCells then FirstRow := 0 else FirstRow := FFixedRows;
|
|
for I := FirstRow to FRowCount - 1 do
|
|
begin
|
|
Span := InternalGetCellSpan(ACol, I);
|
|
if (Span.RowSpan > 0) and (Span.ColSpan > 0) then
|
|
begin
|
|
InternalGetHExtent(ACol, Span.ColSpan, R.Right, Dummy);
|
|
InternalGetVExtent(I, Span.RowSpan, R.Bottom, Dummy);
|
|
MaxExtent := Max(MaxExtent, MeasureCell(ACol, I, R, GetDrawState(ACol, I, GridFocused), mpColWidth).X - R.Right + Extent);
|
|
end;
|
|
end;
|
|
ColWidths[ACol] := MaxExtent;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.AutoSizeGrid(Priority: TKGridMeasureCellPriority; FixedCells: Boolean);
|
|
var
|
|
R: TRect;
|
|
CellExtent: TPoint;
|
|
Dummy, Extent, FirstCol, FirstRow, I, J, MaxExtent: Integer;
|
|
Span: TKGridCellSpan;
|
|
ModifyCols, ModifyRows, GridFocused: Boolean;
|
|
ColMaxExtents: TDynIntegers;
|
|
begin
|
|
LockUpdate;
|
|
try
|
|
{ Despite the update lock, this function is rather slow for huge grids,
|
|
of course, because it has to measure all cells. }
|
|
GridFocused := HasFocus;
|
|
MaxExtent := 0;
|
|
Extent := 0;
|
|
R.Left := 0;
|
|
R.Top := 0;
|
|
if FixedCells then FirstCol := 0 else FirstCol := FFixedCols;
|
|
if FixedCells then FirstRow := 0 else FirstRow := FFixedRows;
|
|
ModifyCols := Priority in [mpColWidth, mpCellExtent];
|
|
ModifyRows := Priority in [mpRowHeight, mpCellExtent];
|
|
if ModifyCols then
|
|
begin
|
|
SetLength(ColMaxExtents, FColCount - FirstCol);
|
|
for I := 0 to FColCount - FirstCol - 1 do
|
|
ColMaxExtents[I] := FMinColWidth;
|
|
end;
|
|
for J := FirstRow to FRowCount - 1 do
|
|
begin
|
|
if ModifyRows then
|
|
begin
|
|
MaxExtent := 0;
|
|
Extent := InternalGetRowHeights(J);
|
|
end;
|
|
for I := FirstCol to FColCount - 1 do
|
|
begin
|
|
Span := InternalGetCellSpan(I, J);
|
|
if (Span.RowSpan > 0) and (Span.ColSpan > 0) then
|
|
begin
|
|
InternalGetHExtent(I, Span.ColSpan, R.Right, Dummy);
|
|
InternalGetVExtent(J, Span.RowSpan, R.Bottom, Dummy);
|
|
CellExtent := MeasureCell(I, J, R, GetDrawState(I, J, GridFocused), Priority);
|
|
if ModifyRows then
|
|
MaxExtent := Max(MaxExtent, CellExtent.Y - R.Bottom + Extent);
|
|
if ModifyCols then
|
|
ColMaxExtents[I - FirstCol] := Max(ColMaxExtents[I - FirstCol], CellExtent.x - R.Right + InternalGetColWidths(I));
|
|
end;
|
|
end;
|
|
if ModifyRows then
|
|
RowHeights[J] := MaxExtent;
|
|
end;
|
|
if ModifyCols then
|
|
for I := FirstCol to FColCount - 1 do
|
|
ColWidths[I] := ColMaxExtents[I - FirstCol];
|
|
finally
|
|
UnlockUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.AutoSizeRow(ARow: Integer; FixedCells: Boolean);
|
|
var
|
|
R: TRect;
|
|
Dummy, Extent, FirstCol, I, MaxExtent: Integer;
|
|
Span: TKGridCellSpan;
|
|
GridFocused: Boolean;
|
|
begin
|
|
if RowValid(ARow) then
|
|
begin
|
|
GridFocused := HasFocus;
|
|
R.Left := 0;
|
|
R.Top := 0;
|
|
MaxExtent := FMinRowHeight;
|
|
Extent := InternalGetRowHeights(ARow);
|
|
if FixedCells then FirstCol := 0 else FirstCol := FFixedCols;
|
|
for I := FirstCol to FColCount - 1 do
|
|
begin
|
|
Span := InternalGetCellSpan(I, ARow);
|
|
if (Span.RowSpan > 0) and (Span.ColSpan > 0) then
|
|
begin
|
|
InternalGetHExtent(I, Span.ColSpan, R.Right, Dummy);
|
|
InternalGetVExtent(ARow, Span.RowSpan, R.Bottom, Dummy);
|
|
MaxExtent := Max(MaxExtent, MeasureCell(I, ARow, R, GetDrawState(I, ARow, GridFocused), mpRowHeight).Y - R.Bottom + Extent);
|
|
end;
|
|
end;
|
|
RowHeights[ARow] := MaxExtent;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.BeginColDrag(var Origin: Integer;
|
|
const MousePt: TPoint): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnBeginColDrag) then
|
|
FOnBeginColDrag(Self, Origin, MousePt, Result)
|
|
else if Assigned(FCols) then
|
|
FCols[Origin].BeginDrag(Origin, MousePt, Result);
|
|
Origin := MinMax(Origin, FFixedCols, FColCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.BeginColSizing(var Index, Pos: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnBeginColSizing) then
|
|
FOnBeginColSizing(Self, Index, Pos, Result)
|
|
else if Assigned(FCols) then
|
|
Result := FCols[Index].CanResize;
|
|
Index := MinMax(Index, 0, FColCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.BeginRowDrag(var Origin: Integer;
|
|
const MousePt: TPoint): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnBeginRowDrag) then
|
|
FOnBeginRowDrag(Self, Origin, MousePt, Result)
|
|
else if Assigned(FRows) then
|
|
FRows[Origin].BeginDrag(Origin, MousePt, Result);
|
|
Origin := MinMax(Origin, FFixedRows, FRowCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.BeginRowSizing(var Index, Pos: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnBeginRowSizing) then
|
|
FOnBeginRowSizing(Self, Index, Pos, Result)
|
|
else if Assigned(FRows) then
|
|
Result := FRows[Index].CanResize;
|
|
Index := MinMax(Index, 0, FRowCount - 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.CancelMode;
|
|
begin
|
|
try
|
|
case FGridState of
|
|
gsColSizing, gsRowSizing:
|
|
SuggestSizing(csStop);
|
|
gsColMoving, gsRowMoving:
|
|
begin
|
|
ProcessDragWindow(FHitPos, Point(0, 0), cInvalidIndex, FGridState = gsColMoving, True);
|
|
SuggestDrag(csStop);
|
|
end;
|
|
else
|
|
InvalidateCell(FHitCell.Col, FHitCell.Row);
|
|
end;
|
|
finally
|
|
MouseCapture := False;
|
|
FGridState := gsNormal;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.CellHintTimerHandler(Sender: TObject);
|
|
begin
|
|
if (FMouseOver.Col = FHintCell.Col) and (FMouseOver.Row = FHintCell.Row) then
|
|
MouseCellHint(FMouseOver.Col, FMouseOver.Row, True);
|
|
FCellHintTimer.Enabled := False;
|
|
end;
|
|
|
|
function TKCustomGrid.CellRect(ACol, ARow: Integer; out R: TRect;
|
|
VisibleOnly: Boolean): Boolean;
|
|
var
|
|
I, W, H: Integer;
|
|
Span: TKGridCellSpan;
|
|
begin
|
|
Result := False;
|
|
if ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
Span := InternalGetCellSpan(ACol, ARow);
|
|
if (Span.ColSpan <= 0) or (Span.RowSpan <= 0) then
|
|
Span := MakeCellSpan(1, 1);
|
|
if CellToPoint(ACol, ARow, R.TopLeft, VisibleOnly) then
|
|
begin
|
|
W := 0;
|
|
for I := ACol to ACol + Span.ColSpan - 1 do
|
|
Inc(W, InternalGetColWidths(I) + InternalGetEffectiveColSpacing(I));
|
|
H := 0;
|
|
for I := ARow to ARow + Span.RowSpan - 1 do
|
|
Inc(H, InternalGetRowHeights(I) + InternalGetEffectiveRowSpacing(I));
|
|
if ACol >= FFixedCols then
|
|
begin
|
|
if goVertLine in FOptions then Dec(W, FGridLineWidth);
|
|
end else
|
|
if goFixedVertLine in FOptions then Dec(W, FGridLineWidth);
|
|
if ARow >= FFixedRows then
|
|
begin
|
|
if goHorzLine in FOptions then Dec(H, FGridLineWidth);
|
|
end else
|
|
if goFixedHorzLine in FOptions then Inc(H, FGridLineWidth);
|
|
if (W > 0) and (H > 0) then
|
|
begin
|
|
R.Right := R.Left + W;
|
|
R.Bottom := R.Top + H;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.CellSelected(ACol, ARow: Integer): Boolean;
|
|
begin
|
|
Result := CellInGridRect(ACol, ARow, Selection);
|
|
end;
|
|
|
|
function TKCustomGrid.CellToPoint(ACol, ARow: Integer; var Point: TPoint;
|
|
VisibleOnly: Boolean): Boolean;
|
|
|
|
function Axis(const Info: TKGridAxisInfo; Cell: Integer; out Coord: Integer): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := False;
|
|
if (Cell >= 0) and (Cell < Info.TotalCellCount) then
|
|
begin
|
|
I := 0;
|
|
Coord := 0;
|
|
while (I < Cell) and (I < Info.FixedCellCount) and (not VisibleOnly or (Coord < Info.ClientExtent)) do
|
|
begin
|
|
Inc(Coord, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
if not VisibleOnly or (Coord < Info.ClientExtent) then
|
|
begin
|
|
if I = Info.FixedCellCount then
|
|
begin
|
|
Dec(Coord, Info.ScrollOffset);
|
|
I := Info.FirstGridCell;
|
|
while not VisibleOnly and (Cell < I) and (I > Info.FixedCellCount) do
|
|
begin
|
|
Dec(I);
|
|
Dec(Coord, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
end;
|
|
while (I < Cell) and (I < Info.TotalCellCount) and (not VisibleOnly or (Coord < Info.ClientExtent)) do
|
|
begin
|
|
Inc(Coord, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
Result := Cell = I;
|
|
if Result then
|
|
begin
|
|
while (I >= 0) and (Info.CellExtent(I) = 0) do Dec(I);
|
|
if I < Cell - 1 then
|
|
Dec(Coord, Info.EffectiveSpacing(I + 1));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
Result := Axis(GetAxisInfoHorz([]), ACol, Point.X);
|
|
if Result then
|
|
Result := Axis(GetAxisInfoVert([]), ARow, Point.Y);
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKCustomGrid.CellVisible(ACol, ARow: Integer): Boolean;
|
|
begin
|
|
Result := CellInGridRect(ACol, ARow, VisibleGridRect);
|
|
end;
|
|
|
|
procedure TKCustomGrid.Changed;
|
|
begin
|
|
if Assigned(FOnChanged) then
|
|
FOnChanged(Self, FEditorCell.Col, FEditorCell.Row);
|
|
end;
|
|
|
|
procedure TKCustomGrid.ChangeDataSize(ColInsert: Boolean; ColAt, ColCnt: Integer;
|
|
RowInsert: Boolean; RowAt, RowCnt: Integer);
|
|
|
|
procedure Axis(var Data: TKGridAxisItems; AxisItemClass: TKGridAxisItemClass;
|
|
Insert: Boolean; DefFixedCnt: Integer; var At, Cnt, MaxLen, ItemCount, FixedCount: Integer);
|
|
var
|
|
I, Len: Integer;
|
|
begin
|
|
if Cnt > 0 then
|
|
begin
|
|
Len := Length(Data);
|
|
if Insert then
|
|
begin
|
|
At := MinMax(At, 0, Len);
|
|
SetLength(Data, Len + Cnt);
|
|
for I := Len - 1 downto At do Data[I + Cnt] := Data[I];
|
|
for I := At to At + Cnt - 1 do
|
|
begin
|
|
Data[I] := AxisItemClass.Create(Self);
|
|
Data[I].InitialPos := MaxLen + 1;
|
|
Inc(MaxLen);
|
|
end;
|
|
if FixedCount < 0 then
|
|
FixedCount := DefFixedCnt
|
|
else if At < FixedCount then
|
|
Inc(FixedCount, Cnt);
|
|
end
|
|
else if Len > 0 then
|
|
begin
|
|
At := MinMax(At, 0, Len - 1);
|
|
Cnt := Min(Cnt, Len - At);
|
|
if Cnt > 0 then
|
|
begin
|
|
for I := At to At + Cnt - 1 do
|
|
Data[I].Free;
|
|
for I := At to Len - Cnt - 1 do Data[I] := Data[I + Cnt];
|
|
SetLength(Data, Len - Cnt);
|
|
if At < FixedCount then
|
|
Dec(FixedCount, FixedCount - At);
|
|
end;
|
|
end;
|
|
ItemCount := Length(Data);
|
|
FixedCount := Min(FixedCount, ItemCount - 1);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
OldFixedRows, OldFixedCols, I, J, Len: Integer;
|
|
UpdateNeeded: Boolean;
|
|
Reason: TKGridSizeChange;
|
|
begin
|
|
EditorMode := False;
|
|
UpdateNeeded := False;
|
|
if not ColInsert then
|
|
ColCnt := Min(ColCnt, FColCount - 1);
|
|
if not RowInsert then
|
|
RowCnt := Min(RowCnt, FRowCount - 1);
|
|
OldFixedCols := FFixedCols;
|
|
Axis(FCols, FColClass, ColInsert, cFixedColsDef,
|
|
ColAt, ColCnt, FMaxCol, FColCount, FFixedCols);
|
|
OldFixedRows := FFixedRows;
|
|
Axis(FRows, FRowClass, RowInsert, cFixedRowsDef,
|
|
RowAt, RowCnt, FMaxRow, FRowCount, FFixedRows);
|
|
FMemCol := cInvalidIndex;
|
|
FMemRow := cInvalidIndex;
|
|
if goVirtualGrid in FOptions then
|
|
begin
|
|
if Assigned(FCells) then
|
|
begin
|
|
for I := 0 to Length(FCells) - 1 do
|
|
for J := 0 to Length(FCells[I]) - 1 do
|
|
FCells[I, J].Free;
|
|
FCells := nil;
|
|
UpdateNeeded := True;
|
|
end;
|
|
end else
|
|
begin
|
|
// take rows first because probably there will be always much more rows
|
|
if RowCnt > 0 then
|
|
begin
|
|
Len := Length(FCells);
|
|
if FRowCount > Len then
|
|
begin
|
|
SetLength(FCells, Len + RowCnt);
|
|
for I := Len - 1 downto RowAt do FCells[I + RowCnt] := FCells[I];
|
|
for I := RowAt to RowAt + RowCnt - 1 do
|
|
begin
|
|
SetLength(FCells[I], FColCount);
|
|
for J := 0 to Length(FCells[I]) - 1 do FCells[I, J] := nil;
|
|
end;
|
|
end else
|
|
begin
|
|
for I := RowAt to RowAt + RowCnt - 1 do
|
|
begin
|
|
for J := 0 to Length(FCells[I]) - 1 do FCells[I, J].Free;
|
|
FCells[I] := nil;
|
|
end;
|
|
for I := RowAt to Len - RowCnt - 1 do FCells[I] := FCells[I + RowCnt];
|
|
SetLength(FCells, Len - RowCnt);
|
|
end;
|
|
end;
|
|
if ColCnt > 0 then
|
|
begin
|
|
for I := 0 to Length(FCells) - 1 do
|
|
begin
|
|
Len := Length(FCells[I]);
|
|
if FColCount > Len then
|
|
begin
|
|
SetLength(FCells[I], Len + ColCnt);
|
|
for J := Len - 1 downto ColAt do FCells[I, J + ColCnt] := FCells[I, J];
|
|
for J := ColAt to ColAt + ColCnt - 1 do FCells[I, J] := nil;
|
|
end
|
|
else if FColCount < Len then
|
|
begin
|
|
for J := ColAt to ColAt + ColCnt - 1 do FCells[I, J].Free;
|
|
for J := ColAt to Len - ColCnt - 1 do FCells[I, J] := FCells[I, J + ColCnt];
|
|
SetLength(FCells[I], Len - ColCnt);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if (ColCnt > 0) or (RowCnt > 0) then
|
|
begin
|
|
SelectionFix(FSelection);
|
|
if (FFixedRows <> OldFixedRows) or (FFixedCols <> OldFixedCols) then
|
|
ResetTopLeft;
|
|
UpdateAxes(ColCnt > 0, cAll, RowCnt > 0, cAll, []);
|
|
UpdateCellSpan;
|
|
if ColCnt > 0 then
|
|
begin
|
|
if ColInsert then
|
|
begin
|
|
ClearSortModeVert;
|
|
Reason := scColInserted;
|
|
end else
|
|
Reason := scColDeleted;
|
|
SizeChanged(Reason, ColAt, ColCnt);
|
|
end;
|
|
if RowCnt > 0 then
|
|
begin
|
|
if RowInsert then
|
|
begin
|
|
ClearSortModeHorz;
|
|
Reason := scRowInserted
|
|
end else
|
|
Reason := scRowDeleted;
|
|
SizeChanged(Reason, RowAt, RowCnt);
|
|
end;
|
|
end else if UpdateNeeded then
|
|
Invalidate;
|
|
end;
|
|
|
|
function TKCustomGrid.CheckColDrag(Origin: Integer; var Destination: Integer;
|
|
const MousePt: TPoint): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnCheckColDrag) then
|
|
FOnCheckColDrag(Self, Origin, Destination, MousePt, Result)
|
|
else if Assigned(FCols) then
|
|
FCols[Destination].CheckDrag(Origin, Destination, MousePt, Result);
|
|
Destination := MinMax(Destination, FFixedCols, FColCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.CheckRowDrag(Origin: Integer; var Destination: Integer;
|
|
const MousePt: TPoint): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnCheckRowDrag) then
|
|
FOnCheckRowDrag(Self, Origin, Destination, MousePt, Result)
|
|
else if Assigned(FRows) then
|
|
FRows[Destination].CheckDrag(Origin, Destination, MousePt, Result);
|
|
Destination := MinMax(Destination, FFixedRows, FRowCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.ClampInView(ACol, ARow: Integer): Boolean;
|
|
var
|
|
DeltaHorz, DeltaVert: Integer;
|
|
begin
|
|
Result := ScrollNeeded(ACol, ARow, DeltaHorz, DeltaVert);
|
|
if Result then
|
|
Scroll(cScrollDelta, cScrollDelta, DeltaHorz, DeltaVert, True);
|
|
end;
|
|
|
|
procedure TKCustomGrid.ClearCol(ACol: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Assigned(FCells) and ColValid(ACol) then
|
|
begin
|
|
for I := 0 to FRowCount - 1 do
|
|
FreeAndNil(FCells[I, ACol]);
|
|
UpdateCellSpan;
|
|
InvalidateCol(ACol);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ClearGrid;
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
if Assigned(FCells) then
|
|
begin
|
|
for I := 0 to FColCount - 1 do
|
|
for J := 0 to FRowCount - 1 do
|
|
FreeAndNil(FCells[J, I]);
|
|
UpdateCellSpan;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ClearRow(ARow: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Assigned(FCells) and RowValid(ARow) then
|
|
begin
|
|
for I := 0 to FColCount - 1 do
|
|
FreeAndNil(FCells[ARow, I]);
|
|
UpdateCellSpan;
|
|
InvalidateRow(ARow);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ClearSortMode;
|
|
begin
|
|
ClearSortModeHorz;
|
|
ClearSortModeVert;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ClearSortModeHorz;
|
|
var
|
|
OldIndex: Integer;
|
|
begin
|
|
if SortModeUnlocked then
|
|
begin
|
|
OldIndex := SortCol;
|
|
if OldIndex >= 0 then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FCols[OldIndex].SortMode := smNone;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
InvalidateGridRect(GridRect(OldIndex, 0, OldIndex, FFixedRows - 1));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ClearSortModeVert;
|
|
var
|
|
OldIndex: Integer;
|
|
begin
|
|
if SortModeUnlocked then
|
|
begin
|
|
OldIndex := SortRow;
|
|
if OldIndex >= 0 then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FRows[OldIndex].SortMode := smNone;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
InvalidateGridRect(GridRect(0, OldIndex, FFixedCols - 1, OldIndex));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.CMDesignHitTest(var Msg: TLMMouse);
|
|
begin
|
|
Msg.Result := Integer(Flag(cGF_DesignHitTest));
|
|
end;
|
|
|
|
procedure TKCustomGrid.CMEnabledChanged(var Msg: TLMessage);
|
|
begin
|
|
inherited;
|
|
if not Enabled then EditorMode := False;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TKCustomGrid.CMShowingChanged(var Msg: TLMessage);
|
|
begin
|
|
inherited;
|
|
if Showing then
|
|
UpdateScrollRange(True, True, False);
|
|
end;
|
|
|
|
procedure TKCustomGrid.CMSysColorChange(var Msg: TLMessage);
|
|
begin
|
|
inherited;
|
|
FColors.ClearBrightColors;
|
|
end;
|
|
|
|
procedure TKCustomGrid.CMVisibleChanged(var Msg: TLMessage);
|
|
begin
|
|
inherited;
|
|
if not Visible then
|
|
EditorMode := False;
|
|
end;
|
|
|
|
procedure TKCustomGrid.CMWantSpecialKey(var Msg: TLMKey);
|
|
begin
|
|
inherited;
|
|
if (goEditing in Options) and (Msg.CharCode in [VK_RETURN, VK_ESCAPE]) then
|
|
Msg.Result := 1;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ColMoved(FromIndex, ToIndex: Integer);
|
|
begin
|
|
if Assigned(FOnColMoved) then
|
|
FOnColMoved(Self, FromIndex, ToIndex);
|
|
end;
|
|
|
|
function TKCustomGrid.ColSelectable(ACol: Integer): Boolean;
|
|
begin
|
|
Result := (ACol >= FFixedCols) and (ACol < FColCount);
|
|
end;
|
|
|
|
function TKCustomGrid.ColSelected(ACol: Integer): Boolean;
|
|
begin
|
|
Result := ColInGridRect(ACol, Selection);
|
|
end;
|
|
|
|
function TKCustomGrid.ColValid(ACol: Integer): Boolean;
|
|
begin
|
|
Result := (ACol >= 0) and (ACol < FColCount);
|
|
end;
|
|
|
|
procedure TKCustomGrid.ColWidthsChanged(ACol: Integer);
|
|
begin
|
|
if Assigned(FOnColWidthsChanged) then
|
|
FOnColWidthsChanged(Self)
|
|
else if Assigned(FOnColWidthsChangedEx) then
|
|
FOnColWidthsChangedEx(Self, ACol);
|
|
end;
|
|
|
|
function TKCustomGrid.CompareCellInstances(ACell1, ACell2: TKGridCell): Integer;
|
|
begin
|
|
if Assigned(FOnCompareCellInstances) then
|
|
Result := FOnCompareCellInstances(Self, ACell1, ACell2)
|
|
else if Assigned(FCells) then
|
|
Result := DefaultCompareCells(ACell1, ACell2)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.CompareCells(ACol1, ARow1, ACol2, ARow2: Integer): Integer;
|
|
begin
|
|
if Assigned(FOnCompareCells) then
|
|
Result := FOnCompareCells(Self, ACol1, ARow1, ACol2, ARow2)
|
|
else if Assigned(FCells) then
|
|
Result := DefaultCompareCells(InternalGetCell(ACol1, ARow1), InternalGetCell(ACol2, ARow1))
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.CompareCols(ARow, ACol1, ACol2: Integer): Integer;
|
|
begin
|
|
if Assigned(FOnCompareCells) then
|
|
Result := FOnCompareCells(Self, ACol1, ARow, ACol2, ARow)
|
|
else if Assigned(FCells) then
|
|
Result := DefaultCompareCells(InternalGetCell(ACol1, ARow), InternalGetCell(ACol2, ARow))
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.CompareRows(ACol, ARow1, ARow2: Integer): Integer;
|
|
begin
|
|
if Assigned(FOnCompareCells) then
|
|
Result := FOnCompareCells(Self, ACol, ARow1, ACol, ARow2)
|
|
else if Assigned(FCells) then
|
|
Result := DefaultCompareCells(InternalGetCell(ACol, ARow1), InternalGetCell(ACol, ARow2))
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TKCustomGrid.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
with Params do
|
|
begin
|
|
Style := Style or WS_TABSTOP or WS_CLIPCHILDREN or WS_CLIPSIBLINGS;
|
|
if HasHorzScrollBar then Style := Style or WS_HSCROLL;
|
|
if HasVertScrollBar then Style := Style or WS_VSCROLL;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.CustomSortCols(ByRow: Integer;
|
|
var SortMode: TKGridSortMode): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Assigned(FOnCustomSortCols) then FOnCustomSortCols(Self, ByRow, SortMode, Result);
|
|
end;
|
|
|
|
function TKCustomGrid.CustomSortRows(ByCol: Integer;
|
|
var SortMode: TKGridSortMode): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Assigned(FOnCustomSortRows) then FOnCustomSortRows(Self, ByCol, SortMode, Result);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultColWidthChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
for I := 0 to FColCount - 1 do FCols[I].Extent := FDefaultColWidth;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
UpdateAxes(True, cAll, False, cAll, [afCheckMinExtent]);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultComboKeyPreview(AEditor: TComboBox;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
if Key in [VK_RETURN, VK_ESCAPE, VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT] then
|
|
begin
|
|
if AEditor.DroppedDown then
|
|
IsGridKey := False;
|
|
end
|
|
else if AEditor.Style in [csSimple, csDropDown] then
|
|
begin
|
|
// we have a combo box with edit control
|
|
DoEditKeyPreview(StringLength(AEditor.Text), AEditor.SelStart, AEditor.SelLength, 1, False, True, True,
|
|
Key, ShiftState, IsGridKey);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultComboSelect(AEditor: TComboBox; SelectAll,
|
|
CaretToLeft: Boolean);
|
|
begin
|
|
if AEditor.Style in [csSimple, csDropDown] then
|
|
begin
|
|
// we have a combo box with edit control
|
|
if SelectAll then
|
|
AEditor.SelectAll
|
|
else
|
|
begin
|
|
AEditor.SelLength := 0;
|
|
if CaretToLeft then
|
|
AEditor.SelStart := 0
|
|
else
|
|
AEditor.SelStart := StringLength(AEditor.Text);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditKeyPreview(AEditor: TCustomEdit;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
var
|
|
MultiLine, StartLine, EndLine: Boolean;
|
|
TextLen, LineCount: Integer;
|
|
begin
|
|
TextLen := StringLength(AEditor.Text);
|
|
if AEditor is TCustomMemo then
|
|
begin
|
|
MultiLine := True;
|
|
LineCount := TCustomMemo(AEditor).Lines.Count;
|
|
StartLine := AEditor.SelStart < StringLength(TCustomMemo(AEditor).Lines[0]);
|
|
EndLine := AEditor.SelStart > TextLen - StringLength(TCustomMemo(AEditor).Lines[TCustomMemo(AEditor).Lines.Count - 1]);
|
|
end else
|
|
begin
|
|
MultiLine := False;
|
|
StartLine := True;
|
|
EndLine := True;
|
|
LineCount := 1;
|
|
end;
|
|
DoEditKeyPreview(StringLength(AEditor.Text), AEditor.SelStart, AEditor.SelLength, LineCount, MultiLine, StartLine, EndLine,
|
|
Key, ShiftState, IsGridKey);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorCreate(ACol, ARow: Integer;
|
|
var AEditor: TWinControl);
|
|
begin
|
|
AEditor := TEdit.Create(nil);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorDataFromGrid(AEditor: TWinControl;
|
|
ACol, ARow: Integer; var AssignText: Boolean);
|
|
begin
|
|
// empty
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorDataToGrid(AEditor: TWinControl;
|
|
ACol, ARow: Integer; var AssignText: Boolean);
|
|
begin
|
|
// empty
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorDestroy(AEditor: TWinControl; ACol,
|
|
ARow: Integer);
|
|
begin
|
|
// empty
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorKeyPreview(AEditor: TWinControl;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
if AEditor is TCustomEdit then
|
|
DefaultEditKeyPreview(TCustomEdit(AEditor), ACol, ARow, Key, ShiftState, IsGridKey)
|
|
else if AEditor is TCustomComboBox then
|
|
DefaultComboKeyPreview(TComboBox(AEditor), ACol, ARow, Key, ShiftState, IsGridKey)
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorResize(AEditor: TWinControl;
|
|
ACol, ARow: Integer; var ARect: TRect);
|
|
begin
|
|
// empty
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditorSelect(AEditor: TWinControl;
|
|
ACol, ARow: Integer; SelectAll, CaretToLeft, SelectedByMouse: Boolean);
|
|
begin
|
|
if AEditor is TCustomEdit then
|
|
DefaultEditSelect(TCustomEdit(AEditor), SelectAll, CaretToLeft)
|
|
else if AEditor is TCustomComboBox then
|
|
DefaultComboSelect(TComboBox(AEditor), SelectAll, CaretToLeft);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultEditSelect(AEditor: TCustomEdit; SelectAll,
|
|
CaretToLeft: Boolean);
|
|
begin
|
|
if SelectAll then
|
|
AEditor.SelectAll
|
|
else
|
|
begin
|
|
if CaretToLeft then
|
|
AEditor.SelStart := 0
|
|
else
|
|
AEditor.SelStart := StringLength(AEditor.Text);
|
|
AEditor.SelLength := 0;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.DefaultCompareCells(ACell1, ACell2: TKGridCell): Integer;
|
|
var
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
S1, S2: string;
|
|
{$ELSE}
|
|
W1, W2: PWideChar;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF STRING_IS_UNICODE}
|
|
if ACell1 is TKGridTextCell then S1 := TKGridTextCell(ACell1).Text else S1 := '';
|
|
if ACell2 is TKGridTextCell then S2 := TKGridTextCell(ACell2).Text else S2 := '';
|
|
Result := CompareStrings(S1, S2);
|
|
{$ELSE}
|
|
if ACell1 is TKGridTextCell then W1 := TKGridTextCell(ACell1).TextPtr else W1 := '';
|
|
if ACell2 is TKGridTextCell then W2 := TKGridTextCell(ACell2).TextPtr else W2 := '';
|
|
Result := CompareWideChars(W1, W2);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultMouseCellHint(ACol, ARow: Integer;
|
|
AShow: Boolean);
|
|
var
|
|
R: TRect;
|
|
Extent: TPoint;
|
|
AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
begin
|
|
if ColValid(ACol) and Cols[ACol].CellHint then
|
|
begin
|
|
if AShow then
|
|
begin
|
|
AText := Cells[ACol, ARow];
|
|
if (AText <> '') and (ARow >= FFixedRows) and
|
|
((ARow <> FEditorCell.Row) or (ACol <> FEditorCell.Col) or not EditorMode) and
|
|
CellRect(ACol, ARow, R, True) then
|
|
begin
|
|
Extent := MeasureCell(ACol, ARow, R, GetDrawState(ACol, ARow, HasFocus), mpCellExtent);
|
|
if (Extent.X > R.Right - R.Left) or (Extent.Y > R.Bottom - R.Top) then
|
|
begin
|
|
FreeAndNil(FHint);
|
|
FHint := TKTextHint.Create(nil);
|
|
TKTextHint(FHint).Text := AText;
|
|
Inc(R.Left, 10);
|
|
Inc(R.Top, 10);
|
|
FHint.ShowAt(ClientToScreen(R.TopLeft));
|
|
end;
|
|
end;
|
|
end else
|
|
FreeAndNil(FHint);
|
|
end else
|
|
FreeAndNil(FHint);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultRowHeightChanged;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
for I := 0 to FRowCount - 1 do FRows[I].Extent := FDefaultRowHeight;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
UpdateAxes(False, cAll, True, cAll, [afCheckMinExtent]);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultScrollBarKeyPreview(AEditor: TScrollBar;
|
|
ACol, ARow: Integer; var Key: Word; ShiftState: TShiftState; var IsGridKey: Boolean);
|
|
begin
|
|
if (Key = VK_LEFT) and (AEditor.Position > AEditor.Min) or
|
|
(Key = VK_RIGHT) and (AEditor.Position < AEditor.Max) then
|
|
IsGridKey := False;
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefaultSetCaretToLeft(Key: Word; ShiftState: TShiftState);
|
|
begin
|
|
if (Key in [VK_DOWN, VK_NEXT]) or (Key in [VK_RIGHT, VK_END]) and (Col < FColCount - 1) then
|
|
FlagSet(cGF_CaretToLeft);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DefineProperties(Filer: TFiler);
|
|
|
|
function DoColData: Boolean;
|
|
begin
|
|
if (Filer.Ancestor <> nil) and (Filer.Ancestor is TKCustomGrid) then
|
|
Result := not CompareAxisItems(TKCustomGrid(Filer.Ancestor).FCols, FCols)
|
|
else
|
|
Result := FCols <> nil;
|
|
end;
|
|
|
|
function DoRowData: Boolean;
|
|
begin
|
|
if (Filer.Ancestor <> nil) and (Filer.Ancestor is TKCustomGrid) then
|
|
Result := not CompareAxisItems(TKCustomGrid(Filer.Ancestor).FRows, FRows)
|
|
else
|
|
Result := FRows <> nil;
|
|
end;
|
|
|
|
begin
|
|
inherited;
|
|
with Filer do
|
|
begin
|
|
DefineProperty('ColWidths', ReadColWidths, WriteColWidths, DoColData);
|
|
DefineProperty('RowHeights', ReadRowHeights, WriteRowHeights, DoRowData);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.DeleteCol(At: Integer);
|
|
begin
|
|
DeleteCols(At, 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DeleteCols(At, Count: Integer);
|
|
begin
|
|
if ColValid(At) and (FColCount > 1) then
|
|
begin
|
|
Count := Min(Count, FColCount - Max(At, 1));
|
|
ChangeDataSize(False, At, Count, False, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.DeleteRow(At: Integer);
|
|
begin
|
|
DeleteRows(At, 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.DeleteRows(At, Count: Integer);
|
|
begin
|
|
if RowValid(At) and (FRowCount > 1) then
|
|
begin
|
|
Count := Min(Count, FRowCount - Max(At, 1));
|
|
ChangeDataSize(False, 0, 0, False, At, Count);
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean;
|
|
var
|
|
Key: Word;
|
|
begin
|
|
Result := inherited DoMouseWheelDown(Shift, MousePos);
|
|
if not Result then
|
|
begin
|
|
Key := VK_DOWN;
|
|
KeyDown(Key, []);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
|
|
var
|
|
Key: Word;
|
|
begin
|
|
Result := inherited DoMouseWheelUp(Shift, MousePos);
|
|
if not Result then
|
|
begin
|
|
Key := VK_UP;
|
|
KeyDown(Key, []);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.DragMove(ACol, ARow: Integer; MousePt: TPoint);
|
|
begin
|
|
case FGridState of
|
|
gsColMoving: if CheckColDrag(FDragOrigin, ACol, MousePt) and (FDragDest <> ACol) then
|
|
begin
|
|
SuggestDrag(csHide);
|
|
FDragDest := ACol;
|
|
SuggestDrag(csShow);
|
|
end;
|
|
gsRowMoving: if CheckRowDrag(FDragOrigin, ARow, MousePt) and (FDragDest <> ARow) then
|
|
begin
|
|
SuggestDrag(csHide);
|
|
FDragDest := ARow;
|
|
SuggestDrag(csShow);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
|
|
AState: TKGridDrawState): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnDrawCell) then
|
|
FOnDrawCell(Self, ACol, ARow, ARect, AState)
|
|
else if Assigned(FCells) then with InternalGetCell(ACol, ARow) do
|
|
begin
|
|
ApplyDrawProperties;
|
|
DrawCell(ACol, ARow, ARect, AState)
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKCustomGrid.EditorCreate(ACol, ARow: Integer): TWinControl;
|
|
begin
|
|
Result := nil;
|
|
if Assigned(FOnEditorCreate) then
|
|
FOnEditorCreate(Self, ACol, ARow, Result)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorCreate(ACol, ARow, Result)
|
|
else
|
|
DefaultEditorCreate(ACol, ARow, Result);
|
|
end;
|
|
|
|
procedure TKCustomGrid.EditorDataFromGrid(AEditor: TWinControl; ACol, ARow: Integer);
|
|
var
|
|
AssignText: Boolean;
|
|
begin
|
|
AssignText := True;
|
|
if Assigned(FOnEditorDataFromGrid) then
|
|
FOnEditorDataFromGrid(Self, AEditor, ACol, ARow, AssignText)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorDataFromGrid(AEditor, ACol, ARow, AssignText)
|
|
else
|
|
DefaultEditorDataFromGrid(AEditor, ACol, ARow, AssignText);
|
|
if AssignText then
|
|
SetControlText(AEditor, Cells[ACol, ARow]);
|
|
end;
|
|
|
|
procedure TKCustomGrid.EditorDataToGrid(AEditor: TWinControl; ACol, ARow: Integer);
|
|
var
|
|
AssignText: Boolean;
|
|
begin
|
|
AssignText := True;
|
|
if Assigned(FOnEditorDataToGrid) then
|
|
FOnEditorDataToGrid(Self, AEditor, ACol, ARow, AssignText)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorDataToGrid(AEditor, ACol, ARow, AssignText)
|
|
else
|
|
DefaultEditorDataToGrid(AEditor, ACol, ARow, AssignText);
|
|
if AssignText then
|
|
Cells[ACol, ARow] := GetControlText(AEditor);
|
|
end;
|
|
|
|
procedure TKCustomGrid.EditorDestroy(var AEditor: TWinControl; ACol, ARow: Integer);
|
|
begin
|
|
if Assigned(FOnEditorDestroy) then
|
|
FOnEditorDestroy(Self, AEditor, ACol, ARow)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorDestroy(AEditor, ACol, ARow)
|
|
else
|
|
DefaultEditorDestroy(AEditor, ACol, ARow);
|
|
end;
|
|
|
|
function TKCustomGrid.EditorIsTransparent: Boolean;
|
|
begin
|
|
Result := False;
|
|
if FEditorTransparency = etTransparent then
|
|
Result := True
|
|
else if FEditorTransparency = etDefault then
|
|
begin
|
|
{ Default behavior. For example TCheckBox is not meant to be transparent
|
|
by VCL/LCL but from grid's point of view it should be. }
|
|
Result :=
|
|
(FEditor is TCustomCheckBox) or
|
|
(FEditor is TRadioButton) or
|
|
(FEditor is TStaticText);
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.EditorKeyPreview(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var Key: Word; Shift: TShiftState): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnEditorKeyPreview) then
|
|
FOnEditorKeyPreview(Self, AEditor, ACol, ARow, Key, Shift, Result)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorKeyPreview(AEditor, ACol, ARow, Key, Shift, Result)
|
|
else
|
|
DefaultEditorKeyPreview(AEditor, ACol, ARow, Key, Shift, Result);
|
|
end;
|
|
|
|
procedure TKCustomGrid.EditorResize(AEditor: TWinControl; ACol, ARow: Integer;
|
|
var ARect: TRect);
|
|
begin
|
|
if Assigned(FOnEditorResize) then
|
|
FOnEditorResize(Self, AEditor, ACol, ARow, ARect)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorResize(AEditor, ACol, ARow, ARect)
|
|
else
|
|
DefaultEditorResize(AEditor, ACol, ARow, ARect);
|
|
end;
|
|
|
|
procedure TKCustomGrid.EditorSelect(AEditor: TWinControl; ACol, ARow: Integer;
|
|
SelectAll, CaretToLeft, SelectedByMouse: Boolean);
|
|
begin
|
|
if Assigned(FOnEditorSelect) then
|
|
FOnEditorSelect(Self, AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).EditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse)
|
|
else
|
|
DefaultEditorSelect(AEditor, ACol, ARow, SelectAll, CaretToLeft, SelectedByMouse);
|
|
end;
|
|
|
|
procedure TKCustomGrid.EditorWindowProc(var Msg: TLMessage);
|
|
|
|
procedure PaintCellBackground(DC: HDC);
|
|
var
|
|
SaveIndex: Integer;
|
|
ACanvas: TCanvas;
|
|
R, TmpBlockRect: TRect;
|
|
begin
|
|
if CellRect(Col, Row, R) then
|
|
begin
|
|
ACanvas := TCanvas.Create;
|
|
SaveIndex := SaveDC(DC);
|
|
try
|
|
ACanvas.Handle := DC;
|
|
R := Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top);
|
|
TmpBlockRect := SelectionRect;
|
|
OffsetRect(TmpBlockRect, -R.Left, -R.Top);
|
|
InternalPaintCell(Col, Row, GetDrawState(Col, Row, HasFocus),
|
|
R, TmpBlockRect, ACanvas, False, False);
|
|
FEditor.Brush.Color := ACanvas.Brush.Color;
|
|
finally
|
|
RestoreDC(DC, SaveIndex);
|
|
ACanvas.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure GotFocus;
|
|
begin
|
|
InvalidateCurrentSelection;
|
|
end;
|
|
|
|
procedure LostFocus;
|
|
begin
|
|
InvalidateCurrentSelection;
|
|
end;
|
|
|
|
var
|
|
Key: Word;
|
|
Shift: TShiftState;
|
|
CallDefault: Boolean;
|
|
Form: TCustomForm;
|
|
begin
|
|
CallDefault := True;
|
|
case Msg.Msg of
|
|
CM_MOUSEENTER, CM_MOUSELEAVE: // not called if editor is captured
|
|
try
|
|
MouseOverCells; // some win32 error might popup here
|
|
except
|
|
end;
|
|
CN_CHAR:
|
|
ClampInView(FEditorCell.Col, FEditorCell.Row);
|
|
{$IFNDEF FPC}
|
|
CN_COMMAND:
|
|
if TWMCommand(Msg).Ctl = FEditor.Handle then
|
|
begin
|
|
case TWMCommand(Msg).NotifyCode of
|
|
CBN_KILLFOCUS, BN_KILLFOCUS, LBN_KILLFOCUS, EN_KILLFOCUS: LostFocus;
|
|
CBN_SETFOCUS, BN_SETFOCUS, EN_SETFOCUS: GotFocus;
|
|
end;
|
|
end;
|
|
{$ELSE}
|
|
LM_ERASEBKGND:
|
|
begin
|
|
if EditorIsTransparent then
|
|
begin
|
|
PaintCellBackground(TLMEraseBkGnd(Msg).DC);
|
|
CallDefault := False;
|
|
Msg.Result := 1;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
{ CN_KEYDOWN is sent from TApplication.IsKeyMsg as 'preview' so this message
|
|
is used as KeyPreview. WM_KEYDOWN is not sent here by all inplace editors as
|
|
some of them might have another child window with input focus
|
|
(in such cases WM_KEYDOWN is sent directly to it). But if it is sent here
|
|
so let's decide if it can be processed by inplace editor, either. }
|
|
CN_KEYDOWN, LM_KEYDOWN:
|
|
begin
|
|
Key := TLMKey(Msg).CharCode;
|
|
Shift := KeyDataToShiftState(TLMKey(Msg).KeyData);
|
|
case Key of
|
|
VK_RETURN, VK_ESCAPE, VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN,
|
|
VK_PRIOR, VK_NEXT, VK_HOME, VK_END, VK_TAB:
|
|
begin
|
|
if EditorKeyPreview(FEditor, FEditorCell.Col, FEditorCell.Row, Key, Shift) then
|
|
begin
|
|
DefaultSetCaretToLeft(Key, Shift);
|
|
if Msg.Msg = CN_KEYDOWN then
|
|
PostLateUpdate(Msg)
|
|
else
|
|
ClampInView(FEditorCell.Col, FEditorCell.Row);
|
|
if (Key <> VK_TAB) or (goTabs in FOptions) then
|
|
begin
|
|
CallDefault := False;
|
|
Msg.Result := 1;
|
|
end;
|
|
end;
|
|
end else
|
|
ClampInView(FEditorCell.Col, FEditorCell.Row);
|
|
end;
|
|
end;
|
|
LM_GETDLGCODE: if goTabs in FOptions then
|
|
Msg.Result := Msg.Result or DLGC_WANTTAB or DLGC_WANTARROWS;
|
|
LM_KILLFOCUS:
|
|
LostFocus;
|
|
LM_MOUSEMOVE:
|
|
begin
|
|
if Flag(cGF_ThroughClick) and (GetCaptureControl = FEditor) then
|
|
begin
|
|
if (FGridState = gsSelecting) and not PtInRect(FEditor.BoundsRect, ScreenToClient(Mouse.CursorPos)) then
|
|
begin
|
|
MouseCapture := True;
|
|
FlagClear(cGF_ThroughClick);
|
|
end;
|
|
MouseOverCells;
|
|
end;
|
|
end;
|
|
LM_LBUTTONUP:
|
|
begin
|
|
if Flag(cGF_ThroughClick) then
|
|
begin
|
|
FGridState := gsNormal;
|
|
FlagClear(cGF_ThroughClick);
|
|
end;
|
|
end;
|
|
LM_SETFOCUS:
|
|
begin
|
|
Form := GetParentForm(Self);
|
|
if Assigned(Form) and not (csDestroying in Form.ComponentState) then
|
|
GotFocus
|
|
else
|
|
CallDefault := False; // eat the message to avoid an exception in LCL (TForm.SetFocusedControl)
|
|
end;
|
|
end;
|
|
if CallDefault then
|
|
FEditorWindowProc(Msg);
|
|
end;
|
|
|
|
function TKCustomGrid.EndColDrag(Origin, Destination: Integer;
|
|
const MousePt: TPoint): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnEndColDrag) then
|
|
FOnEndColDrag(Self, Origin, Destination, MousePt, Result)
|
|
else if Assigned(FCols) then
|
|
FCols[Destination].EndDrag(Origin, Destination, MousePt, Result)
|
|
end;
|
|
|
|
function TKCustomGrid.EndColSizing(var Index, Pos: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnEndColSizing) then
|
|
FOnEndColSizing(Self, Index, Pos, Result);
|
|
Index := MinMax(Index, 0, FColCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.EndRowDrag(Origin, Destination: Integer;
|
|
const MousePt: TPoint): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnEndRowDrag) then
|
|
FOnEndRowDrag(Self, Origin, Destination, MousePt, Result)
|
|
else if Assigned(FRows) then
|
|
FRows[Destination].EndDrag(Origin, Destination, MousePt, Result)
|
|
end;
|
|
|
|
function TKCustomGrid.EndRowSizing(var Index, Pos: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnEndRowSizing) then
|
|
FOnEndRowSizing(Self, Index, Pos, Result);
|
|
Index := MinMax(Index, 0, FRowCount - 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.FindBaseCell(ACol, ARow: Integer; out BaseCol,
|
|
BaseRow: Integer);
|
|
begin
|
|
if ColValid(ACol) and RowValid(ARow) then
|
|
InternalFindBaseCell(ACol, ARow, BaseCol, BaseRow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.FocusCell(ACol, ARow: Integer);
|
|
begin
|
|
if ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
InternalFindBaseCell(ACol, ARow, ACol, ARow);
|
|
if SelectionMove(ACol, ARow, ssInit, [sfMustUpdate, sfClampInView]) then
|
|
Click;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.FreeData;
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
for I := 0 to FColCount - 1 do
|
|
FCols[I].Free;
|
|
FCols := nil;
|
|
for I := 0 to FRowCount - 1 do
|
|
FRows[I].Free;
|
|
FRows := nil;
|
|
for I := 0 to Length(FCells) - 1 do
|
|
for J := 0 to Length(FCells[I]) - 1 do
|
|
FCells[I, J].Free;
|
|
FCells := nil;
|
|
end;
|
|
|
|
function TKCustomGrid.GetAllCellsSelected: Boolean;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
Result := (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1) and
|
|
(R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.GetAllColsSelected: Boolean;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
Result := (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.GetAllRowsSelected: Boolean;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
Result := (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.GetAxisInfo(var Info: TKGridAxisInfo);
|
|
var
|
|
I, Extent: Integer;
|
|
begin
|
|
with Info do
|
|
begin
|
|
if InfoMask * [aiFixedParams, aiFullVisBoundary, aiGridBoundary, aiGridExtent] <> [] then
|
|
begin
|
|
FixedBoundary := 0;
|
|
I := 0;
|
|
while I < FixedCellCount do
|
|
begin
|
|
Inc(FixedBoundary, CellExtent(I) + EffectiveSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
if aiGridExtent in InfoMask then
|
|
begin
|
|
I := FixedCellCount;
|
|
GridExtent := FixedBoundary;
|
|
while I < TotalCellCount do
|
|
begin
|
|
Inc(GridExtent, Int64(CellExtent(I)) + EffectiveSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
if aiGridBoundary in InfoMask then
|
|
begin
|
|
GridCells := FirstGridCell;
|
|
GridBoundary := FixedBoundary - ScrollOffset;
|
|
while (GridCells < TotalCellCount) and (GridBoundary < ClientExtent) do
|
|
begin
|
|
Inc(GridBoundary, CellExtent(GridCells) + EffectiveSpacing(GridCells));
|
|
Inc(GridCells);
|
|
end;
|
|
GridBoundary := Min(GridBoundary, ClientExtent);
|
|
GridCells := Min(GridCells, TotalCellCount);
|
|
end;
|
|
if aiFullVisBoundary in InfoMask then
|
|
begin
|
|
FullVisCells := FirstGridCell;
|
|
FullVisBoundary := FixedBoundary - ScrollOffset;
|
|
while FullVisCells < TotalCellCount do
|
|
begin
|
|
Extent := CellExtent(FullVisCells) + EffectiveSpacing(FullVisCells);
|
|
if FullVisBoundary + Extent <= ClientExtent then
|
|
begin
|
|
Inc(FullVisBoundary, Extent);
|
|
Inc(FullVisCells);
|
|
end else
|
|
Break;
|
|
end;
|
|
FullVisCells := Min(FullVisCells, TotalCellCount);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetAxisInfoBoth(Mask: TKGridAxisInfoMask): TKGridAxisInfoBoth;
|
|
begin
|
|
Result.Horz := GetAxisInfoHorz(Mask);
|
|
Result.Vert := GetAxisInfoVert(Mask);
|
|
end;
|
|
|
|
function TKCustomGrid.GetAxisInfoHorz(Mask: TKGridAxisInfoMask): TKGridAxisInfo;
|
|
begin
|
|
with Result do
|
|
begin
|
|
AlignLastCell := goAlignLastCol in FOptions;
|
|
CanResize := BeginColSizing;
|
|
CellExtent := InternalGetColWidths;
|
|
EffectiveSpacing := InternalGetEffectiveColSpacing;
|
|
FixedCellCount := FFixedCols;
|
|
FixedSelectable := gxEditFixedCols in FOptionsEx;
|
|
FirstGridCell := FTopLeft.Col;
|
|
FirstGridCellExtent := FTopLeftExtent.Col;
|
|
if HandleAllocated then
|
|
ClientExtent := ClientWidth
|
|
else
|
|
// don't create Handle, fake ClientWidth instead
|
|
ClientExtent := Width;
|
|
MinCellExtent := InternalGetMinColWidth;
|
|
MaxCellExtent := InternalGetMaxColWidth;
|
|
TotalCellCount := FColCount;
|
|
ScrollOffset := FScrollOffset.X;
|
|
InfoMask := Mask;
|
|
end;
|
|
GetAxisInfo(Result);
|
|
end;
|
|
|
|
function TKCustomGrid.GetAxisInfoVert(Mask: TKGridAxisInfoMask): TKGridAxisInfo;
|
|
begin
|
|
with Result do
|
|
begin
|
|
AlignLastCell := goAlignLastRow in FOptions;
|
|
CanResize := BeginRowSizing;
|
|
CellExtent := InternalGetRowHeights;
|
|
EffectiveSpacing := InternalGetEffectiveRowSpacing;
|
|
FixedCellCount := FFixedRows;
|
|
FixedSelectable := gxEditFixedRows in FOptionsEx;
|
|
FirstGridCell := FTopLeft.Row;
|
|
FirstGridCellExtent := FTopLeftExtent.Row;
|
|
if HandleAllocated then
|
|
ClientExtent := ClientHeight
|
|
else
|
|
// don't create Handle, fake ClientWidth instead
|
|
ClientExtent := Height;
|
|
MinCellExtent := InternalGetMinRowHeight;
|
|
MaxCellExtent := InternalGetMaxRowHeight;
|
|
TotalCellCount := FRowCount;
|
|
ScrollOffset := FScrollOffset.Y;
|
|
InfoMask := Mask;
|
|
end;
|
|
GetAxisInfo(Result);
|
|
end;
|
|
|
|
function TKCustomGrid.GetCell(ACol, ARow: Integer): TKGridCell;
|
|
begin
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
Result := InternalGetCell(ACol, ARow)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TKCustomGrid.GetCells(ACol, ARow: Integer): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
|
|
var
|
|
Data: TKGridCell;
|
|
begin
|
|
Result := '';
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
Data := InternalGetCell(ACol, ARow);
|
|
if Data is TKGridTextCell then
|
|
Result := TKGridTextCell(Data).Text;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetCellSpan(ACol, ARow: Integer): TKGridCellSpan;
|
|
begin
|
|
if ColValid(ACol) and RowValid(ARow) then
|
|
Result := InternalGetCellSpan(ACol, ARow)
|
|
else
|
|
Result := MakeCellSpan(1, 1);
|
|
end;
|
|
|
|
function TKCustomGrid.GetCols(Index: Integer): TKGridCol;
|
|
begin
|
|
if ColValid(Index) and (FCols[Index] is TKGridCol) then
|
|
Result := TKGridCol(FCols[Index])
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TKCustomGrid.GetColWidths(Index: Integer): Integer;
|
|
begin
|
|
if ColValid(Index) then
|
|
Result := FCols[Index].Extent
|
|
else
|
|
Result := 0
|
|
end;
|
|
|
|
function TKCustomGrid.GetDefaultDrawing: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TKCustomGrid.GetDragRect(Info: TKGridAxisInfoBoth; out DragRect: TRect): Boolean;
|
|
var
|
|
W, H, ES: Integer;
|
|
P: TPoint;
|
|
begin
|
|
Result := False;
|
|
if FGridState = gsColMoving then
|
|
begin
|
|
if CellToPoint(FDragDest, 0, P) then
|
|
begin
|
|
if FDragDest > FDragOrigin then
|
|
begin
|
|
ES := Info.Horz.EffectiveSpacing(FDragDest);
|
|
Inc(P.X, Info.Horz.CellExtent(FDragDest));
|
|
end else
|
|
begin
|
|
if FDragDest > 0 then
|
|
ES := Info.Horz.EffectiveSpacing(FDragDest - 1)
|
|
else
|
|
ES := 0;
|
|
Dec(P.X, ES);
|
|
end;
|
|
case FDragStyle of
|
|
dsLayeredConst, dsLayeredFaded:
|
|
begin
|
|
W := FDragArrow.Width;
|
|
H := Min(Info.Vert.FixedBoundary, Info.Vert.ClientExtent);
|
|
end;
|
|
else
|
|
W := 5;
|
|
H := Info.Vert.GridBoundary;
|
|
end;
|
|
Dec(P.X, (W - ES) shr 1);
|
|
DragRect := Rect(P.X, 0, P.X + W, H);
|
|
Result := True;
|
|
end;
|
|
end else
|
|
begin
|
|
if CellToPoint(0, FDragDest, P) then
|
|
begin
|
|
if FDragDest >= FDragOrigin then
|
|
begin
|
|
ES := Info.Vert.EffectiveSpacing(FDragDest);
|
|
Inc(P.Y, Info.Vert.CellExtent(FDragDest));
|
|
end else
|
|
begin
|
|
if FDragDest > 0 then
|
|
ES := Info.Vert.EffectiveSpacing(FDragDest - 1)
|
|
else
|
|
ES := 0;
|
|
Dec(P.Y, ES);
|
|
end;
|
|
case FDragStyle of
|
|
dsLayeredConst, dsLayeredFaded:
|
|
begin
|
|
W := Min(Info.Horz.FixedBoundary, Info.Horz.ClientExtent);
|
|
H := FDragArrow.Height;
|
|
end;
|
|
else
|
|
W := Info.Horz.GridBoundary;
|
|
H := 5;
|
|
end;
|
|
Dec(P.Y, (H - ES) shr 1);
|
|
DragRect := Rect(0, P.Y, W, P.Y + H);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetDrawState(ACol, ARow: Integer; AFocused: Boolean): TKGridDrawState;
|
|
var
|
|
BaseCol, BaseRow: Integer;
|
|
begin
|
|
Result := [];
|
|
if ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
if (ACol < FFixedCols) or (ARow < FFixedRows) then
|
|
begin
|
|
Result := [gdFixed];
|
|
if (goRowSorting in FOptions) and (ARow = FCols[ACol].SortArrowIndex) then
|
|
if FCols[ACol].SortMode = smDown then
|
|
Include(Result, gdRowsSortedDown)
|
|
else if FCols[ACol].SortMode = smUp then
|
|
Include(Result, gdRowsSortedUp);
|
|
if (goColSorting in FOptions) and (ACol = FRows[ARow].SortArrowIndex) and
|
|
((ARow > 0) or not (goRowSorting in FOptions)) then
|
|
if (FRows[ARow].SortMode = smDown) then
|
|
Include(Result, gdColsSortedDown)
|
|
else if FRows[ARow].SortMode = smUp then
|
|
Include(Result, gdColsSortedUp);
|
|
//aki:
|
|
if (((gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows)) or
|
|
((gxEditFixedCols in FOptionsEx) and (ACol < FFixedCols))) and
|
|
CellSelected(ACol, ARow) then
|
|
begin
|
|
Include(Result, gdSelected);
|
|
if (ACol = FSelection.Col1) and (ARow = FSelection.Row1) then
|
|
begin
|
|
if EditorMode and (FEditor.Left >= 0) and (FEditor.Top >= 0) then
|
|
Include(Result, gdEdited)
|
|
else if AFocused then
|
|
Include(Result, gdFocused);
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
if CellSelected(ACol, ARow) then
|
|
begin
|
|
Result := [gdSelected];
|
|
if (ACol = FSelection.Col1) and (ARow = FSelection.Row1) then
|
|
begin
|
|
if EditorMode and (FEditor.Left >= 0) and (FEditor.Top >= 0) then
|
|
Include(Result, gdEdited)
|
|
else if AFocused then
|
|
Include(Result, gdFocused);
|
|
end;
|
|
end else
|
|
Result := [];
|
|
if (FCols[ACol].SortMode <> smNone) or (FRows[ARow].SortMode <> smNone) then
|
|
Include(Result, gdSorted);
|
|
end;
|
|
if (FGridState in [gsNormal, gsSelecting, gsColMoveWaiting, gsRowMoveWaiting,
|
|
gsColSortWaiting, gsRowSortWaiting]) and not (csDesigning in ComponentState) then
|
|
begin
|
|
InternalFindBaseCell(ACol, ARow, BaseCol, BaseRow);
|
|
if (ACol = FMouseOver.Col) and (ARow = FMouseOver.Row) then
|
|
begin
|
|
if MouseCapture and ColValid(FHitCell.Col) and RowValid(FHitCell.Row) then
|
|
begin
|
|
InternalFindBaseCell(FHitCell.Col, FHitCell.Row, BaseCol, BaseRow);
|
|
if (BaseCol = ACol) and (BaseRow = ARow) then
|
|
Include(Result, gdMouseDown);
|
|
end;
|
|
if goMouseOverCells in FOptions then
|
|
Include(Result, gdMouseOver);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetEditorMode: Boolean;
|
|
begin
|
|
Result := Assigned(FEditor);
|
|
end;
|
|
|
|
function TKCustomGrid.GetEffectiveColSpacing(ACol: Integer): Integer;
|
|
begin
|
|
if ColValid(ACol) then
|
|
Result := InternalGetEffectiveColSpacing(ACol)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.GetEffectiveRowSpacing(ARow: Integer): Integer;
|
|
begin
|
|
if RowValid(ARow) then
|
|
Result := InternalGetEffectiveRowSpacing(ARow)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.GetEntireColSelected(Index: Integer): Boolean;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
Result := (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1) and
|
|
(R.Col1 <= Index) and (Index <= R.Col2);
|
|
end;
|
|
|
|
function TKCustomGrid.GetEntireRowSelected(Index: Integer): Boolean;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
Result := (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1) and
|
|
(R.Row1 <= Index) and (Index <= R.Row2);
|
|
end;
|
|
|
|
function TKCustomGrid.GetEntireSelectedColCount: Integer;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
if (R.Row1 = FFixedRows) and (R.Row2 = FRowCount - 1) then
|
|
Result := R.Col2 - R.Col1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.GetEntireSelectedRowCount: Integer;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
if (R.Col1 = FFixedCols) and (R.Col2 = FColCount - 1) then
|
|
Result := R.Row2 - R.Row1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.GetGridHeight: Integer;
|
|
begin
|
|
Result := GetAxisInfoVert([aiGridBoundary]).GridBoundary;
|
|
end;
|
|
|
|
function TKCustomGrid.GetGridWidth: Integer;
|
|
begin
|
|
Result := GetAxisInfoHorz([aiGridBoundary]).GridBoundary;
|
|
end;
|
|
|
|
function TKCustomGrid.GetLastVisibleCol: Integer;
|
|
begin
|
|
Result := GetAxisInfoHorz([aiGridBoundary]).GridCells - 1;
|
|
end;
|
|
|
|
function TKCustomGrid.GetLastVisibleRow: Integer;
|
|
begin
|
|
Result := GetAxisInfoVert([aiGridBoundary]).GridCells - 1;
|
|
end;
|
|
|
|
function TKCustomGrid.GetMoreCellsSelected: Boolean;
|
|
begin
|
|
Result := (FSelection.Row1 <> FSelection.Row2) or
|
|
(FSelection.Col1 <> FSelection.Col2);
|
|
end;
|
|
|
|
function TKCustomGrid.GetObjects(ACol, ARow: Integer): TObject;
|
|
var
|
|
Data: TKGridCell;
|
|
begin
|
|
Result := nil;
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
Data := InternalGetCell(ACol, ARow);
|
|
if Data is TKGridObjectCell then
|
|
Result := TKGridObjectCell(Data).CellObject;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetRowHeights(Index: Integer): Integer;
|
|
begin
|
|
if RowValid(Index) then
|
|
Result := FRows[Index].Extent
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.GetRows(Index: Integer): TKGridRow;
|
|
begin
|
|
if RowValid(Index) and (FRows[Index] is TKGridRow) then
|
|
Result := TKGridRow(FRows[Index])
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetSelAvail: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TKCustomGrid.GetSelection: TKGridRect;
|
|
begin
|
|
Result := AdjustSelection(FSelection);
|
|
end;
|
|
|
|
function TKCustomGrid.GetSelectionCount: Integer;
|
|
begin
|
|
Result := Length(FSelections) + 1;
|
|
end;
|
|
|
|
function TKCustomGrid.GetSelectionRect: TRect;
|
|
begin
|
|
Result := Rect(0,0,0,0);
|
|
if GridRectToRect(Selection, Result, False, goRangeSelect in FOptions) then
|
|
begin
|
|
if FOptions * [goFixedHorzLine, goHorzLine] = [goFixedHorzLine, goHorzLine] then
|
|
Dec(Result.Bottom, GetEffectiveRowSpacing(Max(Selection.Row1, Selection.Row2)));
|
|
if FOptions * [goFixedVertLine, goVertLine] = [goFixedVertLine, goVertLine] then
|
|
Dec(Result.Right, GetEffectiveColSpacing(Max(Selection.Col1, Selection.Col2)));
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetSelections(Index: Integer): TKGridRect;
|
|
begin
|
|
if Index = 0 then
|
|
Result := Selection
|
|
else if (Index > 0) and (Index < SelectionCount) then
|
|
Result := FSelections[Index - 1]
|
|
else
|
|
Result := GridRect(0,0,0,0);
|
|
end;
|
|
|
|
function TKCustomGrid.GetSortCol: Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := cInvalidIndex;
|
|
for I := 0 to FColCount - 1 do
|
|
if FCols[I].SortMode <> smNone then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetSortRow: Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := cInvalidIndex;
|
|
for I := 0 to FRowCount - 1 do
|
|
if FRows[I].SortMode <> smNone then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GetTabStops(Index: Integer): Boolean;
|
|
begin
|
|
if ColValid(Index) and (FCols[Index] is TKGridCol) then
|
|
Result := TKGridCol(FCols[Index]).TabStop
|
|
else
|
|
Result := True
|
|
end;
|
|
|
|
function TKCustomGrid.GetThemedCells: Boolean;
|
|
begin
|
|
Result := Themes and (FOptions * [goThemes, goThemedCells] = [goThemes, goThemedCells]);
|
|
end;
|
|
|
|
function TKCustomGrid.GetThemes: Boolean;
|
|
begin
|
|
{$IFDEF USE_THEMES}
|
|
Result := ThemeServices.ThemesEnabled
|
|
{$ELSE}
|
|
Result := False;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TKCustomGrid.GetVisibleColCount: Integer;
|
|
begin
|
|
Result := LastVisibleCol;
|
|
end;
|
|
|
|
function TKCustomGrid.GetVisibleGridRect: TKGridRect;
|
|
begin
|
|
Result := GridRect(FTopLeft.Col, FTopLeft.Row, VisibleColCount, VisibleRowCount);
|
|
end;
|
|
|
|
function TKCustomGrid.GetVisibleRowCount: Integer;
|
|
begin
|
|
Result := LastVisibleRow;
|
|
end;
|
|
|
|
function TKCustomGrid.GridRectSelectable(const GridRect: TKGridRect): Boolean;
|
|
begin
|
|
Result := ColSelectable(GridRect.Col1) and ColSelectable(GridRect.Col2) and
|
|
RowSelectable(GridRect.Row1) and RowSelectable(GridRect.Row2);
|
|
end;
|
|
|
|
function TKCustomGrid.GridRectToRect(GridRect: TKGridRect; var R: TRect;
|
|
VisibleOnly: Boolean; Merged: Boolean): Boolean;
|
|
|
|
function Axis(const Info: TKGridAxisInfo; var Index1, Index2: Integer; Split: Boolean): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Split then
|
|
begin
|
|
// adjust indexes for either fixed or nonfixed area
|
|
if Index1 >= Info.FixedCellCount then
|
|
begin
|
|
if VisibleOnly then
|
|
if Index2 >= Info.FirstGridCell then
|
|
Index1 := Max(Index1, Info.FirstGridCell)
|
|
else
|
|
Result := False;
|
|
Index2 := Max(Index2, Index1);
|
|
end else
|
|
Index2 := Min(Index2, Info.FixedCellCount - 1);
|
|
end
|
|
else if (Index1 >= Info.FixedCellCount) and VisibleOnly then
|
|
begin
|
|
if Index2 >= Info.FirstGridCell then
|
|
Index1 := Max(Index1, Info.FirstGridCell)
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure Axis1(const Info: TKGridAxisInfo; Index1, Index2, AMin: Integer;
|
|
out AMax: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
AMax := AMin;
|
|
I := Index1;
|
|
if Info.CellExtent(I) = 0 then
|
|
begin
|
|
while (I >= 0) and (Info.CellExtent(I) = 0) do Dec(I);
|
|
Inc(I);
|
|
end;
|
|
while (I <= Index2) and (not VisibleOnly or (AMax < Info.ClientExtent)) do
|
|
begin
|
|
if not VisibleOnly or (I < Info.FixedCellCount) or (I >= Info.FirstGridCell) then
|
|
Inc(AMax, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
// if (Index1 < Info.FirstGridCell) and (I = Info.FirstGridCell) then
|
|
// Dec(AMax, Info.ScrollOffset);
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Info: TKGridAxisInfoBoth;
|
|
begin
|
|
Result := False;
|
|
NormalizeGridRect(GridRect);
|
|
if GridRectValid(GridRect) then
|
|
begin
|
|
Info := GetAxisInfoBoth([]);
|
|
if Merged then
|
|
GridRect := InternalExpandGridRect(GridRect);
|
|
// aki:
|
|
if Axis(Info.Horz, GridRect.Col1, GridRect.Col2, not (gxEditFixedCols in FOptionsEx)) and
|
|
Axis(Info.Vert, GridRect.Row1, GridRect.Row2, not (gxEditFixedRows in FOptionsEx)) then
|
|
begin
|
|
if CellToPoint(GridRect.Col1, GridRect.Row1, R.TopLeft, VisibleOnly) then
|
|
begin
|
|
Axis1(Info.Horz, GridRect.Col1, GridRect.Col2, R.Left, R.Right);
|
|
Axis1(Info.Vert, GridRect.Row1, GridRect.Row2, R.Top, R.Bottom);
|
|
Result := (R.Right > R.Left) and (R.Bottom > R.Top);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.GridRectValid(const GridRect: TKGridRect): Boolean;
|
|
begin
|
|
Result := ColValid(GridRect.Col1) and ColValid(GridRect.Col2) and
|
|
RowValid(GridRect.Row1) and RowValid(GridRect.Row2);
|
|
end;
|
|
|
|
function TKCustomGrid.GridStateToInvisibleCells: TKGridInvisibleCells;
|
|
begin
|
|
case FGridState of
|
|
gsColMoving: Result := icFixedCols;
|
|
gsRowMoving: Result := icFixedRows;
|
|
gsSelecting: Result := icCells;
|
|
else
|
|
Result := icNone;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.HasFocus: Boolean;
|
|
var
|
|
Form: TCustomForm;
|
|
begin
|
|
Form := GetParentForm(Self);
|
|
if (Form <> nil) and Form.Visible and Form.Enabled and Form.Active then
|
|
Result := (Form.ActiveControl = Self) or (FEditor <> nil) and (Form.ActiveControl = FEditor)
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TKCustomGrid.HasHorzScrollBar: Boolean;
|
|
begin
|
|
Result := (FScrollBars in [ssHorizontal, ssBoth]) and
|
|
not (goAlignLastCol in FOptions);
|
|
end;
|
|
|
|
function TKCustomGrid.HasVertScrollBar: Boolean;
|
|
begin
|
|
Result := (FScrollBars in [ssVertical, ssBoth]) and
|
|
not (goAlignLastRow in FOptions);
|
|
end;
|
|
|
|
procedure TKCustomGrid.HideCellHint;
|
|
begin
|
|
DefaultMouseCellHint(-1, -1, False);
|
|
end;
|
|
|
|
function TKCustomGrid.InitialCol(ACol: Integer): Integer;
|
|
var
|
|
Item: TKGridAxisItem;
|
|
begin
|
|
Item := FCols[ACol];
|
|
if Item <> nil then
|
|
Result := Item.InitialPos
|
|
else
|
|
Result := ACol;
|
|
end;
|
|
|
|
function TKCustomGrid.InitialColInv(ACol: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
Item: TKGridAxisItem;
|
|
begin
|
|
Result := ACol;
|
|
for I := 0 to FColCount - 1 do
|
|
begin
|
|
Item := FCols[I];
|
|
if (Item <> nil) and (Item.InitialPos = ACol) then
|
|
begin
|
|
Result := I;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.InitialRow(ARow: Integer): Integer;
|
|
var
|
|
Item: TKGridAxisItem;
|
|
begin
|
|
Item := FRows[ARow];
|
|
if Item <> nil then
|
|
Result := Item.InitialPos
|
|
else
|
|
Result := ARow;
|
|
end;
|
|
|
|
function TKCustomGrid.InitialRowInv(ARow: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
Item: TKGridAxisItem;
|
|
begin
|
|
Result := ARow;
|
|
for I := 0 to FRowCount - 1 do
|
|
begin
|
|
Item := FRows[I];
|
|
if (Item <> nil) and (Item.InitialPos = ARow) then
|
|
begin
|
|
Result := I;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InsertCol(At: Integer);
|
|
begin
|
|
InsertCols(At, 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InsertCols(At, Count: Integer);
|
|
begin
|
|
if not ColValid(At) then At := FColCount;
|
|
ChangeDataSize(True, At, Count, False, 0, 0);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InsertRow(At: Integer);
|
|
begin
|
|
InsertRows(At, 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InsertRows(At, Count: Integer);
|
|
begin
|
|
if not RowValid(At) then At := FRowCount;
|
|
ChangeDataSize(False, 0, 0, True, At, Count);
|
|
end;
|
|
|
|
function TKCustomGrid.InsertSortedCol(out ByRow, ACol: Integer): Boolean;
|
|
begin
|
|
ByRow := SortRow;
|
|
if ByRow >= 0 then
|
|
begin
|
|
ACol := InternalInsertNR(ByRow, FFixedCols, FColCount - 1, FRows[ByRow].SortMode = smUp,
|
|
CompareCols);
|
|
if ACol >= FFixedCols then
|
|
begin
|
|
LockSortMode;
|
|
try
|
|
InsertCol(ACol);
|
|
finally
|
|
UnlockSortMode;
|
|
end;
|
|
end;
|
|
end;
|
|
Result := (ByRow >= 0) and (ACol >= FFixedCols);
|
|
end;
|
|
|
|
function TKCustomGrid.InsertSortedRow(out ByCol, ARow: Integer): Boolean;
|
|
begin
|
|
ByCol := SortCol;
|
|
if ByCol >= 0 then
|
|
begin
|
|
ARow := InternalInsertNR(ByCol, FFixedRows, FRowCount - 1, FCols[ByCol].SortMode = smUp,
|
|
CompareRows);
|
|
if ARow >= FFixedRows then
|
|
begin
|
|
LockSortMode;
|
|
try
|
|
InsertRow(ARow);
|
|
finally
|
|
UnlockSortMode;
|
|
end;
|
|
end;
|
|
end;
|
|
Result := (ByCol >= 0) and (ARow >= FFixedRows);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalExchangeCols(Index1, Index2: Integer);
|
|
var
|
|
I: Integer;
|
|
AxisItem: TKGridAxisItem;
|
|
CellPtr: TKGridCell;
|
|
begin
|
|
AxisItem := FCols[Index1];
|
|
FCols[Index1] := FCols[Index2];
|
|
FCols[Index2] := AxisItem;
|
|
if Assigned(FCells) then
|
|
begin
|
|
for I := 0 to FRowCount - 1 do
|
|
begin
|
|
CellPtr := FCells[I, Index1];
|
|
FCells[I, Index1] := FCells[I, Index2];
|
|
FCells[I, Index2] := CellPtr;
|
|
end;
|
|
end;
|
|
if Assigned(FOnExchangeCols) then
|
|
FOnExchangeCols(Self, Index1, Index2);
|
|
if FSelection.Col1 = Index1 then
|
|
FSelection.Col1 := Index2
|
|
else if FSelection.Col1 = Index2 then
|
|
FSelection.Col1 := Index1;
|
|
FSelection.Col2 := FSelection.Col1;
|
|
FEditorCell.Col := FSelection.Col1;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalExchangeRows(Index1, Index2: Integer);
|
|
var
|
|
AxisItem: TKGridAxisItem;
|
|
CellPtr: TKGridCellRow;
|
|
begin
|
|
AxisItem := FRows[Index1];
|
|
FRows[Index1] := FRows[Index2];
|
|
FRows[Index2] := AxisItem;
|
|
if Assigned(FCells) then
|
|
begin
|
|
CellPtr := FCells[Index1];
|
|
FCells[Index1] := FCells[Index2];
|
|
FCells[Index2] := CellPtr;
|
|
end else
|
|
CellPtr := nil;
|
|
if Assigned(FOnExchangeRows) then
|
|
FOnExchangeRows(Self, Index1, Index2);
|
|
if FSelection.Row1 = Index1 then
|
|
FSelection.Row1 := Index2
|
|
else if FSelection.Row1 = Index2 then
|
|
FSelection.Row1 := Index1;
|
|
FSelection.Row2 := FSelection.Row1;
|
|
FEditorCell.Row := FSelection.Row1;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalExpandGridRect(const GridRect: TKGridRect): TKGridRect;
|
|
var
|
|
I, J, MyCol, MyRow: Integer;
|
|
Span: TKGridCellSpan;
|
|
begin
|
|
Result := GridRect;
|
|
for I := GridRect.Col1 to GridRect.Col2 do
|
|
for J := GridRect.Row1 to GridRect.Row2 do
|
|
begin
|
|
InternalFindBaseCell(I, J, MyCol, MyRow);
|
|
Span := InternalGetCellSpan(MyCol, MyRow);
|
|
Result.Col1 := Min(Result.Col1, MyCol);
|
|
Result.Col2 := Max(Result.Col2, MyCol + Span.ColSpan - 1);
|
|
Result.Row1 := Min(Result.Row1, MyRow);
|
|
Result.Row2 := Max(Result.Row2, MyRow + Span.RowSpan - 1);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalFindBaseCell(ACol, ARow: Integer; out BaseCol, BaseRow: Integer);
|
|
begin
|
|
BaseCol := ACol;
|
|
BaseRow := ARow;
|
|
with InternalGetCellSpan(ACol, ARow) do
|
|
if (ColSpan <= 0) and (RowSpan <= 0) then
|
|
begin
|
|
BaseCol := ACol + ColSpan;
|
|
BaseRow := ARow + RowSpan;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalFlip(Left, Right: Integer;
|
|
Exchange: TKGridExchangeProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to (Right - Left) div 2 do
|
|
Exchange(Left + I, Right - I);
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetCell(ACol, ARow: Integer): TKGridCell;
|
|
begin
|
|
if FCells[ARow, ACol] = nil then
|
|
FCells[ARow, ACol] := FCellClass.Create(Self);
|
|
Result := FCells[ARow, ACol];
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetCellSpan(ACol, ARow: Integer): TKGridCellSpan;
|
|
begin
|
|
Result := MakeCellSpan(1, 1);
|
|
if Assigned(FOnCellSpan) then
|
|
FOnCellSpan(Self, ACol, ARow, Result)
|
|
else if Assigned(FCells) then with InternalGetCell(ACol, ARow) do
|
|
Result := Span;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetColWidths(Index: Integer): Integer;
|
|
begin
|
|
Result := FCols[Index].Extent
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetEffectiveColSpacing(ACol: Integer): Integer;
|
|
begin
|
|
if FCols[ACol].Extent = 0 then
|
|
begin
|
|
if (goIndicateHiddenCells in FOptions) and ((ACol = 0) or (FCols[ACol - 1].Extent <> 0)) then
|
|
Result := FHCI.VBegin.Width
|
|
else
|
|
Result := 0;
|
|
end
|
|
else if FOptions * [goFixedVertLine, goVertLine] <> [] then
|
|
begin
|
|
if (ACol = FColCount - 1) and (goAlignLastCol in FOptions) then
|
|
Result := 0
|
|
else
|
|
Result := FGridLineWidth
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetEffectiveRowSpacing(ARow: Integer): Integer;
|
|
begin
|
|
if FRows[ARow].Extent = 0 then
|
|
begin
|
|
if (goIndicateHiddenCells in FOptions) and ((ARow = 0) or (FRows[ARow - 1].Extent <> 0)) then
|
|
Result := FHCI.HBegin.Height
|
|
else
|
|
Result := 0;
|
|
end
|
|
else if FOptions * [goFixedHorzLine, goHorzLine] <> [] then
|
|
begin
|
|
if (ARow = FRowCount - 1) and (goAlignLastRow in FOptions) or
|
|
ThemedCells and (ARow < FFixedRows) and (goHeader in FOptions) then
|
|
Result := 0
|
|
else
|
|
Result := FGridLineWidth
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalGetHExtent(AIndex, AColSpan: Integer;
|
|
out DestExtent, DestSpacing: Integer);
|
|
var
|
|
I, J, K, L, Spacing: Integer;
|
|
begin
|
|
DestExtent := InternalGetColWidths(AIndex);
|
|
Spacing := InternalGetEffectiveColSpacing(AIndex);
|
|
DestSpacing := Spacing;
|
|
if AColSpan > 1 then
|
|
begin
|
|
// cell is merged across columns
|
|
if DestExtent > 0 then J := DestSpacing else J := 0;
|
|
for I := AIndex + 1 to AIndex + AColSpan - 1 do
|
|
begin
|
|
K := InternalGetColWidths(I);
|
|
L := InternalGetEffectiveColSpacing(I);
|
|
if K > 0 then
|
|
J := L;
|
|
Inc(DestExtent, K);
|
|
Inc(DestSpacing, L);
|
|
end;
|
|
if DestExtent > 0 then
|
|
begin
|
|
Inc(DestExtent, DestSpacing - J);
|
|
DestSpacing := J;
|
|
end else
|
|
DestSpacing := Spacing;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalGetVExtent(AIndex, ARowSpan: Integer;
|
|
out DestExtent, DestSpacing: Integer);
|
|
var
|
|
I, J, K, L, Spacing: Integer;
|
|
begin
|
|
DestExtent := InternalGetRowHeights(AIndex);
|
|
Spacing := InternalGetEffectiveRowSpacing(AIndex);
|
|
DestSpacing := Spacing;
|
|
if ARowSpan > 1 then
|
|
begin
|
|
// cell is merged across rows
|
|
if DestExtent > 0 then J := DestSpacing else J := 0;
|
|
for I := AIndex + 1 to AIndex + ARowSpan - 1 do
|
|
begin
|
|
K := InternalGetRowHeights(I);
|
|
L := InternalGetEffectiveRowSpacing(I);
|
|
if K > 0 then
|
|
J := L;
|
|
Inc(DestExtent, K);
|
|
Inc(DestSpacing, L);
|
|
end;
|
|
if DestExtent > 0 then
|
|
begin
|
|
Inc(DestExtent, DestSpacing - J);
|
|
DestSpacing := J;
|
|
end else
|
|
DestSpacing := Spacing;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetMaxColWidth(Index: Integer): Integer;
|
|
begin
|
|
if (FCols[Index].MaxExtent > 0) and not (goAlignLastCol in FOptions) then
|
|
Result := FCols[Index].MaxExtent
|
|
else
|
|
Result := MaxInt;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetMaxRowHeight(Index: Integer): Integer;
|
|
begin
|
|
if (FRows[Index].MaxExtent > 0) and not (goAlignLastRow in FOptions) then
|
|
Result := FRows[Index].MaxExtent
|
|
else
|
|
Result := MaxInt;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetMinColWidth(Index: Integer): Integer;
|
|
begin
|
|
if FCols[Index].MinExtent > 0 then
|
|
Result := FCols[Index].MinExtent
|
|
else
|
|
Result := FMinColWidth;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetMinRowHeight(Index: Integer): Integer;
|
|
begin
|
|
if FRows[Index].MinExtent > 0 then
|
|
Result := FRows[Index].MinExtent
|
|
else
|
|
Result := FMinRowHeight;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalGetRowHeights(Index: Integer): Integer;
|
|
begin
|
|
Result := FRows[Index].Extent;
|
|
if (Result > 0) and (Index < FFixedRows) and (goHeader in FOptions) and ThemedCells
|
|
and (FOptions * [goFixedHorzLine, goHorzLine] <> []) then
|
|
Inc(Result, FGridLineWidth);
|
|
end;
|
|
|
|
function TKCustomGrid.InternalInsertNR(ByIndex, Left, Right: Integer;
|
|
SortedUp: Boolean; Compare: TKGridCompareProc): Integer;
|
|
var
|
|
Key, Mult: Integer;
|
|
begin
|
|
if SortedUp then Mult := -1 else Mult := 1;
|
|
repeat
|
|
Key := (Left + Right) div 2;
|
|
if Compare(ByIndex, cInvalidIndex, Key) * Mult < 0 then
|
|
Right := Key - 1
|
|
else
|
|
Left := Key + 1;
|
|
until Left > Right;
|
|
Result := Left;
|
|
end;
|
|
|
|
function TKCustomGrid.InternalInsertIfCellModifiedNR(ByIndex, Index, Left, Right: Integer;
|
|
SortedUp: Boolean; Compare: TKGridCompareProc): Integer;
|
|
var
|
|
Key, Mult, TmpLeft, TmpRight: Integer;
|
|
begin
|
|
Result := Index;
|
|
if SortedUp then Mult := 1 else Mult := -1;
|
|
if Left < Index then
|
|
begin
|
|
TmpLeft := Left;
|
|
TmpRight := Index - 1;
|
|
repeat
|
|
Key := (TmpLeft + TmpRight) div 2;
|
|
if Compare(ByIndex, Key, Index) * Mult < 0 then
|
|
TmpRight := Key - 1
|
|
else
|
|
TmpLeft := Key + 1;
|
|
until TmpLeft > TmpRight;
|
|
if TmpLeft < Index then
|
|
begin
|
|
Result := TmpLeft;
|
|
Exit;
|
|
end;
|
|
end;
|
|
if Index < Right then
|
|
begin
|
|
TmpLeft := Index + 1;
|
|
TmpRight := Right;
|
|
repeat
|
|
Key := (TmpLeft + TmpRight) div 2;
|
|
if Compare(ByIndex, Key, Index) * Mult < 0 then
|
|
TmpRight := Key - 1
|
|
else
|
|
TmpLeft := Key + 1;
|
|
until TmpLeft > TmpRight;
|
|
Result := TmpRight;
|
|
end;
|
|
Result := MinMax(Result, Left, Right);
|
|
end;
|
|
|
|
function TKCustomGrid.InternalMove(var ACol, ARow: Integer; Command: TKGridMoveCommand; Wrap, Expanding: Boolean): Boolean;
|
|
var
|
|
BaseCol, BaseRow, BkCol, BkRow, BkBaseCol, BkBaseRow: Integer;
|
|
BkCommand: TKGridMoveCommand;
|
|
begin
|
|
BkCol := ACol;
|
|
BkRow := ARow;
|
|
BkCommand := mcNone;
|
|
InternalFindBaseCell(ACol, ARow, BkBaseCol, BkBaseRow);
|
|
repeat
|
|
case Command of
|
|
mcDown:
|
|
begin
|
|
Inc(ARow);
|
|
if ARow < FRowCount then
|
|
begin
|
|
if FMemCol >= 0 then
|
|
ACol := FMemCol;
|
|
FMemRow := ARow;
|
|
end
|
|
else if Wrap then
|
|
begin
|
|
ARow := FFixedRows;
|
|
Inc(ACol);
|
|
if ACol >= FColCount then
|
|
begin
|
|
// aki:
|
|
if (gxEditFixedCols in FOptionsEx) or ((gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows)) then
|
|
ACol := 0
|
|
else
|
|
ACol := FFixedCols;
|
|
end;
|
|
FMemCol := ACol;
|
|
end
|
|
else if BkCommand <> mcNone then
|
|
begin
|
|
Dec(ARow);
|
|
Command := BkCommand;
|
|
BkCommand := mcNone;
|
|
end else
|
|
ARow := BkRow;
|
|
end;
|
|
mcEnd:
|
|
begin
|
|
ACol := FColCount - 1;
|
|
FMemCol := ACol;
|
|
if FMemRow >= 0 then
|
|
ARow := FMemRow;
|
|
Command := mcLeft;
|
|
end;
|
|
mcHome:
|
|
begin
|
|
// aki:
|
|
if (gxEditFixedCols in FOptionsEx) or ((gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows)) then
|
|
ACol := 0
|
|
else
|
|
ACol := FFixedCols;
|
|
FMemCol := ACol;
|
|
if FMemRow >= 0 then
|
|
ARow := FMemRow;
|
|
Command := mcRight;
|
|
end;
|
|
mcLeft:
|
|
begin
|
|
Dec(ACol);
|
|
// aki:
|
|
if (gxEditFixedCols in FOptionsEx) or ((gxEditFixedRows in FOptionsEx) and (ARow<FFixedRows)) then
|
|
begin
|
|
if ACol >= 0 then
|
|
begin
|
|
if FMemRow >= 0 then
|
|
ARow := FMemRow;
|
|
FMemCol := ACol;
|
|
end
|
|
else
|
|
if Wrap then
|
|
begin
|
|
ACol := FColCount - 1;
|
|
Dec(ARow);
|
|
if ARow < 0 then ARow := FRowCount - 1;
|
|
FMemRow := ARow;
|
|
end
|
|
else if BkCommand <> mcNone then
|
|
begin
|
|
Inc(ACol);
|
|
Command := BkCommand;
|
|
BkCommand := mcNone;
|
|
end else
|
|
ACol := BkCol;
|
|
end else
|
|
begin
|
|
if ACol >= FFixedCols then
|
|
begin
|
|
if FMemRow >= 0 then
|
|
ARow := FMemRow;
|
|
FMemCol := ACol;
|
|
end
|
|
else if Wrap then
|
|
begin
|
|
ACol := FColCount - 1;
|
|
Dec(ARow);
|
|
if ARow < FFixedRows then ARow := FRowCount - 1;
|
|
FMemRow := ARow;
|
|
end
|
|
else if BkCommand <> mcNone then
|
|
begin
|
|
Inc(ACol);
|
|
Command := BkCommand;
|
|
BkCommand := mcNone;
|
|
end else
|
|
ACol := BkCol;
|
|
end;
|
|
end;
|
|
mcMoveUp:
|
|
begin
|
|
// aki:
|
|
if ((gxEditFixedRows in FOptionsEx) or (ARow > FFixedRows)) and (FMemCol >= 0) then
|
|
ACol := FMemCol;
|
|
ARow := FTopLeft.Row;
|
|
Command := mcUp;
|
|
BkCommand := mcDown;
|
|
end;
|
|
mcMoveDown:
|
|
begin
|
|
if (ARow < FRowCount - 1) and (FMemCol >= 0) then
|
|
ACol := FMemCol;
|
|
ARow := FTopLeft.Row + PageHeight - 1;
|
|
Command := mcDown;
|
|
BkCommand := mcUp;
|
|
end;
|
|
mcRight:
|
|
begin
|
|
Inc(ACol);
|
|
if ACol < FColCount then
|
|
begin
|
|
if FMemRow >= 0 then
|
|
ARow := FMemRow;
|
|
FMemCol := ACol;
|
|
end
|
|
else if Wrap then
|
|
begin
|
|
ACol := FFixedCols;
|
|
Inc(ARow);
|
|
if ARow >= FRowCount then ARow := FFixedRows;
|
|
FMemRow := ARow;
|
|
end
|
|
else if BkCommand <> mcNone then
|
|
begin
|
|
Dec(ACol);
|
|
Command := BkCommand;
|
|
BkCommand := mcNone;
|
|
end else
|
|
ACol := BkCol;
|
|
end;
|
|
mcUp:
|
|
begin
|
|
Dec(ARow);
|
|
// aki:
|
|
if (ARow >= FFixedRows) or ((gxEditFixedRows in FOptionsEx) and (ARow >= 0)) then
|
|
begin
|
|
if FMemCol >= 0 then
|
|
ACol := FMemCol;
|
|
FMemRow := ARow;
|
|
end
|
|
else if Wrap then
|
|
begin
|
|
ARow := FRowCount - 1;
|
|
Dec(ACol);
|
|
if ACol < FFixedCols then ACol := FColCount - 1;
|
|
FMemCol := ACol;
|
|
end
|
|
else if BkCommand <> mcNone then
|
|
begin
|
|
Inc(ARow);
|
|
Command := BkCommand;
|
|
BkCommand := mcNone;
|
|
end else
|
|
ARow := BkRow;
|
|
end;
|
|
mcPageDown:
|
|
begin
|
|
if (ARow < FRowCount - 1) and (FMemCol >= 0) then
|
|
ACol := FMemCol;
|
|
ARow := Min(ARow + PageHeight, FRowCount - 1);
|
|
Command := mcDown;
|
|
BkCommand := mcUp;
|
|
FMemRow := ARow;
|
|
end;
|
|
mcPageLeft:
|
|
begin
|
|
if (ARow > FFixedCols) and (FMemRow >= 0) then
|
|
ARow := FMemRow;
|
|
ACol := Max(ACol - PageWidth, FFixedCols);
|
|
Command := mcLeft;
|
|
BkCommand := mcRight;
|
|
FMemCol := ACol;
|
|
end;
|
|
mcPageRight:
|
|
begin
|
|
if (ARow < FColCount - 1) and (FMemRow >= 0) then
|
|
ARow := FMemRow;
|
|
ACol := Min(ACol + PageWidth, FColCount - 1);
|
|
Command := mcRight;
|
|
BkCommand := mcLeft;
|
|
FMemCol := ACol;
|
|
end;
|
|
mcPageUp:
|
|
begin
|
|
if (ARow > FFixedRows) and (FMemCol >= 0) then
|
|
ACol := FMemCol;
|
|
ARow := Max(ARow - PageHeight, FFixedRows);
|
|
Command := mcUp;
|
|
BkCommand := mcDown;
|
|
FMemRow := ARow;
|
|
end;
|
|
mcTop:
|
|
begin
|
|
ACol := FFixedCols;
|
|
ARow := FFixedRows;
|
|
FMemCol := ACol;
|
|
FMemRow := ARow;
|
|
Command := mcRight;
|
|
Wrap := True;
|
|
end;
|
|
mcBottom:
|
|
begin
|
|
ACol := FColCount - 1;
|
|
ARow := FRowCount - 1;
|
|
FMemCol := ACol;
|
|
FMemRow := ARow;
|
|
Command := mcLeft;
|
|
Wrap := True;
|
|
end;
|
|
end;
|
|
InternalFindBaseCell(ACol, ARow, BaseCol, BaseRow);
|
|
until (ACol = BkCol) and (ARow = BkRow) or ((BaseCol <> BkBaseCol) or (BaseRow <> BkBaseRow)) and
|
|
(not Expanding and SelectCell(BaseCol, BaseRow) or Expanding and SelectionExpand(BaseCol, BaseRow));
|
|
Result := (ACol <> BkCol) or (ARow <> BkRow);
|
|
ACol := BaseCol;
|
|
ARow := BaseRow;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalPaintCell(ACol, ARow: Integer; AState: TKGridDrawState;
|
|
const ARect, ABlockRect: TRect; ACanvas: TCanvas; Clip, Printing: Boolean);
|
|
begin
|
|
FCellPainter.Col := ACol;
|
|
FCellPainter.Row := ARow;
|
|
FCellPainter.State := AState;
|
|
FCellPainter.CellPos := ARect.TopLeft;
|
|
FCellPainter.Canvas := ACanvas;
|
|
FCellPainter.CellRect := ARect;
|
|
FCellPainter.BlockRect := ABlockRect;
|
|
FCellPainter.FPrinting := Printing;
|
|
// prepare cell painter and draw cell
|
|
FCellPainter.BeginDraw;
|
|
try
|
|
if Clip or Printing then
|
|
FCellPainter.BeginClip;
|
|
try
|
|
// FCellPainter.Canvas.TextRect(ARect, ARect.Left, ARect.Top, 'debugtest');
|
|
if not DrawCell(FCellPainter.Col, FCellPainter.Row, FCellPainter.CellRect, FCellPainter.State) then
|
|
FCellPainter.DrawEmptyCell; // stub function
|
|
finally
|
|
FCellPainter.EndClip;
|
|
end;
|
|
finally
|
|
FCellPainter.EndDraw;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalQuickSortNR(ByIndex, Left, Right: Integer;
|
|
SortedDown: Boolean; Compare: TKGridCompareProc; Exchange: TKGridExchangeProc);
|
|
type
|
|
TStackItem = record
|
|
LIndex, RIndex: Integer;
|
|
end;
|
|
const
|
|
cStackGrow = 100;
|
|
var
|
|
Key, L, R, LBack, RBack, StackLen, StackPtr: Integer;
|
|
Stack: array of TStackItem;
|
|
begin
|
|
{ this is the non recursive quick sort algorithm to avoid stack overflows.
|
|
Right parts of divided arrays are stored into a stack-like array
|
|
in dynamic memory for later use. }
|
|
SetLength(Stack, cStackGrow);
|
|
StackPtr := 0;
|
|
with Stack[StackPtr] do begin LIndex := Left; RIndex := Right end;
|
|
repeat
|
|
with Stack[StackPtr] do begin Left := LIndex; Right := RIndex end;
|
|
Dec(StackPtr);
|
|
repeat
|
|
L := Left;
|
|
R := Right;
|
|
Key := (L + R) div 2;
|
|
LBack := Left - 1;
|
|
RBack := Right;
|
|
repeat
|
|
if SortedDown then
|
|
begin
|
|
while (L < Right) and (Compare(ByIndex, L, Key) < 0) do Inc(L);
|
|
while (R > Left) and (Compare(ByIndex, R, Key) > 0) do Dec(R);
|
|
end else
|
|
begin
|
|
while (L < Right) and (Compare(ByIndex, L, Key) > 0) do Inc(L);
|
|
while (R > Left) and (Compare(ByIndex, R, Key) < 0) do Dec(R);
|
|
end;
|
|
if L <= R then
|
|
begin
|
|
if L < R then
|
|
if (L = Key) or (R = Key) then
|
|
begin
|
|
// preserve Key, exchange later
|
|
LBack := L;
|
|
RBack := R;
|
|
end else
|
|
Exchange(L, R);
|
|
Dec(R);
|
|
Inc(L);
|
|
end;
|
|
until L >= R;
|
|
// exchange anything with former Key
|
|
if LBack >= Left then
|
|
Exchange(LBack, RBack);
|
|
if L < Right then
|
|
begin
|
|
Inc(StackPtr);
|
|
StackLen := Length(Stack);
|
|
if StackPtr >= StackLen then
|
|
SetLength(Stack, StackLen + cStackGrow);
|
|
with Stack[StackPtr] do begin LIndex := L; RIndex := Right end;
|
|
end;
|
|
Right := R;
|
|
until Left >= Right;
|
|
until StackPtr < 0;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalSetCell(ACol, ARow: Integer; Value: TKGridCell);
|
|
var
|
|
TmpClass: TClass;
|
|
TmpCell: TKGridCell;
|
|
Span: TKGridCellSpan;
|
|
begin
|
|
if FCells[ARow, ACol] <> nil then
|
|
Span := FCells[ARow, ACol].Span
|
|
else
|
|
Span := MakeCellSpan(1, 1);
|
|
FreeAndNil(FCells[ARow, ACol]);
|
|
if Value <> nil then
|
|
begin
|
|
TmpClass := Value.ClassType;
|
|
TmpCell := TKGridCellClass(TmpClass).Create(Self);
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
TmpCell.Assign(Value);
|
|
TmpCell.Span := Span;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
FCells[ARow, ACol] := TmpCell;
|
|
end;
|
|
InvalidateCell(ACol, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalSetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
var
|
|
Cell, Tmp: TKGridCell;
|
|
begin
|
|
Cell := InternalGetCell(ACol, ARow);
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
if not (Cell is TKGridTextCell) then
|
|
begin
|
|
if FCellClass.InheritsFrom(TKGridTextCell) then
|
|
Tmp := FCellClass.Create(Self)
|
|
else
|
|
Tmp := TKGridTextCell.Create(Self);
|
|
Tmp.Assign(Cell);
|
|
Cell.Free;
|
|
FCells[ARow, ACol] := Tmp;
|
|
end;
|
|
TKGridTextCell(FCells[ARow, ACol]).Text := Text;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
InvalidateCell(ACol, ARow);
|
|
end;
|
|
|
|
function TKCustomGrid.InternalSetCellSpan(ACol, ARow: Integer;
|
|
const Value: TKGridCellSpan): TKGridRect;
|
|
|
|
procedure Merge(ACol1, ARow1, ACol2, ARow2: Integer);
|
|
var
|
|
I, J: Integer;
|
|
Cell: TKGridCell;
|
|
begin
|
|
for I := ACol1 to ACol2 - 1 do
|
|
for J := ARow1 to ARow2 - 1 do
|
|
begin
|
|
Cell := InternalGetCell(I, J);
|
|
if (I = ACol1) and (J = ARow1) then
|
|
Cell.Span := MakeCellSpan(ACol2 - ACol1, ARow2 - ARow1)
|
|
else
|
|
Cell.Span := MakeCellSpan(ACol1 - I, ARow1 - J);
|
|
end;
|
|
end;
|
|
|
|
procedure Split(ACol1, ARow1, ACol2, ARow2: Integer);
|
|
var
|
|
I, J: Integer;
|
|
RefSpan: TKGridCellSpan;
|
|
begin
|
|
RefSpan := MakeCellSpan(1, 1);
|
|
for I := ACol1 to ACol2 - 1 do
|
|
for J := ARow1 to ARow2 - 1 do
|
|
InternalGetCell(I, J).Span := RefSpan;
|
|
end;
|
|
|
|
var
|
|
I, J, BaseCol, BaseRow: Integer;
|
|
Span: TKGridCellSpan;
|
|
Cell: TKGridCell;
|
|
begin
|
|
Result := GridRect(ACol, ARow, ACol + Value.ColSpan - 1, ARow + Value.ColSpan - 1);
|
|
if (ACol >= FFixedCols) and (ARow >= FFixedRows) then
|
|
FlagSet(cGF_SelCellsMerged);
|
|
Span := InternalGetCell(ACol, ARow).Span;
|
|
if (Span.ColSpan > 1) or (Span.RowSpan > 1) then
|
|
begin
|
|
// destroy previously merged area
|
|
Split(ACol, ARow, ACol + Span.ColSpan, ARow + Span.RowSpan);
|
|
Result.Col2 := Max(Result.Col2, ACol + Span.ColSpan - 1);
|
|
Result.Row2 := Max(Result.Row2, ARow + Span.RowSpan - 1);
|
|
end;
|
|
for I := ACol to ACol + Value.ColSpan - 1 do
|
|
for J := ARow to ARow + Value.RowSpan - 1 do
|
|
begin
|
|
Cell := InternalGetCell(I, J);
|
|
Span := Cell.Span;
|
|
if (Span.ColSpan <> 1) or (Span.RowSpan <> 1) then
|
|
begin
|
|
// adjust all four overlapping spans
|
|
InternalFindBaseCell(I, J, BaseCol, BaseRow);
|
|
if (BaseCol <> ACol) or (BaseRow <> ARow) then
|
|
begin
|
|
Span := InternalGetCell(BaseCol, BaseRow).Span;
|
|
Split(Max(ACol, BaseCol), Max(ARow, BaseRow),
|
|
Min(ACol + Value.ColSpan, BaseCol + Span.ColSpan), Min(ARow + Value.RowSpan, BaseRow + Span.RowSpan));
|
|
Merge(BaseCol, BaseRow, BaseCol + Span.ColSpan, ARow);
|
|
Merge(BaseCol, ARow + Value.RowSpan, BaseCol + Span.ColSpan, BaseRow + Span.RowSpan);
|
|
Merge(BaseCol, Max(ARow, BaseRow), ACol, Min(ARow + Value.RowSpan, BaseRow + Span.RowSpan));
|
|
Merge(ACol + Value.ColSpan, Max(ARow, BaseRow), BaseCol + Span.ColSpan, Min(ARow + Value.RowSpan, BaseRow + Span.RowSpan));
|
|
Result.Col1 := Min(Result.Col1, BaseCol);
|
|
Result.Row1 := Min(Result.Row1, BaseRow);
|
|
Result.Col2 := Max(Result.Col2, BaseCol + Span.ColSpan - 1);
|
|
Result.Row2 := Max(Result.Row2, BaseRow + Span.RowSpan - 1);
|
|
end;
|
|
end;
|
|
if (I = ACol) and (J = ARow) then
|
|
Cell.Span := Value
|
|
else
|
|
Cell.Span := MakeCellSpan(ACol - I, ARow - J);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalSetColCount(Value: Integer);
|
|
begin
|
|
if Value > FColCount then
|
|
ChangeDataSize(True, FColCount, Value - FColCount, False, 0, 0)
|
|
else if Value < FColCount then
|
|
ChangeDataSize(False, Value, FColCount - Value, False, 0, 0);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalSetFixedCols(Value: Integer);
|
|
begin
|
|
ColCount := Max(ColCount, Value + 1);
|
|
FFixedCols := Value;
|
|
ResetTopLeft;
|
|
SelectionFix(FSelection);
|
|
UpdateAxes(True, cAll, False, cAll, []);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalSetFixedRows(Value: Integer);
|
|
begin
|
|
RowCount := Max(RowCount, Value + 1);
|
|
FFixedRows := Value;
|
|
ResetTopLeft;
|
|
SelectionFix(FSelection);
|
|
UpdateAxes(False, cAll, True, cAll, []);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalSetRowCount(Value: Integer);
|
|
begin
|
|
if Value > FRowCount then
|
|
ChangeDataSize(False, 0, 0, True, FRowCount, Value - FRowCount)
|
|
else if Value < FRowCount then
|
|
ChangeDataSize(False, 0, 0, False, Value, FRowCount - Value);
|
|
end;
|
|
|
|
function TKCustomGrid.InternalUpdateVirtualGrid: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InternalUnlockUpdate;
|
|
begin
|
|
ClearSortMode;
|
|
UpdateAxes(True, cAll, True, cAll, [afCheckMinExtent]);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateCell(ACol, ARow: Integer);
|
|
begin
|
|
InvalidateGridRect(GridRect(GridPoint(ACol, ARow)));
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateCol(ACol: Integer);
|
|
var
|
|
GR: TKGridRect;
|
|
begin
|
|
if UpdateUnlocked and HandleAllocated then
|
|
begin
|
|
ACol := MinMax(ACol, 0, FColCount - 1);
|
|
GR.Col1 := ACol;
|
|
GR.Col2 := ACol;
|
|
if FFixedRows > 0 then
|
|
begin
|
|
GR.Row1 := 0;
|
|
GR.Row2 := FFixedRows - 1;
|
|
InvalidateGridRect(GR);
|
|
end;
|
|
GR.Row1 := FFixedRows;
|
|
GR.Row2 := LastVisibleRow;
|
|
InvalidateGridRect(GR);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateCols(FirstCol: Integer);
|
|
var
|
|
Boundary, FirstRow: Integer;
|
|
P: TPoint;
|
|
R: TRect;
|
|
GR: TKGridRect;
|
|
begin
|
|
if UpdateUnlocked and HandleAllocated then
|
|
begin
|
|
FirstCol := MinMax(FirstCol, 0, FColCount - 1);
|
|
if FirstCol >= FFixedCols then
|
|
FirstCol := Max(FirstCol, FTopLeft.Col);
|
|
if FFixedRows > 0 then
|
|
begin
|
|
GR := GridRect(FirstCol, 0, FirstCol, FFixedRows - 1);
|
|
GR := InternalExpandGridRect(GR);
|
|
Boundary := GR.Col1;
|
|
FirstRow := 0;
|
|
end else
|
|
begin
|
|
Boundary := MaxInt;
|
|
FirstRow := FTopLeft.Row;
|
|
end;
|
|
GR := GridRect(FirstCol, FTopLeft.Row, FirstCol, LastVisibleRow);
|
|
GR := InternalExpandGridRect(GR);
|
|
FirstCol := Min(Boundary, GR.Col1);
|
|
if FirstCol >= FFixedCols then
|
|
FirstCol := Max(FirstCol, FTopLeft.Col);
|
|
if CellToPoint(FirstCol, FirstRow, P, True) then
|
|
begin
|
|
if FirstCol >= FFixedCols then
|
|
Boundary := GetAxisInfoHorz([aiFixedParams]).FixedBoundary
|
|
else
|
|
Boundary := 0;
|
|
R := Rect(Max(P.X, Boundary), 0, ClientWidth, ClientHeight);
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateCurrentSelection;
|
|
begin
|
|
InvalidateSelection(Selection);
|
|
if EditorMode and CellInGridRect(Col, Row, Selection) then
|
|
FEditor.Invalidate;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateGridRect(const GR: TKGridRect; Merged: Boolean);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if UpdateUnlocked and HandleAllocated and GridRectToRect(GR, R, True, Merged) then
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateRow(ARow: Integer);
|
|
var
|
|
GR: TKGridRect;
|
|
begin
|
|
if UpdateUnlocked and HandleAllocated then
|
|
begin
|
|
ARow := MinMax(ARow, 0, FRowCount - 1);
|
|
GR.Row1 := ARow;
|
|
GR.Row2 := ARow;
|
|
if FFixedCols > 0 then
|
|
begin
|
|
GR.Col1 := 0;
|
|
GR.Col2 := FFixedCols - 1;
|
|
InvalidateGridRect(GR);
|
|
end;
|
|
GR.Col1 := FFixedCols;
|
|
GR.Col2 := LastVisibleCol;
|
|
InvalidateGridRect(GR);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateRows(FirstRow: Integer);
|
|
var
|
|
Boundary, FirstCol: Integer;
|
|
P: TPoint;
|
|
R: TRect;
|
|
GR: TKGridRect;
|
|
begin
|
|
if UpdateUnlocked and HandleAllocated then
|
|
begin
|
|
FirstRow := MinMax(FirstRow, 0, FRowCount - 1);
|
|
if FirstRow >= FFixedRows then
|
|
FirstRow := Max(FirstRow, FTopLeft.Row);
|
|
if FFixedCols > 0 then
|
|
begin
|
|
GR := GridRect(0, FirstRow, FFixedCols - 1, FirstRow);
|
|
GR := InternalExpandGridRect(GR);
|
|
Boundary := GR.Row1;
|
|
FirstCol := 0;
|
|
end else
|
|
begin
|
|
Boundary := MaxInt;
|
|
FirstCol := FTopLeft.Col;
|
|
end;
|
|
GR := GridRect(FirstCol, FirstRow, LastVisibleCol, FirstRow);
|
|
GR := InternalExpandGridRect(GR);
|
|
FirstRow := Min(Boundary, GR.Row1);
|
|
if FirstRow >= FFixedRows then
|
|
FirstRow := Max(FirstRow, FTopLeft.Row);
|
|
if CellToPoint(FirstCol, FirstRow, P, True) then
|
|
begin
|
|
if FirstRow >= FFixedRows then
|
|
Boundary := GetAxisInfoVert([aiFixedParams]).FixedBoundary
|
|
else
|
|
Boundary := 0;
|
|
R := Rect(0, Max(P.Y, Boundary), ClientWidth, ClientHeight);
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.InvalidateSelection(ASelection: TKGridRect);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if UpdateUnlocked and HandleAllocated then
|
|
begin
|
|
ASelection := AdjustSelection(ASelection);
|
|
if GridRectToRect(ASelection, R, True) then
|
|
InvalidateRect(Handle, @R, False);
|
|
if goIndicateSelection in FOptions then
|
|
begin
|
|
// this causes extremely slow painting under GTKx!
|
|
// do not use goIndicateSelection here!
|
|
if not (goRowSelect in FOptions) and (FFixedRows > 0) and GridRectToRect(
|
|
GridRect(ASelection.Col1, 0, ASelection.Col2, FFixedRows - 1), R, True) then
|
|
InvalidateRect(Handle, @R, False);
|
|
if (FFixedCols > 0) and GridRectToRect(
|
|
GridRect(0, ASelection.Row1, FFixedCols - 1, ASelection.Row2), R, True) then
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.IsDoubleBuffered: Boolean;
|
|
begin
|
|
Result := DoubleBuffered or (goDoubleBufferedCells in FOptions);
|
|
end;
|
|
|
|
function TKCustomGrid.IsThemed: Boolean;
|
|
begin
|
|
Result := goThemes in FOptions;
|
|
end;
|
|
|
|
procedure TKCustomGrid.KeyDown(var Key: Word; Shift: TShiftState);
|
|
var
|
|
ACol, ARow, ATopRow, SelCol, SelRow: Integer;
|
|
Stage: TKGridSelectionStage;
|
|
Expanding: Boolean;
|
|
begin
|
|
inherited;
|
|
SelCol := FSelection.Col1;
|
|
SelRow := FSelection.Row1;
|
|
Expanding := False;
|
|
if ssShift in Shift then
|
|
begin
|
|
Stage := ssExpand;
|
|
if (goRangeSelect in FOptions) and (FRangeSelectStyle = rsMS_Excel) then
|
|
begin
|
|
SelCol := FSelection.Col2;
|
|
SelRow := FSelection.Row2;
|
|
Expanding := True;
|
|
end;
|
|
end else
|
|
Stage := ssInit;
|
|
ACol := SelCol;
|
|
ARow := SelRow;
|
|
ATopRow := FTopLeft.Row;
|
|
if ssCtrl in Shift then
|
|
case Key of
|
|
VK_UP: Dec(ATopRow);
|
|
VK_DOWN: Inc(ATopRow);
|
|
VK_LEFT: InternalMove(ACol, ARow, mcPageLeft, False, Expanding);
|
|
VK_RIGHT: InternalMove(ACol, ARow, mcPageRight, False, Expanding);
|
|
VK_PRIOR: InternalMove(Acol, ARow, mcMoveUp, False, Expanding);
|
|
VK_NEXT: InternalMove(Acol, ARow, mcMoveDown, False, Expanding);
|
|
VK_HOME: InternalMove(Acol, ARow, mcTop, False, Expanding);
|
|
VK_END: InternalMove(Acol, ARow, mcBottom, False, Expanding);
|
|
end
|
|
else
|
|
case Key of
|
|
VK_RETURN:
|
|
begin
|
|
FlagSet(cGF_EnterPressed);
|
|
if goEnterMoves in FOptions then
|
|
begin
|
|
if (ACol = FColCount - 1) and (ARow = FRowCount - 1) and (gxEnterAppendsRow in FOptionsEx) then
|
|
begin
|
|
InsertRow(FRowCount);
|
|
InternalMove(ACol, ARow, DirectionToCommand(FMoveDirection), True, Expanding);
|
|
end else
|
|
InternalMove(ACol, ARow, DirectionToCommand(FMoveDirection), (gxEnterWraps in FOptionsEx), Expanding);
|
|
end else
|
|
EditorMode := not EditorMode;
|
|
end;
|
|
VK_ESCAPE:
|
|
begin
|
|
CancelMode;
|
|
if EditorMode then
|
|
begin
|
|
EditorDataFromGrid(FEditor, FEditorCell.Col, FEditorCell.Row);
|
|
EditorMode := False;
|
|
end;
|
|
end;
|
|
VK_UP: InternalMove(ACol, ARow, mcUp, False, Expanding);
|
|
VK_DOWN: InternalMove(ACol, ARow, mcDown, False, Expanding);
|
|
VK_LEFT: InternalMove(ACol, ARow, mcLeft, False, Expanding);
|
|
VK_RIGHT: InternalMove(ACol, ARow, mcRight, False, Expanding);
|
|
VK_NEXT: InternalMove(ACol, ARow, mcPageDown, False, Expanding);
|
|
VK_PRIOR: InternalMove(ACol, ARow, mcPageUp, False, Expanding);
|
|
VK_HOME: InternalMove(ACol, ARow, mcHome, False, Expanding);
|
|
VK_END: InternalMove(ACol, ARow, mcEnd, False, Expanding);
|
|
VK_TAB:
|
|
begin
|
|
if goTabs in FOptions then
|
|
begin
|
|
if not (ssAlt in Shift) then
|
|
repeat
|
|
if ssShift in Shift then
|
|
begin
|
|
InternalMove(ACol, ARow, mcLeft, gxTabWraps in FOptionsEx, Expanding);
|
|
Stage := ssInit;
|
|
end else
|
|
begin
|
|
if (ACol = FColCount - 1) and (ARow = FRowCount - 1) and (gxTabAppendsRow in FOptionsEx) then
|
|
begin
|
|
InsertRow(FRowCount);
|
|
InternalMove(ACol, ARow, mcRight, True, Expanding);
|
|
end else
|
|
InternalMove(ACol, ARow, mcRight, gxTabWraps in FOptionsEx, Expanding);
|
|
end;
|
|
until TabStops[ACol] or (ACol = FSelection.Col1);
|
|
end;
|
|
end;
|
|
VK_F2: EditorMode := True;
|
|
end;
|
|
DefaultSetCaretToLeft(Key, Shift);
|
|
// aki:
|
|
if (gxEditFixedCols in FOptionsEx) and (gxEditFixedRows in FOptionsEx) then
|
|
begin
|
|
ACol := MinMax(ACol, 0, FColCount - 1);
|
|
ARow := MinMax(ARow, 0, FRowCount - 1);
|
|
end
|
|
else if (gxEditFixedCols in FOptionsEx) then
|
|
begin
|
|
ACol := MinMax(ACol, 0, FColCount - 1);
|
|
ARow := MinMax(ARow, FFixedRows, FRowCount - 1);
|
|
end
|
|
else if (gxEditFixedRows in FOptionsEx) and (ARow < FFixedRows) then
|
|
begin
|
|
ACol := MinMax(ACol, 0, FColCount - 1);
|
|
ARow := MinMax(ARow, 0, FRowCount - 1);
|
|
end else
|
|
begin
|
|
ACol := MinMax(ACol, FFixedCols, FColCount - 1);
|
|
ARow := MinMax(ARow, FFixedRows, FRowCount - 1);
|
|
end;
|
|
if (ACol <> SelCol) or (ARow <> SelRow) then
|
|
begin
|
|
if SelectionMove(ACol, ARow, Stage, [sfMustUpdate, sfClampInView, sfDontCallSelectCell, sfNoMemPos]) then
|
|
begin
|
|
Click;
|
|
if not (goAlwaysShowEditor in FOptions) then
|
|
EditorMode := False;
|
|
Key := 0;
|
|
end;
|
|
end
|
|
else if ATopRow <> FTopLeft.Row then
|
|
TopRow := MinMax(ATopRow, FFixedRows, FRowCount - 1);
|
|
// whenever set, this flag is only valid for the nearest KeyDown call
|
|
FlagClear(cGF_CaretToLeft or cGF_EnterPressed);
|
|
end;
|
|
|
|
procedure TKCustomGrid.Loaded;
|
|
begin
|
|
inherited;
|
|
FColors.ClearBrightColors;
|
|
FColors.BrightRangeBkGnds;
|
|
end;
|
|
|
|
procedure TKCustomGrid.LateUpdate(var Msg: TLMessage);
|
|
begin
|
|
inherited;
|
|
case Msg.Msg of
|
|
CN_KEYDOWN:
|
|
begin
|
|
KeyDown(TLMKey(Msg).CharCode, KeyDataToShiftState(TLMKey(Msg).KeyData));
|
|
end;
|
|
LM_SETFOCUS:
|
|
begin
|
|
InvalidateCurrentSelection;
|
|
SafeSetFocus;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.LockSortMode;
|
|
begin
|
|
Inc(FSortModeLock);
|
|
end;
|
|
|
|
function TKCustomGrid.MeasureCell(ACol, ARow: Integer; const ARect: TRect;
|
|
AState: TKGridDrawState; Priority: TKGridMeasureCellPriority): TPoint;
|
|
begin
|
|
FCellPainter.Col := ACol;
|
|
FCellPainter.Row := ARow;
|
|
FCellPainter.State := AState;
|
|
FCellPainter.CellPos := ARect.TopLeft;
|
|
FCellPainter.Canvas := Canvas;
|
|
FCellPainter.CellRect := ARect;
|
|
FCellPainter.FPrinting := False;
|
|
// prepare cell painter and measure cell data
|
|
FCellPainter.BeginDraw;
|
|
try
|
|
Result.X := ARect.Right - ARect.Left;
|
|
Result.Y := ARect.Bottom - ARect.Top;
|
|
if Assigned(FOnMeasureCell) then
|
|
FOnMeasureCell(Self, ACol, ARow, ARect, AState, Priority, Result)
|
|
else if Assigned(FCells) then with InternalGetCell(ACol, ARow) do
|
|
begin
|
|
ApplyDrawProperties;
|
|
MeasureCell(ACol, ARow, ARect, AState, Priority, Result)
|
|
end else
|
|
Result := FCellPainter.DefaultMeasure(Priority);
|
|
finally
|
|
FCellPainter.EndDraw;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TKCustomGrid.MeasurePages(var Info: TKPrintMeasureInfo);
|
|
|
|
procedure Axis(const Info: TKGridAxisInfo; CanvasExtent, SelStart, SelEnd: Integer;
|
|
SelOnly, FitToPage: Boolean; out Pages, OutlineExtent: Integer);
|
|
var
|
|
I, StartIndex, EndIndex, Extent, PageExtent: Integer;
|
|
begin
|
|
Pages := 1;
|
|
PageExtent := 0;
|
|
OutlineExtent := 0;
|
|
if SelOnly then
|
|
begin
|
|
StartIndex := SelStart;
|
|
EndIndex := SelEnd;
|
|
end else
|
|
begin
|
|
StartIndex := 0;
|
|
EndIndex := Info.TotalCellCount - 1;
|
|
end;
|
|
for I := StartIndex to EndIndex do
|
|
begin
|
|
Extent := Info.CellExtent(I) + Info.EffectiveSpacing(I);
|
|
if FitToPage or (PageExtent + Extent < CanvasExtent) or (I = 0) then
|
|
Inc(PageExtent, Extent)
|
|
else
|
|
begin
|
|
Inc(Pages);
|
|
OutlineExtent := Max(OutlineExtent, PageExtent);
|
|
PageExtent := Extent;
|
|
end;
|
|
end;
|
|
OutlineExtent := Max(OutlineExtent, PageExtent);
|
|
end;
|
|
|
|
var
|
|
ColPages, RowPages: Integer;
|
|
Scale: Double;
|
|
FitToPage, SelOnly: Boolean;
|
|
R: TKGridRect;
|
|
APageSetup: TKPrintPageSetup;
|
|
begin
|
|
R := InternalExpandGridRect(Selection);
|
|
NormalizeGridRect(R);
|
|
APageSetup := PageSetup;
|
|
FitToPage := poFitToPage in APageSetup.Options;
|
|
SelOnly := APageSetup.Range = prSelectedOnly;
|
|
Scale := APageSetup.Scale / 100;
|
|
Axis(GetAxisInfoHorz([]), Round(APageSetup.PaintAreaWidth / Scale), R.Col1, R.Col2,
|
|
SelOnly, FitToPage, ColPages, Info.OutlineWidth);
|
|
if FitToPage then
|
|
Scale := APageSetup.PaintAreaWidth / Info.OutlineWidth;
|
|
Axis(GetAxisInfoVert([]), Round(APageSetup.PaintAreaHeight / Scale), R.Row1, R.Row2,
|
|
SelOnly, False, RowPages, Info.OutlineHeight);
|
|
Info.HorzPageCount := ColPages;
|
|
Info.VertPageCount := RowPages;
|
|
Info.PageCount := ColPages * RowPages;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseCellHint(ACol, ARow: Integer; AShow: Boolean);
|
|
begin
|
|
if Assigned(FOnMouseCellHint) then
|
|
FOnMouseCellHint(Self, ACol, ARow, AShow)
|
|
else
|
|
DefaultMouseCellHint(ACol, ARow, AShow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseClickCell(ACol, ARow: Integer);
|
|
begin
|
|
if (gxFixedCellClickSelect in FOptionsEx) and ((ARow < FFixedRows) or (ACol < FFixedCols)) and (ssShift in GetShiftState) then
|
|
begin
|
|
if (ARow < FFixedRows) and (ACol < FFixedCols) then
|
|
begin
|
|
if AllCellsSelected then
|
|
UnselectRange
|
|
else
|
|
SelectAll;
|
|
end else
|
|
begin
|
|
if ACol >= FFixedCols then
|
|
begin
|
|
if EntireColSelected[ACol] then
|
|
UnselectRange
|
|
else
|
|
SelectCol(ACol);
|
|
end else
|
|
begin
|
|
if EntireRowSelected[ARow] then
|
|
UnselectRange
|
|
else
|
|
SelectRow(ARow);
|
|
end;
|
|
end;
|
|
end;
|
|
if Assigned(FOnMouseClickCell) then
|
|
FOnMouseClickCell(Self, ACol, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseDblClickCell(ACol, ARow: Integer);
|
|
begin
|
|
if Assigned(FOnMouseDblClickCell) then
|
|
FOnMouseDblClickCell(Self, ACol, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var
|
|
BaseCol, BaseRow: Integer;
|
|
CellFound: Boolean;
|
|
State: TKGridState;
|
|
begin
|
|
inherited;
|
|
if (Button = mbLeft) and not FScrollTimer.Enabled then
|
|
begin
|
|
SafeSetFocus;
|
|
if ssDouble in Shift then
|
|
DblClick;
|
|
FHitPos := Point(X, Y);
|
|
State := gsNormal;
|
|
CellFound := PointToCell(FHitPos, False, icNone, FHitCell.Col, FHitCell.Row, BaseCol, BaseRow);
|
|
if CellFound then
|
|
InternalFindBaseCell(FHitCell.Col, FHitCell.Row, BaseCol, BaseRow);
|
|
if PointToSizing(FHitPos, State, FSizingIndex, FSizingDest) then
|
|
begin
|
|
if (State = gsColSizing) and
|
|
BeginColSizing(FSizingIndex, FSizingDest) or
|
|
(State = gsRowSizing) and
|
|
BeginRowSizing(FSizingIndex, FSizingDest) then
|
|
begin
|
|
FGridState := State;
|
|
if CellFound then
|
|
InvalidateCell(BaseCol, BaseRow);
|
|
Update;
|
|
SuggestSizing(csStart);
|
|
end;
|
|
end
|
|
else if CellFound then
|
|
begin
|
|
if FMouseOver.Col >= 0 then
|
|
begin
|
|
MouseCellHint(FMouseOver.Col, FMouseOver.Row, False);
|
|
FCellHintTimer.Enabled := False;
|
|
end;
|
|
// aki: row for greater than fixed cols:
|
|
if (FHitCell.Row < FFixedRows) and (FHitCell.Col >= FFixedCols) and (not (gxEditFixedRows in FOptionsEx)) then
|
|
begin
|
|
if goColMoving in FOptions then
|
|
FGridState := gsColMoveWaiting
|
|
else if goRowSorting in FOptions then
|
|
FGridState := gsRowSortWaiting;
|
|
end
|
|
// aki: col
|
|
else if ((FHitCell.Col < FFixedCols) and (FHitCell.Row >= FFixedRows)) and (not (gxEditFixedCols in FOptionsEx)) then
|
|
begin
|
|
if goRowMoving in FOptions then
|
|
FGridState := gsRowMoveWaiting
|
|
else if goColSorting in FOptions then
|
|
FGridState := gsColSortWaiting;
|
|
end
|
|
// aki: row for greater than fixed row:
|
|
else if ((FHitCell.Col < FFixedCols) and (FHitCell.Row < FFixedRows)) and (not (gxEditFixedRows in FOptionsEx)) then
|
|
begin
|
|
FGridState := gsClickWaiting;
|
|
end else
|
|
begin
|
|
FlagSet(cGF_SelectedByMouse);
|
|
try
|
|
if SelectionMove(BaseCol, BaseRow, ssInit, [sfMustUpdate, sfClampInView]) then
|
|
begin
|
|
FGridState := gsSelecting;
|
|
EditorMode := (goAlwaysShowEditor in FOptions) or (ssDouble in Shift);
|
|
end;
|
|
finally
|
|
FlagClear(cGF_SelectedByMouse);
|
|
end;
|
|
end;
|
|
InvalidateCell(BaseCol, BaseRow);
|
|
if ssDouble in Shift then
|
|
MouseDblClickCell(BaseCol, BaseRow);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseEnterCell(ACol, ARow: Integer);
|
|
begin
|
|
if Assigned(FOnMouseEnterCell) then
|
|
FOnMouseEnterCell(Self, ACol, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseFormLeave;
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
inherited;
|
|
if EditorMode then
|
|
begin
|
|
P := FEditor.ScreenToClient(Mouse.CursorPos);
|
|
if PtInRect(FEditor.ClientRect, P) then
|
|
FEditor.Perform(CM_MOUSEENTER, 0, 0)
|
|
else
|
|
MouseOverCells;
|
|
end else
|
|
MouseOverCells;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseLeaveCell(ACol, ARow: Integer);
|
|
begin
|
|
if Assigned(FOnMouseLeaveCell) then
|
|
FOnMouseLeaveCell(Self, ACol, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
|
|
function CanDrag: Boolean;
|
|
begin
|
|
Result :=
|
|
(X > FHitPos.X + 8) or
|
|
(X < FHitPos.X - 8) or
|
|
(Y > FHitPos.Y + 8) or
|
|
(Y < FHitPos.Y - 8);
|
|
end;
|
|
|
|
var
|
|
MustScroll: Boolean;
|
|
DeltaHorz, DeltaVert, HitCol, HitRow, SelCol, SelRow: Integer;
|
|
MousePt: TPoint;
|
|
begin
|
|
inherited;
|
|
MousePt := Point(X, Y);
|
|
if MouseCapture then
|
|
begin
|
|
case FGridState of
|
|
gsColSizing:
|
|
begin
|
|
SuggestSizing(csHide);
|
|
FSizingDest := X;
|
|
SuggestSizing(csShow);
|
|
end;
|
|
gsRowSizing:
|
|
begin
|
|
SuggestSizing(csHide);
|
|
FSizingDest := Y;
|
|
SuggestSizing(csShow);
|
|
end;
|
|
gsColMoveWaiting: if CanDrag then
|
|
begin
|
|
FDragOrigin := FHitCell.Col;
|
|
if BeginColDrag(FDragOrigin, MousePt) then
|
|
begin
|
|
ProcessDragWindow(FHitPos, MousePt, FDragOrigin, True, False);
|
|
FGridState := gsColMoving;
|
|
FDragDest := FDragOrigin;
|
|
SuggestDrag(csStart);
|
|
end;
|
|
end;
|
|
gsRowMoveWaiting: if CanDrag then
|
|
begin
|
|
FDragOrigin := FHitCell.Row;
|
|
if BeginRowDrag(FDragOrigin, MousePt) then
|
|
begin
|
|
ProcessDragWindow(FHitPos, MousePt, FDragOrigin, False, False);
|
|
FGridState := gsRowMoving;
|
|
FDragDest := FDragOrigin;
|
|
SuggestDrag(csStart);
|
|
end;
|
|
end;
|
|
gsSelecting, gsColMoving, gsRowMoving:
|
|
begin
|
|
if FGridState <> gsSelecting then
|
|
ProcessDragWindow(FHitPos, MousePt, cInvalidIndex, FGridState = gsColMoving, False);
|
|
if not FScrollTimer.Enabled and PointToCell(MousePt, True,
|
|
GridStateToInvisibleCells, HitCol, HitRow, SelCol, SelRow) then
|
|
begin
|
|
MustScroll := ScrollNeeded(HitCol, HitRow, DeltaHorz, DeltaVert);
|
|
if MustScroll then
|
|
begin
|
|
Scroll(cScrollDelta, cScrollDelta, DeltaHorz, DeltaVert, False);
|
|
FScrollTimer.Enabled := True;
|
|
end;
|
|
if FGridState = gsSelecting then
|
|
begin
|
|
InternalFindBaseCell(SelCol, SelRow, SelCol, SelRow);
|
|
SelectionMove(SelCol, SelRow, ssExpand, [sfMustUpdate])
|
|
end else
|
|
DragMove(HitCol, HitRow, MousePt);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
MouseOverCells;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseOverCells;
|
|
var
|
|
MousePt: TPoint;
|
|
HitCol, HitRow, BaseCol, BaseRow: Integer;
|
|
begin
|
|
MousePt := ScreenToClient(Mouse.CursorPos);
|
|
if not (FGridState in [gsColMoving, gsRowMoving]) and
|
|
((goMouseOverCells in FOptions) or (FGridState <> gsNormal)) and
|
|
PtInRect(ClientRect, MousePt) and
|
|
PointToCell(MousePt, False, icNone, HitCol, HitRow, BaseCol, BaseRow) then
|
|
begin
|
|
InternalFindBaseCell(HitCol, HitRow, BaseCol, BaseRow);
|
|
if (BaseCol <> FMouseOver.Col) or (BaseRow <> FMouseOver.Row) then
|
|
begin
|
|
if FMouseOver.Col >= 0 then
|
|
begin
|
|
InvalidateCell(FMouseOver.Col, FMouseOver.Row);
|
|
MouseCellHint(FMouseOver.Col, FMouseOver.Row, False);
|
|
MouseLeaveCell(FMouseOver.Col, FMouseOver.Row);
|
|
end;
|
|
InvalidateCell(BaseCol, BaseRow);
|
|
if EditorMode and (
|
|
(FMouseOver.Col = FEditorCell.Col) and (FMouseOver.Row = FEditorCell.Row) and
|
|
((BaseCol <> FEditorCell.Col) or (BaseRow <> FEditorCell.Row))
|
|
or
|
|
(BaseCol = FEditorCell.Col) and (BaseRow = FEditorCell.Row) and
|
|
((FMouseOver.Col <> FEditorCell.Col) or (FMouseOver.Row <> FEditorCell.Row))
|
|
) then
|
|
FEditor.Invalidate;
|
|
FMouseOver := GridPoint(BaseCol, BaseRow);
|
|
MouseEnterCell(FMouseOver.Col, FMouseOver.Row);
|
|
if not MouseCapture then
|
|
begin
|
|
FHintCell := FMouseOver;
|
|
FCellHintTimer.Enabled := False;
|
|
FCellHintTimer.Interval := FMouseCellHintTime;
|
|
FCellHintTimer.Enabled := True;
|
|
end;
|
|
end;
|
|
end
|
|
else if FMouseOver.Col >= 0 then
|
|
begin
|
|
if EditorMode and (FMouseOver.Col = FEditorCell.Col) and (FMouseOver.Row = FEditorCell.Row) then
|
|
FEditor.Invalidate;
|
|
InvalidateCell(FMouseOver.Col, FMouseOver.Row);
|
|
MouseCellHint(FMouseOver.Col, FMouseOver.Row, False);
|
|
MouseLeaveCell(FMouseOver.Col, FMouseOver.Row);
|
|
FMouseOver := GridPoint(-1, -1);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
|
|
function NextSortMode(ASortMode: TKGridSortMode): TKGridSortMode;
|
|
begin
|
|
case FSortStyle of
|
|
ssDownUp: if ASortMode = smDown then Result := smUp else Result := smDown;
|
|
ssDownUpNone:
|
|
case ASortMode of
|
|
smDown: Result := smUp;
|
|
smUp: Result := smNone;
|
|
else
|
|
Result := smDown;
|
|
end;
|
|
else
|
|
case ASortMode of
|
|
smUp: Result := smDown;
|
|
smDown: Result := smNone;
|
|
else
|
|
Result := smUp;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
BaseCol, BaseRow, BaseHitCol, BaseHitRow, HitCol, HitRow, Tmp: Integer;
|
|
CellFound: Boolean;
|
|
CellPt, MousePt: TPoint;
|
|
begin
|
|
inherited;
|
|
if Button = mbLeft then
|
|
begin
|
|
MousePt := Point(X, Y);
|
|
case FGridState of
|
|
gsColMoving, gsRowMoving:
|
|
begin
|
|
ProcessDragWindow(FHitPos, MousePt, -1, FGridState = gsColMoving, True);
|
|
SuggestDrag(csStop);
|
|
end;
|
|
gsColSizing, gsRowSizing:
|
|
SuggestSizing(csStop);
|
|
end;
|
|
if ColValid(FHitCell.Col) and RowValid(FHitCell.Row) and
|
|
PointToCell(MousePt, False, icNone, HitCol, HitRow, BaseCol, BaseRow) then
|
|
begin
|
|
InternalFindBaseCell(HitCol, HitRow, BaseCol, BaseRow);
|
|
InternalFindBaseCell(FHitCell.Col, FHitCell.Row, BaseHitCol, BaseHitRow);
|
|
CellFound := (BaseHitCol = BaseCol) and (BaseHitRow = BaseRow);
|
|
end else
|
|
CellFound := False;
|
|
case FGridState of
|
|
gsSelecting:
|
|
begin
|
|
ClampInView(Col, Row);
|
|
if CellFound then
|
|
MouseClickCell(BaseCol, BaseRow);
|
|
Click;
|
|
end;
|
|
gsColSortWaiting, gsRowSortWaiting, gsColMoveWaiting, gsRowMoveWaiting:
|
|
if CellFound then
|
|
begin
|
|
if not (ssShift in Shift) and ((FGridState = gsColSortWaiting) or (FGridState = gsRowMoveWaiting)) and
|
|
(goColSorting in FOptions) and (BaseCol = FRows[BaseRow].SortArrowIndex) then
|
|
SortCols(BaseRow, NextSortMode(Rows[BaseRow].SortMode))
|
|
else if not (ssShift in Shift) and ((FGridState = gsRowSortWaiting) or (FGridState = gsColMoveWaiting)) and
|
|
(goRowSorting in FOptions) and (BaseRow = FCols[BaseCol].SortArrowIndex) then
|
|
SortRows(BaseCol, NextSortMode(Cols[BaseCol].SortMode))
|
|
else
|
|
begin
|
|
InvalidateCell(BaseCol, BaseRow);
|
|
MouseClickCell(BaseCol, BaseRow);
|
|
Click;
|
|
end;
|
|
end;
|
|
gsClickWaiting:
|
|
if CellFound then
|
|
begin
|
|
InvalidateCell(BaseCol, BaseRow);
|
|
MouseClickCell(BaseCol, BaseRow);
|
|
Click;
|
|
end;
|
|
gsColMoving:
|
|
if EndColDrag(FDragOrigin, FDragDest, MousePt) and (FDragOrigin <> FDragDest) then
|
|
MoveCol(FDragOrigin, FDragDest)
|
|
else
|
|
InvalidateCol(FDragOrigin);
|
|
gsRowMoving:
|
|
if EndRowDrag(FDragOrigin, FDragDest, MousePt) and (FDragOrigin <> FDragDest) then
|
|
MoveRow(FDragOrigin, FDragDest)
|
|
else
|
|
InvalidateRow(FDragOrigin);
|
|
gsColSizing:
|
|
begin
|
|
case FSizingStyle of
|
|
ssLine, ssXORLine:
|
|
if EndColSizing(FSizingIndex, FSizingDest) and CellToPoint(FSizingIndex, 0, CellPt) then
|
|
begin
|
|
Tmp := FSizingDest - CellPt.X;
|
|
if not (goMouseCanHideCells in FOptions) then
|
|
Tmp := Max(Tmp, InternalGetMinColWidth(FSizingIndex));
|
|
ColWidths[FSizingIndex] := Tmp;
|
|
end;
|
|
end;
|
|
UpdateDesigner;
|
|
end;
|
|
gsRowSizing:
|
|
begin
|
|
case FSizingStyle of
|
|
ssLine, ssXORLine:
|
|
if EndRowSizing(FSizingIndex, FSizingDest) and CellToPoint(0, FSizingIndex, CellPt) then
|
|
begin
|
|
Tmp := FSizingDest - CellPt.Y;
|
|
if not (goMouseCanHideCells in FOptions) then
|
|
Tmp := Max(Tmp, InternalGetMinRowHeight(FSizingIndex));
|
|
RowHeights[FSizingIndex] := Tmp;
|
|
end;
|
|
end;
|
|
UpdateDesigner;
|
|
end
|
|
else
|
|
if CellFound then
|
|
InvalidateCell(BaseCol, BaseRow);
|
|
end;
|
|
FlagClear(cGF_ThroughClick);
|
|
FGridState := gsNormal;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.MouseToCell(X, Y: Integer; var ACol, ARow: Integer): Boolean;
|
|
var
|
|
DummyCol, DummyRow: Integer;
|
|
begin
|
|
Result := PointToCell(Point(X, Y), False, icNone, ACol, ARow, DummyCol, DummyRow);
|
|
if Result then
|
|
InternalFindBaseCell(ACol, ARow, ACol, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.MoveCol(FromIndex, ToIndex: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FromIndex <> ToIndex) and ColValid(FromIndex) and ColValid(ToIndex) then
|
|
begin
|
|
if ToIndex > FromIndex then
|
|
for I := ToIndex downto FromIndex do
|
|
InternalExchangeCols(I, FromIndex)
|
|
else
|
|
for I := ToIndex to FromIndex do
|
|
InternalExchangeCols(I, FromIndex);
|
|
SelectionFix(FSelection);
|
|
UpdateAxes(True, cAll, False, cAll, []);
|
|
UpdateCellSpan;
|
|
ClearSortModeVert;
|
|
ColMoved(FromIndex, ToIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MoveRow(FromIndex, ToIndex: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if (FromIndex <> ToIndex) and RowValid(FromIndex) and RowValid(ToIndex) then
|
|
begin
|
|
if ToIndex > FromIndex then
|
|
for I := ToIndex downto FromIndex do
|
|
InternalExchangeRows(I, FromIndex)
|
|
else
|
|
for I := ToIndex to FromIndex do
|
|
InternalExchangeRows(I, FromIndex);
|
|
SelectionFix(FSelection);
|
|
UpdateAxes(False, cAll, True, cAll, []);
|
|
UpdateCellSpan;
|
|
ClearSortModeHorz;
|
|
RowMoved(FromIndex, ToIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.MoveToNextCell;
|
|
var
|
|
ACol , ARow : Integer;
|
|
begin
|
|
ACol := FSelection.Col1;
|
|
ARow := FSelection.Row1;
|
|
InternalMove(ACol, ARow, DirectionToCommand(FMoveDirection), True, False);
|
|
if SelectionMove(ACol, ARow, ssInit, [sfMustUpdate, sfClampInView, sfDontCallSelectCell]) then
|
|
Click;
|
|
end;
|
|
|
|
function TKCustomGrid.PageHeight: Integer;
|
|
var
|
|
Info: TKGridAxisInfo;
|
|
begin
|
|
Info := GetAxisInfoVert([aiFullVisBoundary]);
|
|
Result := Max(Info.FullVisCells - Info.FirstGridCell, 1);
|
|
end;
|
|
|
|
function TKCustomGrid.PageWidth: Integer;
|
|
var
|
|
Info: TKGridAxisInfo;
|
|
begin
|
|
Info := GetAxisInfoHorz([aiFullVisBoundary]);
|
|
Result := Max(Info.FullVisCells - Info.FirstGridCell, 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.PaintCell(ACanvas: TCanvas; ACol, ARow: Integer; AX, AY: Integer; APrinting: Boolean; ABlockRect: PRect);
|
|
var
|
|
R, ClipRect, TmpRect, TmpBlockRect: TRect;
|
|
CellBitmap: TBitmap;
|
|
TmpCanvas: TCanvas;
|
|
ClipCells: Boolean;
|
|
Info: TKGridAxisInfoBoth;
|
|
begin
|
|
if (ColWidths[ACol] > 0) and (RowHeights[ARow] > 0) then
|
|
if CellRect(ACol, ARow, R, True) then
|
|
begin
|
|
if not APrinting and ((goDoubleBufferedCells in FOptions) or DoubleBuffered) then
|
|
CellBitmap := TBitmap.Create
|
|
else
|
|
CellBitmap := nil;
|
|
try
|
|
if CellBitmap <> nil then
|
|
begin
|
|
TmpRect := Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top);
|
|
CellBitmap.Width := TmpRect.Right; // SetSize not supported prior Delphi 2006
|
|
CellBitmap.Height := TmpRect.Bottom;
|
|
TmpCanvas := CellBitmap.Canvas;
|
|
SelectClipRect(TmpCanvas.Handle, TmpRect);
|
|
ClipCells := False;
|
|
end else
|
|
begin
|
|
if ACanvas <> nil then
|
|
begin
|
|
TmpRect := Rect(AX, AY, AX + R.Right - R.Left, AY + R.Bottom - R.Top);
|
|
TmpCanvas := ACanvas;
|
|
SelectClipRect(TmpCanvas.Handle, TmpRect);
|
|
end else
|
|
begin
|
|
TmpRect := R;
|
|
TmpCanvas := Canvas;
|
|
end;
|
|
ClipCells := goClippedCells in FOptions;
|
|
end;
|
|
if ABlockRect <> nil then
|
|
TmpBlockRect := ABlockRect^
|
|
else
|
|
TmpBlockRect := SelectionRect;
|
|
if CellBitmap <> nil then
|
|
OffsetRect(TmpBlockRect, -R.Left, -R.Top);
|
|
if (ACanvas = nil) or (ACanvas = Canvas) then
|
|
begin
|
|
Info := GetAxisInfoBoth([aiFixedParams]);
|
|
if (ARow >= FFixedRows) and (ACol < FFixedCols) then
|
|
ClipRect := Rect(0, Info.Vert.FixedBoundary, Info.Horz.FixedBoundary, Info.Vert.ClientExtent)
|
|
else if (ARow < FFixedRows) and (ACol >= FFixedCols) then
|
|
ClipRect := Rect(Info.Horz.FixedBoundary, 0, Info.Horz.ClientExtent, Info.Vert.FixedBoundary)
|
|
else if (ARow >= FFixedRows) and (ACol >= FFixedCols) then
|
|
ClipRect := Rect(Info.Horz.FixedBoundary, Info.Vert.FixedBoundary, Info.Horz.ClientExtent, Info.Vert.ClientExtent)
|
|
else
|
|
ClipRect := Rect(0, 0, Info.Horz.FixedBoundary, Info.Vert.FixedBoundary);
|
|
SelectClipRect(Canvas.Handle, ClipRect);
|
|
end;
|
|
InternalPaintCell(ACol, ARow, GetDrawState(ACol, ARow, HasFocus), TmpRect, TmpBlockRect, TmpCanvas, ClipCells, False);
|
|
if CellBitmap <> nil then
|
|
begin
|
|
Canvas.Lock;
|
|
try
|
|
Canvas.Draw(R.Left, R.Top, CellBitmap);
|
|
finally
|
|
Canvas.Unlock;
|
|
end;
|
|
end;
|
|
finally
|
|
CellBitmap.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.PaintCells(ACanvas: TCanvas; CellBitmap: TBitmap; MainClipRgn: HRGN;
|
|
FirstCol, LastCol, FirstRow, LastRow, X, Y, MaxX, MaxY: Integer; Printing, PaintSelection: Boolean;
|
|
const ABlockRect: TRect): TPoint;
|
|
var
|
|
I, J, I1, J1, XBack, YBack,
|
|
CHExtent, CHSpacing, CVExtent, CVSpacing,
|
|
HExtent, HSpacing, VExtent, VSpacing: Integer;
|
|
ClipCells, DrawLinesHorz, DrawLinesVert, GridFocused, HasHeader, HasFixedThemedCells, UseThemedCells: Boolean;
|
|
CellState: TKGridDrawState;
|
|
Span: TKGridCellSpan;
|
|
BorderRect, CellRect, TmpRect, TmpBlockRect: TRect;
|
|
TmpCanvas: TCanvas;
|
|
begin
|
|
GridFocused := Printing or HasFocus;
|
|
UseThemedCells := ThemedCells;
|
|
YBack := Y;
|
|
XBack := X;
|
|
// search for hidden merged cells first and update the FirstCol and FirstRow
|
|
// this is supposed to be faster for huge grids than to parse entire grid all the time
|
|
HExtent := FirstCol;
|
|
VExtent := FirstRow;
|
|
if FirstCol > 0 then // not for fixed cells
|
|
begin
|
|
I := FirstRow;
|
|
while (I <= LastRow) and (Y <= MaxY) do
|
|
begin
|
|
InternalFindBaseCell(FirstCol, I, I1, J1);
|
|
HExtent := Min(HExtent, I1);
|
|
VExtent := Min(VExtent, J1);
|
|
Inc(Y, InternalGetRowHeights(I) + InternalGetEffectiveRowSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
if FirstRow > 0 then // not for fixed cells
|
|
begin
|
|
I := FirstCol;
|
|
while (I <= LastCol) and (X <= MaxX) do
|
|
begin
|
|
InternalFindBaseCell(I, FirstRow, I1, J1);
|
|
HExtent := Min(HExtent, I1);
|
|
VExtent := Min(VExtent, J1);
|
|
Inc(X, InternalGetColWidths(I) + InternalGetEffectiveColSpacing(I));
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
while FirstCol > HExtent do
|
|
begin
|
|
Dec(FirstCol);
|
|
Dec(XBack, InternalGetColWidths(FirstCol) + InternalGetEffectiveColSpacing(FirstCol));
|
|
end;
|
|
while FirstRow > VExtent do
|
|
begin
|
|
Dec(FirstRow);
|
|
Dec(YBack, InternalGetRowHeights(FirstRow) + InternalGetEffectiveRowSpacing(FirstRow));
|
|
end;
|
|
// now draw the grid
|
|
Y := YBack;
|
|
I := FirstRow;
|
|
while (I <= LastRow) and (Y <= MaxY) do
|
|
begin
|
|
X := XBack;
|
|
VExtent := InternalGetRowHeights(I);
|
|
VSpacing := InternalGetEffectiveRowSpacing(I);
|
|
J := FirstCol;
|
|
while (J <= LastCol) and (X <= MaxX) do
|
|
begin
|
|
HExtent := InternalGetColWidths(J);
|
|
HSpacing := InternalGetEffectiveColSpacing(J);
|
|
Span := InternalGetCellSpan(J, I);
|
|
if (Span.ColSpan > 0) and (Span.RowSpan > 0) then
|
|
begin
|
|
InternalGetHExtent(J, Span.ColSpan, CHExtent, CHSpacing);
|
|
InternalGetVExtent(I, Span.RowSpan, CVExtent, CVSpacing);
|
|
CellRect := Rect(X, Y, X + CHExtent, Y + CVExtent);
|
|
BorderRect := CellRect;
|
|
Inc(BorderRect.Bottom, CVSpacing);
|
|
Inc(BorderRect.Right, CHSpacing);
|
|
TmpRect := BorderRect;
|
|
if not Printing then
|
|
TranslateRectToDevice(ACanvas.Handle, TmpRect);
|
|
if Printing or RectInRegion(MainClipRgn, TmpRect) then
|
|
begin
|
|
if (CHExtent > 0) and (CVExtent > 0) then
|
|
begin
|
|
CellState := GetDrawState(J, I, GridFocused);
|
|
if Printing then
|
|
begin
|
|
CellState := CellState - [gdEdited, gdMouseDown, gdMouseOver];
|
|
if not PaintSelection then
|
|
CellState := CellState - [gdSelected, gdFocused];
|
|
end;
|
|
// default brush style for lines
|
|
ACanvas.Brush.Style := bsSolid;
|
|
// draw default grid
|
|
if (CHSpacing > 0) or (CVSpacing > 0) then
|
|
begin
|
|
DrawLinesHorz := CVSpacing > 0;
|
|
DrawLinesVert := CHSPacing > 0;
|
|
if gdFixed in CellState then
|
|
begin
|
|
HasHeader := (I < FFixedRows) and (goHeader in FOptions) and UseThemedCells;
|
|
HasFixedThemedCells := ((I < FFixedRows) or (J < FFixedCols)) and (gxFixedThemedCells in FOptionsEx) and UseThemedCells;
|
|
DrawLinesHorz := DrawLinesHorz and (goFixedHorzLine in FOptions) and not HasFixedThemedCells;
|
|
DrawLinesVert := DrawLinesVert and (goFixedVertLine in FOptions) and not (HasHeader or HasFixedThemedCells);
|
|
if UseThemedCells then
|
|
ACanvas.Brush.Color := FColors.FixedThemedCellLines
|
|
else
|
|
ACanvas.Brush.Color := FColors.FixedCellLines;
|
|
end else
|
|
begin
|
|
ACanvas.Brush.Color := FColors.CellLines;
|
|
DrawLinesHorz := DrawLinesHorz and (goHorzLine in FOptions);
|
|
DrawLinesVert := DrawLinesVert and (goVertLine in FOptions);
|
|
end;
|
|
if DrawLinesHorz then
|
|
begin
|
|
TmpRect := Rect(CellRect.Left, CellRect.Bottom, BorderRect.Right, BorderRect.Bottom);
|
|
ACanvas.FillRect(TmpRect);
|
|
end else
|
|
CellRect.Bottom := BorderRect.Bottom;
|
|
if DrawLinesVert then
|
|
begin
|
|
TmpRect := Rect(CellRect.Right, CellRect.Top, BorderRect.Right, CellRect.Bottom);
|
|
ACanvas.FillRect(TmpRect);
|
|
end else
|
|
CellRect.Right := BorderRect.Right;
|
|
end;
|
|
TmpBlockRect := ABlockRect;
|
|
if CellBitmap <> nil then
|
|
begin
|
|
TmpRect := Rect(0, 0, CellRect.Right - CellRect.Left, CellRect.Bottom - CellRect.Top);
|
|
CellBitmap.Width := TmpRect.Right; // SetSize not supported prior Delphi 2006
|
|
CellBitmap.Height := TmpRect.Bottom;
|
|
TmpCanvas := CellBitmap.Canvas;
|
|
SelectClipRect(TmpCanvas.Handle, TmpRect);
|
|
ClipCells := False;
|
|
OffsetRect(TmpBlockRect, -CellRect.Left, -CellRect.Top);
|
|
end else
|
|
begin
|
|
TmpRect := CellRect;
|
|
TmpCanvas := ACanvas;
|
|
ClipCells := goClippedCells in FOptions;
|
|
end;
|
|
InternalPaintCell(J, I, CellState, TmpRect, TmpBlockRect, TmpCanvas, ClipCells, Printing);
|
|
if CellBitmap <> nil then
|
|
ACanvas.Draw(CellRect.Left, CellRect.Top, CellBitmap);
|
|
end
|
|
else if goIndicateHiddenCells in FOptions then
|
|
begin
|
|
TmpRect := BorderRect;
|
|
if (HExtent = 0) and (HSpacing > 0) then
|
|
begin
|
|
if (I = 0) and (CVExtent > FHCI.VBegin.Height) then
|
|
begin
|
|
ACanvas.Draw(TmpRect.Left, TmpRect.Top, FHCI.VBegin);
|
|
Inc(TmpRect.Top, FHCI.VBegin.Height);
|
|
end;
|
|
if (I = FRowCount - 1) and (CVExtent > FHCI.VEnd.Height) then
|
|
begin
|
|
Dec(TmpRect.Bottom, FHCI.VEnd.Height);
|
|
ACanvas.Draw(TmpRect.Left, TmpRect.Bottom, FHCI.HEnd);
|
|
end;
|
|
ACanvas.StretchDraw(TmpRect, FHCI.VCenter);
|
|
end;
|
|
if (VExtent = 0) and (VSpacing > 0) then
|
|
begin
|
|
if (J = 0) and (CHExtent > FHCI.HBegin.Width) then
|
|
begin
|
|
ACanvas.Draw(TmpRect.Left, TmpRect.Top, FHCI.HBegin);
|
|
Inc(TmpRect.Left, FHCI.HBegin.Width);
|
|
end;
|
|
if (J = FColCount - 1) and (CHExtent > FHCI.HEnd.Width) then
|
|
begin
|
|
Dec(TmpRect.Right, FHCI.HEnd.Width);
|
|
ACanvas.Draw(TmpRect.Right, TmpRect.Top, FHCI.HEnd);
|
|
end;
|
|
ACanvas.StretchDraw(TmpRect, FHCI.HCenter);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
Inc(X, HExtent + HSpacing);
|
|
Inc(J);
|
|
end;
|
|
Inc(Y, VExtent + VSpacing);
|
|
Inc(I);
|
|
end;
|
|
Result := Point(X, Y);
|
|
end;
|
|
|
|
procedure TKCustomGrid.PaintDragSuggestion(ACanvas: TCanvas);
|
|
|
|
procedure DragSuggLine(X, Y, W, H: Integer);
|
|
begin
|
|
with ACanvas do
|
|
begin
|
|
Pen.Color := FColors.DragSuggestionLine;
|
|
Pen.Style := psSolid;
|
|
Pen.Width := 1;
|
|
Brush.Color := FColors.DragSuggestionBkGnd;
|
|
Brush.Style := bsSolid;
|
|
Rectangle(X, Y, X + W, Y + H);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Len: Integer;
|
|
ArrowCopy: TKAlphaBitmap;
|
|
R: TRect;
|
|
begin
|
|
if GetDragRect(GetAxisInfoBoth([aiGridBoundary]), R) then
|
|
begin
|
|
case FDragStyle of
|
|
dsLayeredConst, dsLayeredFaded:
|
|
begin
|
|
ArrowCopy := TKAlphaBitmap.Create;
|
|
try
|
|
if FGridState = gsColMoving then
|
|
begin
|
|
ArrowCopy.CopyFrom(FDragArrow);
|
|
ArrowCopy.AlphaDrawTo(ACanvas, R.Left, R.Top);
|
|
Len := R.Bottom - R.Top - ArrowCopy.Height shl 1;
|
|
if Len > 0 then
|
|
begin
|
|
ArrowCopy.MirrorVert;
|
|
ArrowCopy.AlphaDrawTo(ACanvas, R.Left, R.Bottom - ArrowCopy.Height);
|
|
if Len > 6 then
|
|
DragSuggLine(R.Left + ArrowCopy.Width shr 1 - 1,
|
|
R.Top + ArrowCopy.Height + 1, 3, Len - 2);
|
|
end;
|
|
end else
|
|
begin
|
|
ArrowCopy.CopyFromRotated(FDragArrow);
|
|
ArrowCopy.AlphaDrawTo(ACanvas, R.Left, R.Top);
|
|
Len := R.Right - R.Left - ArrowCopy.Width shl 1;
|
|
if Len > 0 then
|
|
begin
|
|
ArrowCopy.MirrorHorz;
|
|
ArrowCopy.AlphaDrawTo(ACanvas, R.Right - ArrowCopy.Width, R.Top);
|
|
if Len > 6 then
|
|
DragSuggLine(R.Left + ArrowCopy.Width + 1,
|
|
R.Top + ArrowCopy.Height shr 1 - 1, Len - 2, 3);
|
|
end;
|
|
end;
|
|
finally
|
|
ArrowCopy.Free;
|
|
end;
|
|
end;
|
|
dsLine, dsXORLine:
|
|
begin
|
|
with ACanvas do
|
|
begin
|
|
// prevent rounded caps
|
|
Pen.Width := 1;
|
|
if FDragStyle = dsLine then
|
|
Pen.Color := clRed
|
|
else
|
|
begin
|
|
Pen.Mode := pmXOR;
|
|
Pen.Color := clWhite;
|
|
end;
|
|
try
|
|
if FGridState = gsColMoving then
|
|
begin
|
|
for Len := 0 to 4 do
|
|
begin
|
|
ACanvas.MoveTo(R.Left + Len, R.Top);
|
|
ACanvas.LineTo(R.Left + Len, R.Bottom);
|
|
end;
|
|
end else
|
|
begin
|
|
for Len := 0 to 4 do
|
|
begin
|
|
ACanvas.MoveTo(R.Left, R.Top + Len);
|
|
ACanvas.LineTo(R.Right, R.Top + Len);
|
|
end;
|
|
end;
|
|
finally
|
|
Pen.Mode := pmCopy;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.PaintHeaderAlignment(ACanvas: TCanvas; ARect: TRect);
|
|
begin
|
|
{$IFDEF USE_THEMES}
|
|
if ThemedCells then with ThemeServices do
|
|
begin
|
|
Inc(ARect.Bottom);
|
|
DrawElement(ACanvas.Handle, GetElementDetails(thHeaderItemRightNormal), ARect)
|
|
end else
|
|
{$ENDIF}
|
|
begin
|
|
ACanvas.Brush.Color := FColors.FixedCellBkGnd;
|
|
Dec(ARect.Bottom);
|
|
ACanvas.FillRect(ARect);
|
|
if {$IFDEF FPC}not Flat{$ELSE}Ctl3D{$ENDIF} then
|
|
{$IFDEF USE_WINAPI}
|
|
// looks somewhat better though
|
|
DrawEdge(ACanvas.Handle, ARect, BDR_RAISEDINNER, BF_LEFT or BF_TOP or BF_BOTTOM or BF_SOFT);
|
|
{$ELSE}
|
|
DrawEdges(ACanvas, ARect, cl3DHilight, cl3DShadow, BF_LEFT or BF_TOP or BF_BOTTOM);
|
|
{$ENDIF}
|
|
ACanvas.Brush.Color := FColors.FixedCellLines;
|
|
ACanvas.FillRect(Rect(ARect.Left, ARect.Bottom, ARect.Right, ARect.Bottom + 1));
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.PaintPage;
|
|
|
|
procedure Axis(const Info: TKGridAxisInfo; CanvasExtent, Page, SelStart, SelEnd: Integer;
|
|
SelOnly, FitToPage: Boolean; out FirstIndex, LastIndex, PageExtent: Integer);
|
|
var
|
|
I, Extent, StartIndex, EndIndex, Pages: Integer;
|
|
begin
|
|
Pages := 1;
|
|
PageExtent := 0;
|
|
if SelOnly then
|
|
begin
|
|
StartIndex := SelStart;
|
|
EndIndex := SelEnd;
|
|
end else
|
|
begin
|
|
StartIndex := 0;
|
|
EndIndex := Info.TotalCellCount - 1;
|
|
end;
|
|
FirstIndex := StartIndex;
|
|
LastIndex := StartIndex;
|
|
for I := StartIndex to EndIndex do
|
|
begin
|
|
Extent := Info.CellExtent(I) + Info.EffectiveSpacing(I);
|
|
if FitToPage or (PageExtent + Extent < CanvasExtent) or (I = 0) then
|
|
Inc(PageExtent, Extent)
|
|
else
|
|
begin
|
|
FirstIndex := LastIndex;
|
|
LastIndex := I;
|
|
if Page = Pages then
|
|
begin
|
|
Dec(LastIndex);
|
|
Exit;
|
|
end;
|
|
Inc(Pages);
|
|
PageExtent := Extent;
|
|
end;
|
|
end;
|
|
FirstIndex := LastIndex;
|
|
LastIndex := EndIndex;
|
|
end;
|
|
|
|
var
|
|
FirstCol, FirstRow, LastCol, LastRow, OutlineWidth, OutlineHeight, AreaWidth, AreaHeight: Integer;
|
|
FitToPage, SelOnly{$IFDEF LCLQT}, AThemedCells{$ENDIF}: Boolean;
|
|
TmpRect, TmpRect1: TRect;
|
|
MainClipRgn: HRGN;
|
|
R: TKGridRect;
|
|
APageSetup: TKPrintPageSetup;
|
|
// CellBitmap: TBitmap;
|
|
begin
|
|
R := InternalExpandGridRect(Selection);
|
|
NormalizeGridRect(R);
|
|
APageSetup := PageSetup;
|
|
FitToPage := poFitToPage in APageSetup.Options;
|
|
SelOnly := APageSetup.Range = prSelectedOnly;
|
|
AreaWidth := Round(APageSetup.PaintAreaWidth / APageSetup.CurrentScale);
|
|
AreaHeight := Round(APageSetup.PaintAreaHeight / APageSetup.CurrentScale);
|
|
Axis(GetAxisInfoHorz([]), AreaWidth, (APageSetup.CurrentPage - 1) mod APageSetup.HorzPageCount + 1,
|
|
R.Col1, R.Col2, SelOnly, FitToPage, FirstCol, LastCol, OutlineWidth);
|
|
Axis(GetAxisInfoVert([]), AreaHeight, (APageSetup.CurrentPage - 1) div APageSetup.HorzPageCount + 1,
|
|
R.Row1, R.Row2, SelOnly, False, FirstRow, LastRow, OutlineHeight);
|
|
if poUseColor in APageSetup.Options then
|
|
FColors.ColorScheme := csNormal
|
|
else
|
|
FColors.ColorScheme := csGrayScale;
|
|
TmpRect := Rect(0, 0, OutlineWidth, OutlineHeight);
|
|
TmpRect1 := Rect(0, 0, AreaWidth, AreaHeight);
|
|
IntersectRect(TmpRect, TmpRect, TmpRect1);
|
|
TranslateRectToDevice(APageSetup.Canvas.Handle, TmpRect);
|
|
{$IFDEF LCLQT}
|
|
AThemedCells := goThemedCells in FOptions;
|
|
Exclude(FOptions, goThemedCells);
|
|
{$ENDIF}
|
|
MainClipRgn := CreateRectRgnIndirect(TmpRect);
|
|
// if goDoubleBufferedCells in FOptions then
|
|
// CellBitmap := TBitmap.Create
|
|
// else
|
|
// CellBitmap := nil;
|
|
try
|
|
SelectClipRgn(APageSetup.Canvas.Handle, MainClipRgn);
|
|
TmpRect := SelectionRect;
|
|
if SelOnly then
|
|
OffsetRect(TmpRect, -TmpRect.Left, -TmpRect.Top);
|
|
PaintCells(PageSetup.Canvas, nil, MainClipRgn, FirstCol, LastCol, FirstRow, LastRow,
|
|
0, 0, OutlineWidth, OutlineHeight, True, poPaintSelection in APageSetup.Options, TmpRect);
|
|
finally
|
|
DeleteObject(MainClipRgn);
|
|
// CellBitmap.Free;
|
|
{$IFDEF LCLQT}
|
|
if AThemedCells then
|
|
Include(FOptions, goThemedCells);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.PaintSizingSuggestion(ACanvas: TCanvas);
|
|
var
|
|
Info: TKGridAxisInfo;
|
|
I: Integer;
|
|
begin
|
|
case FSizingStyle of
|
|
ssLine, ssXORLine:
|
|
begin
|
|
with ACanvas do
|
|
begin
|
|
Pen.Width := 1;
|
|
if FSizingStyle = ssLine then
|
|
Pen.Color := clRed
|
|
else
|
|
begin
|
|
Pen.Mode := pmXOR;
|
|
Pen.Color := clWhite;
|
|
end;
|
|
try
|
|
case FGridState of
|
|
gsColSizing:
|
|
begin
|
|
Info := GetAxisInfoVert([aiGridBoundary]);
|
|
for I := 0 to 1 do
|
|
begin
|
|
ACanvas.MoveTo(FSizingDest + I, 0);
|
|
ACanvas.LineTo(FSizingDest + I, Info.GridBoundary);
|
|
end;
|
|
end;
|
|
gsRowSizing:
|
|
begin
|
|
Info := GetAxisInfoHorz([aiGridBoundary]);
|
|
for I := 0 to 1 do
|
|
begin
|
|
ACanvas.MoveTo(0, FSizingDest + I);
|
|
ACanvas.LineTo(Info.GridBoundary, FSizingDest + I);
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
Pen.Mode := pmCopy;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.PaintToCanvas(ACanvas: TCanvas);
|
|
var
|
|
I, Bottom, ClientH, ClientW, GridW, GridH, SaveIndex: Integer;
|
|
TmpExtent: TPoint;
|
|
TmpRect: TRect;
|
|
CurClipRgn, MainClipRgn: HRGN;
|
|
DC: HDC;
|
|
CellBitmap: TBitmap;
|
|
Info: TKGridAxisInfoBoth;
|
|
TmpBlockRect: TRect;
|
|
begin
|
|
DC := ACanvas.Handle;
|
|
SaveIndex := SaveDC(DC); // don't delete
|
|
ACanvas.Lock;
|
|
try
|
|
if Enabled or (FDisabledDrawStyle = ddNormal) then
|
|
FColors.ColorScheme := csNormal
|
|
else if FDisabledDrawStyle = ddGrayed then
|
|
FColors.ColorScheme := csGrayed
|
|
else
|
|
FColors.ColorScheme := csBright;
|
|
ClientH := ClientHeight;
|
|
ClientW := ClientWidth;
|
|
Info := GetAxisInfoBoth([aiFixedParams]);
|
|
GridW := 0; GridH := 0;
|
|
TmpExtent := Point(0, 0);
|
|
if (goDoubleBufferedCells in FOptions) and not DoubleBuffered then
|
|
CellBitmap := TBitmap.Create
|
|
else
|
|
CellBitmap := nil;
|
|
MainClipRgn := CreateEmptyRgn;
|
|
CurClipRgn := CreateEmptyRgn;
|
|
try
|
|
TmpBlockRect := SelectionRect;
|
|
if GetClipRgn(DC, MainClipRgn) <> 1 then
|
|
begin
|
|
DeleteObject(MainClipRgn);
|
|
TmpRect := Rect(0, 0, ClientW, ClientH);
|
|
TranslateRectToDevice(DC, TmpRect);
|
|
MainClipRgn := CreateRectRgnIndirect(TmpRect);
|
|
end;
|
|
// draw clipped selectable cells first (to avoid some GTK clipping problems)
|
|
TmpRect := Rect(Info.Horz.FixedBoundary, Info.Vert.FixedBoundary, ClientW, ClientH);
|
|
if not IsRectEmpty(TmpRect) then
|
|
begin
|
|
TranslateRectToDevice(DC, TmpRect);
|
|
if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then
|
|
begin
|
|
TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, FTopLeft.Col, FColCount - 1, FTopLeft.Row, FRowCount - 1,
|
|
Info.Horz.FixedBoundary - FScrollOffset.X, Info.Vert.FixedBoundary - FScrollOffset.Y, ClientW, ClientH, False, True, TmpBlockRect);
|
|
end;
|
|
end;
|
|
GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y);
|
|
// clipped fixed rows
|
|
TmpRect := Rect(Info.Horz.FixedBoundary, 0, ClientW, Info.Vert.FixedBoundary);
|
|
if not IsRectEmpty(TmpRect) then
|
|
begin
|
|
TranslateRectToDevice(DC, TmpRect);
|
|
if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then
|
|
TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, FTopLeft.Col, FColCount - 1, 0, FFixedRows - 1,
|
|
Info.Horz.FixedBoundary - FScrollOffset.X, 0, ClientW, ClientH, False, True, TmpBlockRect);
|
|
end;
|
|
GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y);
|
|
// clipped fixed columns
|
|
TmpRect := Rect(0, Info.Vert.FixedBoundary, Info.Horz.FixedBoundary, ClientH);
|
|
if not IsRectEmpty(TmpRect) then
|
|
begin
|
|
TranslateRectToDevice(DC, TmpRect);
|
|
if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then
|
|
TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, 0, FFixedCols - 1, FTopLeft.Row, FRowCount - 1, 0,
|
|
Info.Vert.FixedBoundary - FScrollOffset.Y, ClientW, ClientH, False, True, TmpBlockRect);
|
|
end;
|
|
GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y);
|
|
// non-clipped fixed cells
|
|
TmpRect := Rect(0, 0, Info.Horz.FixedBoundary, Info.Vert.FixedBoundary);
|
|
if not IsRectEmpty(TmpRect) then
|
|
begin
|
|
TranslateRectToDevice(DC, TmpRect);
|
|
if ExtSelectClipRectEx(DC, TmpRect, RGN_AND, CurClipRgn, MainClipRgn) then
|
|
TmpExtent := PaintCells(ACanvas, CellBitmap, CurClipRgn, 0, FFixedCols - 1, 0, FFixedRows - 1,
|
|
0, 0, ClientW, ClientH, False, True, TmpBlockRect);
|
|
end;
|
|
GridW := Max(GridW, TmpExtent.X); GridH := Max(GridH, TmpExtent.Y);
|
|
finally
|
|
FinalizePrevRgn(DC, MainClipRgn);
|
|
DeleteObject(CurClipRgn);
|
|
CellBitmap.Free;
|
|
end;
|
|
// draw a focus rectangle around cells in goRangeSelect and goRowSelect mode
|
|
if not (csDesigning in ComponentState) and (goDrawFocusSelected in FOptions) and
|
|
(FOptions * [goRangeSelect, goRowSelect] <> []) and Focused and not EditorMode then
|
|
begin
|
|
// to ensure coming DrawFocusRect will be painted correctly:
|
|
SetBkColor(DC, $FFFFFF);
|
|
SetTextColor(DC, 0);
|
|
ACanvas.DrawFocusRect(TmpBlockRect);
|
|
end;
|
|
// default color for client area parts not consumed by cells
|
|
ACanvas.Brush.Style := bsSolid;
|
|
// fill window client area parts not consumed by cells
|
|
if GridH < ClientH then
|
|
begin
|
|
ACanvas.Brush.Color := Color;
|
|
ACanvas.FillRect(Rect(0, GridH, GridW, ClientH));
|
|
end;
|
|
if GridW < ClientW then
|
|
begin
|
|
if (goHeader in FOptions) and (goHeaderAlignment in FOptions) and (FFixedRows > 0) then
|
|
begin
|
|
Bottom := 0;
|
|
for I := 0 to FFixedRows - 1 do
|
|
Inc(Bottom, InternalGetRowHeights(I) + InternalGetEffectiveRowSpacing(I));
|
|
PaintHeaderAlignment(ACanvas, Rect(GridW, 0, ClientW, Bottom));
|
|
end else
|
|
Bottom := 0;
|
|
ACanvas.Brush.Color := Color;
|
|
ACanvas.FillRect(Rect(GridW, Bottom, ClientW, ClientH));
|
|
end;
|
|
if FGridState in [gsColMoving, gsRowMoving] then PaintDragSuggestion(ACanvas);
|
|
if FGridState in [gsColSizing, gsRowSizing] then PaintSizingSuggestion(ACanvas);
|
|
finally
|
|
RestoreDC(DC, SaveIndex);
|
|
Canvas.Unlock;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.PointToCell(Point: TPoint; OutSide: Boolean;
|
|
InvisibleCells: TKGridInvisibleCells; out HitCol, HitRow, SelCol, SelRow: Integer): Boolean;
|
|
|
|
function Axis1(const Info: TKGridAxisInfo; Coord: Integer; InVis1, InVis2: TKGridInvisibleCells): Integer;
|
|
var
|
|
I, PtBegin, PtEnd, PtEOFixed: Integer;
|
|
begin
|
|
Result := -1;
|
|
// check fixed cells
|
|
I := 0;
|
|
PtBegin := 0;
|
|
while (I < Info.FixedCellCount) and (Result < 0) do
|
|
begin
|
|
PtEnd := PtBegin + Info.CellExtent(I) + Info.EffectiveSpacing(I);
|
|
if (InvisibleCells in [icNone, InVis1]) {or (Info.FixedSelectable and (Info.FirstGridCell = Info.FixedCellCount)) } and
|
|
(Coord >= PtBegin) and (Coord < PtEnd) then
|
|
Result := I;
|
|
PtBegin := PtEnd;
|
|
Inc(I);
|
|
end;
|
|
if (Result < 0) then
|
|
begin
|
|
PtEOFixed := PtBegin - Info.ScrollOffset;
|
|
I := Info.FirstGridCell;
|
|
if (Coord < PtEOFixed) and (InvisibleCells in [InVis2, icCells]) then
|
|
begin
|
|
// check the invisible cells to the left or top
|
|
PtEnd := PtEOFixed;
|
|
while (I > Info.FixedCellCount) and (Result < 0) do
|
|
begin
|
|
Dec(I);
|
|
PtBegin := PtEnd - Info.CellExtent(I) - Info.EffectiveSpacing(I);
|
|
if (Coord >= PtBegin) and (Coord < PtEnd) then
|
|
Result := I;
|
|
PtEnd := PtBegin;
|
|
end;
|
|
if OutSide and (Result < 0) then
|
|
if Info.FixedSelectable then
|
|
Result := 0
|
|
else
|
|
Result := Info.FixedCellCount;
|
|
end else
|
|
begin
|
|
// check visible cells and invisible ones to the right or bottom
|
|
PtBegin := PtEOFixed;
|
|
while (I < Info.TotalCellCount) and (Result < 0) do
|
|
begin
|
|
PtEnd := PtBegin + Info.CellExtent(I) + Info.EffectiveSpacing(I);
|
|
if (Coord >= PtBegin) and (Coord < PtEnd) then
|
|
Result := I;
|
|
PtBegin := PtEnd;
|
|
Inc(I);
|
|
end;
|
|
if OutSide and (Result < 0) then
|
|
Result := Info.TotalCellCount - 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function Axis2(const Info: TKGridAxisInfo; Index: Integer): Integer;
|
|
begin
|
|
if Index = Info.FixedCellCount then
|
|
begin
|
|
// some first nonfixed columns or rows may be hidden, so take first visible column/row
|
|
while (Index < Info.TotalCellCount) and (Info.CellExtent(Index) = 0) do
|
|
Inc(Index);
|
|
if Index >= Info.TotalCellCount then
|
|
Index := Info.FixedCellCount;
|
|
end
|
|
else if Index = Info.TotalCellCount - 1 then
|
|
begin
|
|
// some last columns or rows may be hidden, so take last visible column/row
|
|
while (Index >= Info.FixedCellCount) and (Info.CellExtent(Index) = 0) do
|
|
Dec(Index);
|
|
if Index < Info.FixedCellCount then
|
|
Index := Info.TotalCellCount - 1;
|
|
end;
|
|
Result := Index;
|
|
end;
|
|
|
|
var
|
|
Info: TKGridAxisInfo;
|
|
begin
|
|
Result := False;
|
|
Info := GetAxisInfoHorz([]);
|
|
HitCol := Axis1(Info, Point.X, icFixedRows, icFixedCols);
|
|
if HitCol >= 0 then
|
|
begin
|
|
if OutSide then SelCol := Axis2(Info ,HitCol) else SelCol := HitCol;
|
|
Info := GetAxisInfoVert([]);
|
|
HitRow := Axis1(Info, Point.Y, icFixedCols, icFixedRows);
|
|
if HitRow >= 0 then
|
|
begin
|
|
if OutSide then SelRow := Axis2(Info, HitRow) else SelRow := HitRow;
|
|
Result := True;
|
|
end;
|
|
end
|
|
end;
|
|
|
|
function TKCustomGrid.PointToSizing(Point: TPoint; var State: TKGridState;
|
|
var Index, Pos: Integer): Boolean;
|
|
|
|
function AxisSizing(const Info: TKGridAxisInfo; Coord: Integer;
|
|
var Index, Pos: Integer): Boolean;
|
|
const
|
|
cDelta = 3;
|
|
var
|
|
I, ICopy, Dummy, ES, Line, StartCell: Integer;
|
|
begin
|
|
Result := False;
|
|
if (Info.FullVisCells < Info.GridCells) and
|
|
(Coord >= Info.ClientExtent - cDelta) and (Coord <= Info.ClientExtent) then
|
|
begin
|
|
Index := Info.FullVisCells;
|
|
Pos := Info.ClientExtent;
|
|
Result := True;
|
|
end else
|
|
begin
|
|
Line := Info.FullVisBoundary;
|
|
StartCell := Info.FullVisCells - 1;
|
|
for I := StartCell downto Info.FirstGridCell do
|
|
begin
|
|
ES := Info.EffectiveSpacing(I);
|
|
ICopy := I;
|
|
if ((I < StartCell) or not Info.AlignLastCell) and
|
|
({(Info.CellExtent(I) <> 0) or (I = StartCell) and} Info.CanResize(ICopy, Dummy)) and
|
|
(Coord >= Line - ES - cDelta) and (Coord <= Line + cDelta) then
|
|
begin
|
|
Index := I;
|
|
Pos := Line;
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
Dec(Line, Info.CellExtent(I) + ES);
|
|
end;
|
|
if not Result then
|
|
begin
|
|
Line := Info.FixedBoundary;
|
|
for I := Info.FixedCellCount - 1 downto 0 do
|
|
begin
|
|
ES := Info.EffectiveSpacing(I);
|
|
ICopy := I;
|
|
if (Coord >= Line - ES - cDelta) and (Coord <= Line + cDelta) and Info.CanResize(ICopy, Dummy) then
|
|
begin
|
|
Index := I;
|
|
Pos := Line;
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
Dec(Line, Info.CellExtent(I) + ES);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
EffColSizing, EffRowSizing: Boolean;
|
|
Info: TKGridAxisInfoBoth;
|
|
begin
|
|
Result := False;
|
|
EffColSizing := (goColSizing in FOptions) or (csDesigning in ComponentState);
|
|
EffRowSizing := (goRowSizing in FOptions) or (csDesigning in ComponentState);
|
|
if EffColSizing or EffRowSizing then
|
|
begin
|
|
Info := GetAxisInfoBoth([aiFullVisBoundary, aiGridBoundary]);
|
|
if EffColSizing and AxisSizing(Info.Horz, Point.X, Index, Pos) and
|
|
((Point.Y < Info.Vert.FixedBoundary) or (Point.Y < Info.Vert.GridBoundary) and
|
|
(InternalGetColWidths(Index) = 0)) then
|
|
begin
|
|
Result := True;
|
|
State := gsColSizing;
|
|
end
|
|
else if EffRowSizing and AxisSizing(Info.Vert, Point.Y, Index, Pos) and
|
|
((Point.X < Info.Horz.FixedBoundary) or (Point.X < Info.Horz.GridBoundary) and
|
|
(InternalGetRowHeights(Index) = 0)) then
|
|
begin
|
|
Result := True;
|
|
State := gsRowSizing;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ProcessDragWindow(const PtIni, PtCur: TPoint; Index: Integer; ColDrag, Hide: Boolean);
|
|
var
|
|
MaxWidth, MaxHeight: Integer;
|
|
Alpha: Byte;
|
|
Gradient: Boolean;
|
|
RClip, RSrc, RDest: TRect;
|
|
P: TKGridCoord;
|
|
Form: TCustomForm;
|
|
Info: TKGridAxisInfoBoth;
|
|
begin
|
|
if FDragStyle in [dsLayeredConst, dsLayeredFaded] then
|
|
begin
|
|
if Index >= 0 then
|
|
begin
|
|
// (re)initialize drag image bitmaps
|
|
if ColDrag then
|
|
P := GridPoint(Index, 0)
|
|
else
|
|
P := GridPoint(0, Index);
|
|
if CellToPoint(P.Col, P.Row, RSrc.TopLeft) then
|
|
begin
|
|
Form := GetParentForm(Self);
|
|
if Form <> nil then
|
|
begin
|
|
MaxWidth := Min(ClientWidth, Form.ClientWidth - Left);
|
|
MaxHeight := Min(ClientHeight, Form.ClientHeight - Top);
|
|
end else
|
|
begin
|
|
MaxWidth := ClientWidth;
|
|
MaxHeight := ClientHeight;
|
|
end;
|
|
Info := GetAxisInfoBoth([aiGridBoundary]);
|
|
if ColDrag then
|
|
begin
|
|
RSrc.Right := RSrc.Left + GetColWidths(Index);
|
|
RSrc.Bottom := Info.Vert.GridBoundary;
|
|
RClip := Rect(Info.Horz.FixedBoundary, 0, MaxWidth, MaxHeight);
|
|
end else
|
|
begin
|
|
RSrc.Bottom := RSrc.Top + GetRowHeights(Index);
|
|
RSrc.Right := Info.Horz.GridBoundary;
|
|
RClip := Rect(0, Info.Vert.FixedBoundary, MaxWidth, MaxHeight);
|
|
end;
|
|
if IntersectRect(RDest, RSrc, RClip) then
|
|
begin
|
|
if FDragWindow = nil then FDragWindow := TKDragWindow.Create;
|
|
if FDragStyle = dsLayeredFaded then
|
|
begin
|
|
Alpha := $E0;
|
|
Gradient := True;
|
|
end else
|
|
begin
|
|
Alpha := $80;
|
|
Gradient := False;
|
|
end;
|
|
EditorMode := False;
|
|
Update;
|
|
FDragWindow.Show(Self, RDest, PtIni, PtCur, Alpha, Gradient);
|
|
end;
|
|
end;
|
|
end
|
|
else if FDragWindow <> nil then
|
|
begin
|
|
if Hide then
|
|
FDragWindow.Hide
|
|
else
|
|
FDragWindow.Move(PtCur);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.RealizeCellClass;
|
|
var
|
|
I, J: Integer;
|
|
Cell, TmpCell: TKGridCell;
|
|
UpdateNeeded: Boolean;
|
|
begin
|
|
if Assigned(FCells) then
|
|
begin
|
|
UpdateNeeded := False;
|
|
for I := 0 to FColCount - 1 do
|
|
for J := 0 to FRowCount - 1 do
|
|
begin
|
|
Cell := FCells[J, I];
|
|
if (Cell <> nil) and (Cell.ClassType <> FCellClass) then
|
|
begin
|
|
TmpCell := FCellClass.Create(Self);
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
TmpCell.Assign(Cell); // copy known properties
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
Cell.Free;
|
|
FCells[J, I] := TmpCell;
|
|
UpdateNeeded := True;
|
|
end;
|
|
end;
|
|
if UpdateNeeded then
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.RealizeColClass;
|
|
var
|
|
I: Integer;
|
|
TmpItem: TKGridAxisItem;
|
|
UpdateNeeded: Boolean;
|
|
begin
|
|
UpdateNeeded := False;
|
|
for I := 0 to FColCount - 1 do
|
|
if FCols[I].ClassType <> FColClass then
|
|
begin
|
|
TmpItem := FColClass.Create(Self);
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
TmpItem.Assign(FCols[I]);
|
|
TmpItem.InitialPos := FCols[I].InitialPos;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
FCols[I].Free;
|
|
FCols[I] := TmpItem;
|
|
UpdateNeeded := True;
|
|
end;
|
|
if UpdateNeeded then
|
|
UpdateAxes(True, cAll, False, cAll, []);
|
|
end;
|
|
|
|
procedure TKCustomGrid.RealizeRowClass;
|
|
var
|
|
I: Integer;
|
|
TmpItem: TKGridAxisItem;
|
|
UpdateNeeded: Boolean;
|
|
begin
|
|
UpdateNeeded := False;
|
|
for I := 0 to FRowCount - 1 do
|
|
if FRows[I].ClassType <> FRowClass then
|
|
begin
|
|
TmpItem := FRowClass.Create(Self);
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
TmpItem.Assign(FRows[I]);
|
|
TmpItem.InitialPos := FRows[I].InitialPos;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
FRows[I].Free;
|
|
FRows[I] := TmpItem;
|
|
UpdateNeeded := True;
|
|
end;
|
|
if UpdateNeeded then
|
|
UpdateAxes(False, cAll, True, cAll, []);
|
|
end;
|
|
|
|
procedure TKCustomGrid.ReadColWidths(Reader: TReader);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Reader do
|
|
begin
|
|
ReadListBegin;
|
|
for I := 0 to FColCount - 1 do ColWidths[I] := ReadInteger;
|
|
ReadListEnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ReadRowHeights(Reader: TReader);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Reader do
|
|
begin
|
|
ReadListBegin;
|
|
for I := 0 to FRowCount - 1 do RowHeights[I] := ReadInteger;
|
|
ReadListEnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ResetTopLeft;
|
|
begin
|
|
if (FTopLeft.Col <> FFixedCols) or (FTopLeft.Row <> FFixedRows) then
|
|
begin
|
|
FTopLeft := GridPoint(FFixedCols, FFixedRows);
|
|
Invalidate;
|
|
TopLeftChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.RowHeightsChanged(ARow: Integer);
|
|
begin
|
|
if Assigned(FOnRowHeightsChanged) then
|
|
FOnRowHeightsChanged(Self)
|
|
else if Assigned(FOnRowHeightsChangedEx) then
|
|
FOnRowHeightsChangedEx(Self, ARow)
|
|
end;
|
|
|
|
procedure TKCustomGrid.RowMoved(FromIndex, ToIndex: Integer);
|
|
begin
|
|
if Assigned(FOnRowMoved) then
|
|
FOnRowMoved(Self, FromIndex, ToIndex);
|
|
end;
|
|
|
|
function TKCustomGrid.RowSelectable(ARow: Integer): Boolean;
|
|
begin
|
|
Result := (ARow >= FFixedRows) and (ARow < FRowCount);
|
|
end;
|
|
|
|
function TKCustomGrid.RowSelected(ARow: Integer): Boolean;
|
|
begin
|
|
Result := RowInGridRect(ARow, FSelection);
|
|
end;
|
|
|
|
function TKCustomGrid.RowValid(ARow: Integer): Boolean;
|
|
begin
|
|
Result := (ARow >= 0) and (ARow < FRowCount);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SafeSetFocus;
|
|
var
|
|
Form: TCustomForm;
|
|
begin
|
|
Form := GetParentForm(Self);
|
|
if (Form <> nil) and Form.Visible and Form.Enabled and not (csDestroying in Form.ComponentState) then
|
|
if EditorMode and FEditor.Enabled then
|
|
Form.ActiveControl := FEditor
|
|
else if Visible and Enabled then
|
|
Form.ActiveControl := Self;
|
|
end;
|
|
|
|
procedure TKCustomGrid.Scroll(CodeHorz, CodeVert, DeltaHorz, DeltaVert: Integer;
|
|
CallUpdateEditor: Boolean);
|
|
|
|
function Axis(Code: Cardinal; HasScrollBar: Boolean; ScrollCode: Cardinal; Delta: Integer;
|
|
ScrollMode: TKGridScrollMode; const Info: TKGridAxisInfo;
|
|
var FirstGridCell, ScrollPos, ScrollOffset: Integer): Boolean;
|
|
|
|
procedure DoScroll(ADelta: Integer; OnlyIfGreater: Boolean = False);
|
|
var
|
|
I, TotalExtent: Integer;
|
|
begin
|
|
I := 0;
|
|
ScrollOffset := 0;
|
|
if ADelta > 0 then
|
|
begin
|
|
while (I < ADelta) and (FirstGridCell < Info.FirstGridCellExtent) do
|
|
begin
|
|
TotalExtent := Info.CellExtent(FirstGridCell) + Info.EffectiveSpacing(FirstGridCell);
|
|
if OnlyIfGreater then
|
|
if I + TotalExtent > ADelta then
|
|
begin
|
|
if ScrollMode = smSmooth then
|
|
ScrollOffset := ADelta - I;
|
|
Break;
|
|
end;
|
|
Inc(I, TotalExtent);
|
|
Inc(FirstGridCell);
|
|
end;
|
|
end
|
|
else if ADelta < 0 then
|
|
begin
|
|
while (I > ADelta) and (FirstGridCell > Info.FixedCellCount) do
|
|
begin
|
|
Dec(FirstGridCell);
|
|
TotalExtent := Info.CellExtent(FirstGridCell) + Info.EffectiveSpacing(FirstGridCell);
|
|
if OnlyIfGreater then
|
|
if I - TotalExtent < ADelta then
|
|
begin
|
|
if ScrollMode = smSmooth then
|
|
begin
|
|
ScrollOffset := ADelta - I + TotalExtent;
|
|
Dec(ScrollPos, TotalExtent);
|
|
end else
|
|
Inc(FirstGridCell);
|
|
Break;
|
|
end;
|
|
Dec(I, TotalExtent);
|
|
end;
|
|
end;
|
|
Inc(ScrollPos, I);
|
|
end;
|
|
|
|
var
|
|
OldScrollPos, OldScrollOffset: Integer;
|
|
SI: TScrollInfo;
|
|
begin
|
|
Result := False;
|
|
if HasScrollBar then
|
|
begin
|
|
FillChar(SI, SizeOf(TScrollInfo), 0);
|
|
SI.cbSize := SizeOf(TScrollInfo);
|
|
SI.fMask := SIF_PAGE or SIF_RANGE or SIF_TRACKPOS;
|
|
GetScrollInfo(Handle, Code, SI);
|
|
{$IF DEFINED(LCLGTK2)}
|
|
{.$WARNING "scrollbar arrows still not working properly on GTK2 in some cases!"}
|
|
SI.nTrackPos := Delta;
|
|
{$IFEND}
|
|
end;
|
|
OldScrollPos := ScrollPos;
|
|
OldScrollOffset := ScrollOffset;
|
|
if ScrollCode = Cardinal(cScrollDelta) then
|
|
DoScroll(Delta) // in Pixels!
|
|
else if HasScrollBar then
|
|
case ScrollCode of
|
|
SB_TOP:
|
|
begin
|
|
FirstGridCell := Info.FixedCellCount;
|
|
ScrollPos := SI.nMin;
|
|
ScrollOffset := 0;
|
|
end;
|
|
SB_BOTTOM:
|
|
begin
|
|
FirstGridCell := Info.FirstGridCellExtent;
|
|
ScrollPos := SI.nMax - Max(SI.nPage - 1, 0);
|
|
ScrollOffset := 0;
|
|
end;
|
|
SB_LINEUP: DoScroll(ScrollDeltaFromDelta(Info, -1));
|
|
SB_LINEDOWN: DoScroll(ScrollDeltaFromDelta(Info, 1));
|
|
SB_PAGEUP: DoScroll(-SI.nPage);
|
|
SB_PAGEDOWN: DoScroll(SI.nPage);
|
|
SB_THUMBTRACK, SB_THUMBPOSITION: DoScroll(SI.nTrackPos - ScrollPos, True);
|
|
end;
|
|
FirstGridCell := MinMax(FirstGridCell, Info.FixedCellCount, Info.FirstGridCellExtent);
|
|
if (ScrollPos <> OldScrollPos) or (ScrollOffset <> OldScrollOffset) then
|
|
begin
|
|
if HasScrollBar then
|
|
begin
|
|
FillChar(SI, SizeOf(TScrollInfo), 0);
|
|
SI.cbSize := SizeOf(TScrollInfo);
|
|
SI.fMask := SIF_POS;
|
|
SI.nPos := ScrollPos + ScrollOffset;
|
|
SetScrollInfo(Handle, Code, SI, True);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Horz, Vert: Boolean; //because of $B-
|
|
OldTopLeft: TKGridCoord;
|
|
begin
|
|
OldTopLeft := FTopLeft;
|
|
Horz := Axis(SB_HORZ, FScrollBars in [ssHorizontal, ssBoth], CodeHorz, DeltaHorz,
|
|
FScrollModeHorz, GetAxisInfoHorz([]), FTopLeft.Col, FScrollPos.x, FScrollOffset.X);
|
|
Vert := Axis(SB_VERT, FScrollBars in [ssVertical, ssBoth], CodeVert, DeltaVert,
|
|
FScrollModeVert, GetAxisInfoVert([]), FTopLeft.Row, FScrollPos.y, FScrollOffset.Y);
|
|
if Horz or Vert then
|
|
begin
|
|
if Horz then
|
|
InvalidateCols(FFixedCols);
|
|
if Vert then
|
|
InvalidateRows(FFixedRows);
|
|
if CallUpdateEditor then
|
|
UpdateEditor(Flag(cGF_EditorModeActive));
|
|
if (OldTopLeft.Col <> FTopLeft.Col) or (OldTopLeft.Row <> FTopLeft.Row) then
|
|
TopLeftChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ScrollBy(AColCount, ARowCount: Integer);
|
|
begin
|
|
Scroll(cScrollDelta, cScrollDelta,
|
|
ScrollDeltaFromDelta(GetAxisInfoHorz([]), AColCount),
|
|
ScrollDeltaFromDelta(GetAxisInfoVert([]), ARowCount),
|
|
True);
|
|
end;
|
|
|
|
function TKCustomGrid.ScrollDeltaFromDelta(const Info: TKGridAxisInfo; ADelta: Integer): Integer;
|
|
var
|
|
I, CellExtent, MaxIndex: Integer;
|
|
begin
|
|
Result := 0;
|
|
I := Info.FirstGridCell;
|
|
MaxIndex := Info.FirstGridCell + ADelta;
|
|
if ADelta > 0 then
|
|
begin
|
|
while (I < Info.FirstGridCellExtent) do
|
|
begin
|
|
CellExtent := Info.CellExtent(I);
|
|
Inc(Result, CellExtent + Info.EffectiveSpacing(I));
|
|
Inc(I);
|
|
if (CellExtent > 0) and (I >= MaxIndex) then
|
|
Break;
|
|
end;
|
|
end
|
|
else if ADelta < 0 then
|
|
begin
|
|
while (I > Info.FixedCellCount) do
|
|
begin
|
|
Dec(I);
|
|
CellExtent := Info.CellExtent(I);
|
|
Dec(Result, CellExtent + Info.EffectiveSpacing(I));
|
|
if (CellExtent > 0) and (I <= MaxIndex) then
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.ScrollNeeded(ACol, ARow: Integer;
|
|
out DeltaHorz, DeltaVert: Integer): Boolean;
|
|
|
|
function Axis(Info: TKGridAxisInfo; Index, Span: Integer; var Delta: Integer): Boolean;
|
|
var
|
|
I, Extent: Integer;
|
|
begin
|
|
Result := False;
|
|
Delta := 0;
|
|
if Index < Info.FixedCellCount then Exit;
|
|
if Index = Info.FirstGridCell then
|
|
begin
|
|
if Info.ScrollOffset <> 0 then
|
|
Result := True;
|
|
end;
|
|
if Index < Info.FirstGridCell then
|
|
begin
|
|
for I := Info.FirstGridCell - 1 downto Index do
|
|
Dec(Delta, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
Result := True;
|
|
end else
|
|
begin
|
|
Extent := Info.FixedBoundary - Info.ScrollOffset;
|
|
for I := Info.FirstGridCell to Index - 1 do
|
|
Inc(Extent, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
Delta := Extent;
|
|
for I := Index to Index + Span - 1 do
|
|
Inc(Delta, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
if Delta > Info.ClientExtent then
|
|
begin
|
|
Delta := Min(Extent - Info.FixedBoundary, Delta + Info.ScrollOffset - Info.ClientExtent);
|
|
if Delta > 0 then
|
|
Result := True;
|
|
end else
|
|
Delta := 0;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Horz, Vert: Boolean;
|
|
Span: TKGridCellSpan;
|
|
begin
|
|
DeltaHorz := 0; DeltaVert := 0;
|
|
Span := InternalGetCellSpan(ACol, ARow);
|
|
Horz := (FGridState <> gsRowMoving) and Axis(GetAxisInfoHorz([aiFixedParams]), ACol, Span.ColSpan, DeltaHorz);
|
|
Vert := (FGridState <> gsColMoving) and Axis(GetAxisInfoVert([aiFixedParams]), ARow, Span.RowSpan, DeltaVert);
|
|
Result := Horz or Vert;
|
|
end;
|
|
|
|
procedure TKCustomGrid.ScrollTimerHandler(Sender: TObject);
|
|
var
|
|
DeltaHorz, DeltaVert, HitCol, HitRow, SelCol, SelRow: Integer;
|
|
MousePt: TPoint;
|
|
begin
|
|
MousePt := ScreenToClient(Mouse.CursorPos);
|
|
if MouseCapture and not Dragging and
|
|
PointToCell(MousePt, True, GridStateToInvisibleCells, HitCol, HitRow,
|
|
SelCol, SelRow) and ScrollNeeded(HitCol, HitRow, DeltaHorz, DeltaVert) then
|
|
begin
|
|
Scroll(cScrollDelta, cScrollDelta, DeltaHorz, DeltaVert, False);
|
|
if FGridState = gsSelecting then
|
|
begin
|
|
InternalFindBaseCell(SelCol, SelRow, SelCol, SelRow);
|
|
SelectionMove(SelCol, SelRow, ssExpand, [sfMustUpdate])
|
|
end else
|
|
DragMove(HitCol, HitRow, MousePt);
|
|
end else
|
|
begin
|
|
FScrollTimer.Enabled := False;
|
|
UpdateEditor(Flag(cGF_EditorModeActive));
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectAll;
|
|
begin
|
|
if goRangeSelect in Options then
|
|
// aki:
|
|
if (gxEditFixedRows in FOptionsEx) and (gxEditFixedCols in FOptionsEx) then
|
|
Selection := GridRect(0, 0, FColCount - 1, FRowCount - 1)
|
|
else if gxEditFixedRows in FOptionsEx then
|
|
Selection := GridRect(FFixedCols, 0, FColCount - 1, FRowCount - 1)
|
|
else if gxEditFixedCols in FOptionsEx then
|
|
Selection := GridRect(0, FFixedRows, FColCount - 1, FRowCount - 1)
|
|
else
|
|
Selection := GridRect(FFixedCols, FFixedRows, FColCount - 1, FRowCount - 1);
|
|
end;
|
|
|
|
function TKCustomGrid.SelectCell(ACol, ARow: Integer): Boolean;
|
|
begin
|
|
// aki:
|
|
if (ColWidths[ACol] = 0) or (RowHeights[ARow] = 0) then
|
|
Result := False
|
|
else if (ARow < FFixedRows) and (not(gxEditFixedRows in FOptionsEx)) then
|
|
Result := False
|
|
else if not (gxEditFixedCols in FOptionsEx) and not (gxEditFixedRows in FOptionsEx) and (ACol < FFixedCols) then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnSelectCell) then
|
|
FOnSelectCell(Self, ACol, ARow, Result)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).SelectCell(ACol, ARow, Result);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectCol(ACol: Integer);
|
|
begin
|
|
if goRangeSelect in Options then
|
|
// aki:
|
|
if gxEditFixedRows in FOptionsEx then
|
|
Selection := GridRect(ACol, 0, ACol, FRowCount - 1)
|
|
else
|
|
Selection := GridRect(ACol, FFixedRows, ACol, FRowCount - 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectCols(FirstCol, Count: Integer);
|
|
begin
|
|
if goRangeSelect in Options then
|
|
// aki:
|
|
if gxEditFixedRows in FOptionsEx then
|
|
Selection := GridRect(FirstCol, 0, FirstCol + Count, FRowCount - 1)
|
|
else
|
|
Selection := GridRect(FirstCol, FFixedRows, FirstCol + Count, FRowCount - 1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectionChanged(NewSelection: TKGridRect;
|
|
Flags: TKGridSelectionFlags);
|
|
var
|
|
ICol, IRow: Integer;
|
|
begin
|
|
SelectionFix(NewSelection);
|
|
if FRangeSelectStyle = rsMS_Excel then
|
|
begin
|
|
ICol := NewSelection.Col2;
|
|
IRow := NewSelection.Row2;
|
|
end else
|
|
begin
|
|
ICol := NewSelection.Col1;
|
|
IRow := NewSelection.Row1;
|
|
end;
|
|
if (sfMustUpdate in Flags) and not GridRectEqual(FSelection, NewSelection) then
|
|
begin
|
|
InvalidateCurrentSelection;
|
|
FSelection := NewSelection;
|
|
if not (sfClampInView in Flags) or not ClampInView(ICol, IRow) then
|
|
InvalidateCurrentSelection;
|
|
end else
|
|
FSelection := NewSelection;
|
|
InvalidatePageSetup;
|
|
if not (sfNoMemPos in Flags) then
|
|
begin
|
|
FMemCol := ICol;
|
|
FMemRow := IRow;
|
|
end;
|
|
if sfMustUpdate in Flags then
|
|
UpdateEditor(Flag(cGF_EditorModeActive));
|
|
end;
|
|
|
|
function TKCustomGrid.SelectionExpand(ACol, ARow: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnSelectionExpand) then
|
|
FOnSelectionExpand(Self, ACol, ARow, Result)
|
|
else if Assigned(FCells) then
|
|
InternalGetCell(ACol, ARow).SelectionExpand(ACol, ARow, Result);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectionFix(var Sel: TKGridRect);
|
|
begin
|
|
//aki:
|
|
if (not (gxEditFixedCols in FOptionsEx) and (Sel.Row1 >= FFixedRows)) or (not (gxEditFixedRows in FOptionsEx) and (Sel.Row1 < FFixedRows)) then
|
|
begin
|
|
Sel.Col1 := MinMax(Sel.Col1, FFixedCols, FColCount - 1);
|
|
Sel.Col2 := MinMax(Sel.Col2, FFixedCols, FColCount - 1);
|
|
end else
|
|
begin
|
|
Sel.Col1 := MinMax(Sel.Col1, 0, FColCount - 1);
|
|
Sel.Col2 := MinMax(Sel.Col2, 0, FColCount - 1);
|
|
end;
|
|
if not (gxEditFixedRows in FOptionsEx) then
|
|
begin
|
|
Sel.Row1 := MinMax(Sel.Row1, FFixedRows, FRowCount - 1);
|
|
Sel.Row2 := MinMax(Sel.Row2, FFixedRows, FRowCount - 1);
|
|
end else
|
|
begin
|
|
Sel.Row1 := MinMax(Sel.Row1, 0, FRowCount - 1);
|
|
Sel.Row2 := MinMax(Sel.Row2, 0, FRowCount - 1);
|
|
end;
|
|
if not (goRangeSelect in FOptions) then
|
|
Sel.Cell2 := Sel.Cell1
|
|
end;
|
|
|
|
function TKCustomGrid.SelectionMove(ACol, ARow: Integer;
|
|
Stage: TKGridSelectionStage;
|
|
Flags: TKGridSelectionFlags): Boolean;
|
|
var
|
|
NewSelection: TKGridRect;
|
|
begin
|
|
Result := False;
|
|
if (Stage = ssExpand) and not (goRangeSelect in FOptions) then
|
|
Stage := ssInit;
|
|
case Stage of
|
|
ssInit:
|
|
begin
|
|
NewSelection := GridRect(ACol, ARow, ACol, ARow);
|
|
if not GridRectEqual(FSelection, NewSelection) and
|
|
((sfDontCallSelectCell in Flags) or SelectCell(ACol, ARow)) then
|
|
Result := True;
|
|
end;
|
|
ssExpand:
|
|
begin
|
|
NewSelection := FSelection;
|
|
if FRangeSelectStyle = rsMS_Excel then
|
|
begin
|
|
NewSelection.Cell2 := GridPoint(ACol, ARow);
|
|
if not GridRectEqual(FSelection, NewSelection) and
|
|
((sfDontCallSelectCell in Flags) or SelectionExpand(ACol, ARow)) then
|
|
Result := True;
|
|
end else
|
|
begin
|
|
NewSelection.Cell1 := GridPoint(ACol, ARow);
|
|
if not GridRectEqual(FSelection, NewSelection) and
|
|
((sfDontCallSelectCell in Flags) or SelectCell(ACol, ARow)) then
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
if Result then
|
|
SelectionChanged(NewSelection, Flags);
|
|
if not Result and GridRectEqual(NewSelection, FSelection) then
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectionNormalize;
|
|
var
|
|
R: TKGridRect;
|
|
begin
|
|
R := Selection;
|
|
NormalizeGridRect(R);
|
|
Selection := R;
|
|
end;
|
|
|
|
function TKCustomGrid.SelectionSet(const NewSelection: TKGridRect): Boolean;
|
|
begin
|
|
Result := False;
|
|
if not GridRectEqual(FSelection, NewSelection) then
|
|
begin
|
|
if ((FSelection.Col1 <> NewSelection.Col1) or (FSelection.Row1 <> NewSelection.Row1)
|
|
and SelectCell(NewSelection.Col1, NewSelection.Row1)) or
|
|
((FSelection.Col2 <> NewSelection.Col2) or (FSelection.Row2 <> NewSelection.Row2)
|
|
and SelectionExpand(NewSelection.Col2, NewSelection.Row2)) then
|
|
Result := True;
|
|
end;
|
|
if Result then
|
|
SelectionChanged(NewSelection, [sfMustUpdate, sfClampInView]);
|
|
// if not Result and GridRectEqual(NewSelection, FSelection) then
|
|
// Result := True;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectRow(ARow: Integer);
|
|
begin
|
|
if goRangeSelect in Options then
|
|
Selection := GridRect(FFixedCols, ARow, FColCount - 1, ARow);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SelectRows(FirstRow, Count: Integer);
|
|
begin
|
|
if goRangeSelect in Options then
|
|
Selection := GridRect(FFixedCols, FirstRow, FColCount - 1, FirstRow + Count);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetCell(ACol, ARow: Integer; Value: TKGridCell);
|
|
begin
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
InternalSetCell(ACol, ARow, Value);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetCellPainterClass(Value: TKGridCellPainterClass);
|
|
begin
|
|
if Value <> FCellPainterClass then
|
|
begin
|
|
FCellPainterClass := Value;
|
|
FCellPainter.Free;
|
|
FCellPainter := FCellPainterClass.Create(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetCells(ACol, ARow: Integer; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
|
|
begin
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
InternalSetCells(ACol, ARow, Text);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetCellSpan(ACol, ARow: Integer; Value: TKGridCellSpan);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
// cells cannot be merged across fixed area boundaries
|
|
if ACol >= FFixedCols then I := FColCount else I := FFixedCols;
|
|
Value.ColSpan := MinMax(Value.ColSpan, 1, I - ACol);
|
|
if ARow >= FFixedRows then I := FRowCount else I := FFixedRows;
|
|
Value.RowSpan := MinMax(Value.RowSpan, 1, I - ARow);
|
|
with InternalGetCell(ACol, ARow) do
|
|
if (ColSpan <> Value.ColSpan) or (RowSpan <> Value.RowSpan) then
|
|
begin
|
|
EditorMode := False;
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
InvalidateGridRect(InternalSetCellSpan(ACol, ARow, Value), False);
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetCol(Value: Integer);
|
|
begin
|
|
if ColSelectable(Value) and ((Value <> FSelection.Col1) or (FSelection.Col1 <> FSelection.Col2)) then
|
|
FocusCell(Value, Row);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetColCount(Value: Integer);
|
|
begin
|
|
if Value < 1 then Value := 1;
|
|
InternalSetColCount(Value);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetColWidths(Index: Integer; Value: Integer);
|
|
begin
|
|
if ColValid(Index) then
|
|
begin
|
|
if Value < InternalGetMinColWidth(Index) then
|
|
Value := 0
|
|
else
|
|
Value := Min(Value, InternalGetMaxColWidth(Index));
|
|
if Value <> FCols[Index].Extent then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FCols[Index].Extent := Value;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
UpdateAxes(True, Index, False, cAll, [afCallEvent, afCheckMinExtent]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetColors(Value: TKGridColors);
|
|
begin
|
|
FColors.Assign(Value);
|
|
end;
|
|
|
|
{$IFDEF FPC}
|
|
procedure TKCustomGrid.SetCursor(Value: TCursor);
|
|
begin
|
|
FTmpCursor := Value;
|
|
if (FCursor <> crHSplit) and (FCursor <> crVSplit) and
|
|
(FCursor <> crHResize) and (FCursor <> crVResize) then
|
|
inherited;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TKCustomGrid.SetDefaultColWidth(Value: Integer);
|
|
begin
|
|
if Value <> FDefaultColWidth then
|
|
begin
|
|
FDefaultColWidth := Value;
|
|
DefaultColWidthChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetDefaultDrawing(Value: Boolean);
|
|
begin
|
|
// does nothing
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetDefaultRowHeight(Value: Integer);
|
|
begin
|
|
if Value <> FDefaultRowHeight then
|
|
begin
|
|
FDefaultRowHeight := Value;
|
|
DefaultRowHeightChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetDisabledDrawStyle(Value: TKGridDisabledDrawStyle);
|
|
begin
|
|
if Value <> FDisabledDrawStyle then
|
|
begin
|
|
FDisabledDrawStyle := Value;
|
|
if not Enabled then
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetDragStyle(Value: TKGridDragStyle);
|
|
begin
|
|
if Value <> FDragStyle then
|
|
begin
|
|
CancelMode;
|
|
FDragStyle := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetEditorMode(Value: Boolean);
|
|
begin
|
|
if Value <> EditorMode then
|
|
UpdateEditor(Value);
|
|
FlagAssign(cGF_EditorModeActive, Value);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetEditorTransparency(Value: TKGridEditorTransparency);
|
|
begin
|
|
if Value <> FEditorTransparency then
|
|
begin
|
|
FEditorTransparency := Value;
|
|
if EditorMode then
|
|
FEditor.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetFixedCols(Value: Integer);
|
|
begin
|
|
if (Value <> FFixedCols) and (FFixedCols >= 0) then
|
|
InternalSetFixedCols(Value);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetFixedRows(Value: Integer);
|
|
begin
|
|
if (Value <> FFixedRows) and (FFixedRows >= 0) then
|
|
InternalSetFixedRows(Value);
|
|
end;
|
|
|
|
{$IFDEF FPC}
|
|
procedure TKCustomGrid.SetFlat(Value: Boolean);
|
|
begin
|
|
if Value <> FFlat then
|
|
begin
|
|
FFlat := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TKCustomGrid.SetGridLineWidth(Value: Integer);
|
|
begin
|
|
if FGridLineWidth <> Value then
|
|
begin
|
|
FGridLineWidth := Value;
|
|
UpdateAxes(FOptions * [goFixedHorzLine, goHorzLine] <> [], cAll,
|
|
FOptions * [goFixedVertLine, goVertLine] <> [], cAll, []);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetLeftCol(Value: Integer);
|
|
begin
|
|
if ColValid(Value) and (Value <> FTopLeft.Col) then
|
|
ScrollBy(Value - FTopLeft.Col, 0);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetMinColWidth(Value: Integer);
|
|
var
|
|
I, Extent, MinColWidth: Integer;
|
|
begin
|
|
Value := Max(Value, cMinColWidthMin);
|
|
if Value <> FMinColWidth then
|
|
begin
|
|
FMinColWidth := Value;
|
|
if FMinColWidth > FDefaultColWidth then
|
|
begin
|
|
FDefaultColWidth := FMinColWidth;
|
|
DefaultColWidthChanged;
|
|
end else
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
for I := 0 to FColCount - 1 do
|
|
begin
|
|
Extent := FCols[I].Extent;
|
|
MinColWidth := InternalGetMinColWidth(I);
|
|
if (Extent > 0) and (Extent < MinColWidth) then
|
|
FCols[I].Extent := MinColWidth;
|
|
end;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
UpdateAxes(True, cAll, False, cAll, []);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetMinRowHeight(Value: Integer);
|
|
var
|
|
I, Extent, MinRowHeight: Integer;
|
|
begin
|
|
Value := Max(Value, cMinRowHeightMin);
|
|
if Value <> FMinRowHeight then
|
|
begin
|
|
FMinRowHeight := Value;
|
|
if FMinRowHeight > FDefaultRowHeight then
|
|
begin
|
|
FDefaultRowHeight := FMinRowHeight;
|
|
DefaultRowHeightChanged;
|
|
end else
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
for I := 0 to FRowCount - 1 do
|
|
begin
|
|
Extent := FRows[I].Extent;
|
|
MinRowHeight := InternalGetMinRowHeight(I);
|
|
if (Extent > 0) and (Extent < MinRowHeight) then
|
|
FRows[I].Extent := MinRowHeight;
|
|
end;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
UpdateAxes(False, cAll, True, cAll, []);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetMouseCellHintTime(const AValue: Cardinal);
|
|
begin
|
|
FMouseCellHintTime := MinMax(AValue, cMouseCellHintTimeMin, cMouseCellHintTimeMax);
|
|
end;
|
|
|
|
function TKCustomGrid.SetMouseCursor(X, Y: Integer): Boolean;
|
|
var
|
|
ACursor: TCursor;
|
|
Index, Pos: Integer;
|
|
State: TKGridState;
|
|
begin
|
|
{$IFDEF FPC}
|
|
ACursor := FTmpCursor;
|
|
{$ELSE}
|
|
ACursor := Cursor;
|
|
{$ENDIF}
|
|
State := gsNormal;
|
|
Index := 0; Pos := 0;
|
|
PointToSizing(Point(X, Y), State, Index, Pos);
|
|
case State of
|
|
gsColSizing:
|
|
begin
|
|
FlagSet(cGF_DesignHitTest);
|
|
if (FCols[Index].Extent = 0) or (csDesigning in ComponentState) then
|
|
ACursor := crHSplit
|
|
else
|
|
ACursor := crHResize
|
|
end;
|
|
gsRowSizing:
|
|
begin
|
|
FlagSet(cGF_DesignHitTest);
|
|
if (FRows[Index].Extent = 0) or (csDesigning in ComponentState) then
|
|
ACursor := crVSplit
|
|
else
|
|
ACursor := crVResize;
|
|
end;
|
|
else
|
|
FlagClear(cGF_DesignHitTest);
|
|
end;
|
|
{$IFDEF FPC}
|
|
FCursor := ACursor;
|
|
SetTempCursor(ACursor);
|
|
{$ELSE}
|
|
Windows.SetCursor(Screen.Cursors[ACursor]);
|
|
{$ENDIF}
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetObjects(ACol, ARow: Integer; Value: TObject);
|
|
var
|
|
Cell, Tmp: TKGridCell;
|
|
begin
|
|
if Assigned(FCells) and ColValid(ACol) and RowValid(ARow) then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
Cell := InternalGetCell(ACol, ARow);
|
|
if not (Cell is TKGridObjectCell) then
|
|
begin
|
|
if FCellClass.InheritsFrom(TKGridObjectCell) then
|
|
Tmp := FCellClass.Create(Self)
|
|
else
|
|
Tmp := TKGridObjectCell.Create(Self);
|
|
Tmp.Assign(Cell);
|
|
Cell.Free;
|
|
FCells[ARow, ACol] := Tmp;
|
|
end;
|
|
TKGridObjectCell(FCells[ARow, ACol]).CellObject := Value;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
InvalidateCell(ACol, ARow);
|
|
end
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetOptions(Value: TKGridOptions);
|
|
const
|
|
UpdatePaintSet = [goClippedCells, goDrawFocusSelected, goDoubleBufferedCells,
|
|
goFixedHorzLine, goFixedVertLine, goHeader, goHeaderAlignment, goHorzLine,
|
|
goIndicateSelection, goIndicateHiddenCells, goThemedCells, goThemes, goVertLine];
|
|
UpdateScrollBarsSet = [goAlignLastCol, goAlignLastRow];
|
|
UpdateSelectionSet = [goRangeSelect, goRowSelect];
|
|
UpdateSortingSet = [goColSorting, goRowSorting];
|
|
var
|
|
UpdateCols, UpdatePaint, UpdateRows, UpdateScrollBars,
|
|
UpdateSelection, UpdateSorting, UpdateThemes, UpdateThemedCells,
|
|
UpdateVirtualGrid, WasVirtual: Boolean;
|
|
begin
|
|
if FOptions <> Value then
|
|
begin
|
|
UpdateCols := ((Value * [goHorzLine, goFixedHorzLine] = []) xor
|
|
(FOptions * [goHorzLine, goFixedHorzLine] = [])) or
|
|
((goIndicateHiddenCells in Value) <> (goIndicateHiddenCells in FOptions));
|
|
UpdateRows := ((Value * [goVertLine, goFixedVertLine] = []) xor
|
|
(FOptions * [goVertLine, goFixedVertLine] = [])) or
|
|
((goIndicateHiddenCells in Value) <> (goIndicateHiddenCells in FOptions));
|
|
UpdatePaint := Value * UpdatePaintSet <> FOptions * UpdatePaintSet;
|
|
UpdateScrollBars := Value * UpdateScrollBarsSet <> FOptions * UpdateScrollBarsSet;
|
|
UpdateSelection := Value * UpdateSelectionSet <> FOptions * UpdateSelectionSet;
|
|
UpdateSorting := Value * UpdateSortingSet <> FOptions * UpdateSortingSet;
|
|
UpdateThemes := (goThemes in Value) <> (goThemes in FOptions);
|
|
UpdateThemedCells := (goThemedCells in Value) <> (goThemedCells in FOptions);
|
|
UpdateVirtualGrid := (goVirtualGrid in Value) <> (goVirtualGrid in FOptions);
|
|
WasVirtual := goVirtualGrid in FOptions;
|
|
FOptions := Value;
|
|
if UpdateSelection then
|
|
SelectionFix(FSelection);
|
|
if UpdateCols or UpdateRows then
|
|
UpdateAxes(UpdateCols, cAll, UpdateRows, cAll, []);
|
|
if UpdateScrollBars or UpdateThemes then
|
|
{$IFDEF FPC}
|
|
UpdateSize;
|
|
{$ELSE}
|
|
RecreateWnd;
|
|
{$ENDIF}
|
|
if UpdateSorting then
|
|
ClearSortMode;
|
|
if UpdateVirtualGrid then
|
|
begin
|
|
if InternalUpdateVirtualGrid then
|
|
ChangeDataSize(False, 0, 0, False, 0, 0)
|
|
else if WasVirtual then
|
|
Include(FOptions, goVirtualGrid)
|
|
else
|
|
Exclude(FOptions, goVirtualGrid);
|
|
end;
|
|
if UpdatePaint or UpdateSelection or UpdateVirtualGrid then
|
|
begin
|
|
Invalidate;
|
|
InvalidatePageSetup;
|
|
end;
|
|
if UpdateThemedCells then
|
|
Include(FOptions, goMouseOverCells);
|
|
if not (goEditing in FOptions) then
|
|
EditorMode := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetOptionsEx(Value: TKGridOptionsEx);
|
|
const
|
|
UpdatePaintSet = [gxFixedThemedCells];
|
|
var
|
|
UpdatePaint: Boolean;
|
|
begin
|
|
if FOptionsEx <> Value then
|
|
begin
|
|
UpdatePaint := Value * UpdatePaintSet <> FOptionsEx * UpdatePaintSet;
|
|
FOptionsEx := Value;
|
|
if UpdatePaint then
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetRow(Value: Integer);
|
|
begin
|
|
if RowSelectable(Value) and ((Value <> FSelection.Row1) or (FSelection.Row1 <> FSelection.Row2)) then
|
|
FocusCell(Col, Value);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetRowCount(Value: Integer);
|
|
begin
|
|
if Value < 1 then Value := 1;
|
|
InternalSetRowCount(Value);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetRowHeights(Index: Integer; Value: Integer);
|
|
begin
|
|
if RowValid(Index) then
|
|
begin
|
|
if Value < InternalGetMinRowHeight(Index) then
|
|
Value := 0
|
|
else
|
|
Value := Min(Value, InternalGetMaxRowHeight(Index));
|
|
if Value <> FRows[Index].Extent then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FRows[Index].Extent := Value;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
UpdateAxes(False, cAll, True, Index, [afCallEvent, afCheckMinExtent]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetScrollBars(Value: TScrollStyle);
|
|
begin
|
|
if FScrollBars <> Value then
|
|
begin
|
|
FScrollBars := Value;
|
|
{$IFDEF FPC}
|
|
UpdateSize;
|
|
{$ELSE}
|
|
RecreateWnd;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetScrollModeHorz(const Value: TKGridScrollMode);
|
|
begin
|
|
if Value <> FScrollModeHorz then
|
|
begin
|
|
FScrollModeHorz := Value;
|
|
UpdateScrollRange(True, False, True);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetScrollModeVert(const Value: TKGridScrollMode);
|
|
begin
|
|
if Value <> FScrollModeVert then
|
|
begin
|
|
FScrollModeVert := Value;
|
|
UpdateScrollRange(False, True, True);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetScrollSpeed(Value: Cardinal);
|
|
begin
|
|
Value := MinMax(Integer(Value), cScrollSpeedMin, cScrollSpeedMax);
|
|
if Value <> FScrollSpeed then
|
|
begin
|
|
FScrollSpeed := Value;
|
|
FScrollTimer.Enabled := False;
|
|
FScrollTimer.Interval := FScrollSpeed;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetSelection(const Value: TKGridRect);
|
|
var
|
|
G: TKGridRect;
|
|
begin
|
|
if GridRectSelectable(Value) and not GridRectEqual(Value, FSelection) then
|
|
begin
|
|
InternalFindBaseCell(Value.Col1, Value.Row1, G.Col1, G.Row1);
|
|
InternalFindBaseCell(Value.Col2, Value.Row2, G.Col2, G.Row2);
|
|
SelectionSet(G);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetSelections(Index: Integer; const Value: TKGridRect);
|
|
begin
|
|
if (Index >= 0) and (Index < SelectionCount) then
|
|
begin
|
|
//TODO!
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetSizingStyle(Value: TKGridSizingStyle);
|
|
begin
|
|
if Value <> FSizingStyle then
|
|
begin
|
|
CancelMode;
|
|
FSizingStyle := Value;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetTabStops(Index: Integer; Value: Boolean);
|
|
begin
|
|
if ColValid(Index) and (FCols[Index] is TKGridCol) then
|
|
TKGridCol(FCols[Index]).TabStop := Value;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SetTopRow(Value: Integer);
|
|
begin
|
|
if RowValid(Value) and (Value <> FTopLeft.Row) then
|
|
ScrollBy(0, Value - FTopLeft.Row);
|
|
end;
|
|
|
|
procedure TKCustomGrid.ShowCellHint;
|
|
begin
|
|
DefaultMouseCellHint(FHintCell.Col, FHintCell.Row, True);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SizeChanged(Change: TKGridSizeChange;
|
|
Index, Count: Integer);
|
|
begin
|
|
if Assigned(FOnSizeChanged) then
|
|
FOnSizeChanged(Self, Change, Index, Count);
|
|
end;
|
|
|
|
procedure TKCustomGrid.SortCols(ByRow: Integer; SortMode: TKGridSortMode);
|
|
var
|
|
Sorted: Boolean;
|
|
OldSortMode: TKGridSortMode;
|
|
begin
|
|
if SortModeUnlocked and RowValid(ByRow) and (FRows[ByRow].SortMode <> SortMode) then
|
|
begin
|
|
OldSortMode := FRows[ByRow].SortMode;
|
|
ClearSortModeVert;
|
|
if FColCount > 1 then
|
|
begin
|
|
EditorMode := False;
|
|
Sorted := CustomSortCols(ByRow, SortMode);
|
|
if not Sorted and (SortMode <> smNone) then
|
|
begin
|
|
if OldSortMode <> smNone then
|
|
InternalFlip(FFixedCols, FColCount - 1, InternalExchangeCols)
|
|
else
|
|
InternalQuickSortNR(ByRow, FFixedCols, FColCount - 1, SortMode = smDown,
|
|
CompareCols, InternalExchangeCols);
|
|
end;
|
|
if Sorted or (SortMode <> smNone) then
|
|
begin
|
|
UpdateScrollRange(True, False, False);
|
|
UpdateCellSpan;
|
|
if not ClampInView(Col, Row) then
|
|
InvalidateCols(FFixedCols);
|
|
end;
|
|
if SortMode <> smNone then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FRows[ByRow].SortMode := SortMode;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
Row := ByRow;
|
|
end;
|
|
InvalidateGridRect(GridRect(0, ByRow, FFixedCols - 1, ByRow));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TKCustomGrid.SortModeUnlocked: Boolean;
|
|
begin
|
|
Result := FSortModeLock = 0;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SortRows(ByCol: Integer; SortMode: TKGridSortMode);
|
|
var
|
|
Sorted: Boolean;
|
|
OldSortMode: TKGridSortMode;
|
|
begin
|
|
if SortModeUnlocked and ColValid(ByCol) and (FCols[ByCol].SortMode <> SortMode) then
|
|
begin
|
|
OldSortMode := FCols[ByCol].SortMode;
|
|
ClearSortModeHorz;
|
|
if FRowCount > 1 then
|
|
begin
|
|
EditorMode := False;
|
|
Sorted := CustomSortRows(ByCol, SortMode);
|
|
if not Sorted and (SortMode <> smNone) then
|
|
begin
|
|
if OldSortMode <> smNone then
|
|
InternalFlip(FFixedRows, FRowCount - 1, InternalExchangeRows)
|
|
else
|
|
InternalQuickSortNR(ByCol, FFixedRows, FRowCount - 1, SortMode = smDown,
|
|
CompareRows, InternalExchangeRows);
|
|
end;
|
|
if Sorted or (SortMode <> smNone) then
|
|
begin
|
|
UpdateScrollRange(False, True, False);
|
|
UpdateCellSpan;
|
|
if not ClampInView(Col, Row) then
|
|
InvalidateRows(FFixedRows);
|
|
end;
|
|
if SortMode <> smNone then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FCols[ByCol].SortMode := SortMode;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
Col := ByCol;
|
|
end;
|
|
InvalidateGridRect(GridRect(ByCol, 0, ByCol, FFixedRows - 1));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SuggestDrag(State: TKGridCaptureState);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if HandleAllocated and GetDragRect(GetAxisInfoBoth([aiGridBoundary]), R) then
|
|
begin
|
|
if State = csStart then
|
|
begin
|
|
InvalidateCell(FHitCell.Col, FHitCell.Row);
|
|
Update;
|
|
end;
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.SuggestSizing(State: TKGridCaptureState);
|
|
|
|
function Axis(const Info: TKGridAxisInfo; CellPt: Integer; AxisItems: TKGridAxisItems): Integer;
|
|
var
|
|
Tmp, MinExtent: Integer;
|
|
begin
|
|
Result := Info.CellExtent(FSizingIndex);
|
|
MinExtent := Info.MinCellExtent(FSizingIndex);
|
|
if goMouseCanHideCells in FOptions then
|
|
begin
|
|
if Result > 0 then
|
|
begin
|
|
if FSizingDest - CellPt > Max(MinExtent div 2, MinExtent - 5) then
|
|
Result := Max(FSizingDest - CellPt, MinExtent)
|
|
else
|
|
Result := 0;
|
|
end else
|
|
begin
|
|
Tmp := FSizingIndex;
|
|
while (Tmp > 0) and (Info.CellExtent(Tmp - 1) = 0) do
|
|
Dec(Tmp);
|
|
if Tmp <> FSizingIndex then
|
|
Inc(CellPt, Info.EffectiveSpacing(Tmp));
|
|
if FSizingDest - CellPt >= MinExtent then
|
|
Result := FSizingDest - CellPt;
|
|
end;
|
|
end else
|
|
Result := Max(FSizingDest - CellPt, MinExtent);
|
|
end;
|
|
|
|
var
|
|
R: TRect;
|
|
Info: TKGridAxisInfo;
|
|
begin
|
|
if HandleAllocated then
|
|
begin
|
|
case FGridState of
|
|
gsColSizing:
|
|
begin
|
|
case FSizingStyle of
|
|
ssLine, ssXORLine:
|
|
begin
|
|
Info := GetAxisInfoVert([aiGridBoundary]);
|
|
R := Rect(FSizingDest, 0, FSizingDest + 2, Info.GridBoundary);
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
ssUpdate:
|
|
begin
|
|
if (State = csShow) and CellToPoint(FSizingIndex, 0, R.TopLeft) then
|
|
ColWidths[FSizingIndex] := Axis(GetAxisInfoHorz([]), R.Left, FCols);
|
|
end;
|
|
end;
|
|
end;
|
|
gsRowSizing:
|
|
begin
|
|
case FSizingStyle of
|
|
ssLine, ssXORLine:
|
|
begin
|
|
Info := GetAxisInfoHorz([aiGridBoundary]);
|
|
R := Rect(0, FSizingDest, Info.GridBoundary, FSizingDest + 2);
|
|
InvalidateRect(Handle, @R, False);
|
|
end;
|
|
ssUpdate:
|
|
begin
|
|
if (State = csShow) and CellToPoint(0, FSizingIndex, R.TopLeft) then
|
|
RowHeights[FSizingIndex] := Axis(GetAxisInfoVert([]), R.Top, FRows);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.TopLeftChanged;
|
|
begin
|
|
if Assigned(FOnTopLeftChanged) then
|
|
FOnTopLeftChanged(Self);
|
|
end;
|
|
|
|
procedure TKCustomGrid.UnlockSortMode;
|
|
begin
|
|
if FSortModeLock > 0 then
|
|
Dec(FSortModeLock);
|
|
end;
|
|
|
|
procedure TKCustomGrid.UnselectRange;
|
|
begin
|
|
Selection := GridRect(FSelection.Cell1);
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateAxes(Horz: Boolean; FirstCol: Integer;
|
|
Vert: Boolean; FirstRow: Integer; Flags: TKGridAxisUpdateFlags);
|
|
|
|
procedure Axis1(Info: TKGridAxisInfo; AxisItems: TKGridAxisItems;
|
|
var FirstIndex: Integer);
|
|
var
|
|
I, AExtent: Integer;
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
for I := 0 to Info.TotalCellCount - 1 do
|
|
begin
|
|
AExtent := Info.CellExtent(I);
|
|
if (AExtent > 0) and (AExtent < Info.MinCellExtent(I)) then
|
|
begin
|
|
AxisItems[I].Extent := 0;
|
|
FirstIndex := Min(FirstIndex, I);
|
|
end
|
|
else if AExtent > Info.MaxCellExtent(I) then
|
|
begin
|
|
AxisItems[I].Extent := Info.MaxCellExtent(I);
|
|
FirstIndex := Min(FirstIndex, I);
|
|
end;
|
|
end;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
end;
|
|
|
|
procedure Axis2(Info: TKGridAxisInfo; AxisItems: TKGridAxisItems;
|
|
var FirstIndex: Integer);
|
|
|
|
function CalcGridExtent(FixedExtent: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := FixedExtent;
|
|
for I := Info.FixedCellCount to Info.TotalCellCount - 1 do
|
|
Inc(Result, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
end;
|
|
|
|
var
|
|
I, CellExtent, Delta, FixedExtent, GridExtent: Integer;
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
FixedExtent := 0;
|
|
for I := 0 to Info.FixedCellCount - 1 do
|
|
Inc(FixedExtent, Info.CellExtent(I) + Info.EffectiveSpacing(I));
|
|
GridExtent := CalcGridExtent(FixedExtent);
|
|
if GridExtent <> Info.ClientExtent then
|
|
begin
|
|
if GridExtent < Info.ClientExtent then
|
|
begin
|
|
// cells would occupy a smaller area than Info.ClientExtent
|
|
// try to enlarge the last cell if visible:
|
|
I := Info.TotalCellCount - 1;
|
|
while (I >= Info.FixedCellCount) and (GridExtent < Info.ClientExtent) do
|
|
begin
|
|
CellExtent := Info.CellExtent(I);
|
|
if CellExtent <> 0 then
|
|
begin
|
|
Delta := Info.ClientExtent - GridExtent;
|
|
AxisItems[I].Extent := CellExtent + Delta;
|
|
Inc(GridExtent, Delta);
|
|
FirstIndex := Min(FirstIndex, I);
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
if I < Info.FixedCellCount then
|
|
begin
|
|
// apparently all cells are hidden. Try to unhide last cell
|
|
I := Info.TotalCellCount - 1;
|
|
AxisItems[I].Extent := Info.MinCellExtent(I);
|
|
GridExtent := CalcGridExtent(FixedExtent);
|
|
if GridExtent > Info.ClientExtent then
|
|
AxisItems[I].Extent := 0 //oops, does not fit, hide again, leave empty area
|
|
else
|
|
AxisItems[I].Extent := Info.CellExtent(I) + Info.ClientExtent - GridExtent;
|
|
end;
|
|
end else
|
|
begin
|
|
// cells would occupy a greater area than Info.ClientExtent
|
|
// try to decrease the extents of not fully visible cells
|
|
I := Info.TotalCellCount - 1;
|
|
while (I >= Info.FixedCellCount) and (GridExtent > Info.ClientExtent) do
|
|
begin
|
|
CellExtent := Info.CellExtent(I);
|
|
if CellExtent > Info.MinCellExtent(I) then
|
|
begin
|
|
Delta := Min(GridExtent - Info.ClientExtent, CellExtent - Info.MinCellExtent(I));
|
|
AxisItems[I].Extent := CellExtent - Delta;
|
|
Dec(GridExtent, Delta);
|
|
FirstIndex := Min(FirstIndex, I);
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
if GridExtent > Info.ClientExtent then
|
|
begin
|
|
// still everything not visible, hide some cells
|
|
I := Info.TotalCellCount - 1;
|
|
while (I >= Info.FixedCellCount) and (GridExtent > Info.ClientExtent) do
|
|
begin
|
|
CellExtent := Info.CellExtent(I);
|
|
if CellExtent > 0 then
|
|
begin
|
|
AxisItems[I].Extent := 0;
|
|
FirstIndex := Min(FirstIndex, I);
|
|
GridExtent := CalcGridExtent(FixedExtent);
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
if (GridExtent < Info.ClientExtent) and (I >= Info.FixedCellCount) then
|
|
begin
|
|
// cells would occupy a smaller area than Info.ClientExtent - 2nd test
|
|
I := Info.TotalCellCount - 1;
|
|
while (I >= Info.FixedCellCount) and (GridExtent < Info.ClientExtent) do
|
|
begin
|
|
CellExtent := Info.CellExtent(I);
|
|
if CellExtent <> 0 then
|
|
begin
|
|
Delta := Info.ClientExtent - GridExtent;
|
|
AxisItems[I].Extent := CellExtent + Delta;
|
|
Inc(GridExtent, Delta);
|
|
FirstIndex := Min(FirstIndex, I);
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ColIndex, RowIndex: Integer;
|
|
Info: TKGridAxisInfo;
|
|
begin
|
|
if not UpdateUnlocked then Exit;
|
|
if Horz then
|
|
begin
|
|
Info := GetAxisInfoHorz([]);
|
|
if FirstCol >= 0 then ColIndex := FirstCol else ColIndex := FColCount;
|
|
if afCheckMinExtent in Flags then
|
|
Axis1(Info, FCols, ColIndex);
|
|
if (goAlignLastCol in FOptions) then
|
|
begin
|
|
if FTopLeft.Col <> FFixedCols then
|
|
begin
|
|
FTopLeft.Col := FFixedCols;
|
|
TopLeftChanged;
|
|
end;
|
|
Axis2(Info, FCols, ColIndex);
|
|
end;
|
|
end;
|
|
if Vert then
|
|
begin
|
|
Info := GetAxisInfoVert([]);
|
|
if FirstRow >= 0 then RowIndex := FirstRow else RowIndex := FRowCount;
|
|
if afCheckMinExtent in Flags then
|
|
Axis1(Info, FRows, RowIndex);
|
|
if (goAlignLastRow in FOptions) then
|
|
begin
|
|
if FTopLeft.Row <> FFixedRows then
|
|
begin
|
|
FTopLeft.Row := FFixedRows;
|
|
TopLeftChanged;
|
|
end;
|
|
Axis2(Info, FRows, RowIndex);
|
|
end;
|
|
end;
|
|
UpdateScrollRange(Horz, Vert, False);
|
|
UpdateEditor(Flag(cGF_EditorModeActive));
|
|
if Horz then
|
|
begin
|
|
if ColIndex < FColCount then
|
|
ColWidthsChanged(ColIndex);
|
|
if FirstCol = cAll then
|
|
Invalidate
|
|
else if ColIndex < FColCount then
|
|
InvalidateCols(ColIndex);
|
|
end;
|
|
if Vert then
|
|
begin
|
|
if RowIndex < FRowCount then
|
|
RowHeightsChanged(RowIndex);
|
|
if FirstRow = cAll then
|
|
Invalidate
|
|
else if RowIndex < FRowCount then
|
|
InvalidateRows(RowIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateCellSpan;
|
|
|
|
function DoUpdate(FirstCol, FirstRow, LastCol, LastRow: Integer): Boolean;
|
|
var
|
|
I, J: Integer;
|
|
Span, RefSpan: TKGridCellSpan;
|
|
begin
|
|
Result := False;
|
|
RefSpan := MakeCellSpan(1, 1);
|
|
// don't make this too complicated, but maybe it is little bit slower:
|
|
// reset all negative spans
|
|
for I := FirstCol to LastCol - 1 do
|
|
for J := FirstRow to LastRow - 1 do
|
|
if FCells[J, I] <> nil then
|
|
begin
|
|
with FCells[J, I].Span do
|
|
if (ColSpan <= 0) or (RowSpan <= 0) then
|
|
FCells[J, I].Span := RefSpan;
|
|
end;
|
|
// create all spans
|
|
for I := FirstCol to LastCol - 1 do
|
|
for J := FirstRow to LastRow - 1 do
|
|
if FCells[J, I] <> nil then
|
|
begin
|
|
with FCells[J, I].Span do
|
|
if (ColSpan > 1) or (RowSpan > 1) then
|
|
begin
|
|
Result := True;
|
|
Span := MakeCellSpan(Min(ColSpan, LastCol - I), Min(RowSpan, LastRow - J));
|
|
FCells[J, I].Span := RefSpan;
|
|
InternalSetCellSpan(I, J, Span);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if Assigned(FCells) then
|
|
begin
|
|
FlagSet(cGF_GridUpdates);
|
|
try
|
|
// cells cannot be merged across fixed area boundaries
|
|
DoUpdate(0, 0, FFixedCols, FFixedRows);
|
|
DoUpdate(FFixedCols, 0, FColCount, FFixedRows);
|
|
DoUpdate(0, FFixedRows, FFixedCols, FRowCount);
|
|
if Flag(cGF_SelCellsMerged) then
|
|
if not DoUpdate(FFixedCols, FFixedRows, FColCount, FRowCount) then
|
|
FlagClear(cGF_SelCellsMerged);
|
|
finally
|
|
FlagClear(cGF_GridUpdates);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateDesigner;
|
|
var
|
|
ParentForm: TCustomForm;
|
|
begin
|
|
if (csDesigning in ComponentState) and HandleAllocated and
|
|
not (csUpdating in ComponentState) then
|
|
begin
|
|
ParentForm := GetParentForm(Self);
|
|
if Assigned(ParentForm) and Assigned(ParentForm.Designer) then
|
|
ParentForm.Designer.Modified;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateEditor(Show: Boolean);
|
|
|
|
procedure InternalEditorSetPos(R: TRect; CallResize: Boolean);
|
|
begin
|
|
// aki:
|
|
if ((FEditorCell.Col >= FTopLeft.Col) and ((FScrollOffset.X = 0) or (FEditorCell.Col > FTopLeft.Col)) or
|
|
(gxEditFixedCols in FOptionsEx) and (FEditorCell.Col < FFixedCols)) and
|
|
((FEditorCell.Row >= FTopLeft.Row) and ((FScrollOffset.Y = 0) or (FEditorCell.Row > FTopLeft.Row)) or
|
|
(gxEditFixedRows in FOptionsEx) and (FEditorCell.Row < FFixedRows)) then
|
|
begin
|
|
if CallResize then
|
|
EditorResize(FEditor, FEditorCell.Col, FEditorCell.Row, R);
|
|
with R do
|
|
begin
|
|
FEditor.Constraints.MaxWidth := Right - Left + 1;
|
|
FEditor.Constraints.MaxHeight := Bottom - Top + 1;
|
|
FEditor.Height := Bottom - Top;
|
|
FEditor.Width := Right - Left;
|
|
if gxEditorVCenter in FOptionsEx then
|
|
Inc(Top, (Bottom - Top - FEditor.Height) div 2);
|
|
if gxEditorHCenter in FOptionsEx then
|
|
Inc(Left, (Right - Left - FEditor.Width) div 2);
|
|
FEditor.SetBounds(Left, Top, FEditor.Width, FEditor.Height);
|
|
end;
|
|
end else
|
|
begin
|
|
// hide the editor in some way
|
|
FEditor.Left := - 10 - FEditor.Width;
|
|
FEditor.Top := - 10 - FEditor.Height;
|
|
end;
|
|
end;
|
|
|
|
procedure InternalEditorMove;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if (FEditor <> nil) and CellRect(FEditorCell.Col, FEditorCell.Row, R) then
|
|
begin
|
|
if not EqualRect(FEditorRect, R) then with R do
|
|
begin
|
|
FEditorRect := R;
|
|
InternalEditorSetPos(R, True);
|
|
SetControlClipRect(FEditor, R);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure InternalEditorCreate;
|
|
var
|
|
R: TRect;
|
|
PropInfo: PPropInfo;
|
|
P: TPoint;
|
|
ACell: TKGridCell;
|
|
begin
|
|
if (FEditor = nil) and HandleAllocated and Enabled and Visible then
|
|
begin
|
|
if CellRect(Col, Row, R) and SelectCell(Col, Row) then
|
|
begin
|
|
FEditorCell.Col := Col;
|
|
FEditorCell.Row := Row;
|
|
FEditor := EditorCreate(FEditorCell.Col, FEditorCell.Row);
|
|
if FEditor <> nil then
|
|
begin
|
|
if Assigned(FCells) then
|
|
begin
|
|
ACell := Cell[FEditorCell.Col, FEditorCell.Row];
|
|
if FEditedCell = nil then FEditedCell := TKGridCellClass(ACell.ClassType).Create(nil);
|
|
FEditedCell.Assign(ACell);
|
|
end;
|
|
FThroughClick := False;
|
|
FEditorRect := R;
|
|
TabStop := False;
|
|
FEditor.Visible := False;
|
|
FEditor.Align := alNone;
|
|
FEditor.Constraints.MinWidth := 0;
|
|
FEditor.Constraints.MinHeight := 0;
|
|
PropInfo := GetPropInfo(FEditor, 'AutoSize');
|
|
if PropInfo <> nil then
|
|
SetOrdProp(FEditor, PropInfo, Integer(False));
|
|
// I hope no other steps to delimit inplace editor's size
|
|
// some controls as TComboBox on Win cannot be arbitrary resized :-(
|
|
FEditor.ControlStyle := FEditor.ControlStyle - [csAcceptsControls, csFramed, csFixedWidth, csFixedHeight] {$IFDEF COMPILER7_UP} - [csParentBackground] {$ENDIF};
|
|
FEditor.TabStop := True;
|
|
InternalEditorSetPos(R, True); // call this here too to be compatible with all LCL widget sets
|
|
FEditor.Parent := Self;
|
|
FEditor.HandleNeeded;
|
|
InternalEditorSetPos(R, True);
|
|
SetControlClipRect(FEditor, R);
|
|
EditorDataFromGrid(FEditor, FEditorCell.Col, FEditorCell.Row);
|
|
FEditor.Visible := True; // Remark: don't set DoubleBuffered because not all editors support it!
|
|
EditorSelect(FEditor, FEditorCell.Col, FEditorCell.Row,
|
|
not (goNoSelEditText in FOptions), Flag(cGF_CaretToLeft), Flag(cGF_SelectedByMouse));
|
|
FlagClear(cGF_CaretToLeft);
|
|
SafeSetFocus;
|
|
if FThroughClick then
|
|
begin
|
|
P := FEditor.ScreenToClient(Mouse.CursorPos);
|
|
PostMessage(FEditor.Handle, LM_LBUTTONDOWN, 1, MakeLong(P.X, P.Y));
|
|
MouseCapture := False;
|
|
FlagSet(cGF_ThroughClick);
|
|
FThroughClick := False;
|
|
end;
|
|
InvalidateCurrentSelection;
|
|
FEditorWindowProc := FEditor.WindowProc;
|
|
FEditor.WindowProc := EditorWindowProc;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure InternalEditorDestroy;
|
|
var
|
|
Form: TCustomForm;
|
|
begin
|
|
if FEditor <> nil then
|
|
begin
|
|
FEditor.WindowProc := FEditorWindowProc;
|
|
Form := GetParentForm(Self);
|
|
if Assigned(Form) and (csDestroying in Form.ComponentState) then
|
|
Form := nil;
|
|
if FEditor.HandleAllocated then
|
|
EditorDataToGrid(FEditor, FEditorCell.Col, FEditorCell.Row);
|
|
TabStop := True;
|
|
if Assigned(Form) and (Form.ActiveControl = FEditor) then
|
|
Form.ActiveControl := Self;
|
|
FEditor.Visible := False;
|
|
FEditor.Parent := nil;
|
|
EditorDestroy(FEditor, FEditorCell.Col, FEditorCell.Row);
|
|
FreeAndNil(FEditor);
|
|
if Assigned(FCells) then
|
|
if CompareCellInstances(FEditedCell, InternalGetCell(FEditorCell.Col, FEditorCell.Row)) <> 0 then
|
|
Changed;
|
|
FEditorCell := GridPoint(-1, -1);
|
|
if Assigned(Form) and (Form.ActiveControl = nil) then
|
|
Form.ActiveControl := Self;
|
|
InvalidateCurrentSelection;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
PosChanged: Boolean;
|
|
begin
|
|
if not Flag(cGF_EditorUpdating) then
|
|
begin
|
|
FlagSet(cGF_EditorUpdating);
|
|
try
|
|
if (goEditing in FOptions) and Show and (InternalGetColWidths(Col) > 0) and (InternalGetRowHeights(Row) > 0) then
|
|
begin
|
|
PosChanged := (FEditorCell.Col <> Col) or (FEditorCell.Row <> Row);
|
|
if (FEditor = nil) or PosChanged then
|
|
begin
|
|
InternalEditorDestroy;
|
|
InternalEditorCreate;
|
|
end else
|
|
InternalEditorMove;
|
|
end else
|
|
InternalEditorDestroy;
|
|
finally
|
|
FlagClear(cGF_EditorUpdating);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateScrollRange(Horz, Vert, UpdateNeeded: Boolean);
|
|
|
|
function Axis(Code: Cardinal; HasScrollBar: Boolean; ScrollMode: TKGridScrollMode;
|
|
Info: TKGridAxisInfo; out FirstGridCell, FirstGridCellExtent, ScrollPos: Integer;
|
|
var ScrollOffset: Integer): Boolean;
|
|
var
|
|
I, CellExtent, MaxExtent, PageExtent, ScrollExtent: Integer;
|
|
CheckFirstGridCell: Boolean;
|
|
SI: TScrollInfo;
|
|
begin
|
|
Result := False;
|
|
CheckFirstGridCell := True;
|
|
ScrollExtent := 0;
|
|
PageExtent := 0;
|
|
MaxExtent := Info.ClientExtent - Info.FixedBoundary;
|
|
I := Info.TotalCellCount - 1;
|
|
FirstGridCellExtent := I;
|
|
while I >= Info.FixedCellCount do
|
|
begin
|
|
CellExtent := Info.CellExtent(I);
|
|
Inc(ScrollExtent, CellExtent + Info.EffectiveSpacing(I));
|
|
if CheckFirstGridCell then
|
|
begin
|
|
if (ScrollExtent <= MaxExtent) then
|
|
begin
|
|
PageExtent := ScrollExtent;
|
|
FirstGridCellExtent := I;
|
|
if (Info.FirstGridCell > I) or (Info.FirstGridCell = I) and (ScrollOffset <> 0) then
|
|
begin
|
|
FirstGridCell := I;
|
|
Result := True;
|
|
end;
|
|
end else
|
|
begin
|
|
if PageExtent = 0 then
|
|
PageExtent := ScrollExtent;
|
|
CheckFirstGridCell := False;
|
|
end;
|
|
end;
|
|
if I = FirstGridCell then
|
|
ScrollPos := ScrollExtent;
|
|
Dec(I);
|
|
end;
|
|
ScrollPos := ScrollExtent - ScrollPos;
|
|
if Result or ((ScrollMode = smCell) or not HasScrollBar) and (ScrollOffset <> 0) then
|
|
begin
|
|
ScrollOffset := 0;
|
|
Result := True;
|
|
end;
|
|
if HandleAllocated then
|
|
if HasScrollBar then
|
|
begin
|
|
FillChar(SI, SizeOf(TScrollInfo), 0);
|
|
SI.cbSize := SizeOf(TScrollInfo);
|
|
SI.fMask := SIF_RANGE or SIF_PAGE or SIF_POS {$IFDEF UNIX}or SIF_UPDATEPOLICY{$ENDIF};
|
|
SI.nMin := 0;
|
|
SI.nMax := ScrollExtent {$IFNDEF FPC}- 1{$ENDIF};
|
|
SI.nPos := ScrollPos + ScrollOffset;
|
|
SI.nPage := PageExtent;
|
|
{$IFDEF UNIX}
|
|
SI.ntrackPos := SB_POLICY_CONTINUOUS;
|
|
{$ENDIF}
|
|
SetScrollInfo(Handle, Code, SI, True);
|
|
ShowScrollBar(Handle, Code, PageExtent < ScrollExtent);
|
|
end else
|
|
ShowScrollBar(Handle, Code, False);
|
|
end;
|
|
|
|
var
|
|
UpdateHorz, UpdateVert: Boolean;
|
|
begin
|
|
if not UpdateUnlocked then Exit;
|
|
UpdateHorz := Horz and Axis(SB_HORZ, HasHorzScrollBar, FScrollModeHorz,
|
|
GetAxisInfoHorz([aiFixedParams]), FTopLeft.Col, FTopLeftExtent.Col, FScrollPos.X, FScrollOffset.X);
|
|
UpdateVert := Vert and Axis(SB_VERT, HasVertScrollBar, FScrollModeVert,
|
|
GetAxisInfoVert([aiFixedParams]), FTopLeft.Row, FTopLeftExtent.Row, FScrollPos.Y, FScrollOffset.Y);
|
|
if UpdateNeeded or UpdateHorz then
|
|
InvalidateCols(FFixedCols);
|
|
if UpdateNeeded or UpdateVert then
|
|
InvalidateRows(FFixedRows);
|
|
if UpdateNeeded or UpdateHorz or UpdateVert then
|
|
begin
|
|
UpdateEditor(Flag(cGF_EditorModeActive));
|
|
if UpdateHorz or UpdateVert then
|
|
TopLeftChanged;
|
|
if FOptions * [goRowSelect, goRangeSelect] <> [] then
|
|
InvalidateCurrentSelection;
|
|
end;
|
|
InvalidatePageSetup;
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateSize;
|
|
begin
|
|
inherited;
|
|
UpdateAxes(True, FColCount, True, FRowCount, [afCheckMinExtent]);
|
|
end;
|
|
|
|
procedure TKCustomGrid.UpdateSortMode(ACol, ARow: Integer);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
LockSortMode;
|
|
try
|
|
if FCols[ACol].SortMode <> smNone then
|
|
begin
|
|
Index := InternalInsertIfCellModifiedNR(ACol, ARow, FFixedRows, FRowCount - 1, FCols[ACol].SortMode = smUp, CompareRows);
|
|
if Index <> ARow then
|
|
begin
|
|
MoveRow(ARow, Index);
|
|
ClampInView(ACol, Index);
|
|
end;
|
|
end;
|
|
if FRows[ARow].SortMode <> smNone then
|
|
begin
|
|
Index := InternalInsertIfCellModifiedNR(ARow, ACol, FFixedCols, FColCount - 1, FRows[ARow].SortMode = smUp, CompareCols);
|
|
if Index <> ACol then
|
|
begin
|
|
MoveCol(ACol, Index);
|
|
ClampInView(Index, ARow);
|
|
end;
|
|
end;
|
|
finally
|
|
UnlockSortMode;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMChar(var Msg: {$IFDEF FPC}TLMChar{$ELSE}TWMChar{$ENDIF});
|
|
begin
|
|
if (goEditing in Options) and CharInSetEx(Char(Msg.CharCode), [^H, #32..#255]) then
|
|
begin
|
|
EditorMode := True;
|
|
if EditorMode then
|
|
PostMessage(FEditor.Handle, LM_CHAR, Word(Msg.CharCode), 0);
|
|
Msg.Result := 1;
|
|
end else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMEraseBkGnd(var Msg: TLMEraseBkGnd);
|
|
begin
|
|
if Flag(cGF_EditorUpdating) or not (goEraseBackground in FOptions) then
|
|
Msg.Result := 1
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMGetDlgCode(var Msg: TLMNoParams);
|
|
begin
|
|
Msg.Result := DLGC_WANTARROWS;
|
|
if goTabs in FOptions then Msg.Result := Msg.Result or DLGC_WANTTAB;
|
|
if goEditing in FOptions then Msg.Result := Msg.Result or DLGC_WANTCHARS;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMHScroll(var Msg: TLMHScroll);
|
|
begin
|
|
if not EditorMode or (Msg.ScrollBar <> FEditor.Handle) then
|
|
begin
|
|
SafeSetFocus;
|
|
Scroll(Msg.ScrollCode, cScrollNoAction, Msg.Pos, 0, True);
|
|
end else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMKillFocus(var Msg: TLMKillFocus);
|
|
begin
|
|
inherited;
|
|
// focus moves to another control including inplace editor
|
|
if not Flag(cGF_EditorUpdating) then
|
|
InvalidateCurrentSelection;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMSetFocus(var Msg: TLMSetFocus);
|
|
begin
|
|
// focus moves to the grid - post message
|
|
if not Flag(cGF_EditorUpdating) then
|
|
PostLateUpdate(FillMessage(LM_SETFOCUS, 0, 0), True);
|
|
end;
|
|
|
|
procedure TKCustomGrid.WMVScroll(var Msg: TLMVScroll);
|
|
begin
|
|
if not EditorMode or (Msg.ScrollBar <> FEditor.Handle) then
|
|
begin
|
|
SafeSetFocus;
|
|
Scroll(cScrollNoAction, Msg.ScrollCode, 0, Msg.Pos, True);
|
|
end else
|
|
inherited;
|
|
end;
|
|
|
|
{$IFNDEF FPC}
|
|
procedure TKCustomGrid.WndProc(var Msg: TMessage);
|
|
|
|
procedure PaintCellBackground(ACanvas: TCanvas; R: TRect);
|
|
var
|
|
TmpBlockRect: TRect;
|
|
begin
|
|
R := Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top);
|
|
TmpBlockRect := SelectionRect;
|
|
OffsetRect(TmpBlockRect, -R.Left, -R.Top);
|
|
InternalPaintCell(Col, Row, GetDrawState(Col, Row, HasFocus),
|
|
R, TmpBlockRect, ACanvas, False, False);
|
|
end;
|
|
|
|
var
|
|
R: TRect;
|
|
SaveIndex: Integer;
|
|
ACanvas: TCanvas;
|
|
begin
|
|
case Msg.Msg of
|
|
WM_CTLCOLORBTN..WM_CTLCOLORSTATIC:
|
|
begin
|
|
if EditorMode and EditorIsTransparent and
|
|
CellRect(Col, Row, R) then
|
|
begin
|
|
if Themes then
|
|
begin
|
|
ACanvas := TCanvas.Create;
|
|
SaveIndex := SaveDC(Msg.WParam);
|
|
try
|
|
ACanvas.Handle := Msg.WParam;
|
|
PaintCellBackground(ACanvas, R);
|
|
finally
|
|
RestoreDC(Msg.WParam, SaveIndex);
|
|
ACanvas.Free;
|
|
end;
|
|
Msg.Result := GetStockObject(NULL_BRUSH);
|
|
end else
|
|
begin
|
|
PaintCellBackground(FTmpBitmap.Canvas, R);
|
|
SetTextColor(Msg.WParam, ColorToRGB(TCheckBox(FEditor).Font.Color));
|
|
SetBkColor(Msg.WParam, ColorToRGB(FTmpBitmap.Canvas.Brush.Color));
|
|
Msg.Result := FTmpBitmap.Canvas.Brush.Handle;
|
|
end;
|
|
end else
|
|
inherited;
|
|
end;
|
|
else
|
|
inherited;
|
|
end
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure TKCustomGrid.WriteColWidths(Writer: TWriter);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Writer do
|
|
begin
|
|
WriteListBegin;
|
|
for I := 0 to FColCount - 1 do WriteInteger(ColWidths[I]);
|
|
WriteListEnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TKCustomGrid.WriteRowHeights(Writer: TWriter);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with Writer do
|
|
begin
|
|
WriteListBegin;
|
|
for I := 0 to FRowCount - 1 do WriteInteger(RowHeights[I]);
|
|
WriteListEnd;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF FPC}
|
|
initialization
|
|
{$i kgrids.lrs}
|
|
{$ELSE}
|
|
{$R kgrids.res}
|
|
{$ENDIF}
|
|
end.
|