tpad.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. {
  2. Author: Vitaliy Trifonov
  3. }
  4. program pad_demo;
  5. {$MODE OBJFPC}
  6. {$IFDEF DEBUG}
  7. {$ASSERTIONS ON}
  8. {$OVERFLOWCHECKS ON}
  9. {$RANGECHECKS ON}
  10. {$CHECKPOINTER ON}
  11. {$ENDIF}
  12. uses
  13. ncurses, panel, sysutils;
  14. type
  15. TNcCoord = array[0..1] of Smallint;
  16. TNcStr = packed record
  17. str: AnsiString;
  18. attr: attr_t;
  19. coord: TNcCoord;
  20. end;
  21. const y = 0; x = 1;
  22. function CTRL( ch: chtype ): chtype; inline;
  23. begin
  24. CTRL := ch AND $001F
  25. end;
  26. function randomchar: chtype;
  27. var
  28. ch: Char = #0;
  29. begin
  30. while not (ch in ['0'..'9','A'..'Z','a'..'z']) do
  31. ch := Char(Random(123));
  32. randomchar := chtype(ch);
  33. end;
  34. function randompair: longint;
  35. var
  36. pair: longint = 0;
  37. begin
  38. while not (pair in [1..5]) do
  39. pair := Random(6);
  40. randompair := pair;
  41. end;
  42. procedure draw;
  43. var
  44. y, x: Smallint;
  45. begin
  46. for y := 0 to LINES - 1 do
  47. for x := 0 to COLS - 1 do
  48. mvaddch(y, x, randomchar OR COLOR_PAIR(randompair));
  49. end;
  50. procedure draw_pad(win: PWINDOW);
  51. var
  52. y, x, my, mx: Smallint;
  53. begin
  54. getmaxyx(win,my,mx);
  55. wborder(win, ACS_CKBOARD,ACS_CKBOARD,ACS_CKBOARD,ACS_CKBOARD,
  56. ACS_CKBOARD,ACS_CKBOARD,ACS_CKBOARD,ACS_CKBOARD);
  57. for y := 1 to my - 2 do
  58. if (y mod 5) = 1 then
  59. for x := 1 to mx - 2 do
  60. if (x mod 10) = 1 then
  61. mvwaddch(win, y, x, randomchar OR COLOR_PAIR(randompair))
  62. else
  63. mvwaddch(win, y, x, ACS_HLINE)
  64. else
  65. for x := 1 to mx - 2 do
  66. if (x mod 10) = 1 then
  67. mvwaddch(win, y, x, ACS_VLINE)
  68. else
  69. mvwaddch(win, y, x, chtype(' '))
  70. end;
  71. function st_middle(scrlen, itemlen: Smallint): Smallint; inline;
  72. begin
  73. st_middle := (scrlen - itemlen) div 2;
  74. end;
  75. procedure print_in_middle(win: PWINDOW; var nstr: TNcStr; width: Longint);
  76. var
  77. my, mx: Smallint;
  78. begin
  79. getmaxyx(win, my, mx);
  80. mx -= nstr.coord[1];
  81. if (width > length(nstr.str)) OR (width < 1) then
  82. width := length(nstr.str);
  83. if width > mx then
  84. width := mx;
  85. nstr.coord[x] += st_middle(mx,width);
  86. wattron(win,nstr.attr);
  87. mvwaddnstr(win,nstr.coord[y],nstr.coord[x],PChar(nstr.str),width);
  88. wattroff(win,nstr.attr);
  89. end;
  90. type
  91. TBarData = packed record
  92. beg, len, slen: Smallint;
  93. end;
  94. TPad = class
  95. private
  96. wyx, pyx, ppos, grid: TNcCoord;
  97. hbar, vbar: TBarData;
  98. padwin, projwin: PWINDOW;
  99. panel: PPANEL;
  100. header: TNcStr;
  101. changed: Boolean;
  102. procedure init_bars;
  103. procedure draw_hbar;
  104. procedure draw_vbar;
  105. public
  106. function scroll_right: Boolean;
  107. function scroll_left: Boolean;
  108. function scroll_down: Boolean;
  109. function scroll_up: Boolean;
  110. function doevent: chtype;
  111. procedure dorefresh;
  112. function move(const ncoord: array of Smallint): Boolean; inline;
  113. function hide: Boolean; inline;
  114. function show: Boolean; inline;
  115. procedure resize;
  116. function resize(const nsize: array of Smallint): Boolean;
  117. constructor create(const parm: array of TNcCoord; const hdr: TNcStr);
  118. destructor destroy; override;
  119. property win: PWINDOW read padwin;
  120. property ysize: Smallint read wyx[y];
  121. property xsize: Smallint read wyx[x];
  122. end;
  123. procedure TPad.init_bars;
  124. function get_scrl_len(blen, wsz, psz: Smallint): Smallint; inline;
  125. begin
  126. get_scrl_len := (blen * wsz) div psz;
  127. end;
  128. begin
  129. hbar.beg := 4;
  130. hbar.len := wyx[x] - hbar.beg * 2;
  131. hbar.slen := get_scrl_len(hbar.len, wyx[x], pyx[x]);
  132. vbar.beg := 2;
  133. vbar.len := wyx[y] - vbar.beg * 2;
  134. vbar.slen := get_scrl_len(vbar.len, wyx[y], pyx[y]);
  135. end;
  136. function get_scrl_beg(ind, slen, blen, wsz, psz, bbeg: Smallint): Smallint;
  137. begin
  138. if psz <> wsz then
  139. get_scrl_beg := (ind * (blen - slen)) div (psz - wsz) + bbeg
  140. else
  141. get_scrl_beg := bbeg;
  142. end;
  143. procedure TPad.draw_hbar;
  144. var
  145. i, sbeg: Smallint;
  146. begin
  147. with hbar do
  148. begin
  149. sbeg := get_scrl_beg(ppos[x],hbar.slen,hbar.len,wyx[x], pyx[x],hbar.beg);
  150. wattron(projwin,header.attr);
  151. for i := beg to beg + len - 1 do
  152. if (i < sbeg) OR (i > sbeg + slen) then
  153. mvwaddch(projwin,wyx[y]-1,i ,ACS_CKBOARD)
  154. else
  155. mvwaddch(projwin,wyx[y]-1,i,ACS_BLOCK);
  156. wattroff(projwin,header.attr);
  157. end
  158. end;
  159. procedure TPad.draw_vbar;
  160. var
  161. i, sbeg: Smallint;
  162. begin
  163. with vbar do
  164. begin
  165. sbeg := get_scrl_beg(ppos[y],vbar.slen,vbar.len,wyx[y], pyx[y],vbar.beg);
  166. wattron(projwin,header.attr);
  167. for i := beg to beg + len - 1 do
  168. if (i < sbeg) OR (i > sbeg + slen) then
  169. mvwaddch(projwin,i,wyx[x]-1,ACS_CKBOARD)
  170. else
  171. mvwaddch(projwin,i,wyx[x]-1,ACS_BLOCK);
  172. wattroff(projwin,header.attr);
  173. end
  174. end;
  175. function TPad.scroll_right: Boolean;
  176. begin
  177. if ppos[x] > 0 then
  178. begin
  179. if (ppos[x] < grid[x]) then
  180. ppos[x] := 0
  181. else
  182. ppos[x] -= grid[x];
  183. draw_hbar;
  184. changed := true;
  185. scroll_right := true
  186. end
  187. else
  188. scroll_right := false
  189. end;
  190. function TPad.scroll_left: Boolean;
  191. var
  192. dwidth: Longint;
  193. begin
  194. dwidth := pyx[x] - wyx[x] + 2;
  195. if ppos[x] < dwidth then
  196. begin
  197. if ppos[x] > (dwidth - grid[x]) then
  198. ppos[x] := dwidth
  199. else
  200. ppos[x] += grid[x];
  201. draw_hbar;
  202. changed := true;
  203. scroll_left := true
  204. end
  205. else
  206. scroll_left := false
  207. end;
  208. function TPad.scroll_down: Boolean;
  209. begin
  210. if ppos[y] > 0 then
  211. begin
  212. if ppos[y] < grid[y] then
  213. ppos[y] := 0
  214. else
  215. ppos[y] -= grid[y];
  216. draw_vbar;
  217. changed := true;
  218. scroll_down := true
  219. end
  220. else
  221. scroll_down := false
  222. end;
  223. function TPad.scroll_up: Boolean;
  224. var
  225. dheight: Longint;
  226. begin
  227. dheight := pyx[y] - wyx[y] + 2;
  228. if ppos[y] < dheight then
  229. begin
  230. if ppos[y] > (dheight - grid[x]) then
  231. ppos[y] := dheight
  232. else
  233. ppos[y] += grid[x];
  234. draw_vbar;
  235. changed := true;
  236. scroll_up := true
  237. end
  238. else
  239. scroll_up := false
  240. end;
  241. function TPad.doevent: chtype;
  242. var
  243. ch: chtype;
  244. rval: Boolean = true;
  245. begin
  246. ch := wgetch(projwin);
  247. case ch of
  248. KEY_DOWN: rval := scroll_up;
  249. KEY_UP: rval := scroll_down;
  250. KEY_LEFT: rval := scroll_right;
  251. KEY_RIGHT: rval := scroll_left;
  252. end;
  253. if not rval then
  254. begin
  255. ncurses.beep();
  256. flash();
  257. end;
  258. doevent := ch
  259. end;
  260. procedure TPad.dorefresh;
  261. var
  262. rval: Longint = OK;
  263. begin
  264. if changed then
  265. begin
  266. rval := copywin(padwin,projwin,ppos[y],ppos[x],1,1,wyx[y]-2,wyx[x]-2, 0);
  267. assert(rval=OK,'copywin error');
  268. if rval = OK then
  269. changed := false;
  270. end
  271. end;
  272. function TPad.move(const ncoord: array of Smallint): Boolean;
  273. begin
  274. move := move_panel(panel, ncoord[y], ncoord[x]) = OK
  275. end;
  276. function TPad.hide: Boolean;
  277. begin
  278. hide := hide_panel(panel) = OK
  279. end;
  280. function TPad.show: Boolean;
  281. begin
  282. show := show_panel(panel) = OK
  283. end;
  284. procedure TPad.resize;
  285. var
  286. nsize: TNcCoord;
  287. doresize: Boolean = false;
  288. begin
  289. getbegyx(projwin,nsize[y],nsize[x]);
  290. nsize[y] += wyx[y];
  291. nsize[x] += wyx[x];
  292. if nsize[y] > LINES then
  293. begin
  294. nsize[y] := LINES; doresize := true
  295. end
  296. else
  297. nsize[y] := wyx[y];
  298. if nsize[x] > COLS then
  299. begin
  300. nsize[x] := COLS; doresize := true
  301. end
  302. else
  303. nsize[x] := wyx[x];
  304. if doresize then
  305. resize(nsize)
  306. end;
  307. function TPad.resize(const nsize: array of Smallint): Boolean;
  308. var
  309. by, bx: Smallint;
  310. domove: Boolean = false;
  311. tcoord: TNcCoord;
  312. begin
  313. if (nsize[y] <= LINES)AND(nsize[x] <= COLS) then
  314. begin
  315. if nsize[y] > pyx[y] + 2 then
  316. tcoord[y] := pyx[y] + 2
  317. else
  318. tcoord[y] := nsize[y];
  319. if nsize[x] > pyx[x] + 2 then
  320. tcoord[x] := pyx[x] + 2
  321. else
  322. tcoord[x] := nsize[x];
  323. getbegyx(projwin, by, bx);
  324. if tcoord[y] + by >= LINES then
  325. begin
  326. by := LINES - tcoord[y]; domove := true
  327. end;
  328. if tcoord[x] + bx >= COLS then
  329. begin
  330. bx := COLS - tcoord[x]; domove := true
  331. end;
  332. if tcoord[x] > (pyx[x] - ppos[x]) then
  333. scroll_right;
  334. if tcoord[y] > (pyx[y] - ppos[y]) then
  335. scroll_down;
  336. hide_panel(panel);
  337. wresize(projwin, tcoord[y], tcoord[x]);
  338. if domove then
  339. move_panel(panel, by, bx);
  340. show_panel(panel);
  341. box(projwin, ACS_VLINE, ACS_HLINE);
  342. getmaxyx(projwin,wyx[y],wyx[x]);
  343. header.coord[y] := 0; header.coord[x] := 0;
  344. print_in_middle(projwin, header, 0);
  345. init_bars;
  346. draw_hbar;
  347. draw_vbar;
  348. changed := true;
  349. resize := true
  350. end
  351. else
  352. resize := false
  353. end;
  354. constructor TPad.create(const parm: array of TNcCoord; const hdr: TNcStr);
  355. {$IFDEF DEBUG}
  356. var
  357. tysz, txsz: Smallint;
  358. {$ENDIF}
  359. begin
  360. if parm[0,y] >= parm[1,y] + 2 then
  361. wyx[y] := parm[1,y] + 2
  362. else
  363. wyx[y] := parm[0,y];
  364. if parm[0,x] >= parm[1,x] + 2 then
  365. wyx[x] := parm[1,x] + 2
  366. else
  367. wyx[x] := parm[0,x];
  368. projwin := newwin(wyx[y], wyx[x], (LINES - wyx[y]) div 2, (COLS - wyx[x]) div 2);
  369. intrflush(projwin, FALSE);
  370. keypad(projwin, TRUE);
  371. box(projwin, ACS_VLINE, ACS_HLINE);
  372. panel := new_panel(projwin);
  373. padwin := newpad(parm[1,y], parm[1,x]);
  374. header := hdr;
  375. pyx := parm[1];
  376. grid := parm[2];
  377. {$IFDEF DEBUG}
  378. getmaxyx(projwin,tysz, txsz);
  379. assert((wyx[y]=tysz)AND(wyx[x]=txsz), 'Invalid window');
  380. getmaxyx(padwin,tysz, txsz);
  381. assert((pyx[y]=tysz)AND(pyx[x]=txsz), 'Invalid pad');
  382. {$ENDIF}
  383. FmtStr(header.str, '%s, pad: h=%d w=%d, win: h=%d w=%d', [hdr.str,pyx[y],pyx[x],wyx[y],wyx[x]]);
  384. print_in_middle(projwin, header, 0);
  385. init_bars;
  386. draw_hbar;
  387. draw_vbar;
  388. changed := true;
  389. end;
  390. destructor TPad.destroy;
  391. begin
  392. del_panel(panel);
  393. delwin(padwin);
  394. delwin(projwin);
  395. end;
  396. procedure init_stdscr;
  397. begin
  398. draw;
  399. attron(COLOR_PAIR(7));
  400. mvaddstr(LINES - 3, 0,'press "+" "-" to resize ');
  401. mvaddstr(LINES - 2, 0,'press UP, DOWN, LEFT, RIGHT to scroll');
  402. mvaddstr(LINES - 1, 0,'press F10 or q to exit ');
  403. attroff(COLOR_PAIR(7));
  404. end;
  405. var
  406. ch: chtype;
  407. ncpad: TPad;
  408. my_bg: Smallint = COLOR_BLACK;
  409. wnd, pad, grid: TNcCoord;
  410. code: Word;
  411. header: TNcStr = (str:'Pad demo';attr:A_NORMAL;coord:(0,0));
  412. begin
  413. try
  414. initscr();
  415. noecho();
  416. clear();
  417. cbreak();
  418. curs_set(0);
  419. keypad(stdscr, TRUE);
  420. meta(stdscr, TRUE);
  421. mousemask(1, nil);
  422. if has_colors() then
  423. begin
  424. start_color();
  425. if (use_default_colors() = OK) then
  426. my_bg := -1
  427. else
  428. my_bg := COLOR_BLACK;
  429. init_pair(1, COLOR_YELLOW, my_bg);
  430. init_pair(2, COLOR_MAGENTA, my_bg);
  431. init_pair(3, COLOR_WHITE, my_bg);
  432. init_pair(4, COLOR_CYAN, my_bg);
  433. init_pair(5, COLOR_GREEN, my_bg);
  434. init_pair(6, COLOR_WHITE, COLOR_BLUE);
  435. init_pair(7, COLOR_BLACK, COLOR_YELLOW);
  436. end;
  437. init_stdscr;
  438. //refresh();
  439. wnd[y] := LINES - 6;
  440. wnd[x] := COLS - 12;
  441. pad[y] := wnd[y] + 6;
  442. pad[x] := wnd[x] + 6;
  443. grid[y] := 3;
  444. grid[x] := 3;
  445. if paramcount > 1 then
  446. begin
  447. val(ParamStr(1),pad[y],code);
  448. val(ParamStr(2),pad[x],code);
  449. end;
  450. if paramcount > 3 then
  451. begin
  452. val(ParamStr(3),wnd[y],code);
  453. val(ParamStr(4),wnd[x],code);
  454. end;
  455. header.attr := COLOR_PAIR(6);
  456. ncpad := TPad.create([wnd,pad,grid],header);
  457. draw_pad(ncpad.win);
  458. ncpad.dorefresh;
  459. update_panels();
  460. doupdate();
  461. repeat
  462. ch := ncpad.doevent;
  463. case ch of
  464. chtype('+'): ncpad.resize([ncpad.ysize + 1,ncpad.xsize + 1]);
  465. chtype('='): ncpad.resize([ncpad.ysize + 1,ncpad.xsize + 1]);
  466. chtype('-'): ncpad.resize([ncpad.ysize - 1,ncpad.xsize - 1]);
  467. chtype(' '): ncpad.resize([wnd[y],wnd[x]]);
  468. KEY_RESIZE:
  469. begin
  470. flash();
  471. init_stdscr;
  472. ncpad.resize;
  473. end;
  474. end;
  475. ncpad.dorefresh;
  476. update_panels();
  477. doupdate();
  478. until (ch = chtype('q')) OR (ch = KEY_F(10));
  479. finally
  480. ncpad.destroy;
  481. curs_set(1);
  482. endwin();
  483. end;
  484. end.