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.
+