sortdemo.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. PROGRAM SortDemo;
  2. { Graphical demonstration of sorting algorithms (W. N~ker, 02/96) }
  3. { based on "Sortieren" of Purity #48 }
  4. {
  5. Translated to PCQ from Kick(Maxon) Pascal.
  6. Updated the source to 2.0+.
  7. Now uses GadTools for menus.
  8. Added CloseWindowSafely.
  9. Cleaned up the menuhandling.
  10. Added LockWinSize and RestoreWin, now the
  11. window will be locked on showtime.
  12. The German text was translated to English
  13. by Andreas Neumann, thanks Andreas.
  14. Jun 03 1998.
  15. Translated to FPC Pascal.
  16. Removed CloseWindowSafely, have do add
  17. that procedure to Intuition.
  18. Fixed a bug, when you halt the show the
  19. window stayed locked.
  20. Aug 23 1998.
  21. [email protected]
  22. One last remark, the heapsort can't be stoped
  23. so you have to wait until it's finished.
  24. }
  25. uses Exec, Intuition, Graphics, Utility, GadTools;
  26. {$I tagutils.inc}
  27. CONST version : PChar = '$VER: SortDemo 1.3 (23-Aug-98)';
  28. nmax=2000;
  29. MinWinX = 80;
  30. MinWiny = 80;
  31. w : pWindow = Nil;
  32. s : pScreen = Nil;
  33. MenuStrip : pMenu = Nil;
  34. vi : Pointer = Nil;
  35. ltrue : longint = -1;
  36. modenames : Array[0..7] of string[10] = (
  37. 'Heapsort',
  38. 'Shellsort',
  39. 'Pick out',
  40. 'Insert',
  41. 'Shakersort',
  42. 'Bubblesort',
  43. 'Quicksort',
  44. 'Mergesort');
  45. { The easiest way to use gadtoolsmenus in FPC is
  46. to have them as const types. No need to cast
  47. strings to PChar. That we have to use recordmembers
  48. name is a pain.
  49. }
  50. nm : array[0..21] of tNewMenu = (
  51. (nm_Type: NM_TITLE; nm_Label: 'Demo'; nm_CommKey: NIL; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  52. (nm_Type: NM_ITEM; nm_Label: 'Start'; nm_CommKey: 'S'; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  53. (nm_Type: NM_ITEM; nm_Label: 'Stop'; nm_CommKey: 'H'; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  54. { this will be a barlabel, have to set this one later }
  55. (nm_Type: NM_ITEM; nm_Label: NIL; nm_CommKey: NIL; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  56. (nm_Type: NM_ITEM; nm_Label: 'Quit'; nm_CommKey: 'Q'; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  57. (nm_Type: NM_TITLE; nm_Label: 'Algorithm'; nm_CommKey: NIL; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  58. (nm_Type: NM_ITEM; nm_Label: 'HeapSort'; nm_CommKey: '1'; nm_Flags: CHECKIT+CHECKED+MENUTOGGLE; nm_MutualExclude: 254; nm_UserData: NIL),
  59. (nm_Type: NM_ITEM; nm_Label: 'ShellSort'; nm_CommKey: '2'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 253; nm_UserData: NIL),
  60. (nm_Type: NM_ITEM; nm_Label: 'Pick out'; nm_CommKey: '3'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 251; nm_UserData: NIL),
  61. (nm_Type: NM_ITEM; nm_Label: 'Insert'; nm_CommKey: '4'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 247; nm_UserData: NIL),
  62. (nm_Type: NM_ITEM; nm_Label: 'ShakerSort'; nm_CommKey: '5'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 239; nm_UserData: NIL),
  63. (nm_Type: NM_ITEM; nm_Label: 'BubbleSort'; nm_CommKey: '6'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 223; nm_UserData: NIL),
  64. (nm_Type: NM_ITEM; nm_Label: 'QuickSort'; nm_CommKey: '7'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 191; nm_UserData: NIL),
  65. (nm_Type: NM_ITEM; nm_Label: 'MergeSort'; nm_CommKey: '8'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 127; nm_UserData: NIL),
  66. (nm_Type: NM_TITLE; nm_Label: 'Preferences'; nm_CommKey: NIL; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  67. (nm_Type: NM_ITEM; nm_Label: 'Data'; nm_CommKey: NIL; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  68. (nm_Type: NM_SUB; nm_Label: 'Random'; nm_CommKey: 'R'; nm_Flags: CHECKIT+CHECKED+MENUTOGGLE; nm_MutualExclude: 2; nm_UserData: NIL),
  69. (nm_Type: NM_SUB; nm_Label: 'Malicious'; nm_CommKey: 'M'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 1; nm_UserData: NIL),
  70. (nm_Type: NM_ITEM; nm_Label: 'Diagram'; nm_CommKey: NIL; nm_Flags: 0; nm_MutualExclude: 0; nm_UserData: NIL),
  71. (nm_Type: NM_SUB; nm_Label: 'Needles'; nm_CommKey: 'N'; nm_Flags: CHECKIT+CHECKED+MENUTOGGLE; nm_MutualExclude: 2; nm_UserData: NIL),
  72. (nm_Type: NM_SUB; nm_Label: 'Dots'; nm_CommKey: 'D'; nm_Flags: CHECKIT+MENUTOGGLE; nm_MutualExclude: 1; nm_UserData: NIL),
  73. (nm_Type: NM_END; nm_Label: NIL; nm_CommKey: NIL; nm_Flags: 0;nm_MutualExclude:0;nm_UserData:NIL));
  74. VAR sort: ARRAY[1..nmax] OF Real;
  75. sort2: ARRAY[1..nmax] OF Real; { for dumb Mergesort %-( }
  76. num,range,modus : Integer;
  77. rndom,needles : Boolean;
  78. Rast : pRastPort;
  79. QuitStopDie : Boolean;
  80. Msg : pMessage;
  81. wintitle : string[80];
  82. scrtitle : string[80];
  83. tags : array[1..18] of tTagItem;
  84. Procedure CleanUp(s : string; err : Integer);
  85. begin
  86. if MenuStrip <> nil then begin
  87. ClearMenuStrip(w);
  88. FreeMenus(MenuStrip);
  89. end;
  90. if vi <> nil then FreeVisualInfo(vi);
  91. if w <> nil then CloseWindow(w);
  92. if GfxBase <> nil then CloseLibrary(GfxBase);
  93. if GadToolsBase <> nil then CloseLibrary(GadToolsBase);
  94. if s <> '' then writeln(s);
  95. Halt(err);
  96. end;
  97. Procedure RestoreWin;
  98. var
  99. dummy : Boolean;
  100. begin
  101. dummy := WindowLimits(w,MinWinX,MinWinY,-1,-1);
  102. end;
  103. Procedure LockWinSize(x,y,x2,y2 : Integer);
  104. var
  105. dummy : Boolean;
  106. begin
  107. dummy := WindowLimits(w,x,y,x2,y2);
  108. end;
  109. FUNCTION cancel: Boolean;
  110. { checked while sorting }
  111. VAR m,i,s: Integer;
  112. result : boolean;
  113. IM : pIntuiMessage;
  114. BEGIN
  115. result := False;
  116. IM := pIntuiMessage(GetMsg(w^.UserPort));
  117. IF IM<>Nil THEN BEGIN
  118. IF IM^.IClass=IDCMP_CLOSEWINDOW THEN
  119. result := True; { Close-Gadget }
  120. IF IM^.IClass=IDCMP_MENUPICK THEN BEGIN
  121. m := IM^.Code AND $1F;
  122. i := (IM^.Code SHR 5) AND $3F;
  123. s := (IM^.Code SHR 11) AND $1F;
  124. IF (m=0) AND (i=1) THEN result := True; { Menu item "Stop" }
  125. END;
  126. ReplyMsg(pMessage(Msg));
  127. END;
  128. cancel := result;
  129. END;
  130. PROCEDURE showstack(size: Integer);
  131. { little diagram showing the depth of Quicksort's recursion :-) }
  132. BEGIN
  133. SetAPen(Rast,2); IF size>0 THEN RectFill(Rast,0,0,3,size-1);
  134. SetAPen(Rast,0); RectFill(Rast,0,size,3,size);
  135. END;
  136. PROCEDURE setpixel(i: Integer);
  137. BEGIN
  138. SetAPen(Rast,1);
  139. IF needles THEN BEGIN
  140. Move(Rast,i,range); Draw(Rast,i,Round((1-sort[i])*range));
  141. END ELSE
  142. IF WritePixel(Rast,i,Round((1-sort[i])*range))=0 THEN;
  143. END;
  144. PROCEDURE clearpixel(i: Integer);
  145. BEGIN
  146. SetAPen(Rast,0);
  147. IF needles THEN BEGIN
  148. Move(Rast,i,range); Draw(Rast,i,Round((1-sort[i])*range));
  149. END ELSE
  150. IF WritePixel(Rast,i,Round((1-sort[i])*range))=0 THEN;
  151. END;
  152. procedure Exchange(var first,second : real);
  153. var
  154. temp : real;
  155. begin
  156. temp := first;
  157. first := second;
  158. second := temp;
  159. end;
  160. PROCEDURE swapit(i,j: integer);
  161. BEGIN
  162. clearpixel(i); clearpixel(j);
  163. Exchange(sort[i],sort[j]);
  164. setpixel(i); setpixel(j);
  165. END;
  166. FUNCTION descending(i,j: Integer): Boolean;
  167. BEGIN
  168. descending := sort[i]>sort[j];
  169. END;
  170. Function IntToStr (I : Longint) : String;
  171. Var S : String;
  172. begin
  173. Str (I,S);
  174. IntToStr:=S;
  175. end;
  176. PROCEDURE settitles(time: Longint);
  177. VAR
  178. s : string[80];
  179. BEGIN
  180. s := modenames[modus];
  181. IF time=0 THEN
  182. wintitle := s + ' running ...'
  183. ELSE IF time < 0 then
  184. wintitle := '<- ' + IntToStr(num) + ' Data ->'
  185. ELSE
  186. wintitle := IntToStr(time) + ' Seconds';
  187. scrtitle := strpas(@version[6]) + ' - ' + s;
  188. wintitle := wintitle + #0;
  189. scrtitle := scrtitle + #0;
  190. SetWindowTitles(w,@wintitle[1],@scrtitle[1]);
  191. END;
  192. PROCEDURE refresh;
  193. { react on new size of window/init data }
  194. VAR i: Integer;
  195. BEGIN
  196. num := w^.GZZWidth; IF num>nmax THEN num := nmax;
  197. range := w^.GZZHeight;
  198. settitles(-1);
  199. SetRast(Rast,0); { clear screen }
  200. FOR i := 1 TO num DO BEGIN
  201. IF rndom THEN sort[i] := Random { produces 0..1 }
  202. ELSE sort[i] := (num-i)/num;
  203. setpixel(i);
  204. END;
  205. END;
  206. { *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* }
  207. { *#*#*#*#*#*#*#*#*#*#*# The sorting algorithms! #*#*#*#*#*#*#*#*#*#*#*#* }
  208. { *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* }
  209. PROCEDURE bubblesort;
  210. { like the head of a beer, reaaal slow and easy-going }
  211. VAR i,j,max: Integer;
  212. BEGIN
  213. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  214. max := num;
  215. REPEAT
  216. j := 1;
  217. FOR i := 1 TO max-1 DO
  218. IF descending(i,i+1) THEN BEGIN
  219. swapit(i,i+1); j := i;
  220. END;
  221. max := j;
  222. UNTIL (max=1) OR cancel;
  223. RestoreWin;
  224. END;
  225. PROCEDURE shakersort;
  226. { interesting variant, but bubblesort still remains hopelessness }
  227. { (because it only compares and swaps immediate adjacent units) }
  228. VAR i,j,min,max: Integer;
  229. BEGIN
  230. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  231. min := 1;
  232. max := num;
  233. REPEAT
  234. j := min;
  235. FOR i := min TO max-1 DO
  236. IF descending(i,i+1) THEN BEGIN
  237. swapit(i,i+1); j := i;
  238. END;
  239. max := j;
  240. j := max;
  241. FOR i := max DOWNTO min+1 DO
  242. IF descending(i-1,i) THEN BEGIN
  243. swapit(i,i-1); j := i;
  244. END;
  245. min := j;
  246. UNTIL (max=min) OR cancel;
  247. RestoreWin;
  248. END;
  249. PROCEDURE e_sort;
  250. { Insert: a pretty human strategy }
  251. VAR i,j: Integer;
  252. BEGIN
  253. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  254. FOR i := 2 TO num DO BEGIN
  255. j := i;
  256. WHILE j>1 DO
  257. IF descending(j-1,j) THEN BEGIN
  258. swapit(j-1,j); Dec(j);
  259. END ELSE
  260. j := 1;
  261. IF cancel THEN begin
  262. RestoreWin;
  263. Exit;
  264. end;
  265. END;
  266. RestoreWin;
  267. END;
  268. PROCEDURE a_sort;
  269. { Pick out: Preparation is one half of a life }
  270. { Take a look at the ridiculous low percentage of successful comparisions: }
  271. { Although there are only n swaps, there are n^2/2 comparisions! }
  272. { Both is a record, one in a good sense, the other one in a bad sense. }
  273. VAR i,j,minpos: Integer;
  274. min: Real;
  275. BEGIN
  276. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  277. FOR i := 1 TO num-1 DO BEGIN
  278. minpos := i; min := sort[i];
  279. FOR j := i+1 TO num DO
  280. IF descending(minpos,j) THEN
  281. minpos := j;
  282. IF minpos<>i THEN swapit(i,minpos);
  283. IF cancel THEN begin
  284. RestoreWin;
  285. Exit;
  286. end;
  287. END;
  288. RestoreWin;
  289. END;
  290. PROCEDURE shellsort;
  291. { brilliant extension of E-Sort, stunning improvement of efficience }
  292. VAR i,j,gap: Integer;
  293. BEGIN
  294. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  295. gap := num DIV 2;
  296. REPEAT
  297. FOR i := 1+gap TO num DO BEGIN
  298. j := i;
  299. WHILE j>gap DO
  300. IF descending(j-gap,j) THEN BEGIN
  301. swapit(j,j-gap); j := j-gap;
  302. END ELSE
  303. j := 1;
  304. IF cancel THEN begin
  305. RestoreWin;
  306. Exit;
  307. end;
  308. END;
  309. gap := gap DIV 2;
  310. UNTIL gap=0;
  311. RestoreWin;
  312. END;
  313. PROCEDURE seepaway(i,max: Integer);
  314. { belongs to heapsort }
  315. VAR j: Integer;
  316. BEGIN
  317. j := 2*i;
  318. WHILE j<=max DO BEGIN
  319. IF j<max THEN IF descending(j+1,j) THEN
  320. Inc(j);
  321. IF descending(j,i) THEN BEGIN
  322. swapit(j,i);
  323. i := j; j := 2*i;
  324. END ELSE
  325. j := max+1; { cancels }
  326. END;
  327. END;
  328. PROCEDURE heapsort;
  329. { this genius rules over the chaos: it's the best algorithm, I know about }
  330. { The only disadvantage compared with shellsort: it's not easy to understand }
  331. { and impossible to know it by heart. }
  332. VAR i,j: Integer;
  333. BEGIN
  334. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  335. i := num DIV 2 + 1;
  336. j := num;
  337. WHILE i>1 DO BEGIN
  338. Dec(i); seepaway(i,j);
  339. END;
  340. WHILE j>1 DO BEGIN
  341. swapit(i,j);
  342. Dec(j); seepaway(i,j);
  343. END;
  344. RestoreWin;
  345. END;
  346. PROCEDURE quicksort;
  347. { "divide and rule": a classic, but recursive >>-( }
  348. { In this demonstration it is faster than heapsort, but does considerable }
  349. { more unsuccessful comparisions. }
  350. VAR stack: ARRAY[1..100] OF RECORD li,re: Integer; END;
  351. sp,l,r,m,i,j: Integer;
  352. BEGIN
  353. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  354. sp := 1; stack[1].li := 1; stack[1].re := num;
  355. REPEAT
  356. l := stack[sp].li; r := stack[sp].re; Dec(sp);
  357. showstack(sp);
  358. m := (l+r) DIV 2;
  359. i := l; j := r;
  360. REPEAT
  361. WHILE descending(m,i) DO Inc(i);
  362. WHILE descending(j,m) DO Dec(j);
  363. IF j>i THEN swapit(i,j);
  364. IF m=i THEN m := j ELSE IF m=j THEN m := i; { ahem ... }
  365. { This "Following" of the reference data is only required because }
  366. { I stubborn call the comparision function, and this one only gets }
  367. { indices on the values which have to be compared. }
  368. UNTIL i>=j;
  369. IF i>l THEN BEGIN
  370. Inc(sp); stack[sp].li := l; stack[sp].re := i; END;
  371. IF i+1<r THEN BEGIN
  372. Inc(sp); stack[sp].li := i+1; stack[sp].re := r; END;
  373. UNTIL (sp=0) OR cancel;
  374. RestoreWin;
  375. END;
  376. PROCEDURE mergesort;
  377. { *the* algorithm for lists with pointers on it, for arrays rather }
  378. { inacceptable. The non.recursive implementation came out pretty more }
  379. { complicated than the one for quicksort, as quicksort first does }
  380. { something and then recurses; with mergesort it is the other way round. }
  381. VAR stack: ARRAY[1..100] OF RECORD li,re,mi: Integer; END;
  382. sp,l,r,i,j,k,m: Integer;
  383. BEGIN
  384. LockWinSize(w^.Width,w^.Height,w^.Width,w^.Height);
  385. sp := 1; stack[1].li := 1; stack[1].re := num; stack[1].mi := 0;
  386. REPEAT
  387. l := stack[sp].li; r := stack[sp].re; m := stack[sp].mi; Dec(sp);
  388. showstack(sp);
  389. IF m>0 THEN BEGIN { put two halfs together }
  390. { Unfortunately it is only possible in an efficient way by using }
  391. { extra memory; mergesort really is something for lists with }
  392. { pointers originally ... }
  393. FOR i := m DOWNTO l do sort2[i] := sort[i]; i := l;
  394. FOR j := m+1 TO r DO sort2[r+m+1-j] := sort[j]; j := r;
  395. FOR k := l TO r DO BEGIN
  396. clearpixel(k);
  397. IF sort2[i]<sort2[j] THEN BEGIN
  398. sort[k] := sort2[i]; Inc(i);
  399. END ELSE BEGIN
  400. sort[k] := sort2[j]; Dec(j);
  401. END;
  402. setpixel(k);
  403. END;
  404. END ELSE IF l<r THEN BEGIN
  405. { create two halfs and the order to put them together }
  406. m := (l+r) DIV 2;
  407. Inc(sp); stack[sp].li := l; stack[sp].mi := m; stack[sp].re := r;
  408. Inc(sp); stack[sp].li := m+1; stack[sp].mi := 0; stack[sp].re := r;
  409. Inc(sp); stack[sp].li := l; stack[sp].mi := 0; stack[sp].re := m;
  410. END;
  411. UNTIL (sp=0) OR cancel;
  412. RestoreWin;
  413. END;
  414. Procedure OpenEverything;
  415. begin
  416. GadToolsBase := OpenLibrary(PChar('gadtools.library'#0),37);
  417. if GadToolsBase = nil then CleanUp('Can''t open gadtools.library',20);
  418. GfxBase := OpenLibrary(GRAPHICSNAME,37);
  419. if GfxBase = nil then CleanUp('Can''t open graphics.library',20);
  420. s := LockPubScreen(nil);
  421. if s = nil then CleanUp('Could not lock pubscreen',10);
  422. vi := GetVisualInfoA(s, NIL);
  423. if vi = nil then CleanUp('No visual info',10);
  424. tags[1] := TagItem(WA_IDCMP, IDCMP_CLOSEWINDOW or IDCMP_MENUPICK or IDCMP_NEWSIZE);
  425. tags[2] := TagItem(WA_Left, 0);
  426. tags[3] := TagItem(WA_Top, s^.BarHeight+1);
  427. tags[4] := TagItem(WA_Width, 224);
  428. tags[5] := TagItem(WA_Height, s^.Height-(s^.BarHeight-1));
  429. tags[6] := TagItem(WA_MinWidth, MinWinX);
  430. tags[7] := TagItem(WA_MinHeight, MinWinY);
  431. tags[8] := TagItem(WA_MaxWidth, -1);
  432. tags[9] := TagItem(WA_MaxHeight, -1);
  433. tags[10] := TagItem(WA_DepthGadget, ltrue);
  434. tags[11] := TagItem(WA_DragBar, ltrue);
  435. tags[12] := TagItem(WA_CloseGadget, ltrue);
  436. tags[13] := TagItem(WA_SizeGadget, ltrue);
  437. tags[14] := TagItem(WA_Activate, ltrue);
  438. tags[15] := TagItem(WA_SizeBRight, ltrue);
  439. tags[16] := TagItem(WA_GimmeZeroZero, ltrue);
  440. tags[17] := TagItem(WA_PubScreen, longint(s));
  441. tags[18].ti_Tag := TAG_END;
  442. w := OpenWindowTagList(NIL, @tags[1]);
  443. IF w=NIL THEN CleanUp('Could not open window',20);
  444. Rast := w^.RPort;
  445. { Here we set the barlabel }
  446. nm[3].nm_Label := PChar(NM_BARLABEL);
  447. if pExecBase(_ExecBase)^.LibNode.Lib_Version >= 39 then begin
  448. tags[1] := TagItem(GTMN_FrontPen, 1);
  449. tags[2].ti_Tag := TAG_END;
  450. MenuStrip := CreateMenusA(@nm,@tags[1]);
  451. end else MenuStrip := CreateMenusA(@nm,NIL);
  452. if MenuStrip = nil then CleanUp('Could not open Menus',10);
  453. if LayoutMenusA(MenuStrip,vi,NIL)=false then
  454. CleanUp('Could not layout Menus',10);
  455. if SetMenuStrip(w, MenuStrip) = false then
  456. CleanUp('Could not set the Menus',10);
  457. end;
  458. PROCEDURE ProcessIDCMP;
  459. VAR
  460. IMessage : tIntuiMessage;
  461. IPtr : pIntuiMessage;
  462. Procedure ProcessMenu;
  463. var
  464. MenuNumber : Integer;
  465. ItemNumber : Integer;
  466. SubItemNumber : Integer;
  467. t0,t1,l : Longint;
  468. begin
  469. if IMessage.Code = MENUNULL then
  470. Exit;
  471. MenuNumber := MenuNum(IMessage.Code);
  472. ItemNumber := ItemNum(IMessage.Code);
  473. SubItemNumber := SubNum(IMessage.Code);
  474. case MenuNumber of
  475. 0 : begin
  476. case ItemNumber of
  477. 0 : begin
  478. refresh;
  479. settitles(0);
  480. CurrentTime(t0,l);
  481. CASE modus OF
  482. 0: heapsort;
  483. 1: shellsort;
  484. 2: a_sort;
  485. 3: e_sort;
  486. 4: shakersort;
  487. 5: bubblesort;
  488. 6: quicksort;
  489. 7: mergesort;
  490. END;
  491. CurrentTime(t1,l);
  492. settitles(t1-t0);
  493. end;
  494. 3 : QuitStopDie := True;
  495. end;
  496. end;
  497. 1 : begin
  498. case ItemNumber of
  499. 0..7 : modus := ItemNumber;
  500. end;
  501. settitles(-1);
  502. end;
  503. 2 : begin
  504. case ItemNumber of
  505. 0 : begin
  506. case SubItemNumber of
  507. 0 : if not rndom then rndom := true;
  508. 1 : if rndom then rndom := false;
  509. end;
  510. end;
  511. 1 : begin
  512. case SubItemNumber of
  513. 0 : if not needles then needles := true;
  514. 1 : if needles then needles := false;
  515. end;
  516. end;
  517. end;
  518. end;
  519. end;
  520. end;
  521. begin
  522. IPtr := pIntuiMessage(Msg);
  523. IMessage := IPtr^;
  524. ReplyMsg(Msg);
  525. case IMessage.IClass of
  526. IDCMP_MENUPICK : ProcessMenu;
  527. IDCMP_NEWSIZE : refresh;
  528. IDCMP_CLOSEWINDOW : QuitStopDie := True;
  529. end;
  530. end;
  531. begin
  532. OpenEverything;
  533. QuitStopDie := False;
  534. modus := 0;
  535. needles := true;
  536. rndom := true;
  537. refresh;
  538. repeat
  539. Msg := WaitPort(w^.UserPort);
  540. Msg := GetMsg(w^.UserPort);
  541. ProcessIDCMP;
  542. until QuitStopDie;
  543. CleanUp('',0);
  544. end.