pascal.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. { GPC demo program for the CRT unit.
  2. Copyright (C) 1999-2006 Free Software Foundation, Inc.
  3. Author: Frank Heckenbach <frank@pascal.gnu.de>
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License as
  6. published by the Free Software Foundation, version 2.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; see the file COPYING. If not, write to
  13. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. Boston, MA 02111-1307, USA.
  15. As a special exception, if you incorporate even large parts of the
  16. code of this demo program into another program with substantially
  17. different functionality, this does not cause the other program to
  18. be covered by the GNU General Public License. This exception does
  19. not however invalidate any other reasons why it might be covered
  20. by the GNU General Public License. }
  21. {$gnu-pascal,I+}
  22. program CRTDemo;
  23. uses GPC, CRT;
  24. type
  25. TFrameChars = array [1 .. 8] of Char;
  26. TSimulateBlockCursorKind = (bc_None, bc_Blink, bc_Static);
  27. const
  28. SingleFrame: TFrameChars = (chCornerTLS, chLineHS, chCornerTRS, chLineVS, chLineVS, chCornerBLS, chLineHS, chCornerBRS);
  29. DoubleFrame: TFrameChars = (chCornerTLD, chLineHD, chCornerTRD, chLineVD, chLineVD, chCornerBLD, chLineHD, chCornerBRD);
  30. var
  31. ScrollState: Boolean = True;
  32. SimulateBlockCursorKind: TSimulateBlockCursorKind = bc_None;
  33. CursorShape: TCursorShape = CursorNormal;
  34. MainPanel: TPanel;
  35. OrigScreenSize: TPoint;
  36. procedure FrameWin (const Title: String; const Frame: TFrameChars; TitleInverse: Boolean);
  37. var
  38. w, h, y, Color: Integer;
  39. Attr: TTextAttr;
  40. begin
  41. HideCursor;
  42. SetPCCharSet (True);
  43. ClrScr;
  44. w := GetXMax;
  45. h := GetYMax;
  46. WriteCharAt (1, 1, 1, Frame[1], TextAttr);
  47. WriteCharAt (2, 1, w - 2, Frame[2], TextAttr);
  48. WriteCharAt (w, 1, 1, Frame[3], TextAttr);
  49. for y := 2 to h - 1 do
  50. begin
  51. WriteCharAt (1, y, 1, Frame[4], TextAttr);
  52. WriteCharAt (w, y, 1, Frame[5], TextAttr)
  53. end;
  54. WriteCharAt (1, h, 1, Frame[6], TextAttr);
  55. WriteCharAt (2, h, w - 2, Frame[7], TextAttr);
  56. WriteCharAt (w, h, 1, Frame[8], TextAttr);
  57. SetPCCharSet (False);
  58. Attr := TextAttr;
  59. if TitleInverse then
  60. begin
  61. Color := GetTextColor;
  62. TextColor (GetTextBackground);
  63. TextBackground (Color)
  64. end;
  65. WriteStrAt ((w - Length (Title)) div 2 + 1, 1, Title, TextAttr);
  66. TextAttr := Attr
  67. end;
  68. function GetKey (TimeOut: Integer) = Key: TKey; forward;
  69. procedure ClosePopUpWindow;
  70. begin
  71. PanelDelete (GetActivePanel);
  72. PanelDelete (GetActivePanel)
  73. end;
  74. function PopUpConfirm (XSize, YSize: Integer; const Msg: String): Boolean;
  75. var
  76. ax, ay: Integer;
  77. Key: TKey;
  78. SSize: TPoint;
  79. begin
  80. repeat
  81. SSize := ScreenSize;
  82. ax := (SSize.x - XSize - 4) div 2 + 1;
  83. ay := (SSize.y - YSize - 4) div 2 + 1;
  84. PanelNew (ax, ay, ax + XSize + 3, ay + YSize + 1, False);
  85. TextBackground (Black);
  86. TextColor (Yellow);
  87. SetControlChars (True);
  88. FrameWin ('', DoubleFrame, False);
  89. NormalCursor;
  90. PanelNew (ax + 2, ay + 1, ax + XSize + 2, ay + YSize, False);
  91. ClrScr;
  92. Write (Msg);
  93. Key := GetKey (-1);
  94. if Key = kbScreenSizeChanged then ClosePopUpWindow
  95. until Key <> kbScreenSizeChanged;
  96. PopUpConfirm := not (Key in [kbEsc, kbAltEsc])
  97. end;
  98. procedure MainDraw;
  99. begin
  100. WriteLn ('3, F3 : Open a window');
  101. WriteLn ('4, F4 : Close window');
  102. WriteLn ('5, F5 : Previous window');
  103. WriteLn ('6, F6 : Next window');
  104. WriteLn ('7, F7 : Move window');
  105. WriteLn ('8, F8 : Resize window');
  106. Write ('q, Esc: Quit')
  107. end;
  108. procedure StatusDraw;
  109. const
  110. YesNo: array [Boolean] of String [3] = ('No', 'Yes');
  111. SimulateBlockCursorIDs: array [TSimulateBlockCursorKind] of String [8] = ('Off', 'Blinking', 'Static');
  112. CursorShapeIDs: array [TCursorShape] of String [7] = ('Ignored', 'Hidden', 'Normal', 'Fat', 'Block');
  113. var
  114. SSize: TPoint;
  115. begin
  116. WriteLn ('You can change some of the following');
  117. WriteLn ('settings by pressing the key shown');
  118. WriteLn ('in parentheses. Naturally, color and');
  119. WriteLn ('changing the cursor shape or screen');
  120. WriteLn ('size does not work on all terminals.');
  121. WriteLn;
  122. WriteLn ('XCurses version: ', YesNo[XCRT]);
  123. WriteLn ('CRTSavePreviousScreen: ', YesNo[CRTSavePreviousScreenWorks]);
  124. WriteLn ('(M)onochrome: ', YesNo[IsMonochrome]);
  125. SSize := ScreenSize;
  126. WriteLn ('Screen (C)olumns: ', SSize.x);
  127. WriteLn ('Screen (L)ines: ', SSize.y);
  128. WriteLn ('(R)estore screen size');
  129. WriteLn ('(B)reak checking: ', YesNo[CheckBreak]);
  130. WriteLn ('(S)crolling: ', YesNo[ScrollState]);
  131. WriteLn ('S(i)mulated block cursor: ', SimulateBlockCursorIDs[SimulateBlockCursorKind]);
  132. Write ('C(u)rsor shape: ', CursorShapeIDs[CursorShape]);
  133. GotoXY (36, WhereY)
  134. end;
  135. procedure RedrawAll; forward;
  136. procedure CheckScreenSize; forward;
  137. procedure StatusKey (Key: TKey);
  138. var SSize, NewSize: TPoint;
  139. begin
  140. case LoCase (Key2Char (Key)) of
  141. 'm': begin
  142. SetMonochrome (not IsMonochrome);
  143. RedrawAll
  144. end;
  145. 'c': begin
  146. SSize := ScreenSize;
  147. if SSize.x > 40 then
  148. NewSize.x := 40
  149. else
  150. NewSize.x := 80;
  151. if SSize.y > 25 then
  152. NewSize.y := 50
  153. else
  154. NewSize.y := 25;
  155. SetScreenSize (NewSize.x, NewSize.y);
  156. CheckScreenSize
  157. end;
  158. 'l': begin
  159. SSize := ScreenSize;
  160. if SSize.x > 40 then
  161. NewSize.x := 80
  162. else
  163. NewSize.x := 40;
  164. if SSize.y > 25 then
  165. NewSize.y := 25
  166. else
  167. NewSize.y := 50;
  168. SetScreenSize (NewSize.x, NewSize.y);
  169. CheckScreenSize
  170. end;
  171. 'r': begin
  172. SetScreenSize (OrigScreenSize.x, OrigScreenSize.y);
  173. CheckScreenSize
  174. end;
  175. 'b': CheckBreak := not CheckBreak;
  176. 's': ScrollState := not ScrollState;
  177. 'i': if SimulateBlockCursorKind = High (SimulateBlockCursorKind) then
  178. SimulateBlockCursorKind := Low (SimulateBlockCursorKind)
  179. else
  180. Inc (SimulateBlockCursorKind);
  181. 'u': case CursorShape of
  182. CursorNormal: CursorShape := CursorBlock;
  183. CursorFat,
  184. CursorBlock : CursorShape := CursorHidden;
  185. else CursorShape := CursorNormal
  186. end;
  187. end;
  188. ClrScr;
  189. StatusDraw
  190. end;
  191. procedure TextAttrDemo;
  192. var f, b, y, x1, y1, x2, y2, Fill, n1, n2, n3: Integer;
  193. begin
  194. GetWindow (x1, y1, x2, y2);
  195. Window (x1 - 1, y1, x2, y2);
  196. TextColor (White);
  197. TextBackground (Blue);
  198. ClrScr;
  199. SetScroll (False);
  200. Fill := GetXMax - 32;
  201. for y := 1 to GetYMax do
  202. begin
  203. GotoXY (1, y);
  204. b := (y - 1) mod 16;
  205. n1 := 0;
  206. for f := 0 to 15 do
  207. begin
  208. TextAttr := f + 16 * b;
  209. n2 := (Fill * (1 + 2 * f) + 16) div 32;
  210. n3 := (Fill * (2 + 2 * f) + 16) div 32;
  211. Write ('' : n2 - n1, NumericBaseDigitsUpper[b], NumericBaseDigitsUpper[f], '' : n3 - n2);
  212. n1 := n3
  213. end
  214. end
  215. end;
  216. procedure CharSetDemo (UsePCCharSet: Boolean);
  217. var h, l, y, x1, y1, x2, y2, Fill, n1, n2: Integer;
  218. begin
  219. GetWindow (x1, y1, x2, y2);
  220. Window (x1 - 1, y1, x2, y2);
  221. ClrScr;
  222. SetScroll (False);
  223. SetPCCharSet (UsePCCharSet);
  224. SetControlChars (False);
  225. Fill := GetXMax - 35;
  226. for y := 1 to GetYMax do
  227. begin
  228. GotoXY (1, y);
  229. h := (y - 2) mod 16;
  230. n1 := (Fill + 9) div 18;
  231. if y = 1 then
  232. Write ('' : 3 + n1)
  233. else
  234. Write (16 * h : 3 + n1);
  235. for l := 0 to 15 do
  236. begin
  237. n2 := (Fill * (2 + l) + 9) div 18;
  238. if y = 1 then
  239. Write ('' : n2 - n1, l : 2)
  240. else
  241. Write ('' : n2 - n1 + 1, Chr (16 * h + l));
  242. n1 := n2
  243. end
  244. end
  245. end;
  246. procedure NormalCharSetDemo;
  247. begin
  248. CharSetDemo (False)
  249. end;
  250. procedure PCCharSetDemo;
  251. begin
  252. CharSetDemo (True)
  253. end;
  254. procedure FKeyDemoDraw;
  255. var x1, y1, x2, y2: Integer;
  256. begin
  257. GetWindow (x1, y1, x2, y2);
  258. Window (x1, y1, x2 - 1, y2);
  259. ClrScr;
  260. SetScroll (False);
  261. WriteLn ('You can type the following keys');
  262. WriteLn ('(function keys if present on the');
  263. WriteLn ('terminal, letters as alternatives):');
  264. GotoXY (1, 4);
  265. WriteLn ('S, Left : left (wrap-around)');
  266. WriteLn ('D, Right : right (wrap-around)');
  267. WriteLn ('E, Up : up (wrap-around)');
  268. WriteLn ('X, Down : down (wrap-around)');
  269. WriteLn ('A, Home : go to first column');
  270. WriteLn ('F, End : go to last column');
  271. WriteLn ('R, Page Up : go to first line');
  272. WriteLn ('C, Page Down: go to last line');
  273. WriteLn ('Y, Ctrl-PgUp: first column and line');
  274. GotoXY (1, 13);
  275. WriteLn ('B, Ctrl-PgDn: last column and line');
  276. WriteLn ('Z, Ctrl-Home: clear screen');
  277. WriteLn ('N, Ctrl-End : clear to end of line');
  278. WriteLn ('V, Insert : insert a line');
  279. WriteLn ('T, Delete : delete a line');
  280. WriteLn ('# : beep');
  281. WriteLn ('* : flash');
  282. WriteLn ('Tab, Enter, Backspace, other');
  283. WriteLn (' normal characters: write text')
  284. end;
  285. procedure FKeyDemoKey (Key: TKey);
  286. const TabSize = 8;
  287. var
  288. ch: Char;
  289. NewX: Integer;
  290. begin
  291. case LoCaseKey (Key) of
  292. Ord ('s'), kbLeft : if WhereX = 1 then GotoXY (GetXMax, WhereY) else GotoXY (WhereX - 1, WhereY);
  293. Ord ('d'), kbRight : if WhereX = GetXMax then GotoXY (1, WhereY) else GotoXY (WhereX + 1, WhereY);
  294. Ord ('e'), kbUp : if WhereY = 1 then GotoXY (WhereX, GetYMax) else GotoXY (WhereX, WhereY - 1);
  295. Ord ('x'), kbDown : if WhereY = GetYMax then GotoXY (WhereX, 1) else GotoXY (WhereX, WhereY + 1);
  296. Ord ('a'), kbHome : Write (chCR);
  297. Ord ('f'), kbEnd : GotoXY (GetXMax, WhereY);
  298. Ord ('r'), kbPgUp : GotoXY (WhereX, 1);
  299. Ord ('c'), kbPgDn : GotoXY (WhereX, GetYMax);
  300. Ord ('y'), kbCtrlPgUp: GotoXY (1, 1);
  301. Ord ('b'), kbCtrlPgDn: GotoXY (GetXMax, GetYMax);
  302. Ord ('z'), kbCtrlHome: ClrScr;
  303. Ord ('n'), kbCtrlEnd : ClrEOL;
  304. Ord ('v'), kbIns : InsLine;
  305. Ord ('t'), kbDel : DelLine;
  306. Ord ('#') : Beep;
  307. Ord ('*') : Flash;
  308. kbTab : begin
  309. NewX := ((WhereX - 1) div TabSize + 1) * TabSize + 1;
  310. if NewX <= GetXMax then GotoXY (NewX, WhereY) else WriteLn
  311. end;
  312. kbCR : WriteLn;
  313. kbBkSp : Write (chBkSp, ' ', chBkSp);
  314. else ch := Key2Char (Key);
  315. if ch <> #0 then Write (ch)
  316. end
  317. end;
  318. procedure KeyDemoDraw;
  319. begin
  320. WriteLn ('Press some keys ...')
  321. end;
  322. procedure KeyDemoKey (Key: TKey);
  323. var ch: Char;
  324. begin
  325. ch := Key2Char (Key);
  326. if ch <> #0 then
  327. begin
  328. Write ('Normal key');
  329. if IsPrintable (ch) then Write (' `', ch, '''');
  330. WriteLn (', ASCII #', Ord (ch))
  331. end
  332. else
  333. WriteLn ('Special key ', Ord (Key2Scan (Key)))
  334. end;
  335. procedure IOSelectPeriodical;
  336. var
  337. CurrentTime: TimeStamp;
  338. s: String (8);
  339. i: Integer;
  340. begin
  341. GetTimeStamp (CurrentTime);
  342. with CurrentTime do
  343. WriteStr (s, Hour : 2, ':', Minute : 2, ':', Second : 2);
  344. for i := 1 to Length (s) do
  345. if s[i] = ' ' then s[i] := '0';
  346. GotoXY (1, 12);
  347. Write ('The time is: ', s)
  348. end;
  349. procedure IOSelectDraw;
  350. begin
  351. WriteLn ('IOSelect is a way to handle I/O from');
  352. WriteLn ('or to several places simultaneously,');
  353. WriteLn ('without having to use threads or');
  354. WriteLn ('signal/interrupt handlers or waste');
  355. WriteLn ('CPU time with busy waiting.');
  356. WriteLn;
  357. WriteLn ('This demo shows how IOSelect works');
  358. WriteLn ('in connection with CRT. It displays');
  359. WriteLn ('a clock, but still reacts to user');
  360. WriteLn ('input immediately.');
  361. IOSelectPeriodical
  362. end;
  363. procedure ModifierPeriodical;
  364. const
  365. Pressed: array [Boolean] of String [8] = ('Released', 'Pressed');
  366. ModifierNames: array [1 .. 7] of record
  367. Modifier: Integer;
  368. Name: String (17)
  369. end =
  370. ((shLeftShift, 'Left Shift'),
  371. (shRightShift, 'Right Shift'),
  372. (shLeftCtrl, 'Left Control'),
  373. (shRightCtrl, 'Right Control'),
  374. (shAlt, 'Alt (left)'),
  375. (shAltGr, 'AltGr (right Alt)'),
  376. (shExtra, 'Extra'));
  377. var
  378. ShiftState, i: Integer;
  379. begin
  380. ShiftState := GetShiftState;
  381. for i := 1 to 7 do
  382. with ModifierNames[i] do
  383. begin
  384. GotoXY (1, 4 + i);
  385. ClrEOL;
  386. Write (Name, ':');
  387. GotoXY (20, WhereY);
  388. Write (Pressed[(ShiftState and Modifier) <> 0])
  389. end
  390. end;
  391. procedure ModifierDraw;
  392. begin
  393. WriteLn ('Modifier keys (NOTE: only');
  394. WriteLn ('available on some systems;');
  395. WriteLn ('X11: only after key press):');
  396. ModifierPeriodical
  397. end;
  398. procedure ChecksDraw;
  399. begin
  400. WriteLn ('(O)S shell');
  401. WriteLn ('OS shell with (C)learing');
  402. WriteLn ('(R)efresh check');
  403. Write ('(S)ound check')
  404. end;
  405. procedure ChecksKey (Key: TKey);
  406. var
  407. i, j: Integer;
  408. WasteTime: Real; attribute (volatile);
  409. procedure DoOSShell;
  410. var
  411. Result: Integer;
  412. Shell: TString;
  413. begin
  414. Shell := GetShellPath (Null);
  415. {$I-}
  416. Result := Execute (Shell);
  417. {$I+}
  418. if (InOutRes <> 0) or (Result <> 0) then
  419. begin
  420. ClrScr;
  421. if InOutRes <> 0 then
  422. WriteLn (GetIOErrorMessage, ' while trying to execute `', Shell, '''.')
  423. else
  424. WriteLn ('`', Shell, ''' returned status ', Result, '.');
  425. Write ('Any key to continue.');
  426. BlockCursor;
  427. Discard (GetKey (-1))
  428. end
  429. end;
  430. begin
  431. case LoCase (Key2Char (Key)) of
  432. 'o': begin
  433. if PopUpConfirm (36, 12, 'You will now get an OS shell. Unless' + NewLine +
  434. 'CRTDemo is running in its own (GUI)' + NewLine +
  435. 'window, the shell will run on the' + NewLine +
  436. 'same screen as CRTDemo which is not' + NewLine +
  437. 'cleared before the shell is started.' + NewLine +
  438. 'If possible, the screen contents are' + NewLine +
  439. 'restored to the state before CRTDemo' + NewLine +
  440. 'was started. After leaving the shell' + NewLine +
  441. 'in the usual way (usually by enter-' + NewLine +
  442. 'ing `exit''), you will get back to' + NewLine +
  443. 'the demo. <ESC> to abort, any other' + NewLine +
  444. 'key to start.') then
  445. begin
  446. RestoreTerminal (True);
  447. DoOSShell
  448. end;
  449. ClosePopUpWindow
  450. end;
  451. 'c': begin
  452. if PopUpConfirm (36, 9, 'You will now get an OS shell. Unless' + NewLine +
  453. 'CRTDemo is running in its own (GUI)' + NewLine +
  454. 'window, the screen will be cleared,' + NewLine +
  455. 'and the cursor will be moved to the' + NewLine +
  456. 'top before the shell is started.' + NewLine +
  457. 'After leaving the shell in the usual' + NewLine +
  458. 'way (usually by entering `exit''),' + NewLine +
  459. 'you will get back to the demo. <ESC>' + NewLine +
  460. 'to abort, any other key to start.') then
  461. begin
  462. RestoreTerminalClearCRT;
  463. DoOSShell
  464. end;
  465. ClosePopUpWindow
  466. end;
  467. 'r': begin
  468. if PopUpConfirm (36, 11, 'The program will now get busy with' + NewLine +
  469. 'some dummy computations. However,' + NewLine +
  470. 'CRT output in the form of dots will' + NewLine +
  471. 'still appear continuously one by one' + NewLine +
  472. '(rather than the whole line at once' + NewLine +
  473. 'in the end). While running, the test' + NewLine +
  474. 'cannot be interrupted. <ESC> to' + NewLine +
  475. 'abort, any other key to start.') then
  476. begin
  477. SetCRTUpdate (UpdateRegularly);
  478. BlockCursor;
  479. WriteLn;
  480. WriteLn;
  481. for i := 1 to GetXMax - 2 do
  482. begin
  483. Write ('.');
  484. for j := 1 to 400000 do WasteTime := Random
  485. end;
  486. SetCRTUpdate (UpdateInput);
  487. WriteLn;
  488. Write ('Press any key.');
  489. Discard (GetKey (-1))
  490. end;
  491. ClosePopUpWindow
  492. end;
  493. 's': begin
  494. if PopUpConfirm (32, 4, 'You will now hear some sounds if' + NewLine +
  495. 'supported (otherwise there will' + NewLine +
  496. 'just be a short pause). <ESC> to' + NewLine +
  497. 'abort, any other key to start.') then
  498. begin
  499. BlockCursor;
  500. for i := 0 to 7 do
  501. begin
  502. Sound (Round (440 * 2 ** (Round (i * 12 / 7 + 0.3) / 12)));
  503. if GetKey (400000) in [kbEsc, kbAltEsc] then Break
  504. end;
  505. NoSound
  506. end;
  507. ClosePopUpWindow
  508. end;
  509. end
  510. end;
  511. type
  512. PWindowList = ^TWindowList;
  513. TWindowList = record
  514. Next, Prev: PWindowList;
  515. Panel, FramePanel: TPanel;
  516. WindowType: Integer;
  517. x1, y1, xs, ys: Integer;
  518. State: (ws_None, ws_Moving, ws_Resizing);
  519. end;
  520. TKeyProc = procedure (Key: TKey);
  521. TProcedure = procedure;
  522. const
  523. MenuNameLength = 16;
  524. WindowTypes: array [0 .. 9] of record
  525. DrawProc,
  526. PeriodicalProc: procedure;
  527. KeyProc : TKeyProc;
  528. Name : String (MenuNameLength);
  529. Color,
  530. Background,
  531. MinSizeX,
  532. MinSizeY,
  533. PrefSizeX,
  534. PrefSizeY : Integer;
  535. RedrawAlways,
  536. WantCursor : Boolean
  537. end =
  538. ((MainDraw , nil , nil , 'CRT Demo' , LightGreen, Blue , 26, 7, 0, 0, False, False),
  539. (StatusDraw , nil , StatusKey , 'Status' , White , Red , 38, 16, 0, 0, True, True),
  540. (TextAttrDemo , nil , nil , 'Text Attributes' , White , Blue , 32, 16, 64, 16, False, False),
  541. (NormalCharSetDemo, nil , nil , 'Character Set' , Black , Green , 35, 17, 53, 17, False, False),
  542. (PCCharSetDemo , nil , nil , 'PC Character Set', Black , Brown , 35, 17, 53, 17, False, False),
  543. (KeyDemoDraw , nil , KeyDemoKey , 'Keys' , Blue , LightGray, 29, 5, -1, -1, False, True),
  544. (FKeyDemoDraw , nil , FKeyDemoKey, 'Function Keys' , Blue , LightGray, 37, 22, -1, -1, False, True),
  545. (ModifierDraw , ModifierPeriodical, nil , 'Modifier Keys' , Black , Cyan , 29, 11, 0, 0, True, False),
  546. (IOSelectDraw , IOSelectPeriodical, nil , 'IOSelect Demo' , White , Magenta , 38, 12, 0, 0, False, False),
  547. (ChecksDraw , nil , ChecksKey , 'Various Checks' , Black , Red , 26, 4, 0, 0, False, False));
  548. MenuMax = High (WindowTypes);
  549. MenuXSize = MenuNameLength + 4;
  550. MenuYSize = MenuMax + 2;
  551. var
  552. WindowList: PWindowList = nil;
  553. procedure RedrawFrame (p: PWindowList);
  554. begin
  555. with p^, WindowTypes[WindowType] do
  556. begin
  557. PanelActivate (FramePanel);
  558. Window (x1, y1, x1 + xs - 1, y1 + ys - 1);
  559. ClrScr;
  560. case State of
  561. ws_None : if p = WindowList then
  562. FrameWin (' ' + Name + ' ', DoubleFrame, True)
  563. else
  564. FrameWin (' ' + Name + ' ', SingleFrame, False);
  565. ws_Moving : FrameWin (' Move Window ', SingleFrame, True);
  566. ws_Resizing: FrameWin (' Resize Window ', SingleFrame, True);
  567. end
  568. end
  569. end;
  570. procedure DrawWindow (p: PWindowList);
  571. begin
  572. with p^, WindowTypes[WindowType] do
  573. begin
  574. RedrawFrame (p);
  575. PanelActivate (Panel);
  576. Window (x1 + 2, y1 + 1, x1 + xs - 2, y1 + ys - 2);
  577. ClrScr;
  578. DrawProc
  579. end
  580. end;
  581. procedure RedrawAll;
  582. var
  583. LastPanel: TPanel;
  584. p: PWindowList;
  585. x2, y2: Integer;
  586. begin
  587. LastPanel := GetActivePanel;
  588. PanelActivate (MainPanel);
  589. TextBackground (Blue);
  590. ClrScr;
  591. p := WindowList;
  592. if p <> nil then
  593. repeat
  594. with p^ do
  595. begin
  596. PanelActivate (FramePanel);
  597. GetWindow (x1, y1, x2, y2); { updated automatically by CRT }
  598. xs := x2 - x1 + 1;
  599. ys := y2 - y1 + 1
  600. end;
  601. DrawWindow (p);
  602. p := p^.Next
  603. until p = WindowList;
  604. PanelActivate (LastPanel)
  605. end;
  606. procedure CheckScreenSize;
  607. var
  608. LastPanel: TPanel;
  609. MinScreenSizeX, MinScreenSizeY, i: Integer;
  610. SSize: TPoint;
  611. begin
  612. LastPanel := GetActivePanel;
  613. PanelActivate (MainPanel);
  614. HideCursor;
  615. MinScreenSizeX := MenuXSize;
  616. MinScreenSizeY := MenuYSize;
  617. for i := Low (WindowTypes) to High (WindowTypes) do
  618. with WindowTypes[i] do
  619. begin
  620. MinScreenSizeX := Max (MinScreenSizeX, MinSizeX + 2);
  621. MinScreenSizeY := Max (MinScreenSizeY, MinSizeY + 2)
  622. end;
  623. SSize := ScreenSize;
  624. Window (1, 1, SSize.x, SSize.y);
  625. if (SSize.x < MinScreenSizeX) or (SSize.y < MinScreenSizeY) then
  626. begin
  627. NormVideo;
  628. ClrScr;
  629. RestoreTerminal (True);
  630. WriteLn (StdErr, 'Sorry, your screen is too small for this demo (', SSize.x, 'x', SSize.y, ').');
  631. WriteLn (StdErr, 'You need at least ', MinScreenSizeX, 'x', MinScreenSizeY, ' characters.');
  632. Halt (2)
  633. end;
  634. PanelActivate (LastPanel);
  635. RedrawAll
  636. end;
  637. procedure Die; attribute (noreturn);
  638. begin
  639. NoSound;
  640. RestoreTerminalClearCRT;
  641. WriteLn (StdErr, 'You''re trying to kill me. Since I have break checking turned off,');
  642. WriteLn (StdErr, 'I''m not dying, but I''ll do you a favour and terminate now.');
  643. Halt (3)
  644. end;
  645. function GetKey (TimeOut: Integer) = Key: TKey;
  646. var
  647. NeedSelect, SelectValue: Integer;
  648. SimulateBlockCursorCurrent: TSimulateBlockCursorKind;
  649. SelectInput: array [1 .. 1] of PAnyFile = (@Input);
  650. NextSelectTime: MicroSecondTimeType = 0; attribute (static);
  651. TimeOutTime: MicroSecondTimeType;
  652. LastPanel: TPanel;
  653. p: PWindowList;
  654. begin
  655. LastPanel := GetActivePanel;
  656. if TimeOut < 0 then
  657. TimeOutTime := High (TimeOutTime)
  658. else
  659. TimeOutTime := GetMicroSecondTime + TimeOut;
  660. NeedSelect := 0;
  661. if TimeOut >= 0 then
  662. Inc (NeedSelect);
  663. SimulateBlockCursorCurrent := SimulateBlockCursorKind;
  664. if SimulateBlockCursorCurrent <> bc_None then
  665. Inc (NeedSelect);
  666. p := WindowList;
  667. repeat
  668. if @WindowTypes[p^.WindowType].PeriodicalProc <> nil then
  669. Inc (NeedSelect);
  670. p := p^.Next
  671. until p = WindowList;
  672. p := WindowList;
  673. repeat
  674. with p^, WindowTypes[WindowType] do
  675. if RedrawAlways then
  676. begin
  677. PanelActivate (Panel);
  678. ClrScr;
  679. DrawProc
  680. end;
  681. p := p^.Next
  682. until p = WindowList;
  683. if NeedSelect <> 0 then
  684. repeat
  685. CRTUpdate;
  686. SelectValue := IOSelectRead (SelectInput, Max (0, Min (NextSelectTime, TimeOutTime) - GetMicroSecondTime));
  687. if SelectValue = 0 then
  688. begin
  689. case SimulateBlockCursorCurrent of
  690. bc_None : ;
  691. bc_Blink : SimulateBlockCursor;
  692. bc_Static: begin
  693. SimulateBlockCursor;
  694. SimulateBlockCursorCurrent := bc_None;
  695. Dec (NeedSelect)
  696. end
  697. end;
  698. NextSelectTime := GetMicroSecondTime + 120000;
  699. p := WindowList;
  700. repeat
  701. with p^, WindowTypes[WindowType] do
  702. if @PeriodicalProc <> nil then
  703. begin
  704. PanelActivate (Panel);
  705. PeriodicalProc
  706. end;
  707. p := p^.Next
  708. until p = WindowList
  709. end;
  710. until (NeedSelect = 0) or (SelectValue <> 0) or ((TimeOut >= 0) and (GetMicroSecondTime >= TimeOutTime));
  711. if NeedSelect = 0 then
  712. SelectValue := 1;
  713. if SelectValue = 0 then
  714. Key := 0
  715. else
  716. Key := ReadKeyWord;
  717. if SimulateBlockCursorKind <> bc_None then
  718. SimulateBlockCursorOff;
  719. if IsDeadlySignal (Key) then Die;
  720. if Key = kbScreenSizeChanged then CheckScreenSize;
  721. PanelActivate (LastPanel)
  722. end;
  723. function Menu = n: Integer;
  724. var
  725. i, ax, ay: Integer;
  726. Key: TKey;
  727. Done: Boolean;
  728. SSize: TPoint;
  729. begin
  730. n := 1;
  731. repeat
  732. SSize := ScreenSize;
  733. ax := (SSize.x - MenuXSize) div 2 + 1;
  734. ay := (SSize.y - MenuYSize) div 2 + 1;
  735. PanelNew (ax, ay, ax + MenuXSize - 1, ay + MenuYSize - 1, False);
  736. SetControlChars (True);
  737. TextColor (Blue);
  738. TextBackground (LightGray);
  739. FrameWin (' Select Window ', DoubleFrame, True);
  740. IgnoreCursor;
  741. PanelNew (ax + 1, ay + 1, ax + MenuXSize - 2, ay + MenuYSize - 2, False);
  742. ClrScr;
  743. TextColor (Black);
  744. SetScroll (False);
  745. Done := False;
  746. repeat
  747. for i := 1 to MenuMax do
  748. begin
  749. GotoXY (1, i);
  750. if i = n then
  751. TextBackground (Green)
  752. else
  753. TextBackground (LightGray);
  754. ClrEOL;
  755. Write (' ', WindowTypes[i].Name);
  756. ChangeTextAttr (2, i, 1, Red + $10 * GetTextBackground)
  757. end;
  758. Key := GetKey (-1);
  759. case LoCaseKey (Key) of
  760. kbUp : if n = 1 then n := MenuMax else Dec (n);
  761. kbDown : if n = MenuMax then n := 1 else Inc (n);
  762. kbHome,
  763. kbPgUp,
  764. kbCtrlPgUp,
  765. kbCtrlHome : n := 1;
  766. kbEnd,
  767. kbPgDn,
  768. kbCtrlPgDn,
  769. kbCtrlEnd : n := MenuMax;
  770. kbCR : Done := True;
  771. kbEsc, kbAltEsc : begin
  772. n := -1;
  773. Done := True
  774. end;
  775. Ord ('a') .. Ord ('z'): begin
  776. i := MenuMax;
  777. while (i > 0) and (LoCase (Key2Char (Key)) <> LoCase (WindowTypes[i].Name[1])) do Dec (i);
  778. if i > 0 then
  779. begin
  780. n := i;
  781. Done := True
  782. end
  783. end;
  784. end
  785. until Done or (Key = kbScreenSizeChanged);
  786. ClosePopUpWindow
  787. until Key <> kbScreenSizeChanged
  788. end;
  789. procedure NewWindow (WindowType, ax, ay: Integer);
  790. var
  791. p, LastWindow: PWindowList;
  792. MaxX1, MaxY1: Integer;
  793. SSize: TPoint;
  794. begin
  795. New (p);
  796. if WindowList = nil then
  797. begin
  798. p^.Prev := p;
  799. p^.Next := p
  800. end
  801. else
  802. begin
  803. p^.Prev := WindowList;
  804. p^.Next := WindowList^.Next;
  805. p^.Prev^.Next := p;
  806. p^.Next^.Prev := p;
  807. end;
  808. p^.WindowType := WindowType;
  809. with p^, WindowTypes[WindowType] do
  810. begin
  811. SSize := ScreenSize;
  812. if PrefSizeX > 0 then xs := PrefSizeX else xs := MinSizeX;
  813. if PrefSizeY > 0 then ys := PrefSizeY else ys := MinSizeY;
  814. xs := Min (xs + 2, SSize.x);
  815. ys := Min (ys + 2, SSize.y);
  816. MaxX1 := SSize.x - xs + 1;
  817. MaxY1 := SSize.y - ys + 1;
  818. if ax = 0 then x1 := Random (MaxX1) + 1 else x1 := Min (ax, MaxX1);
  819. if ay = 0 then y1 := Random (MaxY1) + 1 else y1 := Min (ay, MaxY1);
  820. if (ax = 0) and (PrefSizeX < 0) then Inc (xs, Random (SSize.x - x1 - xs + 2));
  821. if (ax = 0) and (PrefSizeY < 0) then Inc (ys, Random (SSize.y - y1 - ys + 2));
  822. State := ws_None;
  823. PanelNew (1, 1, 1, 1, False);
  824. FramePanel := GetActivePanel;
  825. SetControlChars (True);
  826. TextColor (Color);
  827. TextBackground (Background);
  828. PanelNew (1, 1, 1, 1, False);
  829. SetPCCharSet (False);
  830. Panel := GetActivePanel;
  831. end;
  832. LastWindow := WindowList;
  833. WindowList := p;
  834. if LastWindow <> nil then RedrawFrame (LastWindow);
  835. DrawWindow (p)
  836. end;
  837. procedure OpenWindow;
  838. var WindowType: Integer;
  839. begin
  840. WindowType := Menu;
  841. if WindowType >= 0 then NewWindow (WindowType, 0, 0)
  842. end;
  843. procedure NextWindow;
  844. var LastWindow: PWindowList;
  845. begin
  846. LastWindow := WindowList;
  847. WindowList := WindowList^.Next;
  848. PanelTop (WindowList^.FramePanel);
  849. PanelTop (WindowList^.Panel);
  850. RedrawFrame (LastWindow);
  851. RedrawFrame (WindowList)
  852. end;
  853. procedure PreviousWindow;
  854. var LastWindow: PWindowList;
  855. begin
  856. PanelMoveAbove (WindowList^.Panel, MainPanel);
  857. PanelMoveAbove (WindowList^.FramePanel, MainPanel);
  858. LastWindow := WindowList;
  859. WindowList := WindowList^.Prev;
  860. RedrawFrame (LastWindow);
  861. RedrawFrame (WindowList)
  862. end;
  863. procedure CloseWindow;
  864. var p: PWindowList;
  865. begin
  866. if WindowList^.WindowType <> 0 then
  867. begin
  868. p := WindowList;
  869. NextWindow;
  870. PanelDelete (p^.FramePanel);
  871. PanelDelete (p^.Panel);
  872. p^.Next^.Prev := p^.Prev;
  873. p^.Prev^.Next := p^.Next;
  874. Dispose (p)
  875. end
  876. end;
  877. procedure MoveWindow;
  878. var
  879. Done, Changed: Boolean;
  880. SSize: TPoint;
  881. begin
  882. with WindowList^ do
  883. begin
  884. Done := False;
  885. Changed := True;
  886. State := ws_Moving;
  887. repeat
  888. if Changed then DrawWindow (WindowList);
  889. Changed := True;
  890. case LoCaseKey (GetKey (-1)) of
  891. Ord ('s'), kbLeft : if x1 > 1 then Dec (x1);
  892. Ord ('d'), kbRight : if x1 + xs - 1 < ScreenSize.x then Inc (x1);
  893. Ord ('e'), kbUp : if y1 > 1 then Dec (y1);
  894. Ord ('x'), kbDown : if y1 + ys - 1 < ScreenSize.y then Inc (y1);
  895. Ord ('a'), kbHome : x1 := 1;
  896. Ord ('f'), kbEnd : x1 := ScreenSize.x - xs + 1;
  897. Ord ('r'), kbPgUp : y1 := 1;
  898. Ord ('c'), kbPgDn : y1 := ScreenSize.y - ys + 1;
  899. Ord ('y'), kbCtrlPgUp: begin
  900. x1 := 1;
  901. y1 := 1
  902. end;
  903. Ord ('b'), kbCtrlPgDn: begin
  904. SSize := ScreenSize;
  905. x1 := SSize.x - xs + 1;
  906. y1 := SSize.y - ys + 1
  907. end;
  908. kbCR,
  909. kbEsc, kbAltEsc : Done := True;
  910. else Changed := False
  911. end
  912. until Done;
  913. State := ws_None;
  914. DrawWindow (WindowList)
  915. end
  916. end;
  917. procedure ResizeWindow;
  918. var
  919. Done, Changed: Boolean;
  920. SSize: TPoint;
  921. begin
  922. with WindowList^, WindowTypes[WindowType] do
  923. begin
  924. Done := False;
  925. Changed := True;
  926. State := ws_Resizing;
  927. repeat
  928. if Changed then DrawWindow (WindowList);
  929. Changed := True;
  930. case LoCaseKey (GetKey (-1)) of
  931. Ord ('s'), kbLeft : if xs > MinSizeX + 2 then Dec (xs);
  932. Ord ('d'), kbRight : if x1 + xs - 1 < ScreenSize.x then Inc (xs);
  933. Ord ('e'), kbUp : if ys > MinSizeY + 2 then Dec (ys);
  934. Ord ('x'), kbDown : if y1 + ys - 1 < ScreenSize.y then Inc (ys);
  935. Ord ('a'), kbHome : xs := MinSizeX + 2;
  936. Ord ('f'), kbEnd : xs := ScreenSize.x - x1 + 1;
  937. Ord ('r'), kbPgUp : ys := MinSizeY + 2;
  938. Ord ('c'), kbPgDn : ys := ScreenSize.y - y1 + 1;
  939. Ord ('y'), kbCtrlPgUp: begin
  940. xs := MinSizeX + 2;
  941. ys := MinSizeY + 2
  942. end;
  943. Ord ('b'), kbCtrlPgDn: begin
  944. SSize := ScreenSize;
  945. xs := SSize.x - x1 + 1;
  946. ys := SSize.y - y1 + 1
  947. end;
  948. kbCR,
  949. kbEsc, kbAltEsc : Done := True;
  950. else Changed := False
  951. end
  952. until Done;
  953. State := ws_None;
  954. DrawWindow (WindowList)
  955. end
  956. end;
  957. procedure ActivateCursor;
  958. begin
  959. with WindowList^, WindowTypes[WindowType] do
  960. begin
  961. PanelActivate (Panel);
  962. if WantCursor then
  963. SetCursorShape (CursorShape)
  964. else
  965. HideCursor
  966. end;
  967. SetScroll (ScrollState)
  968. end;
  969. var
  970. Key: TKey;
  971. ScreenShot, Done: Boolean;
  972. begin
  973. ScreenShot := ParamStr (1) = '--screenshot';
  974. if ParamCount <> Ord (ScreenShot) then
  975. begin
  976. RestoreTerminal (True);
  977. WriteLn (StdErr, ParamStr (0), ': invalid argument `', ParamStr (Ord (ScreenShot) + 1), '''');
  978. Halt (1)
  979. end;
  980. CRTSavePreviousScreen (True);
  981. SetCRTUpdate (UpdateInput);
  982. MainPanel := GetActivePanel;
  983. CheckScreenSize;
  984. OrigScreenSize := ScreenSize;
  985. if ScreenShot then
  986. begin
  987. CursorShape := CursorBlock;
  988. NewWindow (6, 1, 1);
  989. NewWindow (2, 1, MaxInt);
  990. NewWindow (8, MaxInt, 1);
  991. NewWindow (5, 1, 27);
  992. KeyDemoKey (Ord ('f'));
  993. KeyDemoKey (246);
  994. KeyDemoKey (kbDown);
  995. NewWindow (3, MaxInt, 13);
  996. NewWindow (4, MaxInt, 31);
  997. NewWindow (7, MaxInt, MaxInt);
  998. NewWindow (9, MaxInt, 33);
  999. NewWindow (0, 1, 2);
  1000. NewWindow (1, 1, 14);
  1001. ActivateCursor;
  1002. OpenWindow
  1003. end
  1004. else
  1005. NewWindow (0, 3, 2);
  1006. Done := False;
  1007. repeat
  1008. ActivateCursor;
  1009. Key := GetKey (-1);
  1010. case LoCaseKey (Key) of
  1011. Ord ('3'), kbF3 : OpenWindow;
  1012. Ord ('4'), kbF4 : CloseWindow;
  1013. Ord ('5'), kbF5 : PreviousWindow;
  1014. Ord ('6'), kbF6 : NextWindow;
  1015. Ord ('7'), kbF7 : MoveWindow;
  1016. Ord ('8'), kbF8 : ResizeWindow;
  1017. Ord ('q'), kbEsc,
  1018. kbAltEsc: Done := True;
  1019. else
  1020. if WindowList <> nil then
  1021. with WindowList^, WindowTypes[WindowType] do
  1022. if @KeyProc <> nil then
  1023. begin
  1024. TextColor (Color);
  1025. TextBackground (Background);
  1026. KeyProc (Key)
  1027. end
  1028. end
  1029. until Done
  1030. end.