2
0

edit_demo.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. Program Edit_Demo;
  2. {---------------------------------------------------------------------------
  3. CncWare
  4. (c) Copyright 1999-2000
  5. ---------------------------------------------------------------------------
  6. Filename..: edit_demo.pp
  7. Programmer: Ken J. Wright, [email protected]
  8. Date......: 12/12/99
  9. Purpose - Demonstrate the use of the oCrt unit.
  10. -------------------------------<< REVISIONS >>--------------------------------
  11. Ver | Date | Prog| Description
  12. -------+----------+-----+-----------------------------------------------------
  13. 1.00 | 12/12/99 | kjw | Initial Release.
  14. 1.01 | 12/13/99 | kjw | Changed to use oCrt.
  15. 1.02 | 06/16/00 | kjw | Added help & goto line pop-up screens.
  16. | Changes for control keys.
  17. 1.03 | 07/25/00 | kjw | Added use of new tnMenu object.
  18. ------------------------------------------------------------------------------
  19. }
  20. uses oCrt;
  21. const
  22. MAXLINES = 52; { allow for long screens }
  23. CURLINES : Integer = MAXLINES; { adjusted later }
  24. FRAMED = true;
  25. NOFRAME = false;
  26. bg = 16; { background color multiplier }
  27. type
  28. { doubly linked list of strings to edit }
  29. pLine = ^tLine;
  30. tLine = Record
  31. s : ^string;
  32. next,
  33. prev : pLine;
  34. End;
  35. s80 = string[80];
  36. var
  37. hdr, { list head }
  38. line, { current position in list }
  39. line1 : pLine; { first list item of current page }
  40. ss : array[1..MAXLINES] of s80; { a sliding screen buffer }
  41. xp,yp : string; { x & y positions for the status line }
  42. EdWin, { main edit window }
  43. StatWin : tnWindow; { status line }
  44. mnu0 : tnMenu; { main menu }
  45. mnu1 : pnMenu; { dynamic menu for sub menus }
  46. xi, { integer scratch pad }
  47. cv, { edit character return value }
  48. idx : integer; { current screen buffer row index }
  49. cline, { current line number }
  50. dlines : integer; { number of displayed lines }
  51. lines : longint; { total number of lines in the list }
  52. mactive, { is the menu active? }
  53. Finished : boolean; { exit when finished }
  54. tf : text; { the text file we are reading/writing }
  55. fnam : string; { name of the current file, tf }
  56. { replace the old string with a new one }
  57. Procedure ReallocateLine(var p : pLine; s : string);
  58. Begin
  59. If p = Nil Then Exit;
  60. If p^.s^ <> s Then Begin
  61. FreeMem(p^.s,Length(p^.s^)+1);
  62. GetMem(p^.s,Length(s)+1);
  63. p^.s^ := s;
  64. End;
  65. End;
  66. { insert a new pline into the edit list before p }
  67. Procedure InsertLine(var p : pLine; s : string);
  68. Var
  69. tmp : pLine;
  70. Begin
  71. New(tmp);
  72. GetMem(tmp^.s,Length(s)+1);
  73. tmp^.s^ := s;
  74. tmp^.prev := p^.prev;
  75. tmp^.next := p;
  76. p^.prev := tmp;
  77. tmp^.prev^.next := tmp;
  78. inc(lines);
  79. End;
  80. { delete a pline from the edit list }
  81. Procedure DeleteLine(var p : pLine);
  82. Var
  83. tmp : pLine;
  84. Begin
  85. FreeMem(p^.s,Length(p^.s^));
  86. tmp := p^.next;
  87. tmp^.prev := p^.prev;
  88. p^.prev^.next := tmp;
  89. Dispose(p);
  90. p := tmp;
  91. dec(lines);
  92. If cline > lines Then cline := lines;
  93. End;
  94. { return the minimum of two integer values }
  95. Function Min(i1,i2 : integer) : integer;
  96. Begin
  97. If i1 < i2 Then
  98. Min := i1
  99. Else
  100. Min := i2;
  101. End;
  102. { fill the edit buffer starting with position h in the edit list }
  103. Procedure LoadLines(var h : pLine);
  104. Var
  105. tmp : pLine;
  106. i : integer;
  107. Begin
  108. FillChar(ss,SizeOf(ss),#0);
  109. tmp := h;
  110. If tmp = hdr Then tmp := tmp^.Next;
  111. For i := 1 to CURLINES Do Begin
  112. If (tmp <> Nil) and (tmp <> hdr) Then Begin
  113. ss[i] := tmp^.s^;
  114. tmp := tmp^.next;
  115. dlines := i;
  116. End;
  117. End;
  118. End;
  119. { display the edit buffer in the edit window }
  120. Procedure DisplayLines;
  121. Var
  122. i : integer;
  123. Begin
  124. With EdWin Do Begin
  125. For i := 1 to CURLINES Do Begin
  126. FWrite(1,i,GetColor,Cols,ss[i]);
  127. End;
  128. End;
  129. End;
  130. { free the entire edit list }
  131. Procedure ClearLines(var h : pLine);
  132. Var
  133. tmp : pLine;
  134. Begin
  135. If h <> Nil Then Begin
  136. tmp := h^.prev;
  137. If (tmp <> h) and (tmp^.s <> Nil) Then Begin
  138. FreeMem(tmp^.s,Length(tmp^.s^)+1);
  139. tmp^.next := h;
  140. Dispose(tmp);
  141. End;
  142. End;
  143. New(h);
  144. h^.next := h;
  145. h^.prev := h;
  146. h^.s := nil;
  147. End;
  148. Function PromptFile(hs : string; var s : string) : integer;
  149. Var
  150. win : pnWindow;
  151. ret : integer;
  152. Begin
  153. New(win,Init(1,1,EdWin.Cols,3,cyan*bg,FRAMED,cyan*bg+white));
  154. With win^ Do Begin
  155. PutHeader(hs,GetFrameColor,center);
  156. FWrite(2,1,GetColor,0,'Filename: ');
  157. Align(center,center);
  158. Show;
  159. s := Edit(12,1,GetColor+white,Cols,12,fnam,ret);
  160. PromptFile := ret;
  161. Hide;
  162. End;
  163. Dispose(win,Done);
  164. End;
  165. { prompt for, and open a text file }
  166. Function OpenFile(var f : text; prompt : boolean) : boolean;
  167. Var
  168. s : string;
  169. tst : text;
  170. ret : integer;
  171. Begin
  172. If prompt Then
  173. ret := PromptFile('Open File',s)
  174. Else Begin
  175. s := fnam;
  176. ret := nkEnter;
  177. End;
  178. If ret = nkEnter Then Begin
  179. Assign(tst,s);
  180. {$I-}
  181. Reset(tst);
  182. {$I+}
  183. If IoResult = 0 Then Begin
  184. Close(tst);
  185. Assign(f,s);
  186. Reset(f);
  187. OpenFile := true;
  188. fnam := s;
  189. End Else Begin
  190. nShowMessage('Could not open file "'+s+'"',79,' Error ',78,true);
  191. OpenFile := false;
  192. End;
  193. End Else
  194. OpenFile := false;
  195. End;
  196. { read a file line by line into the edit list }
  197. Procedure ReadFile(var f : text; prompt : boolean);
  198. Var
  199. err : boolean;
  200. s : string;
  201. win : pnWindow;
  202. Begin
  203. If Not OpenFile(f,prompt) Then Exit;
  204. ClearLines(hdr);
  205. lines := 0;
  206. win := nShowMessage('Reading "'+fnam+'"...',47,' Open File ',46,false);
  207. {$I-}
  208. Repeat
  209. If Not Eof(f) Then Begin
  210. Readln(f,s);
  211. err := (IoResult <> 0);
  212. If Not Err Then InsertLine(hdr,s);
  213. End;
  214. Until Eof(f) or err;
  215. Close(f);
  216. {$I+}
  217. win^.Hide;
  218. win^.Done;
  219. line1 := hdr^.next;
  220. line := line1;
  221. LoadLines(line1);
  222. DisplayLines;
  223. idx := 1;
  224. End;
  225. { save the edit list to disk }
  226. Procedure SaveFile(var f : text);
  227. Var
  228. tmp : text;
  229. s,
  230. tnam : string;
  231. cur : pLine;
  232. win : pnWindow;
  233. Begin
  234. If PromptFile('Save File',s) = nkEsc Then
  235. Exit
  236. Else
  237. fnam := s;
  238. tnam := fnam+'~';
  239. Assign(tmp,tnam);
  240. Assign(f,fnam);
  241. win := nShowMessage('Saving "'+fnam+'"...',47,' Save File ',46,false);
  242. {$I-}
  243. Reset(tmp);
  244. If IoResult = 0 Then Begin
  245. Close(tmp);
  246. Erase(tmp);
  247. Rename(f,tnam);
  248. Assign(f,fnam);
  249. End;
  250. ReWrite(f);
  251. cur := hdr^.next;
  252. Repeat
  253. If cur <> hdr Then Writeln(f,cur^.s^);
  254. cur := cur^.next;
  255. Until cur = hdr;
  256. Close(f);
  257. {$I+}
  258. win^.Hide;
  259. win^.Done;
  260. End;
  261. { make the menu appear active }
  262. Procedure MenuUp;
  263. Begin
  264. With mnu0 Do Begin
  265. SetColor(48);
  266. SetCursorColor(79);
  267. Show;
  268. End;
  269. StatWin.FWrite(1,1,StatWin.GetColor,0,'Esc=Edit');
  270. End;
  271. { make the menu appear inactive }
  272. Procedure MenuDown;
  273. Begin
  274. With mnu0 Do Begin
  275. SetColor(56);
  276. SetCursorColor(56);
  277. Show;
  278. End;
  279. StatWin.FWrite(1,1,StatWin.GetColor,0,'Esc=Menu');
  280. End;
  281. { execute the File submenu }
  282. Procedure Menu_File;
  283. Begin
  284. mnu0.SetIndex(1);
  285. MenuUp;
  286. New(mnu1,Init(1,1,0,3,1,48,79,8,FRAMED,62));
  287. With mnu1^ Do Begin
  288. Add('Open');
  289. Add('Save');
  290. Add('Exit - F10');
  291. Post; { need the item count for move }
  292. Move(1,nMaxRows-Count-2);
  293. Start;
  294. Case Index of
  295. 1 : ReadFile(tf,true);
  296. 2 : SaveFile(tf);
  297. 3 : Finished := true;
  298. End;
  299. Hide;
  300. End;
  301. Dispose(mnu1,Done);
  302. MenuDown;
  303. End;
  304. { display the help screen }
  305. Procedure Help;
  306. Var
  307. hwin : pnWindow;
  308. Begin
  309. mnu0.SetIndex(4);
  310. MenuUp;
  311. New(hwin,Init(1,1,40,20,62,FRAMED,49));
  312. With hwin^ Do Begin
  313. Align(center,center);
  314. PutHeader('Edit_Demo Help',15,center);
  315. FWrite(2, 2,63,0,'Ctrl/Q - Move to column 1');
  316. FWrite(2, 3,63,0,'Ctrl/W - Move to end of line');
  317. FWrite(2, 4,63,0,'Ctrl/A - Move to previous word');
  318. FWrite(2, 5,63,0,'Ctrl/F - Move to next word');
  319. FWrite(2, 6,63,0,'Ctrl/G - Delete character');
  320. FWrite(2, 7,63,0,'Ctrl/H - Destructive Backspace');
  321. FWrite(2, 8,63,0,'Ctrl/D - Move forward one column');
  322. FWrite(2, 9,63,0,'Ctrl/S - Move back one column');
  323. FWrite(2,10,63,0,'Ctrl/I - Toggle Insert/Overwrite');
  324. FWrite(2,11,63,0,'Ctrl/P - Embed control character');
  325. FWrite(2,12,63,0,'Ctrl/L - Goto line number');
  326. FWrite(2,13,63,0,'Ctrl/N - Insert new line');
  327. FWrite(2,14,63,0,'Ctrl/Y - Delete current line');
  328. FWrite(2,15,63,0,'Ctrl/X - Move down one line');
  329. FWrite(2,16,63,0,'Ctrl/E - Move up one line');
  330. FWrite(2,17,63,0,'Esc/1..0 - F1..F10');
  331. Show;
  332. Repeat Until Keypressed;
  333. While KeyPressed Do ReadKey;
  334. Hide;
  335. End;
  336. Dispose(hwin,Done);
  337. MenuDown;
  338. End;
  339. { goto the specified line in the edit buffer }
  340. Function GotoLine : boolean;
  341. Var
  342. gwin : pnWindow;
  343. l,
  344. ii : longint;
  345. esc : boolean;
  346. aline : pline;
  347. Begin
  348. New(gwin,Init(1,1,40,3,62,FRAMED,49));
  349. With gwin^ Do Begin
  350. Align(center,center);
  351. PutHeader('Goto Line Number',15,center);
  352. FWrite(2,1,63,0,'Line: ');
  353. Show;
  354. ec.ClearMode := true;
  355. ii := EditNumber(8,1,63,8,0,'',cline,1,lines,esc);
  356. { If esc or not (i in [1..lines]) Then i := ii;}
  357. Hide;
  358. End;
  359. Dispose(gwin,Done);
  360. If Not esc Then Begin
  361. l := 0;
  362. aline := hdr;
  363. Repeat
  364. inc(l);
  365. aline := aline^.next;
  366. Until (l = ii);
  367. line1 := aline;
  368. cline := l;
  369. End;
  370. GotoLine := (Not esc);
  371. End;
  372. { initialize the global stuff }
  373. Procedure EditInit;
  374. Begin
  375. With mnu0 Do Begin
  376. Init(1,1,45,1,5,56,56,7,NOFRAME,0);
  377. Add('File');
  378. Add('InsLn');
  379. Add('DelLn');
  380. Add('Help');
  381. Add('Exit');
  382. Post;
  383. Align(left,bottom);
  384. End;
  385. With StatWin Do Begin
  386. Init(1,1,nStdScr.Cols-(mnu0.Wind^.Cols),1,48,NOFRAME,0);
  387. Align(right,bottom);
  388. Show;
  389. End;
  390. MenuDown;
  391. With EdWin Do Begin
  392. Init(1,1,nStdScr.Cols,nStdScr.Rows-1,30,FRAMED,31);
  393. PutHeader(' oCrt Editor Demonstration ',15,center);
  394. Show;
  395. GotoXY(1,1);
  396. {--------------------------------------------------------------------
  397. The next line causes sedit to exit after every keystroke so we can
  398. capture the insert mode and cursor positions for display update.
  399. Alternatively, we could setup an ec.Special string to exit only on
  400. certain keystrokes of interest.
  401. --------------------------------------------------------------------}
  402. ec.ExitMode := true;
  403. { too re-assign a built-in key, put it in ec.special,
  404. then use it in the case statement below
  405. EdWin.ec.Special := EdWin.ec.Special + #5;
  406. }
  407. { now let's bind some keystrokes to the editor window }
  408. ec.AddChMap(^a#0#0+chr(nKeyCtrlLeft));
  409. ec.AddChMap(^s#0#0+chr(nKeyLeft));
  410. ec.AddChMap(^f#0#0+chr(nKeyCtrlRight));
  411. ec.AddChMap(^d#0#0+chr(nKeyRight));
  412. ec.AddChMap(^e#0#0+chr(nKeyUp));
  413. ec.AddChMap(^x#0#0+chr(nKeyDown));
  414. ec.AddChMap(^q#0#0+chr(nKeyHome));
  415. ec.AddChMap(^w#0#0+chr(nKeyEnd));
  416. { define the number of edit window rows }
  417. CURLINES := Min(MAXLINES,Rows);
  418. End;
  419. FillChar(ss,SizeOf(ss),#0);
  420. nEscDelay(250);
  421. idx := 1;
  422. Finished := false;
  423. mactive := false;
  424. ClearLines(hdr);
  425. If ParamCount > 0 Then Begin
  426. fnam := ParamStr(1);
  427. ReadFile(tf,false);
  428. End Else
  429. fnam := '';
  430. { an empty list? }
  431. If hdr^.next = hdr Then Begin
  432. InsertLine(hdr,'');
  433. line1 := hdr^.next;
  434. line := line1;
  435. dlines := 1;
  436. End;
  437. cline := 1;
  438. End;
  439. Begin
  440. EditInit;
  441. Repeat
  442. With EdWin Do Begin
  443. Case ec.InsMode of
  444. true : StatWin.FWrite(11,1,StatWin.GetColor,0,'Ins');
  445. false: StatWin.FWrite(11,1,StatWin.GetColor,0,'Ovr');
  446. End;
  447. Str(WhereX:0,xp);
  448. Str(cline:0,yp);
  449. StatWin.FWrite(16,1,StatWin.GetColor,StatWin.Cols,'Col:'+xp+' Row:'+yp);
  450. If mactive Then Begin
  451. With mnu0 Do Begin
  452. MenuUp;
  453. Start;
  454. Case Index Of
  455. 1 : cv := nkAltF;
  456. 2 : cv := nkF1;
  457. 3 : cv := nkF2;
  458. 4 : cv := nkF3;
  459. 5 : cv := nkF10;
  460. Else cv := 0;
  461. End;
  462. MenuDown;
  463. Show;
  464. End;
  465. mactive := false;
  466. Active;
  467. GotoXY(WhereX,WhereY);
  468. End Else Begin
  469. ss[idx] := Edit(1,idx,26,Cols,WhereX,ss[idx],cv);
  470. FWrite(1,idx,GetColor,Cols,ss[idx]);
  471. ReallocateLine(line,ss[idx]);
  472. End;
  473. Case cv of
  474. 12 : If GotoLine Then Begin
  475. idx := 1;
  476. LoadLines(line1);
  477. DisplayLines;
  478. End;
  479. {5,}
  480. nkUp : Begin
  481. dec(idx);
  482. dec(cline);
  483. If (idx < 1) and (line1^.prev <> hdr) Then Begin
  484. line1 := line1^.prev;
  485. LoadLines(line1);
  486. DisplayLines;
  487. End;
  488. End;
  489. nkDown : Begin
  490. inc(idx);
  491. inc(cline);
  492. If idx > CURLINES Then Begin
  493. line1 := line1^.next;
  494. LoadLines(line1);
  495. DisplayLines;
  496. End;
  497. End;
  498. nkPgUp : Begin
  499. For xi := 1 to CURLINES Do Begin
  500. line1 := line1^.prev;
  501. dec(cline);
  502. If line1 = hdr Then
  503. line1 := line1^.next;
  504. End;
  505. LoadLines(line1);
  506. DisplayLines;
  507. End;
  508. nkPgDn : Begin
  509. If dlines = CURLINES Then Begin
  510. For xi := 1 to CURLINES Do Begin
  511. inc(cline);
  512. line1 := line1^.next;
  513. If line1 = hdr Then
  514. line1 := line1^.prev;
  515. End;
  516. LoadLines(line1);
  517. DisplayLines;
  518. End;
  519. End;
  520. nkEnter: Begin
  521. GotoXY(1,WhereY);
  522. If line^.next = hdr Then Begin
  523. InsertLine(hdr,'');
  524. If dlines < CURLINES Then inc(dlines);
  525. End;
  526. If idx < CURLINES Then
  527. inc(idx)
  528. Else Begin
  529. line1 := line1^.next;
  530. LoadLines(line1);
  531. DisplayLines;
  532. End;
  533. inc(cline);
  534. End;
  535. 14, { ctrl/n }
  536. nkF1 : Begin
  537. { first displayed line? }
  538. If line1 = line Then Begin
  539. line1 := line1^.prev;
  540. InsertLine(line,'');
  541. line1 := line1^.next;
  542. End Else
  543. InsertLine(line,'');
  544. LoadLines(line1);
  545. DisplayLines;
  546. End;
  547. 25, { ctrl/y }
  548. nkF2 : Begin
  549. { first displayed line? }
  550. If line1 = line Then line1 := line^.next;
  551. DeleteLine(line);
  552. LoadLines(line1);
  553. DisplayLines;
  554. End;
  555. nkAltH,
  556. nkF3 : Help;
  557. nkEsc : mactive := true;
  558. nkF10 : Finished := true;
  559. nkAltF : menu_file;
  560. End;
  561. Active;
  562. If idx > CURLINES Then idx := CURLINES; { keep in window, }
  563. If idx > dlines Then idx := dlines; { but not below last }
  564. If idx < 1 Then idx := 1;
  565. If cline < 1 Then cline := 1;
  566. If cline > lines Then cline := lines;
  567. GotoXY(WhereX,idx);
  568. line := line1;
  569. For xi := 1 to idx-1 Do Begin
  570. line := line^.next;
  571. End;
  572. End;
  573. Until Finished;
  574. ClearLines(hdr);
  575. EdWin.Done;
  576. StatWin.Done;
  577. ClrScr;
  578. End.