2010-05-01 18:10:38 +00:00
|
|
|
{
|
|
|
|
fpspreadsheetgrid.pas
|
|
|
|
|
|
|
|
Grid component which can load and write data from / to FPSpreadsheet documents
|
|
|
|
|
2014-04-20 20:31:36 +00:00
|
|
|
AUTHORS: Felipe Monteiro de Carvalho, Werner Pamler
|
2010-05-01 18:10:38 +00:00
|
|
|
}
|
2014-05-08 22:44:52 +00:00
|
|
|
|
|
|
|
{ To do:
|
|
|
|
- When Lazarus 1.4 comes out remove the workaround for the RGB2HLS bug in
|
|
|
|
FindNearestPaletteIndex.
|
2014-06-06 08:48:22 +00:00
|
|
|
- Arial bold is not shown as such if loaded from ods
|
|
|
|
- Background color of first cell is ignored.
|
2014-05-08 22:44:52 +00:00
|
|
|
}
|
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
unit fpspreadsheetgrid;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
|
|
|
|
fpspreadsheet;
|
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
{ TsCustomWorksheetGrid }
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
TsCustomWorksheetGrid = class(TCustomDrawGrid)
|
2009-10-06 19:25:18 +00:00
|
|
|
private
|
2014-04-29 21:58:48 +00:00
|
|
|
{ Private declarations }
|
2014-04-19 19:29:13 +00:00
|
|
|
FWorkbook: TsWorkbook;
|
2009-10-06 19:25:18 +00:00
|
|
|
FWorksheet: TsWorksheet;
|
2014-05-03 21:27:31 +00:00
|
|
|
FHeaderCount: Integer;
|
2014-05-28 21:26:38 +00:00
|
|
|
FInitColCount: Integer;
|
|
|
|
FInitRowCount: Integer;
|
2014-05-04 18:07:54 +00:00
|
|
|
FFrozenCols: Integer;
|
|
|
|
FFrozenRows: Integer;
|
2014-05-07 22:44:00 +00:00
|
|
|
FEditText: String;
|
2014-05-08 15:54:29 +00:00
|
|
|
FOldEditText: String;
|
2014-05-07 22:44:00 +00:00
|
|
|
FLockCount: Integer;
|
|
|
|
FEditing: Boolean;
|
2014-05-11 16:16:59 +00:00
|
|
|
FCellFont: TFont;
|
2014-05-23 23:13:49 +00:00
|
|
|
FReadFormulas: Boolean;
|
2014-05-03 20:12:44 +00:00
|
|
|
function CalcAutoRowHeight(ARow: Integer): Integer;
|
2014-04-19 19:29:13 +00:00
|
|
|
function CalcColWidth(AWidth: Single): Integer;
|
2014-04-20 14:57:23 +00:00
|
|
|
function CalcRowHeight(AHeight: Single): Integer;
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure ChangedCellHandler(ASender: TObject; ARow, ACol: Cardinal);
|
2014-05-08 21:52:04 +00:00
|
|
|
procedure ChangedFontHandler(ASender: TObject; ARow, ACol: Cardinal);
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure FixNeighborCellBorders(ACol, ARow: Integer);
|
2014-05-11 10:39:14 +00:00
|
|
|
|
|
|
|
// Setter/Getter
|
2014-05-11 11:56:20 +00:00
|
|
|
function GetBackgroundColor(ACol, ARow: Integer): TsColor;
|
|
|
|
function GetBackgroundColors(ARect: TGridRect): TsColor;
|
2014-05-11 09:20:52 +00:00
|
|
|
function GetCellBorder(ACol, ARow: Integer): TsCellBorders;
|
|
|
|
function GetCellBorders(ARect: TGridRect): TsCellBorders;
|
|
|
|
function GetCellBorderStyle(ACol, ARow: Integer; ABorder: TsCellBorder): TsCellBorderStyle;
|
|
|
|
function GetCellBorderStyles(ARect: TGridRect; ABorder: TsCellBorder): TsCellBorderStyle;
|
2014-05-11 16:16:59 +00:00
|
|
|
function GetCellFont(ACol, ARow: Integer): TFont;
|
|
|
|
function GetCellFonts(ARect: TGridRect): TFont;
|
|
|
|
function GetCellFontColor(ACol, ARow: Integer): TsColor;
|
|
|
|
function GetCellFontColors(ARect: TGridRect): TsColor;
|
|
|
|
function GetCellFontName(ACol, ARow: Integer): String;
|
|
|
|
function GetCellFontNames(ARect: TGridRect): String;
|
|
|
|
function GetCellFontSize(ACol, ARow: Integer): Single;
|
|
|
|
function GetCellFontSizes(ARect: TGridRect): Single;
|
|
|
|
function GetCellFontStyle(ACol, ARow: Integer): TsFontStyles;
|
|
|
|
function GetCellFontStyles(ARect: TGridRect): TsFontStyles;
|
2014-05-10 12:32:05 +00:00
|
|
|
function GetHorAlignment(ACol, ARow: Integer): TsHorAlignment;
|
|
|
|
function GetHorAlignments(ARect: TGridRect): TsHorAlignment;
|
2014-05-03 21:27:31 +00:00
|
|
|
function GetShowGridLines: Boolean;
|
|
|
|
function GetShowHeaders: Boolean;
|
2014-05-11 10:39:14 +00:00
|
|
|
function GetTextRotation(ACol, ARow: Integer): TsTextRotation;
|
|
|
|
function GetTextRotations(ARect: TGridRect): TsTextRotation;
|
2014-05-10 12:32:05 +00:00
|
|
|
function GetVertAlignment(ACol, ARow: Integer): TsVertAlignment;
|
|
|
|
function GetVertAlignments(ARect: TGridRect): TsVertAlignment;
|
2014-05-11 09:20:52 +00:00
|
|
|
function GetWordwrap(ACol, ARow: Integer): Boolean;
|
|
|
|
function GetWordwraps(ARect: TGridRect): Boolean;
|
2014-05-11 11:56:20 +00:00
|
|
|
procedure SetBackgroundColor(ACol, ARow: Integer; AValue: TsColor);
|
|
|
|
procedure SetBackgroundColors(ARect: TGridRect; AValue: TsColor);
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure SetCellBorder(ACol, ARow: Integer; AValue: TsCellBorders);
|
|
|
|
procedure SetCellBorders(ARect: TGridRect; AValue: TsCellBorders);
|
|
|
|
procedure SetCellBorderStyle(ACol, ARow: Integer; ABorder: TsCellBorder; AValue: TsCellBorderStyle);
|
|
|
|
procedure SetCellBorderStyles(ARect: TGridRect; ABorder: TsCellBorder; AValue: TsCellBorderStyle);
|
2014-05-11 16:16:59 +00:00
|
|
|
procedure SetCellFont(ACol, ARow: Integer; AValue: TFont);
|
|
|
|
procedure SetCellFonts(ARect: TGridRect; AValue: TFont);
|
|
|
|
procedure SetCellFontColor(ACol, ARow: Integer; AValue: TsColor);
|
|
|
|
procedure SetCellFontColors(ARect: TGridRect; AValue: TsColor);
|
|
|
|
procedure SetCellFontName(ACol, ARow: Integer; AValue: String);
|
|
|
|
procedure SetCellFontNames(ARect: TGridRect; AValue: String);
|
|
|
|
procedure SetCellFontStyle(ACol, ARow: Integer; AValue: TsFontStyles);
|
|
|
|
procedure SetCellFontStyles(ARect: TGridRect; AValue: TsFontStyles);
|
|
|
|
procedure SetCellFontSize(ACol, ARow: Integer; AValue: Single);
|
|
|
|
procedure SetCellFontSizes(ARect: TGridRect; AValue: Single);
|
2014-05-04 18:07:54 +00:00
|
|
|
procedure SetFrozenCols(AValue: Integer);
|
|
|
|
procedure SetFrozenRows(AValue: Integer);
|
2014-05-10 12:32:05 +00:00
|
|
|
procedure SetHorAlignment(ACol, ARow: Integer; AValue: TsHorAlignment);
|
|
|
|
procedure SetHorAlignments(ARect: TGridRect; AValue: TsHorAlignment);
|
2014-05-03 21:27:31 +00:00
|
|
|
procedure SetShowGridLines(AValue: Boolean);
|
|
|
|
procedure SetShowHeaders(AValue: Boolean);
|
2014-05-11 10:39:14 +00:00
|
|
|
procedure SetTextRotation(ACol, ARow: Integer; AValue: TsTextRotation);
|
|
|
|
procedure SetTextRotations(ARect: TGridRect; AValue: TsTextRotation);
|
2014-05-10 12:32:05 +00:00
|
|
|
procedure SetVertAlignment(ACol, ARow: Integer; AValue: TsVertAlignment);
|
|
|
|
procedure SetVertAlignments(ARect: TGridRect; AValue: TsVertAlignment);
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure SetWordwrap(ACol, ARow: Integer; AValue: boolean);
|
|
|
|
procedure SetWordwraps(ARect: TGridRect; AValue: boolean);
|
2014-05-08 22:44:52 +00:00
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
protected
|
|
|
|
{ Protected declarations }
|
2014-05-04 18:07:54 +00:00
|
|
|
procedure DefaultDrawCell(ACol, ARow: Integer; var ARect: TRect; AState: TGridDrawState); override;
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure DoPrepareCanvas(ACol, ARow: Integer; AState: TGridDrawState); override;
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure DrawAllRows; override;
|
|
|
|
procedure DrawCellBorders; overload;
|
|
|
|
procedure DrawCellBorders(ACol, ARow: Integer; ARect: TRect); overload;
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure DrawFocusRect(aCol,aRow:Integer; ARect:TRect); override;
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure DrawSelection;
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure DrawTextInCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState); override;
|
2014-05-09 22:00:53 +00:00
|
|
|
function GetBorderStyle(ACol, ARow, ADeltaCol, ADeltaRow: Integer;
|
|
|
|
var ABorderStyle: TsCellBorderStyle): Boolean;
|
2014-04-30 19:09:54 +00:00
|
|
|
function GetCellHeight(ACol, ARow: Integer): Integer;
|
2014-04-19 19:29:13 +00:00
|
|
|
function GetCellText(ACol, ARow: Integer): String;
|
2014-05-07 22:44:00 +00:00
|
|
|
function GetEditText(ACol, ARow: Integer): String; override;
|
2014-05-11 09:20:52 +00:00
|
|
|
function HasBorder(ACell: PCell; ABorder: TsCellBorder): Boolean;
|
2014-05-08 21:52:04 +00:00
|
|
|
procedure HeaderSized(IsColumn: Boolean; index: Integer); override;
|
2014-05-22 21:54:24 +00:00
|
|
|
procedure InternalDrawTextInCell(AText, AMeasureText: String; ARect: TRect;
|
|
|
|
AJustification: Byte; ACellHorAlign: TsHorAlignment;
|
|
|
|
ACellVertAlign: TsVertAlignment; ATextRot: TsTextRotation;
|
|
|
|
ATextWrap, ReplaceTooLong: Boolean);
|
2014-05-08 15:54:29 +00:00
|
|
|
procedure KeyDown(var Key : Word; Shift : TShiftState); override;
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure Loaded; override;
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure LoadFromWorksheet(AWorksheet: TsWorksheet);
|
2014-05-09 22:00:53 +00:00
|
|
|
procedure MoveSelection; override;
|
2014-05-08 15:54:29 +00:00
|
|
|
procedure SelectEditor; override;
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure SetEditText(ACol, ARow: Longint; const AValue: string); override;
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure Setup;
|
2014-05-03 21:27:31 +00:00
|
|
|
property DisplayFixedColRow: Boolean read GetShowHeaders write SetShowHeaders default true;
|
2014-05-04 18:07:54 +00:00
|
|
|
property FrozenCols: Integer read FFrozenCols write SetFrozenCols;
|
|
|
|
property FrozenRows: Integer read FFrozenRows write SetFrozenRows;
|
2014-05-23 23:13:49 +00:00
|
|
|
property ReadFormulas: Boolean read FReadFormulas write FReadFormulas;
|
2014-05-03 21:27:31 +00:00
|
|
|
property ShowGridLines: Boolean read GetShowGridLines write SetShowGridLines default true;
|
|
|
|
property ShowHeaders: Boolean read GetShowHeaders write SetShowHeaders default true;
|
2014-05-08 22:44:52 +00:00
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
public
|
2014-04-29 21:58:48 +00:00
|
|
|
{ public methods }
|
2009-10-06 19:25:18 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
2014-04-19 19:29:13 +00:00
|
|
|
destructor Destroy; override;
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure BeginUpdate;
|
|
|
|
procedure EditingDone; override;
|
|
|
|
procedure EndUpdate;
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure GetSheets(const ASheets: TStrings);
|
2014-06-05 21:57:23 +00:00
|
|
|
function GetGridCol(ASheetCol: Cardinal): Integer;
|
|
|
|
function GetGridRow(ASheetRow: Cardinal): Integer;
|
2014-05-07 22:44:00 +00:00
|
|
|
function GetWorksheetCol(AGridCol: Integer): Cardinal;
|
|
|
|
function GetWorksheetRow(AGridRow: Integer): Cardinal;
|
|
|
|
procedure LoadFromSpreadsheetFile(AFileName: string;
|
|
|
|
AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); overload;
|
|
|
|
procedure LoadFromSpreadsheetFile(AFileName: string;
|
|
|
|
AWorksheetIndex: Integer = 0); overload;
|
2014-05-28 21:26:38 +00:00
|
|
|
procedure NewWorksheet(AColCount, ARowCount: Integer);
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure SaveToSpreadsheetFile(AFileName: string;
|
|
|
|
AOverwriteExisting: Boolean = true); overload;
|
|
|
|
procedure SaveToSpreadsheetFile(AFileName: string; AFormat: TsSpreadsheetFormat;
|
|
|
|
AOverwriteExisting: Boolean = true); overload;
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure SelectSheetByIndex(AIndex: Integer);
|
2014-05-08 12:12:06 +00:00
|
|
|
|
|
|
|
{ Utilities related to Workbooks }
|
|
|
|
procedure Convert_sFont_to_Font(sFont: TsFont; AFont: TFont);
|
|
|
|
procedure Convert_Font_to_sFont(AFont: TFont; sFont: TsFont);
|
|
|
|
function FindNearestPaletteIndex(AColor: TColor): TsColor;
|
|
|
|
|
2014-04-29 21:58:48 +00:00
|
|
|
{ public properties }
|
2014-04-19 19:29:13 +00:00
|
|
|
property Worksheet: TsWorksheet read FWorksheet;
|
|
|
|
property Workbook: TsWorkbook read FWorkbook;
|
2014-05-07 22:44:00 +00:00
|
|
|
property HeaderCount: Integer read FHeaderCount;
|
2014-05-10 12:32:05 +00:00
|
|
|
|
|
|
|
{ maybe these should become published ... }
|
2014-05-11 11:56:20 +00:00
|
|
|
property BackgroundColor[ACol, ARow: Integer]: TsColor
|
|
|
|
read GetBackgroundColor write SetBackgroundColor;
|
|
|
|
property BackgroundColors[ARect: TGridRect]: TsColor
|
|
|
|
read GetBackgroundColors write SetBackgroundColors;
|
2014-05-11 09:20:52 +00:00
|
|
|
property CellBorder[ACol, ARow: Integer]: TsCellBorders
|
|
|
|
read GetCellBorder write SetCellBorder;
|
|
|
|
property CellBorders[ARect: TGridRect]: TsCellBorders
|
|
|
|
read GetCellBorders write SetCellBorders;
|
|
|
|
property CellBorderStyle[ACol, ARow: Integer; ABorder: TsCellBorder]: TsCellBorderStyle
|
|
|
|
read GetCellBorderStyle write SetCellBorderStyle;
|
|
|
|
property CellBorderStyles[ARect: TGridRect; ABorder: TsCellBorder]: TsCellBorderStyle
|
|
|
|
read GetCellBorderStyles write SetCellBorderStyles;
|
2014-05-11 16:16:59 +00:00
|
|
|
property CellFont[ACol, ARow: Integer]: TFont
|
|
|
|
read GetCellFont write SetCellFont;
|
|
|
|
property CellFonts[ARect: TGridRect]: TFont
|
|
|
|
read GetCellFonts write SetCellFonts;
|
|
|
|
property CellFontName[ACol, ARow: Integer]: String
|
|
|
|
read GetCellFontName write SetCellFontName;
|
|
|
|
property CellFontNames[ARect: TGridRect]: String
|
|
|
|
read GetCellFontNames write SetCellFontNames;
|
|
|
|
property CellFontStyle[ACol, ARow: Integer]: TsFontStyles
|
|
|
|
read GetCellFontStyle write SetCellFontStyle;
|
|
|
|
property CellFontStyles[ARect: TGridRect]: TsFontStyles
|
|
|
|
read GetCellFontStyles write SetCellFontStyles;
|
|
|
|
property CellFontSize[ACol, ARow: Integer]: Single
|
|
|
|
read GetCellFontSize write SetCellFontSize;
|
|
|
|
property CellFontSizes[ARect: TGridRect]: Single
|
|
|
|
read GetCellFontSizes write SetCellFontSizes;
|
2014-05-10 12:32:05 +00:00
|
|
|
property HorAlignment[ACol, ARow: Integer]: TsHorAlignment
|
|
|
|
read GetHorAlignment write SetHorAlignment;
|
|
|
|
property HorAlignments[ARect: TGridRect]: TsHorAlignment
|
|
|
|
read GetHorAlignments write SetHorAlignments;
|
2014-05-11 10:39:14 +00:00
|
|
|
property TextRotation[ACol, ARow: Integer]: TsTextRotation
|
|
|
|
read GetTextRotation write SetTextRotation;
|
|
|
|
property TextRotations[ARect: TGridRect]: TsTextRotation
|
|
|
|
read GetTextRotations write SetTextRotations;
|
2014-05-10 12:32:05 +00:00
|
|
|
property VertAlignment[ACol, ARow: Integer]: TsVertAlignment
|
|
|
|
read GetVertAlignment write SetVertAlignment;
|
|
|
|
property VertAlignments[ARect: TGridRect]: TsVertAlignment
|
|
|
|
read GetVertAlignments write SetVertAlignments;
|
2014-05-11 09:20:52 +00:00
|
|
|
property Wordwrap[ACol, ARow: Integer]: Boolean
|
|
|
|
read GetWordwrap write SetWordwrap;
|
|
|
|
property Wordwraps[ARect: TGridRect]: Boolean
|
|
|
|
read GetWordwraps write SetWordwraps;
|
2009-10-06 19:25:18 +00:00
|
|
|
end;
|
|
|
|
|
2010-05-01 18:10:38 +00:00
|
|
|
{ TsWorksheetGrid }
|
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
TsWorksheetGrid = class(TsCustomWorksheetGrid)
|
|
|
|
published
|
2014-04-30 19:09:54 +00:00
|
|
|
// inherited from TsCustomWorksheetGrid
|
2014-05-03 21:27:31 +00:00
|
|
|
property DisplayFixedColRow; deprecated 'Use ShowHeaders';
|
2014-05-04 18:07:54 +00:00
|
|
|
property FrozenCols;
|
|
|
|
property FrozenRows;
|
2014-05-23 23:13:49 +00:00
|
|
|
property ReadFormulas;
|
2014-05-03 21:27:31 +00:00
|
|
|
property ShowGridLines;
|
|
|
|
property ShowHeaders;
|
2014-04-30 19:09:54 +00:00
|
|
|
|
|
|
|
// inherited from other ancestors
|
2009-10-06 19:25:18 +00:00
|
|
|
property Align;
|
|
|
|
property AlternateColor;
|
|
|
|
property Anchors;
|
|
|
|
property AutoAdvance;
|
|
|
|
property AutoEdit;
|
|
|
|
property AutoFillColumns;
|
|
|
|
//property BiDiMode;
|
|
|
|
property BorderSpacing;
|
|
|
|
property BorderStyle;
|
|
|
|
property Color;
|
|
|
|
property ColCount;
|
2014-04-19 19:29:13 +00:00
|
|
|
//property Columns;
|
2009-10-06 19:25:18 +00:00
|
|
|
property Constraints;
|
|
|
|
property DefaultColWidth;
|
|
|
|
property DefaultDrawing;
|
|
|
|
property DefaultRowHeight;
|
|
|
|
property DragCursor;
|
|
|
|
property DragKind;
|
|
|
|
property DragMode;
|
|
|
|
property Enabled;
|
|
|
|
property ExtendedSelect;
|
|
|
|
property FixedColor;
|
|
|
|
property Flat;
|
|
|
|
property Font;
|
|
|
|
property GridLineWidth;
|
|
|
|
property HeaderHotZones;
|
|
|
|
property HeaderPushZones;
|
|
|
|
property MouseWheelOption;
|
|
|
|
property Options;
|
|
|
|
//property ParentBiDiMode;
|
|
|
|
property ParentColor default false;
|
|
|
|
property ParentFont;
|
|
|
|
property ParentShowHint;
|
|
|
|
property PopupMenu;
|
|
|
|
property RowCount;
|
|
|
|
property ScrollBars;
|
|
|
|
property ShowHint;
|
|
|
|
property TabOrder;
|
|
|
|
property TabStop;
|
|
|
|
property TitleFont;
|
|
|
|
property TitleImageList;
|
|
|
|
property TitleStyle;
|
|
|
|
property UseXORFeatures;
|
|
|
|
property Visible;
|
|
|
|
property VisibleColCount;
|
|
|
|
property VisibleRowCount;
|
|
|
|
|
|
|
|
property OnBeforeSelection;
|
|
|
|
property OnChangeBounds;
|
|
|
|
property OnClick;
|
|
|
|
property OnColRowDeleted;
|
|
|
|
property OnColRowExchanged;
|
|
|
|
property OnColRowInserted;
|
|
|
|
property OnColRowMoved;
|
|
|
|
property OnCompareCells;
|
|
|
|
property OnDragDrop;
|
|
|
|
property OnDragOver;
|
|
|
|
property OnDblClick;
|
|
|
|
property OnDrawCell;
|
|
|
|
property OnEditButtonClick;
|
|
|
|
property OnEditingDone;
|
|
|
|
property OnEndDock;
|
|
|
|
property OnEndDrag;
|
|
|
|
property OnEnter;
|
|
|
|
property OnExit;
|
|
|
|
property OnGetEditMask;
|
|
|
|
property OnGetEditText;
|
|
|
|
property OnHeaderClick;
|
|
|
|
property OnHeaderSized;
|
|
|
|
property OnKeyDown;
|
|
|
|
property OnKeyPress;
|
|
|
|
property OnKeyUp;
|
|
|
|
property OnMouseDown;
|
|
|
|
property OnMouseMove;
|
|
|
|
property OnMouseUp;
|
|
|
|
property OnMouseWheel;
|
|
|
|
property OnMouseWheelDown;
|
|
|
|
property OnMouseWheelUp;
|
|
|
|
property OnPickListSelect;
|
|
|
|
property OnPrepareCanvas;
|
|
|
|
property OnResize;
|
|
|
|
property OnSelectEditor;
|
|
|
|
property OnSelection;
|
|
|
|
property OnSelectCell;
|
|
|
|
property OnSetEditText;
|
|
|
|
property OnShowHint;
|
|
|
|
property OnStartDock;
|
|
|
|
property OnStartDrag;
|
|
|
|
property OnTopLeftChanged;
|
|
|
|
property OnUTF8KeyPress;
|
|
|
|
property OnValidateEntry;
|
|
|
|
property OnContextPopup;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure Register;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
uses
|
2014-05-08 12:12:06 +00:00
|
|
|
Types, LCLType, LCLIntf, Math, fpCanvas, GraphUtil, fpsUtils;
|
2014-04-21 21:43:43 +00:00
|
|
|
|
2014-05-22 21:54:24 +00:00
|
|
|
const
|
|
|
|
HOR_ALIGNMENTS: array[haLeft..haRight] of TAlignment = (
|
|
|
|
taLeftJustify, taCenter, taRightJustify
|
|
|
|
);
|
|
|
|
VERT_ALIGNMENTS: array[TsVertAlignment] of TTextLayout = (
|
|
|
|
tlBottom, tlTop, tlCenter, tlBottom
|
|
|
|
);
|
|
|
|
|
2014-04-21 21:43:43 +00:00
|
|
|
var
|
|
|
|
FillPattern_BIFF2: TBitmap = nil;
|
|
|
|
|
|
|
|
procedure Create_FillPattern_BIFF2(ABkColor: TColor);
|
|
|
|
begin
|
|
|
|
FreeAndNil(FillPattern_BIFF2);
|
|
|
|
FillPattern_BIFF2 := TBitmap.Create;
|
|
|
|
with FillPattern_BIFF2 do begin
|
|
|
|
SetSize(4, 4);
|
|
|
|
Canvas.Brush.Color := ABkColor;
|
|
|
|
Canvas.FillRect(0, 0, Width, Height);
|
|
|
|
Canvas.Pixels[0, 0] := clBlack;
|
|
|
|
Canvas.Pixels[2, 2] := clBlack;
|
|
|
|
end;
|
|
|
|
end;
|
2014-04-19 19:29:13 +00:00
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure DrawHairLineHor(ACanvas: TCanvas; x1, x2, y: Integer);
|
|
|
|
var
|
|
|
|
clr: TColor;
|
|
|
|
x: Integer;
|
|
|
|
begin
|
|
|
|
if odd(x1) then inc(x1);
|
|
|
|
x := x1;
|
|
|
|
clr := ACanvas.Pen.Color;
|
|
|
|
while (x <= x2) do begin
|
|
|
|
ACanvas.Pixels[x, y] := clr;
|
|
|
|
inc(x, 2);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure DrawHairLineVert(ACanvas: TCanvas; x, y1, y2: Integer);
|
|
|
|
var
|
|
|
|
clr: TColor;
|
|
|
|
y: Integer;
|
|
|
|
begin
|
|
|
|
if odd(y1) then inc(y1);
|
|
|
|
y := y1;
|
|
|
|
clr := ACanvas.Pen.Color;
|
|
|
|
while (y <= y2) do begin
|
|
|
|
ACanvas.Pixels[x, y] := clr;
|
|
|
|
inc(y, 2);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-29 21:58:48 +00:00
|
|
|
function WrapText(ACanvas: TCanvas; const AText: string; AMaxWidth: integer): string;
|
|
|
|
// code posted by taazz in the Lazarus Forum:
|
|
|
|
// http://forum.lazarus.freepascal.org/index.php/topic,21305.msg124743.html#msg124743
|
|
|
|
var
|
|
|
|
DC: HDC;
|
|
|
|
textExtent: TSize;
|
|
|
|
S, P, E: PChar;
|
|
|
|
line: string;
|
|
|
|
isFirstLine: boolean;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
DC := ACanvas.Handle;
|
|
|
|
isFirstLine := True;
|
|
|
|
P := PChar(AText);
|
|
|
|
while P^ = ' ' do
|
|
|
|
Inc(P);
|
|
|
|
while P^ <> #0 do begin
|
|
|
|
S := P;
|
|
|
|
E := nil;
|
|
|
|
while (P^ <> #0) and (P^ <> #13) and (P^ <> #10) do begin
|
|
|
|
LCLIntf.GetTextExtentPoint(DC, S, P - S + 1, textExtent);
|
|
|
|
if (textExtent.CX > AMaxWidth) and (E <> nil) then begin
|
|
|
|
if (P^ <> ' ') and (P^ <> ^I) then begin
|
|
|
|
while (E >= S) do
|
|
|
|
case E^ of
|
|
|
|
'.', ',', ';', '?', '!', '-', ':',
|
|
|
|
')', ']', '}', '>', '/', '\', ' ':
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
Dec(E);
|
|
|
|
end;
|
|
|
|
if E < S then
|
|
|
|
E := P - 1;
|
|
|
|
end;
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
E := P;
|
|
|
|
Inc(P);
|
|
|
|
end;
|
|
|
|
if E <> nil then begin
|
|
|
|
while (E >= S) and (E^ = ' ') do
|
|
|
|
Dec(E);
|
|
|
|
end;
|
|
|
|
if E <> nil then
|
|
|
|
SetString(Line, S, E - S + 1)
|
|
|
|
else
|
|
|
|
SetLength(Line, 0);
|
|
|
|
if (P^ = #13) or (P^ = #10) then begin
|
|
|
|
Inc(P);
|
|
|
|
if (P^ <> (P - 1)^) and ((P^ = #13) or (P^ = #10)) then
|
|
|
|
Inc(P);
|
|
|
|
if P^ = #0 then
|
|
|
|
line := line + LineEnding;
|
|
|
|
end
|
|
|
|
else if P^ <> ' ' then
|
|
|
|
P := E + 1;
|
|
|
|
while P^ = ' ' do
|
|
|
|
Inc(P);
|
|
|
|
if isFirstLine then begin
|
|
|
|
Result := Line;
|
|
|
|
isFirstLine := False;
|
|
|
|
end else
|
|
|
|
Result := Result + LineEnding + line;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-09 22:00:53 +00:00
|
|
|
function CalcSelectionColor(c: TColor; ADelta: Byte) : TColor;
|
2014-05-08 22:44:52 +00:00
|
|
|
type
|
|
|
|
TRGBA = record R,G,B,A: Byte end;
|
|
|
|
begin
|
|
|
|
c := ColorToRGB(c);
|
2014-05-09 22:00:53 +00:00
|
|
|
TRGBA(Result).A := 0;
|
|
|
|
if TRGBA(c).R < 128
|
|
|
|
then TRGBA(Result).R := TRGBA(c).R + ADelta
|
|
|
|
else TRGBA(Result).R := TRGBA(c).R - ADelta;
|
|
|
|
if TRGBA(c).G < 128
|
|
|
|
then TRGBA(Result).G := TRGBA(c).G + ADelta
|
|
|
|
else TRGBA(Result).G := TRGBA(c).G - ADelta;
|
|
|
|
if TRGBA(c).B < 128
|
|
|
|
then TRGBA(Result).B := TRGBA(c).B + ADelta
|
|
|
|
else TRGBA(Result).B := TRGBA(c).B - ADelta;
|
2014-05-08 22:44:52 +00:00
|
|
|
end;
|
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
procedure Register;
|
|
|
|
begin
|
|
|
|
RegisterComponents('Additional',[TsWorksheetGrid]);
|
|
|
|
end;
|
|
|
|
|
2010-05-01 18:10:38 +00:00
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
{ TsCustomWorksheetGrid }
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
constructor TsCustomWorksheetGrid.Create(AOwner: TComponent);
|
2009-10-06 19:25:18 +00:00
|
|
|
begin
|
2014-04-19 19:29:13 +00:00
|
|
|
inherited Create(AOwner);
|
2014-05-03 21:27:31 +00:00
|
|
|
FHeaderCount := 1;
|
2014-05-28 21:26:38 +00:00
|
|
|
FInitColCount := 26;
|
|
|
|
FInitRowCount := 100;
|
2014-05-11 16:16:59 +00:00
|
|
|
FCellFont := TFont.Create;
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
2009-10-06 19:25:18 +00:00
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
destructor TsCustomWorksheetGrid.Destroy;
|
|
|
|
begin
|
|
|
|
FreeAndNil(FWorkbook);
|
2014-05-11 16:16:59 +00:00
|
|
|
FreeAndNil(FCellFont);
|
2014-04-19 19:29:13 +00:00
|
|
|
inherited Destroy;
|
|
|
|
end;
|
2009-10-06 19:25:18 +00:00
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
{ Suppresses unnecessary repaints. }
|
|
|
|
procedure TsCustomWorksheetGrid.BeginUpdate;
|
|
|
|
begin
|
|
|
|
inc(FLockCount);
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Converts the column width, given in "characters" of the default font, to pixels
|
|
|
|
All chars are assumed to have the same width defined by the "0".
|
|
|
|
Therefore, this calculation is only approximate. }
|
2014-04-19 19:29:13 +00:00
|
|
|
function TsCustomWorksheetGrid.CalcColWidth(AWidth: Single): Integer;
|
|
|
|
var
|
|
|
|
w0: Integer;
|
|
|
|
begin
|
2014-05-08 21:52:04 +00:00
|
|
|
Convert_sFont_to_Font(FWorkbook.GetFont(0), Canvas.Font);
|
2014-04-19 19:29:13 +00:00
|
|
|
w0 := Canvas.TextWidth('0');
|
|
|
|
Result := Round(AWidth * w0);
|
2009-10-06 19:25:18 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-03 20:12:44 +00:00
|
|
|
{ Finds the max cell height per row and uses this to define the RowHeights[].
|
2014-05-08 21:52:04 +00:00
|
|
|
Returns DefaultRowHeight if the row does not contain any cells.
|
|
|
|
ARow is a grid row index. }
|
2014-05-03 20:12:44 +00:00
|
|
|
function TsCustomWorksheetGrid.CalcAutoRowHeight(ARow: Integer): Integer;
|
|
|
|
var
|
|
|
|
c: Integer;
|
|
|
|
h: Integer;
|
2014-04-20 14:57:23 +00:00
|
|
|
begin
|
2014-05-03 20:12:44 +00:00
|
|
|
h := 0;
|
2014-05-03 21:27:31 +00:00
|
|
|
for c := FHeaderCount to ColCount-1 do
|
2014-05-03 20:12:44 +00:00
|
|
|
h := Max(h, GetCellHeight(c, ARow));
|
|
|
|
if h = 0 then
|
|
|
|
Result := DefaultRowHeight
|
|
|
|
else
|
|
|
|
Result := h;
|
2014-04-20 14:57:23 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-31 21:04:53 +00:00
|
|
|
{ Converts the row height (from a worksheet row), given in lines, to pixels }
|
2014-05-03 20:12:44 +00:00
|
|
|
function TsCustomWorksheetGrid.CalcRowHeight(AHeight: Single): Integer;
|
2014-05-31 21:04:53 +00:00
|
|
|
var
|
|
|
|
h_pts: Single;
|
2014-04-30 19:09:54 +00:00
|
|
|
begin
|
2014-05-31 21:04:53 +00:00
|
|
|
h_pts := AHeight * (Workbook.GetFont(0).Size + ROW_HEIGHT_CORRECTION);
|
|
|
|
Result := PtsToPX(h_pts, Screen.PixelsPerInch) + 4;
|
2014-04-30 19:09:54 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure TsCustomWorksheetGrid.ChangedCellHandler(ASender: TObject; ARow, ACol:Cardinal);
|
|
|
|
begin
|
|
|
|
if FLockCount = 0 then Invalidate;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 21:52:04 +00:00
|
|
|
{ Handler for the event that the font has changed in a given cell.
|
|
|
|
As a consequence, the row height may have to be adapted.
|
|
|
|
Row/Col coordinates are in worksheet units here! }
|
|
|
|
procedure TsCustomWorksheetGrid.ChangedFontHandler(ASender: TObject; ARow, ACol: Cardinal);
|
|
|
|
var
|
|
|
|
h: Integer;
|
|
|
|
lRow: PRow;
|
|
|
|
begin
|
|
|
|
if (FWorksheet <> nil) then begin
|
|
|
|
lRow := FWorksheet.FindRow(ARow);
|
|
|
|
if lRow = nil then begin
|
|
|
|
// There is no row record --> row height changes according to font height
|
|
|
|
// Otherwise the row height would be fixed according to the value in the row record.
|
|
|
|
ARow := ARow + FHeaderCount; // convert row index to grid units
|
|
|
|
RowHeights[ARow] := CalcAutoRowHeight(ARow);
|
|
|
|
end;
|
|
|
|
Invalidate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 12:12:06 +00:00
|
|
|
{ Converts a spreadsheet font to a font used for painting (TCanvas.Font). }
|
|
|
|
procedure TsCustomWorksheetGrid.Convert_sFont_to_Font(sFont: TsFont; AFont: TFont);
|
|
|
|
begin
|
2014-05-23 23:13:49 +00:00
|
|
|
if Assigned(AFont) and Assigned(sFont) then begin
|
2014-05-08 12:12:06 +00:00
|
|
|
AFont.Name := sFont.FontName;
|
|
|
|
AFont.Size := round(sFont.Size);
|
|
|
|
AFont.Style := [];
|
|
|
|
if fssBold in sFont.Style then AFont.Style := AFont.Style + [fsBold];
|
|
|
|
if fssItalic in sFont.Style then AFont.Style := AFont.Style + [fsItalic];
|
|
|
|
if fssUnderline in sFont.Style then AFont.Style := AFont.Style + [fsUnderline];
|
|
|
|
if fssStrikeout in sFont.Style then AFont.Style := AFont.Style + [fsStrikeout];
|
|
|
|
AFont.Color := Workbook.GetPaletteColor(sFont.Color);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Converts a font used for painting (TCanvas.Font) to a spreadsheet font }
|
|
|
|
procedure TsCustomWorksheetGrid.Convert_Font_to_sFont(AFont: TFont; sFont: TsFont);
|
|
|
|
begin
|
|
|
|
if Assigned(AFont) and Assigned(sFont) then begin
|
|
|
|
sFont.FontName := AFont.Name;
|
|
|
|
sFont.Size := AFont.Size;
|
|
|
|
sFont.Style := [];
|
|
|
|
if fsBold in AFont.Style then Include(sFont.Style, fssBold);
|
|
|
|
if fsItalic in AFont.Style then Include(sFont.Style, fssItalic);
|
|
|
|
if fsUnderline in AFont.Style then Include(sFont.Style, fssUnderline);
|
|
|
|
if fsStrikeout in AFont.Style then Include(sFont.Style, fssStrikeout);
|
|
|
|
sFont.Color := FindNearestPaletteIndex(AFont.Color);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Is overridden to show "frozen" cells in the same style as normal cells.
|
|
|
|
"Frozen" cells are internally "fixed" cells of the grid. }
|
2014-05-04 18:07:54 +00:00
|
|
|
procedure TsCustomWorksheetGrid.DefaultDrawCell(aCol, aRow: Integer; var aRect: TRect;
|
|
|
|
AState: TGridDrawState);
|
|
|
|
var
|
|
|
|
wasFixed: Boolean;
|
|
|
|
begin
|
|
|
|
wasFixed := false;
|
|
|
|
if (gdFixed in AState) then
|
|
|
|
if ShowHeaders then begin
|
|
|
|
if ((ARow < FixedRows) and (ARow > 0) and (ACol > 0)) or
|
|
|
|
((ACol < FixedCols) and (ACol > 0) and (ARow > 0))
|
|
|
|
then
|
|
|
|
wasFixed := true;
|
|
|
|
end else begin
|
|
|
|
if (ARow < FixedRows) or (ACol < FixedCols) then
|
|
|
|
wasFixed := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if wasFixed then begin
|
2014-06-02 08:52:37 +00:00
|
|
|
wasFixed := true; // ?????
|
2014-05-04 18:07:54 +00:00
|
|
|
AState := AState - [gdFixed];
|
|
|
|
Canvas.Brush.Color := clWindow;
|
|
|
|
end;
|
|
|
|
|
|
|
|
inherited DefaultDrawCell(ACol, ARow, ARect, AState);
|
|
|
|
|
|
|
|
if wasFixed then begin
|
|
|
|
DrawCellGrid(ACol, ARow, ARect, AState);
|
|
|
|
AState := AState + [gdFixed];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-21 21:43:43 +00:00
|
|
|
{ Adjusts the grid's canvas before painting a given cell. Considers, e.g.
|
|
|
|
background color, horizontal alignment, vertical alignment, etc. }
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.DoPrepareCanvas(ACol, ARow: Integer;
|
|
|
|
AState: TGridDrawState);
|
|
|
|
var
|
|
|
|
ts: TTextStyle;
|
|
|
|
lCell: PCell;
|
|
|
|
r, c: Integer;
|
2014-04-22 23:10:32 +00:00
|
|
|
fnt: TsFont;
|
|
|
|
style: TFontStyles;
|
2014-05-08 22:44:52 +00:00
|
|
|
isSelected: Boolean;
|
2009-10-06 19:25:18 +00:00
|
|
|
begin
|
2014-05-08 22:44:52 +00:00
|
|
|
GetSelectedState(AState, isSelected);
|
2014-05-03 20:12:44 +00:00
|
|
|
Canvas.Font.Assign(Font);
|
2014-04-21 21:43:43 +00:00
|
|
|
Canvas.Brush.Bitmap := nil;
|
2014-05-09 22:00:53 +00:00
|
|
|
Canvas.Brush.Color := Color;
|
2014-04-19 19:29:13 +00:00
|
|
|
ts := Canvas.TextStyle;
|
2014-05-03 21:27:31 +00:00
|
|
|
if ShowHeaders then begin
|
2014-04-19 19:29:13 +00:00
|
|
|
// Formatting of row and column headers
|
2014-04-20 20:31:36 +00:00
|
|
|
if ARow = 0 then begin
|
|
|
|
ts.Alignment := taCenter;
|
|
|
|
ts.Layout := tlCenter;
|
|
|
|
end else
|
|
|
|
if ACol = 0 then begin
|
2014-04-19 19:29:13 +00:00
|
|
|
ts.Alignment := taRightJustify;
|
2014-04-20 20:31:36 +00:00
|
|
|
ts.Layout := tlCenter;
|
|
|
|
end;
|
2014-06-02 08:52:37 +00:00
|
|
|
if ShowHeaders and ((ACol = 0) or (ARow = 0)) then
|
|
|
|
Canvas.Brush.Color := FixedColor
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
if FWorksheet <> nil then begin
|
2014-05-03 21:27:31 +00:00
|
|
|
r := ARow - FHeaderCount;
|
|
|
|
c := ACol - FHeaderCount;
|
2014-04-19 19:29:13 +00:00
|
|
|
lCell := FWorksheet.FindCell(r, c);
|
|
|
|
if lCell <> nil then begin
|
2014-04-20 21:51:12 +00:00
|
|
|
// Background color
|
|
|
|
if (uffBackgroundColor in lCell^.UsedFormattingFields) then begin
|
2014-04-21 21:43:43 +00:00
|
|
|
if FWorkbook.FileFormat = sfExcel2 then begin
|
|
|
|
if (FillPattern_BIFF2 = nil) and (ComponentState = []) then
|
|
|
|
Create_FillPattern_BIFF2(Color);
|
|
|
|
Canvas.Brush.Style := bsImage;
|
|
|
|
Canvas.Brush.Bitmap := FillPattern_BIFF2;
|
|
|
|
end else begin
|
|
|
|
Canvas.Brush.Style := bsSolid;
|
2014-04-23 22:29:32 +00:00
|
|
|
if lCell^.BackgroundColor < FWorkbook.GetPaletteSize then
|
|
|
|
Canvas.Brush.Color := FWorkbook.GetPaletteColor(lCell^.BackgroundColor)
|
|
|
|
else
|
|
|
|
Canvas.Brush.Color := Color;
|
2014-04-21 21:43:43 +00:00
|
|
|
end;
|
2014-04-20 21:51:12 +00:00
|
|
|
end else begin
|
|
|
|
Canvas.Brush.Style := bsSolid;
|
|
|
|
Canvas.Brush.Color := Color;
|
|
|
|
end;
|
2014-04-22 23:10:32 +00:00
|
|
|
// Font
|
|
|
|
if (uffFont in lCell^.UsedFormattingFields) then begin
|
|
|
|
fnt := FWorkbook.GetFont(lCell^.FontIndex);
|
|
|
|
if fnt <> nil then begin
|
|
|
|
Canvas.Font.Name := fnt.FontName;
|
2014-04-23 22:29:32 +00:00
|
|
|
Canvas.Font.Color := FWorkbook.GetPaletteColor(fnt.Color);
|
2014-04-22 23:10:32 +00:00
|
|
|
style := [];
|
|
|
|
if fssBold in fnt.Style then Include(style, fsBold);
|
|
|
|
if fssItalic in fnt.Style then Include(style, fsItalic);
|
|
|
|
if fssUnderline in fnt.Style then Include(style, fsUnderline);
|
|
|
|
if fssStrikeout in fnt.Style then Include(style, fsStrikeout);
|
|
|
|
Canvas.Font.Style := style;
|
|
|
|
Canvas.Font.Size := round(fnt.Size);
|
|
|
|
end;
|
|
|
|
end;
|
2014-05-22 21:54:24 +00:00
|
|
|
if (lCell^.NumberFormat in [nfCurrencyRed, nfAccountingRed]) and
|
2014-05-17 15:13:08 +00:00
|
|
|
not IsNaN(lCell^.NumberValue) and (lCell^.NumberValue < 0)
|
|
|
|
then
|
|
|
|
Canvas.Font.Color := FWorkbook.GetPaletteColor(scRed);
|
2014-04-29 21:58:48 +00:00
|
|
|
// Wordwrap, text alignment and text rotation are handled by "DrawTextInCell".
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
end;
|
2014-05-08 22:44:52 +00:00
|
|
|
|
|
|
|
if IsSelected then
|
2014-05-09 22:00:53 +00:00
|
|
|
Canvas.Brush.Color := CalcSelectionColor(Canvas.Brush.Color, 16);
|
2014-05-08 22:44:52 +00:00
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
Canvas.TextStyle := ts;
|
2014-05-04 18:07:54 +00:00
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
inherited DoPrepareCanvas(ACol, ARow, AState);
|
2009-10-06 19:25:18 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Is overridden in order to paint the cell borders and the selection rectangle.
|
|
|
|
Both features can extend into the neighbor cells and thus are clipped at the
|
|
|
|
cell borders by the standard painting mechanism. In DrawAllRows, clipping at
|
|
|
|
cell borders is no longer active. }
|
|
|
|
procedure TsCustomWorksheetGrid.DrawAllRows;
|
|
|
|
var
|
|
|
|
cliprect: TRect;
|
|
|
|
rgn: HRGN;
|
|
|
|
tmp: Integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
|
|
|
Canvas.SaveHandleState;
|
|
|
|
try
|
2014-06-02 08:52:37 +00:00
|
|
|
// Avoid painting into the header cells
|
2014-05-11 09:20:52 +00:00
|
|
|
cliprect := ClientRect;
|
|
|
|
if FixedCols > 0 then
|
|
|
|
ColRowToOffset(True, True, FixedCols-1, tmp, cliprect.Left);
|
|
|
|
if FixedRows > 0 then
|
|
|
|
ColRowToOffset(False, True, FixedRows-1, tmp, cliprect.Top);
|
|
|
|
rgn := CreateRectRgn(cliprect.Left, cliprect.top, cliprect.Right, cliprect.Bottom);
|
|
|
|
SelectClipRgn(Canvas.Handle, Rgn);
|
|
|
|
|
|
|
|
DrawCellBorders;
|
|
|
|
DrawSelection;
|
|
|
|
|
|
|
|
DeleteObject(rgn);
|
|
|
|
finally
|
|
|
|
Canvas.RestoreHandleState;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Draws the borders of all cells. }
|
|
|
|
procedure TsCustomWorksheetGrid.DrawCellBorders;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
c, r: Integer;
|
|
|
|
rect: TRect;
|
|
|
|
begin
|
|
|
|
if FWorksheet = nil then exit;
|
|
|
|
|
|
|
|
cell := FWorksheet.GetFirstCell;
|
|
|
|
while cell <> nil do begin
|
|
|
|
if (uffBorder in cell^.UsedFormattingFields) then begin
|
|
|
|
c := cell^.Col + FHeaderCount;
|
|
|
|
r := cell^.Row + FHeaderCount;
|
|
|
|
rect := CellRect(c, r);
|
|
|
|
DrawCellBorders(c, r, rect);
|
|
|
|
end;
|
|
|
|
cell := FWorksheet.GetNextCell;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-09 22:00:53 +00:00
|
|
|
{ Draws the border lines around a given cell. Note that when this procedure is
|
|
|
|
called the output is clipped by the cell rectangle, but thick and double
|
|
|
|
border styles extend into the neighbor cell. Therefore, these border lines
|
|
|
|
are drawn in parts. }
|
|
|
|
procedure TsCustomWorksheetGrid.DrawCellBorders(ACol, ARow: Integer; ARect: TRect);
|
2014-05-03 17:00:00 +00:00
|
|
|
|
2014-05-09 22:00:53 +00:00
|
|
|
procedure DrawBorderLine(ACoord: Integer; ARect: TRect; IsHor: Boolean;
|
|
|
|
ABorderStyle: TsCellBorderStyle);
|
2014-05-03 17:00:00 +00:00
|
|
|
const
|
2014-05-11 09:20:52 +00:00
|
|
|
// TsLineStyle = (lsThin, lsMedium, lsDashed, lsDotted, lsThick, lsDouble, lsHair);
|
2014-05-03 17:00:00 +00:00
|
|
|
PEN_STYLES: array[TsLineStyle] of TPenStyle =
|
2014-05-11 09:20:52 +00:00
|
|
|
(psSolid, psSolid, psDash, psDot, psSolid, psSolid, psSolid);
|
|
|
|
PEN_WIDTHS: array[TsLineStyle] of Integer =
|
|
|
|
(1, 2, 1, 1, 3, 1, 1);
|
|
|
|
var
|
|
|
|
width3: Boolean; // line is 3 pixels wide
|
2014-05-09 22:00:53 +00:00
|
|
|
begin
|
|
|
|
Canvas.Pen.Style := PEN_STYLES[ABorderStyle.LineStyle];
|
2014-05-11 09:20:52 +00:00
|
|
|
Canvas.Pen.Width := PEN_WIDTHS[ABorderStyle.LineStyle];
|
2014-05-09 22:00:53 +00:00
|
|
|
Canvas.Pen.Color := FWorkbook.GetPaletteColor(ABorderStyle.Color);
|
2014-05-11 09:20:52 +00:00
|
|
|
Canvas.Pen.EndCap := pecSquare;
|
|
|
|
width3 := (ABorderStyle.LineStyle in [lsThick, lsDouble]);
|
|
|
|
|
|
|
|
// Tuning the rectangle to avoid issues at the grid borders and to get nice corners
|
|
|
|
if (ABorderStyle.LineStyle in [lsMedium, lsThick, lsDouble]) then begin
|
|
|
|
if ACol = ColCount-1 then begin
|
|
|
|
if not IsHor and (ACoord = ARect.Right-1) and width3 then dec(ACoord);
|
|
|
|
dec(ARect.Right);
|
|
|
|
end;
|
|
|
|
if ARow = RowCount-1 then begin
|
|
|
|
if IsHor and (ACoord = ARect.Bottom-1) and width3 then dec(ACoord);
|
|
|
|
dec(ARect.Bottom);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
if ABorderStyle.LineStyle in [lsMedium, lsThick] then begin
|
|
|
|
if IsHor then dec(ARect.Right, 1) else dec(ARect.Bottom, 1);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Painting
|
|
|
|
case ABorderStyle.LineStyle of
|
|
|
|
lsThin, lsMedium, lsThick, lsDotted, lsDashed:
|
|
|
|
if IsHor then
|
|
|
|
Canvas.Line(ARect.Left, ACoord, ARect.Right, ACoord)
|
|
|
|
else
|
|
|
|
Canvas.Line(ACoord, ARect.Top, ACoord, ARect.Bottom);
|
|
|
|
|
|
|
|
lsHair:
|
|
|
|
if IsHor then
|
|
|
|
DrawHairLineHor(Canvas, ARect.Left, ARect.Right, ACoord)
|
|
|
|
else
|
|
|
|
DrawHairLineVert(Canvas, ACoord, ARect.Top, ARect.Bottom);
|
|
|
|
|
|
|
|
lsDouble:
|
|
|
|
if IsHor then begin
|
|
|
|
Canvas.Line(ARect.Left, ACoord-1, ARect.Right, ACoord-1);
|
|
|
|
Canvas.Line(ARect.Left, ACoord+1, ARect.Right, ACoord+1);
|
|
|
|
Canvas.Pen.Color := Color;
|
|
|
|
Canvas.Line(ARect.Left, ACoord, ARect.Right, ACoord);
|
|
|
|
end else begin
|
|
|
|
Canvas.Line(ACoord-1, ARect.Top, ACoord-1, ARect.Bottom);
|
|
|
|
Canvas.Line(ACoord+1, ARect.Top, ACoord+1, ARect.Bottom);
|
|
|
|
Canvas.Pen.Color := Color;
|
|
|
|
Canvas.Line(ACoord, ARect.Top, ACoord, ARect.Bottom);
|
|
|
|
end;
|
2014-05-09 22:00:53 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
bs: TsCellBorderStyle;
|
|
|
|
begin
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
// Left border
|
|
|
|
if GetBorderStyle(ACol, ARow, -1, 0, bs) then
|
|
|
|
DrawBorderLine(ARect.Left-1, ARect, false, bs);
|
|
|
|
// Right border
|
|
|
|
if GetBorderStyle(ACol, ARow, +1, 0, bs) then
|
|
|
|
DrawBorderLine(ARect.Right-1, ARect, false, bs);
|
|
|
|
// Top border
|
|
|
|
if GetBorderstyle(ACol, ARow, 0, -1, bs) then
|
|
|
|
DrawBorderLine(ARect.Top-1, ARect, true, bs);
|
|
|
|
// Bottom border
|
|
|
|
if GetBorderStyle(ACol, ARow, 0, +1, bs) then
|
|
|
|
DrawBorderLine(ARect.Bottom-1, ARect, true, bs);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Is responsible for painting of the focus rectangle. We don't want the red
|
|
|
|
dashed rectangle here, but the thick Excel-like rectangle. }
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure TsCustomWorksheetGrid.DrawFocusRect(aCol, aRow: Integer; ARect: TRect);
|
|
|
|
begin
|
2014-05-11 09:20:52 +00:00
|
|
|
// Nothing do to
|
2014-05-09 22:00:53 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Draws the selection rectangle, 3 pixels wide as in Excel. }
|
|
|
|
procedure TsCustomWorksheetGrid.DrawSelection;
|
|
|
|
var
|
|
|
|
P1, P2: TPoint;
|
|
|
|
selrect: TRect;
|
2014-05-09 22:00:53 +00:00
|
|
|
begin
|
2014-05-11 09:20:52 +00:00
|
|
|
// Cosmetics at the edges of the grid to avoid spurious rests
|
|
|
|
P1 := CellRect(Selection.Left, Selection.Top).TopLeft;
|
|
|
|
P2 := CellRect(Selection.Right, Selection.Bottom).BottomRight;
|
|
|
|
if Selection.Top > TopRow then dec(P1.Y) else inc(P1.Y);
|
|
|
|
if Selection.Left > LeftCol then dec(P1.X) else inc(P1.X);
|
|
|
|
if Selection.Right = ColCount-1 then dec(P2.X);
|
|
|
|
if Selection.Bottom = RowCount-1 then dec(P2.Y);
|
|
|
|
// Set up the canvas
|
|
|
|
Canvas.Pen.Style := psSolid;
|
|
|
|
Canvas.Pen.Width := 3;
|
|
|
|
Canvas.Pen.JoinStyle := pjsMiter;
|
|
|
|
if UseXORFeatures then begin
|
|
|
|
Canvas.Pen.Color := clWhite;
|
|
|
|
Canvas.Pen.Mode := pmXOR;
|
|
|
|
end else
|
|
|
|
Canvas.Pen.Color := clBlack;
|
|
|
|
Canvas.Brush.Style := bsClear;
|
|
|
|
// Paint
|
|
|
|
Canvas.Rectangle(P1.X, P1.Y, P2.X, P2.Y);
|
2014-05-07 22:44:00 +00:00
|
|
|
end;
|
|
|
|
|
2014-04-29 21:58:48 +00:00
|
|
|
{ Draws the cell text. Calls "GetCellText" to determine the text in the cell.
|
|
|
|
Takes care of horizontal and vertical text alignment, text rotation and
|
|
|
|
text wrapping }
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.DrawTextInCell(ACol, ARow: Integer; ARect: TRect;
|
|
|
|
AState: TGridDrawState);
|
2014-04-29 21:58:48 +00:00
|
|
|
var
|
|
|
|
ts: TTextStyle;
|
|
|
|
flags: Cardinal;
|
|
|
|
txt: String;
|
2014-05-22 21:54:24 +00:00
|
|
|
txtL, txtR: String;
|
2014-04-29 21:58:48 +00:00
|
|
|
txtRect: TRect;
|
|
|
|
P: TPoint;
|
|
|
|
w, h, h0, hline: Integer;
|
|
|
|
i: Integer;
|
|
|
|
L: TStrings;
|
|
|
|
c, r: Integer;
|
2014-05-11 09:20:52 +00:00
|
|
|
wrapped: Boolean;
|
2014-04-29 21:58:48 +00:00
|
|
|
horAlign: TsHorAlignment;
|
|
|
|
vertAlign: TsVertAlignment;
|
2014-05-22 21:54:24 +00:00
|
|
|
txtRot: TsTextRotation;
|
2014-04-29 21:58:48 +00:00
|
|
|
lCell: PCell;
|
2014-05-22 21:54:24 +00:00
|
|
|
txtLeft, txtRight: String;
|
|
|
|
justif: Byte;
|
2014-04-19 19:29:13 +00:00
|
|
|
begin
|
2014-04-29 21:58:48 +00:00
|
|
|
if FWorksheet = nil then
|
|
|
|
exit;
|
|
|
|
|
2014-05-03 21:27:31 +00:00
|
|
|
c := ACol - FHeaderCount;
|
|
|
|
r := ARow - FHeaderCount;
|
2014-04-29 21:58:48 +00:00
|
|
|
lCell := FWorksheet.FindCell(r, c);
|
2014-05-22 21:54:24 +00:00
|
|
|
|
|
|
|
// Header
|
2014-04-29 21:58:48 +00:00
|
|
|
if lCell = nil then begin
|
2014-05-03 21:27:31 +00:00
|
|
|
if ShowHeaders and ((ACol = 0) or (ARow = 0)) then begin
|
2014-04-29 21:58:48 +00:00
|
|
|
ts.Alignment := taCenter;
|
|
|
|
ts.Layout := tlCenter;
|
2014-04-30 19:09:54 +00:00
|
|
|
ts.Opaque := false;
|
2014-04-29 21:58:48 +00:00
|
|
|
Canvas.TextStyle := ts;
|
|
|
|
end;
|
|
|
|
inherited DrawCellText(aCol, aRow, aRect, aState, GetCellText(ACol,ARow));
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
2014-05-22 21:54:24 +00:00
|
|
|
// Cells
|
|
|
|
wrapped := (uffWordWrap in lCell^.UsedFormattingFields) or (lCell^.TextRotation = rtStacked);
|
|
|
|
txtRot := lCell^.TextRotation;
|
|
|
|
vertAlign := lCell^.VertAlignment;
|
2014-05-28 09:04:42 +00:00
|
|
|
if vertAlign = vaDefault then vertAlign := vaBottom;
|
2014-04-29 21:58:48 +00:00
|
|
|
if lCell^.HorAlignment <> haDefault then
|
|
|
|
horAlign := lCell^.HorAlignment
|
|
|
|
else begin
|
2014-05-22 21:54:24 +00:00
|
|
|
if (lCell^.ContentType in [cctNumber, cctDateTime]) then
|
2014-04-29 21:58:48 +00:00
|
|
|
horAlign := haRight
|
|
|
|
else
|
|
|
|
horAlign := haLeft;
|
2014-05-28 16:23:50 +00:00
|
|
|
{
|
2014-05-22 21:54:24 +00:00
|
|
|
if txtRot = rt90DegreeCounterClockwiseRotation then begin
|
2014-04-29 21:58:48 +00:00
|
|
|
if horAlign = haRight then horAlign := haLeft else horAlign := haRight;
|
|
|
|
end;
|
2014-05-28 16:23:50 +00:00
|
|
|
}
|
2014-04-29 21:58:48 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
InflateRect(ARect, -constCellPadding, -constCellPadding);
|
|
|
|
|
2014-05-22 21:54:24 +00:00
|
|
|
if (lCell^.NumberFormat in [nfAccounting, nfAccountingRed]) and not IsNaN(lCell^.Numbervalue)
|
|
|
|
then begin
|
|
|
|
case SplitAccountingFormatString(lCell^.NumberFormatStr, Sign(lCell^.NumberValue),
|
|
|
|
txtLeft, txtRight) of
|
|
|
|
1: begin
|
|
|
|
txtLeft := FormatFloat(txtLeft, lCell^.NumberValue);
|
|
|
|
if txtLeft = '' then exit;
|
|
|
|
txt := txtLeft + ' ' + txtRight;
|
|
|
|
end;
|
|
|
|
2: begin
|
|
|
|
txtRight := FormatFloat(txtRight, lCell^.NumberValue);
|
|
|
|
if txtRight = '' then exit;
|
|
|
|
txt := txtLeft + ' ' + txtRight;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
InternalDrawTextInCell(txtLeft, txt, ARect, 0, horAlign, vertAlign,
|
|
|
|
txtRot, wrapped, true);
|
|
|
|
InternalDrawTextInCell(txtRight, txt, ARect, 2, horAlign, vertAlign,
|
|
|
|
txtRot, wrapped, true);
|
|
|
|
end else begin
|
|
|
|
txt := GetCellText(ACol, ARow);
|
|
|
|
if txt = '' then
|
|
|
|
exit;
|
2014-05-28 09:04:42 +00:00
|
|
|
case txtRot of
|
|
|
|
trHorizontal:
|
|
|
|
case horAlign of
|
|
|
|
haLeft : justif := 0;
|
|
|
|
haCenter : justif := 1;
|
|
|
|
haRight : justif := 2;
|
|
|
|
end;
|
|
|
|
rtStacked,
|
|
|
|
rt90DegreeClockwiseRotation:
|
|
|
|
case vertAlign of
|
|
|
|
vaTop : justif := 0;
|
|
|
|
vaCenter: justif := 1;
|
|
|
|
vaBottom: justif := 2;
|
|
|
|
end;
|
|
|
|
rt90DegreeCounterClockwiseRotation:
|
|
|
|
case vertAlign of
|
|
|
|
vaTop : justif := 2;
|
|
|
|
vaCenter: justif := 1;
|
|
|
|
vaBottom: justif := 0;
|
|
|
|
end;
|
2014-05-22 21:54:24 +00:00
|
|
|
end;
|
|
|
|
InternalDrawTextInCell(txt, txt, ARect, justif, horAlign, vertAlign,
|
|
|
|
txtRot, wrapped, false);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
procedure InternalDrawTextInCell(AText, AMeasureText: String; ARect: TRect;
|
|
|
|
AJustification: Byte; ACellHorAlign: TsHorAlignment;
|
|
|
|
ACellVertAlign: TsVertAlignment; ATextRot: TsTextRotation;
|
|
|
|
ATextWrap, ReplaceTooLong: Boolean);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-04-30 19:09:54 +00:00
|
|
|
if (lCell^.TextRotation in [trHorizontal, rtStacked]) or
|
|
|
|
(not (uffTextRotation in lCell^.UsedFormattingFields))
|
|
|
|
then begin
|
2014-04-29 21:58:48 +00:00
|
|
|
// HORIZONAL TEXT DRAWING DIRECTION
|
|
|
|
ts := Canvas.TextStyle;
|
2014-05-11 09:20:52 +00:00
|
|
|
if wrapped then begin
|
2014-04-29 21:58:48 +00:00
|
|
|
ts.Wordbreak := true;
|
|
|
|
ts.SingleLine := false;
|
|
|
|
flags := DT_WORDBREAK and not DT_SINGLELINE;
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(txt), Length(txt), txtRect,
|
|
|
|
DT_CALCRECT or flags);
|
|
|
|
w := txtRect.Right - txtRect.Left;
|
|
|
|
h := txtRect.Bottom - txtRect.Top;
|
|
|
|
end else begin
|
|
|
|
ts.WordBreak := false;
|
|
|
|
ts.SingleLine := false;
|
|
|
|
w := Canvas.TextWidth(txt);
|
|
|
|
h := Canvas.TextHeight('Tg');
|
|
|
|
end;
|
|
|
|
|
|
|
|
Canvas.Font.Orientation := 0;
|
|
|
|
ts.Alignment := HOR_ALIGNMENTS[horAlign];
|
2014-04-30 19:09:54 +00:00
|
|
|
ts.Opaque := false;
|
2014-04-29 21:58:48 +00:00
|
|
|
if h > ARect.Bottom - ARect.Top then
|
|
|
|
ts.Layout := tlTop
|
|
|
|
else
|
|
|
|
ts.Layout := VERT_ALIGNMENTS[vertAlign];
|
|
|
|
|
|
|
|
Canvas.TextStyle := ts;
|
|
|
|
Canvas.TextRect(ARect, ARect.Left, ARect.Top, txt);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
// ROTATED TEXT DRAWING DIRECTION
|
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
txtRect := Bounds(ARect.Left, ARect.Top, ARect.Bottom - ARect.Top, ARect.Right - ARect.Left);
|
|
|
|
hline := Canvas.TextHeight('Tg');
|
2014-05-11 09:20:52 +00:00
|
|
|
if wrapped then begin
|
2014-04-29 21:58:48 +00:00
|
|
|
L.Text := WrapText(Canvas, txt, txtRect.Right - txtRect.Left);
|
|
|
|
flags := DT_WORDBREAK and not DT_SINGLELINE;
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(L.Text), Length(L.Text), txtRect,
|
|
|
|
DT_CALCRECT or flags);
|
|
|
|
w := txtRect.Right - txtRect.Left;
|
|
|
|
h := txtRect.Bottom - txtRect.Top;
|
|
|
|
h0 := hline;
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
L.Text := txt;
|
|
|
|
w := Canvas.TextWidth(txt);
|
|
|
|
h := hline;
|
|
|
|
h0 := 0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
ts := Canvas.TextStyle;
|
|
|
|
ts.SingleLine := true; // Draw text line by line
|
|
|
|
ts.Clipping := false;
|
|
|
|
ts.Layout := tlTop;
|
|
|
|
ts.Alignment := taLeftJustify;
|
2014-04-30 19:09:54 +00:00
|
|
|
ts.Opaque := false;
|
2014-04-29 21:58:48 +00:00
|
|
|
|
|
|
|
if lCell^.TextRotation = rt90DegreeClockwiseRotation then begin
|
|
|
|
// Clockwise
|
|
|
|
Canvas.Font.Orientation := -900;
|
|
|
|
case horAlign of
|
|
|
|
haLeft : P.X := Min(ARect.Right-1, ARect.Left + h - h0);
|
|
|
|
haCenter : P.X := Min(ARect.Right-1, (ARect.Left + ARect.Right + h) div 2);
|
|
|
|
haRight : P.X := ARect.Right - 1;
|
|
|
|
end;
|
|
|
|
for i:= 0 to L.Count-1 do begin
|
|
|
|
w := Canvas.TextWidth(L[i]);
|
|
|
|
case vertAlign of
|
|
|
|
vaTop : P.Y := ARect.Top;
|
|
|
|
vaCenter : P.Y := Max(ARect.Top, (ARect.Top + ARect.Bottom - w) div 2);
|
|
|
|
vaBottom : P.Y := Max(ARect.Top, ARect.Bottom - w);
|
|
|
|
end;
|
|
|
|
Canvas.TextRect(ARect, P.X, P.Y, L[i], ts);
|
|
|
|
dec(P.X, hline);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
// Counter-clockwise
|
|
|
|
Canvas.Font.Orientation := +900;
|
|
|
|
case horAlign of
|
|
|
|
haLeft : P.X := ARect.Left;
|
|
|
|
haCenter : P.X := Max(ARect.Left, (ARect.Left + ARect.Right - h + h0) div 2);
|
|
|
|
haRight : P.X := MAx(ARect.Left, ARect.Right - h + h0);
|
|
|
|
end;
|
|
|
|
for i:= 0 to L.Count-1 do begin
|
|
|
|
w := Canvas.TextWidth(L[i]);
|
|
|
|
case vertAlign of
|
|
|
|
vaTop : P.Y := Min(ARect.Bottom, ARect.Top + w);
|
|
|
|
vaCenter : P.Y := Min(ARect.Bottom, (ARect.Top + ARect.Bottom + w) div 2);
|
|
|
|
vaBottom : P.Y := ARect.Bottom;
|
|
|
|
end;
|
|
|
|
Canvas.TextRect(ARect, P.X, P.Y, L[i], ts);
|
|
|
|
inc(P.X, hline);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
2014-05-22 21:54:24 +00:00
|
|
|
*)
|
2014-04-19 19:29:13 +00:00
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure TsCustomWorksheetGrid.EditingDone;
|
|
|
|
var
|
|
|
|
oldText: String;
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
if (not EditorShowing) and FEditing then begin
|
|
|
|
oldText := GetCellText(Col, Row);
|
|
|
|
if oldText <> FEditText then begin
|
|
|
|
if FWorksheet = nil then
|
|
|
|
FWorksheet := TsWorksheet.Create;
|
|
|
|
cell := FWorksheet.GetCell(Row-FHeaderCount, Col-FHeaderCount);
|
|
|
|
if FEditText = '' then
|
|
|
|
cell^.ContentType := cctEmpty
|
|
|
|
else
|
|
|
|
if TryStrToFloat(FEditText, cell^.NumberValue) then
|
|
|
|
cell^.ContentType := cctNumber
|
|
|
|
else
|
|
|
|
if TryStrToDateTime(FEditText, cell^.DateTimeValue) then begin
|
|
|
|
cell^.ContentType := cctDateTime;
|
2014-05-09 22:00:53 +00:00
|
|
|
if cell^.DateTimeValue < 1.0 then begin // this is a TTime
|
2014-05-07 22:44:00 +00:00
|
|
|
if not (cell^.NumberFormat in [nfShortDateTime, nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM])
|
|
|
|
then cell^.NumberFormat := nfLongTime;
|
|
|
|
end else
|
|
|
|
if frac(cell^.DateTimeValue) = 0 then begin // this is a TDate
|
|
|
|
if not (cell^.NumberFormat in [nfShortDateTime, nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM])
|
|
|
|
then cell^.NumberFormat := nfShortDate
|
|
|
|
end else
|
|
|
|
cell^.NumberFormat := nfShortDateTime;
|
|
|
|
end else begin
|
|
|
|
cell^.UTF8StringValue := FEditText;
|
|
|
|
cell^.ContentType := cctUTF8String;
|
|
|
|
end;
|
|
|
|
FEditText := '';
|
|
|
|
end;
|
|
|
|
inherited EditingDone;
|
|
|
|
end;
|
|
|
|
FEditing := false;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.EndUpdate;
|
|
|
|
begin
|
|
|
|
dec(FLockCount);
|
|
|
|
if FLockCount = 0 then Invalidate;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Copies the borders of a cell to its neighbors. This avoids the nightmare of
|
|
|
|
changing borders due to border conflicts of adjacent cells. }
|
|
|
|
procedure TsCustomWorksheetGrid.FixNeighborCellBorders(ACol, ARow: Integer);
|
|
|
|
|
|
|
|
procedure SetNeighborBorder(NewRow, NewCol: Integer;
|
|
|
|
ANewBorder: TsCellBorder; const ANewBorderStyle: TsCellBorderStyle;
|
|
|
|
AInclude: Boolean);
|
|
|
|
var
|
|
|
|
neighbor: PCell;
|
|
|
|
border: TsCellBorders;
|
|
|
|
begin
|
|
|
|
neighbor := FWorksheet.FindCell(NewRow, NewCol);
|
|
|
|
if neighbor <> nil then begin
|
|
|
|
border := neighbor^.Border;
|
|
|
|
if AInclude then begin
|
|
|
|
Include(border, ANewBorder);
|
|
|
|
FWorksheet.WriteBorderStyle(NewRow, NewCol, ANewBorder, ANewBorderStyle);
|
|
|
|
end else
|
|
|
|
Exclude(border, ANewBorder);
|
|
|
|
FWorksheet.WriteBorders(NewRow, NewCol, border);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
if FWorksheet = nil then exit;
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (FWorksheet <> nil) and (cell <> nil) then
|
|
|
|
with cell^ do begin
|
|
|
|
SetNeighborBorder(Row, Col-1, cbEast, BorderStyles[cbWest], cbWest in Border);
|
|
|
|
SetNeighborBorder(Row, Col+1, cbWest, BorderStyles[cbEast], cbEast in Border);
|
|
|
|
SetNeighborBorder(Row-1, Col, cbSouth, BorderStyles[cbNorth], cbNorth in Border);
|
|
|
|
SetNeighborBorder(Row+1, Col, cbNorth, BorderStyles[cbSouth], cbSouth in Border);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 12:12:06 +00:00
|
|
|
{ The "colors" used by the spreadsheet are indexes into the workbook's color
|
|
|
|
palette. If the user wants to set a color to a particular rgb value this is
|
|
|
|
not possible in general. The method FindNearestPaletteIndex finds the bast
|
|
|
|
matching color in the palette. }
|
|
|
|
function TsCustomWorksheetGrid.FindNearestPaletteIndex(AColor: TColor): TsColor;
|
|
|
|
|
|
|
|
procedure ColorToHSL(RGB: TColor; var H, S, L : double);
|
|
|
|
// Taken from https://code.google.com/p/thtmlviewer/source/browse/trunk/source/HSLUtils.pas?r=277
|
2014-05-08 22:44:52 +00:00
|
|
|
// The procedure in GraphUtils is crashing for some colors in Laz < 1.3
|
2014-05-08 12:12:06 +00:00
|
|
|
var
|
|
|
|
R, G, B, D, Cmax, Cmin: double;
|
|
|
|
begin
|
|
|
|
R := GetRValue(RGB) / 255;
|
|
|
|
G := GetGValue(RGB) / 255;
|
|
|
|
B := GetBValue(RGB) / 255;
|
|
|
|
Cmax := Max(R, Max(G, B));
|
|
|
|
Cmin := Min(R, Min(G, B));
|
|
|
|
|
|
|
|
// calculate luminosity
|
|
|
|
L := (Cmax + Cmin) / 2;
|
|
|
|
|
|
|
|
if Cmax = Cmin then begin // it's grey
|
|
|
|
H := 0; // it's actually undefined
|
|
|
|
S := 0
|
|
|
|
end else begin
|
|
|
|
D := Cmax - Cmin;
|
|
|
|
|
|
|
|
// calculate Saturation
|
|
|
|
if L < 0.5 then
|
|
|
|
S := D / (Cmax + Cmin)
|
|
|
|
else
|
|
|
|
S := D / (2 - Cmax - Cmin);
|
|
|
|
|
|
|
|
// calculate Hue
|
|
|
|
if R = Cmax then
|
|
|
|
H := (G - B) / D
|
|
|
|
else
|
|
|
|
if G = Cmax then
|
|
|
|
H := 2 + (B - R) /D
|
|
|
|
else
|
|
|
|
H := 4 + (R - G) / D;
|
|
|
|
|
|
|
|
H := H / 6;
|
|
|
|
if H < 0 then
|
|
|
|
H := H + 1
|
|
|
|
end
|
|
|
|
end;
|
|
|
|
|
|
|
|
function ColorDistance(color1, color2: TColor): Double;
|
|
|
|
type
|
|
|
|
TRGBA = packed record R,G,B,A: Byte end;
|
|
|
|
var
|
|
|
|
H1,S1,L1, H2,S2,L2: Double;
|
|
|
|
begin
|
|
|
|
ColorToHSL(color1, H1, S1, L1);
|
|
|
|
ColorToHSL(color2, H2, S2, L2);
|
|
|
|
Result := sqr(H1-H2) + sqr(S1-S2) + sqr(L1-L2);
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{
|
2014-05-08 22:44:52 +00:00
|
|
|
// will be activated when Lazarus 1.4 is available. (RgbToHLS bug in Laz < 1.3)
|
|
|
|
|
|
|
|
function ColorDistance(color1, color2: TColor): Integer;
|
|
|
|
type
|
|
|
|
TRGBA = packed record R, G, B, A: Byte end;
|
|
|
|
var
|
|
|
|
H1,L1,S1, H2,L2,S2: Byte;
|
|
|
|
begin
|
|
|
|
ColorToHLS(color1, H1,L1,S1);
|
|
|
|
ColorToHLS(color2, H2,L2,S2);
|
|
|
|
result := sqr(Integer(H1)-H2) + sqr(Integer(L1)-L2) + sqr(Integer(S1)-S2);
|
2014-05-11 09:20:52 +00:00
|
|
|
end;
|
|
|
|
}
|
2014-05-08 22:44:52 +00:00
|
|
|
|
2014-05-08 12:12:06 +00:00
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
dist, mindist: Double;
|
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
if Workbook <> nil then begin
|
|
|
|
mindist := 1E308;
|
|
|
|
for i:=0 to Workbook.GetPaletteSize-1 do begin
|
|
|
|
dist := ColorDistance(AColor, TColor(Workbook.GetPaletteColor(i)));
|
|
|
|
if dist < mindist then begin
|
|
|
|
mindist := dist;
|
|
|
|
Result := i;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 11:56:20 +00:00
|
|
|
function TsCustomWorksheetGrid.GetBackgroundColor(ACol, ARow: Integer): TsColor;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := scNotDefined;
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) and (uffBackgroundColor in cell^.UsedFormattingFields) then
|
|
|
|
Result := cell^.BackgroundColor;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetBackgroundColors(ARect: TGridRect): TsColor;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
clr: TsColor;
|
|
|
|
begin
|
|
|
|
Result := GetBackgroundColor(ARect.Left, ARect.Top);
|
|
|
|
clr := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetBackgroundColor(c, r);
|
|
|
|
if Result <> clr then begin
|
|
|
|
Result := scNotDefined;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
function TsCustomWorksheetGrid.GetCellBorder(ACol, ARow: Integer): TsCellBorders;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := [];
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) and (uffBorder in cell^.UsedFormattingFields) then
|
|
|
|
Result := cell^.Border;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellBorders(ARect: TGridRect): TsCellBorders;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
b: TsCellBorders;
|
|
|
|
begin
|
|
|
|
Result := GetCellBorder(ARect.Left, ARect.Top);
|
|
|
|
b := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetCellBorder(c, r);
|
|
|
|
if Result <> b then begin
|
|
|
|
Result := [];
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellBorderStyle(ACol, ARow: Integer;
|
|
|
|
ABorder: TsCellBorder): TsCellBorderStyle;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := DEFAULT_BORDERSTYLES[ABorder];
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then
|
|
|
|
Result := cell^.BorderStyles[ABorder];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellBorderStyles(ARect: TGridRect;
|
|
|
|
ABorder: TsCellBorder): TsCellBorderStyle;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
bs: TsCellBorderStyle;
|
|
|
|
begin
|
|
|
|
Result := GetCellBorderStyle(ARect.Left, ARect.Top, ABorder);
|
|
|
|
bs := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetCellBorderStyle(c, r, ABorder);
|
|
|
|
if (Result.LineStyle <> bs.LineStyle) or (Result.Color <> bs.Color) then begin
|
|
|
|
Result := DEFAULT_BORDERSTYLES[ABorder];
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
2014-05-08 12:12:06 +00:00
|
|
|
|
2014-05-11 16:16:59 +00:00
|
|
|
function TsCustomWorksheetGrid.GetCellFont(ACol, ARow: Integer): TFont;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
if (FWorkbook <> nil) and (FWorksheet <> nil) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then begin
|
|
|
|
fnt := FWorkbook.GetFont(cell^.FontIndex);
|
|
|
|
Convert_sFont_to_Font(fnt, FCellFont);
|
|
|
|
Result := FCellFont;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFonts(ARect: TGridRect): TFont;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
sFont, sDefFont: TsFont;
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := GetCellFont(ARect.Left, ARect.Top);
|
|
|
|
sDefFont := FWorkbook.GetFont(0); // Default font
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(r), GetWorksheetCol(c));
|
|
|
|
if cell <> nil then begin
|
|
|
|
sFont := FWorkbook.GetFont(cell^.FontIndex);
|
|
|
|
if (sFont.FontName <> sDefFont.FontName) and (sFont.Size <> sDefFont.Size)
|
|
|
|
and (sFont.Style <> sDefFont.Style) and (sFont.Color <> sDefFont.Color)
|
|
|
|
then begin
|
|
|
|
Convert_sFont_to_Font(sDefFont, FCellFont);
|
|
|
|
Result := FCellFont;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontColor(ACol, ARow: Integer): TsColor;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
Result := scNotDefined;
|
|
|
|
if (FWorkbook <> nil) and (FWorksheet <> nil) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then begin
|
|
|
|
fnt := FWorkbook.GetFont(cell^.FontIndex);
|
|
|
|
if fnt <> nil then
|
|
|
|
Result := fnt.Color;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontColors(ARect: TGridRect): TsColor;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
clr: TsColor;
|
|
|
|
begin
|
|
|
|
Result := GetCellFontColor(ARect.Left, ARect.Top);
|
|
|
|
clr := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetCellFontColor(c, r);
|
|
|
|
if (Result <> clr) then begin
|
|
|
|
Result := scNotDefined;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontName(ACol, ARow: Integer): String;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
if (FWorkbook <> nil) and (FWorksheet <> nil) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then begin
|
|
|
|
fnt := FWorkbook.GetFont(cell^.FontIndex);
|
|
|
|
if fnt <> nil then
|
|
|
|
Result := fnt.FontName;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontNames(ARect: TGridRect): String;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
s: String;
|
|
|
|
begin
|
|
|
|
Result := GetCellFontName(ARect.Left, ARect.Top);
|
|
|
|
s := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetCellFontName(c, r);
|
|
|
|
if (Result <> '') and (Result <> s) then begin
|
|
|
|
Result := '';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontSize(ACol, ARow: Integer): Single;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
Result := -1.0;
|
|
|
|
if (FWorkbook <> nil) and (FWorksheet <> nil) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then begin
|
|
|
|
fnt := FWorkbook.GetFont(cell^.FontIndex);
|
|
|
|
if fnt <> nil then
|
|
|
|
Result := fnt.Size;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontSizes(ARect: TGridRect): Single;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
sz: Single;
|
|
|
|
begin
|
|
|
|
Result := GetCellFontSize(ARect.Left, ARect.Top);
|
|
|
|
sz := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetCellFontSize(c, r);
|
|
|
|
if (Result <> -1) and not SameValue(Result, sz, 1E-3) then begin
|
|
|
|
Result := -1.0;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontStyle(ACol, ARow: Integer): TsFontStyles;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
Result := [];
|
|
|
|
if (FWorkbook <> nil) and (FWorksheet <> nil) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then begin
|
|
|
|
fnt := FWorkbook.GetFont(cell^.FontIndex);
|
|
|
|
if fnt <> nil then
|
|
|
|
Result := fnt.Style;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetCellFontStyles(ARect: TGridRect): TsFontStyles;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
style: TsFontStyles;
|
|
|
|
begin
|
|
|
|
Result := GetCellFontStyle(ARect.Left, ARect.Top);
|
|
|
|
style := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetCellFontStyle(c, r);
|
|
|
|
if Result <> style then begin
|
|
|
|
Result := [];
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 21:52:04 +00:00
|
|
|
{ Returns the height (in pixels) of the cell at ACol/ARow (of the grid). }
|
2014-04-30 19:09:54 +00:00
|
|
|
function TsCustomWorksheetGrid.GetCellHeight(ACol, ARow: Integer): Integer;
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
s: String;
|
2014-05-11 09:20:52 +00:00
|
|
|
wrapped: Boolean;
|
2014-04-30 19:09:54 +00:00
|
|
|
txtR: TRect;
|
|
|
|
cellR: TRect;
|
|
|
|
flags: Cardinal;
|
|
|
|
begin
|
|
|
|
Result := 0;
|
2014-05-03 21:27:31 +00:00
|
|
|
if ShowHeaders and ((ACol = 0) or (ARow = 0)) then
|
2014-04-30 19:09:54 +00:00
|
|
|
exit;
|
|
|
|
if FWorksheet = nil then
|
|
|
|
exit;
|
|
|
|
|
2014-05-03 21:27:31 +00:00
|
|
|
lCell := FWorksheet.FindCell(ARow-FHeaderCount, ACol-FHeaderCount);
|
2014-04-30 19:09:54 +00:00
|
|
|
if lCell <> nil then begin
|
|
|
|
s := GetCellText(ACol, ARow);
|
|
|
|
if s = '' then
|
|
|
|
exit;
|
|
|
|
DoPrepareCanvas(ACol, ARow, []);
|
2014-05-11 09:20:52 +00:00
|
|
|
wrapped := (uffWordWrap in lCell^.UsedFormattingFields)
|
2014-04-30 19:09:54 +00:00
|
|
|
or (lCell^.TextRotation = rtStacked);
|
|
|
|
// *** multi-line text ***
|
2014-05-11 09:20:52 +00:00
|
|
|
if wrapped then begin
|
2014-04-30 19:09:54 +00:00
|
|
|
// horizontal
|
|
|
|
if ( (uffTextRotation in lCell^.UsedFormattingFields) and
|
|
|
|
(lCell^.TextRotation in [trHorizontal, rtStacked]))
|
|
|
|
or not (uffTextRotation in lCell^.UsedFormattingFields)
|
|
|
|
then begin
|
|
|
|
cellR := CellRect(ACol, ARow);
|
|
|
|
InflateRect(cellR, -constCellPadding, -constCellPadding);
|
|
|
|
txtR := Bounds(cellR.Left, cellR.Top, cellR.Right-cellR.Left, cellR.Bottom-cellR.Top);
|
|
|
|
flags := DT_WORDBREAK and not DT_SINGLELINE;
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(s), Length(s), txtR,
|
|
|
|
DT_CALCRECT or flags);
|
|
|
|
Result := txtR.Bottom - txtR.Top + 2*constCellPadding;
|
|
|
|
end;
|
|
|
|
// rotated wrapped text:
|
|
|
|
// do not consider this because wrapping affects cell height.
|
|
|
|
end else
|
|
|
|
// *** single-line text ***
|
|
|
|
begin
|
|
|
|
// not rotated
|
|
|
|
if ( not (uffTextRotation in lCell^.UsedFormattingFields) or
|
|
|
|
(lCell^.TextRotation = trHorizontal) )
|
|
|
|
then
|
|
|
|
Result := Canvas.TextHeight(s) + 2*constCellPadding
|
|
|
|
else
|
|
|
|
// rotated by +/- 90°
|
|
|
|
if (uffTextRotation in lCell^.UsedFormattingFields) and
|
|
|
|
(lCell^.TextRotation in [rt90DegreeClockwiseRotation, rt90DegreeCounterClockwiseRotation])
|
|
|
|
then
|
|
|
|
Result := Canvas.TextWidth(s) + 2*constCellPadding;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-29 21:58:48 +00:00
|
|
|
{ GetCellText function returns the text to be written in the cell }
|
2014-04-19 19:29:13 +00:00
|
|
|
function TsCustomWorksheetGrid.GetCellText(ACol, ARow: Integer): String;
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
2014-04-29 21:58:48 +00:00
|
|
|
r, c, i: Integer;
|
|
|
|
s: String;
|
2014-04-19 19:29:13 +00:00
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
|
2014-05-03 21:27:31 +00:00
|
|
|
if ShowHeaders then begin
|
|
|
|
// Headers
|
2014-04-19 19:29:13 +00:00
|
|
|
if (ARow = 0) and (ACol = 0) then
|
|
|
|
exit;
|
|
|
|
if (ARow = 0) then begin
|
2014-05-03 21:27:31 +00:00
|
|
|
Result := GetColString(ACol-FHeaderCount);
|
2014-04-19 19:29:13 +00:00
|
|
|
exit;
|
2009-10-06 19:25:18 +00:00
|
|
|
end
|
|
|
|
else
|
2014-04-19 19:29:13 +00:00
|
|
|
if (ACol = 0) then begin
|
|
|
|
Result := IntToStr(ARow);
|
|
|
|
exit;
|
2009-10-06 19:25:18 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
if FWorksheet <> nil then begin
|
2014-05-03 21:27:31 +00:00
|
|
|
r := ARow - FHeaderCount;
|
|
|
|
c := ACol - FHeaderCount;
|
2014-04-19 19:29:13 +00:00
|
|
|
lCell := FWorksheet.FindCell(r, c);
|
2014-04-29 21:58:48 +00:00
|
|
|
if lCell <> nil then begin
|
2014-04-19 19:29:13 +00:00
|
|
|
Result := FWorksheet.ReadAsUTF8Text(r, c);
|
2014-04-29 21:58:48 +00:00
|
|
|
if lCell^.TextRotation = rtStacked then begin
|
|
|
|
s := Result;
|
|
|
|
Result := '';
|
2014-05-28 09:04:42 +00:00
|
|
|
for i:=1 to Length(s) do begin
|
|
|
|
Result := Result + s[i];
|
|
|
|
if i < Length(s) then Result := Result + LineEnding;
|
|
|
|
end;
|
2014-04-29 21:58:48 +00:00
|
|
|
end;
|
|
|
|
end;
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
end;
|
2009-10-06 19:25:18 +00:00
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
{ Determines the text to be passed to the cell editor. }
|
|
|
|
function TsCustomWorksheetGrid.GetEditText(aCol, aRow: Integer): string;
|
|
|
|
begin
|
|
|
|
Result := GetCellText(aCol, aRow);
|
|
|
|
if Assigned(OnGetEditText) then OnGetEditText(Self, aCol, aRow, result);
|
|
|
|
end;
|
|
|
|
|
2014-05-09 22:00:53 +00:00
|
|
|
{ Determines the style of the border between a cell and its neighbor given by
|
|
|
|
ADeltaCol and ADeltaRow (one of them must be 0, the other one can only be +/-1).
|
|
|
|
ACol and ARow are in grid units. }
|
|
|
|
function TsCustomWorksheetGrid.GetBorderStyle(ACol, ARow, ADeltaCol, ADeltaRow: Integer;
|
|
|
|
var ABorderStyle: TsCellBorderStyle): Boolean;
|
|
|
|
var
|
|
|
|
cell, neighborcell: PCell;
|
|
|
|
border, neighborborder: TsCellBorder;
|
|
|
|
r, c: Cardinal;
|
|
|
|
begin
|
|
|
|
Result := true;
|
|
|
|
if (ADeltaCol = -1) and (ADeltaRow = 0) then begin
|
|
|
|
border := cbWest;
|
|
|
|
neighborborder := cbEast;
|
|
|
|
end else
|
|
|
|
if (ADeltaCol = +1) and (ADeltaRow = 0) then begin
|
|
|
|
border := cbEast;
|
|
|
|
neighborborder := cbWest;
|
|
|
|
end else
|
|
|
|
if (ADeltaCol = 0) and (ADeltaRow = -1) then begin
|
|
|
|
border := cbNorth;
|
|
|
|
neighborborder := cbSouth;
|
|
|
|
end else
|
|
|
|
if (ADeltaCol = 0) and (ADeltaRow = +1) then begin
|
|
|
|
border := cbSouth;
|
|
|
|
neighborBorder := cbNorth;
|
|
|
|
end else
|
|
|
|
raise Exception.Create('TsCustomWorksheetGrid: incorrect col/row for GetBorderStyle.');
|
|
|
|
r := GetWorksheetRow(ARow);
|
|
|
|
c := GetWorksheetCol(ACol);
|
|
|
|
cell := FWorksheet.FindCell(r, c);
|
|
|
|
neighborcell := FWorksheet.FindCell(r+ADeltaRow, c+ADeltaCol);
|
|
|
|
// Only cell has border, but neighbor has not
|
|
|
|
if ((cell <> nil) and (border in cell^.Border)) and
|
|
|
|
((neighborcell = nil) or (neighborborder in neighborcell^.Border))
|
|
|
|
then
|
|
|
|
ABorderStyle := cell^.BorderStyles[border]
|
|
|
|
else
|
|
|
|
// Only neighbor has border, cell has not
|
|
|
|
if ((cell = nil) or not (border in cell^.Border)) and
|
|
|
|
(neighborcell <> nil) and (neighborborder in neighborcell^.Border)
|
|
|
|
then
|
|
|
|
ABorderStyle := neighborcell^.BorderStyles[neighborborder]
|
|
|
|
else
|
|
|
|
// Both cells have shared border -> use top or left border
|
|
|
|
if (cell <> nil) and (border in cell^.Border) and
|
|
|
|
(neighborcell <> nil) and (neighborborder in neighborcell^.Border)
|
|
|
|
then begin
|
|
|
|
if (border in [cbNorth, cbWest]) then
|
|
|
|
ABorderStyle := neighborcell^.BorderStyles[neighborborder]
|
|
|
|
else
|
|
|
|
ABorderStyle := cell^.BorderStyles[border];
|
|
|
|
end else
|
|
|
|
Result := false;
|
|
|
|
end;
|
|
|
|
|
2014-06-05 21:57:23 +00:00
|
|
|
function TsCustomWorksheetGrid.GetGridCol(ASheetCol: Cardinal): Integer;
|
|
|
|
begin
|
|
|
|
Result := ASheetCol + FHeaderCount
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetGridRow(ASheetRow: Cardinal): Integer;
|
|
|
|
begin
|
|
|
|
Result := ASheetRow + FHeaderCount;
|
|
|
|
end;
|
|
|
|
|
2014-05-10 12:32:05 +00:00
|
|
|
function TsCustomWorksheetGrid.GetHorAlignment(ACol, ARow: Integer): TsHorAlignment;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := haDefault;
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if cell <> nil then
|
|
|
|
Result := cell^.HorAlignment;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetHorAlignments(ARect: TGridRect): TsHorAlignment;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
horalign: TsHorAlignment;
|
|
|
|
begin
|
|
|
|
Result := GetHorAlignment(ARect.Left, ARect.Top);
|
|
|
|
horalign := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetHorAlignment(c, r);
|
|
|
|
if Result <> horalign then begin
|
|
|
|
Result := haDefault;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-21 21:43:43 +00:00
|
|
|
{ Returns a list of worksheets contained in the file. Useful for assigning to
|
|
|
|
user controls like TabControl, Combobox etc. in order to select a sheet. }
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.GetSheets(const ASheets: TStrings);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
ASheets.Clear;
|
|
|
|
if Assigned(FWorkbook) then
|
|
|
|
for i:=0 to FWorkbook.GetWorksheetCount-1 do
|
|
|
|
ASheets.Add(FWorkbook.GetWorksheetByIndex(i).Name);
|
|
|
|
end;
|
2009-10-06 19:25:18 +00:00
|
|
|
|
2014-05-03 21:27:31 +00:00
|
|
|
function TsCustomWorksheetGrid.GetShowGridLines: Boolean;
|
|
|
|
begin
|
|
|
|
Result := (Options * [goHorzLine, goVertLine] <> []);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetShowHeaders: Boolean;
|
|
|
|
begin
|
|
|
|
Result := FHeaderCount <> 0;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 10:39:14 +00:00
|
|
|
function TsCustomWorksheetGrid.GetTextRotation(ACol, ARow: Integer): TsTextRotation;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := trHorizontal;
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) then
|
|
|
|
Result := cell^.TextRotation;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetTextRotations(ARect: TGridRect): TsTextRotation;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
textrot: TsTextRotation;
|
|
|
|
begin
|
|
|
|
Result := GetTextRotation(ARect.Left, ARect.Top);
|
|
|
|
textrot := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetTextRotation(c, r);
|
|
|
|
if Result <> textrot then begin
|
|
|
|
Result := trHorizontal;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-10 12:32:05 +00:00
|
|
|
function TsCustomWorksheetGrid.GetVertAlignment(ACol, ARow: Integer): TsVertAlignment;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := vaDefault;
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if cell <> nil then
|
|
|
|
Result := cell^.VertAlignment;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetVertAlignments(ARect: TGridRect): TsVertAlignment;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
vertalign: TsVertAlignment;
|
|
|
|
begin
|
|
|
|
Result := GetVertalignment(ARect.Left, ARect.Top);
|
|
|
|
vertalign := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetVertAlignment(c, r);
|
|
|
|
if Result <> vertalign then begin
|
|
|
|
Result := vaDefault;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
function TsCustomWorksheetGrid.GetWordwrap(ACol, ARow: Integer): Boolean;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
cell := FWorksheet.FindCell(GetWorksheetRow(ARow), GetWorksheetCol(ACol));
|
|
|
|
if (cell <> nil) and (uffWordwrap in cell^.UsedFormattingFields) then
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomWorksheetGrid.GetWordwraps(ARect: TGridRect): Boolean;
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
wrapped: Boolean;
|
|
|
|
begin
|
|
|
|
Result := GetWordwrap(ARect.Left, ARect.Top);
|
|
|
|
wrapped := Result;
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do begin
|
|
|
|
Result := GetWordwrap(c, r);
|
|
|
|
if Result <> wrapped then begin
|
|
|
|
Result := false;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 21:52:04 +00:00
|
|
|
{ Calculates the index of the worksheet column that is displayed in the
|
|
|
|
given column of the grid. If the sheet headers are turned on, both numbers
|
|
|
|
differ by 1, otherwise they are equal. Saves an "if" in cases. }
|
2014-05-07 22:44:00 +00:00
|
|
|
function TsCustomWorksheetGrid.GetWorksheetCol(AGridCol: Integer): cardinal;
|
|
|
|
begin
|
|
|
|
Result := AGridCol - FHeaderCount;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 21:52:04 +00:00
|
|
|
{ Calculates the index of the worksheet row that is displayed in the
|
|
|
|
given row of the grid. If the sheet headers are turned on, both numbers
|
|
|
|
differ by 1, otherwise they are equal. Save an "if" in cases. }
|
2014-05-07 22:44:00 +00:00
|
|
|
function TsCustomWorksheetGrid.GetWorksheetRow(AGridRow: Integer): Cardinal;
|
|
|
|
begin
|
|
|
|
Result := AGridRow - FHeaderCount;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Returns if the cell has the given border }
|
|
|
|
function TsCustomWorksheetGrid.HasBorder(ACell: PCell; ABorder: TsCellBorder): Boolean;
|
|
|
|
begin
|
|
|
|
Result := (ACell <> nil) and (uffBorder in ACell^.UsedFormattingfields) and
|
|
|
|
(ABorder in ACell^.Border);
|
|
|
|
end;
|
|
|
|
|
2014-05-08 21:52:04 +00:00
|
|
|
{ Column width or row heights have changed. Stores the new number in the
|
|
|
|
worksheet. }
|
|
|
|
procedure TsCustomWorksheetGrid.HeaderSized(IsColumn: Boolean; index: Integer);
|
|
|
|
var
|
|
|
|
w0: Integer;
|
2014-05-31 21:04:53 +00:00
|
|
|
h, h_pts: Single;
|
2014-05-08 21:52:04 +00:00
|
|
|
begin
|
|
|
|
if FWorksheet = nil then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
Convert_sFont_to_Font(FWorkbook.GetFont(0), Canvas.Font);
|
|
|
|
if IsColumn then begin
|
|
|
|
// The grid's column width is in "pixels", the worksheet's column width is
|
|
|
|
// in "characters".
|
|
|
|
w0 := Canvas.TextWidth('0');
|
|
|
|
FWorksheet.WriteColWidth(GetWorksheetCol(Index), ColWidths[Index] div w0);
|
|
|
|
end else begin
|
|
|
|
// The grid's row heights are in "pixels", the worksheet's row heights are
|
2014-05-31 21:04:53 +00:00
|
|
|
// in "lines"
|
|
|
|
h_pts := PxToPts(RowHeights[Index] - 4, Screen.PixelsPerInch); // in points
|
|
|
|
h := h_pts / (FWorkbook.GetFont(0).Size + ROW_HEIGHT_CORRECTION);
|
2014-05-08 21:52:04 +00:00
|
|
|
FWorksheet.WriteRowHeight(GetWorksheetRow(Index), h);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-22 21:54:24 +00:00
|
|
|
|
2014-05-28 09:04:42 +00:00
|
|
|
{ Internal general text drawing method.
|
2014-05-22 21:54:24 +00:00
|
|
|
- AText: text to be drawn
|
|
|
|
- AMeasureText: text used for checking if the text fits into the text rectangle.
|
|
|
|
If too large and ReplaceTooLong = true, a series of # is drawn.
|
|
|
|
- ARect: Rectangle in which the text is drawn
|
|
|
|
- AJustification: determines whether the text is drawn at the "start" (0),
|
|
|
|
"center" (1) or "end" (2) of the drawing rectangle. Start/center/end are
|
|
|
|
seen along the text drawing direction.
|
|
|
|
- ACellHorAlign: Is the HorAlignment property stored in the cell
|
|
|
|
- ACellVertAlign: Is the VertAlignment property stored in the cell
|
|
|
|
- ATextRot: determines the rotation angle of the text.
|
2014-05-28 09:04:42 +00:00
|
|
|
- ATextWrap: determines if the text can wrap into multiple lines
|
|
|
|
- ReplaceTooLang: if true too-long texts are replaced by a series of # chars
|
|
|
|
filling the cell.
|
|
|
|
The reason to separate AJustification from ACellHorAlign and ACelVertAlign is
|
|
|
|
the output of nfAccounting formatted numbers where the numbers are always
|
|
|
|
right-aligned, and the currency symbol is left-aligned. }
|
2014-05-22 21:54:24 +00:00
|
|
|
procedure TsCustomWorksheetGrid.InternalDrawTextInCell(AText, AMeasureText: String;
|
|
|
|
ARect: TRect; AJustification: Byte; ACellHorAlign: TsHorAlignment;
|
|
|
|
ACellVertAlign: TsVertAlignment; ATextRot: TsTextRotation;
|
|
|
|
ATextWrap, ReplaceTooLong: Boolean);
|
|
|
|
var
|
|
|
|
ts: TTextStyle;
|
|
|
|
flags: Cardinal;
|
|
|
|
txt: String;
|
|
|
|
txtL, txtR: String;
|
|
|
|
txtRect: TRect;
|
|
|
|
P: TPoint;
|
|
|
|
w, h, h0, hline: Integer;
|
|
|
|
i: Integer;
|
|
|
|
L: TStrings;
|
|
|
|
c, r: Integer;
|
|
|
|
wrapped: Boolean;
|
|
|
|
begin
|
|
|
|
wrapped := ATextWrap or (ATextRot = rtStacked);
|
|
|
|
if AMeasureText = '' then txt := AText else txt := AMeasureText;
|
|
|
|
flags := DT_WORDBREAK and not DT_SINGLELINE or DT_CALCRECT;
|
|
|
|
txtRect := ARect;
|
|
|
|
|
|
|
|
if (ATextRot in [trHorizontal, rtStacked]) then begin
|
|
|
|
// HORIZONAL TEXT DRAWING DIRECTION
|
|
|
|
Canvas.Font.Orientation := 0;
|
|
|
|
ts := Canvas.TextStyle;
|
|
|
|
ts.Opaque := false;
|
|
|
|
if wrapped then begin
|
|
|
|
ts.Wordbreak := true;
|
|
|
|
ts.SingleLine := false;
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(txt), Length(txt), txtRect, flags);
|
|
|
|
w := txtRect.Right - txtRect.Left;
|
|
|
|
h := txtRect.Bottom - txtRect.Top;
|
|
|
|
end else begin
|
|
|
|
ts.WordBreak := false;
|
|
|
|
ts.SingleLine := false;
|
|
|
|
w := Canvas.TextWidth(AMeasureText);
|
|
|
|
h := Canvas.TextHeight('Tg');
|
|
|
|
end;
|
|
|
|
|
|
|
|
if ATextRot = rtStacked then begin
|
|
|
|
// Stacked
|
|
|
|
ts.Alignment := HOR_ALIGNMENTS[ACellHorAlign];
|
|
|
|
if h > ARect.Bottom - ARect.Top then begin
|
|
|
|
if ReplaceTooLong then begin
|
|
|
|
txt := '#';
|
|
|
|
repeat
|
|
|
|
txt := txt + '#';
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(txt), Length(txt), txtRect, flags);
|
|
|
|
until txtRect.Bottom - txtRect.Top > ARect.Bottom - ARect.Top;
|
|
|
|
AText := copy(txt, 1, Length(txt)-1);
|
|
|
|
end;
|
|
|
|
ts.Layout := tlTop;
|
|
|
|
end else
|
|
|
|
case AJustification of
|
|
|
|
0: ts.Layout := tlTop;
|
|
|
|
1: ts.Layout := tlCenter;
|
|
|
|
2: ts.Layout := tlBottom;
|
|
|
|
end;
|
|
|
|
Canvas.TextStyle := ts;
|
|
|
|
Canvas.TextRect(ARect, ARect.Left, ARect.Top, AText);
|
|
|
|
end else begin
|
|
|
|
// Horizontal
|
|
|
|
if h > ARect.Bottom - ARect.Top then
|
|
|
|
ts.Layout := tlTop
|
|
|
|
else
|
|
|
|
ts.Layout := VERT_ALIGNMENTS[ACellVertAlign];
|
|
|
|
if w > ARect.Right - ARect.Left then begin
|
|
|
|
if ReplaceTooLong then begin
|
|
|
|
txt := '';
|
|
|
|
repeat
|
|
|
|
txt := txt + '#';
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(txt), Length(txt), txtRect, flags);
|
|
|
|
until txtRect.Right - txtRect.Left > ARect.Right - ARect.Left;
|
|
|
|
AText := Copy(txt, 1, Length(txt)-1);
|
|
|
|
end;
|
|
|
|
ts.Alignment := taLeftJustify;
|
|
|
|
end else
|
|
|
|
case AJustification of
|
|
|
|
0: ts.Alignment := taLeftJustify;
|
|
|
|
1: ts.Alignment := taCenter;
|
|
|
|
2: ts.Alignment := taRightJustify;
|
|
|
|
end;
|
|
|
|
Canvas.TextStyle := ts;
|
|
|
|
Canvas.TextRect(ARect,ARect.Left, ARect.Top, AText);
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
// ROTATED TEXT DRAWING DIRECTION
|
|
|
|
// Since there is not good API for multiline rotated text, we draw the text
|
|
|
|
// line by line.
|
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
txtRect := Bounds(ARect.Left, ARect.Top, ARect.Bottom - ARect.Top, ARect.Right - ARect.Left);
|
|
|
|
hline := Canvas.TextHeight('Tg');
|
|
|
|
if wrapped then begin
|
|
|
|
// Extract wrapped lines
|
|
|
|
L.Text := WrapText(Canvas, txt, txtRect.Right - txtRect.Left);
|
|
|
|
// Calculate size of wrapped text
|
|
|
|
flags := DT_WORDBREAK and not DT_SINGLELINE or DT_CALCRECT;
|
|
|
|
LCLIntf.DrawText(Canvas.Handle, PChar(L.Text), Length(L.Text), txtRect, flags);
|
|
|
|
w := txtRect.Right - txtRect.Left;
|
|
|
|
h := txtRect.Bottom - txtRect.Top;
|
|
|
|
h0 := hline;
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
L.Text := txt;
|
|
|
|
w := Canvas.TextWidth(txt);
|
|
|
|
h := hline;
|
|
|
|
h0 := 0;
|
|
|
|
end;
|
2014-05-28 09:04:42 +00:00
|
|
|
// w and h are seen along the text direction, not x/y!
|
2014-05-22 21:54:24 +00:00
|
|
|
|
|
|
|
if w > ARect.Bottom - ARect.Top then begin
|
|
|
|
if ReplaceTooLong then begin
|
|
|
|
txt := '#';
|
|
|
|
repeat
|
|
|
|
txt := txt + '#';
|
|
|
|
until Canvas.TextWidth(txt) > ARect.Bottom - ARect.Top;
|
|
|
|
L.Text := Copy(txt, 1, Length(txt)-1);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
ts := Canvas.TextStyle;
|
|
|
|
ts.SingleLine := true; // Draw text line by line
|
|
|
|
ts.Clipping := false;
|
|
|
|
ts.Layout := tlTop;
|
|
|
|
ts.Alignment := taLeftJustify;
|
|
|
|
ts.Opaque := false;
|
|
|
|
|
|
|
|
if ATextRot = rt90DegreeClockwiseRotation then begin
|
|
|
|
// Clockwise
|
|
|
|
Canvas.Font.Orientation := -900;
|
|
|
|
case ACellHorAlign of
|
|
|
|
haLeft : P.X := Min(ARect.Right-1, ARect.Left + h - h0);
|
|
|
|
haCenter : P.X := Min(ARect.Right-1, (ARect.Left + ARect.Right + h) div 2);
|
|
|
|
haRight : P.X := ARect.Right - 1;
|
|
|
|
end;
|
|
|
|
for i:= 0 to L.Count-1 do begin
|
|
|
|
w := Canvas.TextWidth(L[i]);
|
|
|
|
case AJustification of
|
|
|
|
0: P.Y := ARect.Top; // corresponds to "top"
|
|
|
|
1: P.Y := Max(ARect.Top, (Arect.Top + ARect.Bottom - w) div 2); // "center"
|
2014-05-28 09:04:42 +00:00
|
|
|
2: P.Y := Max(ARect.Top, ARect.Bottom - w); // "bottom"
|
2014-05-22 21:54:24 +00:00
|
|
|
end; {
|
|
|
|
case vertAlign of
|
|
|
|
vaTop : P.Y := ARect.Top;
|
|
|
|
vaCenter : P.Y := Max(ARect.Top, (ARect.Top + ARect.Bottom - w) div 2);
|
|
|
|
vaBottom : P.Y := Max(ARect.Top, ARect.Bottom - w);
|
|
|
|
end;}
|
|
|
|
Canvas.TextRect(ARect, P.X, P.Y, L[i], ts);
|
|
|
|
dec(P.X, hline);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
// Counter-clockwise
|
|
|
|
Canvas.Font.Orientation := +900;
|
|
|
|
case ACellHorAlign of
|
|
|
|
haLeft : P.X := ARect.Left;
|
|
|
|
haCenter : P.X := Max(ARect.Left, (ARect.Left + ARect.Right - h + h0) div 2);
|
|
|
|
haRight : P.X := MAx(ARect.Left, ARect.Right - h + h0);
|
|
|
|
end;
|
|
|
|
for i:= 0 to L.Count-1 do begin
|
|
|
|
w := Canvas.TextWidth(L[i]);
|
|
|
|
case AJustification of
|
|
|
|
0: P.Y := ARect.Bottom; // like "Bottom"
|
|
|
|
1: P.Y := Min(ARect.Bottom, (ARect.Top + ARect.Bottom + w) div 2); // "Center"
|
|
|
|
2: P.Y := Min(ARect.Bottom, ARect.Top + w); // like "top"
|
|
|
|
end; {
|
|
|
|
case vertAlign of
|
|
|
|
vaTop : P.Y := Min(ARect.Bottom, ARect.Top + w);
|
|
|
|
vaCenter : P.Y := Min(ARect.Bottom, (ARect.Top + ARect.Bottom + w) div 2);
|
|
|
|
vaBottom : P.Y := ARect.Bottom;
|
|
|
|
end;}
|
|
|
|
Canvas.TextRect(ARect, P.X, P.Y, L[i], ts);
|
|
|
|
inc(P.X, hline);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-08 15:54:29 +00:00
|
|
|
{ Catches the ESC key during editing in order to restore the old cell text }
|
|
|
|
procedure TsCustomWorksheetGrid.KeyDown(var Key : Word; Shift : TShiftState);
|
|
|
|
begin
|
|
|
|
if (Key = VK_ESCAPE) and FEditing then begin
|
|
|
|
SetEditText(Col, Row, FOldEditText);
|
|
|
|
EditorHide;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.Loaded;
|
|
|
|
begin
|
|
|
|
inherited;
|
2014-05-28 21:26:38 +00:00
|
|
|
NewWorksheet(FInitColCount, FInitRowCount);
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-09 22:00:53 +00:00
|
|
|
{ Repaints after moving selection to avoid spurious rests of the old thick
|
|
|
|
selection border. }
|
|
|
|
procedure TsCustomWorksheetGrid.MoveSelection;
|
|
|
|
begin
|
2014-05-11 09:20:52 +00:00
|
|
|
//Refresh;
|
|
|
|
inherited;
|
2014-05-09 22:00:53 +00:00
|
|
|
Refresh;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 21:52:04 +00:00
|
|
|
{ Is called when editing starts. Stores the old text just for the case that
|
|
|
|
the user presses ESC to cancel editing. }
|
2014-05-08 15:54:29 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SelectEditor;
|
|
|
|
begin
|
|
|
|
FOldEditText := GetCellText(Col, Row);
|
|
|
|
inherited;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 11:56:20 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetBackgroundColor(ACol, ARow: Integer;
|
|
|
|
AValue: TsColor);
|
|
|
|
var
|
|
|
|
c, r: Cardinal;
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then begin
|
2014-05-11 11:56:20 +00:00
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
c := GetWorksheetCol(ACol);
|
|
|
|
r := GetWorksheetRow(ARow);
|
|
|
|
FWorksheet.WriteBackgroundColor(r, c, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetBackgroundColors(ARect: TGridRect;
|
|
|
|
AValue: TsColor);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetBackgroundColor(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetCellBorder(ACol, ARow: Integer;
|
|
|
|
AValue: TsCellBorders);
|
|
|
|
var
|
|
|
|
c, r: Cardinal;
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then begin
|
2014-05-11 09:20:52 +00:00
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
c := GetWorksheetCol(ACol);
|
|
|
|
r := GetWorksheetRow(ARow);
|
|
|
|
FWorksheet.WriteBorders(r, c, AValue);
|
|
|
|
FixNeighborCellBorders(ACol, ARow);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellBorders(ARect: TGridRect;
|
|
|
|
AValue: TsCellBorders);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellBorder(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellBorderStyle(ACol, ARow: Integer;
|
|
|
|
ABorder: TsCellBorder; AValue: TsCellBorderStyle);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then begin
|
2014-05-11 09:20:52 +00:00
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
FWorksheet.WriteBorderStyle(GetWorksheetRow(ARow), GetWorksheetCol(ACol), ABorder, AValue);
|
|
|
|
FixNeighborCellBorders(ACol, ARow);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellBorderStyles(ARect: TGridRect;
|
|
|
|
ABorder: TsCellBorder; AValue: TsCellBorderStyle);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellBorderStyle(c, r, ABorder, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 16:16:59 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetCellFont(ACol, ARow: Integer; AValue: TFont);
|
|
|
|
var
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
FCellFont.Assign(AValue);
|
|
|
|
if Assigned(FWorksheet) then begin
|
|
|
|
fnt := TsFont.Create;
|
|
|
|
try
|
|
|
|
Convert_Font_To_sFont(FCellFont, fnt);
|
|
|
|
FWorksheet.WriteFont(GetWorksheetRow(ARow), GetWorksheetCol(ACol),
|
|
|
|
fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
|
|
|
|
finally
|
|
|
|
fnt.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFonts(ARect: TGridRect;
|
|
|
|
AValue: TFont);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellFont(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontColor(ACol, ARow: Integer; AValue: TsColor);
|
|
|
|
begin
|
|
|
|
if Assigned(FWorksheet) then
|
|
|
|
FWorksheet.WriteFontColor(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontColors(ARect: TGridRect; AValue: TsColor);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellFontColor(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontName(ACol, ARow: Integer; AValue: String);
|
|
|
|
begin
|
|
|
|
if Assigned(FWorksheet) then
|
|
|
|
FWorksheet.WriteFontName(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontNames(ARect: TGridRect; AValue: String);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellFontName(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontSize(ACol, ARow: Integer;
|
|
|
|
AValue: Single);
|
|
|
|
begin
|
|
|
|
if Assigned(FWorksheet) then
|
|
|
|
FWorksheet.WriteFontSize(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontSizes(ARect: TGridRect;
|
|
|
|
AValue: Single);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellFontSize(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontStyle(ACol, ARow: Integer;
|
|
|
|
AValue: TsFontStyles);
|
|
|
|
begin
|
|
|
|
if Assigned(FWorksheet) then
|
|
|
|
FWorksheet.WriteFontStyle(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetCellFontStyles(ARect: TGridRect;
|
|
|
|
AValue: TsFontStyles);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetCellFontStyle(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
{ Fetches the text that is currently in the editor. It is not yet transferred
|
|
|
|
to the Worksheet because input is checked only at the end of editing. }
|
|
|
|
procedure TsCustomWorksheetGrid.SetEditText(ACol, ARow: Longint; const AValue: string);
|
|
|
|
begin
|
|
|
|
FEditText := AValue;
|
|
|
|
FEditing := true;
|
|
|
|
inherited SetEditText(aCol, aRow, aValue);
|
|
|
|
end;
|
|
|
|
|
2014-05-04 18:07:54 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetFrozenCols(AValue: Integer);
|
|
|
|
begin
|
|
|
|
FFrozenCols := AValue;
|
|
|
|
Setup;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetFrozenRows(AValue: Integer);
|
|
|
|
begin
|
|
|
|
FFrozenRows := AValue;
|
|
|
|
Setup;
|
|
|
|
end;
|
|
|
|
|
2014-05-10 12:32:05 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetHorAlignment(ACol, ARow: Integer;
|
|
|
|
AValue: TsHorAlignment);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then
|
2014-05-10 12:32:05 +00:00
|
|
|
FWorksheet.WriteHorAlignment(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetHorAlignments(ARect: TGridRect;
|
|
|
|
AValue: TsHorAlignment);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetHorAlignment(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-08 15:54:29 +00:00
|
|
|
{ Shows / hides the worksheet's grid lines }
|
2014-05-03 21:27:31 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetShowGridLines(AValue: Boolean);
|
2014-04-19 19:29:13 +00:00
|
|
|
begin
|
2014-05-11 09:20:52 +00:00
|
|
|
if AValue = GetShowGridLines then
|
|
|
|
Exit;
|
|
|
|
|
2014-05-03 21:27:31 +00:00
|
|
|
if AValue then
|
|
|
|
Options := Options + [goHorzLine, goVertLine]
|
|
|
|
else
|
|
|
|
Options := Options - [goHorzLine, goVertLine];
|
2014-05-11 16:22:48 +00:00
|
|
|
|
|
|
|
if FWorksheet <> nil then
|
|
|
|
if AValue then
|
|
|
|
FWorksheet.Options := FWorksheet.Options + [soShowGridLines]
|
|
|
|
else
|
|
|
|
FWorksheet.Options := FWorksheet.Options - [soShowGridLines];
|
2014-05-03 21:27:31 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-08 15:54:29 +00:00
|
|
|
{ Shows / hides the worksheet's row and column headers. }
|
2014-05-03 21:27:31 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetShowHeaders(AValue: Boolean);
|
|
|
|
begin
|
|
|
|
if AValue = GetShowHeaders then Exit;
|
2014-05-11 16:22:48 +00:00
|
|
|
|
2014-05-03 21:27:31 +00:00
|
|
|
FHeaderCount := ord(AValue);
|
2014-05-11 16:22:48 +00:00
|
|
|
if FWorksheet <> nil then
|
|
|
|
if AValue then
|
|
|
|
FWorksheet.Options := FWorksheet.Options + [soShowHeaders]
|
|
|
|
else
|
|
|
|
FWorksheet.Options := FWorksheet.Options - [soShowHeaders];
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
Setup;
|
|
|
|
end;
|
2009-10-06 19:25:18 +00:00
|
|
|
|
2014-05-11 10:39:14 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetTextRotation(ACol, ARow: Integer;
|
|
|
|
AValue: TsTextRotation);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then
|
2014-05-11 10:39:14 +00:00
|
|
|
FWorksheet.WriteTextRotation(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetTextRotations(ARect: TGridRect;
|
|
|
|
AValue: TsTextRotation);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetTextRotation(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.Setup;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
lCol: PCol;
|
2014-04-20 14:57:23 +00:00
|
|
|
lRow: PRow;
|
2014-05-04 18:07:54 +00:00
|
|
|
fc, fr: Integer;
|
2014-04-19 19:29:13 +00:00
|
|
|
begin
|
|
|
|
if (FWorksheet = nil) or (FWorksheet.GetCellCount = 0) then begin
|
2014-05-03 21:27:31 +00:00
|
|
|
if ShowHeaders then begin
|
2014-05-28 21:26:38 +00:00
|
|
|
ColCount := FInitColCount + 1; //2;
|
|
|
|
RowCount := FInitRowCount + 1; //2;
|
2014-04-19 19:29:13 +00:00
|
|
|
FixedCols := 1;
|
|
|
|
FixedRows := 1;
|
|
|
|
ColWidths[0] := Canvas.TextWidth(' 999999 ');
|
|
|
|
end else begin
|
|
|
|
FixedCols := 0;
|
|
|
|
FixedRows := 0;
|
2014-05-28 21:26:38 +00:00
|
|
|
ColCount := FInitColCount; //0;
|
|
|
|
RowCount := FInitRowCount; //0;
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
end else
|
2014-05-04 18:07:54 +00:00
|
|
|
if FWorksheet <> nil then begin
|
2014-05-26 15:27:35 +00:00
|
|
|
ColCount := FWorksheet.GetLastColIndex + 1 + FHeaderCount;
|
|
|
|
RowCount := FWorksheet.GetLastRowIndex + 1 + FHeaderCount;
|
2014-05-04 18:07:54 +00:00
|
|
|
FixedCols := FFrozenCols + FHeaderCount;
|
|
|
|
FixedRows := FFrozenRows + FHeaderCount;
|
|
|
|
if ShowHeaders then begin
|
|
|
|
ColWidths[0] := Canvas.TextWidth(' 999999 ');
|
|
|
|
RowHeights[0] := DefaultRowHeight;
|
|
|
|
end;
|
2014-05-03 21:27:31 +00:00
|
|
|
for i := FHeaderCount to ColCount-1 do begin
|
|
|
|
lCol := FWorksheet.FindCol(i - FHeaderCount);
|
2014-04-19 19:29:13 +00:00
|
|
|
if (lCol <> nil) then
|
|
|
|
ColWidths[i] := CalcColWidth(lCol^.Width)
|
|
|
|
else
|
|
|
|
ColWidths[i] := DefaultColWidth;
|
|
|
|
end;
|
2014-05-03 21:27:31 +00:00
|
|
|
for i := FHeaderCount to RowCount-1 do begin
|
|
|
|
lRow := FWorksheet.FindRow(i - FHeaderCount);
|
2014-05-07 18:31:27 +00:00
|
|
|
if (lRow = nil) then
|
2014-05-03 20:12:44 +00:00
|
|
|
RowHeights[i] := CalcAutoRowHeight(i)
|
|
|
|
else
|
|
|
|
RowHeights[i] := CalcRowHeight(lRow^.Height);
|
2014-04-30 19:09:54 +00:00
|
|
|
end;
|
2014-05-04 18:07:54 +00:00
|
|
|
end;
|
2014-05-07 22:44:00 +00:00
|
|
|
Invalidate;
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-10 12:32:05 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetVertAlignment(ACol, ARow: Integer;
|
|
|
|
AValue: TsVertAlignment);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then
|
2014-05-10 12:32:05 +00:00
|
|
|
FWorksheet.WriteVertAlignment(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetVertAlignments(ARect: TGridRect;
|
|
|
|
AValue: TsVertAlignment);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetVertAlignment(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-11 09:20:52 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SetWordwrap(ACol, ARow: Integer;
|
|
|
|
AValue: Boolean);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if Assigned(FWorksheet) then
|
2014-05-11 09:20:52 +00:00
|
|
|
FWorksheet.WriteWordwrap(GetWorksheetRow(ARow), GetWorksheetCol(ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomWorksheetGrid.SetWordwraps(ARect: TGridRect;
|
|
|
|
AValue: Boolean);
|
|
|
|
var
|
|
|
|
c,r: Integer;
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
for c := ARect.Left to ARect.Right do
|
|
|
|
for r := ARect.Top to ARect.Bottom do
|
|
|
|
SetWordwrap(c, r, AValue);
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.LoadFromWorksheet(AWorksheet: TsWorksheet);
|
|
|
|
begin
|
|
|
|
FWorksheet := AWorksheet;
|
2014-05-03 21:27:31 +00:00
|
|
|
if FWorksheet <> nil then begin
|
2014-05-07 22:44:00 +00:00
|
|
|
FWorksheet.OnChangeCell := @ChangedCellHandler;
|
2014-05-08 21:52:04 +00:00
|
|
|
FWorksheet.OnChangeFont := @ChangedFontHandler;
|
2014-05-04 18:07:54 +00:00
|
|
|
ShowHeaders := (soShowHeaders in FWorksheet.Options);
|
|
|
|
ShowGridLines := (soShowGridLines in FWorksheet.Options);
|
|
|
|
if (soHasFrozenPanes in FWorksheet.Options) then begin
|
|
|
|
FrozenCols := FWorksheet.LeftPaneWidth;
|
|
|
|
FrozenRows := FWorksheet.TopPaneHeight;
|
|
|
|
end else begin
|
|
|
|
FrozenCols := 0;
|
|
|
|
FrozenRows := 0;
|
|
|
|
end;
|
2014-05-11 09:20:52 +00:00
|
|
|
Row := FrozenRows;
|
|
|
|
Col := FrozenCols;
|
2014-05-03 21:27:31 +00:00
|
|
|
end;
|
2014-04-19 19:29:13 +00:00
|
|
|
Setup;
|
2009-10-06 19:25:18 +00:00
|
|
|
end;
|
|
|
|
|
2010-05-25 09:11:02 +00:00
|
|
|
procedure TsCustomWorksheetGrid.LoadFromSpreadsheetFile(AFileName: string;
|
|
|
|
AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer);
|
|
|
|
begin
|
2014-05-07 22:44:00 +00:00
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
FreeAndNil(FWorkbook);
|
|
|
|
FWorkbook := TsWorkbook.Create;
|
2014-05-23 23:13:49 +00:00
|
|
|
FWorkbook.ReadFormulas := FReadFormulas;
|
2014-05-07 22:44:00 +00:00
|
|
|
FWorkbook.ReadFromFile(AFileName, AFormat);
|
|
|
|
LoadFromWorksheet(FWorkbook.GetWorksheetByIndex(AWorksheetIndex));
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
2010-05-25 09:11:02 +00:00
|
|
|
end;
|
|
|
|
|
2011-06-16 07:55:24 +00:00
|
|
|
procedure TsCustomWorksheetGrid.LoadFromSpreadsheetFile(AFileName: string;
|
|
|
|
AWorksheetIndex: Integer);
|
|
|
|
begin
|
2014-05-07 22:44:00 +00:00
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
FreeAndNil(FWorkbook);
|
|
|
|
FWorkbook := TsWorkbook.Create;
|
2014-05-23 23:13:49 +00:00
|
|
|
FWorkbook.ReadFormulas := FReadFormulas;
|
2014-05-07 22:44:00 +00:00
|
|
|
FWorkbook.ReadFromFile(AFilename);
|
|
|
|
LoadFromWorksheet(FWorkbook.GetWorksheetByIndex(AWorksheetIndex));
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
2011-06-16 07:55:24 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-28 21:26:38 +00:00
|
|
|
procedure TsCustomWorksheetGrid.NewWorksheet(AColCount, ARowCount: Integer);
|
|
|
|
begin
|
|
|
|
BeginUpdate;
|
|
|
|
try
|
|
|
|
FreeAndNil(FWorkbook);
|
|
|
|
FWorkbook := TsWorkbook.Create;
|
|
|
|
FWorksheet := FWorkbook.AddWorksheet('Sheet1');
|
2014-06-03 22:04:11 +00:00
|
|
|
FWorksheet.OnChangeCell := @ChangedCellHandler;
|
|
|
|
FWorksheet.OnChangeFont := @ChangedFontHandler;
|
2014-05-28 21:26:38 +00:00
|
|
|
FInitColCount := AColCount;
|
|
|
|
FInitRowCount := ARowCount;
|
|
|
|
Setup;
|
|
|
|
finally
|
|
|
|
EndUpdate;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
{ Writes the workbook behind the grid to a spreadsheet file. }
|
|
|
|
procedure TsCustomWorksheetGrid.SaveToSpreadsheetFile(AFileName: String;
|
|
|
|
AFormat: TsSpreadsheetFormat; AOverwriteExisting: Boolean = true);
|
2010-05-01 18:10:38 +00:00
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if FWorkbook <> nil then
|
2014-05-07 22:44:00 +00:00
|
|
|
FWorkbook.WriteToFile(AFileName, AFormat, AOverwriteExisting);
|
|
|
|
end;
|
2010-05-01 18:10:38 +00:00
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SaveToSpreadsheetFile(AFileName: String;
|
|
|
|
AOverwriteExisting: Boolean = true);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if FWorkbook <> nil then
|
2014-05-07 22:44:00 +00:00
|
|
|
FWorkbook.WriteToFile(AFileName, AOverwriteExisting);
|
2010-05-01 18:10:38 +00:00
|
|
|
end;
|
|
|
|
|
2014-04-19 19:29:13 +00:00
|
|
|
procedure TsCustomWorksheetGrid.SelectSheetByIndex(AIndex: Integer);
|
|
|
|
begin
|
2014-05-11 16:16:59 +00:00
|
|
|
if FWorkbook <> nil then
|
|
|
|
LoadFromWorksheet(FWorkbook.GetWorksheetByIndex(AIndex));
|
2014-04-19 19:29:13 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-08 12:12:06 +00:00
|
|
|
|
2014-04-21 21:43:43 +00:00
|
|
|
initialization
|
2014-05-31 21:04:53 +00:00
|
|
|
fpsutils.ScreenPixelsPerInch := Screen.PixelsPerInch;
|
2014-04-21 21:43:43 +00:00
|
|
|
|
|
|
|
finalization
|
|
|
|
FreeAndNil(FillPattern_BIFF2);
|
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
end.
|