door.h 16 KB

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