fresnel.register.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. {
  2. Copyright (C) 2025 Mattias Gaertner [email protected]
  3. *****************************************************************************
  4. This file is part of the Fresnel project.
  5. See the file COPYING.modifiedLGPL.txt, included in this distribution,
  6. for details about the license.
  7. *****************************************************************************
  8. }
  9. unit Fresnel.Register;
  10. {$mode objfpc}{$H+}
  11. interface
  12. uses
  13. Classes, SysUtils,
  14. // lcl
  15. LCLProc, LCLType, LCLIntf, LazLoggerBase, Graphics, Controls, Forms,
  16. // IDE intf
  17. FormEditingIntf, PropEdits, LazIDEIntf, ComponentEditors, IDEOptEditorIntf, ProjectIntf,
  18. IDECommands, MenuIntf, IDEWindowIntf, PackageIntf, IDEOptionsIntf,
  19. // codetools
  20. CodeToolManager, CodeCache, StdCodeTools,
  21. // fresnel
  22. Fresnel.DOM, Fresnel.Controls, Fresnel.Forms,
  23. Fresnel.Renderer, Fresnel.Classes, Fresnel.Events, FCL.Events, Fresnel.LCLApp, Fresnel.LCL,
  24. Fresnel.DsgnStrConsts, Fresnel.StylePropEdit, Fresnel.DsgnOptsFrame, Fresnel.DsgnOptions,
  25. Fresnel.DsgnInspector;
  26. const
  27. ProjDescNameFresnelApplication = 'Fresnel Application';
  28. FresnelPkgName = 'Fresnel';
  29. FresnelLCLPkgName = 'FresnelLCL';
  30. FresnelBasePkgName = 'FresnelBase';
  31. FresnelDesignPkgName = 'FresnelDsgn';
  32. type
  33. { TFresnelFormMediator - mediator for TFresnelForm }
  34. TFresnelFormMediator = class(TDesignerMediator,IFresnelFormDesigner)
  35. private
  36. FDsgnForm: TFresnelForm;
  37. FRenderer: TFresnelLCLRenderer;
  38. protected
  39. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  40. procedure OnCSSApplied(Event: TAbstractEvent); virtual;
  41. procedure SetLCLForm(const AValue: TForm); override;
  42. procedure SetDsgnForm(aFrlForm: TFresnelForm); virtual;
  43. public
  44. // needed by the Lazarus form editor
  45. class function CreateMediator(TheOwner, aForm: TComponent): TDesignerMediator;
  46. override;
  47. class function FormClass: TComponentClass; override;
  48. constructor Create(AOwner: TComponent); override;
  49. destructor Destroy; override;
  50. function ComponentAtPos(p: TPoint; MinClass: TComponentClass;
  51. Flags: TDMCompAtPosFlags): TComponent; override;
  52. function ComponentIsIcon(AComponent: TComponent): boolean; override;
  53. function ComponentIsVisible(AComponent: TComponent): Boolean; override;
  54. function GetComponentOriginOnForm(AComponent: TComponent): TPoint; override;
  55. function ParentAcceptsChild(Parent: TComponent;
  56. ChildClass: TComponentClass): boolean; override;
  57. procedure GetBounds(AComponent: TComponent; out CurBounds: TRect); override;
  58. procedure GetClientArea(AComponent: TComponent; out
  59. CurClientArea: TRect; out ScrollOffset: TPoint); override;
  60. procedure InitComponent(AComponent, NewParent: TComponent; NewBounds: TRect); override;
  61. procedure Paint; override;
  62. procedure SetBounds(AComponent: TComponent; NewBounds: TRect); override;
  63. public
  64. // needed by Fresnel
  65. procedure InvalidateRect(Sender: TObject; ARect: TRect; Erase: boolean); virtual;
  66. procedure SetDesignerFormBounds(Sender: TObject; NewBounds: TRect); virtual;
  67. function GetDesignerClientHeight: integer; virtual;
  68. function GetDesignerClientWidth: integer; virtual;
  69. function GetRenderer: TFresnelRenderer; virtual;
  70. property DsgnForm: TFresnelForm read FDsgnForm;
  71. property Renderer: TFresnelLCLRenderer read FRenderer;
  72. end;
  73. { TFileDescFresnelForm }
  74. TFileDescFresnelForm = class(TFileDescPascalUnitWithResource)
  75. public
  76. constructor Create; override;
  77. function Init(var NewFilename: string; NewOwner: TObject;
  78. var NewSource: string; Quiet: boolean): TModalResult; override;
  79. function Initialized(NewFile: TLazProjectFile): TModalResult; override;
  80. function GetInterfaceUsesSection: string; override;
  81. function GetLocalizedName: string; override;
  82. function GetLocalizedDescription: string; override;
  83. end;
  84. { TProjDescFresnelApplication }
  85. TProjDescFresnelApplication = class(TProjectDescriptor)
  86. public
  87. constructor Create; override;
  88. function GetLocalizedName: string; override;
  89. function GetLocalizedDescription: string; override;
  90. function InitProject(AProject: TLazProject): TModalResult; override;
  91. function CreateStartFiles({%H-}AProject: TLazProject): TModalResult; override;
  92. end;
  93. { TFresnelStylePropertyEditor }
  94. TFresnelStylePropertyEditor = class(TStringPropertyEditor)
  95. public
  96. function GetAttributes: TPropertyAttributes; override;
  97. procedure Edit; override;
  98. end;
  99. { TFresnelStyleSheetPropertyEditor }
  100. TFresnelStyleSheetPropertyEditor = class(TClassPropertyEditor)
  101. public
  102. procedure Edit; override;
  103. function GetAttributes: TPropertyAttributes; override;
  104. end;
  105. { TFresnelComponentRequirements }
  106. TFresnelComponentRequirements = class(TComponentRequirements)
  107. public
  108. procedure RequiredPkgs(Pkgs: TStrings); override;
  109. end;
  110. var
  111. FileDescFresnelForm: TFileDescFresnelForm;
  112. ProjDescFresnelApplication: TProjDescFresnelApplication;
  113. var
  114. FresnelOptionsFrameID: integer = 1000;
  115. procedure Register;
  116. implementation
  117. {$R fresneldsgnimg.res}
  118. procedure Register;
  119. var
  120. Key: TIDEShortCut;
  121. Cat: TIDECommandCategory;
  122. begin
  123. FresnelOptions:=TFresnelDsgnOptions.Create(nil);
  124. // register mediator for designer forms
  125. FormEditingHook.RegisterDesignerMediator(TFresnelFormMediator);
  126. FormEditingHook.SetDesignerBaseClassCanAppCreateForm(TFresnelForm,true);
  127. // register elements
  128. RegisterComponents('Fresnel',[TDiv,TSpan,TLabel,TButton,TImage,TBody]);
  129. RegisterComponentRequirements([TDiv,TSpan,TLabel,TButton,TImage,TBody],TFresnelComponentRequirements);
  130. // register fresnel form as new file type
  131. FileDescFresnelForm:=TFileDescFresnelForm.Create;
  132. RegisterProjectFileDescriptor(FileDescFresnelForm,FileDescGroupName);
  133. // register fresnel application as new project type
  134. ProjDescFresnelApplication:=TProjDescFresnelApplication.Create;
  135. RegisterProjectDescriptor(ProjDescFresnelApplication);
  136. // register property editors
  137. RegisterPropertyEditor(TypeInfo(String), TFresnelElement, 'Style', TFresnelStylePropertyEditor);
  138. RegisterPropertyEditor(TypeInfo(String), TFresnelForm, 'Style', THiddenPropertyEditor);
  139. RegisterPropertyEditor(TypeInfo(TStrings), TFresnelForm, 'Stylesheet', TFresnelStyleSheetPropertyEditor);
  140. // register IDE options frame
  141. FresnelOptionsFrameID:=RegisterIDEOptionsEditor(GroupEnvironment,TFresnelOptionsFrame,
  142. FresnelOptionsFrameID)^.Index;
  143. // register shortcut for view CSS Inspector
  144. Key:=IDEShortCut(VK_UNKNOWN,[],VK_UNKNOWN,[]);
  145. Cat:=IDECommandList.FindCategoryByName(CommandCategoryViewName);
  146. ViewCSSInspectorCmd:=RegisterIDECommand(Cat, 'View Fresnel CSS Inspector',
  147. frsFresnelCSSInspector, Key,nil,@ViewCSSInspector);
  148. // add a menu item in the view menu
  149. ViewCSSInspectorMenuCmd:=RegisterIDEMenuCommand(itmViewMainWindows, 'ViewFresnelCSSInspector',
  150. frsFresnelCSSInspector, nil, nil, ViewCSSInspectorCmd{, 'menu_view_fresnel_css_inspector'});
  151. // register window creator
  152. IDEWindowCreators.Add(CSSInspectorWindowName,@CreateCSSInspectorWindow,nil,'250','400','','');
  153. end;
  154. { TFresnelFormMediator }
  155. procedure TFresnelFormMediator.OnCSSApplied(Event: TAbstractEvent);
  156. begin
  157. if Event=nil then ;
  158. end;
  159. procedure TFresnelFormMediator.Notification(AComponent: TComponent;
  160. Operation: TOperation);
  161. begin
  162. inherited Notification(AComponent, Operation);
  163. if Operation=opRemove then
  164. begin
  165. if FDsgnForm=AComponent then
  166. begin
  167. FDsgnForm.Designer:=nil;
  168. FDsgnForm:=nil;
  169. end;
  170. if FRenderer=AComponent then
  171. begin
  172. FRenderer.Canvas:=nil;
  173. FRenderer:=nil;
  174. end;
  175. end;
  176. end;
  177. procedure TFresnelFormMediator.SetLCLForm(const AValue: TForm);
  178. begin
  179. if LCLForm=AValue then exit;
  180. inherited SetLCLForm(AValue);
  181. if FDsgnForm<>nil then
  182. begin
  183. if FRenderer<>nil then
  184. FRenderer.Canvas:=LCLForm.Canvas;
  185. TFresnelLCLFontEngine(FDsgnForm.FontEngine).Canvas:=LCLForm.Canvas;
  186. end else begin
  187. if FRenderer<>nil then
  188. FRenderer.Canvas:=nil;
  189. TFresnelLCLFontEngine(FDsgnForm.FontEngine).Canvas:=nil;
  190. end;
  191. end;
  192. procedure TFresnelFormMediator.SetDsgnForm(aFrlForm: TFresnelForm);
  193. begin
  194. if FDsgnForm=aFrlForm then exit;
  195. if DsgnForm<>nil then
  196. begin
  197. DsgnForm.Designer:=nil;
  198. DsgnForm.EventDispatcher.UnRegisterHandler(@OnCSSApplied,evtViewportCSSApplied);
  199. end;
  200. FDsgnForm:=aFrlForm;
  201. if DsgnForm<>nil then
  202. DsgnForm.AddEventListener(evtViewportCSSApplied,@OnCSSApplied);
  203. end;
  204. class function TFresnelFormMediator.CreateMediator(TheOwner, aForm: TComponent
  205. ): TDesignerMediator;
  206. var
  207. Mediator: TFresnelFormMediator;
  208. aFresnelForm: TFresnelForm;
  209. begin
  210. Result:=inherited CreateMediator(TheOwner,aForm);
  211. Mediator:=TFresnelFormMediator(Result);
  212. aFresnelForm:=aForm as TFresnelForm;
  213. Mediator.SetDsgnForm(aFresnelForm);
  214. aFresnelForm.Designer:=Mediator;
  215. Mediator.FreeNotification(aForm);
  216. aFresnelForm.FontEngine:=TFresnelLCLFontEngine.Create(Mediator);
  217. end;
  218. class function TFresnelFormMediator.FormClass: TComponentClass;
  219. begin
  220. Result:=TFresnelForm;
  221. end;
  222. procedure TFresnelFormMediator.GetBounds(AComponent: TComponent; out
  223. CurBounds: TRect);
  224. var
  225. El: TFresnelElement;
  226. aBox: TFresnelRect;
  227. begin
  228. if AComponent=FDsgnForm then
  229. begin
  230. CurBounds:=FDsgnForm.FormBounds.GetRect;
  231. end else if AComponent is TFresnelElement then
  232. begin
  233. // return borderbox
  234. El:=TFresnelElement(AComponent);
  235. aBox:=El.UsedBorderBox;
  236. FresnelRectToRect(aBox,CurBounds);
  237. end else
  238. inherited GetBounds(AComponent,CurBounds);
  239. //debugln(['TFresnelFormMediator.GetBounds ',DbgSName(AComponent),' ',dbgs(CurBounds)]);
  240. end;
  241. procedure TFresnelFormMediator.SetBounds(AComponent: TComponent;
  242. NewBounds: TRect);
  243. var
  244. El: TFresnelElement;
  245. OldStyle: String;
  246. NewBorderBox: TFresnelRect;
  247. NewLeft, NewTop, NewWidth, NewHeight: TFresnelLength;
  248. begin
  249. //debugln(['TFresnelFormMediator.SetBounds ',DbgSName(AComponent),' ',dbgs(NewBounds)]);
  250. if AComponent=FDsgnForm then
  251. begin
  252. FDsgnForm.WSResize(TFresnelRect.Create(NewBounds),NewBounds.Width,NewBounds.Height);
  253. end else if AComponent is TFresnelElement then
  254. begin
  255. // an element (bounds are controlled by CSS)
  256. El:=TFresnelElement(AComponent);
  257. if El.ComputedPosition in [CSSRegistry.kwAbsolute,CSSRegistry.kwFixed] then
  258. begin
  259. // NewBounds is borderbox
  260. with El.LayoutNode do begin
  261. NewBorderBox.SetRect(NewBounds); // integer to float
  262. NewLeft:=NewBorderBox.Left-MarginLeft;
  263. NewTop:=NewBorderBox.Top-MarginTop;
  264. NewWidth:=NewBorderBox.Width;
  265. NewHeight:=NewBorderBox.Height;
  266. // todo: if parent position is static, use the nearest parent with non static
  267. // todo: right and bottom aligned
  268. OldStyle:=El.Style;
  269. case El.ComputedBoxSizing of
  270. CSSRegistry.kwBorderBox:
  271. begin
  272. end;
  273. CSSRegistry.kwPaddingBox:
  274. begin
  275. NewWidth:=NewWidth-BorderLeft-BorderRight;
  276. NewHeight:=NewHeight-BorderTop-BorderBottom;
  277. end;
  278. CSSRegistry.kwContentBox:
  279. begin
  280. NewWidth:=NewWidth-BorderLeft-BorderRight-PaddingLeft-PaddingRight;
  281. NewHeight:=NewHeight-BorderTop-BorderBottom-PaddingTop-PaddingBottom;
  282. end;
  283. end;
  284. end;
  285. if El.GetStyleAttr('left')<>'' then
  286. El.SetStyleAttr('left',FloatToCSSPx(NewLeft));
  287. if El.GetStyleAttr('top')<>'' then
  288. El.SetStyleAttr('top',FloatToCSSPx(NewTop));
  289. if El.GetStyleAttr('width')<>'' then
  290. El.SetStyleAttr('width',FloatToCSSPx(NewWidth));
  291. if El.GetStyleAttr('height')<>'' then
  292. El.SetStyleAttr('height',FloatToCSSPx(NewHeight));
  293. debugln(['TFresnelFormMediator.SetBounds AComponent=',DbgSName(AComponent),' OldStyle=[',OldStyle,'] OldBorderBox=',FloatToCSSStr(El.UsedBorderBox.Left),',',FloatToCSSStr(El.UsedBorderBox.Top),' w=',FloatToCSSStr(El.UsedBorderBox.Width),',h=',FloatToCSSStr(El.UsedBorderBox.Height),' box-sizing=',CSSRegistry.Keywords[El.ComputedBoxSizing],' NewLeft,Top=',FloatToCSSStr(NewLeft),',',FloatToCSSStr(NewTop),' NewWH=',FloatToCSSStr(NewWidth),'x',FloatToCSSStr(NewHeight)]);
  294. El.Viewport.ApplyCSS;
  295. end;
  296. end else begin
  297. inherited SetBounds(AComponent, NewBounds);
  298. end;
  299. end;
  300. procedure TFresnelFormMediator.GetClientArea(AComponent: TComponent; out
  301. CurClientArea: TRect; out ScrollOffset: TPoint);
  302. var
  303. El: TFresnelElement;
  304. Box, BorderBox: TFresnelRect;
  305. begin
  306. if AComponent=FDsgnForm then
  307. begin
  308. CurClientArea:=Rect(0,0,round(FDsgnForm.Width),round(FDsgnForm.Height));
  309. ScrollOffset:=Point(0,0);
  310. end else if AComponent is TFresnelElement then begin
  311. // return clientbox inside the borderbox
  312. El:=TFresnelElement(AComponent);
  313. BorderBox:=El.UsedBorderBox;
  314. Box:=El.UsedClientBox;
  315. Box.Offset(-BorderBox.Left,-BorderBox.Top);
  316. FresnelRectToRect(Box,CurClientArea);
  317. ScrollOffset.X:=round(El.ScrollLeft);
  318. ScrollOffset.Y:=round(El.ScrollTop);
  319. end else
  320. inherited;
  321. end;
  322. procedure TFresnelFormMediator.InitComponent(AComponent, NewParent: TComponent; NewBounds: TRect);
  323. var
  324. El: TFresnelElement;
  325. BorderBox: TFresnelRect;
  326. begin
  327. if AComponent is TFresnelElement then
  328. begin
  329. // set parentcomponent, needed for streaming
  330. TFresnelFormMediator(AComponent).SetParentComponent(NewParent);
  331. El:=TFresnelElement(AComponent);
  332. debugln(['TFresnelFormMediator.InitComponent AComponent=',DbgSName(AComponent),' NewParent=',DbgSName(NewParent),' Bounds=',dbgs(NewBounds)]);
  333. if FresnelOptions.PositionAbsolute then
  334. begin
  335. // todo: if parent position is static, use the nearest parent with non static
  336. BorderBox.SetRect(NewBounds);
  337. // todo: compute margins via resolver
  338. El.SetStyleAttr('position','absolute');
  339. El.SetStyleAttr('box-sizing','border-box');
  340. El.SetStyleAttr('left',FloatToCSSPx(BorderBox.Left));
  341. El.SetStyleAttr('top',FloatToCSSPx(BorderBox.Top));
  342. if not (El is TReplacedElement) then
  343. begin
  344. if (BorderBox.Width<=0) and (El.NodeCount=0) then
  345. BorderBox.Width:=50;
  346. if (BorderBox.Height<=0) and (El.NodeCount=0) then
  347. BorderBox.Height:=50;
  348. if BorderBox.Width>0 then
  349. El.SetStyleAttr('width',FloatToCSSPx(BorderBox.Width));
  350. if BorderBox.Height>0 then
  351. El.SetStyleAttr('height',FloatToCSSPx(BorderBox.Height));
  352. end;
  353. end;
  354. end else
  355. inherited;
  356. end;
  357. function TFresnelFormMediator.GetComponentOriginOnForm(AComponent: TComponent
  358. ): TPoint;
  359. var
  360. El: TFresnelElement;
  361. BorderBox: TFresnelRect;
  362. begin
  363. if AComponent=FDsgnForm then
  364. begin
  365. Result:=Point(0,0);
  366. end else if AComponent is TFresnelElement then
  367. begin
  368. El:=TFresnelElement(AComponent);
  369. if not El.Rendered then
  370. exit(Point(0,0));
  371. BorderBox:=El.GetBorderBoxOnViewport;
  372. Result.X:=round(BorderBox.Left);
  373. Result.Y:=round(BorderBox.Top);
  374. end else
  375. Result:=inherited GetComponentOriginOnForm(AComponent);
  376. end;
  377. procedure TFresnelFormMediator.Paint;
  378. begin
  379. //debugln(['TFresnelFormMediator.Paint FDsgnForm=',DbgSName(FDsgnForm)]);
  380. if FDsgnForm=nil then exit;
  381. //debugln(['TFresnelFormMediator.Paint FDsgnForm=',DbgSName(FDsgnForm),' Renderer=',DbgSName(FDsgnForm.Renderer)]);
  382. FDsgnForm.Renderer.Draw(FDsgnForm);
  383. end;
  384. function TFresnelFormMediator.ComponentIsIcon(AComponent: TComponent): boolean;
  385. begin
  386. if AComponent is TFresnelElement then
  387. Result:=false
  388. else
  389. Result:=inherited ComponentIsIcon(AComponent);
  390. end;
  391. function TFresnelFormMediator.ComponentIsVisible(AComponent: TComponent
  392. ): Boolean;
  393. begin
  394. if AComponent=FDsgnForm then
  395. Result:=true
  396. else if AComponent is TFresnelElement then
  397. Result:=TFresnelElement(AComponent).Rendered
  398. else
  399. Result:=true;
  400. end;
  401. function TFresnelFormMediator.ComponentAtPos(p: TPoint;
  402. MinClass: TComponentClass; Flags: TDMCompAtPosFlags): TComponent;
  403. var
  404. ElArr: TFresnelElementArray;
  405. El: TFresnelElement;
  406. i: Integer;
  407. begin
  408. if Flags=[] then ;
  409. // skip sub elements aka return only elements owned by the lookup root,
  410. // which are streamed
  411. ElArr:=DsgnForm.GetElementsAt(p.X,p.Y);
  412. for i:=0 to length(ElArr)-1 do
  413. begin
  414. El:=ElArr[i];
  415. if (El=DsgnForm) or (El.Owner=DsgnForm) then
  416. begin
  417. if (MinClass=nil) or El.InheritsFrom(MinClass) then
  418. exit(El);
  419. end;
  420. end;
  421. Result:=nil;
  422. end;
  423. function TFresnelFormMediator.ParentAcceptsChild(Parent: TComponent;
  424. ChildClass: TComponentClass): boolean;
  425. begin
  426. //debugln(['TFresnelFormMediator.ParentAcceptsChild START Parent=',DbgSName(Parent),' Child=',DbgSName(ChildClass)]);
  427. if ChildClass.InheritsFrom(TControl) then
  428. Result:=false
  429. else if ChildClass.InheritsFrom(TFresnelViewport) then
  430. Result:=false
  431. else if Parent is TFresnelElement then
  432. begin
  433. if Parent is TReplacedElement then
  434. exit(false);
  435. Result:=ChildClass.InheritsFrom(TFresnelElement);
  436. end else
  437. Result:=inherited ParentAcceptsChild(Parent, ChildClass);
  438. //debugln(['TFresnelFormMediator.ParentAcceptsChild END Parent=',DbgSName(Parent),' Child=',DbgSName(ChildClass),' Result=',Result]);
  439. end;
  440. constructor TFresnelFormMediator.Create(AOwner: TComponent);
  441. begin
  442. inherited Create(AOwner);
  443. end;
  444. destructor TFresnelFormMediator.Destroy;
  445. begin
  446. SetDsgnForm(nil);
  447. inherited Destroy;
  448. end;
  449. procedure TFresnelFormMediator.InvalidateRect(Sender: TObject; ARect: TRect;
  450. Erase: boolean);
  451. begin
  452. //debugln(['TFresnelFormMediator.InvalidateRect ',DbgSName(FDsgnForm),' ',dbgs(ARect)]);
  453. if (LCLForm=nil) or (not LCLForm.HandleAllocated) then exit;
  454. LCLIntf.InvalidateRect(LCLForm.Handle,@ARect,Erase);
  455. end;
  456. procedure TFresnelFormMediator.SetDesignerFormBounds(Sender: TObject;
  457. NewBounds: TRect);
  458. begin
  459. if LCLForm=nil then exit;
  460. LCLForm.BoundsRect:=NewBounds;
  461. end;
  462. function TFresnelFormMediator.GetDesignerClientHeight: integer;
  463. begin
  464. if LCLForm=nil then
  465. Result:=round(FDsgnForm.Height)
  466. else
  467. Result:=LCLForm.ClientHeight;
  468. end;
  469. function TFresnelFormMediator.GetDesignerClientWidth: integer;
  470. begin
  471. if LCLForm=nil then
  472. Result:=round(FDsgnForm.Width)
  473. else
  474. Result:=LCLForm.ClientWidth;
  475. end;
  476. function TFresnelFormMediator.GetRenderer: TFresnelRenderer;
  477. begin
  478. if FRenderer=nil then
  479. begin
  480. FRenderer:=TFresnelLCLRenderer.Create(Self);
  481. Renderer.Canvas:=LCLForm.Canvas;
  482. end;
  483. Result:=FRenderer;
  484. end;
  485. { TFileDescFresnelForm }
  486. constructor TFileDescFresnelForm.Create;
  487. begin
  488. inherited Create;
  489. Name:='FresnelForm';
  490. ResourceClass:=TFresnelForm;
  491. UseCreateFormStatements:=true;
  492. end;
  493. function TFileDescFresnelForm.Init(var NewFilename: string; NewOwner: TObject;
  494. var NewSource: string; Quiet: boolean): TModalResult;
  495. var
  496. DependencyOwner, aOwner: TObject;
  497. begin
  498. Result:=inherited Init(NewFilename, NewOwner, NewSource, Quiet);
  499. // if project uses the LCL, add dependency FresnelLCL else Fresnel
  500. RequiredPackages:=FresnelPkgName+';'+FresnelDesignPkgName;
  501. aOwner:=NewOwner;
  502. if aOwner=nil then
  503. aOwner:=LazarusIDE.ActiveProject;
  504. if aOwner<>nil then
  505. begin
  506. if PackageEditingInterface.IsOwnerDependingOnPkg(aOwner,'LCL',DependencyOwner) then
  507. RequiredPackages:=FresnelLCLPkgName+';'+FresnelDesignPkgName;
  508. end;
  509. end;
  510. function TFileDescFresnelForm.Initialized(NewFile: TLazProjectFile
  511. ): TModalResult;
  512. var
  513. aProject: TLazProject;
  514. MainFilename: String;
  515. Code: TCodeBuffer;
  516. DependencyOwner: TObject;
  517. NamePos, InPos: integer;
  518. begin
  519. Result:=inherited Initialized(NewFile);
  520. aProject:=LazarusIDE.ActiveProject;
  521. if aProject=nil then begin
  522. debugln(['Warning: TFileDescFresnelForm.Initialized: not adding uses Fresnel, because ActiveProject=nil']);
  523. exit;
  524. end;
  525. if aProject.MainFile=nil then begin
  526. debugln(['Warning: TFileDescFresnelForm.Initialized: not adding uses Fresnel, because ActiveProject.MainFile=nil']);
  527. exit;
  528. end;
  529. if PackageEditingInterface.IsOwnerDependingOnPkg(aProject,'LCL',DependencyOwner) then
  530. begin
  531. // a lcl app -> add Fresnel behind 'interfaces'
  532. MainFilename:=aProject.MainFile.Filename;
  533. Code:=CodeToolBoss.LoadFile(MainFilename,true,false);
  534. if not CodeToolBoss.AddUnitToMainUsesSectionIfNeeded(Code,'Fresnel','',[aufLast]) then
  535. begin
  536. if CodeToolBoss.FindUnitInAllUsesSections(Code,'Fresnel',NamePos,InPos) then
  537. begin
  538. debugln(['Warning: TFileDescFresnelForm.Initialized: failed adding uses Fresnel to "',MainFilename,'"']);
  539. exit;
  540. end;
  541. end;
  542. end;
  543. end;
  544. function TFileDescFresnelForm.GetInterfaceUsesSection: string;
  545. begin
  546. Result:='Classes, SysUtils, Fresnel.Classes, Fresnel.Forms, Fresnel.DOM, Fresnel.Controls';
  547. end;
  548. function TFileDescFresnelForm.GetLocalizedName: string;
  549. begin
  550. Result:='Fresnel Form';
  551. end;
  552. function TFileDescFresnelForm.GetLocalizedDescription: string;
  553. begin
  554. Result:='Create a new Fresnel form';
  555. end;
  556. { TProjDescFresnelApplication }
  557. constructor TProjDescFresnelApplication.Create;
  558. begin
  559. inherited Create;
  560. Name:=ProjDescNameFresnelApplication;
  561. Flags:=Flags+[pfUseDefaultCompilerOptions];
  562. end;
  563. function TProjDescFresnelApplication.GetLocalizedName: string;
  564. begin
  565. Result:=frsFresnelApplication;
  566. end;
  567. function TProjDescFresnelApplication.GetLocalizedDescription: string;
  568. begin
  569. Result:=frsFresnelApplicationDesc;
  570. end;
  571. function TProjDescFresnelApplication.InitProject(AProject: TLazProject
  572. ): TModalResult;
  573. var
  574. NewSource: String;
  575. MainFile: TLazProjectFile;
  576. begin
  577. Result:=inherited InitProject(AProject);
  578. MainFile:=AProject.CreateProjectFile('project1.lpr');
  579. MainFile.IsPartOfProject:=true;
  580. AProject.AddFile(MainFile,false);
  581. AProject.MainFileID:=0;
  582. AProject.UseAppBundle:=true;
  583. AProject.UseManifest:=true;
  584. AProject.Scaled:=true;
  585. // ToDo: AProject.ProjResources.XPManifest.DpiAware := xmdaTrue;
  586. AProject.LoadDefaultIcon;
  587. // create program source
  588. NewSource:='program Project1;'+LineEnding
  589. +LineEnding
  590. +'{$mode objfpc}{$H+}'+LineEnding
  591. +LineEnding
  592. +'uses'+LineEnding
  593. +' {$IFDEF UNIX}'+LineEnding
  594. +' cthreads,'+LineEnding
  595. +' {$ENDIF}'+LineEnding
  596. +' {$IFDEF HASAMIGA}'+LineEnding
  597. +' athreads,'+LineEnding
  598. +' {$ENDIF}'+LineEnding
  599. +' Fresnel, // this includes the Fresnel widgetset'+LineEnding
  600. +' Fresnel.Forms'+LineEnding
  601. +' { you can add units after this };'+LineEnding
  602. +LineEnding
  603. +'begin'+LineEnding
  604. +' Application.Initialize;'+LineEnding
  605. +' Application.Run;'+LineEnding
  606. +'end.'+LineEnding
  607. +LineEnding;
  608. AProject.MainFile.SetSourceText(NewSource,true);
  609. // add Fresnel package dependency
  610. AProject.AddPackageDependency('Fresnel');
  611. AProject.LazCompilerOptions.Win32GraphicApp:=true;
  612. AProject.LazCompilerOptions.UnitOutputDirectory:='lib'+PathDelim+'$(TargetCPU)-$(TargetOS)';
  613. AProject.LazCompilerOptions.TargetFilename:='project1';
  614. end;
  615. function TProjDescFresnelApplication.CreateStartFiles(AProject: TLazProject
  616. ): TModalResult;
  617. begin
  618. Result:=LazarusIDE.DoNewEditorFile(FileDescFresnelForm,'','',
  619. [nfIsPartOfProject,nfOpenInEditor,nfCreateDefaultSrc]);
  620. end;
  621. { TFresnelStylePropertyEditor }
  622. function TFresnelStylePropertyEditor.GetAttributes: TPropertyAttributes;
  623. begin
  624. Result := [paMultiSelect, paDialog, paRevertable];
  625. end;
  626. procedure TFresnelStylePropertyEditor.Edit;
  627. var
  628. TheDialog : TStylePropEditDialog;
  629. begin
  630. TheDialog := TStylePropEditDialog.Create(nil);
  631. try
  632. TheDialog.Caption := 'CSS Inline Style Editor';
  633. TheDialog.Editor := Self;
  634. TheDialog.ShowModal;
  635. finally
  636. TheDialog.Free;
  637. end;
  638. end;
  639. { TFresnelStyleSheetPropertyEditor }
  640. procedure TFresnelStyleSheetPropertyEditor.Edit;
  641. var
  642. TheDialog : TStylePropEditDialog;
  643. begin
  644. TheDialog := TStylePropEditDialog.Create(nil);
  645. try
  646. TheDialog.Caption := 'CSS Stylesheet Editor';
  647. TheDialog.Editor := Self;
  648. TheDialog.ShowModal;
  649. finally
  650. TheDialog.Free;
  651. end;
  652. end;
  653. function TFresnelStyleSheetPropertyEditor.GetAttributes: TPropertyAttributes;
  654. begin
  655. Result := [paMultiSelect, paDialog, paRevertable, paReadOnly];
  656. end;
  657. { TFresnelComponentRequirements }
  658. procedure TFresnelComponentRequirements.RequiredPkgs(Pkgs: TStrings);
  659. procedure RemoveFresnelBase;
  660. var
  661. i: Integer;
  662. begin
  663. i:=Pkgs.IndexOf('FresnelBase');
  664. if i<0 then exit;
  665. Pkgs.Delete(i);
  666. end;
  667. var
  668. aProject: TLazProject;
  669. DependencyOwner: TObject;
  670. begin
  671. // the Fresnel components are part of package FresnelBase, but the project
  672. // actually needs a Fresnel backend.
  673. // if project is using the LCL then use FresnelLCL else Fresnel
  674. aProject:=LazarusIDE.ActiveProject;
  675. if aProject<>nil then
  676. begin
  677. RemoveFresnelBase;
  678. if PackageEditingInterface.IsOwnerDependingOnPkg(aProject,'LCL',DependencyOwner) then
  679. begin
  680. Pkgs.Add('FresnelLCL');
  681. end else begin
  682. Pkgs.Add('Fresnel');
  683. end;
  684. end;
  685. end;
  686. end.