ProjectTree.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. unit ProjectTree;
  2. interface
  3. uses
  4. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  5. Dialogs, ComCtrls, CommCtrl, ExtCtrls, ImgList, Menus, JvComponent, ShellAPI,
  6. JvDockControlForm, JvExComCtrls, JvComCtrls, JvDotNetControls, Misc,
  7. VirtualTrees;
  8. type
  9. PProjectTreeData = ^TProjectTreeData;
  10. TProjectTreeData = record
  11. ItemType: Integer;
  12. pLuaEditFile: TLuaEditFile;
  13. ActiveProject: Boolean;
  14. ToKeep: Boolean;
  15. Deleting: Boolean;
  16. OpenIndex: Integer;
  17. CloseIndex: Integer;
  18. end;
  19. TfrmProjectTree = class(TForm)
  20. Panel1: TPanel;
  21. ppmProjectTree: TPopupMenu;
  22. ActivateSelectedProject1: TMenuItem;
  23. N1: TMenuItem;
  24. UnloadFileProject1: TMenuItem;
  25. JvDockClient1: TJvDockClient;
  26. N2: TMenuItem;
  27. AddUnittoProject1: TMenuItem;
  28. RemoveUnitFromProject1: TMenuItem;
  29. Options1: TMenuItem;
  30. mnuFindTarget: TMenuItem;
  31. vstProjectTree: TVirtualDrawTree;
  32. SystemImages: TImageList;
  33. StatesImages: TImageList;
  34. N3: TMenuItem;
  35. SaveAs1: TMenuItem;
  36. procedure UnloadFileProject1Click(Sender: TObject);
  37. procedure ppmProjectTreePopup(Sender: TObject);
  38. procedure vstProjectTreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
  39. procedure vstProjectTreeDblClick(Sender: TObject);
  40. procedure vstProjectTreeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  41. procedure vstProjectTreeAfterItemPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
  42. function GetNodeInTree(pFile: TLuaEditFile; pPrj: TLuaEditProject): PVirtualNode;
  43. procedure mnuFindTargetClick(Sender: TObject);
  44. procedure vstProjectTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  45. procedure vstProjectTreeDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
  46. procedure FormCreate(Sender: TObject);
  47. procedure vstProjectTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
  48. procedure N3Click(Sender: TObject);
  49. procedure SaveAs1Click(Sender: TObject);
  50. private
  51. { Private declarations }
  52. public
  53. { Public declarations }
  54. procedure BuildProjectTree(HandleNotifier: Boolean = True);
  55. end;
  56. var
  57. frmProjectTree: TfrmProjectTree;
  58. implementation
  59. uses Main;
  60. {$R *.dfm}
  61. // Returns the index of the system icon for the given file object.
  62. function GetIconIndex(Name: String; Flags: Cardinal): Integer;
  63. var
  64. SFI: TSHFileInfo;
  65. begin
  66. if SHGetFileInfo(PChar(Name), 0, SFI, SizeOf(TSHFileInfo), Flags) = 0 then
  67. Result := -1
  68. else
  69. Result := SFI.iIcon;
  70. end;
  71. procedure GetOpenAndClosedIcons(Name: String; var Open, Closed: Integer);
  72. begin
  73. Closed := GetIconIndex(Name, SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  74. Open := GetIconIndex(Name, SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_OPENICON);
  75. end;
  76. // Rescale source but keep aspect ratio
  77. procedure RescaleImage(ScaleX, ScaleY: Integer; Source, Target: TBitmap);
  78. var
  79. NewWidth, NewHeight: Integer;
  80. begin
  81. if (Source.Width > ScaleX) or (Source.Height > ScaleY) then
  82. begin
  83. if Source.Width > Source.Height then
  84. begin
  85. NewWidth := ScaleX;
  86. NewHeight := Round(ScaleY * Source.Height / Source.Width);
  87. end
  88. else
  89. begin
  90. NewHeight := ScaleY;
  91. NewWidth := Round(ScaleX * Source.Width / Source.Height);
  92. end;
  93. Target.Width := NewWidth;
  94. Target.Height := NewHeight;
  95. SetStretchBltMode(Target.Canvas.Handle, HALFTONE);
  96. StretchBlt(Target.Canvas.Handle, 0, 0, NewWidth, NewHeight,
  97. Source.Canvas.Handle, 0, 0, Source.Width, Source.Height, SRCCOPY);
  98. end
  99. else
  100. Target.Assign(Source);
  101. end;
  102. // Little helper to convert a Delphi color to an image list color.
  103. function GetRGBColor(Value: TColor): DWORD;
  104. begin
  105. Result := ColorToRGB(Value);
  106. case Result of
  107. clNone:
  108. Result := CLR_NONE;
  109. clDefault:
  110. Result := CLR_DEFAULT;
  111. end;
  112. end;
  113. ////////////////////////////////////////////////////////////////////////////////
  114. // TfrmProjectTree functions
  115. ////////////////////////////////////////////////////////////////////////////////
  116. procedure TfrmProjectTree.vstProjectTreeDblClick(Sender: TObject);
  117. var
  118. pNode: PVirtualNode;
  119. pData: PProjectTreeData;
  120. pFile: TLuaEditBasicTextFile;
  121. begin
  122. pNode := vstProjectTree.GetFirstSelected;
  123. if Assigned(pNode) then
  124. begin
  125. pData := vstProjectTree.GetNodeData(pNode);
  126. if pData.pLuaEditFile.FileType in LuaEditTextFilesTypeSet then
  127. begin
  128. pFile := TLuaEditBasicTextFile(pData.pLuaEditFile);
  129. if pFile.IsLoaded then
  130. begin
  131. frmLuaEditMain.PopUpUnitToScreen(pFile.DisplayPath);
  132. end;
  133. end
  134. else if pData.pLuaEditFile.FileType = otLuaEditForm then
  135. frmLuaEditMain.DoBringGUIFormToFrontExecute();
  136. end;
  137. frmLuaEditMain.CheckButtons;
  138. end;
  139. function TfrmProjectTree.GetNodeInTree(pFile: TLuaEditFile; pPrj: TLuaEditProject): PVirtualNode;
  140. var
  141. pNode: PVirtualNode;
  142. pData: PProjectTreeData;
  143. begin
  144. Result := nil;
  145. pNode := vstProjectTree.GetFirst;
  146. while Assigned(pNode) do
  147. begin
  148. pData := vstProjectTree.GetNodeData(pNode);
  149. if Assigned(pPrj) then
  150. begin
  151. if ((pData.pLuaEditFile.FileType in LuaEditTextFilesTypeSet) and (not pData.Deleting)) then
  152. begin
  153. if pData.pLuaEditFile.PrjOwner = pPrj then
  154. begin
  155. if pData.pLuaEditFile = pFile then
  156. begin
  157. Result := pNode;
  158. Break;
  159. end;
  160. end;
  161. end;
  162. end
  163. else
  164. begin
  165. if pData.pLuaEditFile.FileType = otLuaEditProject then
  166. begin
  167. if pData.pLuaEditFile = pFile then
  168. begin
  169. Result := pNode;
  170. Break;
  171. end;
  172. end;
  173. end;
  174. pNode := vstProjectTree.GetNext(pNode);
  175. end;
  176. end;
  177. procedure TfrmProjectTree.BuildProjectTree(HandleNotifier: Boolean);
  178. var
  179. pTempPrj: TLuaEditProject;
  180. pPrjNode, pUnitNode, pSingleUnitLastNode: PVirtualNode;
  181. pData, pDataGUIForm: PProjectTreeData;
  182. x, y: Integer;
  183. // Go through all nodes of the tree and set their ToKeep flag to false
  184. procedure UnflagAllExpanded(pTree: TVirtualDrawTree);
  185. var
  186. pNode: PVirtualNode;
  187. pData: PProjectTreeData;
  188. begin
  189. pNode := pTree.GetFirst;
  190. while Assigned(pNode) do
  191. begin
  192. pData := pTree.GetNodeData(pNode);
  193. pData.ToKeep := False;
  194. pNode := pTree.GetNext(pNode);
  195. end;
  196. end;
  197. // Deletes all nodes for wich their ToKeep flag is still on false
  198. procedure CleanTree(pTree: TVirtualDrawTree);
  199. var
  200. pNode, pPrevious: PVirtualNode;
  201. pData: PProjectTreeData;
  202. begin
  203. pNode := pTree.GetFirst;
  204. while Assigned(pNode) do
  205. begin
  206. pData := pTree.GetNodeData(pNode);
  207. if not pData.ToKeep then
  208. begin
  209. pPrevious := pTree.GetPrevious(pNode);
  210. pTree.DeleteNode(pNode);
  211. pNode := pPrevious;
  212. end;
  213. pNode := pTree.GetNext(pNode);
  214. end;
  215. end;
  216. begin
  217. // Initialize stuff
  218. pPrjNode := nil;
  219. pUnitNode := nil;
  220. pSingleUnitLastNode := nil;
  221. // If the changes notifier is handled, we stop it while building the tree
  222. if HandleNotifier then
  223. begin
  224. frmLuaEditMain.jvchnNotifier.Active := False;
  225. frmLuaEditMain.jvchnNotifier.Notifications.Clear;
  226. end;
  227. vstProjectTree.BeginUpdate;
  228. UnflagAllExpanded(vstProjectTree);
  229. for x := 0 to LuaProjects.Count - 1 do
  230. begin
  231. pTempPrj := TLuaEditProject(LuaProjects.Items[x]);
  232. pPrjNode := GetNodeInTree(pTempPrj, nil);
  233. if not Assigned(pPrjNode) then
  234. begin
  235. if pTempPrj.Name <> '[@@SingleUnits@@]' then
  236. begin
  237. // Create the node
  238. pPrjNode := vstProjectTree.AddChild(vstProjectTree.RootNode);
  239. pData := vstProjectTree.GetNodeData(pPrjNode);
  240. pData.pLuaEditFile := pTempPrj;
  241. pData.ActiveProject := (pTempPrj = ActiveProject);
  242. pData.ToKeep := True;
  243. pData.Deleting := False;
  244. // Adding project root to change notifier...
  245. if ((not pTempPrj.IsNew) and HandleNotifier) then
  246. frmLuaEditMain.AddToNotifier(ExtractFileDir(pTempPrj.Path));
  247. end
  248. else
  249. pPrjNode := pSingleUnitLastNode;
  250. end
  251. else
  252. begin
  253. // Update the node's data
  254. pData := vstProjectTree.GetNodeData(pPrjNode);
  255. pData.pLuaEditFile := pTempPrj;
  256. pData.ActiveProject := (pTempPrj = ActiveProject);
  257. pData.ToKeep := True;
  258. pData.Deleting := False;
  259. // Adding project root to change notifier...
  260. if ((not pTempPrj.IsNew) and HandleNotifier) then
  261. frmLuaEditMain.AddToNotifier(ExtractFileDir(pTempPrj.Path));
  262. end;
  263. for y := 0 to pTempPrj.lstUnits.Count - 1 do
  264. begin
  265. pUnitNode := GetNodeInTree(TLuaEditUnit(pTempPrj.lstUnits.Items[y]), pTempPrj);
  266. if not Assigned(pUnitNode) then
  267. begin
  268. // Adding single unit (projectless) to the tree
  269. if pTempPrj.Name = '[@@SingleUnits@@]' then
  270. begin
  271. if not Assigned(pPrjNode) then
  272. pUnitNode := vstProjectTree.InsertNode(vstProjectTree.RootNode, amInsertBefore)
  273. else
  274. pUnitNode := vstProjectTree.InsertNode(pPrjNode, amInsertAfter);
  275. // Update last single unit node
  276. pSingleUnitLastNode := pUnitNode;
  277. end
  278. else
  279. pUnitNode := vstProjectTree.AddChild(pPrjNode);
  280. // Create the node
  281. pData := vstProjectTree.GetNodeData(pUnitNode);
  282. pData.pLuaEditFile := pTempPrj.lstUnits.Items[y];
  283. pData.ActiveProject := False;
  284. pData.ToKeep := True;
  285. pData.Deleting := False;
  286. // Adding unit root to change notifier...
  287. if ((not TLuaEditUnit(pTempPrj.lstUnits.Items[y]).IsNew) and HandleNotifier) then
  288. frmLuaEditMain.AddToNotifier(ExtractFileDir(TLuaEditUnit(pTempPrj.lstUnits.Items[y]).Path));
  289. // Special handling for gui forms
  290. if pData.pLuaEditFile.FileType = otLuaEditForm then
  291. begin
  292. pDataGUIForm := pData;
  293. pUnitNode := vstProjectTree.AddChild(pUnitNode);
  294. pData := vstProjectTree.GetNodeData(pUnitNode);
  295. pData.pLuaEditFile := TLuaEditGUIForm(pDataGUIForm.pLuaEditFile).LinkedDebugFile;
  296. pData.ActiveProject := False;
  297. pData.ToKeep := True;
  298. pData.Deleting := False;
  299. end;
  300. end
  301. else
  302. begin
  303. // Update the node's data
  304. pData := vstProjectTree.GetNodeData(pUnitNode);
  305. pData.pLuaEditFile := pTempPrj.lstUnits.Items[y];
  306. pData.ActiveProject := False;
  307. pData.ToKeep := True;
  308. pData.Deleting := False;
  309. // Adding unit root to change notifier...
  310. if ((not TLuaEditUnit(pTempPrj.lstUnits.Items[y]).IsNew) and HandleNotifier) then
  311. frmLuaEditMain.AddToNotifier(ExtractFileDir(TLuaEditUnit(pTempPrj.lstUnits.Items[y]).Path));
  312. end;
  313. end;
  314. end;
  315. CleanTree(vstProjectTree);
  316. vstProjectTree.EndUpdate;
  317. // Set back on the changes notifier if required
  318. if ((frmLuaEditMain.jvchnNotifier.Notifications.Count > 0) and HandleNotifier) then
  319. frmLuaEditMain.jvchnNotifier.Active := True;
  320. end;
  321. procedure TfrmProjectTree.UnloadFileProject1Click(Sender: TObject);
  322. var
  323. pLuaPrj: TLuaEditProject;
  324. pFile: TLuaEditBasicTextFile;
  325. Answer, x: Integer;
  326. UnitsToDelete: TList;
  327. pNode: PVirtualNode;
  328. pData: PProjectTreeData;
  329. begin
  330. pNode := vstProjectTree.GetFirstSelected;
  331. if Assigned(pNode) then
  332. begin
  333. pData := vstProjectTree.GetNodeData(pNode);
  334. UnitsToDelete := TList.Create;
  335. // Case where the selected file was a project
  336. if pData.pLuaEditFile.FileType = otLuaEditProject then
  337. begin
  338. pLuaPrj := TLuaEditProject(pData.pLuaEditFile);
  339. // Ssaving any new or modified project's files
  340. for x := 0 to pLuaPrj.lstUnits.Count - 1 do
  341. begin
  342. pFile := TLuaEditBasicTextFile(pLuaPrj.lstUnits.Items[x]);
  343. if ((pFile.HasChanged) or (pFile.IsNew)) then
  344. begin
  345. Answer := Application.MessageBox(PChar('Save changes to unit "'+pFile.Name+'"?'), 'LuaEdit', MB_YESNOCANCEL+MB_ICONQUESTION);
  346. if Answer = IDYES then
  347. begin
  348. if SaveUnitsInc then
  349. pFile.SaveInc(pFile.Path)
  350. else
  351. pFile.Save(pFile.Path);
  352. end
  353. else if Answer = IDCANCEL then
  354. begin
  355. UnitsToDelete.Free;
  356. Exit;
  357. end;
  358. end;
  359. UnitsToDelete.Add(pFile);
  360. end;
  361. // saving any new or modified project
  362. if ((pLuaPrj.HasChanged) or (pLuaPrj.IsNew)) then
  363. begin
  364. Answer := Application.MessageBox(PChar('Save changes to project "'+pLuaPrj.Name+'"?'), 'LuaEdit', MB_YESNOCANCEL+MB_ICONQUESTION);
  365. if Answer = IDYES then
  366. begin
  367. if SaveProjectsInc then
  368. pLuaPrj.SaveInc(pLuaPrj.Path)
  369. else
  370. pLuaPrj.Save(pLuaPrj.Path);
  371. end
  372. else if Answer = IDCANCEL then
  373. begin
  374. UnitsToDelete.Free;
  375. Exit;
  376. end;
  377. end;
  378. end
  379. else if pData.pLuaEditFile.FileType in LuaEditTextFilesTypeSet then
  380. begin
  381. pFile := TLuaEditBasicTextFile(pData.pLuaEditFile);
  382. if pFile.PrjOwner.Name = '[@@SingleUnits@@]' then
  383. begin
  384. if ((pFile.HasChanged) or (pFile.IsNew)) then
  385. begin
  386. Answer := Application.MessageBox(PChar('Save changes to unit "'+pFile.Name+'"?'), 'LuaEdit', MB_YESNOCANCEL+MB_ICONQUESTION);
  387. if Answer = IDYES then
  388. begin
  389. if SaveUnitsInc then
  390. pFile.SaveInc(pFile.Path)
  391. else
  392. pFile.Save(pFile.Path);
  393. end
  394. else if Answer = IDCANCEL then
  395. begin
  396. UnitsToDelete.Free;
  397. Exit;
  398. end;
  399. end;
  400. UnitsToDelete.Add(pFile);
  401. end;
  402. end;
  403. // Free and close units and project
  404. for x := UnitsToDelete.Count - 1 downto 0 do
  405. begin
  406. pFile := TLuaEditBasicTextFile(UnitsToDelete.Items[x]);
  407. if Assigned(pFile.AssociatedTab) then
  408. begin
  409. frmLuaEditMain.jvUnitBar.Tabs.Delete(pFile.AssociatedTab.Index);
  410. pFile.AssociatedTab := nil;
  411. LuaOpenedFiles.Remove(pFile);
  412. end;
  413. pData.Deleting := True;
  414. pFile.PrjOwner.lstUnits.Remove(pFile);
  415. pFile.Free;
  416. end;
  417. if Assigned(pLuaPrj) then
  418. LuaProjects.Remove(pLuaPrj);
  419. if pLuaPrj = ActiveProject then
  420. begin
  421. // Try to find another project to automatically set to the active one
  422. if LuaProjects.Count > 1 then
  423. ActiveProject := LuaProjects.Items[LuaProjects.Count - 1]
  424. else
  425. ActiveProject := nil;
  426. end;
  427. // Initialize stuff...
  428. UnitsToDelete.Free;
  429. BuildProjectTree;
  430. frmLuaEditMain.CheckButtons;
  431. end;
  432. end;
  433. procedure TfrmProjectTree.mnuFindTargetClick(Sender: TObject);
  434. var
  435. pData: PProjectTreeData;
  436. pNode: PVirtualNode;
  437. begin
  438. pNode := vstProjectTree.GetFirstSelected;
  439. if Assigned(pNode) then
  440. begin
  441. pData := vstProjectTree.GetNodeData(pNode);
  442. ShellExecute(Self.Handle, 'explore', PChar(ExtractFileDir(pData.pLuaEditFile.Path)), nil, nil, SW_SHOWMAXIMIZED);
  443. end;
  444. end;
  445. procedure TfrmProjectTree.ppmProjectTreePopup(Sender: TObject);
  446. var
  447. pData: PProjectTreeData;
  448. pNode: PVirtualNode;
  449. begin
  450. frmLuaEditMain.CheckButtons();
  451. pNode := vstProjectTree.GetFirstSelected();
  452. mnuFindTarget.Enabled := Assigned(pNode);
  453. if Assigned(pNode) then
  454. begin
  455. pData := vstProjectTree.GetNodeData(pNode);
  456. mnuFindTarget.Enabled := ((not pData.pLuaEditFile.IsNew) and (FileExistsAbs(pData.pLuaEditFile.Path)));
  457. end;
  458. frmLuaEditMain.DoMainMenuProjectExecute;
  459. end;
  460. procedure TfrmProjectTree.vstProjectTreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
  461. begin
  462. NodeDataSize := SizeOf(TProjectTreeData);
  463. end;
  464. procedure TfrmProjectTree.vstProjectTreeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  465. begin
  466. frmLuaEditMain.CheckButtons;
  467. end;
  468. procedure TfrmProjectTree.vstProjectTreeAfterItemPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
  469. var
  470. pRect: TRect;
  471. begin
  472. pRect := ItemRect;
  473. InflateRect(pRect, 0, 1);
  474. pRect.Right := pRect.Left + 22;
  475. TargetCanvas.Brush.Color := clWhite;
  476. TargetCanvas.FillRect(pRect);
  477. // Draw node button since the noda has some child
  478. if ((Node.Parent = Sender.RootNode) and (Node.ChildCount <> 0)) then
  479. begin
  480. // Draw the frame around the button
  481. TargetCanvas.Pen.Color := clBtnShadow;
  482. TargetCanvas.Rectangle(5, 4, 14, 13);
  483. TargetCanvas.MoveTo(14, 8);
  484. TargetCanvas.LineTo(20, 8);
  485. TargetCanvas.Pen.Color := clBlack;
  486. if not (vsExpanded in Node.States) then
  487. begin
  488. // Draw expandable node button (plus sign)
  489. TargetCanvas.MoveTo(7, 8);
  490. TargetCanvas.LineTo(12, 8);
  491. TargetCanvas.MoveTo(9, 6);
  492. TargetCanvas.LineTo(9, 11);
  493. end
  494. else
  495. begin
  496. // Draw non-expandable node button (minus sign)
  497. TargetCanvas.MoveTo(7, 8);
  498. TargetCanvas.LineTo(12, 8);
  499. end;
  500. end;
  501. end;
  502. procedure TfrmProjectTree.vstProjectTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  503. begin
  504. if Key = VK_DELETE then
  505. if Assigned(vstProjectTree.GetFirstSelected()) then
  506. frmLuaEditMain.DoRemoveFromPrjExecute(TLuaEditFile(vstProjectTree.GetNodeData(vstProjectTree.GetFirstSelected())));
  507. end;
  508. procedure TfrmProjectTree.vstProjectTreeDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
  509. const
  510. Style: array[TImageType] of Cardinal = (0, ILD_MASK);
  511. var
  512. pData: PProjectTreeData;
  513. pRect, pImageRect: TRect;
  514. sCellText: String;
  515. iImageIndex, iOverlayIndex: Integer;
  516. ExtraStyle, ForegroundColor: Cardinal;
  517. bShowImageEnabled: Boolean;
  518. begin
  519. with Sender as TVirtualDrawTree do
  520. begin
  521. pData := Sender.GetNodeData(PaintInfo.Node);
  522. PaintInfo.Canvas.Font.Color := clBlack;
  523. PaintInfo.Canvas.Pen.Color := clBlack;
  524. // Determine text color
  525. if pData.pLuaEditFile.FileType = otLuaEditProject then
  526. begin
  527. // Set bold style on the active project node
  528. if pData.ActiveProject then
  529. PaintInfo.Canvas.Font.Style := [fsBold];
  530. end;
  531. if Sender.Selected[PaintInfo.Node] then
  532. begin
  533. PaintInfo.Canvas.Font.Color := clHighlightText
  534. end
  535. else
  536. begin
  537. // Set disabled color for non-loaded units
  538. if not pData.pLuaEditFile.IsLoaded then
  539. begin
  540. PaintInfo.Canvas.Font.Color := clInactiveCaption;
  541. PaintInfo.Canvas.Pen.Color := clInactiveCaption;
  542. end;
  543. end;
  544. SetBKMode(PaintInfo.Canvas.Handle, TRANSPARENT);
  545. pRect := PaintInfo.ContentRect;
  546. InflateRect(pRect, -TextMargin, 0);
  547. Dec(pRect.Right);
  548. Dec(pRect.Bottom);
  549. case PaintInfo.Column of
  550. 0:
  551. begin
  552. // Determine is loaded image style
  553. if Assigned(pData.pLuaEditFile) then
  554. bShowImageEnabled := pData.pLuaEditFile.IsLoaded
  555. else
  556. bShowImageEnabled := False;
  557. // Get image area
  558. pImageRect := pRect;
  559. // Determine image index
  560. if Sender.Expanded[PaintInfo.Node] then
  561. iImageIndex := pData.OpenIndex
  562. else
  563. iImageIndex := pData.CloseIndex;
  564. // Determine overlay index
  565. if pData.pLuaEditFile.IsNew then
  566. iOverlayIndex := 0
  567. else if not pData.pLuaEditFile.IsLoaded then
  568. iOverlayIndex := 1
  569. else if pData.pLuaEditFile.IsReadOnly then
  570. iOverlayIndex := 2
  571. else if pData.pLuaEditFile.HasChanged then
  572. iOverlayIndex := 3
  573. else
  574. iOverlayIndex := 4;
  575. // Handle cell text
  576. pRect.Left := pRect.Left + SystemImages.Width + 2;
  577. sCellText := pData.pLuaEditFile.Name;
  578. DrawText(PaintInfo.Canvas.Handle, PChar(sCellText), Length(sCellText), pRect, DT_TOP or DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS);
  579. ExtraStyle := ILD_TRANSPARENT or ILD_OVERLAYMASK;// and IndexToOverlayMask(iOverlayIndex + 1);
  580. ForegroundColor := ColorToRGB(PaintInfo.Canvas.Font.Color);
  581. // Draw icon
  582. ImageList_DrawEx(SystemImages.Handle, iImageIndex, PaintInfo.Canvas.Handle, pImageRect.Left, pImageRect.Top, 0, 0, GetRGBColor(SystemImages.BkColor), ForegroundColor, Style[SystemImages.ImageType] or ExtraStyle);
  583. // Draw overlay icon
  584. ImageList_DrawEx(StatesImages.Handle, iOverlayIndex, PaintInfo.Canvas.Handle, pImageRect.Left, pImageRect.Top, 0, 0, GetRGBColor(SystemImages.BkColor), ForegroundColor, Style[SystemImages.ImageType] or ExtraStyle);
  585. end;
  586. 1:
  587. begin
  588. sCellText := pData.pLuaEditFile.DisplayPath;
  589. DrawText(PaintInfo.Canvas.Handle, PChar(sCellText), Length(sCellText), pRect, DT_TOP or DT_LEFT or DT_VCENTER or DT_SINGLELINE or DT_PATH_ELLIPSIS);
  590. end;
  591. end;
  592. end;
  593. end;
  594. procedure TfrmProjectTree.FormCreate(Sender: TObject);
  595. var
  596. SFI: TSHFileInfo;
  597. pBitmap: TBitmap;
  598. pIcon: TIcon;
  599. begin
  600. // Load system images...
  601. SystemImages.Handle := SHGetFileInfo('', 0, SFI, SizeOf(SFI), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  602. SystemImages.ShareImages := True;
  603. try
  604. // Load overlay icons...
  605. pBitmap := TBitmap.Create;
  606. pIcon := TIcon.Create;
  607. pIcon.LoadFromFile(GetLuaEditInstallPath() + '\Graphics\FileIsNew.ico');
  608. StatesImages.AddIcon(pIcon);
  609. pIcon.LoadFromFile(GetLuaEditInstallPath() + '\Graphics\FileNotLoaded.ico');
  610. StatesImages.AddIcon(pIcon);
  611. pIcon.LoadFromFile(GetLuaEditInstallPath() + '\Graphics\FileIsReadOnly.ico');
  612. StatesImages.AddIcon(pIcon);
  613. pIcon.LoadFromFile(GetLuaEditInstallPath() + '\Graphics\FileHasChanged.ico');
  614. StatesImages.AddIcon(pIcon);
  615. pIcon.LoadFromFile(GetLuaEditInstallPath() + '\Graphics\FileIsOK.ico');
  616. StatesImages.AddIcon(pIcon);
  617. finally
  618. FreeAndNil(pBitmap);
  619. FreeAndNil(pIcon);
  620. end;
  621. end;
  622. procedure TfrmProjectTree.vstProjectTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
  623. var
  624. pData: PProjectTreeData;
  625. WinDir: String;
  626. begin
  627. pData := Sender.GetNodeData(Node);
  628. // If the pLuaEditFile member is not initialize at this point, we assume it's a project folder
  629. if not Assigned(pData.pLuaEditFile) then
  630. begin
  631. SetLength(WinDir, GetWindowsDirectory(nil, 0));
  632. GetWindowsDirectory(PChar(WinDir), Length(WinDir));
  633. GetOpenAndClosedIcons(WinDir, pData.OpenIndex, pData.CloseIndex);
  634. end
  635. else
  636. GetOpenAndClosedIcons(pData.pLuaEditFile.Path, pData.OpenIndex, pData.CloseIndex);
  637. end;
  638. procedure TfrmProjectTree.N3Click(Sender: TObject);
  639. var
  640. pNode: PVirtualNode;
  641. pData: PProjectTreeData;
  642. begin
  643. pNode := vstProjectTree.GetFirstSelected();
  644. if Assigned(pNode) then
  645. begin
  646. pData := vstProjectTree.GetNodeData(pNode);
  647. if TLuaEditFile(pData).FileType = otLuaEditProject then
  648. if SaveProjectsInc then
  649. TLuaEditProject(pData).SaveInc(TLuaEditProject(pData).Path)
  650. else
  651. TLuaEditProject(pData).Save(TLuaEditProject(pData).Path)
  652. else
  653. frmLuaEditMain.DoSaveExecute(TLuaEditBasicTextFile(pData));
  654. end;
  655. end;
  656. procedure TfrmProjectTree.SaveAs1Click(Sender: TObject);
  657. var
  658. pNode: PVirtualNode;
  659. pData: PProjectTreeData;
  660. begin
  661. pNode := vstProjectTree.GetFirstSelected();
  662. if Assigned(pNode) then
  663. begin
  664. pData := vstProjectTree.GetNodeData(pNode);
  665. if TLuaEditFile(pData).FileType = otLuaEditProject then
  666. if SaveProjectsInc then
  667. TLuaEditProject(pData).SaveInc(TLuaEditProject(pData).Path, False, True)
  668. else
  669. TLuaEditProject(pData).Save(TLuaEditProject(pData).Path, False, True)
  670. else
  671. frmLuaEditMain.DoSaveAsExecute(TLuaEditBasicTextFile(pData));
  672. end;
  673. end;
  674. end.