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
@@ -4,90 +4,90 @@
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
6
  module RatatuiRuby
7
- # Defines the sizing rule for a layout section.
7
+ # Defines the sizing rule for a layout section.
8
+ #
9
+ # Flexible layouts need rules. You can't just place widgets at absolute coordinates; they must adapt to changing terminal sizes.
10
+ #
11
+ # This class defines the rules of engagement. It tells the layout engine exactly how much space a section requires relative to others.
12
+ #
13
+ # Mix and match fixed lengths, percentages, ratios, and minimums. Build layouts that breathe.
14
+ #
15
+ # === Examples
16
+ #
17
+ # Constraint.length(5) # Exactly 5 cells
18
+ # Constraint.percentage(50) # Half the available space
19
+ # Constraint.min(10) # At least 10 cells, maybe more
20
+ # Constraint.fill(1) # Fill remaining space (weight 1)
21
+ class Constraint < Data.define(:type, :value)
22
+ ##
23
+ # :attr_reader: type
24
+ # The type of constraint.
8
25
  #
9
- # Flexible layouts need rules. You can't just place widgets at absolute coordinates; they must adapt to changing terminal sizes.
26
+ # <tt>:length</tt>, <tt>:percentage</tt>, <tt>:min</tt>, <tt>:max</tt>, <tt>:fill</tt>, or <tt>:ratio</tt>.
27
+
28
+ ##
29
+ # :attr_reader: value
30
+ # The numeric value (or array for ratio) associated with the rule.
31
+
32
+ # Requests a fixed size.
10
33
  #
11
- # This class defines the rules of engagement. It tells the layout engine exactly how much space a section requires relative to others.
34
+ # Constraint.length(10) # 10 characters wide/high
12
35
  #
13
- # Mix and match fixed lengths, percentages, ratios, and minimums. Build layouts that breathe.
36
+ # [v] Number of cells (Integer).
37
+ def self.length(v)
38
+ new(type: :length, value: Integer(v))
39
+ end
40
+
41
+ # Requests a percentage of available space.
14
42
  #
15
- # === Examples
43
+ # Constraint.percentage(25) # 25% of the area
16
44
  #
17
- # Constraint.length(5) # Exactly 5 cells
18
- # Constraint.percentage(50) # Half the available space
19
- # Constraint.min(10) # At least 10 cells, maybe more
20
- # Constraint.fill(1) # Fill remaining space (weight 1)
21
- class Constraint < Data.define(:type, :value)
22
- ##
23
- # :attr_reader: type
24
- # The type of constraint.
25
- #
26
- # <tt>:length</tt>, <tt>:percentage</tt>, <tt>:min</tt>, <tt>:max</tt>, <tt>:fill</tt>, or <tt>:ratio</tt>.
27
-
28
- ##
29
- # :attr_reader: value
30
- # The numeric value (or array for ratio) associated with the rule.
31
-
32
- # Requests a fixed size.
33
- #
34
- # Constraint.length(10) # 10 characters wide/high
35
- #
36
- # [v] Number of cells (Integer).
37
- def self.length(v)
38
- new(type: :length, value: Integer(v))
39
- end
40
-
41
- # Requests a percentage of available space.
42
- #
43
- # Constraint.percentage(25) # 25% of the area
44
- #
45
- # [v] Percentage 0-100 (Integer).
46
- def self.percentage(v)
47
- new(type: :percentage, value: Integer(v))
48
- end
45
+ # [v] Percentage 0-100 (Integer).
46
+ def self.percentage(v)
47
+ new(type: :percentage, value: Integer(v))
48
+ end
49
49
 
50
- # Enforces a minimum size.
51
- #
52
- # Constraint.min(5) # At least 5 cells
53
- #
54
- # This section will grow if space permits, but never shrink below +v+.
55
- #
56
- # [v] Minimum cells (Integer).
57
- def self.min(v)
58
- new(type: :min, value: Integer(v))
59
- end
50
+ # Enforces a minimum size.
51
+ #
52
+ # Constraint.min(5) # At least 5 cells
53
+ #
54
+ # This section will grow if space permits, but never shrink below +v+.
55
+ #
56
+ # [v] Minimum cells (Integer).
57
+ def self.min(v)
58
+ new(type: :min, value: Integer(v))
59
+ end
60
60
 
61
- # Enforces a maximum size.
62
- #
63
- # Constraint.max(10) # At most 10 cells
64
- #
65
- # [v] Maximum cells (Integer).
66
- def self.max(v)
67
- new(type: :max, value: Integer(v))
68
- end
61
+ # Enforces a maximum size.
62
+ #
63
+ # Constraint.max(10) # At most 10 cells
64
+ #
65
+ # [v] Maximum cells (Integer).
66
+ def self.max(v)
67
+ new(type: :max, value: Integer(v))
68
+ end
69
69
 
70
- # Fills remaining space proportionally.
71
- #
72
- # Constraint.fill(1) # Equal share
73
- # Constraint.fill(2) # Double share
74
- #
75
- # Fill constraints distribute any space left after satisfying strict rules.
76
- # They behave like flex-grow. A fill(2) takes twice as much space as a fill(1).
77
- #
78
- # [v] Proportional weight (Integer, default: 1).
79
- def self.fill(v = 1)
80
- new(type: :fill, value: Integer(v))
81
- end
70
+ # Fills remaining space proportionally.
71
+ #
72
+ # Constraint.fill(1) # Equal share
73
+ # Constraint.fill(2) # Double share
74
+ #
75
+ # Fill constraints distribute any space left after satisfying strict rules.
76
+ # They behave like flex-grow. A fill(2) takes twice as much space as a fill(1).
77
+ #
78
+ # [v] Proportional weight (Integer, default: 1).
79
+ def self.fill(v = 1)
80
+ new(type: :fill, value: Integer(v))
81
+ end
82
82
 
83
- # Requests a specific ratio of the total space.
84
- #
85
- # Constraint.ratio(1, 3) # 1/3rd of the area
86
- #
87
- # [numerator] Top part of fraction (Integer).
88
- # [denominator] Bottom part of fraction (Integer).
89
- def self.ratio(numerator, denominator)
90
- new(type: :ratio, value: [Integer(numerator), Integer(denominator)])
91
- end
83
+ # Requests a specific ratio of the total space.
84
+ #
85
+ # Constraint.ratio(1, 3) # 1/3rd of the area
86
+ #
87
+ # [numerator] Top part of fraction (Integer).
88
+ # [denominator] Bottom part of fraction (Integer).
89
+ def self.ratio(numerator, denominator)
90
+ new(type: :ratio, value: [Integer(numerator), Integer(denominator)])
92
91
  end
92
+ end
93
93
  end
@@ -4,32 +4,37 @@
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
6
  module RatatuiRuby
7
- # Controls the terminal cursor position.
8
- #
9
- # Interfaces are not just output; they require input. Users need a visual cue—a blinking block or line—to know where their keystrokes will appear.
10
- #
11
- # This widget renders a ghost. It does not draw a character but instructs the terminal to place the hardware cursor at specific coordinates.
12
- #
13
- # Use it for text editors, input fields, or command prompts.
14
- #
15
- # === Examples
16
- #
17
- # Cursor.new(x: 10, y: 5)
18
- class Cursor < Data.define(:x, :y)
19
- ##
20
- # :attr_reader: x
21
- # X coordinate (column).
7
+ # Controls the terminal cursor position.
8
+ #
9
+ # Interfaces are not just output; they require input. Users need a visual cue—a blinking block or line—to know where their keystrokes will appear.
10
+ #
11
+ # This widget renders a ghost. It does not draw a character but instructs the terminal to place the hardware cursor at specific coordinates.
12
+ #
13
+ # Use it for text editors, input fields, or command prompts.
14
+ #
15
+ # === Examples
16
+ #
17
+ # Cursor.new(x: 10, y: 5)
18
+ #
19
+ # See also:
20
+ # - {Declarative implementation using Tree API}[link:/examples/app_login_form/app_rb.html]
21
+ # - {Component-based implementation using Frame API}[link:/examples/app_color_picker/app_rb.html]
22
+ # - RatatuiRuby::Frame#set_cursor_position (Frame API alternative)
23
+ class Cursor < Data.define(:x, :y)
24
+ ##
25
+ # :attr_reader: x
26
+ # X coordinate (column).
22
27
 
23
- ##
24
- # :attr_reader: y
25
- # Y coordinate (row).
28
+ ##
29
+ # :attr_reader: y
30
+ # Y coordinate (row).
26
31
 
27
- # Creates a new Cursor.
28
- #
29
- # [x] Integer.
30
- # [y] Integer.
31
- def initialize(x:, y:)
32
- super(x: Integer(x), y: Integer(y))
33
- end
32
+ # Creates a new Cursor.
33
+ #
34
+ # [x] Integer.
35
+ # [y] Integer.
36
+ def initialize(x:, y:)
37
+ super(x: Integer(x), y: Integer(y))
34
38
  end
39
+ end
35
40
  end
@@ -4,65 +4,67 @@
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
6
  module RatatuiRuby
7
- # Displays a standard progress bar.
8
- #
9
- # Long-running tasks create anxiety. Users need to know that the system is working and how much is left to do.
10
- #
11
- # This widget visualizes completion. It fills a bar based on a percentage.
12
- #
13
- # Use it for downloads, installations, or processing jobs.
7
+ # Displays a standard progress bar.
8
+ #
9
+ # Long-running tasks create anxiety. Users need to know that the system is working and how much is left to do.
10
+ #
11
+ # This widget visualizes completion. It fills a bar based on a percentage.
12
+ #
13
+ # Use it for downloads, installations, or processing jobs.
14
+ #
15
+ # {rdoc-image:/doc/images/widget_gauge_demo.png}[link:/examples/widget_gauge_demo/app_rb.html]
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the interactive demo from the terminal:
20
+ #
21
+ # ruby examples/widget_gauge_demo/app.rb
22
+ class Gauge < Data.define(:ratio, :label, :style, :gauge_style, :block, :use_unicode)
23
+ ##
24
+ # :attr_reader: ratio
25
+ # Progress ratio from 0.0 to 1.0.
26
+
27
+ ##
28
+ # :attr_reader: label
29
+ # Text label to display (optional).
14
30
  #
15
- # === Examples
31
+ # Accepts String or Text::Span for rich styling.
16
32
  #
17
- # Gauge.new(
18
- # ratio: 0.75,
19
- # label: "75%",
20
- # gauge_style: Style.new(fg: :green)
21
- # )
22
- class Gauge < Data.define(:ratio, :label, :style, :gauge_style, :block, :use_unicode)
23
- ##
24
- # :attr_reader: ratio
25
- # Progress ratio from 0.0 to 1.0.
26
-
27
- ##
28
- # :attr_reader: label
29
- # Text label to display (optional).
30
- #
31
- # If nil, it often displays the percentage automatically depending on renderer logic,
32
- # but explicit labels are preferred.
33
+ # If nil, it often displays the percentage automatically depending on renderer logic,
34
+ # but explicit labels are preferred.
33
35
 
34
- ##
35
- # :attr_reader: style
36
- # Base style applied to the entire gauge background (optional).
36
+ ##
37
+ # :attr_reader: style
38
+ # Base style applied to the entire gauge background (optional).
37
39
 
38
- ##
39
- # :attr_reader: gauge_style
40
- # Style applied specifically to the filled bar portion (optional).
40
+ ##
41
+ # :attr_reader: gauge_style
42
+ # Style applied specifically to the filled bar portion (optional).
41
43
 
42
- ##
43
- # :attr_reader: block
44
- # Optional wrapping block.
44
+ ##
45
+ # :attr_reader: block
46
+ # Optional wrapping block.
45
47
 
46
- ##
47
- # :attr_reader: use_unicode
48
- # Whether to use Unicode block characters (true) or ASCII characters (false).
49
- # Default is false (ASCII) to be conservative, though Ratatui defaults to true.
48
+ ##
49
+ # :attr_reader: use_unicode
50
+ # Whether to use Unicode block characters (true) or ASCII characters (false).
51
+ # Default is false (ASCII) to be conservative, though Ratatui defaults to true.
50
52
 
51
- # Creates a new Gauge.
52
- #
53
- # [ratio] Float (0.0 - 1.0).
54
- # [percent] Integer (0 - 100), alternative to ratio.
55
- # [label] String (optional).
56
- # [style] Style object for the background (optional).
57
- # [gauge_style] Style object for the filled bar (optional).
58
- # [block] Block widget (optional).
59
- # [use_unicode] Boolean (default: true).
60
- def initialize(ratio: nil, percent: nil, label: nil, style: nil, gauge_style: nil, block: nil, use_unicode: true)
61
- if percent
62
- ratio = Float(percent) / 100.0
63
- end
64
- ratio = Float(ratio || 0.0)
65
- super(ratio:, label:, style:, gauge_style:, block:, use_unicode:)
53
+ # Creates a new Gauge.
54
+ #
55
+ # [ratio] Float (0.0 - 1.0).
56
+ # [percent] Integer (0 - 100), alternative to ratio.
57
+ # [label] String or Text::Span (optional).
58
+ # [style] Style object for the background (optional).
59
+ # [gauge_style] Style object for the filled bar (optional).
60
+ # [block] Block widget (optional).
61
+ # [use_unicode] Boolean (default: true).
62
+ def initialize(ratio: nil, percent: nil, label: nil, style: nil, gauge_style: nil, block: nil, use_unicode: true)
63
+ if percent
64
+ ratio = Float(percent) / 100.0
66
65
  end
66
+ ratio = Float(ratio || 0.0)
67
+ super(ratio:, label:, style:, gauge_style:, block:, use_unicode:)
67
68
  end
69
+ end
68
70
  end
@@ -4,101 +4,101 @@
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
6
  module RatatuiRuby
7
- # Divides an area into smaller chunks.
7
+ # Divides an area into smaller chunks.
8
+ #
9
+ # Terminal screens vary in size. Hardcoded positions break when the window resizes. You need a way to organize space dynamically.
10
+ #
11
+ # This class manages geometry. It splits a given area into multiple sections based on a list of constraints.
12
+ #
13
+ # Use layouts to build responsive grids. Stack sections vertically for a sidebar-main structure. Partition them horizontally for headers and footers. Let the layout engine do the math.
14
+ #
15
+ # {rdoc-image:/doc/images/widget_layout_split.png}[link:/examples/widget_layout_split/app_rb.html]
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the interactive demo from the terminal:
20
+ #
21
+ # ruby examples/widget_layout_split/app.rb
22
+ class Layout < Data.define(:direction, :constraints, :children, :flex)
23
+ ##
24
+ # :attr_reader: direction
25
+ # Direction of the split.
8
26
  #
9
- # Terminal screens vary in size. Hardcoded positions break when the window resizes. You need a way to organize space dynamically.
27
+ # Either <tt>:vertical</tt> (top to bottom) or <tt>:horizontal</tt> (left to right).
10
28
  #
11
- # This class manages geometry. It splits a given area into multiple sections based on a list of constraints.
12
- #
13
- # Use layouts to build responsive grids. Stack sections vertically for a sidebar-main structure. Partition them horizontally for headers and footers. Let the layout engine do the math.
14
- #
15
- # === Examples
16
- #
17
- # # A simple vertical split (Sidebar / Main)
18
- # Layout.new(
19
- # direction: :horizontal,
20
- # constraints: [
21
- # Constraint.length(20), # Sidebar
22
- # Constraint.min(0) # Main content
23
- # ]
24
- # )
25
- #
26
- # # Flex layout (Centering a block)
27
- # Layout.new(
28
- # direction: :vertical,
29
- # flex: :center,
30
- # constraints: [Constraint.length(10)], # A 10-row block centered vertically
31
- # children: [modal_block]
32
- # )
33
- class Layout < Data.define(:direction, :constraints, :children, :flex)
34
- ##
35
- # :attr_reader: direction
36
- # Direction of the split.
37
- #
38
- # Either <tt>:vertical</tt> (top to bottom) or <tt>:horizontal</tt> (left to right).
39
- #
40
- # layout.direction # => :vertical
29
+ # layout.direction # => :vertical
41
30
 
42
- ##
43
- # :attr_reader: constraints
44
- # Array of rules defining section sizes.
45
- #
46
- # See RatatuiRuby::Constraint.
31
+ ##
32
+ # :attr_reader: constraints
33
+ # Array of rules defining section sizes.
34
+ #
35
+ # See RatatuiRuby::Constraint.
47
36
 
48
- ##
49
- # :attr_reader: children
50
- # Widgets to render in each section (optional).
51
- #
52
- # If provided, `children[i]` is rendered into the area defined by `constraints[i]`.
37
+ ##
38
+ # :attr_reader: children
39
+ # Widgets to render in each section (optional).
40
+ #
41
+ # If provided, `children[i]` is rendered into the area defined by `constraints[i]`.
53
42
 
54
- ##
55
- # :attr_reader: flex
56
- # Strategy for distributing extra space.
57
- #
58
- # One of <tt>:legacy</tt>, <tt>:start</tt>, <tt>:center</tt>, <tt>:end</tt>, <tt>:space_between</tt>, <tt>:space_around</tt>.
43
+ ##
44
+ # :attr_reader: flex
45
+ # Strategy for distributing extra space.
46
+ #
47
+ # One of <tt>:legacy</tt>, <tt>:start</tt>, <tt>:center</tt>, <tt>:end</tt>, <tt>:space_between</tt>, <tt>:space_around</tt>.
59
48
 
60
- # :nodoc:
61
- FLEX_MODES = %i[legacy start center end space_between space_around space_evenly].freeze
49
+ # :nodoc:
50
+ FLEX_MODES = %i[legacy start center end space_between space_around space_evenly].freeze
62
51
 
63
- # Creates a new Layout.
64
- #
65
- # [direction]
66
- # <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
67
- # [constraints]
68
- # list of Constraint objects.
69
- # [children]
70
- # List of widgets to render (optional).
71
- # [flex]
72
- # Flex mode for spacing (default: <tt>:legacy</tt>).
73
- def initialize(direction: :vertical, constraints: [], children: [], flex: :legacy)
74
- super
75
- end
52
+ # Creates a new Layout.
53
+ #
54
+ # [direction]
55
+ # <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
56
+ # [constraints]
57
+ # list of Constraint objects.
58
+ # [children]
59
+ # List of widgets to render (optional).
60
+ # [flex]
61
+ # Flex mode for spacing (default: <tt>:legacy</tt>).
62
+ def initialize(direction: :vertical, constraints: [], children: [], flex: :legacy)
63
+ super
64
+ end
76
65
 
77
- # Splits an area into multiple rectangles.
78
- #
79
- # This is a pure calculation helper for hit testing. It computes where
80
- # widgets *would* be placed without actually rendering them.
81
- #
82
- # rects = Layout.split(
83
- # area,
84
- # direction: :horizontal,
85
- # constraints: [Constraint.percentage(50), Constraint.percentage(50)]
86
- # )
87
- # left, right = rects
88
- #
89
- # [area]
90
- # The area to split (a Rect or any object responding to x, y, width, height).
91
- # [direction]
92
- # <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
93
- # [constraints]
94
- # Array of Constraint objects defining section sizes.
95
- # [flex]
96
- # Flex mode for spacing (default: <tt>:legacy</tt>).
97
- #
98
- # Returns an Array of Rect objects.
99
- def self.split(area, direction: :vertical, constraints:, flex: :legacy)
100
- raw_rects = _split(area, direction, constraints, flex)
101
- raw_rects.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) }
66
+ # Splits an area into multiple rectangles.
67
+ #
68
+ # This is a pure calculation helper for hit testing. It computes where
69
+ # widgets *would* be placed without actually rendering them.
70
+ #
71
+ # rects = Layout.split(
72
+ # area,
73
+ # direction: :horizontal,
74
+ # constraints: [Constraint.percentage(50), Constraint.percentage(50)]
75
+ # )
76
+ # left, right = rects
77
+ #
78
+ # [area]
79
+ # The area to split. Can be a <tt>Rect</tt> or a <tt>Hash</tt> containing <tt>:x</tt>, <tt>:y</tt>, <tt>:width</tt>, and <tt>:height</tt>.
80
+ # [direction]
81
+ # <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
82
+ # [constraints]
83
+ # Array of <tt>Constraint</tt> objects defining section sizes.
84
+ # [flex]
85
+ # Flex mode for spacing (default: <tt>:legacy</tt>).
86
+ #
87
+ # Returns an Array of <tt>Rect</tt> objects.
88
+ def self.split(area, direction: :vertical, constraints:, flex: :legacy)
89
+ # Duck-typing: If it lacks geometry methods but can be a Hash, convert it.
90
+ if !area.respond_to?(:x) && area.respond_to?(:to_h)
91
+ # Assume it's a Hash-like object with :x, :y, etc.
92
+ hash = area.to_h
93
+ area = Rect.new(
94
+ x: hash.fetch(:x, 0),
95
+ y: hash.fetch(:y, 0),
96
+ width: hash.fetch(:width, 0),
97
+ height: hash.fetch(:height, 0)
98
+ )
102
99
  end
100
+ raw_rects = _split(area, direction, constraints, flex)
101
+ raw_rects.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) }
103
102
  end
103
+ end
104
104
  end