diff --git a/components/industrialstuff/industrial.lpk b/components/industrialstuff/industrial.lpk index 7604d5f16..c81c4d09c 100644 --- a/components/industrialstuff/industrial.lpk +++ b/components/industrialstuff/industrial.lpk @@ -100,6 +100,14 @@ + + + + + + + + diff --git a/components/industrialstuff/industrial.pas b/components/industrialstuff/industrial.pas index 1e3c74088..6aff9872a 100644 --- a/components/industrialstuff/industrial.pas +++ b/components/industrialstuff/industrial.pas @@ -10,7 +10,8 @@ interface uses IndLed, Sensors, AllIndustrialRegister, LedNumber, indGnouMeter, AdvLed, indcyBaseLed, indcyClasses, indcyGraphics, indcyTypes, A3nalogGauge, MKnob, - switches, indSliders, indLCDDisplay, LazarusPackageIntf; + switches, indSliders, indLCDDisplay, indlcddisplay_editor, + indLCDDisplay_EditorForm, LazarusPackageIntf; implementation diff --git a/components/industrialstuff/source/AllIndustrialRegister.pas b/components/industrialstuff/source/AllIndustrialRegister.pas index c85842067..42024d62b 100644 --- a/components/industrialstuff/source/AllIndustrialRegister.pas +++ b/components/industrialstuff/source/AllIndustrialRegister.pas @@ -12,7 +12,8 @@ interface uses Classes, LResources, AdvLed, IndLed, LedNumber, Sensors, indGnouMeter, - A3nalogGauge, MKnob, Switches, indSliders, indLCDDisplay; + A3nalogGauge, MKnob, Switches, indSliders, + indLCDDisplay, indLCDDisplay_Editor; procedure Register; @@ -20,15 +21,19 @@ implementation {$R industrial_icons.res} +uses + PropEdits, ComponentEditors; + //========================================================== procedure Register; begin - RegisterComponents ('Industrial',[ + RegisterComponents('Industrial',[ TAdvLed, TIndLed, TLedNumber, TStopLightSensor, TAnalogSensor, TA3nalogGauge, TindGnouMeter, TmKnob, TOnOffSwitch, TMultiSlider, TLCDDisplay ]); - + RegisterPropertyEditor(TypeInfo(TCharDefs), TLCDDisplay, 'CharDefs', TLCDDisplayCharDefsPropertyEditor); + RegisterComponentEditor(TLCDDisplay, TLCDDisplayComponentEditor); end; end. diff --git a/components/industrialstuff/source/indlcddisplay.pas b/components/industrialstuff/source/indlcddisplay.pas index b82c72edb..ddee19000 100644 --- a/components/industrialstuff/source/indlcddisplay.pas +++ b/components/industrialstuff/source/indlcddisplay.pas @@ -51,6 +51,7 @@ type constructor Create(ADisplay: TLCDDisplay); destructor Destroy; override; procedure Add(AChar: String; ADotRows: TDotRows); + procedure Assign(ASource: TPersistent); override; procedure Clear; procedure Delete(AChar: String); procedure LoadFromFile(const AFileName: String); @@ -261,6 +262,21 @@ begin FCharList.Add(AChar, ADotRows); end; +procedure TCharDefs.Assign(ASource: TPersistent); +var + i: Integer; +begin + if (ASource is TCharDefs) then + begin + FColCount := TCharDefs(ASource).ColCount; + FRowCount := TCharDefs(ASource).RowCount; + Clear; + for i := 0 to TCharDefs(ASource).Count-1 do + Add(TCharDefs(ASource).CharByIndex[i], TCharDefs(ASource).DotRowsByIndex[i]); + end else + inherited; +end; + { Clears all characters and their dot matrices. } procedure TCharDefs.Clear; begin diff --git a/components/industrialstuff/source/indlcddisplay_editor.pas b/components/industrialstuff/source/indlcddisplay_editor.pas new file mode 100644 index 000000000..9b8114498 --- /dev/null +++ b/components/industrialstuff/source/indlcddisplay_editor.pas @@ -0,0 +1,192 @@ +unit indlcddisplay_editor; + +{$mode objfpc}{$H+} + +interface + +uses lazlogger, + Classes, SysUtils, PropEdits, ComponentEditors, + indLCDDisplay; + +type + TLCDDisplayCharDefsPropertyEditor = class(TPersistentPropertyEditor) + public + procedure Edit; override; + procedure ExecuteVerb(Index: Integer); override; + function GetAttributes: TPropertyAttributes; override; + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + function LCDDisplay: TLCDDisplay; + end; + + TLCDDisplayComponentEditor = class(TDefaultComponentEditor) + public + procedure EditLines; + procedure ExecuteVerb(Index: Integer); + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + function LCDDisplay: TLCDDisplay; + end; + +procedure EditCharDefs(ALCDDisplay: TLCDDisplay); + +implementation + +uses + Dialogs, indLCDDisplay_EditorForm; + +{ Opens the char def editor. } +procedure EditCharDefs(ALCDDisplay: TLCDDisplay); +var + F: TLCDCharDefsEditor; +begin + F := TLCDCharDefsEditor.Create(nil); + try + F.LCDDisplay := TLCDDisplay(ALCDDisplay); + F.ShowModal; // Cancel has been handled by the editor form. + finally + F.Free; + end; +end; + +{ Loads the char defs of the specified LCDDisplay from an xml file. } +procedure LoadCharDefsFromFile(ALCDDisplay: TLCDDisplay); +var + dlg: TOpenDialog; +begin + dlg := TOpenDialog.Create(nil); + try + dlg.FileName := ''; + dlg.Filter := 'XML files (*.xml)|*.xml'; + if dlg.Execute then + begin + ALCDDisplay.CharDefs.LoadFromFile(dlg.FileName); + ALCDDisplay.Invalidate; + end; + finally + dlg.Free; + end; +end; + +{ Saves the chardefs of the specified LCDDisplay to an xml file. } +procedure SaveCharDefsToFile(ALCDDisplay: TLCDDisplay); +var + dlg: TOpenDialog; +begin + dlg := TSaveDialog.Create(nil); + try + dlg.FileName := ''; + dlg.Filter := 'XML files (*.xml)|*.xml'; + if dlg.Execute then + ALCDDisplay.CharDefs.SaveToFile(dlg.FileName); + finally + dlg.Free; + end; +end; + + +{ TLCDDisplayCharDefsPropertyEditor } + +{ Opens the chardefs editor. } +procedure TLCDDisplayCharDefsPropertyEditor.Edit; +begin + EditCharDefs(LCDDisplay); +end; + +{ Executes the routines assigned to the CharDefs context menu } +procedure TLCDDisplayCharDefsPropertyEditor.ExecuteVerb(Index: Integer); +begin + case Index of + 0: Edit; + 1: LoadCharDefsFromFile(LCDDisplay); + 2: SaveCharDefsToFile(LCDDisplay); + end; +end; + +{ The property editor should open the CharDefs editor. } +function TLCDDisplayCharDefsPropertyEditor.GetAttributes: TPropertyAttributes; +begin + Result := inherited GetAttributes + [paDialog]; +end; + +{ Determines how many items will be added to the CharDefs context menu. } +function TLCDDisplayCharDefsPropertyEditor.GetVerbCount: Integer; +begin + Result := 3; +end; + +{ Determines the menu item text for CharDefs context menu. } +function TLCDDisplayCharDefsPropertyEditor.GetVerb(Index: Integer): string; +begin + case Index of + 0: Result := 'Edit...'; + 1: Result := 'Load from file...'; + 2: Result := 'Save to file...'; + end; +end; + +function TLCDDisplayCharDefsPropertyEditor.LCDDisplay: TLCDDisplay; +begin + Result := TLCDDisplay(GetComponent(0)); +end; + +{ TLCDDisplayComponentEditor } + +procedure TLCDDisplayComponentEditor.EditLines; +begin + { + F := TStringsPropEditorForm.Create(nil); + dlg := + Old := TStrings(GetObjectValue); + TheDialog := CreateDlg(Old); + try + if (TheDialog.ShowModal = mrOK) then begin + New := TheDialog.ListBox.Items; + AssignItems(Old, TheDialog.ListBox.Items); + SetPtrValue(New); + end; + finally + TheDialog.Free; + end; + } +end; + +procedure TLCDDisplayComponentEditor.ExecuteVerb(Index: Integer); +begin + if LCDDisplay = nil then + DebugLn('LCDDisplay = nil') + else + DebugLn(LCDDisplay.ClassName); + + case Index of + 0: EditLines; + 1: EditCharDefs(LCDDisplay); + 2: LoadCharDefsFromFile(LCDDisplay); + 3: SaveCharDefsToFile(LCDDisplay); + end; +end; + +{ Determines how many items will be added to the LCDDisplay context menu. } +function TLCDDisplayComponentEditor.GetVerbCount: Integer; +begin + Result := 4; +end; + +{ Determines the menu item text for LCDDisplay context menu. } +function TLCDDisplayComponentEditor.GetVerb(Index: Integer): string; +begin + case Index of + 0: Result := 'Text...'; + 1: Result := 'Edit character defs...'; + 2: Result := 'Load character defs from file...'; + 3: Result := 'Save character defs to file...'; + end; +end; + +function TLCDDisplayComponentEditor.LCDDisplay: TLCDDisplay; +begin + Result := TLCDDisplay(GetComponent); +end; + +end. + diff --git a/components/industrialstuff/source/indlcddisplay_editorform.lfm b/components/industrialstuff/source/indlcddisplay_editorform.lfm new file mode 100644 index 000000000..50676741f --- /dev/null +++ b/components/industrialstuff/source/indlcddisplay_editorform.lfm @@ -0,0 +1,95 @@ +object LCDCharDefsEditor: TLCDCharDefsEditor + Left = 415 + Height = 338 + Top = 175 + Width = 506 + AutoSize = True + Caption = 'LCDCharDefsEditor' + ClientHeight = 338 + ClientWidth = 506 + OnActivate = FormActivate + OnCloseQuery = FormCloseQuery + OnDestroy = FormDestroy + LCLVersion = '2.3.0.0' + object ButtonPanel: TButtonPanel + Left = 6 + Height = 34 + Top = 298 + Width = 494 + OKButton.Name = 'OKButton' + OKButton.DefaultCaption = True + HelpButton.Name = 'HelpButton' + HelpButton.DefaultCaption = True + CloseButton.Name = 'CloseButton' + CloseButton.DefaultCaption = True + CancelButton.Name = 'CancelButton' + CancelButton.DefaultCaption = True + TabOrder = 3 + ShowButtons = [pbOK, pbCancel] + end + object btnDelete: TButton + AnchorSideLeft.Control = dgEditor + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = dgEditor + Left = 224 + Height = 25 + Top = 64 + Width = 75 + BorderSpacing.Left = 12 + BorderSpacing.Right = 12 + Caption = 'Delete' + OnClick = btnDeleteClick + TabOrder = 2 + end + object dgEditor: TDrawGrid + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = cbCharSelector + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 192 + Top = 64 + Width = 200 + BorderSpacing.Left = 12 + BorderSpacing.Top = 12 + BorderSpacing.Bottom = 6 + BorderStyle = bsNone + ColCount = 1 + DefaultColWidth = 22 + ExtendedSelect = False + FixedCols = 0 + FixedRows = 0 + RowCount = 1 + ScrollBars = ssNone + TabOrder = 1 + OnPrepareCanvas = dgEditorPrepareCanvas + end + object Label1: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Left = 12 + Height = 15 + Top = 12 + Width = 105 + BorderSpacing.Left = 12 + BorderSpacing.Top = 12 + Caption = 'Available characters' + end + object cbCharSelector: TComboBox + AnchorSideLeft.Control = Label1 + AnchorSideTop.Control = Label1 + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 23 + Top = 29 + Width = 114 + AutoCompleteText = [cbactEndOfLineComplete, cbactSearchCaseSensitive, cbactSearchAscending] + BorderSpacing.Top = 2 + ItemHeight = 15 + MaxLength = 1 + OnChange = cbCharSelectorChange + OnKeyDown = cbCharSelectorKeyDown + OnKeyUp = cbCharSelectorKeyUp + TabOrder = 0 + Text = 'cbCharSelector' + end +end diff --git a/components/industrialstuff/source/indlcddisplay_editorform.pas b/components/industrialstuff/source/indlcddisplay_editorform.pas new file mode 100644 index 000000000..d1a950431 --- /dev/null +++ b/components/industrialstuff/source/indlcddisplay_editorform.pas @@ -0,0 +1,192 @@ +unit indLCDDisplay_EditorForm; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel, + Grids, indLCDDisplay; + +type + + { TLCDCharDefsEditor } + + TLCDCharDefsEditor = class(TForm) + btnDelete: TButton; + ButtonPanel: TButtonPanel; + cbCharSelector: TComboBox; + dgEditor: TDrawGrid; + Label1: TLabel; + procedure btnDeleteClick(Sender: TObject); + procedure cbCharSelectorChange(Sender: TObject); + procedure cbCharSelectorKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure cbCharSelectorKeyUp(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure dgEditorPrepareCanvas(sender: TObject; aCol, aRow: Integer; + aState: TGridDrawState); + procedure FormActivate(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure FormDestroy(Sender: TObject); + private + FLCDDisplay: TLCDDisplay; + FSavedCharDefs: TCharDefs; + procedure SetLCDDisplay(AValue: TLCDDisplay); + procedure PopulateCharSelector; + procedure SaveCharDefs; + function SelectedChar: String; + function SelectedDotMatrix: TDotRows; + procedure SetupEditorGrid; + + public + property LCDDisplay: TLCDDisplay read FLCDDisplay write SetLCDDisplay; + + end; + +var + LCDCharDefsEditor: TLCDCharDefsEditor; + +implementation + +{$R *.lfm} + +uses + Math; + +procedure TLCDCharDefsEditor.PopulateCharSelector; +var + i: Integer; +begin + cbCharSelector.DropdownCount := 24; + cbCharSelector.Items.BeginUpdate; + try + cbCharSelector.Clear; + for i := 0 to FLCDDisplay.CharDefs.Count-1 do + cbCharSelector.Items.Add(FLCDDisplay.CharDefs.CharByIndex[i]); + finally + cbCharSelector.Items.EndUpdate; + end; +end; + +{ This is just a sample allowing me to test the property editor... } +procedure TLCDCharDefsEditor.btnDeleteClick(Sender: TObject); +var + ch: String; +begin + ch := SelectedChar; + if ch <> '' then + begin + FLCDDisplay.CharDefs.Delete(ch); + FLCDDisplay.Invalidate; + end; +end; + +procedure TLCDCharDefsEditor.cbCharSelectorChange(Sender: TObject); +begin + dgEditor.Invalidate; +end; + +procedure TLCDCharDefsEditor.cbCharSelectorKeyDown(Sender: TObject; + var Key: Word; Shift: TShiftState); +begin +// cbCharSelector.Text := ''; +end; + +procedure TLCDCharDefsEditor.cbCharSelectorKeyUp(Sender: TObject; + var Key: Word; Shift: TShiftState); +begin + cbCharSelector.SelectAll; +end; + +procedure TLCDCharDefsEditor.dgEditorPrepareCanvas(sender: TObject; + aCol, aRow: Integer; aState: TGridDrawState); +var + dotrows: TDotRows; + r, c: Integer; + dotSet: Boolean; +begin + dotRows := SelectedDotMatrix; + if dotRows = nil then + exit; + + r := ARow; + c := dgEditor.ColCount - 1 - ACol; + dotSet := dotRows[r] and (1 shl c) <> 0; + if dotSet then + dgEditor.Canvas.Brush.Color := clBlack; +end; + +procedure TLCDCharDefsEditor.FormActivate(Sender: TObject); +begin + Constraints.MinHeight := dgEditor.Top + dgEditor.Height + ButtonPanel.Height + 2*ButtonPanel.BorderSpacing.Around; + Constraints.MinWidth := Max( + ButtonPanel.OKButton.Left + ButtonPanel.OKButton.Width + ButtonPanel.BorderSpacing.Around, + btnDelete.Left + btnDelete.Width + btnDelete.BorderSpacing.Right + ); +end; + +{ When the form is not closed by the OK button, we must restored the saved, + original char defs of the FLCDDisplay. } +procedure TLCDCharDefsEditor.FormCloseQuery(Sender: TObject; + var CanClose: Boolean); +begin + if CanClose and (ModalResult <> mrOK) then + begin + FLCDDisplay.CharDefs.Assign(FSavedCharDefs); + FLCDDisplay.Invalidate; + end; +end; + +procedure TLCDCharDefsEditor.FormDestroy(Sender: TObject); +begin + FreeAndNil(FSavedCharDefs); +end; + +{ Save the char defs so that they can be restored if the form is not closed by OK. } +procedure TLCDCharDefsEditor.SaveCharDefs; +begin + FSavedCharDefs.Free; + FSavedCharDefs := TCharDefs.Create(nil); + FSavedCharDefs.Assign(FLCDDisplay.CharDefs); +end; + +{ Returns the currently selected character. Note that this is a string because + we have to deal with UTF8 where a code-point can consist of up to 4 bytes. } +function TLCDCharDefsEditor.SelectedChar: String; +begin + Result := cbCharSelector.Text; +end; + +function TLCDCharDefsEditor.SelectedDotMatrix: TDotRows; +var + ch: String; +begin + ch := SelectedChar; + if ch <> '' then + Result := FLCDDisplay.CharDefs.DotRows[ch] + else + Result := nil; +end; + +procedure TLCDCharDefsEditor.SetLCDDisplay(AValue: TLCDDisplay); +begin + FLCDDisplay := AValue; + SaveCharDefs; + PopulateCharSelector; + SetupEditorGrid; +end; + +{ Reads the size of the dot matrix from FLCDDisplay and use it to define the + number of rows and columns in the editor grid. } +procedure TLCDCharDefsEditor.SetupEditorGrid; +begin + dgEditor.RowCount := FLCDDisplay.DotRowCount; + dgEditor.ColCount := FLCDDisplay.DotColCount; + dgEditor.ClientWidth := dgEditor.ColCount * dgEditor.DefaultColWidth; + dgEditor.ClientHeight := dgEditor.RowCount * dgEditor.DefaultRowHeight; + dgEditor.Constraints.MinWidth := dgEditor.Width; + dgEditor.Constraints.MinHeight := dgEditor.Height; +end; +end. +