ratatui_ruby 0.4.0 → 0.6.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 (441) 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 +98 -176
  7. data/CHANGELOG.md +80 -6
  8. data/README.md +19 -7
  9. data/REUSE.toml +15 -0
  10. data/doc/application_architecture.md +179 -45
  11. data/doc/application_testing.md +80 -32
  12. data/doc/contributors/design/ruby_frontend.md +48 -8
  13. data/doc/contributors/design/rust_backend.md +1 -0
  14. data/doc/contributors/developing_examples.md +191 -48
  15. data/doc/contributors/documentation_style.md +7 -0
  16. data/doc/contributors/examples_audit/p1_high.md +21 -0
  17. data/doc/contributors/examples_audit/p2_moderate.md +81 -0
  18. data/doc/contributors/examples_audit.md +41 -0
  19. data/doc/contributors/index.md +2 -0
  20. data/doc/event_handling.md +21 -7
  21. data/doc/images/app_all_events.png +0 -0
  22. data/doc/images/app_color_picker.png +0 -0
  23. data/doc/images/app_login_form.png +0 -0
  24. data/doc/images/app_stateful_interaction.png +0 -0
  25. data/doc/images/verify_quickstart_dsl.png +0 -0
  26. data/doc/images/verify_quickstart_layout.png +0 -0
  27. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  28. data/doc/images/verify_readme_usage.png +0 -0
  29. data/doc/images/widget_barchart_demo.png +0 -0
  30. data/doc/images/widget_block_demo.png +0 -0
  31. data/doc/images/widget_box_demo.png +0 -0
  32. data/doc/images/widget_calendar_demo.png +0 -0
  33. data/doc/images/widget_canvas_demo.png +0 -0
  34. data/doc/images/widget_cell_demo.png +0 -0
  35. data/doc/images/widget_center_demo.png +0 -0
  36. data/doc/images/widget_chart_demo.png +0 -0
  37. data/doc/images/widget_gauge_demo.png +0 -0
  38. data/doc/images/widget_layout_split.png +0 -0
  39. data/doc/images/widget_line_gauge_demo.png +0 -0
  40. data/doc/images/widget_list_demo.png +0 -0
  41. data/doc/images/widget_overlay_demo.png +0 -0
  42. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  43. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  44. data/doc/images/widget_render.png +0 -0
  45. data/doc/images/widget_rich_text.png +0 -0
  46. data/doc/images/widget_scroll_text.png +0 -0
  47. data/doc/images/widget_scrollbar_demo.png +0 -0
  48. data/doc/images/widget_sparkline_demo.png +0 -0
  49. data/doc/images/widget_style_colors.png +0 -0
  50. data/doc/images/widget_table_demo.png +0 -0
  51. data/doc/images/widget_table_flex.png +0 -0
  52. data/doc/images/widget_tabs_demo.png +0 -0
  53. data/doc/images/widget_text_width.png +0 -0
  54. data/doc/interactive_design.md +25 -30
  55. data/doc/quickstart.md +150 -130
  56. data/doc/terminal_limitations.md +92 -0
  57. data/examples/app_all_events/README.md +99 -0
  58. data/examples/app_all_events/app.rb +96 -0
  59. data/examples/app_all_events/model/app_model.rb +157 -0
  60. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  61. data/examples/app_all_events/model/event_entry.rb +92 -0
  62. data/examples/app_all_events/model/msg.rb +37 -0
  63. data/examples/app_all_events/model/timestamp.rb +54 -0
  64. data/examples/app_all_events/update.rb +73 -0
  65. data/examples/app_all_events/view/app_view.rb +78 -0
  66. data/examples/app_all_events/view/controls_view.rb +52 -0
  67. data/examples/app_all_events/view/counts_view.rb +59 -0
  68. data/examples/app_all_events/view/live_view.rb +70 -0
  69. data/examples/app_all_events/view/log_view.rb +55 -0
  70. data/examples/app_all_events/view.rb +7 -0
  71. data/examples/app_color_picker/README.md +134 -0
  72. data/examples/app_color_picker/app.rb +74 -0
  73. data/examples/app_color_picker/clipboard.rb +84 -0
  74. data/examples/app_color_picker/color.rb +191 -0
  75. data/examples/app_color_picker/controls.rb +90 -0
  76. data/examples/app_color_picker/copy_dialog.rb +166 -0
  77. data/examples/app_color_picker/export_pane.rb +126 -0
  78. data/examples/app_color_picker/harmony.rb +56 -0
  79. data/examples/app_color_picker/input.rb +174 -0
  80. data/examples/app_color_picker/main_container.rb +178 -0
  81. data/examples/app_color_picker/palette.rb +109 -0
  82. data/examples/app_login_form/README.md +47 -0
  83. data/examples/{login_form → app_login_form}/app.rb +38 -42
  84. data/examples/app_stateful_interaction/README.md +31 -0
  85. data/examples/app_stateful_interaction/app.rb +272 -0
  86. data/examples/timeout_demo.rb +43 -0
  87. data/examples/verify_quickstart_dsl/README.md +48 -0
  88. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +17 -6
  89. data/examples/verify_quickstart_layout/README.md +71 -0
  90. data/examples/verify_quickstart_layout/app.rb +71 -0
  91. data/examples/verify_quickstart_lifecycle/README.md +56 -0
  92. data/examples/verify_quickstart_lifecycle/app.rb +54 -0
  93. data/examples/verify_readme_usage/README.md +43 -0
  94. data/examples/verify_readme_usage/app.rb +40 -0
  95. data/examples/widget_barchart_demo/README.md +49 -0
  96. data/examples/widget_barchart_demo/app.rb +238 -0
  97. data/examples/widget_block_demo/README.md +34 -0
  98. data/examples/widget_block_demo/app.rb +256 -0
  99. data/examples/widget_box_demo/README.md +45 -0
  100. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  101. data/examples/widget_calendar_demo/README.md +39 -0
  102. data/examples/widget_calendar_demo/app.rb +109 -0
  103. data/examples/widget_canvas_demo/README.md +27 -0
  104. data/examples/widget_canvas_demo/app.rb +123 -0
  105. data/examples/widget_cell_demo/README.md +36 -0
  106. data/examples/widget_cell_demo/app.rb +111 -0
  107. data/examples/widget_center_demo/README.md +29 -0
  108. data/examples/widget_center_demo/app.rb +116 -0
  109. data/examples/widget_chart_demo/README.md +41 -0
  110. data/examples/widget_chart_demo/app.rb +218 -0
  111. data/examples/widget_gauge_demo/README.md +41 -0
  112. data/examples/widget_gauge_demo/app.rb +212 -0
  113. data/examples/widget_layout_split/README.md +44 -0
  114. data/examples/widget_layout_split/app.rb +246 -0
  115. data/examples/widget_line_gauge_demo/README.md +41 -0
  116. data/examples/widget_line_gauge_demo/app.rb +217 -0
  117. data/examples/widget_list_demo/README.md +49 -0
  118. data/examples/widget_list_demo/app.rb +366 -0
  119. data/examples/widget_map_demo/README.md +39 -0
  120. data/examples/{map_demo → widget_map_demo}/app.rb +24 -21
  121. data/examples/widget_overlay_demo/app.rb +248 -0
  122. data/examples/widget_popup_demo/README.md +36 -0
  123. data/examples/widget_popup_demo/app.rb +104 -0
  124. data/examples/widget_ratatui_logo_demo/README.md +34 -0
  125. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  126. data/examples/widget_ratatui_mascot_demo/README.md +34 -0
  127. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  128. data/examples/widget_rect/README.md +38 -0
  129. data/examples/widget_rect/app.rb +205 -0
  130. data/examples/widget_render/README.md +37 -0
  131. data/examples/widget_render/app.rb +184 -0
  132. data/examples/widget_rich_text/README.md +35 -0
  133. data/examples/widget_rich_text/app.rb +166 -0
  134. data/examples/widget_scroll_text/README.md +37 -0
  135. data/examples/widget_scroll_text/app.rb +107 -0
  136. data/examples/widget_scrollbar_demo/README.md +37 -0
  137. data/examples/widget_scrollbar_demo/app.rb +153 -0
  138. data/examples/widget_sparkline_demo/README.md +42 -0
  139. data/examples/widget_sparkline_demo/app.rb +275 -0
  140. data/examples/widget_style_colors/README.md +34 -0
  141. data/examples/widget_style_colors/app.rb +19 -21
  142. data/examples/widget_table_demo/README.md +48 -0
  143. data/examples/widget_table_demo/app.rb +239 -0
  144. data/examples/widget_tabs_demo/README.md +41 -0
  145. data/examples/widget_tabs_demo/app.rb +181 -0
  146. data/examples/widget_text_width/README.md +35 -0
  147. data/examples/widget_text_width/app.rb +106 -0
  148. data/ext/ratatui_ruby/Cargo.lock +11 -4
  149. data/ext/ratatui_ruby/Cargo.toml +2 -1
  150. data/ext/ratatui_ruby/src/events.rs +359 -62
  151. data/ext/ratatui_ruby/src/frame.rs +227 -0
  152. data/ext/ratatui_ruby/src/lib.rs +110 -27
  153. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  154. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  155. data/ext/ratatui_ruby/src/style.rs +138 -57
  156. data/ext/ratatui_ruby/src/terminal.rs +42 -22
  157. data/ext/ratatui_ruby/src/text.rs +14 -7
  158. data/ext/ratatui_ruby/src/widgets/barchart.rs +74 -54
  159. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  160. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  161. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  162. data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
  163. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  164. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
  165. data/ext/ratatui_ruby/src/widgets/list.rs +211 -12
  166. data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
  167. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  168. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  169. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  170. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  171. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  172. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +97 -3
  173. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  174. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  175. data/ext/ratatui_ruby/src/widgets/table.rs +121 -5
  176. data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
  177. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  178. data/lib/ratatui_ruby/cell.rb +7 -7
  179. data/lib/ratatui_ruby/event/key/character.rb +35 -0
  180. data/lib/ratatui_ruby/event/key/media.rb +44 -0
  181. data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
  182. data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
  183. data/lib/ratatui_ruby/event/key/system.rb +45 -0
  184. data/lib/ratatui_ruby/event/key.rb +112 -52
  185. data/lib/ratatui_ruby/event/mouse.rb +3 -3
  186. data/lib/ratatui_ruby/event/none.rb +43 -0
  187. data/lib/ratatui_ruby/event/paste.rb +1 -1
  188. data/lib/ratatui_ruby/event.rb +56 -4
  189. data/lib/ratatui_ruby/frame.rb +183 -0
  190. data/lib/ratatui_ruby/list_state.rb +88 -0
  191. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +13 -13
  192. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  193. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  194. data/lib/ratatui_ruby/schema/block.rb +163 -168
  195. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  196. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  197. data/lib/ratatui_ruby/schema/center.rb +46 -46
  198. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  199. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  200. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  201. data/lib/ratatui_ruby/schema/cursor.rb +30 -25
  202. data/lib/ratatui_ruby/schema/gauge.rb +54 -52
  203. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  204. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  205. data/lib/ratatui_ruby/schema/list.rb +103 -80
  206. data/lib/ratatui_ruby/schema/list_item.rb +41 -0
  207. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  208. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  209. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  210. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  211. data/lib/ratatui_ruby/schema/rect.rb +99 -56
  212. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  213. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  214. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  215. data/lib/ratatui_ruby/schema/style.rb +66 -46
  216. data/lib/ratatui_ruby/schema/table.rb +126 -115
  217. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  218. data/lib/ratatui_ruby/schema/text.rb +69 -1
  219. data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
  220. data/lib/ratatui_ruby/session/autodoc.rb +482 -0
  221. data/lib/ratatui_ruby/session.rb +55 -23
  222. data/lib/ratatui_ruby/table_state.rb +90 -0
  223. data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
  224. data/lib/ratatui_ruby/test_helper/snapshot.rb +390 -0
  225. data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
  226. data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
  227. data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
  228. data/lib/ratatui_ruby/test_helper.rb +66 -193
  229. data/lib/ratatui_ruby/version.rb +1 -1
  230. data/lib/ratatui_ruby.rb +100 -51
  231. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  232. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  233. data/sig/examples/app_all_events/model/events.rbs +15 -0
  234. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  235. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  236. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  237. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  238. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  239. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  240. data/sig/examples/app_all_events/view.rbs +8 -0
  241. data/sig/examples/app_all_events/view_state.rbs +15 -0
  242. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  243. data/sig/examples/app_login_form/app.rbs +11 -0
  244. data/sig/examples/app_stateful_interaction/app.rbs +33 -0
  245. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  246. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  247. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  248. data/sig/examples/widget_block_demo/app.rbs +32 -0
  249. data/sig/examples/widget_box_demo/app.rbs +11 -0
  250. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  251. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  252. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  253. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  254. data/sig/examples/widget_layout_split/app.rbs +10 -0
  255. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  256. data/sig/examples/widget_list_demo/app.rbs +12 -0
  257. data/sig/examples/widget_map_demo/app.rbs +11 -0
  258. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  259. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  260. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  261. data/sig/examples/widget_rect/app.rbs +12 -0
  262. data/sig/examples/widget_render/app.rbs +10 -0
  263. data/sig/examples/widget_rich_text/app.rbs +11 -0
  264. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  265. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  266. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  267. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  268. data/sig/examples/widget_table_demo/app.rbs +11 -0
  269. data/sig/examples/widget_text_width/app.rbs +10 -0
  270. data/sig/ratatui_ruby/event.rbs +11 -1
  271. data/sig/ratatui_ruby/frame.rbs +11 -0
  272. data/sig/ratatui_ruby/list_state.rbs +13 -0
  273. data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -4
  274. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
  275. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  276. data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
  277. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  278. data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
  279. data/sig/ratatui_ruby/schema/list.rbs +4 -2
  280. data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
  281. data/sig/ratatui_ruby/schema/rect.rbs +3 -0
  282. data/sig/ratatui_ruby/schema/style.rbs +3 -3
  283. data/sig/ratatui_ruby/schema/table.rbs +3 -1
  284. data/sig/ratatui_ruby/schema/text.rbs +8 -6
  285. data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
  286. data/sig/ratatui_ruby/session.rbs +107 -0
  287. data/sig/ratatui_ruby/table_state.rbs +15 -0
  288. data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
  289. data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
  290. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
  291. data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
  292. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
  293. data/sig/ratatui_ruby/test_helper.rbs +5 -4
  294. data/tasks/autodoc/examples.rb +79 -0
  295. data/tasks/autodoc/inventory.rb +63 -0
  296. data/tasks/autodoc/member.rb +56 -0
  297. data/tasks/autodoc/name.rb +19 -0
  298. data/tasks/autodoc/notice.rb +26 -0
  299. data/tasks/autodoc/rbs.rb +38 -0
  300. data/tasks/autodoc/rdoc.rb +45 -0
  301. data/tasks/autodoc.rake +53 -0
  302. data/tasks/bump/changelog.rb +3 -3
  303. data/tasks/bump/history.rb +2 -2
  304. data/tasks/bump/links.rb +67 -0
  305. data/tasks/doc.rake +600 -6
  306. data/tasks/example_viewer.html.erb +172 -0
  307. data/tasks/lint.rake +8 -4
  308. data/tasks/resources/index.html.erb +6 -0
  309. data/tasks/sourcehut.rake +70 -30
  310. data/tasks/terminal_preview/app_screenshot.rb +14 -6
  311. data/tasks/terminal_preview/crash_report.rb +7 -9
  312. data/tasks/terminal_preview/launcher_script.rb +4 -6
  313. data/tasks/terminal_preview/preview_collection.rb +4 -6
  314. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  315. data/tasks/terminal_preview/saved_screenshot.rb +10 -11
  316. data/tasks/terminal_preview/terminal_window.rb +7 -9
  317. data/tasks/test.rake +1 -1
  318. data/tasks/website/index_page.rb +3 -3
  319. data/tasks/website/version.rb +10 -10
  320. data/tasks/website/version_menu.rb +10 -12
  321. data/tasks/website/versioned_documentation.rb +49 -17
  322. data/tasks/website/website.rb +6 -8
  323. data/tasks/website.rake +4 -4
  324. metadata +232 -127
  325. data/LICENSES/BSD-2-Clause.txt +0 -9
  326. data/doc/contributors/better_dx.md +0 -543
  327. data/doc/contributors/example_analysis.md +0 -82
  328. data/doc/images/all_events.png +0 -0
  329. data/doc/images/block_padding.png +0 -0
  330. data/doc/images/block_titles.png +0 -0
  331. data/doc/images/box_demo.png +0 -0
  332. data/doc/images/calendar_demo.png +0 -0
  333. data/doc/images/cell_demo.png +0 -0
  334. data/doc/images/chart_demo.png +0 -0
  335. data/doc/images/flex_layout.png +0 -0
  336. data/doc/images/gauge_demo.png +0 -0
  337. data/doc/images/line_gauge_demo.png +0 -0
  338. data/doc/images/list_demo.png +0 -0
  339. data/doc/images/list_styles.png +0 -0
  340. data/doc/images/login_form.png +0 -0
  341. data/doc/images/quickstart_dsl.png +0 -0
  342. data/doc/images/quickstart_lifecycle.png +0 -0
  343. data/doc/images/readme_usage.png +0 -0
  344. data/doc/images/rich_text.png +0 -0
  345. data/doc/images/scroll_text.png +0 -0
  346. data/doc/images/scrollbar_demo.png +0 -0
  347. data/doc/images/sparkline_demo.png +0 -0
  348. data/doc/images/table_flex.png +0 -0
  349. data/doc/images/table_select.png +0 -0
  350. data/examples/all_events/app.rb +0 -169
  351. data/examples/all_events/app.rbs +0 -7
  352. data/examples/all_events/test_app.rb +0 -139
  353. data/examples/analytics/app.rb +0 -258
  354. data/examples/analytics/app.rbs +0 -7
  355. data/examples/analytics/test_app.rb +0 -132
  356. data/examples/block_padding/app.rb +0 -63
  357. data/examples/block_padding/app.rbs +0 -7
  358. data/examples/block_padding/test_app.rb +0 -31
  359. data/examples/block_titles/app.rb +0 -61
  360. data/examples/block_titles/app.rbs +0 -7
  361. data/examples/block_titles/test_app.rb +0 -34
  362. data/examples/box_demo/app.rbs +0 -7
  363. data/examples/box_demo/test_app.rb +0 -88
  364. data/examples/calendar_demo/app.rb +0 -101
  365. data/examples/calendar_demo/app.rbs +0 -7
  366. data/examples/calendar_demo/test_app.rb +0 -108
  367. data/examples/cell_demo/app.rb +0 -108
  368. data/examples/cell_demo/app.rbs +0 -7
  369. data/examples/cell_demo/test_app.rb +0 -36
  370. data/examples/chart_demo/app.rb +0 -203
  371. data/examples/chart_demo/app.rbs +0 -7
  372. data/examples/chart_demo/test_app.rb +0 -102
  373. data/examples/custom_widget/app.rb +0 -51
  374. data/examples/custom_widget/app.rbs +0 -7
  375. data/examples/custom_widget/test_app.rb +0 -30
  376. data/examples/flex_layout/app.rb +0 -156
  377. data/examples/flex_layout/app.rbs +0 -7
  378. data/examples/flex_layout/test_app.rb +0 -65
  379. data/examples/gauge_demo/app.rb +0 -182
  380. data/examples/gauge_demo/test_app.rb +0 -120
  381. data/examples/hit_test/app.rb +0 -175
  382. data/examples/hit_test/app.rbs +0 -7
  383. data/examples/hit_test/test_app.rb +0 -102
  384. data/examples/line_gauge_demo/app.rb +0 -190
  385. data/examples/line_gauge_demo/app.rbs +0 -7
  386. data/examples/line_gauge_demo/test_app.rb +0 -129
  387. data/examples/list_demo/app.rb +0 -253
  388. data/examples/list_demo/test_app.rb +0 -237
  389. data/examples/list_styles/app.rb +0 -140
  390. data/examples/list_styles/app.rbs +0 -7
  391. data/examples/list_styles/test_app.rb +0 -157
  392. data/examples/login_form/app.rbs +0 -7
  393. data/examples/login_form/test_app.rb +0 -51
  394. data/examples/map_demo/app.rbs +0 -7
  395. data/examples/map_demo/test_app.rb +0 -149
  396. data/examples/mouse_events/app.rb +0 -97
  397. data/examples/mouse_events/app.rbs +0 -7
  398. data/examples/mouse_events/test_app.rb +0 -53
  399. data/examples/popup_demo/app.rb +0 -103
  400. data/examples/popup_demo/app.rbs +0 -7
  401. data/examples/popup_demo/test_app.rb +0 -54
  402. data/examples/quickstart_dsl/app.rbs +0 -7
  403. data/examples/quickstart_dsl/test_app.rb +0 -29
  404. data/examples/quickstart_lifecycle/app.rb +0 -39
  405. data/examples/quickstart_lifecycle/app.rbs +0 -7
  406. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  407. data/examples/ratatui_logo_demo/app.rb +0 -79
  408. data/examples/ratatui_logo_demo/app.rbs +0 -7
  409. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  410. data/examples/ratatui_mascot_demo/app.rb +0 -84
  411. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  412. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  413. data/examples/readme_usage/app.rb +0 -29
  414. data/examples/readme_usage/app.rbs +0 -7
  415. data/examples/readme_usage/test_app.rb +0 -29
  416. data/examples/rich_text/app.rb +0 -141
  417. data/examples/rich_text/app.rbs +0 -7
  418. data/examples/rich_text/test_app.rb +0 -166
  419. data/examples/scroll_text/app.rb +0 -103
  420. data/examples/scroll_text/app.rbs +0 -7
  421. data/examples/scroll_text/test_app.rb +0 -110
  422. data/examples/scrollbar_demo/app.rb +0 -143
  423. data/examples/scrollbar_demo/app.rbs +0 -7
  424. data/examples/scrollbar_demo/test_app.rb +0 -77
  425. data/examples/sparkline_demo/app.rb +0 -240
  426. data/examples/sparkline_demo/test_app.rb +0 -107
  427. data/examples/table_flex/app.rb +0 -65
  428. data/examples/table_flex/app.rbs +0 -7
  429. data/examples/table_flex/test_app.rb +0 -36
  430. data/examples/table_select/app.rb +0 -198
  431. data/examples/table_select/app.rbs +0 -7
  432. data/examples/table_select/test_app.rb +0 -180
  433. data/examples/widget_style_colors/test_app.rb +0 -48
  434. data/tasks/bump/comparison_links.rb +0 -41
  435. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  436. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  437. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  438. /data/doc/images/{map_demo.png → widget_map_demo.png} +0 -0
  439. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  440. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  441. /data/{doc/images/ratatui_logo_demo.png → exe/.gitkeep} +0 -0
@@ -0,0 +1,43 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # README Usage Verification
7
+
8
+ Verifies the primary usage example in the project [README](../../README.md#usage).
9
+
10
+ This example exists as a documentation regression test. It ensures that the very first code snippet a user sees actually works.
11
+
12
+ ## Usage
13
+
14
+ <!-- SYNC:START:app.rb:main -->
15
+ ```ruby
16
+ RatatuiRuby.run do |tui|
17
+ loop do
18
+ tui.draw do |frame|
19
+ frame.render_widget(
20
+ tui.paragraph(
21
+ text: "Hello, Ratatui! Press 'q' to quit.",
22
+ alignment: :center,
23
+ block: tui.block(
24
+ title: "My Ruby TUI App",
25
+ borders: [:all],
26
+ border_color: "cyan"
27
+ )
28
+ ),
29
+ frame.area
30
+ )
31
+ end
32
+ case tui.poll_event
33
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
34
+ break
35
+ else
36
+ nil
37
+ end
38
+ end
39
+ end
40
+ ```
41
+ <!-- SYNC:END -->
42
+
43
+ ![verify_readme_usage](../../doc/images/verify_readme_usage.png)
@@ -0,0 +1,40 @@
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
+ # [SYNC:START:main]
12
+ RatatuiRuby.run do |tui|
13
+ loop do
14
+ tui.draw do |frame|
15
+ frame.render_widget(
16
+ tui.paragraph(
17
+ text: "Hello, Ratatui! Press 'q' to quit.",
18
+ alignment: :center,
19
+ block: tui.block(
20
+ title: "My Ruby TUI App",
21
+ borders: [:all],
22
+ border_color: "cyan"
23
+ )
24
+ ),
25
+ frame.area
26
+ )
27
+ end
28
+ case tui.poll_event
29
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
30
+ break
31
+ else
32
+ nil
33
+ end
34
+ end
35
+ end
36
+ # [SYNC:END:main]
37
+ end
38
+ end
39
+
40
+ VerifyReadmeUsage.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,49 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # BarChart Widget Example
7
+
8
+ Visualizes categorical data with interactive attribute cycling.
9
+
10
+ Comparing magnitudes in raw tables requires mental arithmetic. Bar charts make these comparisons instant and intuitive.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **Data Formats**: Supports simple Hashes, Arrays with individual styles, and Groups (stacked/grouped bars).
15
+ - **Orientation**: Switch between Vertical and Horizontal layouts.
16
+ - **Customization**:
17
+ - Adjustable bar widths and gaps.
18
+ - Custom characters for bars (ASCII art support).
19
+ - Detailed styling for labels and values.
20
+ - **Mini Mode**: Compact rendering for dashboard widgets.
21
+
22
+ ## Hotkeys
23
+
24
+ - **d**: Cycle Data Source (`data`)
25
+ - **v**: Toggle Direction (`direction`)
26
+ - **w**: Adjust Bar Width (`bar_width`)
27
+ - **a**: Adjust Bar Gap (`bar_gap`)
28
+ - **g**: Adjust Group Gap (`group_gap`)
29
+ - **b**: Cycle Bar Character Set (`bar_set`)
30
+ - **s**: Cycle Chart Style (`style`)
31
+ - **x**: Cycle Label Style (`label_style`)
32
+ - **z**: Cycle Value Style (`value_style`)
33
+ - **m**: Toggle Mini Mode (Compact View)
34
+ - **q**: Quit
35
+
36
+ ## Usage
37
+
38
+ ```bash
39
+ ruby examples/widget_barchart_demo/app.rb
40
+ ```
41
+
42
+ ## Learning Outcomes
43
+
44
+ Use this example if you need to...
45
+ - Visualize categorical data (e.g., sales by quarter, CPU usage by core).
46
+ - Create "stats" dashboards with compact visualizations.
47
+ - Understand how `RatatuiRuby::BarChart` handles different data structures.
48
+
49
+ ![Demo](/doc/images/widget_barchart_demo.png)
@@ -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 = 2
27
+ @styles = nil # Initialized in run
28
+ @style_index = 3
29
+ @label_style_index = 3
30
+ @value_style_index = 3
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 = 2
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
@@ -0,0 +1,34 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+ # Block Widget Demo
6
+
7
+ This example demonstrates the versatile `Block` widget, which provides the visual container, borders, and titles for almost every other widget in `ratatui_ruby`.
8
+
9
+ ## Key Concepts
10
+
11
+ - **Borders:** Choose which sides to show and apply different border types (plain, rounded, double, thick, etc.).
12
+ - **Titles:** Add a main title with alignment or multiple titles at the top and bottom with independent styles and positions.
13
+ - **Padding:** Define inner spacing using uniform or directional (L/R/T/B) values.
14
+ - **Styling:** Individually style the block's content area, its borders, and its titles.
15
+ - **Custom Border Sets:** Create entirely custom border appearances by defining each character in the border set.
16
+
17
+ ## Hotkeys
18
+
19
+ - `t`: Cycle **Title** (None, Main Title)
20
+ - `a`: Cycle **Title Alignment** (Left, Center, Right)
21
+ - `s`: Cycle **Title Style** (None, Cyan Bold, Yellow Italic)
22
+ - `e`: Cycle **Additional Titles** (None, Top+Bottom, Complex)
23
+ - `b`: Cycle **Borders** (All, Top/Bottom, Left/Right, None)
24
+ - `y`: Cycle **Border Type** (Rounded, Plain, Double, Thick, Quadrant, Custom)
25
+ - `c`: Cycle **Border Style** (Magenta Bold, None, Green, Blue on White)
26
+ - `p`: Cycle **Padding** (Uniform, None, Directional, Narrow)
27
+ - `f`: Cycle **Base Style** (Dark Gray, None, White on Black)
28
+ - `q`: **Quit**
29
+
30
+ ## Usage
31
+
32
+ ```bash
33
+ ruby examples/widget_block_demo/app.rb
34
+ ```
@@ -0,0 +1,256 @@
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 the Block widget with interactive attribute cycling.
10
+ #
11
+ # Blocks are the foundation of terminal layouts, providing structure, borders, and titles.
12
+ # This demo showcases all available parameters, including advanced title positioning,
13
+ # directional padding, and custom border sets.
14
+ #
15
+ # === Examples
16
+ #
17
+ # Run the demo from the terminal:
18
+ #
19
+ # ruby examples/widget_block_demo/app.rb
20
+ #
21
+ # rdoc-image:/doc/images/widget_block_demo.png
22
+ class WidgetBlockDemo
23
+ def initialize
24
+ @title_configs = [
25
+ { name: "None", title: nil },
26
+ { name: "Main Title", title: "Main Title" },
27
+ ]
28
+ @title_index = 1
29
+
30
+ @titles_configs = [
31
+ { name: "None", titles: [] },
32
+ {
33
+ name: "Top + Bottom",
34
+ titles: [
35
+ { content: "Top Right", alignment: :right, position: :top },
36
+ { content: "Bottom Left", alignment: :left, position: :bottom },
37
+ ],
38
+ },
39
+ {
40
+ name: "Complex",
41
+ titles: [
42
+ { content: "★ Left ★", alignment: :left, position: :top },
43
+ { content: "Center", alignment: :center, position: :top },
44
+ { content: "Right", alignment: :right, position: :top },
45
+ { content: "Bottom Center", alignment: :center, position: :bottom },
46
+ ],
47
+ },
48
+ ]
49
+ @titles_index = 1
50
+
51
+ @alignment_configs = [
52
+ { name: "Left", alignment: :left },
53
+ { name: "Center", alignment: :center },
54
+ { name: "Right", alignment: :right },
55
+ ]
56
+ @alignment_index = 1 # Center
57
+
58
+ @border_configs = [
59
+ { name: "All", borders: [:all] },
60
+ { name: "Top/Bottom", borders: [:top, :bottom] },
61
+ { name: "Left/Right", borders: [:left, :right] },
62
+ { name: "None", borders: [] },
63
+ ]
64
+ @border_index = 0
65
+
66
+ @border_type_configs = [
67
+ { name: "Rounded", type: :rounded },
68
+ { name: "Plain", type: :plain },
69
+ { name: "Double", type: :double },
70
+ { name: "Thick", type: :thick },
71
+ { name: "Quadrant Inside", type: :quadrant_inside },
72
+ { name: "Quadrant Outside", type: :quadrant_outside },
73
+ {
74
+ name: "Custom Set",
75
+ type: nil,
76
+ set: {
77
+ top_left: "1",
78
+ top_right: "2",
79
+ bottom_left: "3",
80
+ bottom_right: "4",
81
+ vertical_left: "5",
82
+ vertical_right: "6",
83
+ horizontal_top: "7",
84
+ horizontal_bottom: "8",
85
+ },
86
+ },
87
+ ]
88
+ @border_type_index = 0
89
+
90
+ @padding_configs = [
91
+ { name: "Uniform (2)", padding: 2 },
92
+ { name: "None (0)", padding: 0 },
93
+ { name: "Directional (L:4, T:2)", padding: [4, 0, 2, 0] },
94
+ { name: "Narrow (H:1, V:0)", padding: [1, 1, 0, 0] },
95
+ ]
96
+ @padding_index = 0
97
+ end
98
+
99
+ def run
100
+ RatatuiRuby.run do |tui|
101
+ @tui = tui
102
+
103
+ @title_styles = [
104
+ { name: "None", style: nil },
105
+ { name: "Magenta Bold", style: @tui.style(fg: :magenta, modifiers: [:bold]) },
106
+ { name: "Cyan Bold", style: @tui.style(fg: :cyan, modifiers: [:bold]) },
107
+ { name: "Yellow Italic", style: @tui.style(fg: :yellow, modifiers: [:italic]) },
108
+ ]
109
+ @title_style_index = 1 # Magenta Bold
110
+
111
+ @border_styles = [
112
+ { name: "Cyan", style: @tui.style(fg: :cyan) },
113
+ { name: "Magenta Bold", style: @tui.style(fg: :magenta, modifiers: [:bold]) },
114
+ { name: "None", style: nil },
115
+ { name: "Blue on White", style: @tui.style(fg: :blue, bg: :white) },
116
+ ]
117
+ @border_style_index = 0
118
+
119
+ @base_styles = [
120
+ { name: "Dark Gray", style: @tui.style(fg: :dark_gray) },
121
+ { name: "None", style: nil },
122
+ { name: "White on Black", style: @tui.style(fg: :white, bg: :black) },
123
+ ]
124
+ @base_style_index = 1
125
+
126
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
127
+
128
+ loop do
129
+ render
130
+ break if handle_input == :quit
131
+ sleep 0.05
132
+ end
133
+ end
134
+ end
135
+
136
+ private def render
137
+ title_config = @title_configs[@title_index]
138
+ titles_config = @titles_configs[@titles_index]
139
+ alignment_config = @alignment_configs[@alignment_index]
140
+ title_style_config = @title_styles[@title_style_index]
141
+ border_config = @border_configs[@border_index]
142
+ border_type_config = @border_type_configs[@border_type_index]
143
+ border_style_config = @border_styles[@border_style_index]
144
+ base_style_config = @base_styles[@base_style_index]
145
+ padding_config = @padding_configs[@padding_index]
146
+
147
+ @tui.draw do |frame|
148
+ main_area, control_area = @tui.layout_split(
149
+ frame.area,
150
+ direction: :vertical,
151
+ constraints: [
152
+ @tui.constraint_fill(1),
153
+ @tui.constraint_length(10),
154
+ ]
155
+ )
156
+
157
+ # Render the demo block
158
+ demo_block = @tui.block(
159
+ title: title_config[:title],
160
+ titles: titles_config[:titles],
161
+ title_alignment: alignment_config[:alignment],
162
+ title_style: title_style_config[:style],
163
+ borders: border_config[:borders],
164
+ border_type: border_type_config[:type],
165
+ border_set: border_type_config[:set],
166
+ border_style: border_style_config[:style],
167
+ style: base_style_config[:style],
168
+ padding: padding_config[:padding]
169
+ )
170
+
171
+ # Paragraph inside the block to show padding/content interaction
172
+ content = @tui.paragraph(
173
+ text: "This paragraph is rendered inside the Block widget.\n" \
174
+ "You can see how padding and base style affect this content.\n\n" \
175
+ "Current State:\n" \
176
+ "• Padding: #{padding_config[:name]}\n" \
177
+ "• Borders: #{border_config[:name]}\n" \
178
+ "• Type: #{border_type_config[:name]}",
179
+ block: demo_block
180
+ )
181
+ frame.render_widget(content, main_area)
182
+
183
+ # Render control panel
184
+ control_panel = @tui.block(
185
+ title: "Controls",
186
+ borders: [:all],
187
+ children: [
188
+ @tui.paragraph(
189
+ text: [
190
+ @tui.text_line(spans: [
191
+ @tui.text_span(content: "t", style: @hotkey_style),
192
+ @tui.text_span(content: ": Title (#{title_config[:name]}) "),
193
+ @tui.text_span(content: "a", style: @hotkey_style),
194
+ @tui.text_span(content: ": Alignment (#{alignment_config[:name]}) "),
195
+ @tui.text_span(content: "s", style: @hotkey_style),
196
+ @tui.text_span(content: ": Title Style (#{title_style_config[:name]})"),
197
+ ]),
198
+ @tui.text_line(spans: [
199
+ @tui.text_span(content: "e", style: @hotkey_style),
200
+ @tui.text_span(content: ": Additional Titles (#{titles_config[:name]})"),
201
+ ]),
202
+ @tui.text_line(spans: [
203
+ @tui.text_span(content: "b", style: @hotkey_style),
204
+ @tui.text_span(content: ": Borders (#{border_config[:name]}) "),
205
+ @tui.text_span(content: "y", style: @hotkey_style),
206
+ @tui.text_span(content: ": Border Type (#{border_type_config[:name]})"),
207
+ ]),
208
+ @tui.text_line(spans: [
209
+ @tui.text_span(content: "c", style: @hotkey_style),
210
+ @tui.text_span(content: ": Border Style (#{border_style_config[:name]}) "),
211
+ @tui.text_span(content: "p", style: @hotkey_style),
212
+ @tui.text_span(content: ": Padding (#{padding_config[:name]})"),
213
+ ]),
214
+ @tui.text_line(spans: [
215
+ @tui.text_span(content: "f", style: @hotkey_style),
216
+ @tui.text_span(content: ": Base Style (#{base_style_config[:name]}) "),
217
+ @tui.text_span(content: "q", style: @hotkey_style),
218
+ @tui.text_span(content: ": Quit"),
219
+ ]),
220
+ ]
221
+ ),
222
+ ]
223
+ )
224
+ frame.render_widget(control_panel, control_area)
225
+ end
226
+ end
227
+
228
+ private def handle_input
229
+ case @tui.poll_event
230
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
231
+ :quit
232
+ in type: :key, code: "t"
233
+ @title_index = (@title_index + 1) % @title_configs.size
234
+ in type: :key, code: "e"
235
+ @titles_index = (@titles_index + 1) % @titles_configs.size
236
+ in type: :key, code: "a"
237
+ @alignment_index = (@alignment_index + 1) % @alignment_configs.size
238
+ in type: :key, code: "s"
239
+ @title_style_index = (@title_style_index + 1) % @title_styles.size
240
+ in type: :key, code: "b"
241
+ @border_index = (@border_index + 1) % @border_configs.size
242
+ in type: :key, code: "y"
243
+ @border_type_index = (@border_type_index + 1) % @border_type_configs.size
244
+ in type: :key, code: "c"
245
+ @border_style_index = (@border_style_index + 1) % @border_styles.size
246
+ in type: :key, code: "p"
247
+ @padding_index = (@padding_index + 1) % @padding_configs.size
248
+ in type: :key, code: "f"
249
+ @base_style_index = (@base_style_index + 1) % @base_styles.size
250
+ else
251
+ nil
252
+ end
253
+ end
254
+ end
255
+
256
+ WidgetBlockDemo.new.run if __FILE__ == $PROGRAM_NAME