ReleaseVisualizer.Mod 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. MODULE ReleaseVisualizer;(** AUTHOR "TF"; PURPOSE "Generate module overview poster"; *)
  2. IMPORT
  3. Streams, Modules, KernelLog, Commands, Options, Strings, Files, WMRectangles,
  4. Texts, TextUtilities, Scanner := ReleaseVisualizerScanner, PDF,
  5. WMMessages, WMGraphics, WMGraphicUtilities, WMWindowManager, WMComponents, WMStandardComponents;
  6. CONST
  7. BoxH = 100; VSpace = 20;
  8. BoxW = 200; HSpace = 20;
  9. E = 0; N = 1; W = 2; S = 3;
  10. KeepAwayDist = 5;
  11. TraceSC = FALSE;
  12. DefaultContext = "A2";
  13. TYPE
  14. Import* = POINTER TO RECORD
  15. m* : ModuleInfo;
  16. next* : Import;
  17. END;
  18. ModuleInfo* = OBJECT
  19. VAR
  20. name*, context* : ARRAY 32 OF CHAR;
  21. desc*, file* : Strings.String;
  22. author*, purpose* : Strings.String;
  23. imports* : Import;
  24. linesOfCode : LONGINT;
  25. ok* : BOOLEAN;
  26. maxdepth : LONGINT;
  27. level* : LONGINT;
  28. nofTotalImports* : LONGINT; (* how often the module is imported *)
  29. nofDirectImports* : LONGINT; (* how often the module is imported directly*)
  30. icMod : ModuleInfo;
  31. icDecision : BOOLEAN;
  32. reference* : ANY;
  33. group*, subgroup* : LONGINT;
  34. subsystems* : SET;
  35. PROCEDURE Dump(details : BOOLEAN);
  36. VAR import : Import;
  37. BEGIN
  38. KernelLog.String(name); KernelLog.String(" IN "); KernelLog.String(context); KernelLog.String(": ");
  39. KernelLog.String("D = "); KernelLog.Int(nofDirectImports, 0);
  40. KernelLog.String(", T = "); KernelLog.Int(nofTotalImports, 0);
  41. KernelLog.String(", mD = "); KernelLog.Int(maxdepth, 0);
  42. KernelLog.String(", group = "); KernelLog.Int(group, 0);
  43. KernelLog.String(", sGroup = "); KernelLog.Int(subgroup, 0);
  44. IF details THEN
  45. KernelLog.String(" [");
  46. import := imports;
  47. WHILE (import # NIL) DO
  48. KernelLog.String(import.m.name);
  49. import := import.next;
  50. IF (import # NIL) THEN KernelLog.String(", "); END;
  51. END;
  52. KernelLog.String("]");
  53. END;
  54. KernelLog.Ln;
  55. END Dump;
  56. PROCEDURE &Init(CONST name, context : ARRAY OF CHAR);
  57. BEGIN
  58. ASSERT((name # "") & (context # ""));
  59. COPY(name, SELF.name);
  60. COPY(context, SELF.context);
  61. desc := NIL; file := NIL; author := NIL; purpose := NIL;
  62. imports := NIL;
  63. linesOfCode := 0;
  64. ok := FALSE;
  65. maxdepth := -1;
  66. level := 0;
  67. nofTotalImports := 0; nofDirectImports := 0;
  68. icMod := NIL;
  69. icDecision := FALSE;
  70. reference := NIL;
  71. group := 0; subgroup := 0;
  72. subsystems := {};
  73. END Init;
  74. END ModuleInfo;
  75. ModuleArray* = POINTER TO ARRAY OF ModuleInfo;
  76. ModuleList* = OBJECT
  77. VAR
  78. modules* : ModuleArray;
  79. nofModules* : LONGINT;
  80. errors : BOOLEAN;
  81. s : Scanner.Scanner;
  82. currentModule : ModuleInfo;
  83. currentFile : Files.FileName;
  84. PROCEDURE &Init;
  85. BEGIN
  86. NEW(modules, 128); nofModules := 0;
  87. errors := FALSE;
  88. s := NIL;
  89. currentModule := NIL;
  90. currentFile := "";
  91. END Init;
  92. PROCEDURE Grow;
  93. VAR n : ModuleArray; i : LONGINT;
  94. BEGIN
  95. NEW(n, LEN(modules) * 2);
  96. FOR i := 0 TO nofModules - 1 DO n[i] := modules[i] END;
  97. modules := n;
  98. END Grow;
  99. PROCEDURE CalcNofDirectImports;
  100. VAR import : Import; i : LONGINT;
  101. BEGIN
  102. FOR i := 0 TO nofModules - 1 DO
  103. import := modules[i].imports;
  104. WHILE import # NIL DO
  105. INC(import.m.nofDirectImports);
  106. import := import.next
  107. END
  108. END
  109. END CalcNofDirectImports;
  110. PROCEDURE CalcTotalImports*;
  111. VAR import : Import; i : LONGINT;
  112. BEGIN
  113. CalcNofDirectImports;
  114. FOR i := 0 TO nofModules - 1 DO
  115. import := modules[i].imports;
  116. WHILE import # NIL DO
  117. INC(import.m.nofTotalImports, import.m.nofDirectImports);
  118. import := import.next
  119. END
  120. END
  121. END CalcTotalImports;
  122. PROCEDURE CalcLevels*(maxLevel : LONGINT);
  123. VAR imp : Import; i, j, l, pass : LONGINT; changed : BOOLEAN;
  124. BEGIN
  125. FOR i := 0 TO nofModules - 1 DO
  126. IF modules[i].nofTotalImports = 0 THEN modules[i].level := maxLevel;
  127. ELSE modules[i].level := GetDepth(modules[i]);
  128. END;
  129. END;
  130. changed := TRUE;
  131. pass := 0;
  132. WHILE changed DO
  133. changed := FALSE;
  134. INC(pass);
  135. KernelLog.String("Improving level structure, pass "); KernelLog.Int(pass, 0); KernelLog.Ln;
  136. FOR i := 0 TO nofModules - 1 DO
  137. IF modules[i].nofTotalImports # 0 THEN
  138. l := MAX(LONGINT);
  139. FOR j := 0 TO nofModules - 1 DO
  140. imp := modules[j].imports;
  141. WHILE imp # NIL DO
  142. IF imp.m = modules[i] THEN
  143. l := MIN(l, modules[j].level -1);
  144. END;
  145. imp := imp.next
  146. END
  147. END;
  148. IF modules[i].level # l THEN
  149. modules[i].level := l;
  150. changed := TRUE;
  151. END
  152. END
  153. END;
  154. END
  155. END CalcLevels;
  156. PROCEDURE GetDepth*(m : ModuleInfo) : LONGINT;
  157. VAR imp : Import; d, max : LONGINT;
  158. BEGIN
  159. IF m.maxdepth # -1 THEN RETURN m.maxdepth END;
  160. max := -1;
  161. imp := m.imports;
  162. WHILE imp # NIL DO
  163. d := GetDepth(imp.m);
  164. IF d > max THEN max := d END;
  165. imp := imp.next
  166. END;
  167. m.maxdepth := max + 1;
  168. RETURN m.maxdepth
  169. END GetDepth;
  170. (* directly or indirectly imports *)
  171. PROCEDURE Imports*(m, i : ModuleInfo) : BOOLEAN;
  172. VAR imp : Import;
  173. BEGIN
  174. IF m.icMod = i THEN RETURN m.icDecision END;
  175. imp := m.imports;
  176. WHILE imp # NIL DO
  177. IF (imp.m = i) OR Imports(imp.m, i) THEN
  178. m.icMod := i; m.icDecision := TRUE;
  179. RETURN TRUE
  180. END;
  181. imp := imp.next
  182. END;
  183. m.icMod := i; m.icDecision := FALSE;
  184. RETURN FALSE
  185. END Imports;
  186. PROCEDURE Dump*(details : BOOLEAN);
  187. VAR i : LONGINT;
  188. BEGIN
  189. FOR i := 0 TO nofModules - 1 DO
  190. modules[i].Dump(details);
  191. END;
  192. END Dump;
  193. PROCEDURE GetModule*(CONST name, context : ARRAY OF CHAR) : ModuleInfo;
  194. VAR i : LONGINT;
  195. BEGIN
  196. i := 0; WHILE (i < nofModules) & ((modules[i].name # name) OR (modules[i].context # context)) DO INC(i) END;
  197. IF i < nofModules THEN
  198. RETURN modules[i]
  199. ELSE
  200. IF nofModules >= LEN(modules) - 1 THEN Grow END;
  201. NEW(modules[nofModules], name, context);
  202. INC(nofModules);
  203. RETURN modules[i]
  204. END
  205. END GetModule;
  206. PROCEDURE AddImport*(m : ModuleInfo; CONST importName, context : ARRAY OF CHAR);
  207. VAR il : Import;
  208. BEGIN
  209. IF importName = "SYSTEM" THEN RETURN END;
  210. NEW(il); il.m := GetModule(importName, context);
  211. il.next := m.imports; m.imports := il
  212. END AddImport;
  213. PROCEDURE Error(CONST str : ARRAY OF CHAR);
  214. BEGIN
  215. KernelLog.String(currentFile);
  216. IF (s # NIL) THEN KernelLog.String("@"); KernelLog.Int(s.errpos, 0); END;
  217. KernelLog.String(" : "); KernelLog.String(str); KernelLog.Ln;
  218. errors := TRUE;
  219. END Error;
  220. PROCEDURE Eat(sym : LONGINT);
  221. BEGIN
  222. IF s.sym = sym THEN Next;
  223. ELSE
  224. KernelLog.String(currentFile); KernelLog.String("@"); KernelLog.Int(s.errpos, 0);
  225. KernelLog.String(" : sym = "); KernelLog.Int(sym, 0); KernelLog.String(" expected");
  226. KernelLog.String(", found sym = "); KernelLog.Int(s.sym, 0); KernelLog.Ln;
  227. END
  228. END Eat;
  229. (* add the comment to the currents tructure *)
  230. PROCEDURE CommentToStructure;
  231. VAR
  232. str : Strings.String;
  233. sr : Streams.StringReader;
  234. t : ARRAY 16 OF CHAR;
  235. author : ARRAY 32 OF CHAR;
  236. purpose : ARRAY 1024 OF CHAR;
  237. BEGIN
  238. str := s.commentStr.GetString();
  239. NEW(sr, s.commentStr.GetLength());
  240. sr.Set(str^);
  241. WHILE sr.res = 0 DO
  242. sr.SkipWhitespace;
  243. sr.Token(t);
  244. IF t = "AUTHOR" THEN
  245. sr.SkipWhitespace;
  246. sr.String(author);
  247. currentModule.author := Strings.NewString(author);
  248. END;
  249. IF t = "PURPOSE" THEN
  250. sr.SkipWhitespace;
  251. sr.String(purpose);
  252. currentModule.purpose := Strings.NewString(purpose);
  253. END;
  254. END
  255. END CommentToStructure;
  256. PROCEDURE Next;
  257. BEGIN
  258. s.Next;
  259. WHILE s.sym = Scanner.comment DO
  260. CommentToStructure;
  261. s.Next
  262. END
  263. END Next;
  264. PROCEDURE ParseImports;
  265. VAR modName, context : ARRAY 64 OF CHAR;
  266. BEGIN
  267. WHILE s.sym = Scanner.ident DO
  268. COPY(s.str, modName);
  269. Next;
  270. IF s.sym = Scanner.becomes THEN
  271. Next;
  272. IF s.sym = Scanner.ident THEN
  273. COPY(s.str, modName);
  274. Next;
  275. ELSE
  276. Error("Expected module identifier");
  277. END;
  278. END;
  279. IF (s.sym = Scanner.in) THEN
  280. Next;
  281. IF (s.sym = Scanner.ident) THEN
  282. COPY(s.str, context);
  283. Next;
  284. ELSE
  285. Error("Expected context identifier");
  286. END;
  287. ELSE
  288. COPY(DefaultContext, context);
  289. END;
  290. AddImport(currentModule, modName, context);
  291. IF s.sym = Scanner.comma THEN Next END;
  292. END;
  293. Eat(Scanner.semicolon)
  294. END ParseImports;
  295. PROCEDURE ParseModule;
  296. VAR moduleName, context : ARRAY 64 OF CHAR;
  297. BEGIN
  298. IF s.sym = Scanner.module THEN
  299. Next;
  300. IF s.sym = Scanner.ident THEN
  301. COPY(s.str, moduleName);
  302. Next;
  303. IF s.sym = Scanner.in THEN
  304. Next;
  305. IF s.sym = Scanner.ident THEN
  306. COPY(s.str, context);
  307. Next;
  308. ELSE Error("Context identifier expected");
  309. END;
  310. ELSE
  311. COPY(DefaultContext, context);
  312. END;
  313. currentModule := GetModule(moduleName, context);
  314. ELSE Error("Module identifier expected");
  315. END;
  316. Eat(Scanner.semicolon);
  317. ELSE Error("Module expected")
  318. END;
  319. IF s.sym = Scanner.import THEN
  320. Next;
  321. ParseImports;
  322. END
  323. END ParseModule;
  324. PROCEDURE ScanModule(CONST filename : ARRAY OF CHAR);
  325. VAR text : Texts.Text; format : LONGINT; res: WORD; s : Scanner.Scanner;
  326. BEGIN
  327. COPY(filename, currentFile);
  328. NEW(text);
  329. TextUtilities.LoadAuto(text, filename, format, res);
  330. IF res # 0 THEN
  331. KernelLog.String(filename); KernelLog.String(" not found"); KernelLog.Ln;
  332. RETURN
  333. END;
  334. s := Scanner.InitWithText(text, 0);
  335. SELF.s := s;
  336. Next; (* establish one look ahead *)
  337. currentModule := NIL;
  338. ParseModule;
  339. IF (currentModule # NIL) THEN
  340. currentModule.linesOfCode := CountLines(text);
  341. END;
  342. END ScanModule;
  343. PROCEDURE ScanForModules(CONST filemask : ARRAY OF CHAR; out : Streams.Writer);
  344. VAR enum : Files.Enumerator; name : ARRAY 256 OF CHAR; flags : SET; time, date, size, nofFiles : LONGINT;
  345. BEGIN
  346. IF (out # NIL) THEN out.String("Scanning modules "); out.String(filemask); out.String(" ... "); out.Update; END;
  347. nofModules := 0;
  348. NEW(enum);
  349. enum.Open(filemask, {});
  350. WHILE enum.HasMoreEntries() DO
  351. IF enum.GetEntry(name, flags, time, date, size) & ~(Files.Directory IN flags) THEN
  352. INC(nofFiles);
  353. ScanModule(name)
  354. END
  355. END;
  356. IF (out # NIL) THEN out.Int(nofFiles, 0); out.String(" files found."); out.Ln; out.Update; END;
  357. END ScanForModules;
  358. END ModuleList;
  359. TYPE
  360. KillerMsg = OBJECT
  361. END KillerMsg;
  362. RealRect* = RECORD l*, t*, r*, b* : LONGREAL; END;
  363. Point = RECORD x, y : LONGREAL END;
  364. PointArray = POINTER TO ARRAY OF Point;
  365. Object = OBJECT
  366. VAR
  367. aabb: RealRect;
  368. parent : Object;
  369. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  370. BEGIN
  371. END Draw;
  372. END Object;
  373. ObjectList = POINTER TO ARRAY OF Object;
  374. Graphic = OBJECT (Object)
  375. VAR
  376. list : ObjectList;
  377. nofObj : LONGINT;
  378. PROCEDURE &Init;
  379. BEGIN
  380. NEW(list, 8);
  381. END Init;
  382. PROCEDURE Add(o : Object);
  383. VAR nl : ObjectList; i : LONGINT;
  384. BEGIN
  385. o.parent := SELF;
  386. IF nofObj >= LEN(list) THEN
  387. NEW(nl, LEN(list) * 2);
  388. FOR i := 0 TO LEN(list) - 1 DO nl[i] := list[i] END;
  389. list := nl
  390. END;
  391. list[nofObj] := o;
  392. INC(nofObj)
  393. END Add;
  394. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  395. VAR i : LONGINT;
  396. BEGIN
  397. FOR i := 0 TO nofObj - 1 DO
  398. list[i].Draw(canvas, dx + fx * aabb.l, dy + fy * aabb.t, fx, fy);
  399. END
  400. END Draw;
  401. END Graphic;
  402. Rectangle = OBJECT(Object)
  403. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  404. BEGIN
  405. WMGraphicUtilities.DrawRect(canvas,
  406. WMRectangles.MakeRect(ENTIER(dx + fx * aabb.l), ENTIER(dy + fy * aabb.t),
  407. ENTIER(dx + fx * aabb.r), ENTIER(dy + fy * aabb.b)),
  408. 0FFH, WMGraphics.ModeCopy);
  409. END Draw;
  410. END Rectangle;
  411. Line = OBJECT(Object)
  412. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  413. BEGIN
  414. canvas.Line(ENTIER(dx + fx * aabb.l), ENTIER(dy + fy * aabb.t), ENTIER(dx + fx * aabb.r), ENTIER(dy + fy * aabb.b),
  415. 0FFH, WMGraphics.ModeCopy);
  416. END Draw;
  417. END Line;
  418. Title = OBJECT(Object)
  419. VAR title : ARRAY 100 OF CHAR;
  420. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  421. BEGIN
  422. canvas.SetFont(WMGraphics.GetFont("Vera", ENTIER(75 * fy + 0.5), {}));
  423. IF canvas IS PDF.PDFCanvas THEN canvas(PDF.PDFCanvas).PDFSetFont("Courier", ENTIER(75 * SHORT(fy)), {}) END;
  424. canvas.DrawString(ENTIER(dx + aabb.l * fx), ENTIER(dy + (aabb.t + 75) * fy), title);
  425. END Draw;
  426. END Title;
  427. TYPE
  428. SmartConnector = OBJECT (Object)
  429. VAR
  430. from, to : Object;
  431. way : PointArray;
  432. nofPoints : LONGINT;
  433. a, b : Point;
  434. PROCEDURE &Init;
  435. BEGIN
  436. NEW(way, 150);
  437. END Init;
  438. PROCEDURE SetFromTo(f, t : Object);
  439. BEGIN
  440. from := f;
  441. to := t;
  442. CalcPath
  443. END SetFromTo;
  444. PROCEDURE CalcDirs(p, d : Point; VAR alternate : LONGINT; VAR d0, d1 : LONGREAL) : LONGINT;
  445. VAR l, t : BOOLEAN; dir : LONGINT;
  446. BEGIN
  447. l := p.x > d.x; t := p.y > d.y;
  448. IF ABS(p.x - d.x) > ABS(p.y - d.y) THEN
  449. IF l THEN dir := W ELSE dir := E END;
  450. IF t THEN alternate := N ELSE alternate := S END;
  451. d0 := ABS(p.x - d.x);
  452. d1 := ABS(p.y - d.y);
  453. ELSE
  454. IF t THEN dir := N ELSE dir := S END;
  455. IF l THEN alternate := W ELSE alternate := E END;
  456. d0 := ABS(p.y - d.y);
  457. d1 := ABS(p.x - d.x);
  458. END;
  459. IF d1 < 0.01 THEN d1 := 10; END;
  460. RETURN dir
  461. END CalcDirs;
  462. PROCEDURE HasIntersection(p : Point; d : LONGINT; VAR mdist : LONGREAL; VAR colBox : RealRect) : BOOLEAN;
  463. VAR g : Graphic;
  464. o : Object;
  465. dist : LONGREAL;
  466. inter, first : BOOLEAN;
  467. i : LONGINT;
  468. BEGIN
  469. IF (parent # NIL) & (parent IS Graphic) THEN
  470. g := parent(Graphic);
  471. first := TRUE;
  472. FOR i := 0 TO g.nofObj - 1 DO
  473. o := g.list[i];
  474. IF (o # NIL) & (o IS ModuleBox) THEN
  475. inter := FALSE;
  476. CASE d OF
  477. |E : IF (o.aabb.l > p.x) & (p.y >= o.aabb.t - KeepAwayDist) & (p.y <= o.aabb.b + KeepAwayDist) THEN dist := o.aabb.l - p.x; inter := TRUE END
  478. |N : IF (o.aabb.b < p.y) & (p.x >= o.aabb.l - KeepAwayDist) & (p.x <= o.aabb.r + KeepAwayDist) THEN dist := p.y - o.aabb.b; inter := TRUE END
  479. |W : IF (o.aabb.r < p.x) & (p.y >= o.aabb.t - KeepAwayDist) & (p.y <= o.aabb.b + KeepAwayDist) THEN dist := p.x - o.aabb.r; inter := TRUE END
  480. |S : IF (o.aabb.t > p.y) & (p.x >= o.aabb.l - KeepAwayDist) & (p.x <= o.aabb.r + KeepAwayDist) THEN dist := o.aabb.t - p.y; inter := TRUE END
  481. END;
  482. IF inter THEN
  483. IF first THEN mdist := dist; first := FALSE; colBox := o.aabb;
  484. ELSE
  485. IF dist < mdist THEN
  486. colBox := o.aabb;
  487. mdist := dist
  488. END
  489. END
  490. END
  491. END
  492. END
  493. END;
  494. RETURN ~first
  495. END HasIntersection;
  496. PROCEDURE Go(VAR p : Point; d : LONGINT; dist : LONGREAL);
  497. BEGIN
  498. IF TraceSC THEN KernelLog.String("Going "); END;
  499. CASE d OF
  500. |E : p.x := p.x + dist ;IF TraceSC THEN KernelLog.String("East ") END;
  501. |N : p.y := p.y - dist ;IF TraceSC THEN KernelLog.String("North ") END;
  502. |W : p.x := p.x - dist ;IF TraceSC THEN KernelLog.String("West ") END;
  503. |S : p.y := p.y + dist ;IF TraceSC THEN KernelLog.String("South ") END;
  504. END;
  505. IF TraceSC THEN KernelLog.Int(ENTIER(dist), 0); KernelLog.Ln END;
  506. END Go;
  507. PROCEDURE CalcPath;
  508. VAR p : Point;
  509. d, altd, lc, lastDir : LONGINT;
  510. d0, d1, dist : LONGREAL;
  511. colBox : RealRect;
  512. ta, tb : Point;
  513. rla, rlb : LONGREAL;
  514. BEGIN
  515. a.x := (from.aabb.l + from.aabb.r) / 2; a.y := (from.aabb.t + from.aabb.b) / 2;
  516. b.x := (to.aabb.l + to.aabb.r) / 2; b.y := (to.aabb.t + to.aabb.b) / 2;
  517. IF from IS ModuleBox THEN rla := from(ModuleBox).rellayerpos ELSE rla := 10 END;
  518. IF to IS ModuleBox THEN rlb := to(ModuleBox).rellayerpos ELSE rlb := 10 END;
  519. (* define start and end position *)
  520. d := CalcDirs(a, b, altd, d0, d1);
  521. d := N;
  522. CASE d OF
  523. |E : a.x := from.aabb.r; b.x := to.aabb.l; ta := a; ta.x := ta.x + rla; tb := b; tb.x := tb.x - rlb;
  524. |N : a.y := from.aabb.t; b.y := to.aabb.b; ta := a; ta.y := ta.y - rla; tb := b; tb.y := tb.y + rlb;
  525. |W : a.x := from.aabb.l; b.x := to.aabb.r; ta := a; ta.x := ta.x - rla; tb := b; tb.x := tb.x + rlb;
  526. |S : a.y := from.aabb.b; b.y := to.aabb.t; ta := a; ta.y := ta.y + rla; tb := b; tb.y := tb.y - rlb;
  527. END;
  528. lc := 0;
  529. nofPoints := 0;
  530. way[nofPoints] := a; INC(nofPoints);
  531. way[nofPoints] := ta; INC(nofPoints);
  532. p := ta; lastDir := d;
  533. WHILE (lc < 100) & ((ABS(p.x - tb.x) > 0.001) OR (ABS(p.y - tb.y) > 0.001)) DO
  534. d := CalcDirs(p, tb, altd, d0, d1);
  535. (* never go back *)
  536. IF (lastDir + 2) MOD 4= d THEN d := altd; d0 := d1 END;
  537. IF HasIntersection(p, d, dist, colBox) & (dist < d0) THEN
  538. IF dist - KeepAwayDist > BoxH THEN
  539. Go(p, d, dist - KeepAwayDist);
  540. ELSE
  541. CASE lastDir OF
  542. |W : Go(p, lastDir, p.x - colBox.l + KeepAwayDist + 1);
  543. |N : Go(p, lastDir, p.y - colBox.t + KeepAwayDist + 1);
  544. |E : Go(p, lastDir, colBox.r - p.x + KeepAwayDist + 1);
  545. |S : Go(p, lastDir, colBox.t - p.y + KeepAwayDist + 1);
  546. END;
  547. END
  548. ELSE
  549. Go(p, d, d0);
  550. lastDir := d
  551. END;
  552. IF nofPoints > 140 THEN
  553. p := tb;
  554. KernelLog.String("Failed."); KernelLog.Ln;
  555. END;
  556. way[nofPoints] := p; INC(nofPoints);
  557. INC(lc)
  558. END;
  559. way[nofPoints] := b; INC(nofPoints);
  560. END CalcPath;
  561. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  562. VAR i : LONGINT;
  563. BEGIN
  564. FOR i := 1 TO nofPoints - 1 DO
  565. canvas.Line(ENTIER(dx + fx * way[i - 1].x), ENTIER(dy + fy * way[i - 1].y),
  566. ENTIER(dx + fx * way[i].x), ENTIER(dy + fy * way[i].y), 0FFH, WMGraphics.ModeCopy);
  567. END
  568. END Draw;
  569. END SmartConnector;
  570. ModuleBox = OBJECT(Rectangle)
  571. VAR
  572. name, info : ARRAY 64 OF CHAR;
  573. color : LONGINT;
  574. m : ModuleInfo;
  575. rellayerpos : LONGREAL;
  576. PROCEDURE Draw(canvas : WMGraphics.Canvas; dx, dy, fx, fy : LONGREAL);
  577. VAR
  578. r, rect : WMRectangles.Rectangle;
  579. ty : LONGREAL;
  580. sec : ARRAY 30 OF CHAR;
  581. i, l : LONGINT;
  582. BEGIN
  583. r := WMRectangles.MakeRect(ENTIER(dx + fx * aabb.l), ENTIER(dy + fy * aabb.t),
  584. ENTIER(dx + fx * aabb.r), ENTIER(dy + fy * aabb.b));
  585. canvas.Fill(r, color, WMGraphics.ModeCopy);
  586. Draw^(canvas, dx, dy, fx, fy);
  587. canvas.SetFont(WMGraphics.GetFont("Oberon", ENTIER(15 * fy + 0.5), {WMGraphics.FontBold}));
  588. IF canvas IS PDF.PDFCanvas THEN canvas(PDF.PDFCanvas).PDFSetFont("Courier", ENTIER(12 * SHORT(fy)), {WMGraphics.FontBold}) END;
  589. ty := 15;
  590. canvas.DrawString(ENTIER(r.l + fx), r.t + ENTIER(ty * fy), name);
  591. canvas.Line(r.l, r.t + ENTIER((ty + 3) * fy), r.r, r.t + ENTIER((ty + 3) * fy), 0FFH,WMGraphics.ModeCopy);
  592. ty := ty + 15;
  593. canvas.SetFont(WMGraphics.GetFont("Oberon", ENTIER(15 * fy + 0.5), {}));
  594. IF canvas IS PDF.PDFCanvas THEN canvas(PDF.PDFCanvas).PDFSetFont("Courier", ENTIER(12 * SHORT(fy)), {}) END;
  595. canvas.DrawString(ENTIER(r.l + fx), r.t + ENTIER(ty * fy), info);
  596. ty := ty + 15;
  597. IF m.author # NIL THEN
  598. canvas.DrawString(ENTIER(r.l + fx), r.t + ENTIER(ty * fy), m.author^);
  599. ty := ty + 15
  600. END;
  601. IF m.purpose # NIL THEN
  602. canvas.SetColor(WMGraphics.Black);
  603. rect := WMRectangles.MakeRect(r.l + ENTIER(fx), r.t + ENTIER((ty - 15) * fy), r.r, r.b);
  604. WMGraphics.DrawStringInRect(canvas, rect, TRUE, WMComponents.AlignTop, WMComponents.AlignLeft, m.purpose^);
  605. (* i := 0; l := Strings.Length(m.purpose^);
  606. WHILE i < l DO
  607. Strings.Copy(m.purpose^, i, MIN(25, l - i), sec);
  608. canvas.DrawString(ENTIER(r.l + fx), r.t + ENTIER(ty * fy), sec);
  609. ty := ty + 15;
  610. INC(i, 25)
  611. END *)
  612. END;
  613. END Draw;
  614. END ModuleBox;
  615. DrawSpace = OBJECT(WMComponents.VisualComponent)
  616. VAR
  617. g : Graphic;
  618. dx, dy : LONGREAL;
  619. PROCEDURE &Init*;
  620. BEGIN
  621. Init^;
  622. NEW(g);
  623. END Init;
  624. PROCEDURE XSetPos(dx, dy : LONGREAL);
  625. BEGIN
  626. SELF.dx := dx; SELF.dy := dy;
  627. Invalidate;
  628. END XSetPos;
  629. PROCEDURE Draw*(canvas : WMGraphics.Canvas);
  630. BEGIN
  631. g.Draw(canvas, -dx, -dy, 0.5, 0.5);
  632. END Draw;
  633. END DrawSpace;
  634. SubSystemInfo = RECORD
  635. mn : ARRAY 64 OF CHAR;
  636. m : ModuleInfo;
  637. color : LONGINT;
  638. nr, group : LONGINT;
  639. propagate : BOOLEAN; (* modules that import modules from this subsystem are part of the subsystem? *)
  640. END;
  641. SubSystems = OBJECT
  642. VAR
  643. s : ARRAY 1024 OF SubSystemInfo;
  644. scount, colorTable : ARRAY 64 OF LONGINT;
  645. nofSubSystemInfo : LONGINT;
  646. ml : ModuleList;
  647. PROCEDURE AddSubSystem(nr : LONGINT; CONST baseModule, context : ARRAY OF CHAR; color, group : LONGINT; propagate : BOOLEAN);
  648. BEGIN
  649. COPY(baseModule, s[nr].mn);
  650. s[nofSubSystemInfo].m := ml.GetModule(baseModule, context);
  651. s[nofSubSystemInfo].color := color;
  652. s[nofSubSystemInfo].nr := nr;
  653. s[nofSubSystemInfo].group := group;
  654. s[nofSubSystemInfo].propagate := propagate;
  655. colorTable[nr] := color;
  656. INC(nofSubSystemInfo)
  657. END AddSubSystem;
  658. PROCEDURE GetColor(snr : LONGINT) : LONGINT;
  659. VAR i, res : LONGINT;
  660. BEGIN
  661. res := LONGINT(0FF0000FFH);
  662. FOR i := 0 TO nofSubSystemInfo - 1 DO
  663. IF s[i].nr = snr THEN res := s[i].color END
  664. END;
  665. RETURN res
  666. END GetColor;
  667. PROCEDURE &Init(ml : ModuleList);
  668. CONST
  669. ColorRuntime = LONGINT(0A0A0FFFFH);
  670. ColorUsb = LONGINT(0A0A0A0FFH);
  671. VAR
  672. i, j : LONGINT;
  673. BEGIN
  674. ASSERT(ml # NIL);
  675. SELF.ml := ml;
  676. i := 32; j := 32;
  677. DEC(j); DEC(j);
  678. AddSubSystem(i, "Trace", "A2", LONGINT(ColorRuntime), j, FALSE);
  679. AddSubSystem(i, "Machine", "A2", LONGINT(ColorRuntime), j, FALSE);
  680. AddSubSystem(i, "Heaps", "A2", LONGINT(ColorRuntime), j, FALSE);
  681. AddSubSystem(i, "Modules", "A2", LONGINT(ColorRuntime), j, FALSE);
  682. AddSubSystem(i, "Objects", "A2", LONGINT(ColorRuntime), j, FALSE);
  683. AddSubSystem(i, "Kernel", "A2", LONGINT(ColorRuntime), j, FALSE);
  684. DEC(j); DEC(i);
  685. AddSubSystem(i, "Sound", "A2", 0008080FFH, j, TRUE);
  686. DEC(j); DEC(i);
  687. AddSubSystem(i, "WMPerfMonPlugins", "A2", LONGINT(0FF0000FFH), j, TRUE);
  688. DEC(j); DEC(i);
  689. AddSubSystem(i, "UsbDebug", "A2", LONGINT(ColorUsb), j, TRUE);
  690. AddSubSystem(i, "UsbDriverLoader", "A2", LONGINT(ColorUsb), j, TRUE);
  691. AddSubSystem(i, "Usbdi", "A2", LONGINT(ColorUsb), j, TRUE);
  692. AddSubSystem(i, "UsbHcdi", "A2", LONGINT(ColorUsb), j, TRUE);
  693. AddSubSystem(i, "UsbHidUP", "A2", LONGINT(ColorUsb), j, TRUE);
  694. DEC(j); DEC(i);
  695. AddSubSystem(i, "Bluetooth", "A2", 0000080FFH, j, TRUE);
  696. DEC(j); DEC(i);
  697. AddSubSystem(i, "FoxBasic", "A2", 06060FFFFH, j, TRUE);
  698. AddSubSystem(i, "BitSets", "A2", 06060FFFFH, j, TRUE);
  699. AddSubSystem(i, "Builtins", "A2", 06060FFFFH, j, TRUE);
  700. AddSubSystem(i, "ObjectFile", "A2", 06060FFFFH, j, TRUE);
  701. AddSubSystem(i, "FoxProgTools", "A2", 06060FFFFH, j, TRUE);
  702. DEC(j); DEC(i);
  703. AddSubSystem(i, "StringPool", "A2", 0008000FFH, j, TRUE);
  704. AddSubSystem(i, "PCDebug", "A2", 0008000FFH, j, TRUE);
  705. DEC(j); DEC(i);
  706. AddSubSystem(i, "Network", "A2", LONGINT(0800080FFH), j, TRUE);
  707. DEC(i);
  708. AddSubSystem(i, "WebHTTPServer", "A2", LONGINT(08000C0FFH), j, TRUE);
  709. DEC(j); DEC(i);
  710. AddSubSystem(i, "WindowManager", "A2", LONGINT(0FFFF80FFH), j, TRUE);
  711. AddSubSystem(i, "WMWindowManager", "A2", LONGINT(0FFFF80FFH), j, TRUE);
  712. DEC(i);
  713. AddSubSystem(i, "WMComponents", "A2", LONGINT(0FF8080FFH), j, TRUE);
  714. DEC(i);
  715. AddSubSystem(i, "XMLScanner", "A2", LONGINT(0800080FFH), 0, TRUE);
  716. AddSubSystem(i, "XMLObjects", "A2", LONGINT(0800080FFH), 0, TRUE);
  717. END Init;
  718. PROCEDURE CheckModule(m : ModuleInfo);
  719. VAR i : LONGINT;
  720. BEGIN
  721. ASSERT((m # NIL) & (m.group = 0) & (m.subgroup = 0));
  722. FOR i := 0 TO nofSubSystemInfo - 1 DO
  723. IF s[i].m # NIL THEN
  724. IF (s[i].propagate & ml.Imports(m, s[i].m)) OR (m = s[i].m) THEN
  725. IF m.group = 0 THEN m.group := s[i].group END;
  726. IF m.subgroup = 0 THEN m.subgroup := s[i].nr END;
  727. INCL(m.subsystems, s[i].nr); INC(scount[s[i].nr])
  728. END;
  729. END
  730. END
  731. END CheckModule;
  732. END SubSystems;
  733. ModuleInfoList = POINTER TO ARRAY OF ModuleInfo;
  734. Level = RECORD
  735. n : LONGINT;
  736. m : ModuleInfoList;
  737. groupLength, groupStart : ARRAY 32 OF LONGINT;
  738. (* starting from 0 *)
  739. nofGroups : LONGINT;
  740. groupCounts : ARRAY 32 OF LONGINT;
  741. groupSlots : ARRAY 32 OF LONGINT;
  742. yAdvance : LONGINT;
  743. END;
  744. Window* = OBJECT (WMComponents.FormWindow)
  745. VAR
  746. label: WMStandardComponents.Label;
  747. viewer : DrawSpace;
  748. hScroll, vScroll : WMStandardComponents.Scrollbar;
  749. range : WMRectangles.Rectangle;
  750. ml : ModuleList;
  751. subSystems : SubSystems;
  752. PROCEDURE CreateForm(): WMComponents.VisualComponent;
  753. VAR panel, toolbar : WMStandardComponents.Panel; button : WMStandardComponents.Button;
  754. BEGIN
  755. NEW(panel); panel.bounds.SetExtents(800, 700); panel.fillColor.Set(0FFFFFFFFH); panel.takesFocus.Set(TRUE);
  756. NEW(toolbar); toolbar.fillColor.Set(000FF00FFH); toolbar.bounds.SetHeight(20); toolbar.alignment.Set(WMComponents.AlignTop);
  757. panel.AddContent(toolbar);
  758. NEW(button); button.alignment.Set(WMComponents.AlignLeft); button.caption.SetAOC("PDF");
  759. button.onClick.Add(WritePDF);
  760. toolbar.AddContent(button);
  761. NEW(label); label.bounds.SetHeight(20); label.alignment.Set(WMComponents.AlignTop);
  762. panel.AddContent(label);
  763. NEW(hScroll); hScroll.alignment.Set(WMComponents.AlignBottom); hScroll.vertical.Set(FALSE); panel.AddContent(hScroll);
  764. hScroll.onPositionChanged.Add(ScrollbarsChanged);
  765. NEW(vScroll); vScroll.alignment.Set(WMComponents.AlignRight); panel.AddContent(vScroll);
  766. vScroll.onPositionChanged.Add(ScrollbarsChanged);
  767. NEW(viewer); viewer.alignment.Set(WMComponents.AlignClient); panel.AddContent(viewer);
  768. RETURN panel
  769. END CreateForm;
  770. PROCEDURE &New(ml : ModuleList);
  771. VAR vc : WMComponents.VisualComponent;
  772. BEGIN
  773. ASSERT(ml # NIL);
  774. SELF.ml := ml;
  775. IncCount;
  776. vc := CreateForm();
  777. Init(vc.bounds.GetWidth(), vc.bounds.GetHeight(), FALSE);
  778. SetContent(vc);
  779. WMWindowManager.DefaultAddWindow(SELF);
  780. SetTitle(Strings.NewString("Release Visualizer"));
  781. NEW(subSystems, ml);
  782. Populate;
  783. END New;
  784. PROCEDURE ScrollbarsChanged(sender, data : ANY);
  785. BEGIN
  786. viewer.Acquire;
  787. viewer.XSetPos(hScroll.pos.Get(), vScroll.pos.Get());
  788. viewer.Release;
  789. END ScrollbarsChanged;
  790. PROCEDURE WritePDF(sender, data : ANY);
  791. VAR pdfPage : WMGraphics.Canvas; pdfCreator : PDF.PDFCreator; minf : REAL;
  792. BEGIN
  793. NEW(pdfCreator);
  794. pdfPage := pdfCreator.NewPage(PDF.PageA0, TRUE, PDF.Unitmm100);
  795. viewer.Acquire;
  796. KernelLog.String("Creating PDF structure ... "); KernelLog.Ln;
  797. minf := (pdfPage.limits.r - pdfPage.limits.l) / (range.r - range.l + 100);
  798. IF (pdfPage.limits.b - pdfPage.limits.t) / (range.b - range.t) < minf THEN
  799. minf := (pdfPage.limits.b - pdfPage.limits.t) / (range.b - range.t + 100)
  800. END;
  801. viewer.g.Draw(pdfPage, range.l + 50, range.t + 50, minf, minf);
  802. KernelLog.String("done, store PDF in file Test.pdf ... "); KernelLog.Ln;
  803. viewer.Release;
  804. pdfCreator.Store("Test.pdf");
  805. KernelLog.String("done."); KernelLog.Ln;
  806. END WritePDF;
  807. PROCEDURE Populate;
  808. VAR mb : ModuleBox;
  809. i, j, k : LONGINT;
  810. levels : POINTER TO ARRAY OF Level;
  811. s : ARRAY 10 OF CHAR;
  812. m: ModuleInfo;
  813. maxDepth : LONGINT;
  814. ssStartPos, ms : ARRAY 32 OF LONGINT;
  815. sp : LONGINT;
  816. r : Line;
  817. t : Title;
  818. maxW, lastG, g, gc, y : LONGINT;
  819. maxProb, maxProbGroup, totSlots : LONGINT;
  820. PROCEDURE Compare(m0, m1 : ModuleInfo) : BOOLEAN;
  821. VAR a, b, c : LONGINT;
  822. BEGIN
  823. IF m0.group> m1.group THEN RETURN TRUE
  824. ELSIF m0.group < m1.group THEN RETURN FALSE
  825. END;
  826. IF m0.subgroup> m1.subgroup THEN RETURN TRUE
  827. ELSIF m0.subgroup < m1.subgroup THEN RETURN FALSE
  828. END;
  829. c := 31;
  830. WHILE c > 0 DO
  831. a := c; WHILE (a > 0) & ~(a IN m0.subsystems) DO DEC(a) END;
  832. b :=c; WHILE (b > 0) & ~(b IN m1.subsystems) DO DEC(b) END;
  833. IF a < b THEN RETURN TRUE
  834. ELSIF a > b THEN RETURN FALSE
  835. END;
  836. DEC(c);
  837. END;
  838. RETURN m0.nofDirectImports < m1.nofDirectImports
  839. END Compare;
  840. PROCEDURE QuickSort(data : ModuleInfoList ; lo, hi: LONGINT);
  841. VAR i, j : LONGINT;
  842. t, x : ModuleInfo;
  843. BEGIN
  844. i := lo; j := hi; x := data[(lo+hi) DIV 2];
  845. WHILE (i <= j) DO
  846. WHILE Compare(data[i], x) DO INC(i) END;
  847. WHILE Compare(x, data[j]) DO DEC(j) END;
  848. IF (i <= j) THEN
  849. t := data[i]; data[i] := data[j]; data[j] := t;
  850. INC(i); DEC(j)
  851. END
  852. END;
  853. IF lo < j THEN QuickSort(data, lo, j) END;
  854. IF i < hi THEN QuickSort(data, i, hi) END
  855. END QuickSort;
  856. BEGIN
  857. ASSERT(ml # NIL);
  858. NEW(r);
  859. KernelLog.String("Found "); KernelLog.Int(ml.nofModules, 0); KernelLog.String(" modules."); KernelLog.Ln;
  860. KernelLog.String("Compute imports statistics ... ");
  861. ml.CalcTotalImports;
  862. KernelLog.String("done."); KernelLog.Ln;
  863. (* find max depth used *)
  864. maxDepth := 0;
  865. FOR i := 0 TO ml.nofModules - 1 DO
  866. m := ml.modules[i];
  867. m.reference := NIL;
  868. m.subsystems := {};
  869. subSystems.CheckModule(m);
  870. maxDepth := MAX(maxDepth, ml.GetDepth(m));
  871. END;
  872. INC(maxDepth);
  873. KernelLog.String("Calculating levels ...");
  874. ml.CalcLevels(maxDepth);
  875. KernelLog.String("done."); KernelLog.Ln;
  876. NEW(levels, maxDepth + 1);
  877. (* store the data in the levels *)
  878. FOR i := 0 TO ml.nofModules - 1 DO
  879. m := ml.modules[i];
  880. IF levels[m.level].m = NIL THEN NEW(levels[m.level].m, ml.nofModules) (* worst case *)END;
  881. levels[m.level].m[levels[m.level].n] := m;
  882. INC(levels[m.level].n);
  883. END;
  884. FOR j := 0 TO 31 DO ms[j] := 0 END;
  885. FOR i := 0 TO LEN(levels) - 1 DO
  886. IF levels[i].m # NIL THEN
  887. QuickSort(levels[i].m, 0, levels[i].n - 1);
  888. (* calc members of most important subsystem *)
  889. FOR j := 0 TO 31 DO levels[i].groupLength[j] := 0 END;
  890. lastG := levels[i].m[0].group; g := 0;
  891. FOR j := 0 TO levels[i].n - 1 DO
  892. m := levels[i].m[j];
  893. IF m.group # lastG THEN INC(g); lastG := m.group END;
  894. INC(levels[i].groupCounts[g]);
  895. INC(levels[i].groupLength[m.group]);
  896. END;
  897. levels[i].groupStart[0] := 0;
  898. FOR j := 1 TO 31 DO levels[i].groupStart[j] := levels[i].groupStart[j - 1] + levels[i].groupLength[j - 1] END;
  899. (* calculate max length for each group *)
  900. levels[i].nofGroups := 0;
  901. FOR j := 0 TO 31 DO
  902. ms[j] := MAX(ms[j], levels[i].groupLength[j]);
  903. IF levels[i].groupLength[j] > 0 THEN INC(levels[i].nofGroups) END;
  904. END;
  905. j := 0;
  906. END
  907. END;
  908. (* calc subsystem start pos*)
  909. ssStartPos[0] := 0;
  910. FOR i := 1 TO 31 DO
  911. ssStartPos[i] := ssStartPos[i - 1] + ms[i - 1];
  912. END;
  913. maxW := 40;
  914. (* allocate slots *)
  915. FOR i := 0 TO LEN(levels) - 1 DO
  916. levels[i].yAdvance := 1;
  917. IF levels[i].n < maxW THEN
  918. FOR j := 0 TO levels[i].nofGroups -1 DO levels[i].groupSlots[j] := levels[i].groupCounts[j] END;
  919. ELSE
  920. totSlots := 0;
  921. FOR j := 0 TO levels[i].nofGroups -1 DO
  922. levels[i].groupSlots[j] := MAX(1, levels[i].groupCounts[j] * (maxW DIV 2 (* spare space for leveling out *)) DIV levels[i].n);
  923. INC(totSlots, levels[i].groupSlots[j])
  924. END;
  925. (* level out *)
  926. FOR k := 0 TO maxW - totSlots - 1 DO
  927. (* find worst group *)
  928. maxProb := -1;
  929. FOR j := 0 TO levels[i].nofGroups -1 DO
  930. IF levels[i].groupCounts[j] DIV levels[i].groupSlots[j] > maxProb THEN
  931. maxProbGroup := j; maxProb := levels[i].groupCounts[j] DIV levels[i].groupSlots[j];
  932. END
  933. END;
  934. (* increase slot *)
  935. INC(levels[i].groupSlots[maxProbGroup])
  936. END;
  937. (* calc yAdvance *)
  938. FOR j := 0 TO levels[i].nofGroups -1 DO
  939. levels[i].yAdvance := MAX(levels[i].yAdvance, levels[i].groupCounts[j] DIV levels[i].groupSlots[j] + 1);
  940. END;
  941. END
  942. END;
  943. y := 1;
  944. FOR i := 0 TO LEN(levels) - 1 DO
  945. IF levels[i].n < maxW THEN sp := (maxW - levels[i].n) DIV 2 ELSE sp := 0 END;
  946. IF levels[i].m # NIL THEN
  947. g := 0; lastG := levels[i].m[0].group; gc := 0;
  948. FOR j := 0 TO levels[i].n - 1 DO
  949. m := levels[i].m[j];
  950. IF m.group # lastG THEN
  951. sp := sp + levels[i].groupSlots[g];
  952. INC(g); lastG := m.group; gc := 0
  953. END;
  954. NEW(mb);
  955. mb.color := subSystems.GetColor(m.subgroup);
  956. mb.aabb.l := (sp + gc MOD levels[i].groupSlots[g])* (BoxW + HSpace) ; mb.aabb.r := mb.aabb.l + BoxW;
  957. mb.aabb.t := (y + gc DIV levels[i].groupSlots[g]) * (BoxH + VSpace); mb.aabb.b := mb.aabb.t + BoxH;
  958. mb.rellayerpos := (VSpace - 5) - (j / levels[i].n) * (VSpace / 2);
  959. range.l := MIN(range.l, ENTIER(mb.aabb.l));
  960. range.t:= MIN(range.t, ENTIER(mb.aabb.t));
  961. range.r := MAX(range.r, ENTIER(mb.aabb.r));
  962. range.b := MAX(range.b, ENTIER(mb.aabb.b));
  963. IF m.file # NIL THEN COPY(m.file^, mb.name);
  964. ELSE COPY(m.name, mb.name);
  965. END;
  966. m.reference := mb;
  967. mb.m := m;
  968. Strings.Append(mb.info, "Imports: ");
  969. Strings.IntToStr(m.nofTotalImports, s); Strings.Append(mb.info, s); Strings.Append(mb.info, "/");
  970. Strings.IntToStr(m.nofDirectImports, s); Strings.Append(mb.info,s);
  971. Strings.IntToStr(m.linesOfCode, s); Strings.Append(mb.info, " LOC: "); Strings.Append(mb.info, s);
  972. viewer.Acquire;
  973. viewer.g.Add(mb);
  974. viewer.Release;
  975. INC(gc)
  976. END;
  977. INC(y, levels[i].yAdvance);
  978. NEW(r); r.aabb.l := 0; r.aabb.r := maxW * (BoxW + HSpace);
  979. r.aabb.t := y * (BoxH + HSpace) - HSpace DIV 2;
  980. r.aabb.b := y * (BoxH + HSpace) - HSpace DIV 2;
  981. viewer.Acquire;
  982. viewer.g.Add(r);
  983. viewer.Release;
  984. END
  985. END;
  986. NEW(t);
  987. t.aabb.l := (range.l + range.r) DIV 2 - 50;
  988. t.aabb.t := range.t;
  989. t.title := "A2 Release Modules";
  990. viewer.Acquire;
  991. viewer.g.Add(t);
  992. viewer.Release;
  993. (* links *)
  994. (* NEW(sl);
  995. viewer.Acquire;
  996. viewer.g.Add(sl);
  997. m := ml.GetModule("PET");
  998. m1 := ml.GetModule("AosFS");
  999. sl.SetFromTo(m.reference(ModuleBox), m1.reference(ModuleBox));
  1000. viewer.Release; *)
  1001. (* count := 0;
  1002. FOR i := 0 TO ml.nofModules - 1 DO
  1003. m := ml.modules[i];
  1004. IF m.reference # NIL THEN
  1005. imp := m.imports;
  1006. WHILE imp # NIL DO
  1007. IF imp.m.reference # NIL THEN
  1008. NEW(sl);
  1009. viewer.Acquire;
  1010. viewer.g.Add(sl);
  1011. INC(count);
  1012. sl.SetFromTo(m.reference(ModuleBox), imp.m.reference(ModuleBox));
  1013. viewer.Release;
  1014. END;
  1015. imp := imp.next
  1016. END
  1017. END
  1018. END;
  1019. KernelLog.String("count = "); KernelLog.Int(count, 0); KernelLog.Ln; *)
  1020. hScroll.min.Set(range.l);
  1021. vScroll.min.Set(range.t);
  1022. hScroll.max.Set(range.r);
  1023. vScroll.max.Set(range.b);
  1024. viewer.Invalidate
  1025. END Populate;
  1026. PROCEDURE Close*;
  1027. BEGIN
  1028. DecCount;
  1029. Close^;
  1030. END Close;
  1031. PROCEDURE Handle*(VAR x: WMMessages.Message);
  1032. BEGIN
  1033. IF (x.msgType = WMMessages.MsgExt) & (x.ext # NIL) & (x.ext IS KillerMsg) THEN Close
  1034. ELSE Handle^(x)
  1035. END
  1036. END Handle;
  1037. END Window;
  1038. VAR
  1039. nofWindows : LONGINT;
  1040. PROCEDURE CountLines(text : Texts.Text) : LONGINT;
  1041. VAR reader : Texts.TextReader; char32 : Texts.Char32; nofLines : LONGINT;
  1042. BEGIN
  1043. ASSERT(text # NIL);
  1044. NEW(reader, text);
  1045. text.AcquireRead;
  1046. nofLines := 1;
  1047. REPEAT
  1048. reader.ReadCh(char32);
  1049. IF (char32 = Texts.NewLineChar) THEN INC(nofLines); END;
  1050. UNTIL reader.eot;
  1051. text.ReleaseRead;
  1052. RETURN nofLines;
  1053. END CountLines;
  1054. PROCEDURE Open*(context : Commands.Context); (** [Options] [filemask] ~ *)
  1055. VAR options : Options.Options; filemask : Files.FileName; moduleList : ModuleList; window : Window;
  1056. BEGIN
  1057. NEW(options);
  1058. options.Add("t", "trace", Options.Flag);
  1059. IF options.Parse(context.arg, context.error) THEN
  1060. filemask := "";
  1061. IF ~context.arg.GetString(filemask) THEN COPY("*.Mod", filemask); END;
  1062. NEW(moduleList);
  1063. moduleList.ScanForModules(filemask, context.out);
  1064. NEW(window, moduleList);
  1065. IF options.GetFlag("trace") THEN
  1066. moduleList.Dump(TRUE);
  1067. END;
  1068. END;
  1069. END Open;
  1070. PROCEDURE IncCount;
  1071. BEGIN {EXCLUSIVE}
  1072. INC(nofWindows);
  1073. END IncCount;
  1074. PROCEDURE DecCount;
  1075. BEGIN {EXCLUSIVE}
  1076. DEC(nofWindows);
  1077. END DecCount;
  1078. PROCEDURE Cleanup;
  1079. VAR die : KillerMsg;
  1080. msg : WMMessages.Message;
  1081. m : WMWindowManager.WindowManager;
  1082. BEGIN {EXCLUSIVE}
  1083. NEW(die); msg.ext := die; msg.msgType := WMMessages.MsgExt;
  1084. m := WMWindowManager.GetDefaultManager();
  1085. m.Broadcast(msg);
  1086. AWAIT(nofWindows = 0)
  1087. END Cleanup;
  1088. BEGIN
  1089. Modules.InstallTermHandler(Cleanup)
  1090. END ReleaseVisualizer.
  1091. System.Free ReleaseVisualizer ~
  1092. ReleaseVisualizerScan ~
  1093. ReleaseVisualizer.Open ~
  1094. ReleaseVisualizer.Open ../TestA2/*.Mod ~
  1095. ReleaseVisualizer.Open --trace ../TestA2/*.Mod ~