ratatui_ruby 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +1 -1
  3. data/.builds/ruby-3.3.yml +1 -1
  4. data/.builds/ruby-3.4.yml +1 -1
  5. data/.builds/ruby-4.0.0.yml +1 -1
  6. data/AGENTS.md +87 -171
  7. data/CHANGELOG.md +38 -1
  8. data/README.md +8 -3
  9. data/REUSE.toml +20 -0
  10. data/doc/application_architecture.md +105 -45
  11. data/doc/application_testing.md +5 -3
  12. data/doc/contributors/design/ruby_frontend.md +9 -5
  13. data/doc/contributors/developing_examples.md +76 -18
  14. data/doc/contributors/documentation_style.md +7 -0
  15. data/doc/contributors/index.md +2 -0
  16. data/doc/event_handling.md +10 -4
  17. data/doc/images/app_all_events.png +0 -0
  18. data/doc/images/app_color_picker.png +0 -0
  19. data/doc/images/verify_readme_usage.png +0 -0
  20. data/doc/images/widget_barchart_demo.png +0 -0
  21. data/doc/images/widget_block_padding.png +0 -0
  22. data/doc/images/widget_block_titles.png +0 -0
  23. data/doc/images/widget_box_demo.png +0 -0
  24. data/doc/images/widget_calendar_demo.png +0 -0
  25. data/doc/images/widget_cell_demo.png +0 -0
  26. data/doc/images/widget_chart_demo.png +0 -0
  27. data/doc/images/widget_gauge_demo.png +0 -0
  28. data/doc/images/widget_layout_split.png +0 -0
  29. data/doc/images/widget_line_gauge_demo.png +0 -0
  30. data/doc/images/widget_list_demo.png +0 -0
  31. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  32. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  33. data/doc/images/widget_render.png +0 -0
  34. data/doc/images/widget_scrollbar_demo.png +0 -0
  35. data/doc/images/widget_sparkline_demo.png +0 -0
  36. data/doc/images/widget_style_colors.png +0 -0
  37. data/doc/images/widget_table_flex.png +0 -0
  38. data/doc/images/widget_tabs_demo.png +0 -0
  39. data/doc/interactive_design.md +25 -30
  40. data/doc/quickstart.md +147 -120
  41. data/examples/app_all_events/README.md +81 -0
  42. data/examples/app_all_events/app.rb +93 -0
  43. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  44. data/examples/app_all_events/model/event_entry.rb +75 -0
  45. data/examples/app_all_events/model/events.rb +180 -0
  46. data/examples/app_all_events/model/highlight.rb +57 -0
  47. data/examples/app_all_events/model/timestamp.rb +54 -0
  48. data/examples/app_all_events/test/snapshots/after_focus_lost.txt +24 -0
  49. data/examples/app_all_events/test/snapshots/after_focus_regained.txt +24 -0
  50. data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +24 -0
  51. data/examples/app_all_events/test/snapshots/after_key_a.txt +24 -0
  52. data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +24 -0
  53. data/examples/app_all_events/test/snapshots/after_mouse_click.txt +24 -0
  54. data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +24 -0
  55. data/examples/app_all_events/test/snapshots/after_multiple_events.txt +24 -0
  56. data/examples/app_all_events/test/snapshots/after_paste.txt +24 -0
  57. data/examples/app_all_events/test/snapshots/after_resize.txt +24 -0
  58. data/examples/app_all_events/test/snapshots/after_right_click.txt +24 -0
  59. data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +24 -0
  60. data/examples/app_all_events/test/snapshots/initial_state.txt +24 -0
  61. data/examples/app_all_events/view/app_view.rb +78 -0
  62. data/examples/app_all_events/view/controls_view.rb +50 -0
  63. data/examples/app_all_events/view/counts_view.rb +55 -0
  64. data/examples/app_all_events/view/live_view.rb +69 -0
  65. data/examples/app_all_events/view/log_view.rb +60 -0
  66. data/examples/app_all_events/view.rb +7 -0
  67. data/examples/app_all_events/view_state.rb +42 -0
  68. data/examples/app_color_picker/README.md +94 -0
  69. data/examples/app_color_picker/app.rb +112 -0
  70. data/examples/app_color_picker/clipboard.rb +84 -0
  71. data/examples/app_color_picker/color.rb +191 -0
  72. data/examples/app_color_picker/copy_dialog.rb +170 -0
  73. data/examples/app_color_picker/harmony.rb +56 -0
  74. data/examples/app_color_picker/input.rb +142 -0
  75. data/examples/app_color_picker/palette.rb +80 -0
  76. data/examples/app_color_picker/scene.rb +201 -0
  77. data/examples/{login_form → app_login_form}/app.rb +39 -42
  78. data/examples/{map_demo → app_map_demo}/app.rb +24 -21
  79. data/examples/{table_select → app_table_select}/app.rb +68 -65
  80. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +15 -6
  81. data/examples/verify_quickstart_layout/app.rb +69 -0
  82. data/examples/{quickstart_lifecycle → verify_quickstart_lifecycle}/app.rb +19 -10
  83. data/examples/verify_readme_usage/app.rb +34 -0
  84. data/examples/widget_barchart_demo/app.rb +238 -0
  85. data/examples/{block_padding → widget_block_padding}/app.rb +17 -13
  86. data/examples/{block_titles → widget_block_titles}/app.rb +25 -17
  87. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  88. data/examples/widget_calendar_demo/app.rb +109 -0
  89. data/examples/widget_cell_demo/app.rb +104 -0
  90. data/examples/widget_chart_demo/app.rb +213 -0
  91. data/examples/widget_gauge_demo/app.rb +212 -0
  92. data/examples/widget_layout_split/app.rb +246 -0
  93. data/examples/widget_line_gauge_demo/app.rb +217 -0
  94. data/examples/widget_list_demo/app.rb +382 -0
  95. data/examples/widget_list_styles/app.rb +141 -0
  96. data/examples/widget_popup_demo/app.rb +104 -0
  97. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  98. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  99. data/examples/widget_rect/app.rb +205 -0
  100. data/examples/widget_render/app.rb +184 -0
  101. data/examples/widget_rich_text/app.rb +137 -0
  102. data/examples/widget_scroll_text/app.rb +108 -0
  103. data/examples/widget_scrollbar_demo/app.rb +153 -0
  104. data/examples/widget_sparkline_demo/app.rb +274 -0
  105. data/examples/widget_style_colors/app.rb +19 -21
  106. data/examples/widget_table_flex/app.rb +95 -0
  107. data/examples/widget_tabs_demo/app.rb +167 -0
  108. data/ext/ratatui_ruby/Cargo.lock +1 -1
  109. data/ext/ratatui_ruby/Cargo.toml +1 -1
  110. data/ext/ratatui_ruby/src/events.rs +121 -36
  111. data/ext/ratatui_ruby/src/frame.rs +115 -0
  112. data/ext/ratatui_ruby/src/lib.rs +79 -26
  113. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  114. data/ext/ratatui_ruby/src/style.rs +138 -57
  115. data/ext/ratatui_ruby/src/terminal.rs +5 -9
  116. data/ext/ratatui_ruby/src/text.rs +13 -6
  117. data/ext/ratatui_ruby/src/widgets/barchart.rs +56 -54
  118. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  119. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  120. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  121. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  122. data/ext/ratatui_ruby/src/widgets/list.rs +32 -9
  123. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  124. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  125. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  126. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  127. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +4 -2
  128. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  129. data/ext/ratatui_ruby/src/widgets/table.rs +8 -4
  130. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  131. data/lib/ratatui_ruby/cell.rb +3 -3
  132. data/lib/ratatui_ruby/event/key.rb +1 -1
  133. data/lib/ratatui_ruby/event/none.rb +43 -0
  134. data/lib/ratatui_ruby/event.rb +56 -4
  135. data/lib/ratatui_ruby/frame.rb +87 -0
  136. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +11 -11
  137. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  138. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  139. data/lib/ratatui_ruby/schema/block.rb +163 -168
  140. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  141. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  142. data/lib/ratatui_ruby/schema/center.rb +46 -46
  143. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  144. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  145. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  146. data/lib/ratatui_ruby/schema/cursor.rb +25 -25
  147. data/lib/ratatui_ruby/schema/gauge.rb +53 -53
  148. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  149. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  150. data/lib/ratatui_ruby/schema/list.rb +86 -84
  151. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  152. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  153. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  154. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  155. data/lib/ratatui_ruby/schema/rect.rb +60 -60
  156. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  157. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  158. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  159. data/lib/ratatui_ruby/schema/style.rb +46 -46
  160. data/lib/ratatui_ruby/schema/table.rb +112 -119
  161. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  162. data/lib/ratatui_ruby/session/autodoc.rb +417 -0
  163. data/lib/ratatui_ruby/session.rb +40 -23
  164. data/lib/ratatui_ruby/test_helper.rb +185 -19
  165. data/lib/ratatui_ruby/version.rb +1 -1
  166. data/lib/ratatui_ruby.rb +65 -39
  167. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  168. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  169. data/sig/examples/app_all_events/model/events.rbs +15 -0
  170. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  171. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  172. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  173. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  174. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  175. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  176. data/sig/examples/app_all_events/view.rbs +8 -0
  177. data/sig/examples/app_all_events/view_state.rbs +15 -0
  178. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  179. data/sig/examples/app_login_form/app.rbs +11 -0
  180. data/sig/examples/app_map_demo/app.rbs +11 -0
  181. data/sig/examples/app_table_select/app.rbs +11 -0
  182. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  183. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  184. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  185. data/sig/examples/widget_block_padding/app.rbs +11 -0
  186. data/sig/examples/widget_block_titles/app.rbs +11 -0
  187. data/sig/examples/widget_box_demo/app.rbs +11 -0
  188. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  189. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  190. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  191. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  192. data/sig/examples/widget_layout_split/app.rbs +10 -0
  193. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  194. data/sig/examples/widget_list_demo/app.rbs +12 -0
  195. data/sig/examples/widget_list_styles/app.rbs +11 -0
  196. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  197. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  198. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  199. data/sig/examples/widget_rect/app.rbs +12 -0
  200. data/sig/examples/widget_render/app.rbs +10 -0
  201. data/sig/examples/widget_rich_text/app.rbs +11 -0
  202. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  203. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  204. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  205. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  206. data/sig/examples/widget_table_flex/app.rbs +11 -0
  207. data/sig/ratatui_ruby/frame.rbs +9 -0
  208. data/sig/ratatui_ruby/ratatui_ruby.rbs +3 -2
  209. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  210. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  211. data/sig/ratatui_ruby/session.rbs +94 -0
  212. data/tasks/autodoc/inventory.rb +61 -0
  213. data/tasks/autodoc/member.rb +56 -0
  214. data/tasks/autodoc/name.rb +19 -0
  215. data/tasks/autodoc/notice.rb +26 -0
  216. data/tasks/autodoc/rbs.rb +38 -0
  217. data/tasks/autodoc/rdoc.rb +45 -0
  218. data/tasks/autodoc.rake +47 -0
  219. data/tasks/bump/history.rb +2 -2
  220. data/tasks/doc.rake +600 -6
  221. data/tasks/example_viewer.html.erb +172 -0
  222. data/tasks/lint.rake +8 -4
  223. data/tasks/resources/index.html.erb +6 -0
  224. data/tasks/sourcehut.rake +4 -4
  225. data/tasks/terminal_preview/app_screenshot.rb +1 -3
  226. data/tasks/terminal_preview/crash_report.rb +7 -9
  227. data/tasks/terminal_preview/launcher_script.rb +4 -6
  228. data/tasks/terminal_preview/preview_collection.rb +4 -6
  229. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  230. data/tasks/terminal_preview/saved_screenshot.rb +7 -9
  231. data/tasks/terminal_preview/terminal_window.rb +7 -9
  232. data/tasks/test.rake +1 -1
  233. data/tasks/website/index_page.rb +3 -3
  234. data/tasks/website/version.rb +10 -10
  235. data/tasks/website/version_menu.rb +10 -12
  236. data/tasks/website/versioned_documentation.rb +49 -17
  237. data/tasks/website/website.rb +6 -8
  238. data/tasks/website.rake +4 -4
  239. metadata +156 -125
  240. data/LICENSES/BSD-2-Clause.txt +0 -9
  241. data/doc/contributors/better_dx.md +0 -543
  242. data/doc/contributors/example_analysis.md +0 -82
  243. data/doc/images/all_events.png +0 -0
  244. data/doc/images/block_padding.png +0 -0
  245. data/doc/images/block_titles.png +0 -0
  246. data/doc/images/box_demo.png +0 -0
  247. data/doc/images/calendar_demo.png +0 -0
  248. data/doc/images/cell_demo.png +0 -0
  249. data/doc/images/chart_demo.png +0 -0
  250. data/doc/images/flex_layout.png +0 -0
  251. data/doc/images/gauge_demo.png +0 -0
  252. data/doc/images/line_gauge_demo.png +0 -0
  253. data/doc/images/list_demo.png +0 -0
  254. data/doc/images/readme_usage.png +0 -0
  255. data/doc/images/scrollbar_demo.png +0 -0
  256. data/doc/images/sparkline_demo.png +0 -0
  257. data/doc/images/table_flex.png +0 -0
  258. data/examples/all_events/app.rb +0 -169
  259. data/examples/all_events/app.rbs +0 -7
  260. data/examples/all_events/test_app.rb +0 -139
  261. data/examples/analytics/app.rb +0 -258
  262. data/examples/analytics/app.rbs +0 -7
  263. data/examples/analytics/test_app.rb +0 -132
  264. data/examples/block_padding/app.rbs +0 -7
  265. data/examples/block_padding/test_app.rb +0 -31
  266. data/examples/block_titles/app.rbs +0 -7
  267. data/examples/block_titles/test_app.rb +0 -34
  268. data/examples/box_demo/app.rbs +0 -7
  269. data/examples/box_demo/test_app.rb +0 -88
  270. data/examples/calendar_demo/app.rb +0 -101
  271. data/examples/calendar_demo/app.rbs +0 -7
  272. data/examples/calendar_demo/test_app.rb +0 -108
  273. data/examples/cell_demo/app.rb +0 -108
  274. data/examples/cell_demo/app.rbs +0 -7
  275. data/examples/cell_demo/test_app.rb +0 -36
  276. data/examples/chart_demo/app.rb +0 -203
  277. data/examples/chart_demo/app.rbs +0 -7
  278. data/examples/chart_demo/test_app.rb +0 -102
  279. data/examples/custom_widget/app.rb +0 -51
  280. data/examples/custom_widget/app.rbs +0 -7
  281. data/examples/custom_widget/test_app.rb +0 -30
  282. data/examples/flex_layout/app.rb +0 -156
  283. data/examples/flex_layout/app.rbs +0 -7
  284. data/examples/flex_layout/test_app.rb +0 -65
  285. data/examples/gauge_demo/app.rb +0 -182
  286. data/examples/gauge_demo/test_app.rb +0 -120
  287. data/examples/hit_test/app.rb +0 -175
  288. data/examples/hit_test/app.rbs +0 -7
  289. data/examples/hit_test/test_app.rb +0 -102
  290. data/examples/line_gauge_demo/app.rb +0 -190
  291. data/examples/line_gauge_demo/app.rbs +0 -7
  292. data/examples/line_gauge_demo/test_app.rb +0 -129
  293. data/examples/list_demo/app.rb +0 -253
  294. data/examples/list_demo/test_app.rb +0 -237
  295. data/examples/list_styles/app.rb +0 -140
  296. data/examples/list_styles/app.rbs +0 -7
  297. data/examples/list_styles/test_app.rb +0 -157
  298. data/examples/login_form/app.rbs +0 -7
  299. data/examples/login_form/test_app.rb +0 -51
  300. data/examples/map_demo/app.rbs +0 -7
  301. data/examples/map_demo/test_app.rb +0 -149
  302. data/examples/mouse_events/app.rb +0 -97
  303. data/examples/mouse_events/app.rbs +0 -7
  304. data/examples/mouse_events/test_app.rb +0 -53
  305. data/examples/popup_demo/app.rb +0 -103
  306. data/examples/popup_demo/app.rbs +0 -7
  307. data/examples/popup_demo/test_app.rb +0 -54
  308. data/examples/quickstart_dsl/app.rbs +0 -7
  309. data/examples/quickstart_dsl/test_app.rb +0 -29
  310. data/examples/quickstart_lifecycle/app.rbs +0 -7
  311. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  312. data/examples/ratatui_logo_demo/app.rb +0 -79
  313. data/examples/ratatui_logo_demo/app.rbs +0 -7
  314. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  315. data/examples/ratatui_mascot_demo/app.rb +0 -84
  316. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  317. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  318. data/examples/readme_usage/app.rb +0 -29
  319. data/examples/readme_usage/app.rbs +0 -7
  320. data/examples/readme_usage/test_app.rb +0 -29
  321. data/examples/rich_text/app.rb +0 -141
  322. data/examples/rich_text/app.rbs +0 -7
  323. data/examples/rich_text/test_app.rb +0 -166
  324. data/examples/scroll_text/app.rb +0 -103
  325. data/examples/scroll_text/app.rbs +0 -7
  326. data/examples/scroll_text/test_app.rb +0 -110
  327. data/examples/scrollbar_demo/app.rb +0 -143
  328. data/examples/scrollbar_demo/app.rbs +0 -7
  329. data/examples/scrollbar_demo/test_app.rb +0 -77
  330. data/examples/sparkline_demo/app.rb +0 -240
  331. data/examples/sparkline_demo/test_app.rb +0 -107
  332. data/examples/table_flex/app.rb +0 -65
  333. data/examples/table_flex/app.rbs +0 -7
  334. data/examples/table_flex/test_app.rb +0 -36
  335. data/examples/table_select/app.rbs +0 -7
  336. data/examples/table_select/test_app.rb +0 -180
  337. data/examples/widget_style_colors/test_app.rb +0 -48
  338. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  339. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  340. /data/doc/images/{login_form.png → app_login_form.png} +0 -0
  341. /data/doc/images/{map_demo.png → app_map_demo.png} +0 -0
  342. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  343. /data/doc/images/{table_select.png → app_table_select.png} +0 -0
  344. /data/doc/images/{quickstart_dsl.png → verify_quickstart_dsl.png} +0 -0
  345. /data/doc/images/{ratatui_logo_demo.png → verify_quickstart_layout.png} +0 -0
  346. /data/doc/images/{quickstart_lifecycle.png → verify_quickstart_lifecycle.png} +0 -0
  347. /data/doc/images/{list_styles.png → widget_list_styles.png} +0 -0
  348. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  349. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  350. /data/doc/images/{rich_text.png → widget_rich_text.png} +0 -0
  351. /data/doc/images/{scroll_text.png → widget_scroll_text.png} +0 -0
@@ -7,7 +7,7 @@ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
 
8
8
  require "ratatui_ruby"
9
9
 
10
- class QuickstartDslApp
10
+ class VerifyQuickstartDsl
11
11
  def run
12
12
  # 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
13
13
  RatatuiRuby.run do |tui|
@@ -18,19 +18,28 @@ class QuickstartDslApp
18
18
  alignment: :center,
19
19
  block: tui.block(
20
20
  title: "My Ruby TUI App",
21
+ title_alignment: :center,
21
22
  borders: [:all],
22
- border_color: "cyan"
23
+ border_color: "cyan",
24
+ style: { fg: "white" }
23
25
  )
24
26
  )
25
27
 
26
28
  # 3. Use RatatuiRuby methods, too.
27
- tui.draw(view)
28
- event = tui.poll_event
29
+ tui.draw do |frame|
30
+ frame.render_widget(view, frame.area)
31
+ end
29
32
 
30
- break if event == "q" || event == :ctrl_c
33
+ # 4. Poll for events with pattern matching
34
+ case tui.poll_event
35
+ in { type: :key, code: "q" }
36
+ break
37
+ else
38
+ # Ignore other events
39
+ end
31
40
  end
32
41
  end
33
42
  end
34
43
  end
35
44
 
36
- QuickstartDslApp.new.run if __FILE__ == $PROGRAM_NAME
45
+ VerifyQuickstartDsl.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
+
8
+ require "ratatui_ruby"
9
+
10
+ class VerifyQuickstartLayout
11
+ def run
12
+ RatatuiRuby.run do |tui|
13
+ loop do
14
+ tui.draw do |frame|
15
+ # 1. Split the screen
16
+ top, bottom = tui.layout_split(
17
+ frame.area,
18
+ direction: :vertical,
19
+ constraints: [
20
+ tui.constraint_percentage(75),
21
+ tui.constraint_percentage(25),
22
+ ]
23
+ )
24
+
25
+ # 2. Render Top Widget
26
+ frame.render_widget(
27
+ tui.paragraph(
28
+ text: "Hello, Ratatui!",
29
+ alignment: :center,
30
+ block: tui.block(title: "Content", borders: [:all], border_color: "cyan")
31
+ ),
32
+ top
33
+ )
34
+
35
+ # 3. Render Bottom Widget with Styled Text
36
+ # We use a Line of Spans to style specific characters
37
+ text_line = tui.text_line(
38
+ spans: [
39
+ tui.text_span(content: "Press '"),
40
+ tui.text_span(
41
+ content: "q",
42
+ style: tui.style(modifiers: [:bold, :underlined])
43
+ ),
44
+ tui.text_span(content: "' to quit."),
45
+ ],
46
+ alignment: :center
47
+ )
48
+
49
+ frame.render_widget(
50
+ tui.paragraph(
51
+ text: text_line,
52
+ block: tui.block(title: "Controls", borders: [:all])
53
+ ),
54
+ bottom
55
+ )
56
+ end
57
+
58
+ case tui.poll_event
59
+ in { type: :key, code: "q" }
60
+ break
61
+ else
62
+ # Ignore other events
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ VerifyQuickstartLayout.new.run if __FILE__ == $PROGRAM_NAME
@@ -7,33 +7,42 @@ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
 
8
8
  require "ratatui_ruby"
9
9
 
10
- class QuickstartLifecycleApp
10
+ class VerifyQuickstartLifecycle
11
11
  def run
12
- # Using the RatatuiRuby.run block for automatic terminal setup/teardown
13
- RatatuiRuby.run do |tui|
12
+ # 1. Initialize the terminal
13
+ RatatuiRuby.init_terminal
14
+
15
+ begin
14
16
  # The Main Loop
15
17
  loop do
16
- # 1. Create your UI (Immediate Mode)
18
+ # 2. Create your UI (Immediate Mode)
17
19
  # We define a Paragraph widget inside a Block with a title and borders.
18
20
  view = RatatuiRuby::Paragraph.new(
19
21
  text: "Hello, Ratatui! Press 'q' to quit.",
20
22
  alignment: :center,
21
23
  block: RatatuiRuby::Block.new(
22
24
  title: "My Ruby TUI App",
25
+ title_alignment: :center,
23
26
  borders: [:all],
24
- border_color: "cyan"
27
+ border_color: "cyan",
28
+ style: { fg: "white" }
25
29
  )
26
30
  )
27
31
 
28
- # 2. Draw the UI
29
- tui.draw(view)
32
+ # 3. Draw the UI
33
+ RatatuiRuby.draw do |frame|
34
+ frame.render_widget(view, frame.area)
35
+ end
30
36
 
31
- # 3. Poll for events
37
+ # 4. Poll for events
32
38
  event = RatatuiRuby.poll_event
33
- break if event == "q" || event == :ctrl_c
39
+ break if event.key? && event.code == "q"
34
40
  end
41
+ ensure
42
+ # 5. Restore the terminal to its original state
43
+ RatatuiRuby.restore_terminal
35
44
  end
36
45
  end
37
46
  end
38
47
 
39
- QuickstartLifecycleApp.new.run if __FILE__ == $PROGRAM_NAME
48
+ VerifyQuickstartLifecycle.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
+
8
+ require "ratatui_ruby"
9
+ class VerifyReadmeUsage
10
+ def run
11
+ RatatuiRuby.run do |tui|
12
+ loop do
13
+ tui.draw do |frame|
14
+ frame.render_widget(
15
+ tui.paragraph(
16
+ text: "Hello, Ratatui! Press 'q' to quit.",
17
+ alignment: :center,
18
+ block: tui.block(
19
+ title: "My Ruby TUI App",
20
+ borders: [:all],
21
+ border_color: "cyan"
22
+ )
23
+ ),
24
+ frame.area
25
+ )
26
+ end
27
+ event = tui.poll_event
28
+ break if event == "q" || event == :ctrl_c
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ VerifyReadmeUsage.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # Demonstrates categorical data visualization with interactive attribute cycling.
10
+ #
11
+ # Raw tables of numbers are hard to scan. Comparing magnitudes requires mental arithmetic, which slows down decision-making.
12
+ #
13
+ # This demo showcases the <tt>BarChart</tt> widget. It provides an interactive playground where you can cycle through different data formats, styles, and orientations in real-time.
14
+ #
15
+ # Use it to understand how to visualize and compare discrete datasets effectively.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_barchart_demo/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_barchart_demo.png
24
+ class WidgetBarchartDemo
25
+ def initialize
26
+ @data_index = 0
27
+ @styles = nil # Initialized in run
28
+ @style_index = 0
29
+ @label_style_index = 0
30
+ @value_style_index = 0
31
+ @bar_sets = [
32
+ { name: "Default", set: nil },
33
+ { name: "Numbers (Short)", set: { 8 => "8", 7 => "7", 6 => "6", 5 => "5", 4 => "4", 3 => "3", 2 => "2", 1 => "1", 0 => "0" } },
34
+ { name: "Letters (Long)", set: { full: "H", seven_eighths: "G", three_quarters: "F", five_eighths: "E", half: "D", three_eighths: "C", one_quarter: "B", one_eighth: "A", empty: " " } },
35
+ { name: "ASCII (Heights)", set: [" ", "_", ".", "-", "=", "+", "*", "#", "@"] },
36
+ ]
37
+ @bar_set_index = 0
38
+ @direction = :vertical
39
+ @bar_width = 8
40
+ @bar_gap = 1
41
+ @group_gap = 0
42
+ @height_mode = :full
43
+ @hotkey_style = nil
44
+ end
45
+
46
+ def run
47
+ RatatuiRuby.run do |tui|
48
+ @tui = tui
49
+ init_styles
50
+
51
+ loop do
52
+ render
53
+ break if handle_input == :quit
54
+ end
55
+ end
56
+ end
57
+
58
+ private def init_styles
59
+ @styles = [
60
+ { name: "Green", style: @tui.style(fg: :green) },
61
+ { name: "Blue", style: @tui.style(fg: :blue) },
62
+ { name: "Red", style: @tui.style(fg: :red) },
63
+ { name: "Cyan", style: @tui.style(fg: :cyan) },
64
+ { name: "Yellow Bold", style: @tui.style(fg: :yellow, modifiers: [:bold]) },
65
+ { name: "Reversed", style: @tui.style(modifiers: [:reversed]) },
66
+ ]
67
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
68
+ end
69
+
70
+ private def current_data
71
+ case @data_index
72
+ when 0 # Simple Hash
73
+ {
74
+ "Q1" => 50,
75
+ "Q2" => 80,
76
+ "Q3" => 45,
77
+ "Q4" => 60,
78
+ "Q1'" => 55,
79
+ "Q2'" => 85,
80
+ "Q3'" => 50,
81
+ "Q4'" => 65,
82
+ }
83
+ when 1 # Array with styles
84
+ [
85
+ ["Mon", 120],
86
+ ["Tue", 150],
87
+ ["Wed", 130],
88
+ ["Thu", 160],
89
+ ["Fri", 140],
90
+ ["Sat", 110, @tui.style(fg: :red)],
91
+ ["Sun", 100, @tui.style(fg: :red)],
92
+ ]
93
+ when 2 # Groups
94
+ [
95
+ @tui.bar_chart_bar_group(label: "2024", bars: [
96
+ @tui.bar_chart_bar(value: 40, label: "Q1"),
97
+ @tui.bar_chart_bar(value: 45, label: "Q2"),
98
+ @tui.bar_chart_bar(value: 50, label: "Q3"),
99
+ @tui.bar_chart_bar(value: 55, label: "Q4"),
100
+ ]),
101
+ @tui.bar_chart_bar_group(label: "2025", bars: [
102
+ @tui.bar_chart_bar(value: 60, label: "Q1", style: @tui.style(fg: :yellow)),
103
+ @tui.bar_chart_bar(value: 65, label: "Q2", style: @tui.style(fg: :yellow)),
104
+ @tui.bar_chart_bar(value: 70, label: "Q3", style: @tui.style(fg: :yellow)),
105
+ @tui.bar_chart_bar(value: 75, label: "Q4", style: @tui.style(fg: :yellow)),
106
+ ]),
107
+ ]
108
+ end
109
+ end
110
+
111
+ private def data_name
112
+ ["Simple Hash", "Styled Array", "Groups"][@data_index]
113
+ end
114
+
115
+ private def render
116
+ @tui.draw do |frame|
117
+ chart_area, controls_area = @tui.layout_split(
118
+ frame.area,
119
+ direction: :vertical,
120
+ constraints: [
121
+ @tui.constraint_fill(1),
122
+ @tui.constraint_length(6),
123
+ ]
124
+ )
125
+
126
+ # Handle Mini Mode
127
+ effective_chart_area = if @height_mode == :mini
128
+ mini_area, = @tui.layout_split(
129
+ chart_area,
130
+ direction: :vertical,
131
+ constraints: [
132
+ @tui.constraint_length(3),
133
+ @tui.constraint_fill(1),
134
+ ]
135
+ )
136
+ mini_area
137
+ else
138
+ chart_area
139
+ end
140
+
141
+ bar_chart = @tui.bar_chart(
142
+ data: current_data,
143
+ bar_width: @bar_width,
144
+ style: @styles[@style_index][:style],
145
+ bar_gap: @bar_gap,
146
+ group_gap: @group_gap,
147
+ direction: @direction,
148
+ label_style: @styles[@label_style_index][:style],
149
+ value_style: @styles[@value_style_index][:style],
150
+ bar_set: @bar_sets[@bar_set_index][:set],
151
+ block: @tui.block(
152
+ title: "BarChart Demo: #{data_name}",
153
+ borders: [:all]
154
+ )
155
+ )
156
+ frame.render_widget(bar_chart, effective_chart_area)
157
+
158
+ render_controls(frame, controls_area)
159
+ end
160
+ end
161
+
162
+ private def render_controls(frame, area)
163
+ controls = @tui.block(
164
+ title: "Controls",
165
+ borders: [:all],
166
+ children: [
167
+ @tui.paragraph(
168
+ text: [
169
+ @tui.text_line(spans: [
170
+ @tui.text_span(content: "d", style: @hotkey_style),
171
+ @tui.text_span(content: ": Data (#{data_name}) "),
172
+ @tui.text_span(content: "v", style: @hotkey_style),
173
+ @tui.text_span(content: ": Direction (#{@direction}) "),
174
+ @tui.text_span(content: "q", style: @hotkey_style),
175
+ @tui.text_span(content: ": Quit"),
176
+ ]),
177
+ @tui.text_line(spans: [
178
+ @tui.text_span(content: "w", style: @hotkey_style),
179
+ @tui.text_span(content: ": Width (#{@bar_width}) "),
180
+ @tui.text_span(content: "a", style: @hotkey_style),
181
+ @tui.text_span(content: ": Gap (#{@bar_gap}) "),
182
+ @tui.text_span(content: "g", style: @hotkey_style),
183
+ @tui.text_span(content: ": Group Gap (#{@group_gap})"),
184
+ ]),
185
+ @tui.text_line(spans: [
186
+ @tui.text_span(content: "s", style: @hotkey_style),
187
+ @tui.text_span(content: ": Style (#{@styles[@style_index][:name]}) "),
188
+ @tui.text_span(content: "x", style: @hotkey_style),
189
+ @tui.text_span(content: ": Label (#{@styles[@label_style_index][:name]}) "),
190
+ @tui.text_span(content: "z", style: @hotkey_style),
191
+ @tui.text_span(content: ": Value (#{@styles[@value_style_index][:name]}) "),
192
+ ]),
193
+ @tui.text_line(spans: [
194
+ @tui.text_span(content: "b", style: @hotkey_style),
195
+ @tui.text_span(content: ": Set (#{@bar_sets[@bar_set_index][:name]}) "),
196
+ @tui.text_span(content: "m", style: @hotkey_style),
197
+ @tui.text_span(content: ": Mode (#{(@height_mode == :full) ? 'Full' : 'Mini'})"),
198
+ ]),
199
+ ]
200
+ ),
201
+ ]
202
+ )
203
+ frame.render_widget(controls, area)
204
+ end
205
+
206
+ private def handle_input
207
+ case @tui.poll_event
208
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
209
+ :quit
210
+ in type: :key, code: "d"
211
+ @data_index = (@data_index + 1) % 3
212
+ in type: :key, code: "v"
213
+ @direction = (@direction == :vertical) ? :horizontal : :vertical
214
+ # Adjust width default based on direction for better UX, though user can manually adjust 'w'
215
+ @bar_width = (@direction == :vertical) ? 8 : 1
216
+ in type: :key, code: "w"
217
+ @bar_width = (@bar_width % 10) + 1
218
+ in type: :key, code: "a"
219
+ @bar_gap = (@bar_gap + 1) % 5
220
+ in type: :key, code: "g"
221
+ @group_gap = (@group_gap + 1) % 5
222
+ in type: :key, code: "s"
223
+ @style_index = (@style_index + 1) % @styles.size
224
+ in type: :key, code: "x"
225
+ @label_style_index = (@label_style_index + 1) % @styles.size
226
+ in type: :key, code: "z"
227
+ @value_style_index = (@value_style_index + 1) % @styles.size
228
+ in type: :key, code: "b"
229
+ @bar_set_index = (@bar_set_index + 1) % @bar_sets.size
230
+ in type: :key, code: "m"
231
+ @height_mode = (@height_mode == :full) ? :mini : :full
232
+ else
233
+ # Ignore
234
+ end
235
+ end
236
+ end
237
+
238
+ WidgetBarchartDemo.new.run if __FILE__ == $0
@@ -7,7 +7,7 @@ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
  require "ratatui_ruby"
8
8
 
9
9
  # A demo showing Block padding capabilities
10
- class BlockPaddingApp
10
+ class WidgetBlockPadding
11
11
  def run
12
12
  RatatuiRuby.run do |tui|
13
13
  loop do
@@ -38,18 +38,22 @@ class BlockPaddingApp
38
38
  text: "Press 'q' to quit."
39
39
  )
40
40
 
41
- # Layout
42
- layout = RatatuiRuby::Layout.new(
43
- direction: :vertical,
44
- constraints: [
45
- RatatuiRuby::Constraint.length(10), # Uniform Padding
46
- RatatuiRuby::Constraint.length(10), # Directional Padding
47
- RatatuiRuby::Constraint.min(0)
48
- ],
49
- children: [para1, para2, para3]
50
- )
41
+ tui.draw do |frame|
42
+ # Layout
43
+ areas = RatatuiRuby::Layout.split(
44
+ frame.area,
45
+ direction: :vertical,
46
+ constraints: [
47
+ RatatuiRuby::Constraint.length(10), # Uniform Padding
48
+ RatatuiRuby::Constraint.length(10), # Directional Padding
49
+ RatatuiRuby::Constraint.min(0),
50
+ ]
51
+ )
51
52
 
52
- tui.draw(layout)
53
+ frame.render_widget(para1, areas[0])
54
+ frame.render_widget(para2, areas[1])
55
+ frame.render_widget(para3, areas[2])
56
+ end
53
57
 
54
58
  event = tui.poll_event
55
59
  break if event == "q" || event == :ctrl_c
@@ -59,5 +63,5 @@ class BlockPaddingApp
59
63
  end
60
64
 
61
65
  if __FILE__ == $0
62
- BlockPaddingApp.new.run
66
+ WidgetBlockPadding.new.run
63
67
  end
@@ -1,10 +1,14 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ #
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later
4
+
1
5
  # frozen_string_literal: true
2
6
 
3
7
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
4
8
  require "ratatui_ruby"
5
9
 
6
10
  # Initialize the terminal
7
- class BlockTitlesApp
11
+ class WidgetBlockTitles
8
12
  def run
9
13
  RatatuiRuby.run do |tui|
10
14
  loop do
@@ -13,7 +17,7 @@ class BlockTitlesApp
13
17
  tui.block(
14
18
  titles: [
15
19
  { content: "Top Left", alignment: :left, position: :top },
16
- { content: "Top Right", alignment: :right, position: :top }
20
+ { content: "Top Right", alignment: :right, position: :top },
17
21
  ],
18
22
  borders: [:all],
19
23
  border_color: "cyan"
@@ -22,32 +26,36 @@ class BlockTitlesApp
22
26
  titles: [
23
27
  { content: "Bottom Left", alignment: :left, position: :bottom },
24
28
  { content: "Bottom Center", alignment: :center, position: :bottom },
25
- { content: "Bottom Right", alignment: :right, position: :bottom }
29
+ { content: "Bottom Right", alignment: :right, position: :bottom },
26
30
  ],
27
31
  borders: [:all],
28
32
  border_color: "magenta"
29
33
  ),
30
34
  tui.block(
31
35
  titles: [
32
- "Simple String Title (Top Left Default)",
33
- { content: "Mixed Title", alignment: :center, position: :bottom }
36
+ "Simple String Title (Top Left Default)",
37
+ { content: "Mixed Title", alignment: :center, position: :bottom },
34
38
  ],
35
39
  borders: [:all],
36
40
  border_color: "green"
37
- )
41
+ ),
38
42
  ]
39
43
 
40
- layout = tui.layout(
41
- direction: :vertical,
42
- constraints: [
43
- tui.constraint(:length, 10),
44
- tui.constraint(:length, 10),
45
- tui.constraint(:length, 10)
46
- ],
47
- children: blocks
48
- )
44
+ tui.draw do |frame|
45
+ layout = tui.layout_split(
46
+ frame.area,
47
+ direction: :vertical,
48
+ constraints: [
49
+ tui.constraint(:length, 10),
50
+ tui.constraint(:length, 10),
51
+ tui.constraint(:length, 10),
52
+ ]
53
+ )
49
54
 
50
- tui.draw(layout)
55
+ layout.each_with_index do |area, i|
56
+ frame.render_widget(blocks[i], area) if blocks[i]
57
+ end
58
+ end
51
59
 
52
60
  event = tui.poll_event
53
61
  break if event == "q" || event == :ctrl_c
@@ -57,5 +65,5 @@ class BlockTitlesApp
57
65
  end
58
66
 
59
67
  if __FILE__ == $0
60
- BlockTitlesApp.new.run
68
+ WidgetBlockTitles.new.run
61
69
  end