nimbox.nim 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. include nimbox/termbox
  2. type
  3. Nimbox* = object of RootObj
  4. Modifier* {.pure.} = enum
  5. Ctrl
  6. Alt
  7. Symbol* {.pure.} = enum
  8. Character
  9. F1
  10. F2
  11. F3
  12. F4
  13. F5
  14. F6
  15. F7
  16. F8
  17. F9
  18. F10
  19. F11
  20. F12
  21. Insert
  22. Delete
  23. Home
  24. End
  25. Pgup
  26. Pgdn
  27. Up
  28. Down
  29. Left
  30. Right
  31. Escape
  32. Space
  33. Tab
  34. Enter
  35. Backspace
  36. Mouse* {.pure.} = enum
  37. Motion
  38. Left
  39. Right
  40. Middle
  41. Release
  42. WheelUp
  43. WheelDown
  44. EventType* {.pure.} = enum
  45. None # Better than a nil Event, because it can be matched with case
  46. Key
  47. Resize
  48. Mouse
  49. Event* = object of RootObj
  50. case kind*: EventType
  51. of EventType.Key:
  52. mods*: seq[Modifier]
  53. sym*: Symbol
  54. ch*: char
  55. of EventType.Mouse:
  56. action*: Mouse
  57. x*, y*: uint
  58. of EventType.Resize:
  59. w*, h*: uint
  60. of EventType.None: discard
  61. NimboxError* = object of Exception
  62. UnsupportedTerminalError* = object of NimboxError
  63. FailedToOpenTtyError* = object of NimboxError
  64. PipeTrapError* = object of NimboxError
  65. UnknownEventTypeError = object of NimboxError
  66. UnknownKeyError = object of NimboxError
  67. UnknownMouseActionError = object of NimboxError
  68. Color* = enum
  69. clrDefault = TB_DEFAULT
  70. clrBlack = TB_BLACK
  71. clrRed = TB_RED
  72. clrGreen = TB_GREEN
  73. clrYellow = TB_YELLOW
  74. clrBlue = TB_BLUE
  75. clrMagenta = TB_MAGENTA
  76. clrCyan = TB_CYAN
  77. clrWhite = TB_WHITE
  78. Style* = enum
  79. styNone = 0
  80. styBold = TB_BOLD
  81. styUnderline = TB_UNDERLINE
  82. styReverse = TB_REVERSE
  83. InputMode* = enum
  84. inpCurrent = TB_INPUT_CURRENT
  85. inpEsc = TB_INPUT_ESC
  86. inpAlt = TB_INPUT_ALT
  87. inpMouse = TB_INPUT_MOUSE
  88. OutputMode* = enum
  89. outCurrent = TB_OUTPUT_CURRENT
  90. outNormal = TB_OUTPUT_NORMAL
  91. out256 = TB_OUTPUT_256
  92. out216 = TB_OUTPUT_216
  93. outGrayscale = TB_OUTPUT_GRAYSCALE
  94. proc `and`*[T](a, b: T): int =
  95. ord(a) or ord(b)
  96. # Setup
  97. proc newNimbox*(): Nimbox =
  98. result = Nimbox()
  99. case tbInit():
  100. of -1: raise newException(UnsupportedTerminalError, "")
  101. of -2: raise newException(FailedToOpenTtyError, "")
  102. of -3: raise newException(PipeTrapError, "")
  103. else: discard
  104. proc `inputMode=`*(_: Nimbox, mode: int) =
  105. discard tbSelectInputMode(cast[cint](mode))
  106. proc `inputMode=`*(nb: Nimbox, mode: InputMode) =
  107. nb.inputMode = ord(mode)
  108. proc `outputMode=`*(_: Nimbox, mode: int) =
  109. discard tbSelectOutputMode(cast[cint](mode))
  110. proc `outputMode=`*(nb: Nimbox, mode: OutputMode) =
  111. nb.outputMode = ord(mode)
  112. proc shutdown*(_: Nimbox) =
  113. tbShutdown()
  114. # Attributes
  115. proc `width`*(_: Nimbox): int =
  116. tbWidth()
  117. proc `height`*(_: Nimbox): int =
  118. tbHeight()
  119. # Display procedures
  120. proc clear*(_: Nimbox) =
  121. tbClear()
  122. proc present*(_: Nimbox) =
  123. tbPresent()
  124. proc print*[T](_: Nimbox, x, y: int, text: string,
  125. fg: Color, bg: Color, style: T) =
  126. var styleInt: int
  127. when style is Style:
  128. styleInt = ord(style)
  129. elif style is int:
  130. styleInt = style
  131. var
  132. fgInt = cast[uint16](ord(fg) or styleInt)
  133. bgInt = cast[uint16](ord(bg))
  134. yInt = cast[cint](y)
  135. for i, c in pairs(text):
  136. tbChangeCell(cast[cint](x + i), yInt, ord(c), fgInt, bgInt)
  137. proc print*(nb: Nimbox, x, y: int, text: string,
  138. fg: Color = clrDefault, bg: Color = clrDefault) =
  139. print(nb, x, y, text, fg, bg, styNone)
  140. proc `cursor=`*(_: Nimbox, xy: (int, int)) =
  141. tbSetCursor(cast[cint](xy[0]), cast[cint](xy[1]))
  142. # proc `cursor=`*(nb: Nimbox, _: nil) =
  143. # nb.cursor = (TB_HIDE_CURSOR, TB_HIDE_CURSOR)
  144. # Events
  145. proc toEvent(kind: cint, evt: ref TbEvent): Event =
  146. var evtKind: EventType
  147. case kind:
  148. of TB_EVENT_KEY: evtKind = EventType.Key
  149. of TB_EVENT_RESIZE: evtKind = EventType.Resize
  150. of TB_EVENT_MOUSE: evtKind = EventType.Mouse
  151. of 0: evtKind = EventType.None # Timeout
  152. of -1: raise newException(NimboxError, "") # Unknown error
  153. else: raise newException(UnknownEventTypeError, "")
  154. case evtKind:
  155. of EventType.Key:
  156. var
  157. mods: seq[Modifier] = @[]
  158. ch = chr(evt.ch)
  159. sym = Symbol.Character
  160. if (evt.`mod` and TB_MOD_ALT) != 0:
  161. mods.add(Modifier.Alt)
  162. if ch == '\0':
  163. case evt.key:
  164. # Function keys
  165. of TB_KEY_F1: sym = Symbol.F1
  166. of TB_KEY_F2: sym = Symbol.F2
  167. of TB_KEY_F3: sym = Symbol.F3
  168. of TB_KEY_F4: sym = Symbol.F4
  169. of TB_KEY_F5: sym = Symbol.F5
  170. of TB_KEY_F6: sym = Symbol.F6
  171. of TB_KEY_F7: sym = Symbol.F7
  172. of TB_KEY_F8: sym = Symbol.F8
  173. of TB_KEY_F9: sym = Symbol.F9
  174. of TB_KEY_F10: sym = Symbol.F10
  175. of TB_KEY_F11: sym = Symbol.F11
  176. of TB_KEY_F12: sym = Symbol.F12
  177. # Motion keys
  178. of TB_KEY_INSERT: sym = Symbol.Insert
  179. of TB_KEY_DELETE: sym = Symbol.Delete
  180. of TB_KEY_HOME: sym = Symbol.Home
  181. of TB_KEY_END: sym = Symbol.End
  182. of TB_KEY_PGUP: sym = Symbol.Pgup
  183. of TB_KEY_PGDN: sym = Symbol.Pgdn
  184. of TB_KEY_ARROW_UP: sym = Symbol.Up
  185. of TB_KEY_ARROW_DOWN: sym = Symbol.Down
  186. of TB_KEY_ARROW_LEFT: sym = Symbol.Left
  187. of TB_KEY_ARROW_RIGHT: sym = Symbol.Right
  188. # Control + key
  189. of TB_KEY_CTRL_2:
  190. ch = '2'
  191. mods.add(Modifier.Ctrl)
  192. of TB_KEY_CTRL_4:
  193. ch = '4'
  194. mods.add(Modifier.Ctrl)
  195. of TB_KEY_CTRL_5:
  196. ch = '5'
  197. mods.add(Modifier.Ctrl)
  198. of TB_KEY_CTRL_6:
  199. ch = '6'
  200. mods.add(Modifier.Ctrl)
  201. of TB_KEY_CTRL_7:
  202. ch = '7'
  203. mods.add(Modifier.Ctrl)
  204. of TB_KEY_CTRL_8:
  205. ch = '8'
  206. sym = Symbol.Backspace
  207. mods.add(Modifier.Ctrl)
  208. of TB_KEY_CTRL_A:
  209. ch = 'A'
  210. mods.add(Modifier.Ctrl)
  211. of TB_KEY_CTRL_B:
  212. ch = 'B'
  213. mods.add(Modifier.Ctrl)
  214. of TB_KEY_CTRL_C:
  215. ch = 'C'
  216. mods.add(Modifier.Ctrl)
  217. of TB_KEY_CTRL_D:
  218. ch = 'D'
  219. mods.add(Modifier.Ctrl)
  220. of TB_KEY_CTRL_E:
  221. ch = 'E'
  222. mods.add(Modifier.Ctrl)
  223. of TB_KEY_CTRL_F:
  224. ch = 'F'
  225. mods.add(Modifier.Ctrl)
  226. of TB_KEY_CTRL_G:
  227. ch = 'G'
  228. mods.add(Modifier.Ctrl)
  229. of TB_KEY_CTRL_H:
  230. ch = 'H'
  231. sym = Symbol.Backspace
  232. mods.add(Modifier.Ctrl)
  233. of TB_KEY_CTRL_I:
  234. ch = 'I'
  235. sym = Symbol.Tab
  236. mods.add(Modifier.Ctrl)
  237. of TB_KEY_CTRL_J:
  238. ch = 'J'
  239. mods.add(Modifier.Ctrl)
  240. of TB_KEY_CTRL_K:
  241. ch = 'K'
  242. mods.add(Modifier.Ctrl)
  243. of TB_KEY_CTRL_L:
  244. ch = 'L'
  245. mods.add(Modifier.Ctrl)
  246. of TB_KEY_CTRL_M:
  247. ch = 'M'
  248. sym = Symbol.Enter
  249. mods.add(Modifier.Ctrl)
  250. of TB_KEY_CTRL_N:
  251. ch = 'N'
  252. mods.add(Modifier.Ctrl)
  253. of TB_KEY_CTRL_O:
  254. ch = 'O'
  255. mods.add(Modifier.Ctrl)
  256. of TB_KEY_CTRL_P:
  257. ch = 'P'
  258. mods.add(Modifier.Ctrl)
  259. of TB_KEY_CTRL_Q:
  260. ch = 'Q'
  261. mods.add(Modifier.Ctrl)
  262. of TB_KEY_CTRL_R:
  263. ch = 'R'
  264. mods.add(Modifier.Ctrl)
  265. of TB_KEY_CTRL_S:
  266. ch = 'S'
  267. mods.add(Modifier.Ctrl)
  268. of TB_KEY_CTRL_T:
  269. ch = 'T'
  270. mods.add(Modifier.Ctrl)
  271. of TB_KEY_CTRL_U:
  272. ch = 'U'
  273. mods.add(Modifier.Ctrl)
  274. of TB_KEY_CTRL_V:
  275. ch = 'V'
  276. mods.add(Modifier.Ctrl)
  277. of TB_KEY_CTRL_W:
  278. ch = 'W'
  279. mods.add(Modifier.Ctrl)
  280. of TB_KEY_CTRL_X:
  281. ch = 'X'
  282. mods.add(Modifier.Ctrl)
  283. of TB_KEY_CTRL_Y:
  284. ch = 'Y'
  285. mods.add(Modifier.Ctrl)
  286. of TB_KEY_CTRL_Z:
  287. ch = 'Z'
  288. mods.add(Modifier.Ctrl)
  289. # Spacing
  290. of TB_KEY_SPACE: sym = Symbol.Space
  291. # Control
  292. of TB_KEY_ESC:
  293. sym = Symbol.Escape
  294. ch = '['
  295. mods.add(Modifier.Ctrl)
  296. else: raise newException(UnknownKeyError, $evt.key)
  297. Event(kind: evtKind, mods: mods, ch: ch, sym: sym)
  298. of EventType.Mouse:
  299. var action: Mouse
  300. if (evt.`mod` and TB_MOD_MOTION) != 0:
  301. action = Mouse.Motion
  302. case evt.key:
  303. # Mouse
  304. of TB_KEY_MOUSE_LEFT: action = Mouse.Left
  305. of TB_KEY_MOUSE_RIGHT: action = Mouse.Right
  306. of TB_KEY_MOUSE_MIDDLE: action = Mouse.Middle
  307. of TB_KEY_MOUSE_RELEASE: action = Mouse.Release
  308. of TB_KEY_MOUSE_WHEEL_UP: action = Mouse.WheelUp
  309. of TB_KEY_MOUSE_WHEEL_DOWN: action = Mouse.WheelDown
  310. else: raise newException(UnknownMouseActionError, $evt.key)
  311. Event(kind: evtKind, action: action,
  312. x: cast[uint](evt.x), y: cast[uint](evt.y))
  313. of EventType.Resize:
  314. Event(kind: evtKind, w: cast[uint](evt.w), h: cast[uint](evt.h))
  315. of EventType.None:
  316. Event(kind: evtKind)
  317. proc peekEvent*(_: Nimbox, timeout: int): Event =
  318. var evt: ref TbEvent
  319. new evt
  320. toEvent(tbPeekEvent(evt, cast[cint](timeout)), evt)
  321. proc pollEvent*(_: Nimbox): Event =
  322. var evt: ref TbEvent
  323. new evt
  324. toEvent(tbPollEvent(evt), evt)