ProjectTree.pas 22 KB

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