door.h 16 KB

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