panel.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. #include "door.h"
  2. #include <set>
  3. #include <string.h>
  4. // #include <memory>
  5. namespace door {
  6. Panel::Panel(int xp, int yp, int panelWidth) : border_color() {
  7. x = xp;
  8. y = yp;
  9. width = panelWidth;
  10. hidden = false;
  11. border_style = BorderStyle::NONE;
  12. // border_color = ANSIColor();
  13. }
  14. Panel::Panel(int panelWidth) : border_color() {
  15. x = 0;
  16. y = 0;
  17. width = panelWidth;
  18. hidden = false;
  19. border_style = BorderStyle::NONE;
  20. }
  21. Panel::Panel(Panel &&ref) {
  22. x = ref.x;
  23. y = ref.y;
  24. width = ref.width;
  25. hidden = ref.hidden;
  26. border_style = ref.border_style;
  27. title = std::move(ref.title);
  28. offset = ref.offset;
  29. lines = std::move(ref.lines);
  30. }
  31. /*
  32. Panel::Panel(const Panel &original) : border_color(original.border_color) {
  33. x = original.x;
  34. y = original.y;
  35. width = original.width;
  36. hidden = original.hidden;
  37. border_style = original.border_style;
  38. // door::Line title_copy(*original.title);
  39. // title = std::move(std::make_unique<door::Line>(title_copy));
  40. // What's wrong with making copies of unique_ptr objects?
  41. title = std::move(std::make_unique<door::Line>(*original.title));
  42. offset = original.offset;
  43. for (auto &line : original.lines) {
  44. // door::Line l(*line);
  45. // lines.push_back(std::move(std::make_unique<door::Line>(l)));
  46. // door::Line l(*line);
  47. lines.push_back(std::move(std::make_unique<door::Line>(*line)));
  48. }
  49. }
  50. */
  51. void Panel::set(int xp, int yp) {
  52. x = xp;
  53. y = yp;
  54. }
  55. void Panel::setTitle(std::unique_ptr<Line> t, int off) {
  56. title = std::move(t);
  57. offset = off;
  58. }
  59. void Panel::setStyle(BorderStyle bs) { border_style = bs; }
  60. // Panel::Panel(Panel &old) = { }
  61. void Panel::setColor(ANSIColor c) { border_color = c; }
  62. void Panel::hide(void) { hidden = true; }
  63. void Panel::show(void) { hidden = false; }
  64. void Panel::addLine(std::unique_ptr<Line> l) {
  65. l->fit();
  66. lines.push_back(std::move(l));
  67. }
  68. // or possibly std::move(l)); }
  69. /*
  70. bool Panel::delLine(std::shared_ptr<Line> l) {
  71. size_t size = lines.size();
  72. remove(lines.begin(), lines.end(), l);
  73. return (size != lines.size());
  74. }
  75. */
  76. /**
  77. * Utility structure that stores the characters needed to
  78. * render boxes.
  79. *
  80. * We assume that Top can be used in Bottom and Middle.
  81. * We assume that Side can be used on Left and Right.
  82. */
  83. struct box_styles {
  84. /// Top Left
  85. const char *tl;
  86. /// Top Right
  87. const char *tr;
  88. /// Top
  89. const char *top;
  90. /// Side
  91. const char *side;
  92. /// Bottom Left
  93. const char *bl;
  94. /// Bottom Right
  95. const char *br;
  96. /// Middle Left
  97. const char *ml;
  98. /// Middle Right
  99. const char *mr;
  100. };
  101. /**
  102. *
  103. * use https://en.wikipedia.org/wiki/Code_page_437 for translations between
  104. * CP437 and unicode symbols.
  105. *
  106. * This holds the characters needed to render the different box styles.
  107. * tl tr top side bl br ml mr
  108. */
  109. struct box_styles UBOXES[] = {{"\u250c", "\u2510", "\u2500", "\u2502", "\u2514",
  110. "\u2518", "\u251c", "\u2524"},
  111. {"\u2554", "\u2557", "\u2550", "\u2551", "\u255a",
  112. "\u255d", "\u2560", "\u2563"},
  113. {"\u2553", "\u2556", "\u2500", "\u2551", "\u2559",
  114. "\u255c", "\u255f", "\u2562"},
  115. {"\u2552", "\u2555", "\u2550", "\u2502", "\u2558",
  116. "\u255b", "\u255e", "\u2561"}};
  117. struct box_styles BOXES[] = {
  118. /*
  119. # ┌──┐
  120. # │ │
  121. # ├──┤
  122. # └──┘
  123. */
  124. {
  125. "\xda",
  126. "\xbf",
  127. "\xc4",
  128. "\xb3",
  129. "\xc0",
  130. "\xd9",
  131. "\xc3",
  132. "\xb4",
  133. },
  134. /*
  135. # ╔══╗
  136. # ║ ║
  137. # ╠══╣
  138. # ╚══╝
  139. */
  140. {
  141. "\xc9",
  142. "\xbb",
  143. "\xcd",
  144. "\xba",
  145. "\xc8",
  146. "\xbc",
  147. "\xcc",
  148. "\xb9",
  149. },
  150. /*
  151. # ╓──╖
  152. # ║ ║
  153. # ╟──╢
  154. # ╙──╜
  155. */
  156. {
  157. "\xd6",
  158. "\xb7",
  159. "\xc4",
  160. "\xba",
  161. "\xd3",
  162. "\xbd",
  163. "\xc7",
  164. "\xb6",
  165. },
  166. /*
  167. # ╒══╕
  168. # │ │
  169. # ╞══╡
  170. # ╘══╛
  171. */
  172. {
  173. "\xd5",
  174. "\xb8",
  175. "\xcd",
  176. "\xb3",
  177. "\xd4",
  178. "\xbe",
  179. "\xc6",
  180. "\xb5",
  181. },
  182. };
  183. const char *JOIN[2][2][2] = {{
  184. {"\xc3", "\xb4"}, // SS 00
  185. {"\xc6", "\xb5"} // SD 01
  186. },
  187. {
  188. {"\xc7", "\xb6"}, // DS 10
  189. {"\xcc", "\xb9"}, // DD 11
  190. }};
  191. const char *UJOIN[2][2][2] = {{
  192. {"\u251c", "\u2524"}, // SS ├ ┤
  193. {"\u255e", "\u2561"} // SD ╞ ╡
  194. },
  195. {
  196. {"\u255f", "\u2562"}, // DS ╟ ╢
  197. {"\u2560", "\u2563"}, // DD ╠ ╣
  198. }};
  199. /*
  200. void Panel::display(void) {
  201. }
  202. void Panel::update(void) {
  203. }
  204. */
  205. bool Panel::update(Door &d) {
  206. int row = y;
  207. int style = (int)border_style;
  208. if (style > 0)
  209. ++row;
  210. bool updated = false;
  211. for (auto &line : lines) {
  212. if (line->update()) {
  213. /*
  214. std::string output = d.previous.debug();
  215. d.log(output);
  216. output = "update():";
  217. output.append(line->debug());
  218. d.log(output);
  219. */
  220. updated = true;
  221. int col = x;
  222. if (style > 0)
  223. ++col;
  224. d << door::Goto(col, row);
  225. d << *line;
  226. }
  227. ++row;
  228. }
  229. return updated;
  230. }
  231. void Panel::update(Door &d, int line) {
  232. int row = y;
  233. int style = (int)border_style;
  234. if (style > 0)
  235. ++row;
  236. // ok, I have the line number to update.
  237. auto &l = lines[line];
  238. row += line;
  239. int col = x;
  240. if (style > 0)
  241. ++col;
  242. d << door::Goto(col, row);
  243. d << *l;
  244. }
  245. void Panel::update(void) {
  246. for (auto &line : lines) {
  247. line->update();
  248. }
  249. }
  250. door::Goto Panel::gotoEnd(void) {
  251. int row = y;
  252. int style = (int)border_style;
  253. if (style > 0)
  254. ++row;
  255. row += lines.size();
  256. int col = x;
  257. if (style > 0)
  258. col += 2;
  259. col += width;
  260. return door::Goto(col, row);
  261. }
  262. /**
  263. * @brief Create a spacer line using block drawing characters.
  264. *
  265. * Return a Line of single or double characters the width of the panel.
  266. * @param single
  267. * @return std::unique_ptr<Line>
  268. */
  269. std::unique_ptr<Line> Panel::spacer_line(bool single) {
  270. std::string spacer_text;
  271. if (door::unicode) {
  272. for (int x = 0; x < width; ++x) {
  273. if (single)
  274. spacer_text.append(UBOXES[0].top);
  275. else
  276. spacer_text.append(UBOXES[1].top);
  277. }
  278. } else {
  279. if (single)
  280. spacer_text = std::string(width, BOXES[0].top[0]);
  281. else
  282. spacer_text = std::string(width, BOXES[1].top[0]);
  283. }
  284. std::unique_ptr<Line> line = make_unique<Line>(spacer_text, width);
  285. return line;
  286. }
  287. // operator<< Panel is called to output the Menu.
  288. // Menu has been massively changed to use Render instead of Colorizer.
  289. std::ostream &operator<<(std::ostream &os, const Panel &p) {
  290. if (p.hidden)
  291. return os;
  292. // Handle borders
  293. int style = (int)p.border_style;
  294. struct box_styles s;
  295. // If there's no style, then everything works.
  296. // If I try style, it prints out first line
  297. // and dies. (Yet it says there's 4 lines!)
  298. if (style > 0) {
  299. // Ok, there needs to be something in this style;
  300. if (style < 5) {
  301. if (unicode)
  302. s = UBOXES[style - 1];
  303. else
  304. s = BOXES[style - 1];
  305. } else {
  306. s.bl = s.br = s.mr = s.ml = " ";
  307. s.top = s.side = " ";
  308. s.tl = s.tr = " ";
  309. }
  310. }
  311. /*
  312. Door *d = dynamic_cast<Door *>(&os);
  313. if (d != nullptr) {
  314. */
  315. /*
  316. os << "style " << style << "."
  317. << " width " << p.width;
  318. os << " SIZE " << p.lines.size() << " ! " << nl;
  319. */
  320. // os << s.tl << s.top << s.tr << s.side << s.br << s.bl;
  321. int row = p.y;
  322. if (style > 0) {
  323. // Top line of border (if needed)
  324. os << door::Goto(p.x, row);
  325. os << p.border_color << s.tl;
  326. if (p.title) {
  327. for (int c = 0; c < p.offset; c++)
  328. os << s.top;
  329. os << *(p.title);
  330. os << p.border_color;
  331. int left = p.width - (p.offset + (p.title)->length());
  332. if (left > 0) {
  333. for (int c = 0; c < left; c++)
  334. os << s.top;
  335. };
  336. os << s.tr;
  337. } else {
  338. for (int c = 0; c < p.width; c++)
  339. os << s.top;
  340. os << s.tr;
  341. };
  342. // os << "";
  343. ++row;
  344. };
  345. for (auto &line : p.lines) {
  346. os << door::Goto(p.x, row);
  347. bool join = false;
  348. int line_is = -1;
  349. int border_is = -1;
  350. // is this a weird line?
  351. {
  352. const char *line_text = line->getText();
  353. if (door::unicode) {
  354. if (strncmp(UBOXES[0].top, line_text, strlen(UBOXES[0].top)) == 0) {
  355. join = true;
  356. line_is = 0;
  357. }
  358. if (strncmp(UBOXES[1].top, line_text, strlen(UBOXES[1].top)) == 0) {
  359. join = true;
  360. line_is = 1;
  361. }
  362. } else {
  363. if (BOXES[0].top[0] == line_text[0]) {
  364. join = true;
  365. line_is = 0;
  366. }
  367. if (BOXES[1].top[0] == line_text[0]) {
  368. join = true;
  369. line_is = 1;
  370. }
  371. }
  372. }
  373. if (style > 0) {
  374. if (join) {
  375. switch (p.border_style) {
  376. case door::BorderStyle::SINGLE:
  377. case door::BorderStyle::DOUBLE_SINGLE:
  378. border_is = 0;
  379. break;
  380. case door::BorderStyle::DOUBLE:
  381. case door::BorderStyle::SINGLE_DOUBLE:
  382. border_is = 1;
  383. break;
  384. default:
  385. break;
  386. }
  387. os << p.border_color;
  388. if (door::unicode)
  389. os << UJOIN[border_is][line_is][0]; // LEFT
  390. else
  391. os << JOIN[border_is][line_is][0]; // LEFT
  392. } else {
  393. os << p.border_color << s.side;
  394. };
  395. };
  396. // os << "[" << row << "," << p.x << "] ";
  397. os << *line;
  398. if (style > 0) {
  399. if (join) {
  400. os << p.border_color;
  401. if (door::unicode)
  402. os << UJOIN[border_is][line_is][1]; // RIGHT
  403. else
  404. os << JOIN[border_is][line_is][1]; // RIGHT
  405. } else
  406. os << p.border_color << s.side;
  407. };
  408. // os << "row " << row;
  409. row++;
  410. // forcing reset works. But why doesn't it work without this?
  411. // os << Color();
  412. }
  413. // Display bottom (if needed)
  414. if (style > 0) {
  415. os << door::Goto(p.x, row);
  416. os << p.border_color << s.bl;
  417. for (int c = 0; c < p.width; c++)
  418. os << s.top;
  419. // os << "";
  420. os << s.br;
  421. };
  422. // };
  423. // os << flush;
  424. return os;
  425. } // namespace door
  426. /*
  427. std::function<void(Door &d, std::string &)> Menu::defaultSelectedColorizer =
  428. Menu::makeColorizer(ANSIColor(COLOR::BLUE, COLOR::WHITE),
  429. ANSIColor(COLOR::BLUE, COLOR::WHITE),
  430. ANSIColor(COLOR::BLUE, COLOR::WHITE),
  431. ANSIColor(COLOR::BLUE, COLOR::WHITE));
  432. std::function<void(Door &d, std::string &)> Menu::defaultUnselectedColorizer
  433. = makeColorizer(ANSIColor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD),
  434. ANSIColor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD),
  435. ANSIColor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD),
  436. ANSIColor(COLOR::YELLOW, COLOR::BLUE, ATTR::BOLD));
  437. */
  438. renderFunction Menu::defaultSelectedRender = Menu::makeRender(
  439. ANSIColor(COLOR::BLUE, COLOR::WHITE), ANSIColor(COLOR::BLUE, COLOR::WHITE),
  440. ANSIColor(COLOR::BLUE, COLOR::WHITE), ANSIColor(COLOR::BLUE, COLOR::WHITE));
  441. renderFunction Menu::defaultUnselectedRender =
  442. Menu::makeRender(ANSIColor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD),
  443. ANSIColor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD),
  444. ANSIColor(COLOR::WHITE, COLOR::BLUE, ATTR::BOLD),
  445. ANSIColor(COLOR::YELLOW, COLOR::BLUE, ATTR::BOLD));
  446. Menu::Menu(int x, int y, int width) : Panel(x, y, width) {
  447. setStyle(BorderStyle::DOUBLE);
  448. // Setup initial sensible default values.
  449. // setColorizer(true, defaultSelectedColorizer);
  450. setRender(true, defaultSelectedRender);
  451. /* makeColorizer(Color(Colors::BLUE, Colors::WHITE, 0),
  452. Color(Colors::BLUE, Colors::WHITE, 0),
  453. Color(Colors::BLUE, Colors::WHITE, 0),
  454. Color(Colors::BLUE, Colors::WHITE, 0)));
  455. */
  456. setRender(false, defaultUnselectedRender);
  457. // setColorizer(false, defaultUnselectedColorizer);
  458. /* makeColorizer(Color(Colors::LWHITE, Colors::BLUE, 0),
  459. Color(Colors::LWHITE, Colors::BLUE),
  460. Color(Colors::LWHITE, Colors::BLUE, 0),
  461. Color(Colors::LYELLOW, Colors::BLUE)));
  462. */
  463. chosen = 0;
  464. }
  465. Menu::Menu(int width) : Panel(width) {
  466. setStyle(BorderStyle::DOUBLE);
  467. setRender(true, defaultSelectedRender);
  468. setRender(false, defaultUnselectedRender);
  469. chosen = 0;
  470. }
  471. /*
  472. Menu::Menu(const Menu &original)
  473. : Panel(original.x, original.y, original.width) {
  474. x = original.x;
  475. y = original.y;
  476. width = original.width;
  477. setStyle(original.border_style);
  478. setRender(true, original.selectedRender);
  479. setRender(false, original.unselectedRender);
  480. options = original.options;
  481. chosen = 0;
  482. }
  483. */
  484. Menu::Menu(Menu &&ref) : Panel(ref.x, ref.y, ref.width) {
  485. x = ref.x;
  486. y = ref.y;
  487. width = ref.width;
  488. border_style = ref.border_style;
  489. setRender(true, ref.selectedRender);
  490. setRender(false, ref.unselectedRender);
  491. options = ref.options;
  492. lines = std::move(ref.lines);
  493. chosen = ref.chosen;
  494. }
  495. void Menu::addSelection(char c, const char *line) {
  496. std::string menuline;
  497. menuline.reserve(5 + strlen(line));
  498. menuline = "[ ] ";
  499. menuline[1] = c;
  500. menuline += line;
  501. // problem: How do I update the "Lines" from this point?
  502. // L->makeWidth(width);
  503. addLine(std::make_unique<Line>(menuline, width));
  504. options.push_back(c);
  505. }
  506. void Menu::defaultSelection(int d) { chosen = d; }
  507. char Menu::which(int d) { return options[d]; }
  508. /*
  509. void Menu::setColorizer(bool selected,
  510. std::function<void(Door &d, std::string &)>
  511. colorizer) { if (selected) selectedColorizer = colorizer; else
  512. unselectedColorizer = colorizer;
  513. }
  514. */
  515. void Menu::setRender(bool selected, renderFunction render) {
  516. if (selected)
  517. selectedRender = render;
  518. else
  519. unselectedRender = render;
  520. }
  521. /**
  522. * make Render function for menus
  523. *
  524. * [O] Menu Item Text
  525. *
  526. * "[" and "]" are in c1, the "O" in c2
  527. *
  528. * "Menu Item Text" upper case letters are in c3, everything else c4.
  529. */
  530. renderFunction Menu::makeRender(ANSIColor c1, ANSIColor c2, ANSIColor c3,
  531. ANSIColor c4) {
  532. renderFunction render = [c1, c2, c3, c4](const std::string &txt) -> Render {
  533. Render r(txt);
  534. bool option = true;
  535. for (char const &c : txt) {
  536. if (option) {
  537. if (c == '[' or c == ']') {
  538. r.append(c1);
  539. option = (c == '[');
  540. } else {
  541. r.append(c2);
  542. }
  543. } else {
  544. if (isupper(c))
  545. r.append(c3);
  546. else
  547. r.append(c4);
  548. }
  549. }
  550. return r;
  551. };
  552. return render;
  553. }
  554. /*
  555. Should this return the index number, or
  556. the actual option?
  557. */
  558. /**
  559. * @todo Fix this, so it only updates the lines that have been changed when
  560. * the user selects something. Also, add the "Up/Down Move" maybe to the
  561. * bottom?
  562. *
  563. * Needs timeout.
  564. *
  565. * Should we return the index offset, or return the actual char? (Like in
  566. * the case of Quit or Help?)
  567. *
  568. * @param door
  569. * @return int
  570. */
  571. int Menu::choose(Door &door) {
  572. // Display menu and make a choice
  573. // step 1: fix up the lines
  574. bool updated = true;
  575. bool update_and_exit = false;
  576. std::set<int> changed;
  577. while (true) {
  578. if (updated) {
  579. for (unsigned int x = 0; x < lines.size(); ++x) {
  580. if (x == chosen) {
  581. lines[x]->setRender(
  582. selectedRender); // setColorize(selectedColorizer);
  583. } else {
  584. lines[x]->setRender(
  585. unselectedRender); // setColorize(unselectedColorizer);
  586. }
  587. }
  588. // this outputs the entire menu
  589. if (changed.empty())
  590. door << *this;
  591. else {
  592. // update just the lines that have changed.
  593. for (auto si : changed) {
  594. // *this->update(door, si);
  595. update(door, si);
  596. }
  597. // Cursor is positioned at the end of the panel/menu.
  598. // The cursor changes colors as you arrow up or down.
  599. // Interesting!
  600. door << gotoEnd();
  601. }
  602. // door << flush;
  603. // door.update();
  604. };
  605. if (update_and_exit)
  606. return chosen + 1;
  607. // Maybe we want to position the cursor on the currently
  608. // selected item?
  609. updated = false;
  610. // Ok, when the option changes, can I control what gets updated??!?
  611. int event = door.sleep_key(door.inactivity);
  612. if (event < 0) {
  613. // timeout!
  614. return event;
  615. }
  616. unsigned int previous_choice = chosen;
  617. changed.clear();
  618. bool use_numberpad = true;
  619. // Don't use the numberpad, if any of the options are 8 or 2 (up/down)
  620. for (const char &c : options) {
  621. if ((c == '8') or (c == '2'))
  622. use_numberpad = false;
  623. }
  624. switch (event) {
  625. case '8':
  626. if (!use_numberpad)
  627. break;
  628. case XKEY_UP_ARROW:
  629. if (chosen > 0) {
  630. chosen--;
  631. updated = true;
  632. }
  633. break;
  634. case '2':
  635. if (!use_numberpad)
  636. break;
  637. case XKEY_DOWN_ARROW:
  638. if (chosen < lines.size() - 1) {
  639. chosen++;
  640. updated = true;
  641. }
  642. break;
  643. case XKEY_HOME:
  644. if (chosen != 0) {
  645. chosen = 0;
  646. updated = true;
  647. }
  648. break;
  649. case XKEY_END:
  650. if (chosen != lines.size() - 1) {
  651. chosen = lines.size() - 1;
  652. updated = true;
  653. }
  654. }
  655. if (event == 0x0d) {
  656. // ENTER -- use current selection
  657. return chosen + 1;
  658. }
  659. for (unsigned int x = 0; x < lines.size(); x++) {
  660. if (toupper(options[x]) == toupper(event)) {
  661. // is the selected one current chosen?
  662. if (chosen == x) {
  663. return x + 1;
  664. }
  665. // No, it isn't!
  666. // Update the screen, and then exit
  667. updated = true;
  668. chosen = x;
  669. update_and_exit = true;
  670. }
  671. }
  672. if (previous_choice != chosen) {
  673. changed.insert(previous_choice);
  674. changed.insert(chosen);
  675. }
  676. }
  677. return 0;
  678. }
  679. Screen::Screen(){}; // hidden = false; }
  680. /*
  681. Screen::Screen(Screen &s) {
  682. hidden = s.hidden;
  683. parts = s.parts;
  684. }
  685. */
  686. void Screen::addPanel(std::unique_ptr<Panel> p) {
  687. panels.push_back(std::move(p));
  688. }
  689. /*
  690. void Screen::hide(void) { hidden = true; }
  691. void Screen::show(void) { hidden = false; }
  692. */
  693. bool Screen::update(Door &d) {
  694. bool updated = false;
  695. for (auto &panel : panels) {
  696. if (panel->update(d))
  697. updated = true;
  698. }
  699. return updated;
  700. }
  701. void Screen::update(void) {
  702. for (auto &panel : panels) {
  703. panel->update();
  704. }
  705. }
  706. std::ostream &operator<<(std::ostream &os, const Screen &s) {
  707. // if (!s.hidden) {
  708. for (auto &panel : s.panels) {
  709. os << *panel;
  710. };
  711. // os << flush;
  712. // }
  713. return os;
  714. }
  715. } // namespace door