door.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. #ifndef DOOR_H
  2. #define DOOR_H
  3. #include "anyoption.h"
  4. #include <cstdint>
  5. #include <ctime>
  6. #include <fstream>
  7. #include <functional>
  8. #include <future>
  9. #include <iostream>
  10. #include <memory>
  11. #include <ostream>
  12. #include <vector>
  13. // raw mode
  14. #include <termios.h>
  15. #include <unistd.h>
  16. #define CSI "\x1b["
  17. // getkey definitions
  18. #define XKEY_START 0x1000
  19. #define XKEY_UP_ARROW 0x1001
  20. #define XKEY_DOWN_ARROW 0x1002
  21. #define XKEY_RIGHT_ARROW 0x1003
  22. #define XKEY_LEFT_ARROW 0x1004
  23. #define XKEY_HOME 0x1010
  24. #define XKEY_END 0x1011
  25. #define XKEY_PGUP 0x1012
  26. #define XKEY_PGDN 0x1023
  27. #define XKEY_INSERT 0x1024
  28. #define XKEY_DELETE 0x7f
  29. #define XKEY_F1 0x1021
  30. #define XKEY_F2 0x1022
  31. #define XKEY_F3 0x1023
  32. #define XKEY_F4 0x1024
  33. #define XKEY_F5 0x1025
  34. #define XKEY_F6 0x1026
  35. #define XKEY_F7 0x1027
  36. #define XKEY_F8 0x1028
  37. #define XKEY_F9 0x1029
  38. #define XKEY_F10 0x102a
  39. #define XKEY_F11 0x102b
  40. #define XKEY_F12 0x102c
  41. #define XKEY_UNKNOWN 0x1111
  42. /**
  43. * @brief The BBS door project.
  44. * This is an attempt at writing a C++ BBS door toolkit.
  45. */
  46. namespace door {
  47. extern bool unicode;
  48. extern bool debug_capture;
  49. /*
  50. Translate CP437 strings to unicode for output.
  51. if (door::unicode) {
  52. // perform translation
  53. }
  54. */
  55. void cp437toUnicode(std::string input, std::string &out);
  56. void cp437toUnicode(const char *input, std::string &out);
  57. /*
  58. door 2.0
  59. */
  60. /**
  61. * ANSI Color codes
  62. */
  63. /**
  64. * @brief The colors available under ANSI-BBS
  65. */
  66. enum class COLOR : std::int8_t {
  67. /// BLACK (0)
  68. BLACK,
  69. /// RED (1)
  70. RED,
  71. /// GREEN (2)
  72. GREEN,
  73. /// BROWN (3)
  74. BROWN,
  75. /// YELLOW (3)
  76. YELLOW = 3,
  77. /// BLUE (4)
  78. BLUE,
  79. /// MAGENTA (5)
  80. MAGENTA,
  81. /// CYAN (6)
  82. CYAN,
  83. /// WHITE (7)
  84. WHITE
  85. };
  86. /**
  87. * @brief ANSI-BBS text attributes
  88. */
  89. enum class ATTR : std::int8_t {
  90. /// RESET forces all attributes (and Colors) to be sent.
  91. RESET,
  92. /// BOLD is the same as BRIGHT.
  93. BOLD,
  94. /// BRIGHT is the same as BOLD.
  95. BRIGHT = 1,
  96. /// SLOW BLINK
  97. BLINK = 5,
  98. /// INVERSE is Background on Foreground.
  99. INVERSE = 7
  100. };
  101. /**
  102. * @class ANSIColor
  103. * This holds foreground, background and ANSI-BBS attribute
  104. * information.
  105. * The special attribute RESET forces attribute and color
  106. * output always.
  107. *
  108. * @brief Foreground, Background and Attributes
  109. *
  110. */
  111. class ANSIColor {
  112. /// Foreground color
  113. COLOR fg;
  114. /// Background color
  115. COLOR bg;
  116. // Track attributes (ATTR)
  117. /// reset flag / always send color and attributes
  118. unsigned int reset : 1;
  119. /// bold / bright flag
  120. unsigned int bold : 1;
  121. /// blink slow blinking text
  122. unsigned int blink : 1;
  123. /// inverse
  124. unsigned int inverse : 1;
  125. public:
  126. // default initialization here
  127. ANSIColor();
  128. ANSIColor(ATTR a);
  129. ANSIColor(COLOR f);
  130. ANSIColor(COLOR f, ATTR a);
  131. ANSIColor(COLOR f, ATTR a1, ATTR a2);
  132. ANSIColor(COLOR f, COLOR b);
  133. ANSIColor(COLOR f, COLOR b, ATTR a);
  134. ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2);
  135. ANSIColor &Attr(ATTR a);
  136. bool operator==(const ANSIColor &c) const;
  137. bool operator!=(const ANSIColor &c) const;
  138. /**
  139. * @return std::string
  140. */
  141. std::string output(void) const;
  142. /**
  143. * @param previous the previous attributes and colors
  144. * @return std::string
  145. */
  146. std::string output(ANSIColor &previous) const;
  147. /**
  148. * @param os Output stream
  149. * @param c ANSIColor
  150. * @return std::ostream&
  151. */
  152. friend std::ostream &operator<<(std::ostream &os, const ANSIColor &c);
  153. };
  154. /**
  155. * @class Door
  156. *
  157. * This handles output to the caller, via ostream.
  158. *
  159. */
  160. class Door : public std::ostream, private std::streambuf {
  161. private:
  162. virtual std::streamsize xsputn(const char *s, std::streamsize n);
  163. virtual int overflow(char c);
  164. std::string doorname;
  165. void parse_dropfile(const char *filepath);
  166. void init(void);
  167. std::time_t startup;
  168. struct termios tio_default;
  169. // getkey functions
  170. signed int getch(void);
  171. void unget(char c);
  172. char get(void);
  173. char buffer[5];
  174. unsigned int bpos;
  175. bool has_dropfile;
  176. std::string dropfilename;
  177. vector<std::string> dropfilelines;
  178. ofstream logf;
  179. void detect_unicode_and_screen(void);
  180. // time thread - time left
  181. std::promise<void> stop_thread;
  182. // std::future<void> stop_future;
  183. // atomic seconds_elapsed ?
  184. int seconds_elapsed;
  185. void time_thread_run(std::future<void> future);
  186. std::thread time_thread;
  187. public:
  188. /**
  189. * @param argc int
  190. * @param argv char *[]
  191. */
  192. Door(std::string dname, int argc, char *argv[]);
  193. /// Default copy ctor deleted
  194. Door(Door &) = delete;
  195. virtual ~Door();
  196. void log(std::string output);
  197. AnyOption opt;
  198. std::string debug_buffer;
  199. /**
  200. * Previous ANSI-BBS colors and attributes sent.
  201. * This is used to optimize our output.
  202. * \see ANSIColor::output()
  203. */
  204. ANSIColor previous;
  205. bool track;
  206. int cx;
  207. int cy;
  208. int width;
  209. int height;
  210. int inactivity;
  211. std::string username;
  212. std::string handle;
  213. std::string location;
  214. std::string sysop;
  215. // std::string bbsname;
  216. int node;
  217. atomic<int> time_left;
  218. signed int getkey(void);
  219. bool haskey(void);
  220. int get_input(void);
  221. signed int sleep_key(int secs);
  222. };
  223. // Use this to define the deprecated colorizer [POC]
  224. // typedef std::function<void(Door &, std::string &)> colorFunction;
  225. /**
  226. * @class ColorOutput
  227. * This works with \ref Render to create the output. This consists
  228. * of ANSIColor and text position + length.
  229. *
  230. * @brief This holds an ANSIColor and text position + length
  231. *
  232. */
  233. class ColorOutput {
  234. public:
  235. ColorOutput();
  236. void reset(void);
  237. /// Color to use for this fragment
  238. ANSIColor c;
  239. /// Starting position of Render.text
  240. int pos;
  241. /// Length
  242. int len;
  243. };
  244. /*
  245. No, don't do this.
  246. Instead, return an iterator/generator.
  247. */
  248. /**
  249. * @class Render
  250. * This holds the string, and a vector that contains ColorOutput parts.
  251. *
  252. * @see Render::output()
  253. *
  254. * @brief Rendering a string with ANSIColor
  255. *
  256. */
  257. class Render {
  258. public:
  259. Render(const std::string txt);
  260. /// Complete text to be rendered.
  261. const std::string text;
  262. /// Vector of ColorOutput object.
  263. std::vector<ColorOutput> outputs;
  264. void output(std::ostream &os);
  265. };
  266. /**
  267. * This defines the render output function. This is used
  268. * to define the setRender functions, as well as the creation
  269. * of render functions.
  270. *
  271. * @brief Render output function
  272. *
  273. */
  274. typedef std::function<Render(const std::string &)> renderFunction;
  275. /**
  276. * This defines the update function.
  277. *
  278. * This updates the text.
  279. */
  280. typedef std::function<std::string(void)> updateFunction;
  281. /**
  282. * @class Clrscr
  283. * Clear the screen
  284. * @brief Clear the screen
  285. */
  286. class Clrscr {
  287. public:
  288. Clrscr(void);
  289. friend std::ostream &operator<<(std::ostream &os, const Clrscr &clr);
  290. };
  291. /**
  292. * Clear the BBS terminal.
  293. *
  294. */
  295. extern Clrscr cls;
  296. /**
  297. * @class NewLine
  298. * Carriage return + Newline
  299. * @brief CR+LF
  300. */
  301. class NewLine {
  302. public:
  303. NewLine(void);
  304. friend std::ostream &operator<<(std::ostream &os, const NewLine &nl);
  305. };
  306. /**
  307. * CRLF
  308. */
  309. extern NewLine nl;
  310. /**
  311. * This resets the colors to normal state.
  312. *
  313. * @brief reset colors to normal
  314. */
  315. extern ANSIColor reset;
  316. /// @deprecated Not used
  317. enum class Justify { NONE, LEFT, RIGHT, CENTER };
  318. /**
  319. * @class Goto
  320. * This handles outputting ANSI codes to position the cursor on the screen.
  321. *
  322. * @brief ANSI Goto X, Y position
  323. */
  324. class Goto {
  325. /// X-Position
  326. int x;
  327. /// Y-Position
  328. int y;
  329. public:
  330. Goto(int xpos, int ypos);
  331. /**
  332. * Default Goto constructor copier
  333. */
  334. Goto(Goto &) = default;
  335. friend std::ostream &operator<<(std::ostream &os, const Goto &g);
  336. };
  337. /* should we try to derive a base class, so you can have multilines of
  338. * multilines? */
  339. class LineBase {
  340. public:
  341. virtual ~LineBase() = default;
  342. virtual bool update(void) = 0;
  343. // friend std::ostream &operator<<(std::ostream &os, const LineBase &lb) = 0;
  344. };
  345. class BasicLine {
  346. private:
  347. std::string text;
  348. bool hasColor;
  349. ANSIColor color;
  350. /// renderFunction to use when rendering Line.
  351. renderFunction render;
  352. /// updateFunction to use when updating.
  353. updateFunction updater;
  354. public:
  355. BasicLine(std::string txt);
  356. BasicLine(std::string txt, ANSIColor c);
  357. BasicLine(const BasicLine &rhs) = default;
  358. virtual ~BasicLine() = default;
  359. bool hasRender(void);
  360. void setText(std::string txt);
  361. void setColor(ANSIColor c);
  362. void setRender(renderFunction rf);
  363. void setUpdater(updateFunction uf);
  364. bool update(void);
  365. friend std::ostream &operator<<(std::ostream &os, const BasicLine &l);
  366. };
  367. class MultiLine {
  368. private:
  369. std::vector<std::shared_ptr<BasicLine>> lines;
  370. public:
  371. MultiLine();
  372. void append(std::shared_ptr<BasicLine> bl);
  373. bool update(void);
  374. friend std::ostream &operator<<(std::ostream &os, const MultiLine &l);
  375. };
  376. /**
  377. * @class Line
  378. * This holds text and ANSIColor information, and knows how to
  379. * send them out to the Door.
  380. * @brief Text and ANSIColor
  381. */
  382. class Line {
  383. private:
  384. /// Text of the line
  385. std::string text;
  386. /// Do we have color?
  387. bool hasColor;
  388. /// Line color
  389. ANSIColor color;
  390. /// Padding characters
  391. std::string padding;
  392. /// Padding color
  393. ANSIColor paddingColor;
  394. /// renderFunction to use when rendering Line.
  395. renderFunction render;
  396. /// updateFunction to use when updating.
  397. updateFunction updater;
  398. public:
  399. Line(std::string &txt, int width = 0);
  400. Line(const char *txt, int width = 0);
  401. Line(std::string &txt, int width, ANSIColor c);
  402. Line(const char *txt, int width, ANSIColor c);
  403. Line(std::string &txt, int width, renderFunction rf);
  404. Line(const char *txt, int width, renderFunction rf);
  405. Line(const Line &rhs);
  406. // ~Line();
  407. bool hasRender(void);
  408. int length(void); // const;
  409. /**
  410. * @param width int
  411. */
  412. void makeWidth(int width);
  413. /**
  414. * @param padstring std::string &
  415. * @param padColor ANSIColor
  416. */
  417. void setPadding(std::string &padstring, ANSIColor padColor);
  418. /**
  419. * @param padstring const char *
  420. * @param padColor ANSIColor
  421. */
  422. void setPadding(const char *padstring, ANSIColor padcolor);
  423. void setText(std::string &txt);
  424. void setText(const char *txt);
  425. void setColor(ANSIColor c);
  426. void setRender(renderFunction rf);
  427. void setUpdater(updateFunction uf);
  428. bool update(void);
  429. /**
  430. * @todo This might be a problem, because const Line wouldn't
  431. * allow me to track "updates". I.E. I send the line, I'd
  432. * need to change the line's State to "nothing changed".
  433. * Then, if something did change, the next update request would
  434. * be able to know that yes, this does indeed need to be sent.
  435. *
  436. * @bug This also might cause problems if I display a shared
  437. * BasicLine (in multiple places), and then update it. It
  438. * would only update in the first place (the others wouldn't
  439. * show it needs an update).
  440. */
  441. friend std::ostream &operator<<(std::ostream &os, const Line &l);
  442. };
  443. /// Example BlueYellow renderFunction
  444. extern renderFunction rBlueYellow;
  445. /**
  446. * The different Borders supported by Panel.
  447. *
  448. */
  449. enum class BorderStyle {
  450. /// NONE (0)
  451. NONE,
  452. /// SINGLE (1)
  453. SINGLE,
  454. /// DOUBLE (2)
  455. DOUBLE,
  456. /// SINGLE top DOUBLE side (3)
  457. SINGLE_DOUBLE,
  458. /// DOUBLE top SINGLE side (4)
  459. DOUBLE_SINGLE,
  460. /// BLANK (5)
  461. BLANK
  462. };
  463. class Panel {
  464. protected:
  465. int x;
  466. int y;
  467. int width; // or padding ?
  468. BorderStyle border_style;
  469. ANSIColor border_color;
  470. /**
  471. * @todo Fix this to use shared_ptr.
  472. * I don't think unique_ptr is the right way to go with this. I want to reuse
  473. * things, and that means shared_ptr!
  474. *
  475. */
  476. std::vector<std::unique_ptr<Line>> lines;
  477. bool hidden;
  478. // when you show panel, should it mark it as
  479. // redisplay everything?? maybe??
  480. bool shown_once; // ?? maybe shown_once_already ?
  481. std::unique_ptr<Line> title;
  482. int offset;
  483. public:
  484. Panel(int x, int y, int width);
  485. // Panel(const Panel &);
  486. Panel(Panel &) = delete; // default;
  487. Panel(Panel &&ref);
  488. void set(int x, int y);
  489. void setTitle(std::unique_ptr<Line> T, int off = 1);
  490. void setStyle(BorderStyle bs);
  491. void setColor(ANSIColor c);
  492. void hide(void);
  493. void show(void);
  494. void addLine(std::unique_ptr<Line> l);
  495. // bool delLine(std::shared_ptr<Line> l); // ?
  496. /*
  497. void display(void);
  498. void update(void);
  499. */
  500. friend std::ostream &operator<<(std::ostream &os, const Panel &p);
  501. };
  502. /*
  503. Menu - defaults to double lines.
  504. Has colorize for selected item / non-selected.
  505. Arrow keys + ENTER, or keypress to select an item.
  506. [O] Option Displayed Here
  507. [ + ] = c1
  508. O = c2
  509. Remaining UC TEXT = c3
  510. Remaining LC text = c4
  511. // Colors for CS and CU (color selected, color unselected)
  512. */
  513. class Menu : public Panel {
  514. private:
  515. unsigned int chosen;
  516. std::vector<char> options;
  517. renderFunction selectedRender;
  518. renderFunction unselectedRender;
  519. /*
  520. std::function<void(Door &d, std::string &)> selectedColorizer;
  521. std::function<void(Door &d, std::string &)> unselectedColorizer;
  522. */
  523. public:
  524. static renderFunction defaultSelectedRender;
  525. static renderFunction defaultUnselectedRender;
  526. /*
  527. static std::function<void(Door &d, std::string &)> defaultSelectedColorizer;
  528. static std::function<void(Door &d, std::string &)> defaultUnselectedColorizer;
  529. */
  530. Menu(int x, int y, int width);
  531. // Menu(const Menu &);
  532. Menu(const Menu &) = delete;
  533. Menu(Menu &&);
  534. void addSelection(char c, const char *line);
  535. void defaultSelection(int d);
  536. void setRender(bool selected, renderFunction render);
  537. /*
  538. void setColorizer(bool selected,
  539. std::function<void(Door &d, std::string &)> colorizer);
  540. */
  541. int choose(Door &door);
  542. static renderFunction makeRender(ANSIColor c1, ANSIColor c2, ANSIColor c3,
  543. ANSIColor c4);
  544. // static std::function<void(Door &d, std::string &)>
  545. // makeColorizer(ANSIColor c1, ANSIColor c2, ANSIColor c3, ANSIColor c4);
  546. };
  547. class Screen {
  548. private:
  549. bool hidden;
  550. std::vector<std::shared_ptr<Panel>> parts;
  551. public:
  552. Screen(void);
  553. Screen(Screen &) = default;
  554. void addPanel(std::shared_ptr<Panel> p);
  555. bool delPanel(std::shared_ptr<Panel> p); // HMM. Or ptr?
  556. void hide(void);
  557. void show(void);
  558. friend std::ostream &operator<<(std::ostream &os, const Screen &s);
  559. };
  560. /*
  561. screen - contains panels.
  562. - default to 1,1 X 80,24
  563. - refresh(style) could redraw panels by order they were added,
  564. or could redraw panels from top to bottom, left to right.
  565. crazy ideas:
  566. hide panels / z-order
  567. how to handle panel on top of other panels?
  568. Can I have you win + show animated final score calculations?
  569. panel - has X,Y and width, optional length. contains lines.
  570. length could be simply number of "lines".
  571. - has optional border. double/single/Ds/Sd TOPbottom
  572. - has optional title.
  573. - has optional footer.
  574. addLine()
  575. append() - Appends another line to current line.
  576. set(X,Y) - set a "line" at a given X,Y position.
  577. menu - another type of panel, contains menu options/lines.
  578. lightmenu - like above, but allows arrow keys to select menu options.
  579. line - contains text.
  580. (Maybe a "dirty" flag is needed here?)
  581. - has optional (width)
  582. - has optional (justify - L, R, Center)
  583. - has optional padding (# of blank chars)
  584. - has color (of text)
  585. - has formatter/coloring function (to colorize the text)
  586. Example would be one that sets capital letters to one color, lower to another.
  587. Another example would be one that displays Score: XXX, where Score is one
  588. color, : is another, and XXX is yet another. Properly padded, of course.
  589. - has "lambda" function to update the value? (Maybe?)
  590. Idea would be that I could update the score, and panel.update(). It would
  591. call all the line.update() functions and only update anything that has
  592. changed.
  593. Crazy ideas:
  594. Can I delete a line, and have it automatically removed from a panel?
  595. lightline - text, changes format/coloring if focus/nofocus is set?
  596. */
  597. } // namespace door
  598. #endif