PageRenderTime 62ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/components/sparta/dockedformeditor/source/sparta_mainide.pas

http://github.com/graemeg/lazarus
Pascal | 1710 lines | 1252 code | 229 blank | 229 comment | 171 complexity | 43bc9477416d786665b742d0558a9d40 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception
  1. {
  2. *****************************************************************************
  3. See the file COPYING.modifiedLGPL.txt, included in this distribution,
  4. for details about the license.
  5. *****************************************************************************
  6. Author: Maciej Izak
  7. DaThoX 2004-2015
  8. FreeSparta.com
  9. }
  10. unit sparta_MainIDE;
  11. {$mode delphi}{$H+}
  12. interface
  13. uses
  14. Classes, SysUtils, SrcEditorIntf, LazIDEIntf, ComCtrls, Controls, Forms, IDEImagesIntf,
  15. Buttons, ExtCtrls, Graphics, IDEWindowIntf, sparta_InterfacesMDI,
  16. sparta_DesignedForm, sparta_resizer, PropEdits, PropEditUtils, FormEditingIntf, ComponentEditors, EditBtn,
  17. {$IFDEF USE_GENERICS_COLLECTIONS}
  18. Generics.Collections, Generics.Defaults,
  19. {$ELSE}
  20. ghashmap, sparta_HashUtils, gvector,
  21. {$ENDIF}
  22. TypInfo, LCLIntf, LCLType, LMessages, sparta_FakeForm, sparta_FakeFrame, SpartaAPI, sparta_strconsts;
  23. const
  24. WM_SETNOFRAME = WM_USER;
  25. WM_BoundToDesignTabSheet = WM_USER + 1;
  26. type
  27. { TDesignFormData }
  28. TDesignFormData = class(TComponent, IDesignedForm, IDesignedFormIDE)
  29. private
  30. FWndMethod: TWndMethod;
  31. FForm: IDesignedFormIDE;
  32. FLastScreenshot: TBitmap;
  33. FPopupParent: TSourceEditorWindowInterface;
  34. FHiding: boolean;
  35. {$IFDEF USE_GENERICS_COLLECTIONS}
  36. FFormImages: TList<TImage>;
  37. {$ELSE}
  38. FFormImages: TList;
  39. {$ENDIF}
  40. protected
  41. procedure WndMethod(var TheMessage: TLMessage);
  42. procedure SetPopupParent(AVal: TSourceEditorWindowInterface);
  43. procedure DoAddForm;
  44. public
  45. {$IFDEF USE_GENERICS_COLLECTIONS}
  46. class var AddFormEvents: TList<TNotifyEvent>;
  47. {$ELSE}
  48. class var AddFormEvents: TVector<TNotifyEvent>;
  49. {$ENDIF}
  50. class constructor Init;
  51. class destructor Finit;
  52. procedure AddFormImage(AImage: TImage);
  53. procedure RemoveFormImage(AImage: TImage);
  54. procedure RepaintFormImages;
  55. property Form: IDesignedFormIDE read FForm implements IDesignedForm, IDesignedFormIDE;
  56. property LastScreenshot: TBitmap read FLastScreenshot;
  57. property PopupParent: TSourceEditorWindowInterface read FPopupParent write SetPopupParent;
  58. constructor Create(AForm: TCustomForm);
  59. destructor Destroy; override;
  60. end;
  61. { TModulePageControl }
  62. TModulePageControl = class(TPageControl)
  63. private
  64. FResizer: TResizer;
  65. FDesignFormData: TDesignFormData;
  66. protected
  67. procedure SetDesignFormData(const AValue: TDesignFormData); virtual;
  68. public
  69. destructor Destroy; override;
  70. procedure ShowDesignPage;
  71. procedure HideDesignPage;
  72. property Resizer: TResizer read FResizer;
  73. property DesignFormData: TDesignFormData read FDesignFormData write SetDesignFormData;
  74. procedure BoundToDesignTabSheet;
  75. end;
  76. { TSourceEditorWindowData }
  77. TSourceEditorWindowData = class
  78. private
  79. FActiveDesignFormData: TDesignFormData;
  80. private
  81. FWndMethod: TWndMethod;
  82. FForm: TSourceEditorWindowInterface;
  83. {$IFDEF USE_GENERICS_COLLECTIONS}
  84. FPageCtrlList: TDictionary<TSourceEditorInterface, TModulePageControl>;
  85. {$ELSE}
  86. FPageCtrlList: THashmap<TSourceEditorInterface, TModulePageControl, THash_TObject>;
  87. {$ENDIF}
  88. FLastTopParent: TControl;
  89. procedure SetActiveDesignFormData(const AValue: TDesignFormData);
  90. protected
  91. procedure WndMethod(var TheMessage: TLMessage);
  92. constructor Create(AForm: TSourceEditorWindowInterface);
  93. destructor Destroy; override;
  94. procedure OnChangeBounds(Sender: TObject);
  95. procedure AddPageCtrl(ASrcEditor: TSourceEditorInterface; APage: TModulePageControl);
  96. procedure RemovePageCtrl(ASrcEditor: TSourceEditorInterface);
  97. public
  98. property ActiveDesignFormData: TDesignFormData read FActiveDesignFormData write SetActiveDesignFormData;
  99. end;
  100. { TDTXTabMaster }
  101. TDTXTabMaster = class(TIDETabMaster)
  102. protected
  103. function GetTabDisplayState: TTabDisplayState; override;
  104. function GetTabDisplayStateEditor(Index: TSourceEditorInterface): TTabDisplayState; override;
  105. public
  106. procedure ToggleFormUnit; override;
  107. procedure JumpToCompilerMessage(ASourceEditor: TSourceEditorInterface); override;
  108. procedure ShowCode(ASourceEditor: TSourceEditorInterface); override;
  109. procedure ShowDesigner(ASourceEditor: TSourceEditorInterface; AIndex: Integer = 0); override;
  110. procedure ShowForm(AForm: TCustomForm); override;
  111. end;
  112. { TDTXComponentsMaster }
  113. TDTXComponentsMaster = class(TIDEComponentsMaster)
  114. function DrawNonVisualComponents(ALookupRoot: TComponent): Boolean; override;
  115. end;
  116. TFormHack = class(TCustomForm);
  117. { TSpartaMainIDE }
  118. TSpartaMainIDE = class(TObject)
  119. public
  120. class function GetCurrentResizer: TResizer;
  121. class procedure TryFreeFormData(Form: TCustomForm);
  122. class procedure Screen_FormAdded(Sender: TObject; Form: TCustomForm);
  123. class procedure Screen_FormDel(Sender: TObject; Form: TCustomForm);
  124. class procedure WindowCreate(Sender: TObject);
  125. class procedure WindowDestroy(Sender: TObject);
  126. class procedure WindowShow(Sender: TObject);
  127. class procedure WindowHide(Sender: TObject);
  128. class procedure EditorActivated(Sender: TObject);
  129. class procedure EditorDestroyed(Sender: TObject);
  130. class procedure EditorCreate(Sender: TObject);
  131. class procedure TabChange(Sender: TObject);
  132. class procedure GlobalOnChangeBounds(Sender: TObject);
  133. class procedure GlobalSNOnChangeBounds(Sender: TObject);
  134. class procedure OnShowDesignerForm(Sender: TObject; AEditor: TSourceEditorInterface;
  135. AComponentPaletteClassSelected: Boolean);
  136. class procedure OnShowSrcEditor(Sender: TObject);
  137. class procedure OnShowMethod(const Name: String);
  138. class procedure OnDesignRefreshPropertyValues;
  139. class procedure OnModifiedPersistentAdded(APersistent: TPersistent; Select: Boolean);
  140. class procedure OnModifiedSender(Sender: TObject; PropName: ShortString);
  141. class procedure OnModified;
  142. class procedure DesignerSetFocus;
  143. class procedure OnDesignMouseDown(Sender: TObject; Button: TMouseButton;
  144. Shift: TShiftState; X, Y: Integer);
  145. end;
  146. var
  147. Forms: Classes.TList; // normal forms
  148. dsgForms: Classes.TList; // design forms
  149. {$IFDEF USE_GENERICS_COLLECTIONS}
  150. SourceEditorWindows: TObjectDictionary<TSourceEditorWindowInterface, TSourceEditorWindowData>;
  151. {$ELSE}
  152. SourceEditorWindows: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>;
  153. {$ENDIF}
  154. LastActiveSourceEditorWindow: TSourceEditorWindowInterface = nil;
  155. LastActiveSourceEditor: TSourceEditorInterface = nil;
  156. BoundInitialized: Boolean;
  157. function FindModulePageControl(AForm: TSourceEditorWindowInterface): TModulePageControl; overload;
  158. function FindSourceEditorForDesigner(ADesigner: TIDesigner): TSourceEditorInterface;
  159. implementation
  160. uses
  161. sparta_ResizerFrame;
  162. // FUTURE USE
  163. //
  164. //function FindDesignForm(ADesigner: TIDesigner): TCustomForm;
  165. //var
  166. // f: TDesignFormData;
  167. //begin
  168. // for Pointer(f) in dsgForms do
  169. // with f as IDesignedForm do
  170. // if Form.Designer = ADesigner then
  171. // Exit(Form);
  172. //
  173. // Result := nil;
  174. //end;
  175. //
  176. //function FindDesignFormData(AForm: TSourceEditorWindowInterface): TDesignFormData; overload;
  177. //begin
  178. // Result := FindDesignFormData(
  179. // FindModulePageControl(AForm)
  180. // );
  181. //end;
  182. //
  183. //procedure HideAllForms;
  184. //var
  185. // f: TDesignFormData;
  186. //begin
  187. // for Pointer(f) in dsgForms do
  188. // ShowWindow(f.Form.Form.Handle, SW_HIDE);
  189. //end;
  190. function FindModulePageControl(ASourceEditor: TSourceEditorInterface): TModulePageControl; overload;
  191. var
  192. LParent: TWinControl;
  193. begin
  194. if ASourceEditor = nil then
  195. Exit(nil);
  196. LParent := ASourceEditor.EditorControl.Parent;
  197. while LParent <> nil do
  198. begin
  199. if LParent is TModulePageControl then
  200. Exit(TModulePageControl(LParent));
  201. LParent := LParent.Parent;
  202. end;
  203. Result := nil;
  204. end;
  205. function FindModulePageControl(AForm: TSourceEditorWindowInterface): TModulePageControl; overload;
  206. begin
  207. Result := FindModulePageControl(AForm.ActiveEditor);
  208. end;
  209. function AbsoluteFindModulePageControl(ASrcEditor: TSourceEditorInterface): TModulePageControl;
  210. var
  211. LSEWD: TSourceEditorWindowData;
  212. {$IFNDEF USE_GENERICS_COLLECTIONS}
  213. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  214. {$ENDIF}
  215. begin
  216. Result := nil;
  217. {$IFDEF USE_GENERICS_COLLECTIONS}
  218. for LSEWD in SourceEditorWindows.Values do
  219. if LSEWD.FPageCtrlList.ContainsKey(ASrcEditor) then
  220. Exit(LSEWD.FPageCtrlList[ASrcEditor]);
  221. {$ELSE}
  222. LIterator := SourceEditorWindows.Iterator;
  223. if LIterator <> nil then
  224. try
  225. repeat
  226. LSEWD := LIterator.Value;
  227. if LSEWD.FPageCtrlList.contains(ASrcEditor) then
  228. Exit(LSEWD.FPageCtrlList[ASrcEditor]);
  229. until not LIterator.next;
  230. finally
  231. LIterator.Free;
  232. end;
  233. {$ENDIF}
  234. end;
  235. function FindSourceEditorForDesigner(ADesigner: TIDesigner): TSourceEditorInterface;
  236. var
  237. i: Integer;
  238. begin
  239. for i := 0 to SourceEditorManagerIntf.SourceEditorCount - 1 do
  240. if SourceEditorManagerIntf.SourceEditors[i].GetDesigner(False) = ADesigner then
  241. Exit(SourceEditorManagerIntf.SourceEditors[i]);
  242. Result := nil;
  243. end;
  244. function FindDesignFormData(ADesigner: TIDesigner): TDesignFormData; overload;
  245. var
  246. p: Pointer;
  247. f: TDesignFormData absolute p;
  248. fi: IDesignedForm = nil;
  249. begin
  250. Result := nil;
  251. if ADesigner = nil then
  252. Exit;
  253. for p in dsgForms do
  254. begin
  255. fi := f.FForm;
  256. with fi do
  257. begin
  258. if (Form.Designer = ADesigner) then
  259. begin
  260. Exit(f);
  261. end;
  262. end;
  263. end;
  264. end;
  265. procedure RefreshAllSourceWindowsModulePageControl;
  266. var
  267. LWindow: TSourceEditorWindowInterface;
  268. LPageCtrl: TModulePageControl;
  269. {$IFNDEF USE_GENERICS_COLLECTIONS}
  270. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  271. {$ENDIF}
  272. begin
  273. {$IFDEF USE_GENERICS_COLLECTIONS}
  274. for LWindow in SourceEditorWindows.Keys do
  275. begin
  276. LPageCtrl := FindModulePageControl(LWindow);
  277. // for example LPageCtrl is nil when we clone module to new window
  278. if (LPageCtrl = nil) or (csDestroying in LWindow.ComponentState) then
  279. Continue;
  280. if LWindow.ActiveEditor = nil then
  281. LPageCtrl.HideDesignPage
  282. else
  283. if LWindow.ActiveEditor.GetDesigner(True) <> nil then
  284. // TODO some check function: is displayed right form?
  285. LPageCtrl.ShowDesignPage
  286. else
  287. LPageCtrl.HideDesignPage;
  288. end;
  289. {$ELSE}
  290. LIterator := SourceEditorWindows.Iterator;
  291. if LIterator <> nil then
  292. try
  293. repeat
  294. LWindow := LIterator.Key;
  295. LPageCtrl := FindModulePageControl(LWindow);
  296. // for example LPageCtrl is nil when we clone module to new window
  297. if (LPageCtrl = nil) or (csDestroying in LWindow.ComponentState) then
  298. Continue;
  299. if LWindow.ActiveEditor = nil then
  300. LPageCtrl.HideDesignPage
  301. else
  302. if LWindow.ActiveEditor.GetDesigner(True) <> nil then
  303. // TODO some check function: is displayed right form?
  304. LPageCtrl.ShowDesignPage
  305. else
  306. LPageCtrl.HideDesignPage;
  307. until not LIterator.next;
  308. finally
  309. LIterator.Free;
  310. end;
  311. {$ENDIF}
  312. end;
  313. // sometimes at some level of initialization form can not contain TIDesigner
  314. // (during ide run and when is oppened default project with some TForm1)
  315. function FindDesignFormData(AForm: TCustomForm): TDesignFormData; overload;
  316. var
  317. f: TDesignFormData;
  318. begin
  319. Result := nil;
  320. if AForm = nil then
  321. Exit;
  322. for Pointer(f) in dsgForms do
  323. with f as IDesignedForm do
  324. if (Form = AForm) then
  325. Exit(f);
  326. end;
  327. function FindDesignFormData(AModulePageCtrl: TModulePageControl): TDesignFormData; overload;
  328. var
  329. LSourceWindow: TSourceEditorWindowInterface;
  330. LSourceEditor: TSourceEditorInterface;
  331. {$IFNDEF USE_GENERICS_COLLECTIONS}
  332. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  333. {$ENDIF}
  334. begin
  335. Result := nil;
  336. if AModulePageCtrl = nil then
  337. Exit;
  338. {$IFDEF USE_GENERICS_COLLECTIONS}
  339. for LSourceWindow in SourceEditorWindows.Keys do
  340. begin
  341. if AModulePageCtrl.Owner = LSourceWindow then
  342. begin
  343. LSourceEditor := LSourceWindow.ActiveEditor;
  344. if LSourceEditor = nil then
  345. Exit;
  346. Result := FindDesignFormData(LSourceEditor.GetDesigner(True));
  347. Exit;
  348. end;
  349. end;
  350. {$ELSE}
  351. LIterator := SourceEditorWindows.Iterator;
  352. if LIterator <> nil then
  353. try
  354. repeat
  355. LSourceWindow := LIterator.Key;
  356. if AModulePageCtrl.Owner = LSourceWindow then
  357. begin
  358. LSourceEditor := LSourceWindow.ActiveEditor;
  359. if LSourceEditor = nil then
  360. Exit;
  361. Result := FindDesignFormData(LSourceEditor.GetDesigner(True));
  362. Exit;
  363. end;
  364. until not LIterator.next;
  365. finally
  366. LIterator.Free;
  367. end;
  368. {$ENDIF}
  369. end;
  370. { TDesignFormData }
  371. procedure TDesignFormData.WndMethod(var TheMessage: TLMessage);
  372. // Without this button F12 don't work. (after creating new for editor is inactive) :<
  373. procedure FixF12_ActiveEditor;
  374. var
  375. i: Integer;
  376. begin
  377. SourceEditorManagerIntf.ActiveEditor := nil;
  378. for i := 0 to SourceEditorManagerIntf.UniqueSourceEditorCount - 1 do
  379. if Form.Form.Designer = SourceEditorManagerIntf.UniqueSourceEditors[i].GetDesigner(True) then
  380. begin
  381. SourceEditorManagerIntf.ActiveEditor := SourceEditorManagerIntf.UniqueSourceEditors[i];
  382. Break;
  383. end;
  384. end;
  385. begin
  386. if TheMessage.msg = WM_SETNOFRAME then
  387. begin
  388. ShowWindow(Form.Form.Handle, SW_HIDE);
  389. FHiding := False;
  390. FixF12_ActiveEditor;
  391. if Form.Form is TFakeForm then
  392. RepaintFormImages;
  393. end;
  394. // during docking, form position was in wrong place... we need to delay changing position :)
  395. if TheMessage.msg = WM_BoundToDesignTabSheet then
  396. if Form.LastActiveSourceWindow <> nil then
  397. SourceEditorWindows[Form.LastActiveSourceWindow].OnChangeBounds(nil);
  398. // we need to correct ActiveEditor to right form
  399. // this code works correctly on Windows platform
  400. // (is necessery for selecting controls after form resizing).
  401. // in Linux platforms below code brings problems with QT (inactive form)
  402. {$IFDEF WINDOWS}
  403. case TheMessage.msg of
  404. LM_LBUTTONDOWN, LM_RBUTTONDOWN, LM_MBUTTONDOWN, LM_XBUTTONDOWN:
  405. if Form.LastActiveSourceWindow <> nil then
  406. begin
  407. SourceEditorManagerIntf.ActiveSourceWindow := Form.LastActiveSourceWindow;
  408. SourceEditorManagerIntf.ActiveEditor := Form.LastActiveSourceWindow.ActiveEditor;
  409. end;
  410. end;
  411. {$ENDIF}
  412. FWndMethod(TheMessage);
  413. end;
  414. procedure TDesignFormData.SetPopupParent(AVal: TSourceEditorWindowInterface);
  415. begin
  416. FPopupParent := AVal;
  417. Form.RealPopupParent := FPopupParent;
  418. end;
  419. class constructor TDesignFormData.Init;
  420. begin
  421. {$IFDEF USE_GENERICS_COLLECTIONS}
  422. AddFormEvents := TList<TNotifyEvent>.Create;
  423. {$ELSE}
  424. AddFormEvents := TVector<TNotifyEvent>.Create;
  425. {$ENDIF}
  426. end;
  427. class destructor TDesignFormData.Finit;
  428. begin
  429. AddFormEvents.Free;
  430. end;
  431. procedure TDesignFormData.AddFormImage(AImage: TImage);
  432. begin
  433. if FFormImages <> nil then
  434. FFormImages.Add(AImage);
  435. end;
  436. procedure TDesignFormData.RemoveFormImage(AImage: TImage);
  437. begin
  438. if FFormImages <> nil then
  439. FFormImages.Remove(AImage);
  440. end;
  441. procedure TDesignFormData.RepaintFormImages;
  442. var
  443. LImage: TImage;
  444. begin
  445. if FFormImages <> nil then
  446. begin
  447. for LImage in FFormImages do
  448. LImage.OnResize(LImage);
  449. end;
  450. end;
  451. procedure TDesignFormData.DoAddForm;
  452. var
  453. {$IFDEF USE_GENERICS_COLLECTIONS}
  454. ne: TNotifyEvent;
  455. {$ELSE}
  456. i: Integer;
  457. {$ENDIF}
  458. begin
  459. {$IFDEF USE_GENERICS_COLLECTIONS}
  460. for ne in AddFormEvents do
  461. ne(Self);
  462. {$ELSE}
  463. if AddFormEvents.Size > 0 then // Arithmetic overflow without a test. Size = unsigned.
  464. for i := 0 to AddFormEvents.Size-1 do
  465. AddFormEvents[i](Self);
  466. {$ENDIF}
  467. end;
  468. constructor TDesignFormData.Create(AForm: TCustomForm);
  469. begin
  470. FForm := AForm as IDesignedFormIDE;
  471. FLastScreenshot := TBitmap.Create;
  472. FWndMethod := FForm.Form.WindowProc;
  473. FForm.Form.WindowProc := WndMethod;
  474. if FForm.Form is TFakeForm then
  475. begin
  476. {$IFDEF USE_GENERICS_COLLECTIONS}
  477. FFormImages := TList<TImage>.Create;
  478. {$ELSE}
  479. FFormImages := TList.Create;
  480. {$ENDIF}
  481. DoAddForm;
  482. end;
  483. end;
  484. destructor TDesignFormData.Destroy;
  485. var
  486. LImage: TImage;
  487. begin
  488. FForm.Form.WindowProc := FWndMethod; // ! important risky point :P
  489. if FFormImages <> nil then
  490. begin
  491. for LImage in FFormImages do
  492. LImage.Free;
  493. FreeAndNil(FFormImages);
  494. end;
  495. FLastScreenshot.Free;
  496. inherited Destroy;
  497. Pointer(FForm) := nil;
  498. end;
  499. { TModulePageControl }
  500. procedure TModulePageControl.SetDesignFormData(const AValue: TDesignFormData);
  501. begin
  502. if (AValue = FDesignFormData) then
  503. // for show lfm code, if we want after editing lfm go back to form without any error
  504. // (when we restart IDE some error can be raised )
  505. if Assigned(FResizer) then
  506. begin
  507. if (AValue <> nil) and (FResizer.DesignedForm = AValue as IDesignedForm) then
  508. Exit;
  509. end
  510. else
  511. Exit;
  512. FDesignFormData := AValue;
  513. if AValue = nil then
  514. begin
  515. //find
  516. if Assigned(FResizer) then
  517. FResizer.DesignedForm := nil;
  518. end
  519. else
  520. begin
  521. AValue.Form.LastActiveSourceWindow := Owner as TSourceEditorWindowInterface;
  522. if Assigned(FResizer) then
  523. FResizer.DesignedForm := AValue;
  524. BoundToDesignTabSheet;
  525. end;
  526. end;
  527. destructor TModulePageControl.Destroy;
  528. begin
  529. DesignFormData := nil;
  530. inherited Destroy;
  531. end;
  532. procedure TModulePageControl.ShowDesignPage;
  533. begin
  534. Pages[1].TabVisible := True;
  535. end;
  536. procedure TModulePageControl.HideDesignPage;
  537. begin
  538. Pages[1].TabVisible:=False;
  539. end;
  540. procedure TModulePageControl.BoundToDesignTabSheet;
  541. begin
  542. if (ActivePageIndex <> 1) then
  543. Exit;
  544. if Assigned(FResizer) then
  545. FResizer.TryBoundSizerToDesignedForm(nil);
  546. end;
  547. { TSourceEditorWindowData }
  548. procedure TSourceEditorWindowData.SetActiveDesignFormData(
  549. const AValue: TDesignFormData);
  550. var
  551. LPageCtrl: TModulePageControl;
  552. begin
  553. if FActiveDesignFormData = AValue then
  554. Exit;
  555. if FActiveDesignFormData <> nil then
  556. // don't hide now if soon form will be hidden (for example on the IDE start)
  557. if not FActiveDesignFormData.FHiding then
  558. begin
  559. FActiveDesignFormData.FForm.HideWindow;
  560. end;
  561. FActiveDesignFormData := AValue;
  562. LPageCtrl := FindModulePageControl(FForm);
  563. if (AValue <> nil) then
  564. begin
  565. with AValue as IDesignedForm do
  566. if not AValue.FHiding and (RealBorderStyle <> bsNone) then
  567. begin
  568. BeginUpdate;
  569. //RealBorderIcons := [];
  570. //RealBorderStyle := bsNone;
  571. Form.Show;
  572. EndUpdate;
  573. end;
  574. // important when we want back to tab where was oppened form :<
  575. LazarusIDE.DoShowDesignerFormOfSrc(FForm.ActiveEditor);
  576. end;
  577. // when is fired DestroyEditor - from this place we can't navigate to pagecontrol by FForm (we need to handle lastactiveeditor)
  578. if LPageCtrl = nil then
  579. Exit;
  580. LPageCtrl.DesignFormData := AValue;
  581. // for USE_POPUP_PARENT_DESIGNER to eliminate form over code << maybe not needed any more since USE_POPUP_PARENT_DESIGNER isn't supported any more
  582. LPageCtrl.OnChange(LPageCtrl);
  583. end;
  584. procedure TSourceEditorWindowData.WndMethod(var TheMessage: TLMessage);
  585. begin
  586. FWndMethod(TheMessage);
  587. end;
  588. constructor TSourceEditorWindowData.Create(AForm: TSourceEditorWindowInterface);
  589. begin
  590. FWndMethod := AForm.WindowProc;
  591. AForm.WindowProc := WndMethod;
  592. FForm := AForm;
  593. {$IFDEF USE_GENERICS_COLLECTIONS}
  594. FPageCtrlList := TDictionary<TSourceEditorInterface, TModulePageControl>.Create;
  595. {$ELSE}
  596. FPageCtrlList := THashmap<TSourceEditorInterface, TModulePageControl, THash_TObject>.Create;
  597. {$ENDIF}
  598. end;
  599. destructor TSourceEditorWindowData.Destroy;
  600. begin
  601. FForm.WindowProc := FWndMethod;
  602. FPageCtrlList.Free;
  603. inherited Destroy;
  604. end;
  605. procedure TSourceEditorWindowData.OnChangeBounds(Sender: TObject);
  606. var
  607. LPageCtrl: TModulePageControl;
  608. begin
  609. LPageCtrl := FindModulePageControl(FForm);
  610. if LPageCtrl <> nil then
  611. //LPageCtrl.BoundToDesignTabSheet;
  612. end;
  613. procedure TSourceEditorWindowData.AddPageCtrl(ASrcEditor: TSourceEditorInterface; APage: TModulePageControl);
  614. begin
  615. {$IFDEF USE_GENERICS_COLLECTIONS}
  616. FPageCtrlList.Add(ASrcEditor, APage);
  617. {$ELSE}
  618. FPageCtrlList.insert(ASrcEditor, APage);
  619. {$ENDIF}
  620. APage.Pages[1].OnChangeBounds:=OnChangeBounds;
  621. end;
  622. procedure TSourceEditorWindowData.RemovePageCtrl(ASrcEditor: TSourceEditorInterface);
  623. begin
  624. {$IFDEF USE_GENERICS_COLLECTIONS}
  625. FPageCtrlList.Remove(ASrcEditor);
  626. {$ELSE}
  627. FPageCtrlList.Delete(ASrcEditor);
  628. {$ENDIF}
  629. end;
  630. { TDTXTabMaster }
  631. function TDTXTabMaster.GetTabDisplayState: TTabDisplayState;
  632. begin
  633. Result := GetTabDisplayStateEditor(SourceEditorManagerIntf.ActiveEditor);
  634. end;
  635. function TDTXTabMaster.GetTabDisplayStateEditor(Index: TSourceEditorInterface
  636. ): TTabDisplayState;
  637. var
  638. LPageCtrl: TModulePageControl;
  639. begin
  640. if Index = nil then
  641. Exit(tdsNone);
  642. LPageCtrl := FindModulePageControl(Index);
  643. if LPageCtrl = nil then
  644. Exit(tdsNone);
  645. case LPageCtrl.PageIndex of
  646. 0: Exit(tdsCode);
  647. 1: Exit(tdsDesign);
  648. else
  649. Exit(tdsOther);
  650. end;
  651. end;
  652. procedure TDTXTabMaster.ToggleFormUnit;
  653. begin
  654. case TabDisplayState of
  655. tdsCode:
  656. ShowDesigner(SourceEditorManagerIntf.ActiveEditor);
  657. tdsDesign:
  658. ShowCode(SourceEditorManagerIntf.ActiveEditor);
  659. end;
  660. end;
  661. procedure TDTXTabMaster.JumpToCompilerMessage(
  662. ASourceEditor: TSourceEditorInterface);
  663. begin
  664. SourceEditorManagerIntf.ActiveEditor := ASourceEditor;
  665. ShowCode(ASourceEditor);
  666. end;
  667. procedure TDTXTabMaster.ShowCode(ASourceEditor: TSourceEditorInterface);
  668. begin
  669. if ASourceEditor = nil then
  670. Exit;
  671. FindModulePageControl(ASourceEditor).PageIndex := 0;
  672. end;
  673. procedure TDTXTabMaster.ShowDesigner(ASourceEditor: TSourceEditorInterface; AIndex: Integer);
  674. var
  675. LPageCtrl: TModulePageControl;
  676. begin
  677. if ASourceEditor = nil then
  678. Exit;
  679. LPageCtrl := FindModulePageControl(ASourceEditor);
  680. if not LPageCtrl.Pages[1].TabVisible then
  681. Exit;
  682. LPageCtrl.PageIndex := 1;
  683. end;
  684. procedure TDTXTabMaster.ShowForm(AForm: TCustomForm);
  685. var
  686. LEditor: TSourceEditorInterface;
  687. begin
  688. LEditor := FindSourceEditorForDesigner(AForm.Designer);
  689. SourceEditorManagerIntf.ActiveEditor := LEditor;
  690. ShowDesigner(LEditor);
  691. end;
  692. { TDTXComponentsMaster }
  693. function TDTXComponentsMaster.DrawNonVisualComponents(ALookupRoot: TComponent
  694. ): Boolean;
  695. var
  696. LFormData: TDesignFormData;
  697. LPageCtrl: TModulePageControl;
  698. begin
  699. Result := True;
  700. LFormData := FindDesignFormData(FormEditingHook.GetDesignerForm(ALookupRoot){ALookupRoot as TCustomForm});
  701. if LFormData = nil then
  702. Exit;
  703. LPageCtrl := FindModulePageControl(LFormData.Form.LastActiveSourceWindow);
  704. if (LPageCtrl = nil) or (LPageCtrl.Resizer = nil) or (LPageCtrl.Resizer.MainDTU = nil) then
  705. Exit;
  706. Result := LPageCtrl.Resizer.MainDTU.ShowNonVisualComponents;
  707. end;
  708. { TSpartaMainIDE }
  709. class procedure TSpartaMainIDE.Screen_FormAdded(Sender: TObject; Form: TCustomForm);
  710. var
  711. LSourceEditor: TSourceEditorInterface;
  712. LFormData: TDesignFormData;
  713. //i: Integer;
  714. LPageCtrl: TModulePageControl;
  715. begin
  716. if IsFormDesign(Form) then
  717. begin
  718. // Form like TForm1 etc...
  719. if (csDesignInstance in Form.ComponentState) or (Form is TNonFormProxyDesignerForm) then
  720. begin
  721. LFormData := TDesignFormData.Create(Form);
  722. LFormData.FHiding:=True;
  723. dsgForms.Add(LFormData);
  724. LSourceEditor := FindSourceEditorForDesigner(Form.Designer);
  725. if LSourceEditor <> nil then
  726. begin
  727. LPageCtrl := FindModulePageControl(LSourceEditor);
  728. if LPageCtrl <> nil then
  729. begin
  730. LPageCtrl.ShowDesignPage;
  731. LPageCtrl.DesignFormData := LFormData;
  732. end;
  733. end;
  734. PostMessage(Form.Handle, WM_SETNOFRAME, 0, 0);
  735. end;
  736. end
  737. else
  738. begin
  739. // ONDREJ: the following code marged with (on-del) seems to help with nothing
  740. // but slows down loading forms and make them flicker.
  741. // I therefore commented it out. Please revert if there'll be regressions.
  742. { // (on-del)
  743. if not BoundInitialized then
  744. begin
  745. for i := 0 to Screen.FormCount - 1 do
  746. if Screen.Forms[i] = Form then
  747. Continue
  748. else
  749. begin
  750. Screen.Forms[i].AddHandlerOnChangeBounds(GlobalOnChangeBounds);
  751. end;
  752. BoundInitialized := True;
  753. end;}
  754. if Form is TSourceEditorWindowInterface then
  755. begin
  756. Form.AddHandlerOnChangeBounds(GlobalSNOnChangeBounds);
  757. //Form.PopupMode := pmExplicit; // (on-del)
  758. Forms.Add(Form); // (on-del)
  759. end
  760. else
  761. begin
  762. //Form.AddHandlerOnChangeBounds(GlobalOnChangeBounds); // (on-del)
  763. end;
  764. //Forms.Add(Form); // (on-del)
  765. end;
  766. end;
  767. class procedure TSpartaMainIDE.TryFreeFormData(Form: TCustomForm);
  768. var
  769. LSEWD: TSourceEditorWindowData;
  770. mpc: TModulePageControl;
  771. LFormData: TDesignFormData;
  772. {$IFNDEF USE_GENERICS_COLLECTIONS}
  773. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  774. LIterator2: THashmap<TSourceEditorInterface, TModulePageControl, THash_TObject>.TIterator;
  775. {$ENDIF}
  776. begin
  777. Form.Parent := nil;
  778. Application.ProcessMessages; // For TFrame - System Error. Code: 1400. Invalid window handle.
  779. LFormData := FindDesignFormData(Form);
  780. dsgForms.Remove(LFormData);
  781. {$IFDEF USE_GENERICS_COLLECTIONS}
  782. for LSEWD in SourceEditorWindows.Values do
  783. begin
  784. if LSEWD.ActiveDesignFormData <> nil then
  785. if LSEWD.ActiveDesignFormData.Form.Form = Form then
  786. LSEWD.FActiveDesignFormData := nil; // important - we can't call OnChange tab, because tab don't exist anymore
  787. for mpc in LSEWD.FPageCtrlList.Values do
  788. if mpc.DesignFormData <> nil then
  789. if mpc.DesignFormData.Form.Form = Form then
  790. mpc.DesignFormData := nil;
  791. end;
  792. {$ELSE}
  793. LIterator := SourceEditorWindows.Iterator;
  794. if LIterator <> nil then
  795. try
  796. repeat
  797. LSEWD := LIterator.Value;
  798. if LSEWD.ActiveDesignFormData <> nil then
  799. if LSEWD.ActiveDesignFormData.Form.Form = Form then
  800. LSEWD.FActiveDesignFormData := nil; // important - we can't call OnChange tab, because tab don't exist anymore
  801. LIterator2 := LSEWD.FPageCtrlList.Iterator;
  802. if LIterator2 <> nil then
  803. try
  804. repeat
  805. mpc := LIterator2.Value;
  806. if mpc.DesignFormData <> nil then
  807. if mpc.DesignFormData.Form.Form = Form then
  808. mpc.DesignFormData := nil;
  809. until not LIterator2.next;
  810. finally
  811. LIterator2.Free;
  812. end;
  813. until not LIterator.next;
  814. finally
  815. LIterator.Free;
  816. end;
  817. {$ENDIF}
  818. LFormData.Free;
  819. end;
  820. class procedure TSpartaMainIDE.Screen_FormDel(Sender: TObject; Form: TCustomForm);
  821. begin
  822. if not IsFormDesign(Form) then
  823. begin
  824. if Form is TSourceEditorWindowInterface then
  825. Form.RemoveHandlerOnChangeBounds(GlobalSNOnChangeBounds)
  826. else
  827. Form.RemoveHandlerOnChangeBounds(GlobalOnChangeBounds)
  828. end
  829. else
  830. TryFreeFormData(Form);
  831. end;
  832. class procedure TSpartaMainIDE.WindowCreate(Sender: TObject);
  833. var
  834. LSourceEditorWindow: TSourceEditorWindowInterface;
  835. begin
  836. if Sender.ClassNameIs('TSourceNotebook') then
  837. begin
  838. LSourceEditorWindow := Sender as TSourceEditorWindowInterface;
  839. {$IFDEF USE_GENERICS_COLLECTIONS}
  840. SourceEditorWindows.Add(LSourceEditorWindow, TSourceEditorWindowData.Create(LSourceEditorWindow));
  841. {$ELSE}
  842. SourceEditorWindows.insert(LSourceEditorWindow, TSourceEditorWindowData.Create(LSourceEditorWindow));
  843. {$ENDIF}
  844. end;
  845. end;
  846. class procedure TSpartaMainIDE.WindowDestroy(Sender: TObject);
  847. var
  848. p: Pointer;
  849. f: TDesignFormData absolute p;
  850. begin
  851. for p in dsgForms do
  852. if f.FForm.LastActiveSourceWindow = Sender then
  853. f.FForm.LastActiveSourceWindow := nil;
  854. {$IFDEF USE_GENERICS_COLLECTIONS}
  855. SourceEditorWindows.Remove(Sender as TSourceEditorWindowInterface);
  856. {$ELSE}
  857. SourceEditorWindows[Sender as TSourceEditorWindowInterface].Free;
  858. SourceEditorWindows.Delete(Sender as TSourceEditorWindowInterface);
  859. {$ENDIF}
  860. if LastActiveSourceEditorWindow = Sender then
  861. LastActiveSourceEditorWindow := nil;
  862. end;
  863. class procedure TSpartaMainIDE.WindowShow(Sender: TObject);
  864. var
  865. LWindow: TSourceEditorWindowInterface;
  866. LWindowData: TSourceEditorWindowData;
  867. LDesignedForm: IDesignedForm;
  868. begin
  869. LWindow := Sender as TSourceEditorWindowInterface;
  870. {$IFDEF USE_GENERICS_COLLECTIONS}
  871. if not SourceEditorWindows.TryGetValue(LWindow, LWindowData) or
  872. (LWindowData.ActiveDesignFormData = nil)
  873. then
  874. Exit;
  875. {$ELSE}
  876. if not SourceEditorWindows.contains(LWindow) then
  877. Exit;
  878. LWindowData := SourceEditorWindows[LWindow];
  879. if LWindowData.ActiveDesignFormData = nil then
  880. Exit;
  881. {$ENDIF}
  882. LDesignedForm := LWindowData.ActiveDesignFormData as IDesignedForm;
  883. LDesignedForm.ShowWindow;
  884. end;
  885. class procedure TSpartaMainIDE.WindowHide(Sender: TObject);
  886. var
  887. LWindow: TSourceEditorWindowInterface;
  888. LWindowData: TSourceEditorWindowData;
  889. LDesignedForm: IDesignedForm;
  890. begin
  891. LWindow := Sender as TSourceEditorWindowInterface;
  892. {$IFDEF USE_GENERICS_COLLECTIONS}
  893. if not SourceEditorWindows.TryGetValue(LWindow, LWindowData) or
  894. (LWindowData.ActiveDesignFormData = nil)
  895. then
  896. Exit;
  897. {$ELSE}
  898. if not SourceEditorWindows.contains(LWindow) then
  899. Exit;
  900. LWindowData := SourceEditorWindows[LWindow];
  901. if LWindowData.ActiveDesignFormData = nil then
  902. Exit;
  903. {$ENDIF}
  904. LDesignedForm := LWindowData.ActiveDesignFormData as IDesignedForm;
  905. LDesignedForm.HideWindow;
  906. end;
  907. class procedure TSpartaMainIDE.DesignerSetFocus;
  908. var
  909. LResizer: TResizer;
  910. begin
  911. LResizer := GetCurrentResizer;
  912. if LResizer<>nil then
  913. LResizer.ActiveResizeFrame.DesignerSetFocus;
  914. end;
  915. class procedure TSpartaMainIDE.EditorActivated(Sender: TObject);
  916. var
  917. LDesigner: TIDesigner;
  918. LSourceEditor: TSourceEditorInterface;
  919. {$IFNDEF USE_GENERICS_COLLECTIONS}
  920. LIterator: THashmap<TSourceEditorInterface, TModulePageControl, THash_TObject>.TIterator;
  921. {$ENDIF}
  922. function LastSourceEditorNotFound: boolean;
  923. var
  924. i: Integer;
  925. se: TSourceEditorInterface;
  926. begin
  927. if (LastActiveSourceEditorWindow = nil) or (LastActiveSourceEditor = nil) then
  928. Exit(False);
  929. {$IFDEF USE_GENERICS_COLLECTIONS}
  930. for se in SourceEditorWindows[LastActiveSourceEditorWindow].FPageCtrlList.Keys do
  931. begin
  932. Result := True;
  933. for i := 0 to LastActiveSourceEditorWindow.Count - 1 do
  934. if se = LastActiveSourceEditorWindow.Items[i] then
  935. begin
  936. Result := False;
  937. Break;
  938. end;
  939. if Result then
  940. begin
  941. LastActiveSourceEditor := se; // after moving code editor into other window, sometimes IDE switch to other tab :\ damn... this line prevent this.
  942. Exit;
  943. end;
  944. end;
  945. {$ELSE}
  946. LIterator := SourceEditorWindows[LastActiveSourceEditorWindow].FPageCtrlList.Iterator;
  947. if LIterator <> nil then
  948. try
  949. repeat
  950. se := LIterator.Key;
  951. Result := True;
  952. for i := 0 to LastActiveSourceEditorWindow.Count - 1 do
  953. if se = LastActiveSourceEditorWindow.Items[i] then
  954. begin
  955. Result := False;
  956. Break;
  957. end;
  958. if Result then
  959. begin
  960. LastActiveSourceEditor := se; // after moving code editor into other window, sometimes IDE switch to other tab :\ damn... this line prevent this.
  961. Exit;
  962. end;
  963. until not LIterator.next;
  964. finally
  965. LIterator.Free;
  966. end;
  967. {$ENDIF}
  968. Result := False;
  969. end;
  970. var
  971. LPageCtrl: TModulePageControl;
  972. LSourceEditorWindow: TSourceEditorWindowInterface;
  973. LDesignFormData: TDesignFormData;
  974. begin
  975. if Sender is TSourceEditorInterface then
  976. begin
  977. LSourceEditor := TSourceEditorInterface(Sender);
  978. // if we create directly new project then Activate is called without EditorCreate...
  979. if not (LSourceEditor.EditorControl.Parent.Parent is TModulePageControl) then
  980. begin
  981. // possible is situation when we moved tab into other window
  982. // then was not called event EditorDestroy - that generates problems with switching tabs
  983. // or when we moving tab to first window ( then is raising : duplicates not allowed in dictionary).
  984. if LastSourceEditorNotFound then
  985. EditorDestroyed(nil);
  986. EditorCreate(Sender);
  987. end;
  988. LDesigner := LSourceEditor.GetDesigner(True);
  989. // should be performed during EditorCreate (parent of parent is module page ctrl)
  990. LPageCtrl := TModulePageControl(LSourceEditor.EditorControl.Parent.Parent);
  991. if LPageCtrl = nil then
  992. Exit;
  993. if LDesigner = nil then
  994. LPageCtrl.HideDesignPage
  995. else
  996. begin
  997. if LPageCtrl.Resizer = nil then
  998. LPageCtrl.FResizer := TResizer.Create(LPageCtrl.Pages[1], TResizerFrame);
  999. LPageCtrl.ShowDesignPage;
  1000. end;
  1001. LSourceEditorWindow := TSourceEditorWindowInterface(LPageCtrl.Owner);
  1002. LastActiveSourceEditorWindow := LSourceEditorWindow;
  1003. LastActiveSourceEditor := LSourceEditor;
  1004. LDesignFormData := FindDesignFormData(LPageCtrl);
  1005. // when we switch tab, design form should be hidden
  1006. if (LDesigner = nil) or (LDesignFormData = nil) then
  1007. SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := nil
  1008. else
  1009. begin
  1010. // during form loading for example from package, ActiveDesignFormData assignment,
  1011. // blocks the message queue responsible for hiding form
  1012. // We can't check it because there are some forms where designing is not handled yet.
  1013. // (for that kind of forms is returned empty designformdata)
  1014. // maybe we can fix this in future
  1015. if not LDesignFormData.FHiding then
  1016. // Prevent unexpected events (when is deactivated some control outside designed form)
  1017. if (LDesignFormData.Form.LastActiveSourceWindow = LSourceEditorWindow)
  1018. // important!!! for many error - switching between editors...
  1019. and (LPageCtrl.PageIndex = 1) then
  1020. SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := LDesignFormData
  1021. else
  1022. SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := nil;
  1023. end;
  1024. case LPageCtrl.PageIndex of
  1025. 0: if LDesignFormData <> nil then LDesignFormData.Form.HideWindow;
  1026. 1:
  1027. begin
  1028. LazarusIDE.DoShowDesignerFormOfSrc(LSourceEditorWindow.ActiveEditor);
  1029. // for lfm edition...
  1030. with LDesignFormData as IDesignedForm do
  1031. if not LDesignFormData.FHiding and (RealBorderStyle <> bsNone) then
  1032. begin
  1033. BeginUpdate;
  1034. //RealBorderIcons := [];
  1035. //RealBorderStyle := bsNone;
  1036. Form.Show;
  1037. EndUpdate;
  1038. LPageCtrl.BoundToDesignTabSheet;
  1039. PostMessage(Form.Handle, WM_BoundToDesignTabSheet, 0, 0);
  1040. end;
  1041. end;
  1042. end;
  1043. end
  1044. else
  1045. begin
  1046. RefreshAllSourceWindowsModulePageControl;
  1047. end;
  1048. end;
  1049. class procedure TSpartaMainIDE.EditorDestroyed(Sender: TObject);
  1050. var
  1051. LSourceEditor: TSourceEditorInterface;
  1052. LPageCtrl: TModulePageControl;
  1053. LSourceEditorWindow: TSourceEditorWindowInterface;
  1054. LFormData: TDesignFormData;
  1055. begin
  1056. // sender is here as special parameter, because is possible situation where is moved editor
  1057. // to another window and was not triggered EditorDestroy - for more info goto editoractivate
  1058. if Sender = nil then
  1059. LSourceEditor := LastActiveSourceEditor
  1060. else
  1061. LSourceEditor := TSourceEditorInterface(Sender);
  1062. // parent don't exist anymore and we must search in each window...
  1063. if Sender = nil then // but not for Sender = nil :P
  1064. LPageCtrl := SourceEditorWindows[LastActiveSourceEditorWindow].FPageCtrlList[LastActiveSourceEditor]
  1065. else
  1066. LPageCtrl := AbsoluteFindModulePageControl(LSourceEditor);
  1067. if LPageCtrl = nil then
  1068. Exit;
  1069. LFormData := FindDesignFormData(LSourceEditor.GetDesigner(False));
  1070. // goto first comment (forced destroy)
  1071. if Sender = nil then
  1072. LSourceEditorWindow := LastActiveSourceEditorWindow
  1073. else
  1074. LSourceEditorWindow := TSourceEditorWindowInterface(LPageCtrl.Owner);
  1075. if LFormData <> nil then
  1076. begin
  1077. SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := nil;
  1078. LFormData.Form.LastActiveSourceWindow := nil;
  1079. end;
  1080. SourceEditorWindows[LSourceEditorWindow].RemovePageCtrl(LSourceEditor);
  1081. LPageCtrl.Free;
  1082. if LastActiveSourceEditor = LSourceEditor then
  1083. LastActiveSourceEditor := nil;
  1084. end;
  1085. class function TSpartaMainIDE.GetCurrentResizer: TResizer;
  1086. var
  1087. LForm: TCustomForm;
  1088. LFormData: TDesignFormData;
  1089. LSourceWindow: TSourceEditorWindowInterface;
  1090. LPageCtrl: TModulePageControl;
  1091. begin
  1092. Result := nil;
  1093. LForm := FormEditingHook.GetDesignerForm(GlobalDesignHook.LookupRoot);
  1094. LFormData := FindDesignFormData(LForm);
  1095. if LFormData=nil then Exit;
  1096. LSourceWindow := (LFormData as IDesignedFormIDE).LastActiveSourceWindow;
  1097. LPageCtrl := FindModulePageControl(LSourceWindow);
  1098. Result := LPageCtrl.Resizer;
  1099. end;
  1100. class procedure TSpartaMainIDE.EditorCreate(Sender: TObject);
  1101. var
  1102. LSourceEditor: TSourceEditorInterface;
  1103. function CreateModulePageControl: TModulePageControl;
  1104. var
  1105. LNewTabSheet: TTabSheet;
  1106. LSourceEditorWindow: TSourceEditorWindowInterface;
  1107. LParent: TWinControl;
  1108. begin
  1109. Result := TModulePageControl.Create(LSourceEditor.EditorControl.Owner);
  1110. Result.TabPosition := tpBottom;
  1111. Result.Align:=alClient;
  1112. LParent := LSourceEditor.EditorControl.Parent;
  1113. LNewTabSheet := TTabSheet.Create(Result);
  1114. LNewTabSheet.PageControl := Result;
  1115. LNewTabSheet.Caption := SCode;
  1116. LSourceEditor.EditorControl.Parent := LNewTabSheet; // ! SynEdit :)
  1117. LNewTabSheet := TTabSheet.Create(Result);
  1118. LNewTabSheet.PageControl := Result;
  1119. LNewTabSheet.Caption := SDesigner;
  1120. Result.OnChange := TabChange;
  1121. Result.Parent := LParent;
  1122. LSourceEditorWindow := TSourceEditorWindowInterface(Result.Owner);
  1123. SourceEditorWindows[LSourceEditorWindow].AddPageCtrl(LSourceEditor, Result)
  1124. end;
  1125. begin
  1126. LSourceEditor := Sender as TSourceEditorInterface;
  1127. if not (LSourceEditor.EditorControl.Parent.Parent is TModulePageControl) then
  1128. CreateModulePageControl;
  1129. end;
  1130. class procedure TSpartaMainIDE.TabChange(Sender: TObject);
  1131. var
  1132. LActiveSourceWindow: TSourceEditorWindowInterface;
  1133. w: TSourceEditorWindowInterface;
  1134. {$IFDEF USE_GENERICS_COLLECTIONS}
  1135. p: TPair<TSourceEditorInterface, TModulePageControl>;
  1136. {$ELSE}
  1137. p: THashmap<TSourceEditorInterface, TModulePageControl, THash_TObject>.TPair;
  1138. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  1139. LIterator2: THashmap<TSourceEditorInterface, TModulePageControl, THash_TObject>.TIterator;
  1140. {$ENDIF}
  1141. LDesigner: TIDesigner;
  1142. LFormData: TDesignFormData;
  1143. LPageCtrl: TModulePageControl;
  1144. LSourceWndData: TSourceEditorWindowData;
  1145. begin
  1146. // activate proper source editor window when user is clicking on page.
  1147. // (at clicking time can be active other source window)
  1148. LActiveSourceWindow := TComponent(Sender).Owner as TSourceEditorWindowInterface;
  1149. if LActiveSourceWindow <> SourceEditorManagerIntf.ActiveSourceWindow then
  1150. SourceEditorManagerIntf.ActiveSourceWindow := LActiveSourceWindow;
  1151. LPageCtrl := TModulePageControl(Sender);
  1152. // in case there is no module and is visible page other than code page.
  1153. if (LActiveSourceWindow.ActiveEditor <> nil) and (LPageCtrl <> nil) then
  1154. begin
  1155. LDesigner := LActiveSourceWindow.ActiveEditor.GetDesigner(True);
  1156. LFormData := FindDesignFormData(LDesigner);
  1157. {$IFDEF USE_GENERICS_COLLECTIONS}
  1158. if (LFormData <> nil) and SourceEditorWindows.TryGetValue(LActiveSourceWindow, LSourceWndData) then
  1159. begin
  1160. case LPageCtrl.ActivePageIndex of
  1161. 0:
  1162. begin
  1163. LSourceWndData.ActiveDesignFormData := nil;
  1164. end;
  1165. 1:
  1166. begin
  1167. // deactivate design tab in other page control :)
  1168. for w in SourceEditorWindows.Keys do
  1169. if w = LActiveSourceWindow then
  1170. Continue
  1171. else
  1172. for p in SourceEditorWindows[w].FPageCtrlList do
  1173. if (p.Value.DesignFormData = LFormData) and (p.Value <> Sender) then
  1174. begin
  1175. IDETabMaster.ShowCode(p.Key);
  1176. end;
  1177. LSourceWndData.ActiveDesignFormData := LFormData;
  1178. // to handle windows with different size
  1179. LPageCtrl.BoundToDesignTabSheet;
  1180. end;
  1181. end;
  1182. end;
  1183. {$ELSE}
  1184. if (LFormData <> nil) and SourceEditorWindows.contains(LActiveSourceWindow) then
  1185. begin
  1186. LSourceWndData := SourceEditorWindows[LActiveSourceWindow];
  1187. case LPageCtrl.ActivePageIndex of
  1188. 0:
  1189. begin
  1190. LSourceWndData.ActiveDesignFormData := nil;
  1191. end;
  1192. 1:
  1193. begin
  1194. // deactivate design tab in other page control :)
  1195. LIterator := SourceEditorWindows.Iterator;
  1196. if LIterator <> nil then
  1197. try
  1198. repeat
  1199. w := LIterator.Key;
  1200. if w = LActiveSourceWindow then
  1201. Continue
  1202. else
  1203. begin
  1204. LIterator2 := SourceEditorWindows[w].FPageCtrlList.Iterator;
  1205. if LIterator2 <> nil then
  1206. try
  1207. repeat
  1208. p := LIterator2.Data;
  1209. if (p.Value.DesignFormData = LFormData) and (p.Value <> Sender) then
  1210. IDETabMaster.ShowCode(p.Key);
  1211. until not LIterator2.next;
  1212. finally
  1213. LIterator2.Free;
  1214. end;
  1215. end;
  1216. until not LIterator.next;
  1217. finally
  1218. LIterator.Free;
  1219. end;
  1220. LSourceWndData.ActiveDesignFormData := LFormData;
  1221. // to handle windows with different size
  1222. LPageCtrl.BoundToDesignTabSheet;
  1223. end;
  1224. end;
  1225. end;
  1226. {$ENDIF}
  1227. end;
  1228. end;
  1229. class procedure TSpartaMainIDE.GlobalOnChangeBounds(Sender: TObject);
  1230. var
  1231. sewd: TSourceEditorWindowData;
  1232. {$IFNDEF USE_GENERICS_COLLECTIONS}
  1233. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  1234. {$ENDIF}
  1235. begin
  1236. {$IFDEF USE_GENERICS_COLLECTIONS}
  1237. for sewd in SourceEditorWindows.Values do
  1238. begin
  1239. sewd.OnChangeBounds(Sender);
  1240. end;
  1241. {$ELSE}
  1242. LIterator := SourceEditorWindows.Iterator;
  1243. if LIterator <> nil then
  1244. try
  1245. repeat
  1246. sewd := LIterator.Value;
  1247. sewd.OnChangeBounds(Sender)
  1248. until not LIterator.next;
  1249. finally
  1250. LIterator.Free;
  1251. end;
  1252. {$ENDIF}
  1253. end;
  1254. class procedure TSpartaMainIDE.GlobalSNOnChangeBounds(Sender: TObject);
  1255. var
  1256. LWindow: TSourceEditorWindowInterface;
  1257. LWindowData: TSourceEditorWindowData;
  1258. LDesignForm: TDesignFormData;
  1259. begin
  1260. // Check parent. Maybe is different? If yes then window changed state (docked/undocked) and we need to perform few actions
  1261. LWindow := Sender as TSourceEditorWindowInterface;
  1262. // dock/undock event :)
  1263. {$IFDEF USE_GENERICS_COLLECTIONS}
  1264. if not SourceEditorWindows.TryGetValue(LWindow, LWindowData) then
  1265. Exit;
  1266. {$ELSE}
  1267. if not SourceEditorWindows.contains(LWindow) then
  1268. Exit;
  1269. LWindowData := SourceEditorWindows[LWindow];
  1270. {$ENDIF}
  1271. if LWindowData.FLastTopParent <> LWindow.GetTopParent then
  1272. begin
  1273. LWindowData.FLastTopParent := LWindow.GetTopParent;
  1274. // refresh for popupparent
  1275. LDesignForm := LWindowData.ActiveDesignFormData;
  1276. LWindowData.ActiveDesignFormData := nil;
  1277. LWindowData.ActiveDesignFormData := LDesignForm;
  1278. // ...
  1279. //PostMessage(LWindow.Handle, WM_BoundToDesignTabSheet, 0, 0);
  1280. if LDesignForm <> nil then
  1281. begin
  1282. LDesignForm.Form.Form.Parent := FindModulePageControl(LWindow).Resizer.ActiveResizeFrame.ClientPanel;
  1283. PostMessage(LDesignForm.Form.Form.Handle, WM_BoundToDesignTabSheet, 0, 0);
  1284. end;
  1285. end;
  1286. LWindowData.OnChangeBounds(Sender);
  1287. end;
  1288. class procedure TSpartaMainIDE.OnDesignMouseDown(Sender: TObject;
  1289. Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1290. begin
  1291. DesignerSetFocus;
  1292. end;
  1293. class procedure TSpartaMainIDE.OnModifiedSender(Sender: TObject; PropName: ShortString);
  1294. begin
  1295. OnModified;
  1296. end;
  1297. class procedure TSpartaMainIDE.OnModified;
  1298. var
  1299. LResizer: TResizer;
  1300. begin
  1301. LResizer := GetCurrentResizer;
  1302. if LResizer<>nil then
  1303. LResizer.ActiveResizeFrame.OnModified;
  1304. end;
  1305. class procedure TSpartaMainIDE.OnModifiedPersistentAdded(
  1306. APersistent: TPersistent; Select: Boolean);
  1307. begin
  1308. OnModified;
  1309. end;
  1310. class procedure TSpartaMainIDE.OnShowDesignerForm(Sender: TObject; AEditor: TSourceEditorInterface;
  1311. AComponentPaletteClassSelected: Boolean);
  1312. var
  1313. LForm: TDesignFormData;
  1314. LPageCtrl, p: TModulePageControl;
  1315. w: TSourceEditorWindowInterface;
  1316. e: TSourceEditorInterface;
  1317. {$IFNDEF USE_GENERICS_COLLECTIONS}
  1318. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  1319. {$ENDIF}
  1320. begin
  1321. LForm := FindDesignFormData(TCustomForm(Sender).Designer);
  1322. if LForm = nil then
  1323. Exit;
  1324. if LForm.FHiding then
  1325. Exit;
  1326. LPageCtrl := FindModulePageControl(SourceEditorManagerIntf.ActiveEditor);
  1327. if LPageCtrl = nil then
  1328. Exit; // it should not happen but who knows :P Lazarus IDE is sometimes mischievous
  1329. if AComponentPaletteClassSelected then
  1330. begin
  1331. // if form is already opened do nothing, if not then show form for active module.
  1332. {$IFDEF USE_GENERICS_COLLECTIONS}
  1333. for w in SourceEditorWindows.Keys do
  1334. begin
  1335. e := w.ActiveEditor;
  1336. if (e = nil) or (e.GetDesigner(True) <> LForm.Form.Form.Designer) then
  1337. Continue;
  1338. p := FindModulePageControl(e);
  1339. if p.PageIndex = 1 then
  1340. Exit;
  1341. end;
  1342. {$ELSE}
  1343. LIterator := SourceEditorWindows.Iterator;
  1344. if LIterator <> nil then
  1345. try
  1346. repeat
  1347. w := LIterator.Key;
  1348. e := w.ActiveEditor;
  1349. if (e = nil) or (e.GetDesigner(True) <> LForm.Form.Form.Designer) then
  1350. Continue;
  1351. p := FindModulePageControl(e);
  1352. if p.PageIndex = 1 then
  1353. Exit;
  1354. until not LIterator.next;
  1355. finally
  1356. LIterator.Free;
  1357. end;
  1358. {$ENDIF}
  1359. end;
  1360. IDETabMaster.ShowDesigner(SourceEditorManagerIntf.ActiveEditor);
  1361. end;
  1362. class procedure TSpartaMainIDE.OnShowSrcEditor(Sender: TObject);
  1363. begin
  1364. IDETabMaster.ShowCode(Sender as TSourceEditorInterface);
  1365. end;
  1366. class procedure TSpartaMainIDE.OnShowMethod(const Name: String);
  1367. var
  1368. LForm: TDesignFormData;
  1369. LSecondEditor: TSourceEditorInterface = nil;
  1370. i: Integer;
  1371. LSourceWindow: TSourceEditorWindowInterface;
  1372. begin
  1373. LForm := FindDesignFormData(FormEditingHook.GetCurrentDesigner);
  1374. if LForm = nil then
  1375. Exit;
  1376. for i := 0 to SourceEditorManagerIntf.SourceWindowCount - 1 do
  1377. begin
  1378. LSourceWindow := SourceEditorManagerIntf.SourceWindows[i];
  1379. if LForm.Form.LastActiveSourceWindow = LSourceWindow then
  1380. Continue;
  1381. if LSourceWindow.ActiveEditor <> nil then
  1382. if LSourceWindow.ActiveEditor.GetDesigner(True) = LForm.Form.Form.Designer then
  1383. begin
  1384. LSecondEditor := LSourceWindow.ActiveEditor;
  1385. Break;
  1386. end;
  1387. end;
  1388. if LSecondEditor = nil then
  1389. begin
  1390. if LForm.Form.LastActiveSourceWindow <> nil then
  1391. begin
  1392. IDETabMaster.ShowCode(LForm.Form.LastActiveSourceWindow.ActiveEditor);
  1393. end;
  1394. end
  1395. else
  1396. begin
  1397. IDETabMaster.ShowCode(LSecondEditor);
  1398. end;
  1399. if LSecondEditor <> nil then
  1400. begin
  1401. LazarusIDE.DoShowMethod(LSecondEditor, Name);
  1402. end;
  1403. end;
  1404. class procedure TSpartaMainIDE.OnDesignRefreshPropertyValues;
  1405. var
  1406. LForm: TCustomForm;
  1407. LSourceWindow: TSourceEditorWindowInterface;
  1408. LFormData: TDesignFormData;
  1409. LPageCtrl: TModulePageControl;
  1410. function RootIsSelected: Boolean;
  1411. var
  1412. LSelection: TPersistentSelectionList;
  1413. i: integer;
  1414. begin
  1415. Result := False;
  1416. LSelection := TPersistentSelectionList.Create;
  1417. GlobalDesignHook.GetSelection(LSelection);
  1418. for i := 0 to LSelection.Count - 1 do
  1419. if LSelection.Items[i] = GlobalDesignHook.LookupRoot then
  1420. begin
  1421. Result := True;
  1422. Break;
  1423. end;
  1424. LSelection.Free;
  1425. end;
  1426. begin
  1427. if (GlobalDesignHook.LookupRoot is TCustomFrame) then
  1428. begin
  1429. if not RootIsSelected then
  1430. Exit;
  1431. LForm := FormEditingHook.GetDesignerForm(GlobalDesignHook.LookupRoot);
  1432. LFormData := FindDesignFormData(LForm);
  1433. LSourceWindow := (LFormData as IDesignedFormIDE).LastActiveSourceWindow;
  1434. LPageCtrl := FindModulePageControl(LSourceWindow);
  1435. TFakeFrame(LForm).SetBounds(LForm.Left-1,LForm.Top-1,TFakeFrame(LForm).Width,TFakeFrame(LForm).Height);
  1436. //LPageCtrl.BoundToDesignTabSheet;
  1437. end
  1438. else
  1439. if (GlobalDesignHook.LookupRoot is TCustomForm) then
  1440. begin
  1441. if not RootIsSelected then
  1442. Exit;
  1443. LForm := TCustomForm(GlobalDesignHook.LookupRoot);
  1444. LFormData := FindDesignFormData(LForm);
  1445. LFormData.RepaintFormImages;
  1446. end;
  1447. end;
  1448. {$IFNDEF USE_GENERICS_COLLECTIONS}
  1449. class procedure FreeSourceEditorWindowsValues;
  1450. var
  1451. LIterator: THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.TIterator;
  1452. begin
  1453. LIterator := SourceEditorWindows.Iterator;
  1454. if LIterator <> nil then
  1455. try
  1456. repeat
  1457. LIterator.Value.Free;
  1458. until not LIterator.next;
  1459. finally
  1460. LIterator.Free;
  1461. end;
  1462. end;
  1463. {$ENDIF}
  1464. initialization
  1465. dsgForms := Classes.TList.Create;
  1466. {$IFDEF USE_GENERICS_COLLECTIONS}
  1467. SourceEditorWindows := TObjectDictionary<TSourceEditorWindowInterface, TSourceEditorWindowData>.Create([doOwnsValues]);
  1468. {$ELSE}
  1469. SourceEditorWindows := THashmap<TSourceEditorWindowInterface, TSourceEditorWindowData, THash_TObject>.Create();
  1470. {$ENDIF}
  1471. Forms := Classes.TList.Create;
  1472. finalization
  1473. Forms.Free;
  1474. {$IFNDEF USE_GENERICS_COLLECTIONS}
  1475. FreeSourceEditorWindowsValues;
  1476. {$ENDIF}
  1477. SourceEditorWindows.Free;
  1478. FreeAndNil(dsgForms);
  1479. end.