door.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. #ifndef DOOR_H
  2. #define DOOR_H
  3. #include <cstdint>
  4. #include <ctime>
  5. #include <fstream>
  6. #include <functional>
  7. #include <future>
  8. #include <iostream>
  9. #include <list>
  10. #include <memory>
  11. #include <ostream>
  12. #include <vector>
  13. #include "anyoption.h"
  14. // raw mode
  15. #include <termios.h>
  16. #include <unistd.h>
  17. #define CSI "\x1b["
  18. // getkey definitions
  19. #define XKEY_START 0x1000
  20. #define XKEY_UP_ARROW 0x1001
  21. #define XKEY_DOWN_ARROW 0x1002
  22. #define XKEY_RIGHT_ARROW 0x1003
  23. #define XKEY_LEFT_ARROW 0x1004
  24. #define XKEY_HOME 0x1010
  25. #define XKEY_END 0x1011
  26. #define XKEY_PGUP 0x1012
  27. #define XKEY_PGDN 0x1023
  28. #define XKEY_INSERT 0x1024
  29. #define XKEY_DELETE 0x7f
  30. #define XKEY_F1 0x1021
  31. #define XKEY_F2 0x1022
  32. #define XKEY_F3 0x1023
  33. #define XKEY_F4 0x1024
  34. #define XKEY_F5 0x1025
  35. #define XKEY_F6 0x1026
  36. #define XKEY_F7 0x1027
  37. #define XKEY_F8 0x1028
  38. #define XKEY_F9 0x1029
  39. #define XKEY_F10 0x102a
  40. #define XKEY_F11 0x102b
  41. #define XKEY_F12 0x102c
  42. #define XKEY_UNKNOWN 0x1111
  43. #define TIMEOUT -1
  44. #define HANGUP -2
  45. #define OUTOFTIME -3
  46. /**
  47. * @brief The BBS door project.
  48. * This is an attempt at writing a C++ BBS door toolkit.
  49. */
  50. namespace door {
  51. extern bool unicode;
  52. extern bool full_cp437;
  53. extern bool debug_capture;
  54. extern std::list<char> pushback;
  55. /*
  56. Translate CP437 strings to unicode for output.
  57. if (door::unicode) {
  58. // perform translation
  59. }
  60. */
  61. void cp437toUnicode(std::string input, std::string &out);
  62. void cp437toUnicode(const char *input, std::string &out);
  63. /*
  64. door 2.0
  65. */
  66. /**
  67. * ANSI Color codes
  68. */
  69. /**
  70. * @brief The colors available under ANSI-BBS
  71. */
  72. enum class COLOR : std::int8_t {
  73. /// BLACK (0)
  74. BLACK,
  75. /// RED (1)
  76. RED,
  77. /// GREEN (2)
  78. GREEN,
  79. /// BROWN (3)
  80. BROWN,
  81. /// YELLOW (3)
  82. YELLOW = 3,
  83. /// BLUE (4)
  84. BLUE,
  85. /// MAGENTA (5)
  86. MAGENTA,
  87. /// CYAN (6)
  88. CYAN,
  89. /// WHITE (7)
  90. WHITE
  91. };
  92. /**
  93. * @brief ANSI-BBS text attributes
  94. */
  95. enum class ATTR : std::int8_t {
  96. /// RESET forces all attributes (and Colors) to be sent.
  97. RESET,
  98. /// BOLD is the same as BRIGHT.
  99. BOLD,
  100. /// BRIGHT is the same as BOLD.
  101. BRIGHT = 1,
  102. /// SLOW BLINK
  103. BLINK = 5,
  104. /// INVERSE is Background on Foreground.
  105. INVERSE = 7
  106. };
  107. constexpr long strhash(const char *txt) {
  108. long result = 0;
  109. for (int x = 0; x < 3; ++x) {
  110. if (txt[x] == 0) break;
  111. result = (result << 8) | txt[x];
  112. }
  113. return result;
  114. };
  115. enum Attribute {
  116. ATTR_NONE = 0x00,
  117. ATTR_BOLD = 0x01,
  118. ATTR_BRIGHT = 0x01,
  119. ATTR_INVERSE = 0x02,
  120. ATTR_BLINK = 0x04,
  121. ATTR_RESET = 0x08,
  122. };
  123. /**
  124. * @class ANSIColor
  125. * This holds foreground, background and ANSI-BBS attribute
  126. * information.
  127. * The special attribute RESET forces attribute and color
  128. * output always.
  129. *
  130. * @brief Foreground, Background and Attributes
  131. *
  132. */
  133. class ANSIColor {
  134. public:
  135. /** Foreground color */
  136. COLOR fg;
  137. /** Background color */
  138. COLOR bg;
  139. // Track attributes (ATTR)
  140. unsigned char attr;
  141. /** reset flag / always send color and attributes */
  142. // unsigned int reset : 1;
  143. /** bold / bright flag */
  144. // unsigned int bold : 1;
  145. /** blink slow blinking text */
  146. // unsigned int blink : 1;
  147. /** inverse */
  148. // unsigned int inverse : 1;
  149. public:
  150. ANSIColor();
  151. constexpr ANSIColor(const char *text)
  152. : fg{COLOR::WHITE}, bg{COLOR::BLACK}, attr{0} {
  153. const char *cp = text;
  154. bool use_on = false;
  155. while (*cp != 0) {
  156. long key = strhash(cp);
  157. switch (key) {
  158. case strhash("BRI"):
  159. attr |= ATTR_BOLD;
  160. break;
  161. case strhash("BOL"):
  162. attr |= ATTR_BOLD;
  163. break;
  164. case strhash("BLI"):
  165. attr |= ATTR_BLINK;
  166. break;
  167. case strhash("INV"):
  168. attr |= ATTR_INVERSE;
  169. break;
  170. case strhash("RES"):
  171. attr |= ATTR_RESET;
  172. break;
  173. case strhash("ON "):
  174. use_on = true;
  175. break;
  176. case strhash("BLU"):
  177. if (use_on)
  178. bg = COLOR::BLUE;
  179. else
  180. fg = COLOR::BLUE;
  181. break;
  182. case strhash("RED"):
  183. if (use_on)
  184. bg = COLOR::RED;
  185. else
  186. fg = COLOR::RED;
  187. break;
  188. case strhash("GRE"):
  189. if (use_on)
  190. bg = COLOR::GREEN;
  191. else
  192. fg = COLOR::GREEN;
  193. break;
  194. case strhash("YEL"):
  195. if (use_on)
  196. bg = COLOR::YELLOW;
  197. else {
  198. fg = COLOR::YELLOW;
  199. attr |= ATTR_BOLD;
  200. }
  201. // if (use_on) throw error!
  202. break;
  203. case strhash("BRO"):
  204. if (use_on)
  205. bg = COLOR::BROWN;
  206. else
  207. fg = COLOR::BROWN;
  208. break;
  209. case strhash("CYA"):
  210. if (use_on)
  211. bg = COLOR::CYAN;
  212. else
  213. fg = COLOR::CYAN;
  214. break;
  215. case strhash("MAG"):
  216. if (use_on)
  217. bg = COLOR::MAGENTA;
  218. else
  219. fg = COLOR::MAGENTA;
  220. break;
  221. case strhash("BLA"):
  222. if (use_on)
  223. bg = COLOR::BLACK;
  224. else
  225. fg = COLOR::BLACK;
  226. break;
  227. case strhash("WHI"):
  228. if (use_on)
  229. bg = COLOR::WHITE;
  230. else
  231. fg = COLOR::WHITE;
  232. break;
  233. }
  234. // skip to the space character
  235. while ((*cp != ' ') && (*cp != 0)) ++cp;
  236. // skip past the space character
  237. while (*cp == ' ') ++cp;
  238. }
  239. };
  240. ANSIColor(ATTR a);
  241. ANSIColor(COLOR f);
  242. ANSIColor(COLOR f, ATTR a);
  243. ANSIColor(COLOR f, ATTR a1, ATTR a2);
  244. ANSIColor(COLOR f, COLOR b);
  245. ANSIColor(COLOR f, COLOR b, ATTR a);
  246. ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2);
  247. ANSIColor &Attr(ATTR a);
  248. bool operator==(const ANSIColor &c) const;
  249. bool operator!=(const ANSIColor &c) const;
  250. void setFg(COLOR f);
  251. void setFg(COLOR f, ATTR a);
  252. void setBg(COLOR b);
  253. /**
  254. * Get the foreground color
  255. * @return COLOR
  256. */
  257. COLOR getFg() { return fg; };
  258. /**
  259. * Get the background color
  260. * @return COLOR
  261. */
  262. COLOR getBg() { return bg; };
  263. void setAttr(ATTR a);
  264. std::string output(void) const;
  265. std::string debug(void);
  266. std::string output(ANSIColor &previous) const;
  267. friend std::ostream &operator<<(std::ostream &os, const ANSIColor &c);
  268. };
  269. /**
  270. * @class Door
  271. *
  272. * This handles output to the caller, via ostream.
  273. */
  274. class Door : public std::ostream, private std::streambuf {
  275. private:
  276. std::streamsize xsputn(const char *s, std::streamsize n) override;
  277. int overflow(int c) override;
  278. /** The name used for logfile */
  279. std::string doorname;
  280. void parse_dropfile(const char *filepath);
  281. void init(void);
  282. std::time_t startup;
  283. /** Initial terminal defaults. */
  284. struct termios tio_default;
  285. signed int getch(void);
  286. signed int getkey_or_pushback(void);
  287. /** Did we read a dropfile? */
  288. bool has_dropfile;
  289. bool debugging;
  290. /** Name of the dropfile. */
  291. std::string dropfilename;
  292. /** Contents of the dropfile. */
  293. vector<std::string> dropfilelines;
  294. /** Logfile */
  295. ofstream logf;
  296. void detect_unicode_and_screen(void);
  297. /** Allow us to stop the time_thread. */
  298. std::promise<void> stop_thread;
  299. /** Used by time_thread to know when a minute has passed. */
  300. int seconds_elapsed;
  301. void time_thread_run(std::future<void> future);
  302. /** Thread used to update time_left and time_used. */
  303. std::thread time_thread;
  304. public:
  305. Door(std::string dname, int argc, char *argv[]);
  306. Door(Door &) = delete;
  307. virtual ~Door();
  308. ofstream &log(void);
  309. /** Commandline options parser. */
  310. AnyOption opt;
  311. /** Buffer that holds the output for testing. */
  312. std::string debug_buffer;
  313. /**
  314. * Previous ANSI-BBS colors and attributes sent.
  315. * This is used to optimize ANSI Color output.
  316. * \see ANSIColor::output()
  317. */
  318. ANSIColor previous;
  319. /** \todo Enable tracking cursor position. */
  320. bool track;
  321. /** \todo Current cursor X position. */
  322. int cx;
  323. /** \todo Current cursor Y position. */
  324. int cy;
  325. /** Detected screen width. \ref Door::detect_unicode_and_screen */
  326. int width;
  327. /** Detected screen height. */
  328. int height;
  329. /**
  330. * @brief Number of seconds before timing out.
  331. *
  332. * When prompting for user input, this is the number of seconds they have to
  333. * respond before we give up and timeout on them. (Default 120/2 minutes)
  334. */
  335. int inactivity;
  336. /** BBS Dropfile username */
  337. std::string username;
  338. /** BBS Dropfile handle */
  339. std::string handle;
  340. /** BBS Dropfile location */
  341. std::string location;
  342. /** BBS Dropfile sysop name */
  343. std::string sysop;
  344. // std::string bbsname;
  345. /** BBS Dropfile node number */
  346. int node;
  347. /** time left in minutes */
  348. atomic<int> time_left;
  349. /** time used in minutes */
  350. atomic<int> time_used;
  351. signed int getkey(void);
  352. bool haskey(void);
  353. signed int sleep_key(int secs);
  354. signed int sleep_ms_key(int msecs);
  355. std::string input_string(int max);
  356. int get_one_of(const char *keys);
  357. };
  358. // Use this to define the deprecated colorizer [POC]
  359. // typedef std::function<void(Door &, std::string &)> colorFunction;
  360. /**
  361. * @class ColorOutput
  362. * This works with \ref Render to create the output. This consists
  363. * of ANSIColor and text position + length.
  364. *
  365. * @brief This holds an ANSIColor and text position + length
  366. *
  367. */
  368. class ColorOutput {
  369. public:
  370. ColorOutput();
  371. void reset(void);
  372. /// Color to use for this fragment
  373. ANSIColor c;
  374. /// Starting position of Render.text
  375. int pos;
  376. /// Length
  377. int len;
  378. };
  379. /*
  380. No, don't do this.
  381. Instead, return an iterator/generator.
  382. */
  383. /**
  384. * @class Render
  385. * This holds the string, and a vector that contains ColorOutput parts.
  386. *
  387. * @see Render::output()
  388. *
  389. * @brief Rendering a string with ANSIColor
  390. *
  391. */
  392. class Render {
  393. /// Complete text to be rendered.
  394. std::string text;
  395. public:
  396. Render(const std::string txt);
  397. /// Vector of ColorOutput object.
  398. std::vector<ColorOutput> outputs;
  399. void append(ANSIColor color, int len = 1);
  400. void output(std::ostream &os);
  401. };
  402. /**
  403. * This defines the render output function. Given the line text, we output the
  404. * color codes needs to display the line.
  405. *
  406. * ~~~{.cpp}
  407. * door::ANSIColor upperColor, lowerColor;
  408. *
  409. * door::RenderFunction render = [upperColor, lowerColor]
  410. * (const std::string &text) -> door::Render {
  411. * door::Render r(text);
  412. * for (char const &c : text) {
  413. * if (std::isupper(c))
  414. * r.append(upperColor);
  415. * else
  416. * r.append(lowerColor);
  417. * }
  418. * return r;
  419. * };
  420. * ~~~
  421. *
  422. * @brief Render output function
  423. *
  424. */
  425. typedef std::function<Render(const std::string &)> renderFunction;
  426. /**
  427. * This defines the update function.
  428. *
  429. * This updates the text.
  430. *
  431. * ~~~{.cpp}
  432. * int score = 0;
  433. *
  434. * door::updateFunction updater = [](void) -> std::string {
  435. * std::string text = "Score: ";
  436. * text += std::to_string(score);
  437. * return text;
  438. * };
  439. *
  440. * fancyLine.setUpdater(updater);
  441. * ~~~
  442. */
  443. typedef std::function<std::string(void)> updateFunction;
  444. /**
  445. * @class Clrscr
  446. * Clear the screen
  447. * @brief Clear the screen
  448. */
  449. class Clrscr {
  450. public:
  451. Clrscr(void);
  452. friend std::ostream &operator<<(std::ostream &os, const Clrscr &clr);
  453. };
  454. /**
  455. * Clear the BBS terminal.
  456. *
  457. */
  458. extern Clrscr cls;
  459. /**
  460. * @class NewLine
  461. * Carriage return + Newline
  462. * @brief CR+LF
  463. */
  464. class NewLine {
  465. public:
  466. NewLine(void);
  467. friend std::ostream &operator<<(std::ostream &os, const NewLine &nl);
  468. };
  469. /**
  470. * CRLF
  471. */
  472. extern NewLine nl;
  473. /**
  474. * This resets the colors to normal state.
  475. *
  476. * @brief reset colors to normal
  477. */
  478. extern ANSIColor reset;
  479. /// @deprecated Not used
  480. enum class Justify { NONE, LEFT, RIGHT, CENTER };
  481. /**
  482. * @class Goto
  483. * This handles outputting ANSI codes to position the cursor on the screen.
  484. *
  485. * @brief ANSI Goto X, Y position
  486. */
  487. class Goto {
  488. /// X-Position
  489. int x;
  490. /// Y-Position
  491. int y;
  492. public:
  493. Goto(int xpos, int ypos);
  494. /**
  495. * Default Goto constructor copier
  496. */
  497. Goto(const Goto &) = default;
  498. void set(int xpos, int ypos);
  499. friend std::ostream &operator<<(std::ostream &os, const Goto &g);
  500. };
  501. extern const char SaveCursor[];
  502. extern const char RestoreCursor[];
  503. #ifdef EXPERIMENTAL
  504. /* should we try to derive a base class, so you can have multilines of
  505. * multilines? */
  506. class LineBase {
  507. public:
  508. virtual ~LineBase() = default;
  509. virtual bool update(void) = 0;
  510. // friend std::ostream &operator<<(std::ostream &os, const LineBase &lb) = 0;
  511. };
  512. class BasicLine {
  513. protected:
  514. std::string text;
  515. bool hasColor;
  516. ANSIColor color;
  517. /// renderFunction to use when rendering Line.
  518. renderFunction render;
  519. /// updateFunction to use when updating.
  520. updateFunction updater;
  521. public:
  522. BasicLine(std::string txt);
  523. BasicLine(std::string txt, ANSIColor c);
  524. BasicLine(const BasicLine &rhs) = default;
  525. virtual ~BasicLine() = default;
  526. bool hasRender(void);
  527. void setText(std::string txt);
  528. void setColor(ANSIColor c);
  529. void setRender(renderFunction rf);
  530. void setUpdater(updateFunction uf);
  531. bool update(void);
  532. friend std::ostream &operator<<(std::ostream &os, const BasicLine &l);
  533. };
  534. class MultiLine {
  535. protected:
  536. std::vector<std::shared_ptr<BasicLine>> lines;
  537. public:
  538. MultiLine();
  539. void append(std::shared_ptr<BasicLine> bl);
  540. bool update(void);
  541. friend std::ostream &operator<<(std::ostream &os, const MultiLine &l);
  542. };
  543. #endif
  544. /**
  545. * @class Line
  546. * This holds text and ANSIColor information, and knows how to
  547. * send them out to the Door.
  548. * @brief Text and ANSIColor
  549. */
  550. class Line {
  551. protected:
  552. /// Text of the line
  553. std::string text;
  554. /// Do we have color?
  555. bool hasColor;
  556. /// Line color
  557. ANSIColor color;
  558. /// Padding characters
  559. std::string padding;
  560. /// Padding color
  561. ANSIColor paddingColor;
  562. /// renderFunction to use when rendering Line.
  563. renderFunction render;
  564. /// updateFunction to use when updating.
  565. updateFunction updater;
  566. int width;
  567. /**
  568. * @param width int
  569. */
  570. // void makeWidth(int width);
  571. public:
  572. Line(const std::string &txt, int width = 0);
  573. Line(const char *txt, int width = 0);
  574. Line(const std::string &txt, int width, ANSIColor c);
  575. Line(const char *txt, int width, ANSIColor c);
  576. Line(const std::string &txt, int width, renderFunction rf);
  577. Line(const char *txt, int width, renderFunction rf);
  578. Line(const Line &rhs);
  579. Line(Line &&rhs);
  580. // ~Line();
  581. bool hasRender(void);
  582. int length(void); // const;
  583. void fit(void);
  584. /**
  585. * @param padstring std::string &
  586. * @param padColor ANSIColor
  587. */
  588. void setPadding(std::string &padstring, ANSIColor padColor);
  589. /**
  590. * @param padstring const char *
  591. * @param padColor ANSIColor
  592. */
  593. void setPadding(const char *padstring, ANSIColor padcolor);
  594. void setText(std::string &txt);
  595. void setText(const char *txt);
  596. const char *getText(void) { return text.c_str(); };
  597. void setColor(ANSIColor c);
  598. void setRender(renderFunction rf);
  599. void setUpdater(updateFunction uf);
  600. bool update(void);
  601. std::string debug(void);
  602. /**
  603. * @todo This might be a problem, because const Line wouldn't
  604. * allow me to track "updates". I.E. I send the line, I'd
  605. * need to change the line's State to "nothing changed".
  606. * Then, if something did change, the next update request would
  607. * be able to know that yes, this does indeed need to be sent.
  608. *
  609. * @bug This also might cause problems if I display a shared
  610. * BasicLine (in multiple places), and then update it. It
  611. * would only update in the first place (the others wouldn't
  612. * show it needs an update).
  613. */
  614. friend std::ostream &operator<<(std::ostream &os, const Line &l);
  615. };
  616. /// Example BlueYellow renderFunction
  617. extern renderFunction rBlueYellow;
  618. /*
  619. Progress Bar Styles:
  620. solid chars.
  621. half step chars.
  622. gradient (1/4 %25, %50, %75) chars.
  623. percentage (solid chars, percentage is XX% or 100)
  624. percent_space (solid chars, percentage is " XX% " or " 100 ")
  625. */
  626. enum class BarStyle { SOLID, HALF_STEP, GRADIENT, PERCENTAGE, PERCENT_SPACE };
  627. /**
  628. * BarColorRange
  629. *
  630. * vector<door::BarColorRange> colorRange = {
  631. * {2500, door::ANSIColor(door::COLOR::RED)},
  632. * {5000, door::ANSIColor(door::COLOR::BROWN)},
  633. * {7500, door::ANSIColor(door::COLOR::YELLOW, door::ATTR::BOLD)},
  634. * {9500, door::ANSIColor(door::COLOR::GREEN)},
  635. * {10100, door::ANSIColor(door::COLOR::GREEN, door::ATTR::BOLD)}};
  636. * BarLine.setColorRange(colorRange);
  637. *
  638. */
  639. struct BarColorRange {
  640. unsigned long percent;
  641. ANSIColor c;
  642. };
  643. class BarLine : public Line {
  644. protected:
  645. BarStyle barstyle;
  646. unsigned long current_percent;
  647. void init(void);
  648. std::string update_bar(void);
  649. int length;
  650. vector<BarColorRange> colorRange;
  651. public:
  652. BarLine(int width);
  653. BarLine(int width, BarStyle style);
  654. BarLine(int width, BarStyle style, ANSIColor c);
  655. void watch(float &percent);
  656. void watch(int &value, int &max);
  657. void setStyle(BarStyle s);
  658. void set(int value, int max);
  659. void set(float percent);
  660. void set(unsigned long percent);
  661. void setColorRange(vector<BarColorRange> bcr);
  662. // friend std::ostream &operator<<(std::ostream &os, const BarLine &b);
  663. };
  664. /**
  665. * The different Borders supported by Panel.
  666. *
  667. */
  668. enum class BorderStyle {
  669. /// NONE (0)
  670. NONE,
  671. /// SINGLE (1)
  672. SINGLE,
  673. /// DOUBLE (2)
  674. DOUBLE,
  675. /// SINGLE top DOUBLE side (3)
  676. SINGLE_DOUBLE,
  677. /// DOUBLE top SINGLE side (4)
  678. DOUBLE_SINGLE,
  679. /// BLANK (5)
  680. BLANK
  681. };
  682. class Panel {
  683. protected:
  684. int x;
  685. int y;
  686. int width; // or padding ?
  687. BorderStyle border_style;
  688. ANSIColor border_color;
  689. /**
  690. * @todo Fix this to use shared_ptr.
  691. * I don't think unique_ptr is the right way to go with this. I want to reuse
  692. * things, and that means shared_ptr!
  693. *
  694. */
  695. std::vector<std::unique_ptr<Line>> lines;
  696. bool hidden;
  697. // when you show panel, should it mark it as
  698. // redisplay everything?? maybe??
  699. bool shown_once; // ?? maybe shown_once_already ?
  700. std::unique_ptr<Line> title;
  701. int offset;
  702. public:
  703. Panel(int x, int y, int width);
  704. Panel(int width);
  705. // Panel(const Panel &);
  706. Panel(Panel &) = delete; // default;
  707. Panel(Panel &&ref);
  708. void set(int x, int y);
  709. void get(int &x, int &y) {
  710. x = this->x;
  711. y = this->y;
  712. };
  713. void setTitle(std::unique_ptr<Line> T, int off = 1);
  714. void setStyle(BorderStyle bs);
  715. void setColor(ANSIColor c);
  716. int getWidth(void) { return width; };
  717. int getHeight(void) {
  718. if (border_style == BorderStyle::NONE)
  719. return lines.size();
  720. else
  721. return lines.size() + 2;
  722. };
  723. void hide(void);
  724. void show(void);
  725. void addLine(std::unique_ptr<Line> l);
  726. // bool delLine(std::shared_ptr<Line> l); // ?
  727. /*
  728. void display(void);
  729. void update(void);
  730. */
  731. /**
  732. * @brief Updates a panel.
  733. *
  734. * returns True if something was changed (and cursor has moved)
  735. * False, nothing to do, cursor is ok.
  736. *
  737. * @param d
  738. * @return true
  739. * @return false
  740. */
  741. bool update(Door &d);
  742. void update(Door &d, int line);
  743. void update(void);
  744. door::Goto gotoEnd(void);
  745. std::unique_ptr<Line> spacer_line(bool single);
  746. void lineSetBack(ANSIColor back);
  747. friend std::ostream &operator<<(std::ostream &os, const Panel &p);
  748. };
  749. /*
  750. Menu - defaults to double lines.
  751. Has colorize for selected item / non-selected.
  752. Arrow keys + ENTER, or keypress to select an item.
  753. [O] Option Displayed Here
  754. [ + ] = c1
  755. O = c2
  756. Remaining UC TEXT = c3
  757. Remaining LC text = c4
  758. // Colors for CS and CU (color selected, color unselected)
  759. */
  760. class Menu : public Panel {
  761. protected:
  762. unsigned int chosen;
  763. std::vector<char> options;
  764. renderFunction selectedRender;
  765. renderFunction unselectedRender;
  766. /*
  767. std::function<void(Door &d, std::string &)> selectedColorizer;
  768. std::function<void(Door &d, std::string &)> unselectedColorizer;
  769. */
  770. public:
  771. static renderFunction defaultSelectedRender;
  772. static renderFunction defaultUnselectedRender;
  773. /*
  774. static std::function<void(Door &d, std::string &)> defaultSelectedColorizer;
  775. static std::function<void(Door &d, std::string &)> defaultUnselectedColorizer;
  776. */
  777. Menu(int x, int y, int width);
  778. Menu(int width);
  779. // Menu(const Menu &);
  780. Menu(const Menu &) = delete;
  781. Menu(Menu &&);
  782. void addSelection(char c, const char *line);
  783. void addSelection(char c, const char *line, updateFunction update);
  784. void defaultSelection(int d);
  785. void setRender(bool selected, renderFunction render);
  786. int choose(Door &door);
  787. char which(int d);
  788. static renderFunction makeRender(ANSIColor c1, ANSIColor c2, ANSIColor c3,
  789. ANSIColor c4);
  790. };
  791. class Screen {
  792. protected:
  793. // bool hidden;
  794. /**
  795. * @brief vector of panels.
  796. */
  797. std::vector<std::unique_ptr<Panel>> panels;
  798. public:
  799. Screen(void);
  800. Screen(Screen &) = default;
  801. void addPanel(std::unique_ptr<Panel> p);
  802. /*
  803. bool delPanel(std::shared_ptr<Panel> p);
  804. void hide(void);
  805. void show(void);
  806. */
  807. bool update(Door &d);
  808. void update(void);
  809. friend std::ostream &operator<<(std::ostream &os, const Screen &s);
  810. };
  811. /*
  812. screen - contains panels.
  813. - default to 1,1 X 80,24
  814. - refresh(style) could redraw panels by order they were added,
  815. or could redraw panels from top to bottom, left to right.
  816. crazy ideas:
  817. hide panels / z-order
  818. how to handle panel on top of other panels?
  819. Can I have you win + show animated final score calculations?
  820. panel - has X,Y and width, optional length. contains lines.
  821. length could be simply number of "lines".
  822. - has optional border. double/single/Ds/Sd TOPbottom
  823. - has optional title.
  824. - has optional footer.
  825. addLine()
  826. append() - Appends another line to current line.
  827. set(X,Y) - set a "line" at a given X,Y position.
  828. menu - another type of panel, contains menu options/lines.
  829. lightmenu - like above, but allows arrow keys to select menu options.
  830. line - contains text.
  831. (Maybe a "dirty" flag is needed here?)
  832. - has optional (width)
  833. - has optional (justify - L, R, Center)
  834. - has optional padding (# of blank chars)
  835. - has color (of text)
  836. - has formatter/coloring function (to colorize the text)
  837. Example would be one that sets capital letters to one color, lower to another.
  838. Another example would be one that displays Score: XXX, where Score is one
  839. color, : is another, and XXX is yet another. Properly padded, of course.
  840. - has "lambda" function to update the value? (Maybe?)
  841. Idea would be that I could update the score, and panel.update(). It would
  842. call all the line.update() functions and only update anything that has
  843. changed.
  844. Crazy ideas:
  845. Can I delete a line, and have it automatically removed from a panel?
  846. lightline - text, changes format/coloring if focus/nofocus is set?
  847. */
  848. } // namespace door
  849. #endif