ncrt.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. Unit nCrt;
  2. {---------------------------------------------------------------------------
  3. CncWare
  4. (c) Copyright 1999
  5. ---------------------------------------------------------------------------
  6. Filename..: ncrt.pp
  7. Programmer: Ken J. Wright
  8. Date......: 03/01/99
  9. Purpose - Misc crt replacements & extras using ncurses.
  10. NOTE: Although most of the crt procedures & functions have been replaced,
  11. this is NOT intended as a total replacement for the crt unit. It simply
  12. makes the ncurses library a little easier to use in a Pascal program,
  13. including the most commonly used crt functions, with some familiar naming.
  14. This mostly eliminates the need for using crt, or ncurses directly. By
  15. utilizing ncurses, we get terminal independence, among other things.
  16. If you also need some of the functionality of crt, then just add crt to the
  17. uses clause of your program *before* ncrt.
  18. -------------------------------<< REVISIONS >>--------------------------------
  19. Ver | Date | Prog| Description
  20. -------+----------+-----+-----------------------------------------------------
  21. 1.00 | 03/01/99 | kjw | Initial Release.
  22. | 03/22/99 | kjw | Added nDelWindow(), delwin() does not nil pointer.
  23. 1.01 | 11/22/99 | kjw | Added the following: nEcho, ClrEol, ClrBot, InsLine,
  24. | DelLine, Delay, nClrEol, nClrBot, nInsLine, nDelLine,
  25. | nRefresh, nScroll, nDrawBox, nNewWindow, nWinColor,
  26. | nWriteScr, nFrame & some functions for returning
  27. | line drawing character values.
  28. ------------------------------------------------------------------------------
  29. }
  30. Interface
  31. Uses linux,ncurses,strings;
  32. Const
  33. { border styles for text boxes }
  34. btNone : integer = 0;
  35. btSingle : integer = 1;
  36. btDouble : integer = 2;
  37. Black = 0;
  38. Blue = 1;
  39. Green = 2;
  40. Cyan = 3;
  41. Red = 4;
  42. Magenta = 5;
  43. Brown = 6;
  44. LightGray = 7;
  45. DarkGray = 8;
  46. LightBlue = 9;
  47. LightGreen = 10;
  48. LightCyan = 11;
  49. LightRed = 12;
  50. LightMagenta = 13;
  51. Yellow = 14;
  52. White = 15;
  53. Type
  54. pwin = ^Window;
  55. Function StartCurses(var win : pWindow) : Boolean;
  56. Procedure EndCurses;
  57. Procedure ClrScr;
  58. Procedure ClrEol;
  59. Procedure ClrBot;
  60. Procedure InsLine;
  61. Procedure DelLine;
  62. Procedure GotoXY(x,y : integer);
  63. Function WhereX : integer;
  64. Function WhereY : integer;
  65. Function Readkey : char;
  66. Function Keypressed : boolean;
  67. Procedure Delay(DTime: Word);
  68. Procedure nEcho(b : boolean);
  69. Procedure nWindow(var win : pWindow; x,y,x1,y1 : integer);
  70. Procedure nNewWindow(var win : pWindow; x,y,x1,y1 : integer);
  71. Procedure nDelWindow(var win : pWindow);
  72. Procedure nWinColor(win : pWindow; att : integer);
  73. Procedure nClrScr(win : pWindow; att : integer);
  74. Procedure nClrEol(win : pWindow);
  75. Procedure nClrBot(win : pWindow);
  76. Procedure nInsLine(win : pWindow);
  77. Procedure nDelLine(win : pWindow);
  78. Procedure nGotoXY(win : pWindow; x,y : integer);
  79. Function nWhereX(win : pWindow) : integer;
  80. Function nWhereY(win : pWindow) : integer;
  81. Function nReadkey(win : pWindow) : char;
  82. Function nReadln(win : pWindow) : string;
  83. Procedure nWrite(win : pWindow; s : string);
  84. Procedure nWriteln(win : pWindow; s : string);
  85. Procedure nWriteScr(win : pWindow; x,y,att : integer; s : string);
  86. Procedure nRefresh(win : pWindow);
  87. Procedure nScroll(win : pWindow; lines,dir : integer);
  88. Procedure nDrawBox(LineStyle,x1,y1,x2,y2,att : Integer);
  89. Procedure nFrame(win : pWindow);
  90. Function nHL : char; { horizontal line }
  91. Function nVL : char; { vertical line }
  92. Function nUL : char; { upper left corner }
  93. Function nLL : char; { lower loft corner }
  94. Function nUR : char; { upper right corner }
  95. Function nLR : char; { lower right corner }
  96. Function nLT : char; { left tee }
  97. Function nRT : char; { right tee }
  98. Function nTT : char; { top tee }
  99. Function nBT : char; { bottom tee }
  100. Function nPL : char; { plus, + }
  101. Function nLA : char; { left arrow }
  102. Function nRA : char; { right arrow }
  103. Function nUA : char; { up arror }
  104. Function nDA : char; { down arrow }
  105. Function IsBold(att : integer) : boolean;
  106. Function SetColorPair(att : integer) : integer;
  107. Procedure FWrite(Col,Row,Attrib:byte;Clear:Integer;s:String);
  108. Implementation
  109. Var
  110. fg,bg : integer;
  111. cp : array [0..7,0..7] of integer; { color pair array }
  112. ps : array [0..255] of char; { for use with pchars }
  113. {--------------------------------------
  114. initialize ncurses screen & keyboard,
  115. return a pointer to stdscr
  116. --------------------------------------}
  117. Function StartCurses(var win : pWindow) : Boolean;
  118. Begin
  119. if initscr=Nil then Begin
  120. StartCurses := FALSE;
  121. halt;
  122. End Else Begin
  123. StartCurses := TRUE;
  124. start_color;
  125. cbreak; { don't buffer keyboard input }
  126. noecho; { don't echo kepresses }
  127. nonl; { don't process cr in newline }
  128. intrflush(stdscr,bool(false));
  129. keypad(stdscr,bool(true));
  130. win := stdscr;
  131. End;
  132. End;
  133. {-------------------
  134. Shutdown ncurses
  135. -------------------}
  136. Procedure EndCurses;
  137. Begin
  138. echo;
  139. nocbreak;
  140. refresh;
  141. endwin;
  142. End;
  143. { clear stdscr }
  144. Procedure ClrScr;
  145. Begin
  146. TouchWin(stdscr);
  147. erase;
  148. refresh;
  149. End;
  150. { clear from the cursor to the end of line in stdscr }
  151. Procedure ClrEol;
  152. Begin
  153. clrtoeol;
  154. refresh;
  155. End;
  156. { clear from the cursor to the bottom of stdscr }
  157. Procedure ClrBot;
  158. Begin
  159. clrtobot;
  160. refresh;
  161. End;
  162. { insert a line at the cursor line in stdscr }
  163. Procedure InsLine;
  164. Begin
  165. insertln;
  166. refresh;
  167. End;
  168. { delete line at the cursor in stdscr }
  169. Procedure DelLine;
  170. Begin
  171. deleteln;
  172. refresh;
  173. End;
  174. { position cursor in stdscr }
  175. Procedure GotoXY(x,y : integer);
  176. Begin
  177. move(y-1,x-1);
  178. refresh;
  179. End;
  180. { find cursor x position in stdscr }
  181. Function WhereX : integer;
  182. var x,y : longint;
  183. Begin
  184. getyx(stdscr,y,x);
  185. WhereX := x+1;
  186. End;
  187. { find cursor y position in stdscr }
  188. Function WhereY : integer;
  189. var x,y : longint;
  190. Begin
  191. getyx(stdscr,y,x);
  192. WhereY := y+1;
  193. End;
  194. { Wait for DTime milliseconds }
  195. Procedure Delay(DTime: Word);
  196. Begin
  197. Select(0,nil,nil,nil,DTime);
  198. End;
  199. { set the echo flag }
  200. Procedure nEcho(b : boolean);
  201. Begin
  202. Case b of
  203. true : echo;
  204. false: noecho;
  205. End;
  206. End;
  207. { create a new subwindow }
  208. Procedure nWindow(var win : pWindow; x,y,x1,y1 : integer);
  209. Begin
  210. nDelWindow(win);
  211. win := subwin(stdscr,y1-y+1,x1-x+1,y-1,x-1);
  212. If win = nil then Exit;
  213. intrflush(win,bool(false));
  214. keypad(win,bool(true));
  215. End;
  216. { create a new window }
  217. Procedure nNewWindow(var win : pWindow; x,y,x1,y1 : integer);
  218. Begin
  219. nDelWindow(win);
  220. win := newwin(y1-y+1,x1-x+1,y-1,x-1);
  221. If win = nil then Exit;
  222. intrflush(win,bool(false));
  223. keypad(win,bool(true));
  224. End;
  225. { delete a window, note this does not clear it }
  226. Procedure nDelWindow(var win : pWindow);
  227. Begin
  228. If win <> Nil Then delwin(win);
  229. win := Nil;
  230. End;
  231. { set the color of the entire window, }
  232. { delayed until next refresh }
  233. Procedure nWinColor(win : pWindow; att : integer);
  234. Begin
  235. wbkgd(win,COLOR_PAIR(SetColorPair(att)));
  236. If IsBold(att) Then
  237. wattr_set(win,A_BOLD);
  238. End;
  239. { clear the specified screen }
  240. procedure nClrScr(win : pWindow; att : integer);
  241. Begin
  242. wbkgd(win,COLOR_PAIR(SetColorPair(att)));
  243. If IsBold(att) Then
  244. wattr_set(win,A_BOLD);
  245. TouchWin(win);
  246. werase(win);
  247. wrefresh(win);
  248. End;
  249. { clear from the cursor to the end of line in a window }
  250. Procedure nClrEol(win : pWindow);
  251. Begin
  252. wclrtoeol(win);
  253. wrefresh(win);
  254. End;
  255. { clear from the cursor to the bottom in a window }
  256. Procedure nClrBot(win : pWindow);
  257. Begin
  258. wclrtobot(win);
  259. wrefresh(win);
  260. End;
  261. { insert a line at the cursor line in a window }
  262. Procedure nInsLine(win : pWindow);
  263. Begin
  264. winsertln(win);
  265. wrefresh(win);
  266. End;
  267. { delete line at the cursor in stdscr }
  268. Procedure nDelLine(win : pWindow);
  269. Begin
  270. wdeleteln(win);
  271. wrefresh(win);
  272. End;
  273. { position cursor in a window }
  274. Procedure nGotoXY(win : pWindow; x,y : integer);
  275. Begin
  276. wmove(win,y-1,x-1);
  277. touchwin(win);
  278. wrefresh(win);
  279. End;
  280. { find cursor x position in a window }
  281. Function nWhereX(win : pWindow) : integer;
  282. var x,y : longint;
  283. Begin
  284. getyx(win,y,x);
  285. nWhereX := x+1;
  286. End;
  287. { find cursor y position in a window }
  288. Function nWhereY(win : pWindow) : integer;
  289. var x,y : longint;
  290. Begin
  291. getyx(win,y,x);
  292. nWhereY := y+1;
  293. End;
  294. { repaint a window }
  295. Procedure nRefresh(win : pWindow);
  296. Begin
  297. touchwin(win);
  298. wrefresh(win);
  299. End;
  300. {
  301. Check if a key has been pressed.
  302. Note: this is best used along with select() on STDIN, as it can suck
  303. up lots of cpu time.
  304. }
  305. function Keypressed : boolean;
  306. var l : longint;
  307. Begin
  308. Keypressed := FALSE;
  309. nodelay(stdscr,bool(TRUE));
  310. l := getch;
  311. If l <> ERR Then Begin { ERR = -(1) from unit ncurses }
  312. ungetch(l);
  313. Keypressed := TRUE;
  314. End;
  315. nodelay(stdscr,bool(FALSE));
  316. End;
  317. { silently read a key from stdscr }
  318. Function Readkey : char;
  319. Begin
  320. Readkey := nReadkey(stdscr);
  321. End;
  322. {
  323. read a keystroke from a window, including function keys
  324. and extended keys (arrows, etc.)
  325. Note: Make sure that keypad(win,true) has been issued prior to use.
  326. ( nWindow does this )
  327. }
  328. Function nReadkey(win : pWindow) : char;
  329. var
  330. c : char;
  331. l : longint;
  332. xtnded : boolean;
  333. Begin
  334. l := wgetch(win);
  335. { if it's an extended key, then map to the IBM values }
  336. if l > 255 then begin
  337. xtnded := true;
  338. c := #27;
  339. Case l of
  340. KEY_BREAK : Begin xtnded := false; c := #3; End;
  341. KEY_BACKSPACE : Begin xtnded := false; c := #8; End;
  342. KEY_IC : c := #82; { insert }
  343. KEY_DC : c := #83; { delete }
  344. KEY_HOME : c := #71; { home }
  345. KEY_END : c := #79; { end }
  346. KEY_UP : c := #72; { up arrow }
  347. KEY_DOWN : c := #80; { down arrow }
  348. KEY_LEFT : c := #75; { left arrow }
  349. KEY_RIGHT : c := #77; { right arrow }
  350. KEY_NPAGE : c := #81; { page down }
  351. KEY_PPAGE : c := #73; { page up }
  352. Else
  353. Begin
  354. If l = Key_f(1) Then c := #59 Else
  355. If l = Key_f(2) Then c := #60 Else
  356. If l = Key_f(3) Then c := #61 Else
  357. If l = Key_f(4) Then c := #62 Else
  358. If l = Key_f(5) Then c := #63 Else
  359. If l = Key_f(6) Then c := #64 Else
  360. If l = Key_f(7) Then c := #65 Else
  361. If l = Key_f(8) Then c := #66 Else
  362. If l = Key_f(9) Then c := #67 Else
  363. If l = Key_f(10) Then c := #68;
  364. End;
  365. End;
  366. If xtnded Then Begin
  367. nReadKey := #0;
  368. ungetch(ord(c));
  369. Exit;
  370. End Else
  371. nReadkey := c;
  372. End Else
  373. nReadkey := chr(ord(l));
  374. End;
  375. { read input string from a window }
  376. { note: by default, echo is false }
  377. Function nReadln(win : pWindow) : string;
  378. Begin
  379. wgetstr(win,ps);
  380. nReadln := StrPas(ps);
  381. End;
  382. { write a string to a window at the current cursor position }
  383. Procedure nWrite(win : pWindow; s : string);
  384. Begin
  385. waddstr(win,StrPCopy(ps,s));
  386. wrefresh(win);
  387. End;
  388. { write a string to a window at the current cursor position }
  389. { followed by a newline }
  390. Procedure nWriteln(win : pWindow; s : string);
  391. Begin
  392. waddstr(win,StrPCopy(ps,s+#10));
  393. wrefresh(win);
  394. End;
  395. { write a string to a window without refreshing screen }
  396. Procedure nWriteScr(win : pWindow; x,y,att : integer; s : string);
  397. Var
  398. xx,yy,
  399. cp : longint;
  400. Begin
  401. cp := SetColorPair(att);
  402. { write string with current attributes }
  403. mvwaddstr(win,y-1,x-1,StrPCopy(ps,s));
  404. { save the new cursor position }
  405. getyx(win,yy,xx);
  406. { update with new attributes }
  407. If IsBold(att) Then
  408. mvwchgat(win,y-1,x-1,-1,A_BOLD,cp,0)
  409. Else
  410. mvwchgat(win,y-1,x-1,-1,A_NORMAL,cp,0);
  411. { return cursor to saved position }
  412. wmove(win,yy,xx);
  413. End;
  414. { scroll a window, up or down, a specified number of lines }
  415. Procedure nScroll(win : pwindow; lines,dir : integer);
  416. var i : integer;
  417. Begin
  418. ScrollOk(win,bool(True));
  419. For i := 1 to lines Do Begin
  420. wscrl(win,dir);
  421. End;
  422. wRefresh(win);
  423. End;
  424. { draw a colored box, with or without a border }
  425. Procedure nDrawBox(LineStyle,x1,y1,x2,y2,att : Integer);
  426. Var
  427. win : pWindow;
  428. Begin
  429. win := SubWin(stdscr,y2-y1+1,x2-x1+1,y1-1,x1-1);
  430. If win = nil Then Begin
  431. write('drawbox: could not allocate window: ',
  432. (y2-y1+1),',',(x2-x1+1),',',(y1-1),',',(x1-1));
  433. exit;
  434. end;
  435. wbkgd(win,COLOR_PAIR(SetColorPair(att)));
  436. If IsBold(att) Then
  437. wattr_set(win,A_BOLD);
  438. werase(win);
  439. case LineStyle of
  440. 1,2 : box(win, ACS_VLINE, ACS_HLINE);
  441. End;
  442. wrefresh(win);
  443. nDelWindow(win);
  444. End;
  445. { add a border to a window }
  446. { waits for a refresh }
  447. Procedure nFrame(win : pWindow);
  448. Begin
  449. box(win, ACS_VLINE, ACS_HLINE);
  450. End;
  451. Function nHL : char;
  452. Begin
  453. nHL := char(ACS_HLINE);
  454. End;
  455. Function nVL : char;
  456. Begin
  457. nVL := char(ACS_VLINE);
  458. End;
  459. Function nUL : char;
  460. Begin
  461. nUL := char(ACS_ULCORNER);
  462. End;
  463. Function nLL : char;
  464. Begin
  465. nLL := char(ACS_LLCORNER);
  466. End;
  467. Function nUR : char;
  468. Begin
  469. nUR := char(ACS_URCORNER);
  470. End;
  471. Function nLR : char;
  472. Begin
  473. nLR := char(ACS_LRCORNER);
  474. End;
  475. Function nLT : char;
  476. Begin
  477. nLT := char(ACS_LTEE);
  478. End;
  479. Function nRT : char;
  480. Begin
  481. nRT := char(ACS_RTEE);
  482. End;
  483. Function nTT : char;
  484. Begin
  485. nTT := char(ACS_TTEE);
  486. End;
  487. Function nBT : char;
  488. Begin
  489. nBT := char(ACS_BTEE);
  490. End;
  491. Function nPL : char;
  492. Begin
  493. nPL := char(ACS_PLUS);
  494. End;
  495. Function nLA : char;
  496. Begin
  497. nLA := char(ACS_LARROW);
  498. End;
  499. Function nRA : char;
  500. Begin
  501. nRA := char(ACS_RARROW);
  502. End;
  503. Function nUA : char;
  504. Begin
  505. nUA := char(ACS_UARROW);
  506. End;
  507. Function nDA : char;
  508. Begin
  509. nDA := char(ACS_DARROW);
  510. End;
  511. { see if the specified attribute is high intensity, }
  512. { used by fwrite() }
  513. Function IsBold(att : integer) : boolean;
  514. Begin
  515. bg := att div 16;
  516. fg := att - ((att div 16) * 16);
  517. isbold := (fg > 7);
  518. End;
  519. { initialize a color pair, used by fwrite() }
  520. Function SetColorPair(att : integer) : integer;
  521. var
  522. i : integer;
  523. { ncurses constants
  524. COLOR_BLACK = 0;
  525. COLOR_RED = 1;
  526. COLOR_GREEN = 2;
  527. COLOR_YELLOW = 3;
  528. COLOR_BLUE = 4;
  529. COLOR_MAGENTA = 5;
  530. COLOR_CYAN = 6;
  531. COLOR_WHITE = 7;
  532. }
  533. Begin
  534. bg := att div 16;
  535. fg := att - ((att div 16) * 16);
  536. While bg > 7 Do dec(bg,8);
  537. While fg > 7 Do dec(fg,8);
  538. { map to ncurses color values }
  539. case bg of
  540. 0 : bg := COLOR_BLACK;
  541. 1 : bg := COLOR_BLUE;
  542. 2 : bg := COLOR_GREEN;
  543. 3 : bg := COLOR_CYAN;
  544. 4 : bg := COLOR_RED;
  545. 5 : bg := COLOR_MAGENTA;
  546. 6 : bg := COLOR_YELLOW;
  547. 7 : bg := COLOR_WHITE;
  548. end;
  549. case fg of
  550. 0 : fg := COLOR_BLACK;
  551. 1 : fg := COLOR_BLUE;
  552. 2 : fg := COLOR_GREEN;
  553. 3 : fg := COLOR_CYAN;
  554. 4 : fg := COLOR_RED;
  555. 5 : fg := COLOR_MAGENTA;
  556. 6 : fg := COLOR_YELLOW;
  557. 7 : fg := COLOR_WHITE;
  558. end;
  559. i := cp[bg,fg];
  560. init_pair(i,fg,bg);
  561. SetColorPair := i;
  562. End;
  563. {---------------------------------------------------------------
  564. write a string to stdscr with color, without moving the cursor
  565. Col = x position
  566. Row = y position
  567. Attrib = color (0..127)
  568. Clear = clear line up to x position
  569. s = string to write
  570. ---------------------------------------------------------------}
  571. procedure FWrite(Col,Row,Attrib:byte;Clear:Integer;s:String);
  572. Const
  573. ClearLine = { Following line is 80 Spaces }
  574. ' ';
  575. Var
  576. cs : string;
  577. win : pWindow;
  578. Begin
  579. if Clear > 0 Then Begin
  580. If Clear > 80 Then Clear := 80;
  581. cs := Copy(ClearLine,1,(Clear-Col)-Length(s)+1);
  582. End Else
  583. cs := '';
  584. s := s+cs;
  585. If s = '' Then Exit;
  586. win := subwin(stdscr,1,Length(s),row-1,col-1);
  587. If win = nil Then Begin
  588. s := ' FWrite: failed to create sub-window for '+s;
  589. write(s,':',length(s));
  590. Exit;
  591. End;
  592. wbkgd(win,COLOR_PAIR(SetColorPair(Attrib)));
  593. If isbold(Attrib) then
  594. wattr_set(win,A_BOLD);
  595. mvwaddstr(win,0,0,StrPCopy(ps,s));
  596. wrefresh(win);
  597. delwin(win);
  598. refresh;
  599. End;
  600. Begin
  601. { load the color pairs array with color pair indices (0..63) }
  602. For bg := 0 to 7 Do For fg := 0 to 7 do cp[bg,fg] := (bg*8)+fg;
  603. End. { of Unit nCrt }