| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- // SPDX-License-Identifier: LGPL-3.0-linking-exception
- { Styles form manager
- ------------------------------------------------------------------------------
- originally written in 2012 by Krzysztof Dibowski dibowski at interia.pl
- }
- {******************************* CONTRIBUTOR(S) ******************************
- - Edivando S. Santos Brasil | [email protected]
- (Compatibility with delphi VCL 11/2018)
- ***************************** END CONTRIBUTOR(S) *****************************}
- unit BCStylesForm;
- {$I bgracontrols.inc}
- interface
- uses
- Classes, SysUtils,
- {$IFDEF FPC}
- FileUtil, ComponentEditors, PropEdits, LazVersion,
- {$ELSE}
- Windows, DesignIntf, DesignEditors, PropertyCategories,
- ToolIntf, ExptIntf, DesignWindows,
- {$ENDIF}
- Forms, Controls, Graphics, Dialogs, ExtCtrls,
- StdCtrls, ActnList, ComCtrls, Buttons,
- bcbasectrls;
- type
- { TBCfrmStyle }
- TBCfrmStyle = class(TForm)
- ActionRefresh: TAction;
- ActionNewFromFile: TAction;
- ActionDelete: TAction;
- ActionNewFromCtrl: TAction;
- ActionList1: TActionList;
- BitBtn1: TBitBtn;
- BitBtn2: TBitBtn;
- gboxPreview: TGroupBox;
- gboxStyles: TGroupBox;
- lvFiles: TListView;
- memoLogs: TMemo;
- OpenDialog1: TOpenDialog;
- pnlBottom: TPanel;
- Splitter1: TSplitter;
- sptrLog: TSplitter;
- ToolBar1: TToolBar;
- btnDelete: TToolButton;
- btnNewFromCtrl: TToolButton;
- ToolButton1: TToolButton;
- btnNewFromFile: TToolButton;
- btnRefresh: TToolButton;
- procedure ActionDeleteExecute({%H-}Sender: TObject);
- procedure ActionNewFromCtrlExecute({%H-}Sender: TObject);
- procedure ActionNewFromFileExecute({%H-}Sender: TObject);
- procedure ActionRefreshExecute({%H-}Sender: TObject);
- procedure FormCloseQuery({%H-}Sender: TObject; var CanClose: boolean);
- procedure lvFilesSelectItem({%H-}Sender: TObject; Item: TListItem;
- Selected: Boolean);
- private
- { private declarations }
- FControl: TControl;
- FPreviewControl: TControl;
- FStyleExt: String;
- procedure AddLog(const AText: String; AClear: Boolean = True);
- procedure CreatePreviewControl;
- function GetFileName: String;
- function GetStylesDir: String;
- public
- { public declarations }
- constructor {%H-}Create(AControl: TControl; const AFileExt: String);
- property FileName: String read GetFileName;
- end;
- { TBCStyleComponentEditor }
- TBCStyleComponentEditor = class(TComponentEditor)
- protected
- procedure BeginUpdate;
- procedure EndUpdate;
- function GetStyleExtension: String;
- procedure DoShowEditor;
- public
- procedure ExecuteVerb(Index: Integer); override;
- function GetVerb({%H-}Index: Integer): String; override;
- function GetVerbCount: Integer; override;
- end;
- { TBCSylePropertyEditor }
- TBCSylePropertyEditor = class({$IFDEF FPC}TClassPropertyEditor{$ELSE}TPropertyEditor{$ENDIF})
- private
- procedure BeginUpdate;
- procedure EndUpdate;
- function GetStyleExtension: String;
- procedure DoShowEditor;
- public
- procedure Edit; Override;
- function GetAttributes: TPropertyAttributes; Override;
- end;
- implementation
- {$IFDEF FPC}
- uses MacroIntf, BCRTTI, IDEImagesIntf;
- {$ELSE}
- uses BCRTTI;
- {$ENDIF}
- { TBCSylePropertyEditor }
- procedure TBCSylePropertyEditor.BeginUpdate;
- begin
- if GetComponent(0).InheritsFrom(TBCStyleGraphicControl) then
- TBCStyleGraphicControl(GetComponent(0)).BeginUpdate
- else
- if GetComponent(0).InheritsFrom(TBCStyleCustomControl) then
- TBCStyleCustomControl(GetComponent(0)).BeginUpdate;
- end;
- procedure TBCSylePropertyEditor.EndUpdate;
- begin
- if GetComponent(0).InheritsFrom(TBCStyleGraphicControl) then
- TBCStyleGraphicControl(GetComponent(0)).EndUpdate
- else
- if GetComponent(0).InheritsFrom(TBCStyleCustomControl) then
- TBCStyleCustomControl(GetComponent(0)).EndUpdate;
- end;
- function TBCSylePropertyEditor.GetStyleExtension: String;
- begin
- if GetComponent(0).InheritsFrom(TBCStyleGraphicControl) then
- Result := TBCStyleGraphicControl(GetComponent(0)).StyleExtension
- else
- if GetComponent(0).InheritsFrom(TBCStyleCustomControl) then
- Result := TBCStyleCustomControl(GetComponent(0)).StyleExtension
- else
- Result := '';
- end;
- procedure TBCSylePropertyEditor.DoShowEditor;
- var f: TBCfrmStyle;
- begin
- if GetStyleExtension='' then
- begin
- {$IFDEF FPC}
- MessageDlg('Empty ext', Format('Class %s has empty style extension',
- [GetComponent(0).ClassName]),mtError,[mbOK],0);
- {$ELSE}
- MessageDlg('Empty ext' + #10#13 + Format('Class %s has empty style extension',
- [GetComponent(0).ClassName]),mtError,[mbOK],0);
- {$ENDIF}
- Exit;
- end;
- f := TBCfrmStyle.Create(TControl(GetComponent(0)),GetStyleExtension);
- try
- if (f.ShowModal=mrOK) and FileExists(f.FileName) then
- begin
- try
- BeginUpdate;
- LoadStyle(GetComponent(0),f.FileName);
- finally
- EndUpdate;
- end;
- end;
- finally
- f.Free;
- end;
- end;
- procedure TBCSylePropertyEditor.Edit;
- begin
- DoShowEditor;
- end;
- function TBCSylePropertyEditor.GetAttributes: TPropertyAttributes;
- begin
- Result := [paDialog, paReadOnly];
- end;
- { TBCfrmStyle }
- procedure TBCfrmStyle.ActionNewFromCtrlExecute(Sender: TObject);
- var
- sName: String;
- sl: TStrings;
- begin
- sName := 'My new style';
- if InputQuery('Create new style', 'Style name', sName) then
- begin
- if Trim(sName)='' then
- raise Exception.Create('Name can not be empty');
- sName := IncludeTrailingBackslash(GetStylesDir) + sName+'.'+FStyleExt;
- if FileExists(sName) then
- raise Exception.Create('Style with this name already exists!');
- sl := TStringList.Create;
- try
- SaveStyle(FControl,'Me','',sl);
- sl.SaveToFile(sName);
- ActionRefresh.Execute;
- finally
- sl.Free;
- end;
- end;
- end;
- procedure TBCfrmStyle.ActionNewFromFileExecute(Sender: TObject);
- begin
- if OpenDialog1.Execute then
- begin
- if FileExists(IncludeTrailingBackslash(GetStylesDir)+ExtractFileName(OpenDialog1.FileName)) then
- raise Exception.Create('This style already exists');
- {$IFDEF FPC}
- CopyFile(OpenDialog1.FileName,IncludeTrailingBackslash(GetStylesDir)+ExtractFileName(OpenDialog1.FileName));
- {$ELSE}
- CopyFile(PWidechar(OpenDialog1.FileName),PWidechar(IncludeTrailingBackslash(GetStylesDir)+ExtractFileName(OpenDialog1.FileName)),False);
- {$ENDIF}
- ActionRefresh.Execute;
- end;
- end;
- procedure TBCfrmStyle.ActionRefreshExecute(Sender: TObject);
- var
- sl: TStrings;
- i: Integer;
- it: TListItem;
- h: TBCStyleHeader;
- begin
- {$IFDEF FPC}//#
- sl := FindAllFiles(GetStylesDir,'*.'+FStyleExt,False);
- {$ENDIF}
- try
- lvFiles.ItemIndex := -1;
- lvFiles.Selected := nil;
- lvFiles.Clear;
- if (sl<>nil) and (sl.Count>0) then
- begin
- lvFiles.{$IFNDEF FPC}Items.{$ENDIF}BeginUpdate;
- try
- for i:=0 to Pred(sl.Count) do
- begin
- it := lvFiles.Items.Add;
- it.Caption := ExtractFileName(sl.Strings[i]);
- GetStyleHeader(sl.Strings[i],@h);
- it.SubItems.Add(h.Author); // Author
- it.SubItems.Add(h.Description); // Description
- end;
- lvFiles.ItemIndex := 0;
- lvFiles.Selected := lvFiles.Items.Item[0];
- // I noticed that OnSelect event is not called when we change
- // selected index manually, so we must call it manually
- lvFilesSelectItem(lvFiles,lvFiles.Selected,True);
- ActionDelete.Enabled := True;
- finally
- lvFiles.{$IFNDEF FPC}Items.{$ENDIF}EndUpdate;
- end;
- end else
- begin
- memoLogs.Clear;
- memoLogs.Visible := False;
- sptrLog.Visible := False;
- FPreviewControl.Visible := False;
- ActionDelete.Enabled := False;
- end;
- finally
- if sl<>nil then sl.Free;
- end;
- end;
- procedure TBCfrmStyle.FormCloseQuery(Sender: TObject; var CanClose: boolean);
- begin
- if (ModalResult=mrOK) and (lvFiles.ItemIndex=-1) then
- begin
- {$IFDEF FPC}
- MessageDlg('Assign file', 'No style selected', mtError, [mbOK], 0);
- {$ELSE}
- MessageDlg('Assign file' + #10#13 + 'No style selected', mtError, [mbOK], 0);
- {$ENDIF}
- CanClose := False;
- end
- else
- CanClose := True;
- end;
- procedure TBCfrmStyle.ActionDeleteExecute(Sender: TObject);
- begin
- if (lvFiles.SelCount=0) or
- {$IFDEF FPC}
- (MessageDlg('Deleting style', 'Do you really want to delete selected style? '+
- 'This action delete file: '+IncludeTrailingBackslash(GetStylesDir)+lvFiles.Selected.Caption,
- mtConfirmation,mbYesNo,0)=mrNo)
- {$ELSE}
- (MessageDlg('Deleting style' + #10#13 + 'Do you really want to delete selected style? '+
- 'This action delete file: '+ IncludeTrailingBackslash(GetStylesDir) + lvFiles.Selected.Caption,
- mtConfirmation,mbYesNo,0)=mrNo)
- {$ENDIF}
- then
- Exit;
- {$IFDEF FPC}
- DeleteFile(IncludeTrailingBackslash(GetStylesDir)+lvFiles.Selected.Caption);
- {$ELSE}
- DeleteFile(PWideChar(IncludeTrailingBackslash(GetStylesDir)+lvFiles.Selected.Caption));
- {$ENDIF}
- ActionRefresh.Execute;
- end;
- procedure TBCfrmStyle.lvFilesSelectItem(Sender: TObject; Item: TListItem;
- Selected: Boolean);
- var
- sl_logs: TStrings;
- i: Integer;
- begin
- if Selected and (Item<>nil) then
- begin
- memoLogs.Visible := False;
- sptrLog.Visible := False;
- memoLogs.Clear;
- FPreviewControl.Visible := True;
- ActionDelete.Enabled := True;
- sl_logs := TStringList.Create;
- try
- if not FileExists(IncludeTrailingBackslash(GetStylesDir)+Item.Caption) then
- Exit;
- LoadStyle(FPreviewControl,IncludeTrailingBackslash(GetStylesDir)+Item.Caption,
- sl_logs);
- // Because load style override it
- FPreviewControl.Constraints.MinWidth := 100;
- FPreviewControl.Constraints.MinHeight := 100;
- // Logs
- for i:=0 to Pred(sl_logs.Count) do
- AddLog(sl_logs.Strings[i],False);
- finally
- sl_logs.Free;
- end;
- end;
- end;
- procedure TBCfrmStyle.AddLog(const AText: String; AClear: Boolean = True);
- begin
- if AClear then memoLogs.Clear;
- if not memoLogs.Visible then
- begin
- memoLogs.Visible := True;
- sptrLog.Visible := True;
- sptrLog.Top := memoLogs.Top - 1;
- end;
- memoLogs.Lines.Add(AText);
- end;
- function TBCfrmStyle.GetStylesDir: String;
- begin
- Result := '$PkgDir(bgracontrols)';
- {$IFDEF FPC}
- IDEMacros.SubstituteMacros(Result);
- {$ENDIF}
- Result := IncludeTrailingBackslash(Result)+'styles';
- end;
- procedure TBCfrmStyle.CreatePreviewControl;
- begin
- FPreviewControl := TControlClass(FControl.ClassType).Create(Self);
- FPreviewControl.Constraints.MinWidth := 100;
- FPreviewControl.Constraints.MinHeight := 100;
- FPreviewControl.Parent := gboxPreview;
- {$IFDEF FPC}//#
- FPreviewControl.Caption := FControl.Caption;
- if Trim(FPreviewControl.Caption) = '' then
- FPreviewControl.Caption := 'Demo';
- {$ENDIF}
- FPreviewControl.Visible := False;
- end;
- function TBCfrmStyle.GetFileName: String;
- begin
- if lvFiles.ItemIndex=-1 then
- Result := ''
- else
- Result := IncludeTrailingBackslash(GetStylesDir)+lvFiles.Selected.Caption;
- end;
- constructor TBCfrmStyle.Create(AControl: TControl;
- const AFileExt: String);
- // It seems that method LoadImage load icon on each call. Others lazarus
- // component editors doesn't check if icon exist but I will do. Small memory leak
- // reduction :P
- {$IFDEF FPC}//#
- function _LoadImage(AIdx: Integer; const AName: String): Integer;
- begin
- {$if laz_fullversion<4990000}
- Result := IDEImages.GetImageIndex(AIdx,AName);
- if Result=-1 then
- Result := IDEImages.LoadImage(AIdx,AName);
- {$else}
- Result := IDEImages.GetImageIndex(AName,AIdx);
- if Result=-1 then
- Result := IDEImages.LoadImage(AName,AIdx);
- {$endif}
- end;
- {$ENDIF}
- begin
- inherited Create(Application);
- FControl := AControl;
- FStyleExt := AFileExt;
- CreatePreviewControl;
- ActionRefresh.Execute;
- {$IFDEF FPC}//#
- ToolBar1.Images := IDEImages.Images_16;
- ActionList1.Images := ToolBar1.Images;
- ActionDelete.ImageIndex := _LoadImage(16,'laz_delete');
- ActionNewFromCtrl.ImageIndex := _LoadImage(16,'laz_add');
- ActionNewFromFile.ImageIndex := _LoadImage(16,'laz_open');
- ActionRefresh.ImageIndex := _LoadImage(16,'laz_refresh');
- {$ENDIF}
- ActionDelete.Enabled := False;
- OpenDialog1.Filter := 'BC Style|*.'+FStyleExt;
- OpenDialog1.DefaultExt := FStyleExt;
- OpenDialog1.InitialDir := GetStylesDir;
- end;
- {$R *.lfm}
- { TBCStyleComponentEditor }
- procedure TBCStyleComponentEditor.BeginUpdate;
- begin
- if Component.InheritsFrom(TBCStyleGraphicControl) then
- TBCStyleGraphicControl(Component).BeginUpdate
- else
- if Component.InheritsFrom(TBCStyleCustomControl) then
- TBCStyleCustomControl(Component).BeginUpdate;
- end;
- procedure TBCStyleComponentEditor.EndUpdate;
- begin
- if Component.InheritsFrom(TBCStyleGraphicControl) then
- TBCStyleGraphicControl(Component).EndUpdate
- else
- if Component.InheritsFrom(TBCStyleCustomControl) then
- TBCStyleCustomControl(Component).EndUpdate;
- end;
- function TBCStyleComponentEditor.GetStyleExtension: String;
- begin
- if Component.InheritsFrom(TBCStyleGraphicControl) then
- Result := TBCStyleGraphicControl(Component).StyleExtension
- else
- if Component.InheritsFrom(TBCStyleCustomControl) then
- Result := TBCStyleCustomControl(Component).StyleExtension
- else
- Result := '';
- end;
- procedure TBCStyleComponentEditor.DoShowEditor;
- var f: TBCfrmStyle;
- begin
- if GetStyleExtension='' then
- begin
- {$IFDEF FPC}
- MessageDlg('Empty ext', Format('Class %s has empty style extension',
- [Component.ClassName]),mtError,[mbOK],0);
- {$ELSE}
- MessageDlg('Empty ext' + #10#13 + Format('Class %s has empty style extension',
- [Component.ClassName]),mtError,[mbOK],0);
- {$ENDIF}
- Exit;
- end;
- f := TBCfrmStyle.Create(TControl(Component),GetStyleExtension);
- try
- if (f.ShowModal=mrOK) and FileExists(f.FileName) then
- begin
- try
- BeginUpdate;
- LoadStyle(Component,f.FileName);
- finally
- EndUpdate;
- end;
- end;
- finally
- f.Free;
- end;
- end;
- procedure TBCStyleComponentEditor.ExecuteVerb(Index: Integer);
- begin
- case Index of
- 0: DoShowEditor;
- end;
- end;
- function TBCStyleComponentEditor.GetVerb(Index: Integer): String;
- begin
- Result := 'Assign style';
- end;
- function TBCStyleComponentEditor.GetVerbCount: Integer;
- begin
- Result := 1;
- end;
- initialization
- RegisterComponentEditor(TBCStyleGraphicControl, TBCStyleComponentEditor);
- RegisterComponentEditor(TBCStyleCustomControl, TBCStyleComponentEditor);
- {$IFDEF FPC}
- RegisterPropertyEditor(ClassTypeInfo(TBCStyleDummyProperty),nil,'',TBCSylePropertyEditor);
- {$ELSE}
- RegisterPropertyEditor(TypeInfo(TBCStyleDummyProperty),nil,'',TBCSylePropertyEditor);
- {$ENDIF}
- end.
|