ratatui_ruby 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +1 -1
  3. data/.builds/ruby-3.3.yml +1 -1
  4. data/.builds/ruby-3.4.yml +1 -1
  5. data/.builds/ruby-4.0.0.yml +1 -1
  6. data/AGENTS.md +87 -171
  7. data/CHANGELOG.md +38 -1
  8. data/README.md +8 -3
  9. data/REUSE.toml +20 -0
  10. data/doc/application_architecture.md +105 -45
  11. data/doc/application_testing.md +5 -3
  12. data/doc/contributors/design/ruby_frontend.md +9 -5
  13. data/doc/contributors/developing_examples.md +76 -18
  14. data/doc/contributors/documentation_style.md +7 -0
  15. data/doc/contributors/index.md +2 -0
  16. data/doc/event_handling.md +10 -4
  17. data/doc/images/app_all_events.png +0 -0
  18. data/doc/images/app_color_picker.png +0 -0
  19. data/doc/images/verify_readme_usage.png +0 -0
  20. data/doc/images/widget_barchart_demo.png +0 -0
  21. data/doc/images/widget_block_padding.png +0 -0
  22. data/doc/images/widget_block_titles.png +0 -0
  23. data/doc/images/widget_box_demo.png +0 -0
  24. data/doc/images/widget_calendar_demo.png +0 -0
  25. data/doc/images/widget_cell_demo.png +0 -0
  26. data/doc/images/widget_chart_demo.png +0 -0
  27. data/doc/images/widget_gauge_demo.png +0 -0
  28. data/doc/images/widget_layout_split.png +0 -0
  29. data/doc/images/widget_line_gauge_demo.png +0 -0
  30. data/doc/images/widget_list_demo.png +0 -0
  31. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  32. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  33. data/doc/images/widget_render.png +0 -0
  34. data/doc/images/widget_scrollbar_demo.png +0 -0
  35. data/doc/images/widget_sparkline_demo.png +0 -0
  36. data/doc/images/widget_style_colors.png +0 -0
  37. data/doc/images/widget_table_flex.png +0 -0
  38. data/doc/images/widget_tabs_demo.png +0 -0
  39. data/doc/interactive_design.md +25 -30
  40. data/doc/quickstart.md +147 -120
  41. data/examples/app_all_events/README.md +81 -0
  42. data/examples/app_all_events/app.rb +93 -0
  43. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  44. data/examples/app_all_events/model/event_entry.rb +75 -0
  45. data/examples/app_all_events/model/events.rb +180 -0
  46. data/examples/app_all_events/model/highlight.rb +57 -0
  47. data/examples/app_all_events/model/timestamp.rb +54 -0
  48. data/examples/app_all_events/test/snapshots/after_focus_lost.txt +24 -0
  49. data/examples/app_all_events/test/snapshots/after_focus_regained.txt +24 -0
  50. data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +24 -0
  51. data/examples/app_all_events/test/snapshots/after_key_a.txt +24 -0
  52. data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +24 -0
  53. data/examples/app_all_events/test/snapshots/after_mouse_click.txt +24 -0
  54. data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +24 -0
  55. data/examples/app_all_events/test/snapshots/after_multiple_events.txt +24 -0
  56. data/examples/app_all_events/test/snapshots/after_paste.txt +24 -0
  57. data/examples/app_all_events/test/snapshots/after_resize.txt +24 -0
  58. data/examples/app_all_events/test/snapshots/after_right_click.txt +24 -0
  59. data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +24 -0
  60. data/examples/app_all_events/test/snapshots/initial_state.txt +24 -0
  61. data/examples/app_all_events/view/app_view.rb +78 -0
  62. data/examples/app_all_events/view/controls_view.rb +50 -0
  63. data/examples/app_all_events/view/counts_view.rb +55 -0
  64. data/examples/app_all_events/view/live_view.rb +69 -0
  65. data/examples/app_all_events/view/log_view.rb +60 -0
  66. data/examples/app_all_events/view.rb +7 -0
  67. data/examples/app_all_events/view_state.rb +42 -0
  68. data/examples/app_color_picker/README.md +94 -0
  69. data/examples/app_color_picker/app.rb +112 -0
  70. data/examples/app_color_picker/clipboard.rb +84 -0
  71. data/examples/app_color_picker/color.rb +191 -0
  72. data/examples/app_color_picker/copy_dialog.rb +170 -0
  73. data/examples/app_color_picker/harmony.rb +56 -0
  74. data/examples/app_color_picker/input.rb +142 -0
  75. data/examples/app_color_picker/palette.rb +80 -0
  76. data/examples/app_color_picker/scene.rb +201 -0
  77. data/examples/{login_form → app_login_form}/app.rb +39 -42
  78. data/examples/{map_demo → app_map_demo}/app.rb +24 -21
  79. data/examples/{table_select → app_table_select}/app.rb +68 -65
  80. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +15 -6
  81. data/examples/verify_quickstart_layout/app.rb +69 -0
  82. data/examples/{quickstart_lifecycle → verify_quickstart_lifecycle}/app.rb +19 -10
  83. data/examples/verify_readme_usage/app.rb +34 -0
  84. data/examples/widget_barchart_demo/app.rb +238 -0
  85. data/examples/{block_padding → widget_block_padding}/app.rb +17 -13
  86. data/examples/{block_titles → widget_block_titles}/app.rb +25 -17
  87. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  88. data/examples/widget_calendar_demo/app.rb +109 -0
  89. data/examples/widget_cell_demo/app.rb +104 -0
  90. data/examples/widget_chart_demo/app.rb +213 -0
  91. data/examples/widget_gauge_demo/app.rb +212 -0
  92. data/examples/widget_layout_split/app.rb +246 -0
  93. data/examples/widget_line_gauge_demo/app.rb +217 -0
  94. data/examples/widget_list_demo/app.rb +382 -0
  95. data/examples/widget_list_styles/app.rb +141 -0
  96. data/examples/widget_popup_demo/app.rb +104 -0
  97. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  98. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  99. data/examples/widget_rect/app.rb +205 -0
  100. data/examples/widget_render/app.rb +184 -0
  101. data/examples/widget_rich_text/app.rb +137 -0
  102. data/examples/widget_scroll_text/app.rb +108 -0
  103. data/examples/widget_scrollbar_demo/app.rb +153 -0
  104. data/examples/widget_sparkline_demo/app.rb +274 -0
  105. data/examples/widget_style_colors/app.rb +19 -21
  106. data/examples/widget_table_flex/app.rb +95 -0
  107. data/examples/widget_tabs_demo/app.rb +167 -0
  108. data/ext/ratatui_ruby/Cargo.lock +1 -1
  109. data/ext/ratatui_ruby/Cargo.toml +1 -1
  110. data/ext/ratatui_ruby/src/events.rs +121 -36
  111. data/ext/ratatui_ruby/src/frame.rs +115 -0
  112. data/ext/ratatui_ruby/src/lib.rs +79 -26
  113. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  114. data/ext/ratatui_ruby/src/style.rs +138 -57
  115. data/ext/ratatui_ruby/src/terminal.rs +5 -9
  116. data/ext/ratatui_ruby/src/text.rs +13 -6
  117. data/ext/ratatui_ruby/src/widgets/barchart.rs +56 -54
  118. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  119. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  120. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  121. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  122. data/ext/ratatui_ruby/src/widgets/list.rs +32 -9
  123. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  124. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  125. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  126. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  127. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +4 -2
  128. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  129. data/ext/ratatui_ruby/src/widgets/table.rs +8 -4
  130. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  131. data/lib/ratatui_ruby/cell.rb +3 -3
  132. data/lib/ratatui_ruby/event/key.rb +1 -1
  133. data/lib/ratatui_ruby/event/none.rb +43 -0
  134. data/lib/ratatui_ruby/event.rb +56 -4
  135. data/lib/ratatui_ruby/frame.rb +87 -0
  136. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +11 -11
  137. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  138. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  139. data/lib/ratatui_ruby/schema/block.rb +163 -168
  140. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  141. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  142. data/lib/ratatui_ruby/schema/center.rb +46 -46
  143. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  144. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  145. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  146. data/lib/ratatui_ruby/schema/cursor.rb +25 -25
  147. data/lib/ratatui_ruby/schema/gauge.rb +53 -53
  148. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  149. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  150. data/lib/ratatui_ruby/schema/list.rb +86 -84
  151. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  152. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  153. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  154. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  155. data/lib/ratatui_ruby/schema/rect.rb +60 -60
  156. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  157. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  158. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  159. data/lib/ratatui_ruby/schema/style.rb +46 -46
  160. data/lib/ratatui_ruby/schema/table.rb +112 -119
  161. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  162. data/lib/ratatui_ruby/session/autodoc.rb +417 -0
  163. data/lib/ratatui_ruby/session.rb +40 -23
  164. data/lib/ratatui_ruby/test_helper.rb +185 -19
  165. data/lib/ratatui_ruby/version.rb +1 -1
  166. data/lib/ratatui_ruby.rb +65 -39
  167. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  168. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  169. data/sig/examples/app_all_events/model/events.rbs +15 -0
  170. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  171. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  172. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  173. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  174. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  175. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  176. data/sig/examples/app_all_events/view.rbs +8 -0
  177. data/sig/examples/app_all_events/view_state.rbs +15 -0
  178. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  179. data/sig/examples/app_login_form/app.rbs +11 -0
  180. data/sig/examples/app_map_demo/app.rbs +11 -0
  181. data/sig/examples/app_table_select/app.rbs +11 -0
  182. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  183. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  184. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  185. data/sig/examples/widget_block_padding/app.rbs +11 -0
  186. data/sig/examples/widget_block_titles/app.rbs +11 -0
  187. data/sig/examples/widget_box_demo/app.rbs +11 -0
  188. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  189. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  190. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  191. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  192. data/sig/examples/widget_layout_split/app.rbs +10 -0
  193. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  194. data/sig/examples/widget_list_demo/app.rbs +12 -0
  195. data/sig/examples/widget_list_styles/app.rbs +11 -0
  196. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  197. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  198. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  199. data/sig/examples/widget_rect/app.rbs +12 -0
  200. data/sig/examples/widget_render/app.rbs +10 -0
  201. data/sig/examples/widget_rich_text/app.rbs +11 -0
  202. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  203. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  204. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  205. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  206. data/sig/examples/widget_table_flex/app.rbs +11 -0
  207. data/sig/ratatui_ruby/frame.rbs +9 -0
  208. data/sig/ratatui_ruby/ratatui_ruby.rbs +3 -2
  209. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  210. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  211. data/sig/ratatui_ruby/session.rbs +94 -0
  212. data/tasks/autodoc/inventory.rb +61 -0
  213. data/tasks/autodoc/member.rb +56 -0
  214. data/tasks/autodoc/name.rb +19 -0
  215. data/tasks/autodoc/notice.rb +26 -0
  216. data/tasks/autodoc/rbs.rb +38 -0
  217. data/tasks/autodoc/rdoc.rb +45 -0
  218. data/tasks/autodoc.rake +47 -0
  219. data/tasks/bump/history.rb +2 -2
  220. data/tasks/doc.rake +600 -6
  221. data/tasks/example_viewer.html.erb +172 -0
  222. data/tasks/lint.rake +8 -4
  223. data/tasks/resources/index.html.erb +6 -0
  224. data/tasks/sourcehut.rake +4 -4
  225. data/tasks/terminal_preview/app_screenshot.rb +1 -3
  226. data/tasks/terminal_preview/crash_report.rb +7 -9
  227. data/tasks/terminal_preview/launcher_script.rb +4 -6
  228. data/tasks/terminal_preview/preview_collection.rb +4 -6
  229. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  230. data/tasks/terminal_preview/saved_screenshot.rb +7 -9
  231. data/tasks/terminal_preview/terminal_window.rb +7 -9
  232. data/tasks/test.rake +1 -1
  233. data/tasks/website/index_page.rb +3 -3
  234. data/tasks/website/version.rb +10 -10
  235. data/tasks/website/version_menu.rb +10 -12
  236. data/tasks/website/versioned_documentation.rb +49 -17
  237. data/tasks/website/website.rb +6 -8
  238. data/tasks/website.rake +4 -4
  239. metadata +156 -125
  240. data/LICENSES/BSD-2-Clause.txt +0 -9
  241. data/doc/contributors/better_dx.md +0 -543
  242. data/doc/contributors/example_analysis.md +0 -82
  243. data/doc/images/all_events.png +0 -0
  244. data/doc/images/block_padding.png +0 -0
  245. data/doc/images/block_titles.png +0 -0
  246. data/doc/images/box_demo.png +0 -0
  247. data/doc/images/calendar_demo.png +0 -0
  248. data/doc/images/cell_demo.png +0 -0
  249. data/doc/images/chart_demo.png +0 -0
  250. data/doc/images/flex_layout.png +0 -0
  251. data/doc/images/gauge_demo.png +0 -0
  252. data/doc/images/line_gauge_demo.png +0 -0
  253. data/doc/images/list_demo.png +0 -0
  254. data/doc/images/readme_usage.png +0 -0
  255. data/doc/images/scrollbar_demo.png +0 -0
  256. data/doc/images/sparkline_demo.png +0 -0
  257. data/doc/images/table_flex.png +0 -0
  258. data/examples/all_events/app.rb +0 -169
  259. data/examples/all_events/app.rbs +0 -7
  260. data/examples/all_events/test_app.rb +0 -139
  261. data/examples/analytics/app.rb +0 -258
  262. data/examples/analytics/app.rbs +0 -7
  263. data/examples/analytics/test_app.rb +0 -132
  264. data/examples/block_padding/app.rbs +0 -7
  265. data/examples/block_padding/test_app.rb +0 -31
  266. data/examples/block_titles/app.rbs +0 -7
  267. data/examples/block_titles/test_app.rb +0 -34
  268. data/examples/box_demo/app.rbs +0 -7
  269. data/examples/box_demo/test_app.rb +0 -88
  270. data/examples/calendar_demo/app.rb +0 -101
  271. data/examples/calendar_demo/app.rbs +0 -7
  272. data/examples/calendar_demo/test_app.rb +0 -108
  273. data/examples/cell_demo/app.rb +0 -108
  274. data/examples/cell_demo/app.rbs +0 -7
  275. data/examples/cell_demo/test_app.rb +0 -36
  276. data/examples/chart_demo/app.rb +0 -203
  277. data/examples/chart_demo/app.rbs +0 -7
  278. data/examples/chart_demo/test_app.rb +0 -102
  279. data/examples/custom_widget/app.rb +0 -51
  280. data/examples/custom_widget/app.rbs +0 -7
  281. data/examples/custom_widget/test_app.rb +0 -30
  282. data/examples/flex_layout/app.rb +0 -156
  283. data/examples/flex_layout/app.rbs +0 -7
  284. data/examples/flex_layout/test_app.rb +0 -65
  285. data/examples/gauge_demo/app.rb +0 -182
  286. data/examples/gauge_demo/test_app.rb +0 -120
  287. data/examples/hit_test/app.rb +0 -175
  288. data/examples/hit_test/app.rbs +0 -7
  289. data/examples/hit_test/test_app.rb +0 -102
  290. data/examples/line_gauge_demo/app.rb +0 -190
  291. data/examples/line_gauge_demo/app.rbs +0 -7
  292. data/examples/line_gauge_demo/test_app.rb +0 -129
  293. data/examples/list_demo/app.rb +0 -253
  294. data/examples/list_demo/test_app.rb +0 -237
  295. data/examples/list_styles/app.rb +0 -140
  296. data/examples/list_styles/app.rbs +0 -7
  297. data/examples/list_styles/test_app.rb +0 -157
  298. data/examples/login_form/app.rbs +0 -7
  299. data/examples/login_form/test_app.rb +0 -51
  300. data/examples/map_demo/app.rbs +0 -7
  301. data/examples/map_demo/test_app.rb +0 -149
  302. data/examples/mouse_events/app.rb +0 -97
  303. data/examples/mouse_events/app.rbs +0 -7
  304. data/examples/mouse_events/test_app.rb +0 -53
  305. data/examples/popup_demo/app.rb +0 -103
  306. data/examples/popup_demo/app.rbs +0 -7
  307. data/examples/popup_demo/test_app.rb +0 -54
  308. data/examples/quickstart_dsl/app.rbs +0 -7
  309. data/examples/quickstart_dsl/test_app.rb +0 -29
  310. data/examples/quickstart_lifecycle/app.rbs +0 -7
  311. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  312. data/examples/ratatui_logo_demo/app.rb +0 -79
  313. data/examples/ratatui_logo_demo/app.rbs +0 -7
  314. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  315. data/examples/ratatui_mascot_demo/app.rb +0 -84
  316. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  317. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  318. data/examples/readme_usage/app.rb +0 -29
  319. data/examples/readme_usage/app.rbs +0 -7
  320. data/examples/readme_usage/test_app.rb +0 -29
  321. data/examples/rich_text/app.rb +0 -141
  322. data/examples/rich_text/app.rbs +0 -7
  323. data/examples/rich_text/test_app.rb +0 -166
  324. data/examples/scroll_text/app.rb +0 -103
  325. data/examples/scroll_text/app.rbs +0 -7
  326. data/examples/scroll_text/test_app.rb +0 -110
  327. data/examples/scrollbar_demo/app.rb +0 -143
  328. data/examples/scrollbar_demo/app.rbs +0 -7
  329. data/examples/scrollbar_demo/test_app.rb +0 -77
  330. data/examples/sparkline_demo/app.rb +0 -240
  331. data/examples/sparkline_demo/test_app.rb +0 -107
  332. data/examples/table_flex/app.rb +0 -65
  333. data/examples/table_flex/app.rbs +0 -7
  334. data/examples/table_flex/test_app.rb +0 -36
  335. data/examples/table_select/app.rbs +0 -7
  336. data/examples/table_select/test_app.rb +0 -180
  337. data/examples/widget_style_colors/test_app.rb +0 -48
  338. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  339. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  340. /data/doc/images/{login_form.png → app_login_form.png} +0 -0
  341. /data/doc/images/{map_demo.png → app_map_demo.png} +0 -0
  342. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  343. /data/doc/images/{table_select.png → app_table_select.png} +0 -0
  344. /data/doc/images/{quickstart_dsl.png → verify_quickstart_dsl.png} +0 -0
  345. /data/doc/images/{ratatui_logo_demo.png → verify_quickstart_layout.png} +0 -0
  346. /data/doc/images/{quickstart_lifecycle.png → verify_quickstart_lifecycle.png} +0 -0
  347. /data/doc/images/{list_styles.png → widget_list_styles.png} +0 -0
  348. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  349. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  350. /data/doc/images/{rich_text.png → widget_rich_text.png} +0 -0
  351. /data/doc/images/{scroll_text.png → widget_scroll_text.png} +0 -0
@@ -0,0 +1,201 @@
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
+ require_relative "input"
7
+ require_relative "palette"
8
+ require_relative "clipboard"
9
+ require_relative "copy_dialog"
10
+
11
+ # Orchestrates layout and rendering of the color picker UI.
12
+ #
13
+ # Building a complete color picker UI involves layout calculation, widget
14
+ # composition, and coordinate tracking for hit testing. Keeping this logic
15
+ # scattered across the main app makes the app harder to read and test.
16
+ #
17
+ # This object owns the layout logic. It orchestrates all sections. It calculates
18
+ # and caches rects for hit testing.
19
+ #
20
+ # Use it to encapsulate complex UI composition.
21
+ #
22
+ # === Example
23
+ #
24
+ # scene = Scene.new(tui)
25
+ # scene.render(frame, input:, palette:, clipboard:, dialog:)
26
+ #
27
+ # # For hit testing:
28
+ # rect = scene.export_rect
29
+ # if rect.contains?(x, y)
30
+ # # Handle click
31
+ # end
32
+ class Scene
33
+ def initialize(tui)
34
+ @tui = tui
35
+ @export_area_rect = nil
36
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
37
+ end
38
+
39
+ # Renders the complete UI given all model objects.
40
+ #
41
+ # Calculates layout once per frame. Renders input, palette, export, controls,
42
+ # and dialog sections. Caches the export area rect for hit testing.
43
+ #
44
+ # [frame] Frame object from RatatuiRuby.draw block
45
+ # [input] Input object for text input display
46
+ # [palette] Palette object for color display
47
+ # [clipboard] Clipboard object for feedback message
48
+ # [dialog] CopyDialog object for confirmation dialog
49
+ #
50
+ # === Example
51
+ #
52
+ # scene.render(frame, input: @input, palette: @palette, clipboard: @clipboard, dialog: @dialog)
53
+ def render(frame, input:, palette:, clipboard:, dialog:)
54
+ input_area, rest = @tui.layout_split(
55
+ frame.area,
56
+ direction: :vertical,
57
+ constraints: [
58
+ @tui.constraint_length(3),
59
+ @tui.constraint_fill(1),
60
+ ]
61
+ )
62
+
63
+ color_area, control_area = @tui.layout_split(
64
+ rest,
65
+ direction: :vertical,
66
+ constraints: [
67
+ @tui.constraint_length(14),
68
+ @tui.constraint_fill(1),
69
+ ]
70
+ )
71
+
72
+ harmony_area, @export_area_rect = @tui.layout_split(
73
+ color_area,
74
+ direction: :vertical,
75
+ constraints: [
76
+ @tui.constraint_length(7),
77
+ @tui.constraint_fill(1),
78
+ ]
79
+ )
80
+
81
+ frame.render_widget(input.render(@tui), input_area)
82
+ frame.render_widget(build_palette_section(palette, harmony_area), harmony_area)
83
+ frame.render_widget(build_export_section(palette), @export_area_rect)
84
+ frame.render_widget(build_controls_section(clipboard), control_area)
85
+
86
+ if dialog.active?
87
+ dialog_center = calculate_center_area(frame.area, 40, 8)
88
+ frame.render_widget(@tui.clear, frame.area)
89
+ frame.render_widget(dialog.render(@tui, dialog_center), dialog_center)
90
+ end
91
+ end
92
+
93
+ # The cached rectangle of the export formats section, used for hit testing.
94
+ #
95
+ # Populated during #render. Use this to detect clicks on the export section.
96
+ #
97
+ # === Example
98
+ #
99
+ # scene.render(frame, ...)
100
+ # if scene.export_rect.contains?(x, y)
101
+ # # Click on export section
102
+ # end
103
+ def export_rect
104
+ @export_area_rect
105
+ end
106
+
107
+ private def build_palette_section(palette, _harmony_area)
108
+ if palette.main.nil?
109
+ @tui.paragraph(text: "No color selected")
110
+ else
111
+ blocks = palette.as_blocks(@tui)
112
+ @tui.layout(
113
+ direction: :horizontal,
114
+ constraints: Array.new(blocks.size) { @tui.constraint_fill(1) },
115
+ children: blocks
116
+ )
117
+ end
118
+ end
119
+
120
+ private def build_export_section(palette)
121
+ if palette.main.nil?
122
+ @tui.block(
123
+ title: "Export Formats",
124
+ borders: [:all],
125
+ children: [
126
+ @tui.paragraph(
127
+ text: @tui.text_line(spans: [
128
+ @tui.text_span(content: "Enter a color to see formats"),
129
+ ])
130
+ ),
131
+ ]
132
+ )
133
+ else
134
+ color = palette.main
135
+ hex = color.hex
136
+ rgb = color.rgb
137
+ hsl = color.hsl_string
138
+ text_color = color.contrasting_text_color
139
+ bg_style = @tui.style(bg: hex, fg: text_color)
140
+
141
+ @tui.block(
142
+ title: "Export Formats",
143
+ borders: [:all],
144
+ style: bg_style,
145
+ children: [
146
+ @tui.paragraph(
147
+ text: [
148
+ @tui.text_line(spans: [
149
+ @tui.text_span(content: "HEX: ", style: bg_style),
150
+ @tui.text_span(content: hex, style: @tui.style(bg: hex, fg: text_color, modifiers: [:underlined])),
151
+ ]),
152
+ @tui.text_line(spans: [
153
+ @tui.text_span(content: "RGB: ", style: bg_style),
154
+ @tui.text_span(content: rgb, style: @tui.style(bg: hex, fg: text_color, modifiers: [:underlined])),
155
+ ]),
156
+ @tui.text_line(spans: [
157
+ @tui.text_span(content: "HSL: ", style: bg_style),
158
+ @tui.text_span(content: hsl, style: @tui.style(bg: hex, fg: text_color, modifiers: [:underlined])),
159
+ ]),
160
+ ]
161
+ ),
162
+ ]
163
+ )
164
+ end
165
+ end
166
+
167
+ private def build_controls_section(clipboard)
168
+ control_lines = [
169
+ @tui.text_line(spans: [
170
+ @tui.text_span(content: "a-z/0-9", style: @hotkey_style),
171
+ @tui.text_span(content: ": Type "),
172
+ @tui.text_span(content: "enter", style: @hotkey_style),
173
+ @tui.text_span(content: ": Parse "),
174
+ @tui.text_span(content: "bksp", style: @hotkey_style),
175
+ @tui.text_span(content: ": Erase "),
176
+ @tui.text_span(content: "esc", style: @hotkey_style),
177
+ @tui.text_span(content: ": Quit"),
178
+ ]),
179
+ ]
180
+
181
+ unless clipboard.message.empty?
182
+ control_lines << @tui.text_line(spans: [
183
+ @tui.text_span(content: clipboard.message, style: @tui.style(fg: :green, modifiers: [:bold])),
184
+ ])
185
+ end
186
+
187
+ @tui.block(
188
+ title: "Controls",
189
+ borders: [:all],
190
+ children: [
191
+ @tui.paragraph(text: control_lines),
192
+ ]
193
+ )
194
+ end
195
+
196
+ private def calculate_center_area(parent_area, width, height)
197
+ x = (parent_area.width - width) / 2
198
+ y = (parent_area.height - height) / 2
199
+ @tui.rect(x:, y:, width:, height:)
200
+ end
201
+ end
@@ -6,7 +6,7 @@
6
6
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
  require "ratatui_ruby"
8
8
 
9
- class LoginFormApp
9
+ class AppLoginForm
10
10
  PREFIX = "Enter Username: [ "
11
11
  SUFFIX = " ]"
12
12
 
@@ -16,7 +16,8 @@ class LoginFormApp
16
16
  end
17
17
 
18
18
  def run
19
- RatatuiRuby.run do
19
+ RatatuiRuby.run do |tui|
20
+ @tui = tui
20
21
  loop do
21
22
  render
22
23
  break if handle_input == :quit
@@ -24,9 +25,7 @@ class LoginFormApp
24
25
  end
25
26
  end
26
27
 
27
- private
28
-
29
- def render
28
+ private def render
30
29
  # 1. Base Layer Construction
31
30
  # We want a cursor relative to the paragraph.
32
31
  # So we wrap Paragraph and Cursor in an Overlay, and put that Overlay in a Center.
@@ -39,17 +38,17 @@ class LoginFormApp
39
38
  cursor_y = 1
40
39
 
41
40
  # The content of the base form
42
- form_content = RatatuiRuby::Overlay.new(layers: [
43
- RatatuiRuby::Paragraph.new(
41
+ form_content = @tui.overlay(layers: [
42
+ @tui.paragraph(
44
43
  text: "#{PREFIX}#{@username}#{SUFFIX}",
45
- block: RatatuiRuby::Block.new(borders: :all, title: "Login Form"),
44
+ block: @tui.block(borders: :all, title: "Login Form"),
46
45
  alignment: :left
47
46
  ),
48
- RatatuiRuby::Cursor.new(x: cursor_x, y: cursor_y),
47
+ @tui.cursor(x: cursor_x, y: cursor_y),
49
48
  ])
50
49
 
51
50
  # Center the form on screen
52
- base_layer = RatatuiRuby::Center.new(
51
+ base_layer = @tui.center(
53
52
  child: form_content,
54
53
  width_percent: 50,
55
54
  height_percent: 20
@@ -57,11 +56,11 @@ class LoginFormApp
57
56
 
58
57
  # 2. Popup Layer Construction
59
58
  final_view = if @show_popup
60
- popup_message = RatatuiRuby::Center.new(
61
- child: RatatuiRuby::Paragraph.new(
59
+ popup_message = @tui.center(
60
+ child: @tui.paragraph(
62
61
  text: "Login Successful!\nPress 'q' to quit.",
63
- style: RatatuiRuby::Style.new(fg: :green, bg: :black),
64
- block: RatatuiRuby::Block.new(borders: :all),
62
+ style: @tui.style(fg: :green, bg: :black),
63
+ block: @tui.block(borders: :all),
65
64
  alignment: :center,
66
65
  wrap: true
67
66
  ),
@@ -70,42 +69,40 @@ class LoginFormApp
70
69
  )
71
70
 
72
71
  # Render Base Layer (background) THEN Popup Layer
73
- RatatuiRuby::Overlay.new(layers: [base_layer, popup_message])
72
+ @tui.overlay(layers: [base_layer, popup_message])
74
73
  else
75
74
  base_layer
76
75
  end
77
76
 
78
77
  # 3. Draw
79
- RatatuiRuby.draw(final_view)
78
+ @tui.draw do |frame|
79
+ frame.render_widget(final_view, frame.area)
80
+ end
80
81
  end
81
82
 
82
- def handle_input
83
- # 4. Event Handling
84
- event = RatatuiRuby.poll_event
85
- return unless event
86
-
87
- if event.key?
88
- if @show_popup
89
- return :quit if event == "q" || event == :ctrl_c
90
- else
91
- # Login Form Input
92
- return :quit if event == :ctrl_c
93
- case event.code
94
- when "enter"
95
- @show_popup = true
96
- when "backspace"
97
- @username.chop!
98
- when "esc"
99
- :quit
100
- else
101
- # Simple text input
102
- if event.text? && !event.ctrl? && !event.alt?
103
- @username += event.code
104
- end
105
- end
106
- end
83
+ private def handle_input
84
+ case @tui.poll_event
85
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
86
+ return :quit if @show_popup
87
+ nil
88
+ in { type: :key, code: "c", modifiers: ["ctrl"] }
89
+ :quit
90
+ in { type: :key, code: "enter" }
91
+ @show_popup ||= true
92
+ nil
93
+ in { type: :key, code: "backspace" }
94
+ @username.chop! unless @show_popup
95
+ nil
96
+ in { type: :key, code: "esc" }
97
+ :quit unless @show_popup
98
+ in { type: :key, code:, modifiers: [] }
99
+ # Simple text input (single character, no modifiers)
100
+ @username += code if !@show_popup && code.length == 1
101
+ nil
102
+ else
103
+ nil
107
104
  end
108
105
  end
109
106
  end
110
107
 
111
- LoginFormApp.new.run if __FILE__ == $0
108
+ AppLoginForm.new.run if __FILE__ == $0
@@ -7,7 +7,7 @@ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
  require "ratatui_ruby"
8
8
 
9
9
  # An example of the Canvas widget showing a world map and animated shapes.
10
- class MapDemoApp
10
+ class AppMapDemo
11
11
  include RatatuiRuby
12
12
 
13
13
  COLORS = [:black, :blue, :white, nil].freeze
@@ -15,40 +15,41 @@ class MapDemoApp
15
15
 
16
16
  # Returns a Canvas view for the map demo with the given circle radius.
17
17
  #
18
+ # +tui+:: The RatatuiRuby::Session instance.
18
19
  # +radius+:: The radius of the animated circle.
19
20
  # +marker+:: The marker type.
20
21
  # +background_color+:: The background color of the canvas.
21
22
  # +show_labels+:: Whether to show city labels.
22
- def view(radius, marker = :braille, background_color = nil, show_labels: true)
23
+ def view(tui, radius, marker = :braille, background_color = nil, show_labels: true)
23
24
  shapes = [
24
- Shape::Map.new(color: :green, resolution: :high),
25
- Shape::Circle.new(x: 0.0, y: 0.0, radius:, color: :red),
26
- Shape::Line.new(x1: 0.0, y1: 0.0, x2: 50.0, y2: 25.0, color: :yellow),
25
+ tui.shape_map(color: :green, resolution: :high),
26
+ tui.shape_circle(x: 0.0, y: 0.0, radius:, color: :red),
27
+ tui.shape_line(x1: 0.0, y1: 0.0, x2: 50.0, y2: 25.0, color: :yellow),
27
28
  ]
28
29
 
29
30
  if show_labels
30
31
  shapes += [
31
- Shape::Label.new(x: -0.1, y: 51.5, text: "London", style: Style.new(fg: :cyan)),
32
- Shape::Label.new(x: 139.7, y: 35.7, text: "Tokyo", style: Style.new(fg: :magenta)),
33
- Shape::Label.new(x: -74.0, y: 40.7, text: "New York", style: Style.new(fg: :yellow)),
34
- Shape::Label.new(x: -122.4, y: 37.8, text: "San Francisco", style: Style.new(fg: :blue)),
35
- Shape::Label.new(x: 151.2, y: -33.9, text: "Sydney", style: Style.new(fg: :green)),
32
+ tui.shape_label(x: -0.1, y: 51.5, text: "London", style: tui.style(fg: :cyan)),
33
+ tui.shape_label(x: 139.7, y: 35.7, text: "Tokyo", style: tui.style(fg: :magenta)),
34
+ tui.shape_label(x: -74.0, y: 40.7, text: "New York", style: tui.style(fg: :yellow)),
35
+ tui.shape_label(x: -122.4, y: 37.8, text: "San Francisco", style: tui.style(fg: :blue)),
36
+ tui.shape_label(x: 151.2, y: -33.9, text: "Sydney", style: tui.style(fg: :green)),
36
37
  ]
37
38
  end
38
39
 
39
- Canvas.new(
40
- shapes: shapes,
40
+ tui.canvas(
41
+ shapes:,
41
42
  x_bounds: [-180.0, 180.0],
42
43
  y_bounds: [-90.0, 90.0],
43
- marker: marker,
44
- block: Block.new(title: "World Map ['b' bg, 'm' marker: #{marker}, 'l' labels: #{show_labels ? 'on' : 'off'}]", borders: :all),
45
- background_color: background_color
44
+ marker:,
45
+ block: tui.block(title: "World Map ['b' bg, 'm' marker: #{marker}, 'l' labels: #{show_labels ? 'on' : 'off'}]", borders: :all),
46
+ background_color:
46
47
  )
47
48
  end
48
49
 
49
50
  # Runs the map demo loop.
50
51
  def run
51
- RatatuiRuby.run do
52
+ RatatuiRuby.run do |tui|
52
53
  radius = 0.0
53
54
  direction = 1
54
55
  bg_index = 0
@@ -63,13 +64,15 @@ class MapDemoApp
63
64
  end
64
65
 
65
66
  # Define the view
66
- v = view(radius, MARKERS[marker_index], COLORS[bg_index], show_labels:)
67
+ canvas = view(tui, radius, MARKERS[marker_index], COLORS[bg_index], show_labels:)
67
68
 
68
- RatatuiRuby.draw(v)
69
+ tui.draw do |frame|
70
+ frame.render_widget(canvas, frame.area)
71
+ end
69
72
 
70
- event = RatatuiRuby.poll_event
73
+ event = tui.poll_event
71
74
  case event
72
- in {type: :key, code: "q"} | {type: :key, code: :ctrl_c}
75
+ in { type: :key, code: "q" } | { type: :key, code: :ctrl_c }
73
76
  break
74
77
  in type: :key, code: "b"
75
78
  bg_index = (bg_index + 1) % COLORS.size
@@ -87,4 +90,4 @@ class MapDemoApp
87
90
  end
88
91
  end
89
92
 
90
- MapDemoApp.new.run if __FILE__ == $PROGRAM_NAME
93
+ AppMapDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -16,24 +16,16 @@ PROCESSES = [
16
16
  { pid: 3456, name: "redis", cpu: 12.4 },
17
17
  { pid: 7890, name: "sidekiq", cpu: 22.8 },
18
18
  { pid: 2345, name: "webpack", cpu: 45.3 },
19
- { pid: 6789, name: "node", cpu: 18.9 }
19
+ { pid: 6789, name: "node", cpu: 18.9 },
20
20
  ].freeze
21
21
 
22
- class TableSelectApp
22
+ class AppTableSelect
23
23
  attr_reader :selected_index, :selected_col, :current_style_index, :column_spacing, :highlight_spacing, :column_highlight_style, :cell_highlight_style
24
24
 
25
- STYLES = [
26
- { name: "Cyan", style: RatatuiRuby::Style.new(fg: :cyan) },
27
- { name: "Red", style: RatatuiRuby::Style.new(fg: :red) },
28
- { name: "Green", style: RatatuiRuby::Style.new(fg: :green) },
29
- { name: "Blue on White", style: RatatuiRuby::Style.new(fg: :blue, bg: :white) },
30
- { name: "Magenta", style: RatatuiRuby::Style.new(fg: :magenta, modifiers: [:bold]) }
31
- ].freeze
32
-
33
25
  HIGHLIGHT_SPACINGS = [
34
26
  { name: "When Selected", spacing: :when_selected },
35
27
  { name: "Always", spacing: :always },
36
- { name: "Never", spacing: :never }
28
+ { name: "Never", spacing: :never },
37
29
  ].freeze
38
30
 
39
31
  def initialize
@@ -42,57 +34,69 @@ class TableSelectApp
42
34
  @current_style_index = 0
43
35
  @column_spacing = 1
44
36
  @highlight_spacing_index = 0
45
- @column_highlight_style = RatatuiRuby::Style.new(fg: :magenta)
46
37
  @show_column_highlight = true
47
- @cell_highlight_style = RatatuiRuby::Style.new(fg: :white, bg: :red, modifiers: [:bold])
48
38
  @show_cell_highlight = true
49
- @hotkey_style = RatatuiRuby::Style.new(modifiers: [:bold, :underlined])
50
39
  end
51
40
 
52
41
  def run
53
- RatatuiRuby.run do
42
+ RatatuiRuby.run do |tui|
43
+ @tui = tui
44
+ setup_styles
54
45
  loop do
55
- render
46
+ @tui.draw do |frame|
47
+ render(frame)
48
+ end
56
49
  break if handle_input == :quit
57
50
  end
58
51
  end
59
52
  end
60
53
 
61
- private
54
+ private def setup_styles
55
+ @styles = [
56
+ { name: "Cyan", style: @tui.style(fg: :cyan) },
57
+ { name: "Red", style: @tui.style(fg: :red) },
58
+ { name: "Green", style: @tui.style(fg: :green) },
59
+ { name: "Blue on White", style: @tui.style(fg: :blue, bg: :white) },
60
+ { name: "Magenta", style: @tui.style(fg: :magenta, modifiers: [:bold]) },
61
+ ]
62
+ @column_highlight_style = @tui.style(fg: :magenta)
63
+ @cell_highlight_style = @tui.style(fg: :white, bg: :red, modifiers: [:bold])
64
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
65
+ end
62
66
 
63
- def render
67
+ private def render(frame)
64
68
  # Create table rows from process data
65
69
  rows = PROCESSES.map { |p| [p[:pid].to_s, p[:name], "#{p[:cpu]}%"] }
66
70
 
67
71
  # Define column widths
68
72
  widths = [
69
- RatatuiRuby::Constraint.length(8),
70
- RatatuiRuby::Constraint.length(15),
71
- RatatuiRuby::Constraint.length(10)
73
+ @tui.constraint_length(8),
74
+ @tui.constraint_length(15),
75
+ @tui.constraint_length(10),
72
76
  ]
73
77
 
74
78
  # Create highlight style (yellow text)
75
- highlight_style = RatatuiRuby::Style.new(fg: :yellow)
79
+ highlight_style = @tui.style(fg: :yellow)
76
80
 
77
- current_style_entry = STYLES[@current_style_index]
81
+ current_style_entry = @styles[@current_style_index]
78
82
  current_spacing_entry = HIGHLIGHT_SPACINGS[@highlight_spacing_index]
79
83
  selection_label = @selected_index.nil? ? "none" : @selected_index.to_s
80
84
 
81
85
  # Main table
82
- table = RatatuiRuby::Table.new(
86
+ table = @tui.table(
83
87
  header: ["PID", "Name", "CPU"],
84
- rows: rows,
85
- widths: widths,
88
+ rows:,
89
+ widths:,
86
90
  selected_row: @selected_index,
87
91
  selected_column: @selected_col,
88
- highlight_style: highlight_style,
92
+ highlight_style:,
89
93
  highlight_symbol: "> ",
90
94
  highlight_spacing: current_spacing_entry[:spacing],
91
95
  column_highlight_style: @show_column_highlight ? @column_highlight_style : nil,
92
96
  cell_highlight_style: @show_cell_highlight ? @cell_highlight_style : nil,
93
97
  style: current_style_entry[:style],
94
98
  column_spacing: @column_spacing,
95
- block: RatatuiRuby::Block.new(
99
+ block: @tui.block(
96
100
  title: "Processes",
97
101
  borders: :all
98
102
  ),
@@ -100,63 +104,62 @@ class TableSelectApp
100
104
  )
101
105
 
102
106
  # Bottom control panel
103
- control_panel = RatatuiRuby::Block.new(
107
+ control_panel = @tui.block(
104
108
  title: "Controls",
105
109
  borders: [:all],
106
110
  children: [
107
- RatatuiRuby::Paragraph.new(
111
+ @tui.paragraph(
108
112
  text: [
109
113
  # Line 1: Navigation
110
- RatatuiRuby::Text::Line.new(spans: [
111
- RatatuiRuby::Text::Span.new(content: "↑/↓", style: @hotkey_style),
112
- RatatuiRuby::Text::Span.new(content: ": Nav Row "),
113
- RatatuiRuby::Text::Span.new(content: "←/→", style: @hotkey_style),
114
- RatatuiRuby::Text::Span.new(content: ": Nav Col "),
115
- RatatuiRuby::Text::Span.new(content: "x", style: @hotkey_style),
116
- RatatuiRuby::Text::Span.new(content: ": Toggle Row (#{selection_label}) "),
117
- RatatuiRuby::Text::Span.new(content: "q", style: @hotkey_style),
118
- RatatuiRuby::Text::Span.new(content: ": Quit")
114
+ @tui.text_line(spans: [
115
+ @tui.text_span(content: "↑/↓", style: @hotkey_style),
116
+ @tui.text_span(content: ": Nav Row "),
117
+ @tui.text_span(content: "←/→", style: @hotkey_style),
118
+ @tui.text_span(content: ": Nav Col "),
119
+ @tui.text_span(content: "x", style: @hotkey_style),
120
+ @tui.text_span(content: ": Toggle Row (#{selection_label}) "),
121
+ @tui.text_span(content: "q", style: @hotkey_style),
122
+ @tui.text_span(content: ": Quit"),
119
123
  ]),
120
124
  # Line 2: Table Controls
121
- RatatuiRuby::Text::Line.new(spans: [
122
- RatatuiRuby::Text::Span.new(content: "s", style: @hotkey_style),
123
- RatatuiRuby::Text::Span.new(content: ": Style (#{current_style_entry[:name]}) "),
124
- RatatuiRuby::Text::Span.new(content: "p", style: @hotkey_style),
125
- RatatuiRuby::Text::Span.new(content: ": Spacing (#{current_spacing_entry[:name]}) ")
125
+ @tui.text_line(spans: [
126
+ @tui.text_span(content: "s", style: @hotkey_style),
127
+ @tui.text_span(content: ": Style (#{current_style_entry[:name]}) "),
128
+ @tui.text_span(content: "p", style: @hotkey_style),
129
+ @tui.text_span(content: ": Spacing (#{current_spacing_entry[:name]}) "),
126
130
  ]),
127
131
  # Line 3: More Controls
128
- RatatuiRuby::Text::Line.new(spans: [
129
- RatatuiRuby::Text::Span.new(content: ": Col Space (#{@column_spacing}) "),
130
- RatatuiRuby::Text::Span.new(content: "c", style: @hotkey_style),
131
- RatatuiRuby::Text::Span.new(content: ": Col Highlight (#{@show_column_highlight ? 'On' : 'Off'}) "),
132
- RatatuiRuby::Text::Span.new(content: "z", style: @hotkey_style),
133
- RatatuiRuby::Text::Span.new(content: ": Cell Highlight (#{@show_cell_highlight ? 'On' : 'Off'})")
134
- ])
132
+ @tui.text_line(spans: [
133
+ @tui.text_span(content: ": Col Space (#{@column_spacing}) "),
134
+ @tui.text_span(content: "c", style: @hotkey_style),
135
+ @tui.text_span(content: ": Col Highlight (#{@show_column_highlight ? 'On' : 'Off'}) "),
136
+ @tui.text_span(content: "z", style: @hotkey_style),
137
+ @tui.text_span(content: ": Cell Highlight (#{@show_cell_highlight ? 'On' : 'Off'})"),
138
+ ]),
135
139
  ]
136
- )
140
+ ),
137
141
  ]
138
142
  )
139
143
 
140
144
  # Layout
141
- layout = RatatuiRuby::Layout.new(
145
+ layout = @tui.layout_split(
146
+ frame.area,
142
147
  direction: :vertical,
143
148
  constraints: [
144
- RatatuiRuby::Constraint.fill(1),
145
- RatatuiRuby::Constraint.length(5),
146
- ],
147
- children: [table, control_panel]
149
+ @tui.constraint_fill(1),
150
+ @tui.constraint_length(5),
151
+ ]
148
152
  )
149
153
 
150
- # Draw the table
151
- RatatuiRuby.draw(layout)
154
+ frame.render_widget(table, layout[0])
155
+ frame.render_widget(control_panel, layout[1])
152
156
  end
153
157
 
154
- def handle_input
155
- event = RatatuiRuby.poll_event
156
- return unless event
158
+ private def handle_input
159
+ event = @tui.poll_event
157
160
 
158
161
  case event
159
- in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
162
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
160
163
  :quit
161
164
  in type: :key, code: "down" | "j"
162
165
  @selected_index = ((@selected_index || -1) + 1) % PROCESSES.length
@@ -174,7 +177,7 @@ class TableSelectApp
174
177
  @selected_col = (@selected_col || 0) - 1
175
178
  @selected_col = 2 if @selected_col.negative?
176
179
  in type: :key, code: "s"
177
- @current_style_index = (@current_style_index + 1) % STYLES.length
180
+ @current_style_index = (@current_style_index + 1) % @styles.length
178
181
  in type: :key, code: "+"
179
182
  @column_spacing += 1
180
183
  in type: :key, code: "-"
@@ -194,5 +197,5 @@ class TableSelectApp
194
197
  end
195
198
 
196
199
  if __FILE__ == $0
197
- TableSelectApp.new.run
200
+ AppTableSelect.new.run
198
201
  end