From 8c38687a90cbf6542696926bfe1e0580cc942495 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Fri, 14 Nov 2014 23:27:49 +0000 Subject: [PATCH] fpspreadsheet: Add actions for font and background color selection. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3727 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpspreadsheet/examples/fpsctrls/main.lfm | 229 +++++++++----- .../fpspreadsheet/examples/fpsctrls/main.pas | 5 + components/fpspreadsheet/fpsactions.pas | 293 ++++++++++++++++-- .../fpspreadsheet/fpspreadsheetgrid.pas | 189 +---------- components/fpspreadsheet/fpsvisualutils.pas | 227 ++++++++++++++ .../laz_fpspreadsheet_visual.lpk | 6 +- .../laz_fpspreadsheet_visual.pas | 4 +- 7 files changed, 677 insertions(+), 276 deletions(-) create mode 100644 components/fpspreadsheet/fpsvisualutils.pas diff --git a/components/fpspreadsheet/examples/fpsctrls/main.lfm b/components/fpspreadsheet/examples/fpsctrls/main.lfm index 840b5b623..558178b63 100644 --- a/components/fpspreadsheet/examples/fpsctrls/main.lfm +++ b/components/fpspreadsheet/examples/fpsctrls/main.lfm @@ -4,7 +4,7 @@ object Form1: TForm1 Top = 243 Width = 925 Caption = 'Form1' - ClientHeight = 575 + ClientHeight = 580 ClientWidth = 925 Menu = MainMenu ShowHint = True @@ -12,7 +12,7 @@ object Form1: TForm1 object Panel1: TPanel Left = 0 Height = 36 - Top = 28 + Top = 26 Width = 925 Align = alTop BevelOuter = bvNone @@ -30,7 +30,7 @@ object Form1: TForm1 end object CellIndicator: TsCellIndicator Left = 95 - Height = 28 + Height = 23 Top = 4 Width = 80 TabOrder = 1 @@ -39,7 +39,7 @@ object Form1: TForm1 end object CellEdit: TsCellEdit Left = 184 - Height = 28 + Height = 23 Top = 4 Width = 731 Anchors = [akTop, akLeft, akRight] @@ -50,8 +50,8 @@ object Form1: TForm1 end object WorkbookTabControl: TsWorkbookTabControl Left = 0 - Height = 511 - Top = 64 + Height = 518 + Top = 62 Width = 672 TabIndex = 0 Tabs.Strings = ( @@ -62,8 +62,8 @@ object Form1: TForm1 WorkbookSource = WorkbookSource object WorksheetGrid: TsWorksheetGrid Left = 2 - Height = 481 - Top = 28 + Height = 493 + Top = 23 Width = 668 FrozenCols = 0 FrozenRows = 0 @@ -116,8 +116,8 @@ object Form1: TForm1 end object InspectorTabControl: TTabControl Left = 677 - Height = 511 - Top = 64 + Height = 518 + Top = 62 Width = 248 OnChange = InspectorTabControlChange TabIndex = 0 @@ -131,8 +131,8 @@ object Form1: TForm1 TabOrder = 2 object Inspector: TsSpreadsheetInspector Left = 2 - Height = 481 - Top = 28 + Height = 493 + Top = 23 Width = 244 Align = alClient RowCount = 25 @@ -144,7 +144,7 @@ object Form1: TForm1 'Options=boAutoCalc, boCalcBeforeSaving, boReadFormulas' 'FormatSettings=' ' ThousandSeparator=.' - ' DecimalSeparator=,' + ' DecimalSeparator=.' ' ListSeparator=;' ' DateSeparator=.' ' TimeSeparator=:' @@ -170,22 +170,22 @@ object Form1: TForm1 WorkbookSource = WorkbookSource Mode = imWorkbook ColWidths = ( - 109 - 110 + 111 + 112 ) end end object Splitter1: TSplitter Left = 672 - Height = 511 - Top = 64 + Height = 518 + Top = 62 Width = 5 Align = alRight ResizeAnchor = akRight end object ToolBar1: TToolBar Left = 0 - Height = 28 + Height = 26 Top = 0 Width = 925 AutoSize = True @@ -196,181 +196,199 @@ object Form1: TForm1 TabOrder = 4 object ToolButton1: TToolButton Left = 1 - Top = 2 + Top = 0 Action = AcAddWorksheet end object ToolButton2: TToolButton Left = 24 - Top = 2 + Top = 0 Action = AcDeleteWorksheet end object ToolButton3: TToolButton Left = 47 - Top = 2 + Top = 0 Action = acRenameWorksheet end object ToolButton4: TToolButton Left = 75 Height = 24 - Top = 2 + Top = 0 Width = 3 Caption = 'ToolButton4' Style = tbsDivider end object ToolButton5: TToolButton - Left = 537 - Top = 2 + Left = 593 + Top = 0 Action = AcFileExit end object ToolButton6: TToolButton - Left = 78 - Top = 2 + Left = 101 + Top = 0 Action = AcFontBold end object ToolButton7: TToolButton - Left = 101 - Top = 2 + Left = 124 + Top = 0 Action = AcFontItalic end object ToolButton8: TToolButton - Left = 124 - Top = 2 + Left = 147 + Top = 0 Action = AcFontUnderline end object ToolButton9: TToolButton Left = 70 Height = 24 - Top = 2 + Top = 0 Width = 5 Caption = 'ToolButton9' Style = tbsDivider end object ToolButton10: TToolButton - Left = 170 + Left = 193 Height = 24 - Top = 2 + Top = 0 Width = 5 Caption = 'ToolButton10' Style = tbsDivider end object ToolButton11: TToolButton - Left = 147 - Top = 2 + Left = 170 + Top = 0 Action = AcFontStrikeout end object ToolButton12: TToolButton - Left = 175 - Top = 2 + Left = 198 + Top = 0 Action = AcHorAlignLeft end object ToolButton13: TToolButton - Left = 198 - Top = 2 + Left = 221 + Top = 0 Action = AcHorAlignCenter end object ToolButton14: TToolButton - Left = 221 - Top = 2 + Left = 244 + Top = 0 Action = AcHorAlignRight end object ToolButton15: TToolButton - Left = 244 + Left = 267 Height = 24 - Top = 2 + Top = 0 Width = 5 Caption = 'ToolButton15' Style = tbsDivider end object ToolButton16: TToolButton - Left = 249 - Top = 2 + Left = 272 + Top = 0 Action = AcVertAlignTop end object ToolButton17: TToolButton - Left = 272 - Top = 2 + Left = 295 + Top = 0 Action = AcVertAlignCenter end object ToolButton18: TToolButton - Left = 295 - Top = 2 + Left = 318 + Top = 0 Action = AcVertAlignBottom end object ToolButton19: TToolButton - Left = 318 + Left = 341 Height = 24 - Top = 2 + Top = 0 Width = 5 Caption = 'ToolButton19' Style = tbsDivider end object ToolButton20: TToolButton - Left = 323 + Left = 374 Hint = 'Number format' - Top = 2 + Top = 0 Caption = 'ToolButton20' DropdownMenu = PuNumFormat ImageIndex = 15 Style = tbsDropDown end object ToolButton21: TToolButton - Left = 381 + Left = 432 Hint = 'Currency format' - Top = 2 + Top = 0 Caption = 'ToolButton21' DropdownMenu = PuCurrencyFormat ImageIndex = 17 Style = tbsDropDown end object ToolButton22: TToolButton - Left = 358 - Top = 2 + Left = 409 + Top = 0 Action = AcNumFormatPercentage end object ToolButton23: TToolButton - Left = 486 + Left = 537 Height = 24 - Top = 2 + Top = 0 Width = 5 Caption = 'ToolButton23' Style = tbsDivider end object ToolButton24: TToolButton - Left = 416 + Left = 467 Hint = 'Date format' - Top = 2 + Top = 0 Caption = 'ToolButton24' DropdownMenu = PuDateFormat ImageIndex = 18 Style = tbsDropDown end object ToolButton25: TToolButton - Left = 451 + Left = 502 Hint = 'Time format' - Top = 2 + Top = 0 Caption = 'ToolButton25' DropdownMenu = PuTimeFormat ImageIndex = 19 Style = tbsDropDown end object ToolButton26: TToolButton - Left = 491 - Top = 2 + Left = 542 + Top = 0 Action = AcDecDecimals end object ToolButton27: TToolButton - Left = 514 - Top = 2 + Left = 565 + Top = 0 Action = AcIncDecimals end object ToolButton28: TToolButton - Left = 560 + Left = 588 Height = 24 - Top = 2 + Top = 0 Width = 5 Caption = 'ToolButton28' Style = tbsDivider end + object ToolButton29: TToolButton + Left = 78 + Top = 0 + Action = AcCellFont + end + object ToolButton30: TToolButton + Left = 346 + Top = 0 + Action = AcBackgroundColor + end + object ToolButton31: TToolButton + Left = 369 + Height = 24 + Top = 0 + Width = 5 + Caption = 'ToolButton31' + Style = tbsDivider + end end object WorkbookSource: TsWorkbookSource AutoDetectFormat = False @@ -637,22 +655,57 @@ object Form1: TForm1 object AcIncDecimals: TsDecimalsAction Category = 'FPSpreadsheet' WorkbookSource = WorkbookSource - Caption = 'Decimals' ImageIndex = 21 end object AcDecDecimals: TsDecimalsAction Category = 'FPSpreadsheet' WorkbookSource = WorkbookSource - Caption = 'Decimals' ImageIndex = 20 Delta = -1 end + object AcCellFont: TsFontAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'AcCellFont' + ImageIndex = 14 + Dialog.MinFontSize = 0 + Dialog.MaxFontSize = 0 + end + object AcBackgroundColor: TsBackgroundColorAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'AcBackgroundColor' + ImageIndex = 22 + Dialog.Color = clBlack + Dialog.CustomColors.Strings = ( + 'ColorA=000000' + 'ColorB=000080' + 'ColorC=008000' + 'ColorD=008080' + 'ColorE=800000' + 'ColorF=800080' + 'ColorG=808000' + 'ColorH=808080' + 'ColorI=C0C0C0' + 'ColorJ=0000FF' + 'ColorK=00FF00' + 'ColorL=00FFFF' + 'ColorM=FF0000' + 'ColorN=FF00FF' + 'ColorO=FFFF00' + 'ColorP=FFFFFF' + 'ColorQ=C0DCC0' + 'ColorR=F0CAA6' + 'ColorS=F0FBFF' + 'ColorT=A4A0A0' + ) + end end object ImageList: TImageList left = 432 top = 249 Bitmap = { - 4C69340000001000000010000000003F9300003F9300003F9300003F9424003F + 4C69350000001000000010000000003F9300003F9300003F9300003F9424003F 948A003E93CC004095CC004095CC004095CC004095CC004095CC004095CC0040 95CC004095CC00409599003F9400003F9300003F9324003F938A0E4B9CD33F76 C0EC5D90D4FF3365A9FFA0A0A0FFA9A9A9FFA9A9A9FFAAAAAAFFACACACFFAEAE @@ -1356,6 +1409,38 @@ object Form1: TForm1 010001010146010101CB010101CC00000048000000000000004E000000E40000 00E900000053FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006B6FFEFF6B6FFEFF6B6F + FEFFFFFFFF0073AAFFFF73AAFFFF73AAFFFFFFFFFF0067D5F0FF67D5F0FF67D5 + F0FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006B6FFEFF6B6FFEFF6B6F + FEFFFFFFFF0073AAFFFF73AAFFFF73AAFFFFFFFFFF0067D5F0FF67D5F0FF67D5 + F0FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006B6FFEFF6B6FFEFF6B6F + FEFFFFFFFF0073AAFFFF73AAFFFF73AAFFFFFFFFFF0067D5F0FF67D5F0FF67D5 + F0FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2EBD0FFB2EBD0FFB2EB + D0FFFFFFFF006DCC50FF6DCC50FF6DCC50FFFFFFFF00EBB060FFEBB060FFEBB0 + 60FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2EBD0FFB2EBD0FFB2EB + D0FFFFFFFF006DCC50FF6DCC50FF6DCC50FFFFFFFF00EBB060FFEBB060FFEBB0 + 60FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B2EBD0FFB2EBD0FFB2EB + D0FFFFFFFF006DCC50FF6DCC50FF6DCC50FFFFFFFF00EBB060FFEBB060FFEBB0 + 60FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B07A58FFB07A58FFB07A + 58FFFFFFFF00DD9BD9FFDD9BD9FFDD9BD9FFFFFFFF00B177FFFFB177FFFFB177 + FFFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B07A58FFB07A58FFB07A + 58FFFFFFFF00DD9BD9FFDD9BD9FFDD9BD9FFFFFFFF00B177FFFFB177FFFFB177 + FFFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B07A58FFB07A58FFB07A + 58FFFFFFFF00DD9BD9FFDD9BD9FFDD9BD9FFFFFFFF00B177FFFFB177FFFFB177 + FFFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF007F7F554D7F7F55667F7F55667F7F55667F7F 55667F7F55667F7F55667F7F55667F7F55667F7F55667F7F55667F7F55667F7F 55667F7F55667F7F55667F7F554D7D7D5367FFFFFFFFFFFFFFFFFFFFFFFFFFFF diff --git a/components/fpspreadsheet/examples/fpsctrls/main.pas b/components/fpspreadsheet/examples/fpsctrls/main.pas index 3675d5ff9..32d60837f 100644 --- a/components/fpspreadsheet/examples/fpsctrls/main.pas +++ b/components/fpspreadsheet/examples/fpsctrls/main.pas @@ -92,6 +92,8 @@ type AcNumFormatTimeInterval: TsNumberFormatAction; AcIncDecimals: TsDecimalsAction; AcDecDecimals: TsDecimalsAction; + AcCellFont: TsFontAction; + AcBackgroundColor: TsBackgroundColorAction; ToolButton11: TToolButton; ToolButton12: TToolButton; ToolButton13: TToolButton; @@ -122,7 +124,10 @@ type ToolButton26: TToolButton; ToolButton27: TToolButton; ToolButton28: TToolButton; + ToolButton29: TToolButton; ToolButton3: TToolButton; + ToolButton30: TToolButton; + ToolButton31: TToolButton; ToolButton4: TToolButton; ToolButton5: TToolButton; ToolButton6: TToolButton; diff --git a/components/fpspreadsheet/fpsactions.pas b/components/fpspreadsheet/fpsactions.pas index fddb26616..f7150466a 100644 --- a/components/fpspreadsheet/fpsactions.pas +++ b/components/fpspreadsheet/fpsactions.pas @@ -3,7 +3,7 @@ unit fpsActions; interface uses - SysUtils, Classes, Controls, ActnList, + SysUtils, Classes, Controls, Graphics, ActnList, StdActns, Dialogs, fpspreadsheet, fpspreadsheetctrls; type @@ -25,7 +25,6 @@ type property WorkbookSource: TsWorkbookSource read FWorkbookSource write FWorkbookSource; end; - { --- Actions related to worksheets --- } TsWorksheetAction = class(TsSpreadsheetAction) @@ -97,6 +96,8 @@ type // protected procedure ApplyFormatToCell(ACell: PCell); virtual; + procedure ApplyFormatToRange(ARange: TsCellrange); virtual; + procedure ApplyFormatToSelection; virtual; procedure ExtractFromCell(ACell: PCell); virtual; public procedure ExecuteTarget(Target: TObject); override; @@ -246,14 +247,97 @@ type end; + { --- Actions like from TCommonDialogAction --- } + + TsCommonDialogSpreadsheetAction = class(TsCellFormatAction) + private + FBeforeExecute: TNotifyEvent; + FExecuteResult: Boolean; + FOnAccept: TNotifyEvent; + FOnCancel: TNotifyEvent; + protected + FDialog: TCommonDialog; + procedure DoAccept; virtual; + procedure DoBeforeExecute; virtual; + procedure DoCancel; virtual; + function GetDialogClass: TCommonDialogClass; virtual; + procedure CreateDialog; virtual; + public + constructor Create(AOwner: TComponent); override; + procedure ExecuteTarget(Target: TObject); override; + property ExecuteResult: Boolean read FExecuteResult; + property BeforeExecute: TNotifyEvent read FBeforeExecute write FBeforeExecute; + property OnAccept: TNotifyEvent read FOnAccept write FOnAccept; + property OnCancel: TNotifyEvent read FOnCancel write FOnCancel; + end; + + { TsFontAction } + TsFontAction = class(TsCommonDialogSpreadsheetAction) + private + function GetDialog: TFontDialog; + protected + procedure ApplyFormatToCell(ACell: PCell); override; + procedure DoAccept; override; + procedure ExtractFromCell(ACell: PCell); override; + function GetDialogClass: TCommonDialogClass; override; + public + constructor Create(AOwner: TComponent); override; + published + property Caption; + property Dialog: TFontDialog read GetDialog; + property Enabled; + property HelpContext; + property HelpKeyword; + property HelpType; + property Hint; + property ImageIndex; + property ShortCut; + property SecondaryShortCuts; + property Visible; +// property BeforeExecute; +// property OnAccept; +// property OnCancel; + property OnHint; + end; + + { TsBackgroundColorAction } + TsBackgroundColorAction = class(TsCommonDialogSpreadsheetAction) + private + FBackgroundColor: TsColor; + function GetDialog: TColorDialog; + protected + procedure ApplyFormatToCell(ACell: PCell); override; + procedure DoAccept; override; + procedure DoBeforeExecute; override; + procedure ExtractFromCell(ACell: PCell); override; + function GetDialogClass: TCommonDialogClass; override; + public + constructor Create(AOwner: TComponent); override; + published + property Caption; + property Dialog: TColorDialog read GetDialog; + property Enabled; + property HelpContext; + property HelpKeyword; + property HelpType; + property Hint; + property ImageIndex; + property ShortCut; + property SecondaryShortCuts; + property Visible; +// property BeforeExecute; +// property OnAccept; +// property OnCancel; + property OnHint; + end; + procedure Register; implementation uses - Dialogs, - fpsutils; + fpsutils, fpsVisualUtils; procedure Register; begin @@ -261,7 +345,7 @@ begin // Worksheet-releated actions TsWorksheetAddAction, TsWorksheetDeleteAction, TsWorksheetRenameAction, // Cell or cell range formatting actions - TsFontStyleAction, + TsFontAction, TsFontStyleAction, TsBackgroundColorAction, TsHorAlignmentAction, TsVertAlignmentAction, TsTextRotationAction, TsWordWrapAction, TsNumberFormatAction, TsDecimalsAction @@ -463,24 +547,32 @@ begin Unused(ACell); end; -procedure TsCellFormatAction.ExecuteTarget(Target: TObject); +procedure TsCellFormatAction.ApplyFormatToRange(ARange: TsCellRange); var - range: Integer; - r,c: Cardinal; - sel: TsCellRangeArray; + r, c: Cardinal; cell: PCell; begin - if not HandlesTarget(Target) then - exit; + for r := ARange.Row1 to ARange.Row2 do + for c := ARange.Col1 to ARange.Col2 do + begin + cell := Worksheet.GetCell(r, c); // Use "GetCell" here to format empty cells as well + ApplyFormatToCell(cell); // no check for nil required because of "GetCell" + end; +end; + +procedure TsCellFormatAction.ApplyFormatToSelection; +var + sel: TsCellRangeArray; + range: Integer; +begin sel := GetSelection; for range := 0 to High(sel) do - for r := sel[range].Row1 to sel[range].Row2 do - for c := sel[range].Col1 to sel[range].Col2 do - begin - cell := Worksheet.GetCell(r, c); // Use "GetCell", empty cells will be formatted! - if cell <> nil then - ApplyFormatToCell(cell); - end; + ApplyFormatToRange(sel[range]); +end; + +procedure TsCellFormatAction.ExecuteTarget(Target: TObject); +begin + ApplyFormatToSelection; end; { Extracts the format item for which the action is responsible from the @@ -850,4 +942,169 @@ begin Hint := 'Less decimal places'; end; + +{ TsCommonDialogSpreadsheetAction } + +constructor TsCommonDialogSpreadsheetAction.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + CreateDialog; + + DisableIfNoHandler := False; + Enabled := True; +end; + +procedure TsCommonDialogSpreadsheetAction.CreateDialog; +var + DlgClass: TCommonDialogClass; +begin + DlgClass := GetDialogClass; + if Assigned(DlgClass) then + begin + FDialog := DlgClass.Create(Self); + FDialog.Name := DlgClass.ClassName; + FDialog.SetSubComponent(True); + end; +end; + +procedure TsCommonDialogSpreadsheetAction.DoAccept; +begin + if Assigned(FOnAccept) then + FOnAccept(Self); +end; + +procedure TsCommonDialogSpreadsheetAction.DoBeforeExecute; +begin + if Assigned(FBeforeExecute) then + FBeforeExecute(Self); +end; + +procedure TsCommonDialogSpreadsheetAction.DoCancel; +begin + if Assigned(FOnCancel) then + FOnCancel(Self); +end; + +function TsCommonDialogSpreadsheetAction.GetDialogClass: TCommonDialogClass; +begin + result := nil; +end; + +procedure TsCommonDialogSpreadsheetAction.ExecuteTarget(Target: TObject); +begin + DoBeforeExecute; + FExecuteResult := FDialog.Execute; + if FExecuteResult then + DoAccept + else + DoCancel; +end; + + +{ TsFontAction } + +constructor TsFontAction.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + Caption := 'Font'; + Hint := 'Select cell font'; +end; + +procedure TsFontAction.ApplyFormatToCell(ACell: PCell); +var + sfnt: TsFont; +begin + sfnt := TsFont.Create; + Convert_Font_to_sFont(Workbook, GetDialog.Font, sfnt); + Worksheet.WriteFont(ACell, Workbook.AddFont(sfnt)); +end; + +procedure TsFontAction.DoAccept; +begin + ApplyFormatToSelection; +end; + +procedure TsFontAction.ExtractFromCell(ACell: PCell); +var + sfnt: TsFont; + fnt: TFont; +begin + fnt := TFont.Create; + try + if (ACell = nil) then + sfnt := Workbook.GetDefaultFont + else + if uffBold in ACell^.UsedFormattingFields then + sfnt := Workbook.GetFont(1) + else + if uffFont in ACell^.UsedFormattingFields then + sfnt := Workbook.GetFont(ACell^.FontIndex) + else + sfnt := Workbook.GetDefaultFont; + Convert_sFont_to_Font(Workbook, sfnt, fnt); + GetDialog.Font.Assign(fnt); + finally + fnt.Free; + end; +end; + +function TsFontAction.GetDialog: TFontDialog; +begin + Result := TFontDialog(FDialog); +end; + +function TsFontAction.GetDialogClass: TCommonDialogClass; +begin + Result := TFontDialog; +end; + + +{ TsBackgroundColorAction } + +constructor TsBackgroundColorAction.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + Caption := 'Backgroundcolor'; + Hint := 'Modify background color'; +end; + +procedure TsBackgroundColorAction.ApplyFormatToCell(ACell: PCell); +begin + Worksheet.WritebackgroundColor(ACell, FBackgroundColor); +end; + +procedure TsBackgroundColorAction.DoAccept; +begin + FBackgroundColor := Workbook.AddColorToPalette(TsColorValue(Dialog.Color)); + ApplyFormatToSelection; +end; + +procedure TsBackgroundColorAction.DoBeforeExecute; +var + cell: PCell; +begin + cell := Worksheet.FindCell(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol); + if (cell = nil) or not (uffBackgroundColor in cell^.UsedFormattingFields) then + FBackgroundColor := scNotDefined + else + FBackgroundColor := cell^.BackgroundColor; + Dialog.Color := Workbook.GetPaletteColor(FBackgroundColor); +end; + +procedure TsBackgroundColorAction.ExtractFromCell(ACell: PCell); +begin + // +end; + +function TsBackgroundColorAction.GetDialog: TColorDialog; +begin + Result := TColorDialog(FDialog); +end; + +function TsBackgroundColorAction.GetDialogClass: TCommonDialogClass; +begin + Result := TColorDialog; +end; + + end. diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index 08a497343..1d6be1188 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -561,7 +561,8 @@ procedure Register; implementation uses - Types, LCLType, LCLIntf, Math, fpCanvas, fpsUtils; + Types, LCLType, LCLIntf, Math, + fpCanvas, fpsUtils, fpsVisualUtils; const {@@ Translation of the fpspreadsheet type of horizontal text alignment to that @@ -643,83 +644,6 @@ begin end; end; -{@@ ---------------------------------------------------------------------------- - Wraps text by inserting line ending characters so that the lines are not - longer than AMaxWidth. - - @param ACanvas Canvas on which the text will be drawn - @param AText Text to be drawn - @param AMaxWidth Maximimum line width (in pixels) - @return Text with inserted line endings such that the lines are shorter than - AMaxWidth. - - @note Based on ocde posted by user "taazz" in the Lazarus forum - http://forum.lazarus.freepascal.org/index.php/topic,21305.msg124743.html#msg124743 --------------------------------------------------------------------------------} -function WrapText(ACanvas: TCanvas; const AText: string; AMaxWidth: integer): string; -var - DC: HDC; - textExtent: TSize = (cx:0; cy:0); - 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; - {@@ ---------------------------------------------------------------------------- Calculates a background color for selected cells. The procedures takes the original background color and dims or brightens it by adding the value ADelta @@ -1075,16 +999,7 @@ end; -------------------------------------------------------------------------------} procedure TsCustomWorksheetGrid.Convert_sFont_to_Font(sFont: TsFont; AFont: TFont); begin - if Assigned(AFont) and Assigned(sFont) then begin - 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; + fpsVisualUtils.Convert_sFont_to_Font(Workbook, sFont, Font); end; {@@ ---------------------------------------------------------------------------- @@ -1096,16 +1011,7 @@ end; 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; + fpsVisualUtils.Convert_Font_to_sFont(Workbook, AFont, sFont); end; {@@ ---------------------------------------------------------------------------- @@ -2035,93 +1941,10 @@ end; @param AColor Color index into the workbook's palette -------------------------------------------------------------------------------} function TsCustomWorksheetGrid.FindNearestPaletteIndex(AColor: TColor): TsColor; - - procedure ColorToHSL(RGB: TColor; out H, S, L : double); - // Taken from https://code.google.com/p/thtmlviewer/source/browse/trunk/source/HSLUtils.pas?r=277 - // The procedure in GraphUtils crashes for some colors in Laz < 1.3 - 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; - 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; - - { - // To 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); - end; - } - -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; + Result := fpsVisualUtils.FindNearestPaletteIndex(Workbook, AColor); end; + (* {@@ ---------------------------------------------------------------------------- Notification by the workbook link that a cell has been modified. --> Repaint. diff --git a/components/fpspreadsheet/fpsvisualutils.pas b/components/fpspreadsheet/fpsvisualutils.pas new file mode 100644 index 000000000..311fa5da1 --- /dev/null +++ b/components/fpspreadsheet/fpsvisualutils.pas @@ -0,0 +1,227 @@ +unit fpsvisualutils; + +interface + +uses + Classes, SysUtils, Graphics, + fpspreadsheet; + +procedure Convert_sFont_to_Font(AWorkbook: TsWorkbook; sFont: TsFont; AFont: TFont); +procedure Convert_Font_to_sFont(AWorkbook: TsWorkbook; AFont: TFont; sFont: TsFont); +function FindNearestPaletteIndex(AWorkbook: TsWorkbook; AColor: TColor): TsColor; +function WrapText(ACanvas: TCanvas; const AText: string; AMaxWidth: integer): string; + + +implementation + +uses + Types, LCLType, LCLIntf, Math; + +{@@ ---------------------------------------------------------------------------- + Converts a spreadsheet font to a font used for painting (TCanvas.Font). + + @param AWorkbook Workbook in which the font is used + @param sFont Font as used by fpspreadsheet (input) + @param AFont Font as used by TCanvas for painting (output) +-------------------------------------------------------------------------------} +procedure Convert_sFont_to_Font(AWorkbook: TsWorkbook; sFont: TsFont; AFont: TFont); +begin + if Assigned(AFont) and Assigned(sFont) then begin + 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 := AWorkbook.GetPaletteColor(sFont.Color); + end; +end; + +{@@ ---------------------------------------------------------------------------- + Converts a font used for painting (TCanvas.Font) to a spreadsheet font. + + @param AFont Font as used by TCanvas for painting (input) + @param sFont Font as used by fpspreadsheet (output) +-------------------------------------------------------------------------------} +procedure Convert_Font_to_sFont(AWorkbook: TsWorkbook; 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(AWorkbook, AFont.Color); + end; +end; + +function FindNearestPaletteIndex(AWorkbook: TsWorkbook; AColor: TColor): TsColor; + + procedure ColorToHSL(RGB: TColor; out H, S, L : double); + // Taken from https://code.google.com/p/thtmlviewer/source/browse/trunk/source/HSLUtils.pas?r=277 + // The procedure in GraphUtils crashes for some colors in Laz < 1.3 + 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; + 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; + + { + // To 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); + end; + } + +var + i: Integer; + dist, mindist: Double; +begin + Result := 0; + if AWorkbook <> nil then + begin + mindist := 1E308; + for i:=0 to AWorkbook.GetPaletteSize-1 do + begin + dist := ColorDistance(AColor, TColor(AWorkbook.GetPaletteColor(i))); + if dist < mindist then + begin + mindist := dist; + Result := i; + end; + end; + end; +end; + +{@@ ---------------------------------------------------------------------------- + Wraps text by inserting line ending characters so that the lines are not + longer than AMaxWidth. + + @param ACanvas Canvas on which the text will be drawn + @param AText Text to be drawn + @param AMaxWidth Maximimum line width (in pixels) + @return Text with inserted line endings such that the lines are shorter than + AMaxWidth. + + @note Based on ocde posted by user "taazz" in the Lazarus forum + http://forum.lazarus.freepascal.org/index.php/topic,21305.msg124743.html#msg124743 +-------------------------------------------------------------------------------} +function WrapText(ACanvas: TCanvas; const AText: string; AMaxWidth: integer): string; +var + DC: HDC; + textExtent: TSize = (cx:0; cy:0); + 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; + +end. diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk index 3333f156a..c1e971379 100644 --- a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk +++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk @@ -20,7 +20,7 @@ It provides graphical components like a grid and chart."/> - + @@ -41,6 +41,10 @@ It provides graphical components like a grid and chart."/> + + + + diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas index 051539048..91d790a75 100644 --- a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas +++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas @@ -8,7 +8,7 @@ interface uses fpspreadsheetctrls, fpspreadsheetgrid, fpspreadsheetchart, fpsActions, - LazarusPackageIntf; + fpsvisualutils, LazarusPackageIntf; implementation @@ -17,7 +17,7 @@ begin RegisterUnit('fpspreadsheetctrls', @fpspreadsheetctrls.Register); RegisterUnit('fpspreadsheetgrid', @fpspreadsheetgrid.Register); RegisterUnit('fpspreadsheetchart', @fpspreadsheetchart.Register); - RegisterUnit('fpsactions', @fpsactions.Register); + RegisterUnit('fpsActions', @fpsActions.Register); end; initialization