517 lines
14 KiB
ObjectPascal
517 lines
14 KiB
ObjectPascal
// 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 | mailedivando@gmail.com
|
|
(Compatibility with delphi VCL 11/2018)
|
|
|
|
***************************** END CONTRIBUTOR(S) *****************************}
|
|
unit BCStylesForm;
|
|
|
|
{$I bgracontrols.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, {$IFDEF FPC}FileUtil, ComponentEditors, PropEdits,{$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
|
|
Result := IDEImages.GetImageIndex(AIdx,AName);
|
|
if Result=-1 then
|
|
Result := IDEImages.LoadImage(AIdx,AName);
|
|
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.
|
|
|