Industrial: Add basic TCharDefs property editor and TLCDDisplay component editor (not yet complete).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8312 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2022-06-17 15:46:35 +00:00
parent fd008e3e37
commit edb43d5153
7 changed files with 513 additions and 4 deletions

View File

@ -100,6 +100,14 @@
<Filename Value="source\indlcddisplay.pas"/>
<UnitName Value="indLCDDisplay"/>
</Item>
<Item>
<Filename Value="source\indlcddisplay_editor.pas"/>
<UnitName Value="indlcddisplay_editor"/>
</Item>
<Item>
<Filename Value="source\indlcddisplay_editorform.pas"/>
<UnitName Value="indLCDDisplay_EditorForm"/>
</Item>
</Files>
<LazDoc Paths="D:\Prog_Lazarus\svn\lazarus-ccr\components\industrialstuff\fpdoc"/>
<RequiredPkgs>

View File

@ -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

View File

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

View File

@ -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

View File

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

View File

@ -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

View File

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