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,45 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Box (Block) Widget Example
7
+
8
+ Demonstrates visual container attributes with interactive cycling.
9
+
10
+ Widgets often float in a void. Without boundaries, interfaces become a chaotic mess of text. `Block` (often called a Box) provides the structure and visual hierarchy needed to organize information.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **Border Types**: Native styles like `:plain`, `:rounded`, `:double`, `:thick`.
15
+ - **Custom Borders**: defining completely custom character sets (e.g. using numbers or letters for borders).
16
+ - **Styling**: Independent control over border color, background style, and title style.
17
+ - **Positioning**: Placing titles on the `:top` or `:bottom` border (`position`).
18
+ - **Alignment**: Aligning titles to `:left`, `:center`, or `:right` (`alignment`).
19
+
20
+ ## Hotkeys
21
+
22
+ - **Arrow Keys**: Change Border/Content Color
23
+ - **Space**: Cycle Border Type (`border_type`)
24
+ - **c**: Cycle Custom Border Set (`border_set`)
25
+ - **Enter**: Cycle Title Alignment (`title_alignment`)
26
+ - **s**: Cycle Content Style (`style`)
27
+ - **t**: Cycle Title Style (`title_style`)
28
+ - **b**: Cycle Border Style (`border_style`)
29
+ - **q**: Quit
30
+
31
+ ## Usage
32
+
33
+ ```bash
34
+ ruby examples/widget_box_demo/app.rb
35
+ ```
36
+
37
+ ## Learning Outcomes
38
+
39
+ Use this example if you need to...
40
+ - Group related widgets together.
41
+ - Create distinct "panels" or "cards" in your UI.
42
+ - Style borders to indicate state (e.g., Red border for error state).
43
+ - Understand the difference between `style` (content) and `border_style` (frame).
44
+
45
+ ![Demo](/doc/images/widget_box_demo.png)
@@ -6,7 +6,22 @@
6
6
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
  require "ratatui_ruby"
8
8
 
9
- class BoxDemoApp
9
+ # Demonstrates visual container attributes with interactive cycling.
10
+ #
11
+ # Widgets often float in void. Without boundaries, interfaces become a chaotic mess of text. Users need structure to parse information.
12
+ #
13
+ # This demo showcases the <tt>Block</tt> widget. It provides an interactive playground where you can cycle through different border types, colors, and title alignments in real-time.
14
+ #
15
+ # Use it to understand how to define distinct areas and create visual hierarchy in your terminal interface.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_box_demo/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_box_demo.png
24
+ class WidgetBoxDemo
10
25
  def initialize
11
26
  # Border Types (ratatui native styles)
12
27
  @border_types = [
@@ -15,7 +30,7 @@ class BoxDemoApp
15
30
  { name: "Double", type: :double },
16
31
  { name: "Thick", type: :thick },
17
32
  { name: "Quadrant Inside", type: :quadrant_inside },
18
- { name: "Quadrant Outside", type: :quadrant_outside }
33
+ { name: "Quadrant Outside", type: :quadrant_outside },
19
34
  ]
20
35
  @border_type_index = 0
21
36
 
@@ -23,14 +38,32 @@ class BoxDemoApp
23
38
  # NOTE: We define these ONCE in initialize for efficiency.
24
39
  @border_sets = [
25
40
  { name: "None", set: nil },
26
- { name: "Digits (Short)", set: {
27
- tl: "1", tr: "2", bl: "3", br: "4",
28
- vl: "5", vr: "6", ht: "7", hb: "8"
29
- }},
30
- { name: "Letters (Long)", set: {
31
- top_left: "A", top_right: "B", bottom_left: "C", bottom_right: "D",
32
- vertical_left: "E", vertical_right: "F", horizontal_top: "G", horizontal_bottom: "H"
33
- }}
41
+ {
42
+ name: "Digits (Short)",
43
+ set: {
44
+ tl: "1",
45
+ tr: "2",
46
+ bl: "3",
47
+ br: "4",
48
+ vl: "5",
49
+ vr: "6",
50
+ ht: "7",
51
+ hb: "8",
52
+ },
53
+ },
54
+ {
55
+ name: "Letters (Long)",
56
+ set: {
57
+ top_left: "A",
58
+ top_right: "B",
59
+ bottom_left: "C",
60
+ bottom_right: "D",
61
+ vertical_left: "E",
62
+ vertical_right: "F",
63
+ horizontal_top: "G",
64
+ horizontal_bottom: "H",
65
+ },
66
+ },
34
67
  ]
35
68
  @border_set_index = 0
36
69
 
@@ -39,26 +72,26 @@ class BoxDemoApp
39
72
  { name: "Red", color: "red" },
40
73
  { name: "Blue", color: "blue" },
41
74
  { name: "Yellow", color: "yellow" },
42
- { name: "Magenta", color: "magenta" }
75
+ { name: "Magenta", color: "magenta" },
43
76
  ]
44
77
  @color_index = 0
45
78
 
46
79
  @title_alignments = [
47
80
  { name: "Left", alignment: :left },
48
81
  { name: "Center", alignment: :center },
49
- { name: "Right", alignment: :right }
82
+ { name: "Right", alignment: :right },
50
83
  ]
51
84
  @title_alignment_index = 0
52
85
 
53
86
  @styles = [
54
87
  { name: "Default", style: nil },
55
- { name: "Blue on White", style: { fg: "blue", bg: "white", modifiers: [:bold] } }
88
+ { name: "Blue on White", style: { fg: "blue", bg: "white", modifiers: [:bold] } },
56
89
  ]
57
90
  @style_index = 0
58
91
 
59
92
  @title_styles = [
60
93
  { name: "Default", style: nil },
61
- { name: "Yellow Bold Underlined", style: { fg: "yellow", modifiers: [:bold, :underlined] } }
94
+ { name: "Yellow Bold Underlined", style: { fg: "yellow", modifiers: [:bold, :underlined] } },
62
95
  ]
63
96
  @title_style_index = 0
64
97
 
@@ -66,15 +99,18 @@ class BoxDemoApp
66
99
  { name: "Default (no border style)", style: nil },
67
100
  { name: "Bold Red", style: { fg: "red", modifiers: [:bold] } },
68
101
  { name: "Cyan Italic", style: { fg: "cyan", modifiers: [:italic] } },
69
- { name: "Magenta Dim", style: { fg: "magenta", modifiers: [:dim] } }
102
+ { name: "Magenta Dim", style: { fg: "magenta", modifiers: [:dim] } },
70
103
  ]
71
104
  @border_style_index = 0
72
105
 
73
- @hotkey_style = RatatuiRuby::Style.new(modifiers: [:bold, :underlined])
106
+ @hotkey_style = nil # Initialized in run when tui is available
74
107
  end
75
108
 
76
109
  def run
77
- RatatuiRuby.run do
110
+ RatatuiRuby.run do |tui|
111
+ @tui = tui
112
+ @hotkey_style = tui.style(modifiers: [:bold, :underlined])
113
+
78
114
  loop do
79
115
  render
80
116
  break if handle_input == :quit
@@ -82,13 +118,11 @@ class BoxDemoApp
82
118
  end
83
119
  end
84
120
 
85
- private
86
-
87
- def render
121
+ private def render
88
122
  # Get current values
89
123
  border_type_config = @border_types[@border_type_index]
90
124
  border_set_config = @border_sets[@border_set_index]
91
-
125
+
92
126
  color_config = @colors[@color_index]
93
127
  title_alignment_config = @title_alignments[@title_alignment_index]
94
128
  style_config = @styles[@style_index]
@@ -106,7 +140,7 @@ class BoxDemoApp
106
140
  type_display += " (Overridden)"
107
141
  end
108
142
 
109
- block = RatatuiRuby::Block.new(
143
+ block = @tui.block(
110
144
  title: "Box Demo",
111
145
  title_alignment: title_alignment_config[:alignment],
112
146
  title_style: title_style_config[:style],
@@ -119,72 +153,73 @@ class BoxDemoApp
119
153
  )
120
154
 
121
155
  # Main content
122
- main_panel = RatatuiRuby::Paragraph.new(
156
+ main_panel = @tui.paragraph(
123
157
  text: "Arrow Keys: Change Color\n\nCurrent Color: #{color_config[:name]}",
124
- block: block,
158
+ block:,
125
159
  fg: style_config[:style] ? nil : color_config[:color],
126
160
  style: style_config[:style],
127
161
  alignment: :center
128
162
  )
129
163
 
130
164
  # Bottom control panel
131
- control_panel = RatatuiRuby::Block.new(
165
+ control_panel = @tui.block(
132
166
  title: "Controls",
133
167
  borders: [:all],
134
168
  children: [
135
- RatatuiRuby::Paragraph.new(
169
+ @tui.paragraph(
136
170
  text: [
137
171
  # Line 1: Main Controls
138
- RatatuiRuby::Text::Line.new(spans: [
139
- RatatuiRuby::Text::Span.new(content: "↑↓←→", style: @hotkey_style),
140
- RatatuiRuby::Text::Span.new(content: ": Color (#{color_config[:name]}) "),
141
- RatatuiRuby::Text::Span.new(content: "q", style: @hotkey_style),
142
- RatatuiRuby::Text::Span.new(content: ": Quit")
172
+ @tui.text_line(spans: [
173
+ @tui.text_span(content: "↑↓←→", style: @hotkey_style),
174
+ @tui.text_span(content: ": Color (#{color_config[:name]}) "),
175
+ @tui.text_span(content: "q", style: @hotkey_style),
176
+ @tui.text_span(content: ": Quit"),
143
177
  ]),
144
178
  # Line 2: Borders
145
- RatatuiRuby::Text::Line.new(spans: [
146
- RatatuiRuby::Text::Span.new(content: "space", style: @hotkey_style),
147
- RatatuiRuby::Text::Span.new(content: ": Border Type (#{type_display}) "),
148
- RatatuiRuby::Text::Span.new(content: "c", style: @hotkey_style),
149
- RatatuiRuby::Text::Span.new(content: ": Border Set (#{border_set_config[:name]})")
179
+ @tui.text_line(spans: [
180
+ @tui.text_span(content: "space", style: @hotkey_style),
181
+ @tui.text_span(content: ": Border Type (#{type_display}) "),
182
+ @tui.text_span(content: "c", style: @hotkey_style),
183
+ @tui.text_span(content: ": Border Set (#{border_set_config[:name]})"),
150
184
  ]),
151
185
  # Line 3: Styles
152
- RatatuiRuby::Text::Line.new(spans: [
153
- RatatuiRuby::Text::Span.new(content: "s", style: @hotkey_style),
154
- RatatuiRuby::Text::Span.new(content: ": Style (#{style_config[:name]}) "),
155
- RatatuiRuby::Text::Span.new(content: "b", style: @hotkey_style),
156
- RatatuiRuby::Text::Span.new(content: ": Border Style (#{border_style_config[:name]})")
186
+ @tui.text_line(spans: [
187
+ @tui.text_span(content: "s", style: @hotkey_style),
188
+ @tui.text_span(content: ": Style (#{style_config[:name]}) "),
189
+ @tui.text_span(content: "b", style: @hotkey_style),
190
+ @tui.text_span(content: ": Border Style (#{border_style_config[:name]})"),
157
191
  ]),
158
192
  # Line 4: Title
159
- RatatuiRuby::Text::Line.new(spans: [
160
- RatatuiRuby::Text::Span.new(content: "enter", style: @hotkey_style),
161
- RatatuiRuby::Text::Span.new(content: ": Align Title (#{title_alignment_config[:name]}) "),
162
- RatatuiRuby::Text::Span.new(content: "t", style: @hotkey_style),
163
- RatatuiRuby::Text::Span.new(content: ": Title Style (#{title_style_config[:name]})")
164
- ])
193
+ @tui.text_line(spans: [
194
+ @tui.text_span(content: "enter", style: @hotkey_style),
195
+ @tui.text_span(content: ": Align Title (#{title_alignment_config[:name]}) "),
196
+ @tui.text_span(content: "t", style: @hotkey_style),
197
+ @tui.text_span(content: ": Title Style (#{title_style_config[:name]})"),
198
+ ]),
165
199
  ]
166
- )
200
+ ),
167
201
  ]
168
202
  )
169
203
 
170
- # Vertical Layout
171
- layout = RatatuiRuby::Layout.new(
172
- direction: :vertical,
173
- constraints: [
174
- RatatuiRuby::Constraint.fill(1),
175
- RatatuiRuby::Constraint.length(6),
176
- ],
177
- children: [main_panel, control_panel]
178
- )
179
-
180
- # 2. Render
181
- RatatuiRuby.draw(layout)
204
+ # 2. Render with Frame API
205
+ @tui.draw do |frame|
206
+ main_rect, control_rect = @tui.layout_split(
207
+ frame.area,
208
+ direction: :vertical,
209
+ constraints: [
210
+ @tui.constraint_fill(1),
211
+ @tui.constraint_length(6),
212
+ ]
213
+ )
214
+ frame.render_widget(main_panel, main_rect)
215
+ frame.render_widget(control_panel, control_rect)
216
+ end
182
217
  end
183
218
 
184
- def handle_input
219
+ private def handle_input
185
220
  # 3. Events
186
- case RatatuiRuby.poll_event
187
- in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
221
+ case @tui.poll_event
222
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
188
223
  :quit
189
224
  in type: :key, code: "up"
190
225
  @color_index = (@color_index - 1) % @colors.size
@@ -212,5 +247,4 @@ class BoxDemoApp
212
247
  end
213
248
  end
214
249
 
215
- BoxDemoApp.new.run if __FILE__ == $0
216
-
250
+ WidgetBoxDemo.new.run if __FILE__ == $0
@@ -0,0 +1,39 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Calendar Widget Example
7
+
8
+ Demonstrates a monthly calendar with customizable headers and event highlighting.
9
+
10
+ Rendering dates in a grid involves complex calculations for leap years and weekday offsets. This widget handles that logic, letting you focus on displaying dates.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **Headers**: Toggling the Month name and Weekday labels.
15
+ - **Surrounding Days**: displaying (or hiding/dimming) days from the previous and next months to fill the grid.
16
+ - **Event Styling**: applying specific styles to individual `Time` or `Date` objects to highlight events.
17
+
18
+ ## Hotkeys
19
+
20
+ - **h**: Toggle Month Header (`show_month_header`)
21
+ - **w**: Toggle Weekday Labels (`show_weekdays_header`)
22
+ - **s**: Toggle Surrounding Days (`show_surrounding`)
23
+ - **e**: Toggle Example Events (`events`)
24
+ - **q**: Quit
25
+
26
+ ## Usage
27
+
28
+ ```bash
29
+ ruby examples/widget_calendar_demo/app.rb
30
+ ```
31
+
32
+ ## Learning Outcomes
33
+
34
+ Use this example if you need to...
35
+ - Display a date picker.
36
+ - Show a schedule or timeline view.
37
+ - Highlight specific dates (deadlines, holidays) on a calendar grid.
38
+
39
+ ![Demo](/doc/images/widget_calendar_demo.png)
@@ -0,0 +1,109 @@
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 monthly calendar attributes with interactive cycling.
10
+ #
11
+ # Dates are complex. Rendering them in a grid requires calculation of leap years, month lengths, and day-of-week offsets.
12
+ # Use this widget to skip the boilerplate.
13
+ #
14
+ # This demo showcases the <tt>Calendar</tt> widget. It provides an interactive playground where you can toggle headers, weekday labels, and event highlights in real-time.
15
+ #
16
+ # Use it to understand how to render time-based data grids efficiently.
17
+ #
18
+ # === Example
19
+ #
20
+ # Run the demo from the terminal:
21
+ #
22
+ # ruby examples/widget_calendar_demo/app.rb
23
+ #
24
+ # rdoc-image:/doc/images/widget_calendar_demo.png
25
+ class WidgetCalendarDemo
26
+ def run
27
+ RatatuiRuby.run do |tui|
28
+ show_header = true
29
+ show_weekdays = true
30
+ show_surrounding = false
31
+ show_events = true
32
+ hotkey_style = tui.style(modifiers: [:bold])
33
+
34
+ loop do
35
+ now = Time.now
36
+ surrounding_style = show_surrounding ? tui.style(fg: "gray", modifiers: [:dim]) : nil
37
+
38
+ events_map = if show_events
39
+ {
40
+ now => tui.style(fg: "green", modifiers: [:bold]),
41
+ (now + (86400 * 2)) => tui.style(fg: "red", modifiers: [:underlined]),
42
+ (now - (86400 * 5)) => tui.style(fg: "blue", bg: "white"),
43
+ }
44
+ else
45
+ {}
46
+ end
47
+
48
+ calendar = tui.calendar(
49
+ year: now.year,
50
+ month: now.month,
51
+ events: events_map,
52
+ header_style: tui.style(fg: "yellow", modifiers: [:bold]),
53
+ show_month_header: show_header,
54
+ show_weekdays_header: show_weekdays,
55
+ show_surrounding: surrounding_style,
56
+ block: tui.block(borders: [:top, :left, :right])
57
+ )
58
+
59
+ controls = tui.paragraph(
60
+ text: [
61
+ tui.text_line(spans: [
62
+ tui.text_span(content: " h/w/s/e", style: hotkey_style),
63
+ tui.text_span(content: ": Toggle Header/Weekdays/Surrounding/Events "),
64
+ tui.text_span(content: "q", style: hotkey_style),
65
+ tui.text_span(content: ": Quit"),
66
+ ]),
67
+ tui.text_line(spans: [
68
+ tui.text_span(content: " Events: ", style: hotkey_style),
69
+ tui.text_span(content: "Today (Green), +2d (Red), -5d (Blue) (#{show_events ? 'On' : 'Off'})"),
70
+ ]),
71
+ ],
72
+ block: tui.block(title: " Controls ", borders: [:all])
73
+ )
74
+
75
+ tui.draw do |frame|
76
+ calendar_area, controls_area = tui.layout_split(
77
+ frame.area,
78
+ direction: :vertical,
79
+ constraints: [
80
+ tui.constraint_min(0),
81
+ tui.constraint_length(4),
82
+ ]
83
+ )
84
+ frame.render_widget(calendar, calendar_area)
85
+ frame.render_widget(controls, controls_area)
86
+ end
87
+
88
+ case tui.poll_event
89
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
90
+ break
91
+ in type: :key, code: "h"
92
+ show_header = !show_header
93
+ in type: :key, code: "w"
94
+ show_weekdays = !show_weekdays
95
+ in type: :key, code: "s"
96
+ show_surrounding = !show_surrounding
97
+ in type: :key, code: "e"
98
+ show_events = !show_events
99
+ else
100
+ nil
101
+ end
102
+
103
+ sleep 0.05
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ WidgetCalendarDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,27 @@
1
+ # Canvas Widget Demo
2
+ <!--
3
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ SPDX-License-Identifier: CC-BY-SA-4.0
5
+ -->
6
+
7
+ This example demonstrates the `Canvas` widget, which provides a high-resolution drawing surface using Braille characters.
8
+
9
+ ## Key Concepts
10
+
11
+ - **Shapes**: Supports `Point`, `Line`, `Rectangle`, `Circle`, and `Map`.
12
+ - **Coordinates**: Uses a float-based coordinate system independent of terminal cells.
13
+ - **Markers**: Can use Braille (high res) or block characters (lower res) for rendering.
14
+
15
+ ## Controls
16
+
17
+ | Key | Action |
18
+ | --- | --- |
19
+ | `q` | Quit |
20
+
21
+ ## Screenshot
22
+
23
+ ![Screenshot of Canvas Widget Demo](../../doc/images/widget_canvas_demo.png)
24
+
25
+ ## Source Code
26
+
27
+ - [app.rb](app.rb)
@@ -0,0 +1,123 @@
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
+ # Demo: Canvas Widget
10
+ # Demonstrates how to draw geometric shapes (Points, Lines, Rects, Circles)
11
+ # on a high-resolution canvas.
12
+ class WidgetCanvasDemo
13
+ def initialize
14
+ @x_offset = 0.0
15
+ @y_offset = 0.0
16
+ @time = 0.0
17
+ end
18
+
19
+ def run
20
+ RatatuiRuby.run do |tui|
21
+ @tui = tui
22
+ loop do
23
+ # Animate
24
+ @time += 0.1
25
+ @x_offset = Math.sin(@time) * 20.0
26
+ @y_offset = Math.cos(@time) * 20.0
27
+
28
+ render
29
+ break if handle_input == :quit
30
+
31
+ sleep 0.05
32
+ end
33
+ end
34
+ end
35
+
36
+ private def render
37
+ @tui.draw do |frame|
38
+ # Define shapes
39
+ shapes = []
40
+
41
+ # 1. Static Grid (Lines)
42
+ (-100..100).step(20) do |i|
43
+ shapes << @tui.shape_line(x1: i.to_f, y1: -100.0, x2: i.to_f, y2: 100.0, color: :gray)
44
+ shapes << @tui.shape_line(x1: -100.0, y1: i.to_f, x2: 100.0, y2: i.to_f, color: :gray)
45
+ end
46
+
47
+ # 2. Moving Circle (The "Player")
48
+ shapes << @tui.shape_circle(
49
+ x: @x_offset,
50
+ y: @y_offset,
51
+ radius: 10.0,
52
+ color: :green
53
+ )
54
+
55
+ # 3. Static Rectangle (Target)
56
+ shapes << @tui.shape_rectangle(
57
+ x: 30.0,
58
+ y: 30.0,
59
+ width: 20.0,
60
+ height: 20.0,
61
+ color: :red
62
+ )
63
+
64
+ # 4. Points (Starfield)
65
+ # Deterministic "random" points
66
+ 10.times do |i|
67
+ shapes << @tui.shape_point(
68
+ x: ((i * 37) % 200) - 100.0,
69
+ y: ((i * 19) % 200) - 100.0
70
+ )
71
+ end
72
+
73
+ # 5. Label
74
+ shapes << @tui.shape_line(x1: 0.0, y1: 0.0, x2: @x_offset, y2: @y_offset, color: :yellow)
75
+
76
+ canvas = @tui.canvas(
77
+ shapes:,
78
+ x_bounds: [-100.0, 100.0],
79
+ y_bounds: [-100.0, 100.0],
80
+ marker: :braille,
81
+ block: @tui.block(title: "Canvas Demo", borders: [:all])
82
+ )
83
+
84
+ # Main area for canvas
85
+ layout = @tui.layout_split(
86
+ frame.area,
87
+ direction: :vertical,
88
+ constraints: [
89
+ @tui.constraint_fill(1),
90
+ @tui.constraint_length(3),
91
+ ]
92
+ )
93
+
94
+ frame.render_widget(canvas, layout[0])
95
+
96
+ # Controls
97
+ controls = @tui.paragraph(
98
+ text: [
99
+ @tui.text_line(spans: [
100
+ @tui.text_span(content: "Canvas auto-animates.", style: @tui.style(fg: :yellow)),
101
+ ]),
102
+ @tui.text_line(spans: [
103
+ @tui.text_span(content: "q", style: @tui.style(modifiers: [:bold, :underlined])),
104
+ @tui.text_span(content: ": Quit"),
105
+ ]),
106
+ ],
107
+ block: @tui.block(borders: [:top])
108
+ )
109
+ frame.render_widget(controls, layout[1])
110
+ end
111
+ end
112
+
113
+ def handle_input
114
+ case @tui.poll_event
115
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
116
+ :quit
117
+ else
118
+ # Ignore other events
119
+ end
120
+ end
121
+ end
122
+
123
+ WidgetCanvasDemo.new.run if __FILE__ == $0
@@ -0,0 +1,36 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Cell Widget Example
7
+
8
+ Demonstrates using `Cell` objects for granular control over individual character grid units.
9
+
10
+ Sometimes you need to render specific characters with unique styles outside of standard widgets. The `Cell` primitive allows you to build custom widgets or inject styled content into Tables.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **Custom Widgets**: A `CheckeredBackground` widget built by rendering `Cell`s in a loop.
15
+ - **Table Integration**: Mixing simple Strings and rich `Cell` objects in a Table row.
16
+ - **Overlays**: Using `RatatuiRuby::Overlay` to stack widgets on top of each other.
17
+ - **Modifiers**: Using `rapid_blink`, `bold`, and `dim` on individual cells.
18
+
19
+ ## Hotkeys
20
+
21
+ - **q** / **Ctrl+c**: Quit
22
+
23
+ ## Usage
24
+
25
+ ```bash
26
+ ruby examples/widget_cell_demo/app.rb
27
+ ```
28
+
29
+ ## Learning Outcomes
30
+
31
+ Use this example if you need to...
32
+ - Create a custom widget (like a game board or specialized graph).
33
+ - Style specific cells in a Table (e.g., Green "OK", Red "FAIL").
34
+ - Understand how to position content precisely with `Cell`.
35
+
36
+ ![Demo](/doc/images/widget_cell_demo.png)