whirled_peas 0.3.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +38 -0
  4. data/README.md +549 -85
  5. data/Rakefile +28 -3
  6. data/examples/intro.rb +52 -0
  7. data/examples/scrolling.rb +53 -0
  8. data/exe/whirled_peas +7 -0
  9. data/lib/whirled_peas.rb +12 -36
  10. data/lib/whirled_peas/command_line.rb +255 -0
  11. data/lib/whirled_peas/config.rb +21 -0
  12. data/lib/whirled_peas/errors.rb +7 -0
  13. data/lib/whirled_peas/frame.rb +0 -5
  14. data/lib/whirled_peas/frame/consumer.rb +30 -0
  15. data/lib/whirled_peas/frame/debug_consumer.rb +30 -0
  16. data/lib/whirled_peas/frame/event_loop.rb +69 -38
  17. data/lib/whirled_peas/frame/producer.rb +36 -19
  18. data/lib/whirled_peas/graphics.rb +19 -0
  19. data/lib/whirled_peas/graphics/box_painter.rb +101 -0
  20. data/lib/whirled_peas/graphics/canvas.rb +118 -0
  21. data/lib/whirled_peas/graphics/composer.rb +80 -0
  22. data/lib/whirled_peas/graphics/container_coords.rb +72 -0
  23. data/lib/whirled_peas/graphics/container_dimensions.rb +93 -0
  24. data/lib/whirled_peas/graphics/container_painter.rb +272 -0
  25. data/lib/whirled_peas/graphics/debugger.rb +52 -0
  26. data/lib/whirled_peas/graphics/grid_painter.rb +69 -0
  27. data/lib/whirled_peas/graphics/mock_screen.rb +26 -0
  28. data/lib/whirled_peas/graphics/painter.rb +23 -0
  29. data/lib/whirled_peas/graphics/renderer.rb +26 -0
  30. data/lib/whirled_peas/graphics/screen.rb +70 -0
  31. data/lib/whirled_peas/graphics/text_dimensions.rb +15 -0
  32. data/lib/whirled_peas/graphics/text_painter.rb +40 -0
  33. data/lib/whirled_peas/settings.rb +5 -0
  34. data/lib/whirled_peas/settings/alignment.rb +24 -0
  35. data/lib/whirled_peas/settings/bg_color.rb +24 -0
  36. data/lib/whirled_peas/settings/border.rb +101 -0
  37. data/lib/whirled_peas/settings/box_settings.rb +8 -0
  38. data/lib/whirled_peas/settings/color.rb +68 -0
  39. data/lib/whirled_peas/settings/container_settings.rb +223 -0
  40. data/lib/whirled_peas/settings/debugger.rb +96 -0
  41. data/lib/whirled_peas/settings/display_flow.rb +27 -0
  42. data/lib/whirled_peas/settings/element_settings.rb +61 -0
  43. data/lib/whirled_peas/settings/grid_settings.rb +19 -0
  44. data/lib/whirled_peas/settings/margin.rb +8 -0
  45. data/lib/whirled_peas/settings/padding.rb +8 -0
  46. data/lib/whirled_peas/settings/position.rb +15 -0
  47. data/lib/whirled_peas/settings/scrollbar.rb +15 -0
  48. data/lib/whirled_peas/settings/sizing.rb +19 -0
  49. data/lib/whirled_peas/settings/spacing.rb +58 -0
  50. data/lib/whirled_peas/settings/text_color.rb +21 -0
  51. data/lib/whirled_peas/settings/text_settings.rb +15 -0
  52. data/lib/whirled_peas/settings/vert_alignment.rb +24 -0
  53. data/lib/whirled_peas/utils.rb +5 -0
  54. data/lib/whirled_peas/utils/ansi.rb +53 -0
  55. data/lib/whirled_peas/utils/formatted_string.rb +64 -0
  56. data/lib/whirled_peas/utils/title_font.rb +75 -0
  57. data/lib/whirled_peas/version.rb +1 -1
  58. data/screen_test/elements/box.frame +1 -0
  59. data/screen_test/elements/box.rb +20 -0
  60. data/screen_test/elements/grid.frame +1 -0
  61. data/screen_test/elements/grid.rb +13 -0
  62. data/screen_test/elements/screen_overflow_x.frame +1 -0
  63. data/screen_test/elements/screen_overflow_x.rb +9 -0
  64. data/screen_test/elements/screen_overflow_y.frame +1 -0
  65. data/screen_test/elements/screen_overflow_y.rb +9 -0
  66. data/screen_test/elements/text.frame +1 -0
  67. data/screen_test/elements/text.rb +9 -0
  68. data/screen_test/elements/text_multiline.frame +1 -0
  69. data/screen_test/elements/text_multiline.rb +9 -0
  70. data/screen_test/settings/align/box_around.frame +1 -0
  71. data/screen_test/settings/align/box_around.rb +16 -0
  72. data/screen_test/settings/align/box_between.frame +1 -0
  73. data/screen_test/settings/align/box_between.rb +16 -0
  74. data/screen_test/settings/align/box_center.frame +1 -0
  75. data/screen_test/settings/align/box_center.rb +21 -0
  76. data/screen_test/settings/align/box_default.frame +1 -0
  77. data/screen_test/settings/align/box_default.rb +20 -0
  78. data/screen_test/settings/align/box_evenly.frame +1 -0
  79. data/screen_test/settings/align/box_evenly.rb +16 -0
  80. data/screen_test/settings/align/box_left.frame +1 -0
  81. data/screen_test/settings/align/box_left.rb +21 -0
  82. data/screen_test/settings/align/box_right.frame +1 -0
  83. data/screen_test/settings/align/box_right.rb +21 -0
  84. data/screen_test/settings/align/children_center.frame +1 -0
  85. data/screen_test/settings/align/children_center.rb +15 -0
  86. data/screen_test/settings/align/children_left.frame +1 -0
  87. data/screen_test/settings/align/children_left.rb +15 -0
  88. data/screen_test/settings/align/children_right.frame +1 -0
  89. data/screen_test/settings/align/children_right.rb +15 -0
  90. data/screen_test/settings/align/grid_center.frame +1 -0
  91. data/screen_test/settings/align/grid_center.rb +18 -0
  92. data/screen_test/settings/align/grid_default.frame +1 -0
  93. data/screen_test/settings/align/grid_default.rb +17 -0
  94. data/screen_test/settings/align/grid_left.frame +1 -0
  95. data/screen_test/settings/align/grid_left.rb +18 -0
  96. data/screen_test/settings/align/grid_right.frame +1 -0
  97. data/screen_test/settings/align/grid_right.rb +18 -0
  98. data/screen_test/settings/ansi/bold.frame +1 -0
  99. data/screen_test/settings/ansi/bold.rb +14 -0
  100. data/screen_test/settings/ansi/color.frame +1 -0
  101. data/screen_test/settings/ansi/color.rb +37 -0
  102. data/screen_test/settings/ansi/underline.frame +1 -0
  103. data/screen_test/settings/ansi/underline.rb +14 -0
  104. data/screen_test/settings/border.frame +1 -0
  105. data/screen_test/settings/border.rb +13 -0
  106. data/screen_test/settings/flow/box_b2t.frame +1 -0
  107. data/screen_test/settings/flow/box_b2t.rb +26 -0
  108. data/screen_test/settings/flow/box_l2r.frame +1 -0
  109. data/screen_test/settings/flow/box_l2r.rb +26 -0
  110. data/screen_test/settings/flow/box_r2l.frame +1 -0
  111. data/screen_test/settings/flow/box_r2l.rb +26 -0
  112. data/screen_test/settings/flow/box_t2b.frame +1 -0
  113. data/screen_test/settings/flow/box_t2b.rb +26 -0
  114. data/screen_test/settings/flow/grid_b2t.frame +1 -0
  115. data/screen_test/settings/flow/grid_b2t.rb +14 -0
  116. data/screen_test/settings/flow/grid_l2r.frame +1 -0
  117. data/screen_test/settings/flow/grid_l2r.rb +14 -0
  118. data/screen_test/settings/flow/grid_r2l.frame +1 -0
  119. data/screen_test/settings/flow/grid_r2l.rb +14 -0
  120. data/screen_test/settings/flow/grid_t2b.frame +1 -0
  121. data/screen_test/settings/flow/grid_t2b.rb +14 -0
  122. data/screen_test/settings/height/box.frame +1 -0
  123. data/screen_test/settings/height/box.rb +13 -0
  124. data/screen_test/settings/height/box_border_sizing.frame +1 -0
  125. data/screen_test/settings/height/box_border_sizing.rb +15 -0
  126. data/screen_test/settings/height/grid.frame +1 -0
  127. data/screen_test/settings/height/grid.rb +14 -0
  128. data/screen_test/settings/height/overflow_box.frame +1 -0
  129. data/screen_test/settings/height/overflow_box.rb +13 -0
  130. data/screen_test/settings/height/overflow_box_l2r.frame +1 -0
  131. data/screen_test/settings/height/overflow_box_l2r.rb +17 -0
  132. data/screen_test/settings/height/overflow_box_t2b.frame +1 -0
  133. data/screen_test/settings/height/overflow_box_t2b.rb +16 -0
  134. data/screen_test/settings/height/overflow_grid.frame +1 -0
  135. data/screen_test/settings/height/overflow_grid.rb +16 -0
  136. data/screen_test/settings/margin.frame +1 -0
  137. data/screen_test/settings/margin.rb +16 -0
  138. data/screen_test/settings/padding.frame +1 -0
  139. data/screen_test/settings/padding.rb +13 -0
  140. data/screen_test/settings/position/box_left.frame +1 -0
  141. data/screen_test/settings/position/box_left.rb +17 -0
  142. data/screen_test/settings/position/box_left_negative.frame +1 -0
  143. data/screen_test/settings/position/box_left_negative.rb +17 -0
  144. data/screen_test/settings/position/box_top.frame +1 -0
  145. data/screen_test/settings/position/box_top.rb +17 -0
  146. data/screen_test/settings/position/box_top_negative.frame +1 -0
  147. data/screen_test/settings/position/box_top_negative.rb +17 -0
  148. data/screen_test/settings/position/grid_left.frame +1 -0
  149. data/screen_test/settings/position/grid_left.rb +18 -0
  150. data/screen_test/settings/position/grid_left_negative.frame +1 -0
  151. data/screen_test/settings/position/grid_left_negative.rb +18 -0
  152. data/screen_test/settings/position/grid_top.frame +1 -0
  153. data/screen_test/settings/position/grid_top.rb +18 -0
  154. data/screen_test/settings/position/grid_top_negative.frame +1 -0
  155. data/screen_test/settings/position/grid_top_negative.rb +18 -0
  156. data/screen_test/settings/scroll/horiz_box.frame +1 -0
  157. data/screen_test/settings/scroll/horiz_box.rb +17 -0
  158. data/screen_test/settings/scroll/horiz_box_align_center.rb +18 -0
  159. data/screen_test/settings/scroll/horiz_box_align_right.rb +18 -0
  160. data/screen_test/settings/scroll/vert_box.frame +1 -0
  161. data/screen_test/settings/scroll/vert_box.rb +20 -0
  162. data/screen_test/settings/title_font.frame +1 -0
  163. data/screen_test/settings/title_font.rb +12 -0
  164. data/screen_test/settings/valign/box_around.frame +1 -0
  165. data/screen_test/settings/valign/box_around.rb +17 -0
  166. data/screen_test/settings/valign/box_between.frame +1 -0
  167. data/screen_test/settings/valign/box_between.rb +17 -0
  168. data/screen_test/settings/valign/box_bottom.frame +1 -0
  169. data/screen_test/settings/valign/box_bottom.rb +17 -0
  170. data/screen_test/settings/valign/box_default.frame +1 -0
  171. data/screen_test/settings/valign/box_default.rb +16 -0
  172. data/screen_test/settings/valign/box_evenly.frame +1 -0
  173. data/screen_test/settings/valign/box_evenly.rb +17 -0
  174. data/screen_test/settings/valign/box_middle.frame +1 -0
  175. data/screen_test/settings/valign/box_middle.rb +17 -0
  176. data/screen_test/settings/valign/box_top.frame +1 -0
  177. data/screen_test/settings/valign/box_top.rb +17 -0
  178. data/screen_test/settings/valign/grid_bottom.frame +1 -0
  179. data/screen_test/settings/valign/grid_bottom.rb +15 -0
  180. data/screen_test/settings/valign/grid_default.frame +1 -0
  181. data/screen_test/settings/valign/grid_default.rb +14 -0
  182. data/screen_test/settings/valign/grid_middle.frame +1 -0
  183. data/screen_test/settings/valign/grid_middle.rb +15 -0
  184. data/screen_test/settings/valign/grid_top.frame +1 -0
  185. data/screen_test/settings/valign/grid_top.rb +15 -0
  186. data/screen_test/settings/width/box_border_sizing.frame +1 -0
  187. data/screen_test/settings/width/box_border_sizing.rb +15 -0
  188. data/screen_test/settings/width/box_content.frame +1 -0
  189. data/screen_test/settings/width/box_content.rb +15 -0
  190. data/screen_test/settings/width/box_default.frame +1 -0
  191. data/screen_test/settings/width/box_default.rb +14 -0
  192. data/screen_test/settings/width/grid.frame +1 -0
  193. data/screen_test/settings/width/grid.rb +14 -0
  194. data/screen_test/settings/width/overflow_align_center.frame +1 -0
  195. data/screen_test/settings/width/overflow_align_center.rb +14 -0
  196. data/screen_test/settings/width/overflow_align_right.frame +1 -0
  197. data/screen_test/settings/width/overflow_align_right.rb +14 -0
  198. data/screen_test/settings/width/overflow_box.frame +1 -0
  199. data/screen_test/settings/width/overflow_box.rb +13 -0
  200. data/screen_test/settings/width/overflow_box_l2r.frame +1 -0
  201. data/screen_test/settings/width/overflow_box_l2r.rb +16 -0
  202. data/screen_test/settings/width/overflow_box_t2b.frame +1 -0
  203. data/screen_test/settings/width/overflow_box_t2b.rb +17 -0
  204. data/screen_test/settings/width/overflow_grid.frame +1 -0
  205. data/screen_test/settings/width/overflow_grid.rb +14 -0
  206. data/tools/whirled_peas/tools/screen_tester.rb +233 -0
  207. data/whirled_peas.gemspec +4 -1
  208. metadata +215 -17
  209. data/lib/whirled_peas/ui.rb +0 -7
  210. data/lib/whirled_peas/ui/ansi.rb +0 -103
  211. data/lib/whirled_peas/ui/canvas.rb +0 -68
  212. data/lib/whirled_peas/ui/color.rb +0 -101
  213. data/lib/whirled_peas/ui/element.rb +0 -224
  214. data/lib/whirled_peas/ui/painter.rb +0 -283
  215. data/lib/whirled_peas/ui/screen.rb +0 -60
  216. data/lib/whirled_peas/ui/settings.rb +0 -523
  217. data/sandbox/auto.rb +0 -13
  218. data/sandbox/box.rb +0 -19
  219. data/sandbox/grid.rb +0 -13
  220. data/sandbox/sandbox.rb +0 -17
  221. data/sandbox/text.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3cb7aa7af0bf74f8818eb5796f310e3b65a73851b7cbab35834e14fe0262ac1
4
- data.tar.gz: 6ae73d252d69d3730c1e1814d441800fca08177a4401abc3e4dcbe6edcd34548
3
+ metadata.gz: 46a66b5e575d80b9e99cd263d8158ece7f500aebfc853df72bd340b7b67a0787
4
+ data.tar.gz: 6a097ab19829f97957eff088dab8aed0241b0d68a79a43681883a07e2a897790
5
5
  SHA512:
6
- metadata.gz: 2b0965214a99209e4830ed68da162cc83d249188e197d8b9fe11b61356f797e2172a648aef2b23f83f9ac45db40d9f4e7daee9471f67069e61998e5f24a8d0ba
7
- data.tar.gz: e0d546f8a60606a918aadf1743848b9839703328bf14a05dcb67f680886ee2eef2c4ae542d89055daf822f74200f64a719e77f1223520266aa7d6703b18ccb03
6
+ metadata.gz: '093f92c928d2dda04cabe54d4bcc627f3083fcc1e1b68ceb413dc2ffcfa3e1f73427a91f9e5d1fee8992fcc1e88f601984e5e04f8b0a58183c5b44ac5e4d2c27'
7
+ data.tar.gz: '0300822358c0ceaeba6c998cbff96ac1c2d94198cc639062e77cfe041132630f94f8dd4ef56a6de45838b068480f0a8ebcc40c23c2b1a5e315ce990ead06ca93'
@@ -6,3 +6,4 @@ rvm:
6
6
  - 2.7.2
7
7
  - 3.0.0
8
8
  before_install: gem install bundler -v 2.1.4
9
+ script: bundle exec rake ci
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.0 - 2021-01-27
4
+
5
+ BREAKING: the settings for the template now fills the full screen and disallows margin.
6
+
7
+ - [b7c12c2](https://github.com/tcollier/whirled_peas/tree/b7c12c2c34d7077b9c2496d05ddd0c6d1eb90699): Update template to fill full screen with border sizing
8
+ - [963b819](https://github.com/tcollier/whirled_peas/tree/963b8196f0d046ba03c893f07e5578bf8c88b7a3): Implement vertical alignment
9
+ - [4bddd54](https://github.com/tcollier/whirled_peas/tree/4bddd54bec5c8f93d145c285379c1816f313f35e): Add `between`, `around`, and `evenly` alignments
10
+
11
+ ## v0.6.0 - 2021-01-25
12
+
13
+ - [73df2af](https://github.com/tcollier/whirled_peas/tree/73df2af1f1eac37fe94f720dce16da1ed568dade): Add support for scroll bars along both axes
14
+ - [f4f44e1](https://github.com/tcollier/whirled_peas/tree/f4f44e1ff6c75ed03cd682e3fa9921401dcd2d00): Implement remaining 3 flow directions for grids
15
+ - [c01d083](https://github.com/tcollier/whirled_peas/tree/c01d083e10bf70983109a8def836bb181099f59c): Implement reverse flow directions for grids
16
+
17
+ ## v0.5.0 - 2021-01-25
18
+
19
+ BREAKING: there was a significant amount of structural refactoring in this release. While that aspect did not add or remove any features, it fixed several layout bugs (some known and some unknown), so most template with moderate complexity will now be laid out slightly differently.
20
+
21
+ - [3ddfede](https://github.com/tcollier/whirled_peas/tree/3ddfedee4ab2fadeecbe82c7c9caf25c2988f095): Allow relative positioning of containers
22
+ - [507e77c](https://github.com/tcollier/whirled_peas/tree/507e77c551bcb9cc832d5c24e2f24eb1afe4eddc): Add height attribute for container settings
23
+ - [af8ef19](https://github.com/tcollier/whirled_peas/tree/af8ef1950edebcd23a57a04982b22a56296ee09b): Add automated screen testing
24
+
25
+ ## v0.4.1 - 2021-01-22
26
+
27
+ - [0f7aa6c](https://github.com/tcollier/whirled_peas/tree/0f7aa6ccc07323230dd602cb43e0341de5a69ad8): Allow relative path for config files
28
+
29
+ ## v0.4.0 - 2021-01-22
30
+
31
+ - [7fd6712](https://github.com/tcollier/whirled_peas/tree/7fd6712818c94cdbfd81828277ca67c705e01793): BREAKING: replace `WhirledPeas.start` with command line executable
32
+ - [2535342](https://github.com/tcollier/whirled_peas/tree/25353424f1ab4af4880f44eb7ddd28afefbbb9b2): Add support for loading screen
33
+ - [7388fc2](https://github.com/tcollier/whirled_peas/tree/7388fc2eacdc8045b725311c11d650d6b8654be8): Add support for title fonts
34
+ - [b345155](https://github.com/tcollier/whirled_peas/tree/b345155b1c212cabe73f9a2562ac8dbbedbbb6df): Add command to list title fonts to executable
35
+ - [d3a8324](https://github.com/tcollier/whirled_peas/tree/d3a832496c36985993217ff11b6d83dd4697c4ed): Add commands for debugging application to executable
36
+
37
+ ## v0.3.0 - 2021-01-21
38
+
39
+ - [617f802](https://github.com/tcollier/whirled_peas/tree/617f8027d6688a2ec81a3e594e529c94485cee85): BREAKING: send frames directly to EventLoop (`Producer#send` renamed to `Producer#send_frame`)
40
+
3
41
  ## v0.2.0 - 2021-01-20
4
42
 
5
43
  - [73eb326](https://github.com/tcollier/whirled_peas/tree/73eb326426f9814e91e3bc7a60dfd87be3d69f7e): Convert "primitive" data types to strings
data/README.md CHANGED
@@ -1,8 +1,24 @@
1
1
  [![Build Status](https://travis-ci.com/tcollier/whirled_peas.svg?branch=main)](https://travis-ci.com/tcollier/whirled_peas)
2
2
 
3
- # WhirledPeas
3
+ ```
4
+ ██╗ ██╗██╗███████╗██╗ ██╗ █████╗ ██╗ ██╗███████╗███████╗
5
+ ██║ ██║██║██╔════╝██║ ██║██╔══██╗██║ ██║╚══███╔╝██╔════╝
6
+ ██║ ██║██║███████╗██║ ██║███████║██║ ██║ ███╔╝ █████╗
7
+ ╚██╗ ██╔╝██║╚════██║██║ ██║██╔══██║██║ ██║ ███╔╝ ██╔══╝
8
+ ╚████╔╝ ██║███████║╚██████╔╝██║ ██║███████╗██║███████╗███████╗
9
+ ╚═══╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝╚══════╝╚══════╝
10
+
11
+ your code's execution with
12
+
13
+ ██╗ ██╗██╗ ██╗██╗██████╗ ██╗ ███████╗██████╗ ██████╗ ███████╗ █████╗ ███████╗
14
+ ██║ ██║██║ ██║██║██╔══██╗██║ ██╔════╝██╔══██╗ ██╔══██╗██╔════╝██╔══██╗██╔════╝
15
+ ██║ █╗ ██║███████║██║██████╔╝██║ █████╗ ██║ ██║ ██████╔╝█████╗ ███████║███████╗
16
+ ██║███╗██║██╔══██║██║██╔══██╗██║ ██╔══╝ ██║ ██║ ██╔═══╝ ██╔══╝ ██╔══██║╚════██║
17
+ ╚███╔███╔╝██║ ██║██║██║ ██║███████╗███████╗██████╔╝ ██║ ███████╗██║ ██║███████║
18
+ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
19
+ ```
4
20
 
5
- Visualize your code's execution with Whirled Peas!
21
+ Easily create terminal-based graphics to visual the execution of your code. Whirled Peas offers templating inspired by HTML and CSS and provides a lightweight tie-in for your code to produce visual animations with these templates.
6
22
 
7
23
  ## Installation
8
24
 
@@ -22,15 +38,24 @@ Or install it yourself as:
22
38
 
23
39
  ## Usage
24
40
 
41
+ A Whirled Peas application consists of the following pieces
42
+
43
+ - The driver (required) - the code that is to be visualized, it emits lightweight frame events through a producer
44
+ - The main template factory (required) - builds templates to convert frame events from the driver into terminal graphics
45
+ - A loading screen template factory (optional) - builds templates to display while content is loading
46
+
47
+ These pieces are configured as following
48
+
25
49
  ```ruby
50
+ # visualize.rb
26
51
  require 'whirled_peas'
27
52
 
28
53
  class TemplateFactory
29
54
  def build(frame, args)
30
- WhirledPeas.template do |body|
31
- body.add_box do |_, settings|
55
+ WhirledPeas.template do |composer|
56
+ composer.add_box('Title') do |_, settings|
32
57
  settings.underline = true
33
- "Hello #{args['name']}"
58
+ "Hello #{args[:name]}"
34
59
  end
35
60
  # ...
36
61
  end
@@ -39,18 +64,44 @@ end
39
64
 
40
65
  class Driver
41
66
  def start(producer)
42
- producer.send_frame('starting', args: { 'name' => 'World' })
67
+ producer.send_frame('starting', args: { name: 'World' })
43
68
  # ...
44
69
  end
45
70
  end
46
71
 
47
- WhirledPeas.start(Driver.new, TemplateFactory.new)
72
+ WhirledPeas.configure do |config|
73
+ config.driver = Driver.new
74
+ config.template_factory = TemplateFactory.new
75
+ end
76
+ ```
77
+
78
+ Then the visualizer is started on the command line with
79
+
80
+ ```
81
+ $ whirled_peas start visualize.rb
48
82
  ```
49
83
 
50
- A Whirled Peas application consists of two pieces
84
+ The optional loading screen can be configured like
51
85
 
52
- 1. The driver, which emits lightweight frame events
53
- 1. The template factory, which builds templates to convert frame events from the driver into terminal graphics
86
+ ```ruby
87
+ class LoadingTemplateFactory
88
+ def build
89
+ WhirledPeas.template do |composer|
90
+ composer.add_box('Loading') do |_, settings|
91
+ settings.set_margin(top: 15)
92
+ settings.align = :center
93
+ settings.full_border(color: :blue, style: :double)
94
+ "Loading..."
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ WhirledPeas.configure do |config|
101
+ # ...
102
+ config.loading_template_factory = LoadingTemplateFactory.new
103
+ end
104
+ ```
54
105
 
55
106
  ### Driver
56
107
 
@@ -72,12 +123,14 @@ The producer provides a single method
72
123
  #
73
124
  # @param name [String] application defined name for the frame. The template factory will be provided this name
74
125
  # @param duration [Number] time in seconds this frame should be displayed for (defaults to 1 frame)
75
- # @param args [Hash] key value pairs to send as arguments to the template factory
126
+ # @param args [Hash<Symbol, Object>] key value pairs to send as arguments to the template factory
76
127
  def send_frame(name, duration:, args:)
77
128
  # implementation
78
129
  end
79
130
  ```
80
131
 
132
+ **IMPORTANT**: the keys in the `args` hash must be symbols!
133
+
81
134
  #### Example
82
135
 
83
136
  Simple application that loads a set of numbers and looks for a pair that adds up to 1,000
@@ -111,27 +164,36 @@ end
111
164
 
112
165
  ### Template Factory
113
166
 
114
- To render the frame events sent by the driver, the application requires a template factory. This factory will be called for each frame event, with the frame name and the arguments supplied by the driver. A template factory can be a simple ruby class and thus can maintain state. Whirled Peas provides a few basic building blocks to make simple, yet elegant terminal-based UIs.
167
+ To render the frame events sent by the driver, the application requires a template factory. This factory will be called for each frame event, with the frame name and the arguments supplied by the driver. A template factory can be an instance of ruby class and thus can maintain state. Whirled Peas provides a few basic building blocks to make simple, yet elegant terminal-based UIs.
168
+
169
+ #### Loading Template Factory
170
+
171
+ `WhirledPeas.configure` takes an optional template factory to build a loading screen. This instance must implement `#build` (taking no arguments). The template returned by that method will be painted while the event loop is waiting for frames. The factory method will be called once per refresh cycle, so it's possible to implement animation.
115
172
 
116
173
  #### Building Blocks
117
174
 
118
- A template is created with `WhirledPeas.template`, which yields a `Template` object and `TemplateSettings`. This template object is a `ComposableElement`, which allows for attaching child elements and setting layout options. `GridElement` and `BoxElement` are two other composable elements and `TextElement` is a simple element that can hold a text/number value and has layout options, but cannot have any child elements.
175
+ A template is created with `WhirledPeas.template`, which yields a `Composer` object for a `Box` and `BoxSettings`. The composer allows for attaching child elements and the settings for setting layout options. The following attributes of the template's settings will be overridden before it is rendered to ensure that it fills the screen exactly
119
176
 
120
- A `ComposableElement` provides the following methods to add child elements, each of these takes an optional string argument that is set as the name of the element (which can be useful when debugging).
177
+ - `margin` - all margin will be set to 0
178
+ - `width` - will be set to the screen's width
179
+ - `height` - will be set to the screen's height
180
+ - `sizing` - will be set `:border` to ensure the entire box fits on the screen and fills it entirely.
121
181
 
122
- - `add_box` - yields a `ComposableElement` and a `BoxSettings`, which will be added to the parent's children
123
- - `add_grid` - yields a `ComposableElement` and a `GridSettings`, which will be added to the parent's children
182
+ A `Composer` provides the following methods to add child elements, each of these takes an optional string argument that is set as the name of the element (which can be useful when debugging).
183
+
184
+ - `add_box` - yields a `Composer` for a `Box` and a `BoxSettings`, which will be added to the parent's children
185
+ - `add_grid` - yields a `Composer` for a `Grid` and a `GridSettings`, which will be added to the parent's children
124
186
  - `add_text` - yields `nil` and a `TextSettings`, which will be added to the parent's children
125
187
 
126
188
  E.g.
127
189
 
128
190
  ```ruby
129
- WhirledPeas.template do |template, template_settings|
130
- template_settings.bg_color = :blue
131
- template.add_grid do |grid, grid_settings|
132
- grid_settings.num_cols = 10
191
+ WhirledPeas.template do |composer, settings|
192
+ settings.bg_color = :blue
193
+ composer.add_grid do |composer, settings|
194
+ settings.num_cols = 10
133
195
  100.times do |i|
134
- grid.add_text { i }
196
+ composer.add_text { i }
135
197
  end
136
198
  end
137
199
  end
@@ -140,80 +202,349 @@ end
140
202
  The above template can also be broken down into more manageable methods, e.g.
141
203
 
142
204
  ```ruby
143
- def number_grid(grid, settings)
205
+ def number_grid(_composer, settings)
144
206
  settings.num_cols = 10
145
- 100.times do |i|
146
- grid.add_text { i }
147
- end
207
+ 100.times.map(&:itself)
148
208
  end
149
209
 
150
- WhirledPeas.template do |template, settings|
210
+ WhirledPeas.template do |composer, settings|
151
211
  settings.bg_color = :blue
152
- template.add_grid(&method(:number_grid))
212
+ composer.add_grid(&method(:number_grid))
153
213
  end
154
214
  ```
155
215
 
156
- Additionally, if no child element is explicitly added to a `GridElement`, but the block returns an array of strings or numbers, those will be converted to `TextElements` and added as children to the `GridElement`. For example, these are identical ways to create a grid of strings
216
+ Additionally, if no child element is explicitly added to a `Grid`, but the block returns an array of strings or numbers, those will be converted to `Text` elements and added as children to the `Grid`. For example, these are identical ways to create a grid of strings
157
217
 
158
218
  ```ruby
159
- template.add_grid do |g|
219
+ template.add_grid do |composer|
160
220
  100.times do |i|
161
- g.add_text { i }
221
+ composer.add_text { i }
162
222
  end
163
223
  end
164
224
 
165
- template.add_grid do |g|
225
+ template.add_grid do
166
226
  100.times.map(&:itself)
167
227
  end
168
228
  ```
169
229
 
170
- Similarly, if no child element is explicilty added to a `BoxElement`, but the block returns a string or number, that value will be converted to a `TextElement` and added as a child. For example, these are identical ways to create a box with string content
230
+ Similarly, if no child element is explicilty added to a `Box`, but the block returns a string or number, that value will be converted to a `Text` and added as a child. For example, these are identical ways to create a box with string content
171
231
 
172
232
  ```ruby
173
- template.add_box do |b|
174
- b.add_text { "Hello!" }
233
+ template.add_box do |composer|
234
+ composer.add_text { "Hello!" }
175
235
  end
176
236
 
177
- template.add_box do |b|
237
+ template.add_box do
178
238
  "Hello!"
179
239
  end
180
240
  ```
181
241
 
182
242
  #### Settings
183
243
 
184
- Each element type has an associated settings type, which provide a custom set of options to format the output. Parent settings may be merged into child settings (assuming the child supports those settings)
244
+ Each element type has an associated settings type, which provide a custom set of options to format the output. Child settings will inherit from the parent, where applicable
185
245
  The available settigs are
186
246
 
187
- | Setting | Description | Default | Availability | Merged? |
188
- | ------------- | ------------------------------------------------------------------ | ------- | --------------------------------- | ------- |
189
- | `align` | Justifies the text (allowed values: `:left`, `:center`, `:right`) | `:left` | `Box`, `Grid`, `Text` | Yes |
190
- | `auto_margin` | Evenly distribute side margin (overrides left/right in `margin`) | `false` | `Box`, `Grid` | Yes |
191
- | `bg_color` | Background color (see [Colors](#colors)) | | `Box`, `Grid`, `Template`, `Text` | Yes |
192
- | `bold` | `true` makes the font bold | `false` | `Box`, `Grid`, `Template`, `Text` | Yes |
193
- | `border` | Set the border for the lements | none | `Box`, `Grid`, | Yes |
194
- | `color` | Foreground text color (see [Colors](#colors)) | | `Box`, `Grid`, `Template`, `Text` | Yes |
195
- | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | `Box` | Yes |
196
- | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | `Box`, `Grid` | Yes |
197
- | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | `Box`, `Grid` | Yes |
198
- | `transpose` | Display grid elements top-to-bottom, then left-to-right | `false` | `Grid` | No |
199
- | `underline` | `true` underlines the font | `false` | `Box`, `Grid`, `Template`, `Text` | Yes |
200
- | `width` | Override the calculated with of an element | | `Box`, `Grid`, `Text` | No |
201
-
202
- ##### Margin and Padding
203
-
204
- Margin and padding settings allow for setting the spacing on each of the 4 sides of the element independently. The set these values, use
205
-
206
- - `clear_margin` - sets all margin values to 0
207
- - `set_margin(left:, top:, right:, bottom:)`
208
- - `clear_padding` - sets all margin values to 0
209
- - `set_padding(left:, top:, right:, bottom:)`
247
+ | Setting | Description | Default | Availability | Inherited |
248
+ | ------------ | -------------------------------------------------------------------------------- | ---------- | --------------------- | -------------------- |
249
+ | `align` | Justifies the content in the horizontal direction | `:left` | `Box`, `Grid` | No |
250
+ | `bg_color` | Background color (see [Colors](#colors)) | | `Box`, `Grid`, `Text` | Yes |
251
+ | `bold` | `true` makes the font bold | `false` | `Box`, `Grid`, `Text` | Yes |
252
+ | `border` | Set the border for the lements | none | `Box`, `Grid`, | Only style and color |
253
+ | `color` | Foreground text color (see [Colors](#colors)) | | `Box`, `Grid`, `Text` | Yes |
254
+ | `flow` | Flow to display child elements (see [Display Flow](#display-flow)) | `:l2r` | `Box`, `Grid` | No |
255
+ | `height` | Override the calculated height of an element's content area | | `Box`, `Grid` | No |
256
+ | `margin` | Set the (left, top, right, bottom) margin of the element | `0` | `Box`, `Grid` | No |
257
+ | `num_cols` | Number of columns in the grid (must be set!) | | `Grid` | No |
258
+ | `padding` | Set the (left, top, right, bottom) padding of the element | `0` | `Box`, `Grid` | No |
259
+ | `position` | Set the (left, top) position of the element relative to parent content area | `0` | `Box`, `Grid` | No |
260
+ | `scrollbar` | Display a scroll bar for vertical or horizontal scrolling | | `Box` | No |
261
+ | `sizing` | Sizing model (`:content` or `:border`) used in conjunction with `width`/`hieght` | `:content` | `Box` | No |
262
+ | `title_font` | Font used for "large" text (see [Large Text](#large-text), ignores `underline`) | | `Text` | No |
263
+ | `underline` | `true` underlines the font | `false` | `Box`, `Grid`, `Text` | Yes |
264
+ | `width` | Override the calculated width of an element's content area | | `Box`, `Grid` | No |
265
+ | `valign` | Justifies the content in the vertical direction | `:top` | `Box`, `Grid` | No |
266
+
267
+ ##### Alignment
268
+
269
+ The `align` setting takes one of several values
270
+
271
+ - `:left` - align content starting at the leftmost edge of the container's content area
272
+
273
+ ```
274
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
275
+ ┃[child 1][child 2][child 3] ┃
276
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
277
+ ```
278
+
279
+ - `:right` - align content starting at the rightmost edge of the container's content area
280
+
281
+ ```
282
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
283
+ ┃ [child 1][child 2][child 3]┃
284
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
285
+ ```
286
+
287
+ - `:center` - align content starting in the horizontal center of the container's content area
288
+
289
+ ```
290
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
291
+ ┃ [child 1][child 2][child 3] ┃
292
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
293
+ ```
294
+
295
+ - `:between` - distribute children so there is equal space between children no space outside of the children
296
+
297
+ ```
298
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
299
+ ┃[child 1] [child 2] [child 3]┃
300
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
301
+ ```
302
+
303
+ - `:around` - distribute children so that they have equal spacing around them, space between two children is twice the space between an edge and a child.
304
+
305
+ ```
306
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
307
+ ┃ [child 1] [child 2] [child 3] ┃
308
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
309
+ ```
310
+
311
+ - `:evenly` - distribute children so there is even spacing between any two children (or space to the edge)
312
+
313
+ ```
314
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
315
+ ┃ [child 1] [child 2] [child 3] ┃
316
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
317
+ ```
318
+
319
+ The `valign` setting takes one of several values
320
+
321
+ - `:top` - align content starting at the top of the container's content area
322
+
323
+ ```
324
+ ┏━━━━━━━━━┓
325
+ ┃[child 1]┃
326
+ ┃[child 2]┃
327
+ ┃[child 3]┃
328
+ ┃ ┃
329
+ ┃ ┃
330
+ ┃ ┃
331
+ ┃ ┃
332
+ ┃ ┃
333
+ ┃ ┃
334
+ ┃ ┃
335
+ ┃ ┃
336
+ ┃ ┃
337
+ ┃ ┃
338
+ ┃ ┃
339
+ ┃ ┃
340
+ ┗━━━━━━━━━┛
341
+ ```
342
+
343
+ - `:bottom` - align content starting at the bottom of the container's content area
344
+
345
+ ```
346
+ ┏━━━━━━━━━┓
347
+ ┃ ┃
348
+ ┃ ┃
349
+ ┃ ┃
350
+ ┃ ┃
351
+ ┃ ┃
352
+ ┃ ┃
353
+ ┃ ┃
354
+ ┃ ┃
355
+ ┃ ┃
356
+ ┃ ┃
357
+ ┃ ┃
358
+ ┃ ┃
359
+ ┃[child 1]┃
360
+ ┃[child 2]┃
361
+ ┃[child 3]┃
362
+ ┗━━━━━━━━━┛
363
+ ```
364
+
365
+ - `:middle` - align content starting in the vertical middle of the container's content area
366
+
367
+ ```
368
+ ┏━━━━━━━━━┓
369
+ ┃ ┃
370
+ ┃ ┃
371
+ ┃ ┃
372
+ ┃ ┃
373
+ ┃ ┃
374
+ ┃ ┃
375
+ ┃[child 1]┃
376
+ ┃[child 2]┃
377
+ ┃[child 3]┃
378
+ ┃ ┃
379
+ ┃ ┃
380
+ ┃ ┃
381
+ ┃ ┃
382
+ ┃ ┃
383
+ ┃ ┃
384
+ ┗━━━━━━━━━┛
385
+ ```
386
+
387
+ - `:between` - distribute children so there is equal space between children no space outside of the children
388
+
389
+ ```
390
+ ┏━━━━━━━━━┓
391
+ ┃[child 1]┃
392
+ ┃ ┃
393
+ ┃ ┃
394
+ ┃ ┃
395
+ ┃ ┃
396
+ ┃ ┃
397
+ ┃ ┃
398
+ ┃[child 2]┃
399
+ ┃ ┃
400
+ ┃ ┃
401
+ ┃ ┃
402
+ ┃ ┃
403
+ ┃ ┃
404
+ ┃ ┃
405
+ ┃[child 3]┃
406
+ ┗━━━━━━━━━┛
407
+ ```
408
+
409
+ - `:around` - distribute children so that they have equal spacing around them, space between two children is twice the space between an edge and a child.
410
+
411
+ ```
412
+ ┏━━━━━━━━━┓
413
+ ┃ ┃
414
+ ┃ ┃
415
+ ┃[child 1]┃
416
+ ┃ ┃
417
+ ┃ ┃
418
+ ┃ ┃
419
+ ┃ ┃
420
+ ┃[child 2]┃
421
+ ┃ ┃
422
+ ┃ ┃
423
+ ┃ ┃
424
+ ┃ ┃
425
+ ┃[child 3]┃
426
+ ┃ ┃
427
+ ┃ ┃
428
+ ┗━━━━━━━━━┛
429
+ ```
430
+
431
+ - `:evenly` - distribute children so there is even spacing between any two children (or space to the edge)
432
+
433
+ ```
434
+ ┏━━━━━━━━━┓
435
+ ┃ ┃
436
+ ┃ ┃
437
+ ┃ ┃
438
+ ┃[child 1]┃
439
+ ┃ ┃
440
+ ┃ ┃
441
+ ┃ ┃
442
+ ┃[child 2]┃
443
+ ┃ ┃
444
+ ┃ ┃
445
+ ┃ ┃
446
+ ┃[child 3]┃
447
+ ┃ ┃
448
+ ┃ ┃
449
+ ┃ ┃
450
+ ┗━━━━━━━━━┛
451
+ ```
452
+
453
+ ##### Position
454
+
455
+ Position settings dictate the relative position from where the painter would have preferred to place the container. Negative numbers move the container left/up and positive numbers move it right/down. To set these values, use
456
+
457
+ - `set_position(left:, top:)`
458
+
459
+ ##### Sizing Model
460
+
461
+ The sizing model determines how to interpret the `width` and `height` settings. The default sizing model is `:content`, which sets the width and height of the cotent area, whereas `:border` sets the width and height of the element inlcuding the padding and border and scroll bars.
462
+
463
+ ###### Examples
464
+
465
+ In the examples below, the `~` character represents padding and would not be displayed in the acutal rendered screen.
466
+
467
+ ```ruby
468
+ settings.width = 10
469
+ settings.height = 3
470
+ settings.set_padding(left: 3, top: 1, right: 3, bottom: 1)
471
+ settings.full_border
472
+
473
+ ## Content sizing
474
+ settings.sizing = :content
475
+
476
+ # Results in the box
477
+ #
478
+ # ┏━━━━━━━━━━━━━━━━┓
479
+ # ┃~~~~~~~~~~~~~~~~┃
480
+ # ┃~~~1234567890~~~┃
481
+ # ┃~~~1234567890~~~┃
482
+ # ┃~~~1234567890~~~┃
483
+ # ┃~~~~~~~~~~~~~~~~┃
484
+ # ┗━━━━━━━━━━━━━━━━┛
485
+
486
+ ## Border sizing
487
+ settings.sizing = :border
488
+
489
+ # Results in the box
490
+ #
491
+ # ┏━━━━━━━━┓
492
+ # ┃~~~12~~~┃
493
+ # ┗━━━━━━━━┛
494
+ ```
495
+
496
+ Notice that a box rendered with `:border` sizing would fit exactly in the content area of a box with the same `width` and `height` that is rendered with `:content` sizing. For containers with no padding and no border, the resulting size is the same for either sizing model.
497
+
498
+ ##### Margin
499
+
500
+ Margin settings dictate the spacing on the outside (i.e. outside of the border) of each of the 4 sides of the container independently. To set these values, use
501
+
502
+ - `set_margin(left:, top:, right:, bottom:, horiz:, vert:)` - set any combination of margin (note: setting `horiz` and `left`/`right` or setting `vert` and `top`/`bottom` is not allowed)
503
+ - `margin.left=(value)` - set left margin
504
+ - `margin.top=(value)` - set top margin
505
+ - `margin.right=(value)` - set right margin
506
+ - `margin.bottom=(value)` - set bottom margin
507
+ - `margin.horiz=(value)` - set left and right margin to the same value
508
+ - `margin.vert=(value)` - set top and bottom margin to the same value
509
+
510
+ Note: values cannot be negative
511
+
512
+ ##### Padding
513
+
514
+ Padding settings dictate the spacing on the inside (i.e. inside of the border) of each of the 4 sides of the container independently. To set these values, use
515
+
516
+ - `set_padding(left:, top:, right:, bottom:, horiz:, vert:)` - set any combination of padding (note: setting `horiz` and `left`/`right` or setting `vert` and `top`/`bottom` is not allowed)
517
+ - `padding.left=(value)` - set left padding
518
+ - `padding.top=(value)` - set top padding
519
+ - `padding.right=(value)` - set right padding
520
+ - `padding.bottom=(value)` - set bottom padding
521
+ - `padding.horiz=(value)` - set left and right padding to the same value
522
+ - `padding.vert=(value)` - set top and bottom padding to the same value
523
+
524
+ Note: values cannot be negative
525
+
526
+ ##### Scrollbar
527
+
528
+ Scroll settings dictate whether the scrollbar will be shown when child content is larger the the container's viewport. A scrollbar adds a unit to the dimensions of a container (as opposed to overwriting the leftmost/bottommost padding)
529
+
530
+ - `set_scrollbar(horiz:, vert:)` - set both scrollbar settings
531
+ - `scrollbar.horiz=(flag)` - show/hide the horizontal scrollbar
532
+ - `scrollbar.vert=(flag)` - show/hide the vertical scrollbar
210
533
 
211
534
  ##### Border
212
535
 
213
536
  The border settings consist of 6 boolean values (border are either width 1 or not shown), the 4 obvious values (`left`, `top`, `right`, and `bottom`) along with 2 other values for inner borders (`inner_horiz` and `inner_vert`) in a grid. A border also has a foreground color (defaults to `:white`) and a style. The background color is determined by the `bg_color` of the element. Border values can be set with
214
537
 
215
- - `clear_border` - sets all border positions to `false`
216
- - `set_border(left:, top:, right:, bottom:, inner_horiz:, inner_vert:, color:, style:)`
538
+ - `set_border(left:, top:, right:, bottom:, inner_horiz:, inner_vert:, color:, style:)` - set any combination of border settings
539
+ - `full_border(style:, color:)` - set all borders to true and optionally set the style or color
540
+ - `border.left=(flag)` - show/hide left border
541
+ - `border.top=(flag)` - show/hide top border
542
+ - `border.right=(flag)` - show/hide right border
543
+ - `border.bottom=(flag)` - show/hide bottom border
544
+ - `border.inner_horiz=(flag)` - show/hide inner horizontal border (dividing grid rows)
545
+ - `border.inner_vert=(flag)` - show/hide inner vertical border (dividing grid columns)
546
+ - `border.color=(flag)` - set the border color
547
+ - `border.style=(flag)` - set the border style
217
548
 
218
549
  Available border styles are
219
550
 
@@ -254,31 +585,71 @@ Child elements can flow in one of 4 directions
254
585
  - `:l2r` left-to-right
255
586
 
256
587
  ```
257
- [child 1] [child 2] ... [child N]
588
+ # In a Box
589
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
590
+ ┃[child 1] [child 2] ... [child N]┃
591
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
592
+
593
+ # In a Grid
594
+ ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
595
+ ┃[child 1]┃[child 2]┃[child 3]┃
596
+ ┣━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━┫
597
+ ┃[chiid 4]┃[child 5]┃ ┃
598
+ ┗━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┛
258
599
  ```
259
600
 
260
601
  - `:r2l` right-to-left
261
602
 
262
603
  ```
263
- [child N] [child N - 1] ... [child 1]
604
+ # In a Box
605
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
606
+ ┃[child N] [child N - 1] ... [child 1]┃
607
+ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
608
+
609
+ # In a Grid
610
+ ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
611
+ ┃[child 3]┃[child 2]┃[child 1]┃
612
+ ┣━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━┫
613
+ ┃ ┃[chiid 5]┃[child 4]┃
614
+ ┗━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┛
264
615
  ```
265
616
 
266
617
  - `:t2b` top-to-bottom
267
618
 
268
619
  ```
269
- [child 1]
270
- [child 2]
271
- ...
272
- [child N]
620
+ # In a Box
621
+ ┏━━━━━━━━━┓
622
+ ┃[child 1]┃
623
+ [child 2]
624
+ ┃ ... ┃
625
+ ┃[child N]┃
626
+ ┗━━━━━━━━━┛
627
+
628
+ # In a Grid
629
+ ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
630
+ ┃[child 1]┃[child 3]┃[child 5]┃
631
+ ┣━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━┫
632
+ ┃[child 2]┃[child 4]┃ ┃
633
+ ┗━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┛
273
634
  ```
274
635
 
275
636
  - `:b2t` bottom-to-top
276
637
 
277
638
  ```
278
- [child N]
279
- [child N - 1]
280
- ...
281
- [child 1]
639
+ # In a Box
640
+ ┏━━━━━━━━━━━━━┓
641
+ ┃[child N] ┃
642
+ [child N - 1]
643
+ ┃ ... ┃
644
+ ┃[child 1] ┃
645
+ ┗━━━━━━━━━━━━━┛
646
+
647
+ # In a Grid
648
+ ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
649
+ ┃[child 2]┃[child 4]┃ ┃
650
+ ┣━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━┫
651
+ ┃[child 1]┃[child 3]┃[child 5]┃
652
+ ┗━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┛
282
653
  ```
283
654
 
284
655
  ##### Colors
@@ -304,14 +675,40 @@ Many of these also have a "bright" option:
304
675
  - `:bright_red`
305
676
  - `:bright_yellow`
306
677
 
678
+ ##### Large Text
679
+
680
+ The `title_font` setting for `Text`s converts the standard terminal font into a large block font. The available fonts vary from system to system. Every system will have a `:default` font available, this font could look like
681
+
682
+ ```
683
+ ██████╗ ███████╗███████╗ █████╗ ██╗ ██╗██╗ ████████╗
684
+ ██╔══██╗██╔════╝██╔════╝██╔══██╗██║ ██║██║ ╚══██╔══╝
685
+ ██║ ██║█████╗ █████╗ ███████║██║ ██║██║ ██║
686
+ ██║ ██║██╔══╝ ██╔══╝ ██╔══██║██║ ██║██║ ██║
687
+ ██████╔╝███████╗██║ ██║ ██║╚██████╔╝███████╗ ██║
688
+ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝
689
+ ```
690
+
691
+ To print out a list of all available fonts as well as sample text in that font, run
692
+
693
+ ```
694
+ $ whirled_peas title_fonts
695
+ ```
696
+
697
+ Note: when using a title font with WhirledPeas for the first time on a system, the gem loads all fonts to check which ones are available. This can be a slow process and may cause a noticeable delay when running a visualization. Running the command above will cache the results and thus when a WhirledPeas visualization is run, there will be no lag from loading fonts.
698
+
307
699
  ### Example
308
700
 
309
701
  ```ruby
310
702
  class TemplateFactory
311
703
  def build(frame, args)
312
704
  set_state(frame, args)
313
- WhirledPeas.template do |t|
314
- t.add_box('Body', &method(:body))
705
+ WhirledPeas.template do |composer, settings|
706
+ settings.flow = :l2r
707
+ settings.align = :center
708
+
709
+ composer.add_box('Title', &method(:title))
710
+ composer.add_box('Sum', &method(:sum))
711
+ composer.add_grid('NumberGrid', &method(:number_grid))
315
712
  end
316
713
  end
317
714
 
@@ -325,35 +722,86 @@ class TemplateFactory
325
722
  @high = args[:high] if args.key?(:high)
326
723
  end
327
724
 
328
- def title(_elem, settings)
725
+ def title(_composer, settings)
329
726
  settings.underline = true
330
727
  "Pair Finder"
331
728
  end
332
729
 
333
- def sum(_elem, settings)
730
+ def sum(_composer, settings)
334
731
  settings.color = @frame == 'found-pair' ? :green : :red
335
732
  @sum ? "Sum: #{@sum}" : 'N/A'
336
733
  end
337
734
 
338
- def number_grid(elem, settings)
735
+ def number_grid(composer, settings)
339
736
  settings.full_border
340
737
  @numbers.each.with_index do |num, index|
341
- g.add_text do |_, settings|
738
+ composer.add_text do |_, settings|
342
739
  settings.bg_color = (@low == index || @high == index) ? :cyan : :white
343
740
  num
344
741
  end
345
742
  end
346
743
  end
744
+ end
745
+ ```
347
746
 
348
- def body(elem, settings)
349
- settings.flow = :l2r
350
- settings.auto_margin = true
747
+ ### Debugging
351
748
 
352
- elem.add_box('Title', &method(:title))
353
- elem.add_box('Sum', &method(:sum))
354
- elem.add_grid('NumberGrid', &method(:number_grid))
355
- end
356
- end
749
+ The `whirled_peas` executable provides some commands that are helpful for debugging.
750
+
751
+ #### list_frames
752
+
753
+ List the frames sent by the driver
754
+
755
+ ```
756
+ $ whirled_peas <config file> list_frames
757
+ Frame 'start' displayed for 5 second(s)
758
+ Frame 'move' displayed for 1 frame ({:direction=>'N'})
759
+ ...
760
+ EOF frame detected
761
+ ```
762
+
763
+ #### play_frame
764
+
765
+ Displays a single frame for several seconds
766
+
767
+ ```
768
+ $ whirled_peas <config file> play_frame move '{"direction":"N"}'
769
+ ```
770
+
771
+ Adding the `--template` flag will result in printing out debug information for the template, e.g.
772
+
773
+ ```
774
+ $ whirled_peas <config file> play_frame move '{"direction":"N"}' --template
775
+ + TEMPLATE [WhirledPeas::Graphics::BoxPainter]
776
+ - Settings
777
+ WhirledPeas::Settings::BoxSettings
778
+ <default>
779
+ - Children
780
+ + TitleContainer [WhirledPeas::Graphics::BoxPainter]
781
+ ...
782
+ ```
783
+
784
+ Note: the `list_frames` command will print out frame names and arguments formatted for this command
785
+
786
+ #### loading
787
+
788
+ Displays the configured loading screen for several seconds
789
+
790
+ ```
791
+ $ whirled_peas <config file> loading
792
+ ```
793
+
794
+ Adding the `--template` flag will result in just printing out the loading template's debug information, e.g.
795
+
796
+ ```
797
+ $ whirled_peas <config file> loading --template
798
+ + TEMPLATE [WhirledPeas::Graphics::BoxPainter]
799
+ - Settings
800
+ WhirledPeas::Settings::BoxSettings
801
+ <default>
802
+ - Children
803
+ + TitleContainer [WhirledPeas::Graphics::BoxPainter]
804
+ ...
357
805
  ```
358
806
 
359
807
  ## Development
@@ -362,6 +810,22 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
362
810
 
363
811
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
364
812
 
813
+ ### Testing
814
+
815
+ In addition to standard RSpec tests, WhirledPeas has custom tests for rendered templates. These files live in `screen_test/rendered`. Each ruby file is expected to define a class named `TemplateFactory` that responds to `#build(name, args)` returning a template (the standard template factory role). Each file should also be accompanied by a `.frame` file with the same base name. This file will contain the output of the rendered screen and is considered the correct output when running tests.
816
+
817
+ Note: viewing `.frame` files with `cat` works better than most other text editors.
818
+
819
+ The following rake tasks are provided to interact with the screen tests
820
+
821
+ - `screen_test` runs all screen tests in the `screen_test/rendered` directory
822
+ - `screen_test:debug[path/to/file.rb]` render the screen without printing it, this allows for debug print statments in the code to appear in the terminal
823
+ - `screen_test:template[path/to/file.rb]` print the rendered template debug tree
824
+ - `screen_test:run[path/to/file.rb]` runs a single screen test
825
+ - `screen_test:save[path/to/file.rb]` saves the output generated by the template in the `.frame` file, overwriting any existing file
826
+ - `screen_test:view[path/to/file.rb]` views the output generated by the template
827
+ - `screen_test:update_all[path/to/file.rb]` interactively step through each pending or failed screen test to compare/set the expected output
828
+
365
829
  ## Contributing
366
830
 
367
831
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/whirled_peas. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/whirled_peas/blob/master/CODE_OF_CONDUCT.md).