tvg.mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. IMPLEMENTATION MODULE tvg;
  2. (* Graphics backend: renders tv's cell buffer with tigr and feeds tigr input
  3. back as tv events. See tvg.def. *)
  4. FROM SYSTEM IMPORT ADDRESS, ADR, CAST, BYTE;
  5. FROM tigr IMPORT TigrPtr, tigrWindow, tigrFree, tigrUpdate, tigrClosed,
  6. tigrFill, tigrBlitTint, tigrBitmap, tigrClear, tigrPlot,
  7. tigrBlitMode, TPixelType, TIGR_BLEND_ALPHA,
  8. tigrMouse, tigrKeyDown, tigrReadChar,
  9. TIGR_FIXED,
  10. TK_ESCAPE, TK_RETURN, TK_TAB, TK_BACKSPACE, TK_SPACE,
  11. TK_LEFT, TK_RIGHT, TK_UP, TK_DOWN, TK_HOME, TK_END,
  12. TK_PAGEUP, TK_PAGEDN, TK_INSERT, TK_DELETE,
  13. TK_F1, TK_F2, TK_F3, TK_F4, TK_F5, TK_F6,
  14. TK_F7, TK_F8, TK_F9, TK_F10, TK_F11, TK_F12;
  15. IMPORT tv;
  16. IMPORT tvfont;
  17. VAR
  18. bmp : TigrPtr;
  19. fontBmp : TigrPtr;
  20. cw, ch : INTEGER;
  21. qe : ARRAY [0..63] OF tv.Event;
  22. qh, qn : INTEGER;
  23. prevLeft : BOOLEAN;
  24. prevRight : BOOLEAN;
  25. prevMiddle : BOOLEAN;
  26. prevX, prevY : INTEGER;
  27. closedFlag : BOOLEAN;
  28. (*========================================================================*)
  29. (* Colours *)
  30. (*========================================================================*)
  31. PROCEDURE Pal (i : INTEGER) : TPixelType;
  32. VAR p : TPixelType; r, g, b : INTEGER;
  33. BEGIN
  34. CASE i OF
  35. 0 : r:=0; g:=0; b:=0;
  36. | 1 : r:=0; g:=0; b:=170;
  37. | 2 : r:=0; g:=170; b:=0;
  38. | 3 : r:=0; g:=170; b:=170;
  39. | 4 : r:=170; g:=0; b:=0;
  40. | 5 : r:=170; g:=0; b:=170;
  41. | 6 : r:=170; g:=85; b:=0;
  42. | 7 : r:=170; g:=170; b:=170;
  43. | 8 : r:=85; g:=85; b:=85;
  44. | 9 : r:=85; g:=85; b:=255;
  45. | 10 : r:=85; g:=255; b:=85;
  46. | 11 : r:=85; g:=255; b:=255;
  47. | 12 : r:=255; g:=85; b:=85;
  48. | 13 : r:=255; g:=85; b:=255;
  49. | 14 : r:=255; g:=255; b:=85;
  50. ELSE
  51. r:=255; g:=255; b:=255
  52. END;
  53. p.r := VAL(BYTE, r); p.g := VAL(BYTE, g);
  54. p.b := VAL(BYTE, b); p.a := VAL(BYTE, 255);
  55. RETURN p
  56. END Pal;
  57. PROCEDURE Fg (attr : CARDINAL) : TPixelType;
  58. BEGIN RETURN Pal(VAL(INTEGER, attr MOD 16)) END Fg;
  59. PROCEDURE Bg (attr : CARDINAL) : TPixelType;
  60. BEGIN RETURN Pal(VAL(INTEGER, (attr DIV 16) MOD 16)) END Bg;
  61. (*========================================================================*)
  62. (* Font / cells *)
  63. (*========================================================================*)
  64. PROCEDURE Bit (b : BYTE; k : INTEGER) : BOOLEAN;
  65. VAR m, i : INTEGER;
  66. BEGIN
  67. m := 1;
  68. FOR i := 1 TO k DO m := m * 2 END;
  69. RETURN (VAL(INTEGER, b) DIV m) MOD 2 = 1
  70. END Bit;
  71. PROCEDURE BuildFont;
  72. VAR g, r, c : INTEGER; white, clear : TPixelType;
  73. BEGIN
  74. fontBmp := tigrBitmap(VAL(CARDINAL, tvfont.NG * tvfont.CW),
  75. VAL(CARDINAL, tvfont.CH));
  76. clear.r := VAL(BYTE, 0); clear.g := VAL(BYTE, 0);
  77. clear.b := VAL(BYTE, 0); clear.a := VAL(BYTE, 0);
  78. tigrClear(fontBmp, clear);
  79. tigrBlitMode(fontBmp, TIGR_BLEND_ALPHA);
  80. white.r := VAL(BYTE, 255); white.g := VAL(BYTE, 255);
  81. white.b := VAL(BYTE, 255); white.a := VAL(BYTE, 255);
  82. FOR g := 0 TO tvfont.NG - 1 DO
  83. FOR r := 0 TO tvfont.CH - 1 DO
  84. FOR c := 0 TO tvfont.CW - 1 DO
  85. IF Bit(tvfont.Row(g, r), tvfont.CW - 1 - c) THEN
  86. tigrPlot(fontBmp,
  87. VAL(CARDINAL, g * tvfont.CW + c),
  88. VAL(CARDINAL, r), white)
  89. END
  90. END
  91. END
  92. END
  93. END BuildFont;
  94. PROCEDURE Seg (px, py, pw, ph : INTEGER; p : TPixelType);
  95. BEGIN
  96. IF (pw > 0) AND (ph > 0) THEN
  97. tigrFill(bmp, VAL(CARDINAL, px), VAL(CARDINAL, py),
  98. VAL(CARDINAL, pw), VAL(CARDINAL, ph), p)
  99. END
  100. END Seg;
  101. PROCEDURE DrawBoxGlyph (cp : CARDINAL; px, py : INTEGER; p : TPixelType);
  102. VAR mx, my : INTEGER;
  103. BEGIN
  104. mx := px + cw DIV 2;
  105. my := py + ch DIV 2;
  106. IF cp = 2500H THEN Seg(px, my, cw, 1, p) (* ─ *)
  107. ELSIF cp = 2502H THEN Seg(mx, py, 1, ch, p) (* │ *)
  108. ELSIF cp = 250CH THEN (* ┌ *)
  109. Seg(mx, my, cw - cw DIV 2, 1, p); Seg(mx, my, 1, ch - ch DIV 2, p)
  110. ELSIF cp = 2510H THEN (* ┐ *)
  111. Seg(px, my, cw DIV 2 + 1, 1, p); Seg(mx, my, 1, ch - ch DIV 2, p)
  112. ELSIF cp = 2514H THEN (* └ *)
  113. Seg(mx, my, cw - cw DIV 2, 1, p); Seg(mx, py, 1, ch DIV 2 + 1, p)
  114. ELSIF cp = 2518H THEN (* ┘ *)
  115. Seg(px, my, cw DIV 2 + 1, 1, p); Seg(mx, py, 1, ch DIV 2 + 1, p)
  116. ELSIF cp = 2550H THEN (* ═ *)
  117. Seg(px, my - 2, cw, 1, p); Seg(px, my + 1, cw, 1, p)
  118. ELSIF cp = 2551H THEN (* ║ *)
  119. Seg(mx - 2, py, 1, ch, p); Seg(mx + 1, py, 1, ch, p)
  120. ELSIF cp = 2554H THEN (* ╔ *)
  121. Seg(mx, my - 2, cw - cw DIV 2, 1, p); Seg(mx, my + 1, cw - cw DIV 2, 1, p);
  122. Seg(mx - 1, my, 1, ch - ch DIV 2, p); Seg(mx + 2, my, 1, ch - ch DIV 2, p)
  123. ELSIF cp = 2557H THEN (* ╗ *)
  124. Seg(px, my - 2, cw DIV 2 + 1, 1, p); Seg(px, my + 1, cw DIV 2 + 1, 1, p);
  125. Seg(mx - 1, my, 1, ch - ch DIV 2, p); Seg(mx + 2, my, 1, ch - ch DIV 2, p)
  126. ELSIF cp = 255AH THEN (* ╚ *)
  127. Seg(mx, my - 2, cw - cw DIV 2, 1, p); Seg(mx, my + 1, cw - cw DIV 2, 1, p);
  128. Seg(mx - 1, py, 1, ch DIV 2 + 1, p); Seg(mx + 2, py, 1, ch DIV 2 + 1, p)
  129. ELSIF cp = 255DH THEN (* ╝ *)
  130. Seg(px, my - 2, cw DIV 2 + 1, 1, p); Seg(px, my + 1, cw DIV 2 + 1, 1, p);
  131. Seg(mx - 1, py, 1, ch DIV 2 + 1, p); Seg(mx + 2, py, 1, ch DIV 2 + 1, p)
  132. END
  133. END DrawBoxGlyph;
  134. PROCEDURE DrawCell (x, y : INTEGER; cp, attr : CARDINAL);
  135. VAR px, py, g : INTEGER; p : TPixelType;
  136. BEGIN
  137. px := x * cw; py := y * ch;
  138. Seg(px, py, cw, ch, Bg(attr));
  139. IF cp >= 20H THEN
  140. p := Fg(attr);
  141. IF (cp >= 2500H) AND (cp <= 257FH) THEN
  142. DrawBoxGlyph(cp, px, py, p)
  143. ELSE
  144. g := tvfont.Index(cp);
  145. IF g < 0 THEN g := tvfont.Index(VAL(CARDINAL, ORD('?'))) END;
  146. IF g >= 0 THEN
  147. tigrBlitTint(bmp, fontBmp,
  148. VAL(CARDINAL, px), VAL(CARDINAL, py),
  149. VAL(CARDINAL, g * tvfont.CW), 0,
  150. VAL(CARDINAL, tvfont.CW), VAL(CARDINAL, tvfont.CH), p)
  151. END
  152. END
  153. END
  154. END DrawCell;
  155. PROCEDURE BlitAll;
  156. VAR x, y : INTEGER; cp, attr : CARDINAL;
  157. BEGIN
  158. FOR y := 0 TO tv.Rows() - 1 DO
  159. FOR x := 0 TO tv.Cols() - 1 DO
  160. tv.CellAt(x, y, cp, attr);
  161. DrawCell(x, y, cp, attr)
  162. END
  163. END
  164. END BlitAll;
  165. (*========================================================================*)
  166. (* Event queue *)
  167. (*========================================================================*)
  168. PROCEDURE Enq (e : tv.Event);
  169. BEGIN
  170. IF qn < 64 THEN
  171. qe[(qh + qn) MOD 64] := e;
  172. qn := qn + 1
  173. END
  174. END Enq;
  175. PROCEDURE EnqKey (k : INTEGER);
  176. VAR e : tv.Event;
  177. BEGIN
  178. e.kind := tv.evKey; e.key := k; e.ch := 0; e.ctrl := FALSE;
  179. e.mx := 0; e.my := 0; e.mbtn := 0;
  180. e.mpressed := FALSE; e.mreleased := FALSE; e.mwheel := 0;
  181. Enq(e)
  182. END EnqKey;
  183. PROCEDURE EnqChar (cp : CARDINAL);
  184. VAR e : tv.Event;
  185. BEGIN
  186. e.kind := tv.evKey; e.key := tv.kChar; e.ch := cp; e.ctrl := FALSE;
  187. e.mx := 0; e.my := 0; e.mbtn := 0;
  188. e.mpressed := FALSE; e.mreleased := FALSE; e.mwheel := 0;
  189. Enq(e)
  190. END EnqChar;
  191. PROCEDURE EnqMouse (mx, my, btn : INTEGER; pressed, released : BOOLEAN;
  192. wheel : INTEGER);
  193. VAR e : tv.Event;
  194. BEGIN
  195. e.kind := tv.evMouse; e.key := tv.kNone; e.ch := 0; e.ctrl := FALSE;
  196. e.mx := mx DIV cw; e.my := my DIV ch; e.mbtn := btn;
  197. e.mpressed := pressed; e.mreleased := released; e.mwheel := wheel;
  198. Enq(e)
  199. END EnqMouse;
  200. (*========================================================================*)
  201. (* Input *)
  202. (*========================================================================*)
  203. PROCEDURE Pump;
  204. VAR mx, my : CARDINAL; buttons : CARDINAL;
  205. left, right, middle : BOOLEAN; c : CARDINAL;
  206. ix, iy, held : INTEGER;
  207. BEGIN
  208. tigrUpdate(bmp);
  209. IF tigrClosed(bmp) # 0 THEN
  210. IF NOT closedFlag THEN closedFlag := TRUE; EnqKey(tv.kEsc) END
  211. END;
  212. IF tigrKeyDown(bmp, TK_ESCAPE) # 0 THEN EnqKey(tv.kEsc) END;
  213. IF tigrKeyDown(bmp, TK_RETURN) # 0 THEN EnqKey(tv.kEnter) END;
  214. IF tigrKeyDown(bmp, TK_TAB) # 0 THEN EnqKey(tv.kTab) END;
  215. IF tigrKeyDown(bmp, TK_BACKSPACE) # 0 THEN EnqKey(tv.kBack) END;
  216. IF tigrKeyDown(bmp, TK_SPACE) # 0 THEN EnqKey(tv.kSpace) END;
  217. IF tigrKeyDown(bmp, TK_LEFT) # 0 THEN EnqKey(tv.kLeft) END;
  218. IF tigrKeyDown(bmp, TK_RIGHT) # 0 THEN EnqKey(tv.kRight) END;
  219. IF tigrKeyDown(bmp, TK_UP) # 0 THEN EnqKey(tv.kUp) END;
  220. IF tigrKeyDown(bmp, TK_DOWN) # 0 THEN EnqKey(tv.kDown) END;
  221. IF tigrKeyDown(bmp, TK_HOME) # 0 THEN EnqKey(tv.kHome) END;
  222. IF tigrKeyDown(bmp, TK_END) # 0 THEN EnqKey(tv.kEnd) END;
  223. IF tigrKeyDown(bmp, TK_PAGEUP) # 0 THEN EnqKey(tv.kPgUp) END;
  224. IF tigrKeyDown(bmp, TK_PAGEDN) # 0 THEN EnqKey(tv.kPgDn) END;
  225. IF tigrKeyDown(bmp, TK_INSERT) # 0 THEN EnqKey(tv.kIns) END;
  226. IF tigrKeyDown(bmp, TK_DELETE) # 0 THEN EnqKey(tv.kDel) END;
  227. IF tigrKeyDown(bmp, TK_F1) # 0 THEN EnqKey(tv.kF1) END;
  228. IF tigrKeyDown(bmp, TK_F2) # 0 THEN EnqKey(tv.kF2) END;
  229. IF tigrKeyDown(bmp, TK_F3) # 0 THEN EnqKey(tv.kF3) END;
  230. IF tigrKeyDown(bmp, TK_F4) # 0 THEN EnqKey(tv.kF4) END;
  231. IF tigrKeyDown(bmp, TK_F5) # 0 THEN EnqKey(tv.kF5) END;
  232. IF tigrKeyDown(bmp, TK_F6) # 0 THEN EnqKey(tv.kF6) END;
  233. IF tigrKeyDown(bmp, TK_F7) # 0 THEN EnqKey(tv.kF7) END;
  234. IF tigrKeyDown(bmp, TK_F8) # 0 THEN EnqKey(tv.kF8) END;
  235. IF tigrKeyDown(bmp, TK_F9) # 0 THEN EnqKey(tv.kF9) END;
  236. IF tigrKeyDown(bmp, TK_F10) # 0 THEN EnqKey(tv.kF10) END;
  237. IF tigrKeyDown(bmp, TK_F11) # 0 THEN EnqKey(tv.kF11) END;
  238. IF tigrKeyDown(bmp, TK_F12) # 0 THEN EnqKey(tv.kF12) END;
  239. LOOP
  240. c := tigrReadChar(bmp);
  241. IF c = 0 THEN EXIT END;
  242. IF c >= 20H THEN EnqChar(c) END
  243. END;
  244. tigrMouse(bmp, mx, my, buttons);
  245. ix := VAL(INTEGER, mx); iy := VAL(INTEGER, my);
  246. left := (buttons MOD 2) = 1;
  247. right := ((buttons DIV 2) MOD 2) = 1;
  248. middle := ((buttons DIV 4) MOD 2) = 1;
  249. IF left AND (NOT prevLeft) THEN EnqMouse(ix, iy, 1, TRUE, FALSE, 0) END;
  250. IF (NOT left) AND prevLeft THEN EnqMouse(ix, iy, 1, FALSE, TRUE, 0) END;
  251. IF right AND (NOT prevRight) THEN EnqMouse(ix, iy, 2, TRUE, FALSE, 0) END;
  252. IF (NOT right) AND prevRight THEN EnqMouse(ix, iy, 2, FALSE, TRUE, 0) END;
  253. IF middle AND (NOT prevMiddle) THEN EnqMouse(ix, iy, 3, TRUE, FALSE, 0) END;
  254. IF (NOT middle) AND prevMiddle THEN EnqMouse(ix, iy, 3, FALSE, TRUE, 0) END;
  255. held := 0;
  256. IF left THEN held := 1
  257. ELSIF right THEN held := 2
  258. ELSIF middle THEN held := 3 END;
  259. IF (ix # prevX) OR (iy # prevY) OR
  260. (left # prevLeft) OR (right # prevRight) OR (middle # prevMiddle) THEN
  261. EnqMouse(ix, iy, held, FALSE, FALSE, 0)
  262. END;
  263. prevX := ix; prevY := iy;
  264. prevLeft := left; prevRight := right; prevMiddle := middle
  265. END Pump;
  266. PROCEDURE ReadEvent (VAR e : Event) : BOOLEAN;
  267. BEGIN
  268. IF qn = 0 THEN Pump END;
  269. IF qn = 0 THEN RETURN FALSE END;
  270. e := qe[qh];
  271. qh := (qh + 1) MOD 64;
  272. qn := qn - 1;
  273. RETURN TRUE
  274. END ReadEvent;
  275. (*========================================================================*)
  276. (* Lifecycle *)
  277. (*========================================================================*)
  278. PROCEDURE InitGfx (title : ARRAY OF CHAR; cols, rows : INTEGER) : BOOLEAN;
  279. VAR discard : INTEGER; ww, hh : INTEGER;
  280. BEGIN
  281. cw := tvfont.CW; ch := tvfont.CH;
  282. BuildFont;
  283. IF cols < 10 THEN cols := 80 END;
  284. IF rows < 3 THEN rows := 30 END;
  285. ww := cols * cw; hh := rows * ch;
  286. bmp := tigrWindow(VAL(CARDINAL, ww), VAL(CARDINAL, hh), title, TIGR_FIXED);
  287. IF bmp = NIL THEN RETURN FALSE END;
  288. IF NOT tv.InitVirtual(cols, rows) THEN RETURN FALSE END;
  289. qh := 0; qn := 0;
  290. prevLeft := FALSE; prevRight := FALSE; prevMiddle := FALSE;
  291. prevX := -1; prevY := -1;
  292. closedFlag := FALSE;
  293. BlitAll;
  294. tigrUpdate(bmp);
  295. RETURN TRUE
  296. END InitGfx;
  297. PROCEDURE Finish;
  298. BEGIN
  299. tv.DrawTree;
  300. BlitAll
  301. END Finish;
  302. PROCEDURE Closed () : BOOLEAN;
  303. BEGIN RETURN closedFlag END Closed;
  304. PROCEDURE CellW () : INTEGER;
  305. BEGIN RETURN cw END CellW;
  306. PROCEDURE CellH () : INTEGER;
  307. BEGIN RETURN ch END CellH;
  308. PROCEDURE Done;
  309. BEGIN
  310. IF bmp # NIL THEN tigrFree(bmp); bmp := NIL END;
  311. IF fontBmp # NIL THEN tigrFree(fontBmp); fontBmp := NIL END
  312. END Done;
  313. END tvg.