tuile 0.15.0 → 0.17.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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +229 -80
  3. data/README.md +49 -24
  4. data/book/02-repaint.md +47 -19
  5. data/book/03-layout.md +98 -49
  6. data/book/04-event-loop.md +17 -16
  7. data/book/05-focus.md +106 -34
  8. data/book/06-theming.md +108 -38
  9. data/book/07-components.md +249 -46
  10. data/book/08-testing.md +134 -32
  11. data/book/10-locale.md +3 -3
  12. data/book/README.md +11 -10
  13. data/examples/file_commander.rb +52 -32
  14. data/examples/hello_world.rb +18 -5
  15. data/examples/sampler.rb +576 -146
  16. data/lib/tuile/buffer.rb +12 -1
  17. data/lib/tuile/canvas/backend.rb +46 -0
  18. data/lib/tuile/canvas.rb +212 -0
  19. data/lib/tuile/color.rb +38 -9
  20. data/lib/tuile/component/abstract_string_field.rb +96 -97
  21. data/lib/tuile/component/abstract_wrapping_field.rb +99 -58
  22. data/lib/tuile/component/big_decimal_field.rb +7 -6
  23. data/lib/tuile/component/button.rb +27 -19
  24. data/lib/tuile/component/checkbox.rb +21 -19
  25. data/lib/tuile/component/checkbox_group.rb +17 -18
  26. data/lib/tuile/component/combo_box.rb +69 -64
  27. data/lib/tuile/component/confirm_window.rb +34 -27
  28. data/lib/tuile/component/date_field.rb +50 -18
  29. data/lib/tuile/component/date_time_field.rb +319 -0
  30. data/lib/tuile/component/fill.rb +93 -0
  31. data/lib/tuile/component/float_field.rb +7 -6
  32. data/lib/tuile/component/form_item.rb +250 -0
  33. data/lib/tuile/component/form_layout.rb +206 -0
  34. data/lib/tuile/component/has_bad_input.rb +99 -28
  35. data/lib/tuile/component/has_caption.rb +14 -5
  36. data/lib/tuile/component/has_content.rb +8 -15
  37. data/lib/tuile/component/has_placeholder.rb +1 -1
  38. data/lib/tuile/component/has_validation.rb +40 -14
  39. data/lib/tuile/component/has_value.rb +71 -17
  40. data/lib/tuile/component/integer_field.rb +7 -6
  41. data/lib/tuile/component/label.rb +8 -15
  42. data/lib/tuile/component/layout/absolute.rb +86 -0
  43. data/lib/tuile/component/layout/box.rb +38 -60
  44. data/lib/tuile/component/layout.rb +127 -13
  45. data/lib/tuile/component/list.rb +233 -120
  46. data/lib/tuile/component/list_dropdown.rb +151 -91
  47. data/lib/tuile/component/menu_bar/cascade.rb +102 -32
  48. data/lib/tuile/component/menu_bar.rb +102 -82
  49. data/lib/tuile/component/notification.rb +76 -49
  50. data/lib/tuile/component/overlay.rb +217 -58
  51. data/lib/tuile/component/password_field.rb +1 -8
  52. data/lib/tuile/component/picker_window.rb +41 -17
  53. data/lib/tuile/component/popup.rb +15 -26
  54. data/lib/tuile/component/progress_bar.rb +17 -11
  55. data/lib/tuile/component/radio_group.rb +16 -17
  56. data/lib/tuile/component/scroller.rb +266 -0
  57. data/lib/tuile/component/select.rb +26 -43
  58. data/lib/tuile/component/slot.rb +4 -5
  59. data/lib/tuile/component/tab_sheet.rb +27 -34
  60. data/lib/tuile/component/tabs.rb +49 -34
  61. data/lib/tuile/component/text_area/wrapped_text.rb +1 -1
  62. data/lib/tuile/component/text_area.rb +32 -28
  63. data/lib/tuile/component/text_field.rb +68 -50
  64. data/lib/tuile/component/text_view.rb +157 -89
  65. data/lib/tuile/component/time_field.rb +51 -21
  66. data/lib/tuile/component/vertical_scroll_bar.rb +257 -0
  67. data/lib/tuile/component/window.rb +27 -26
  68. data/lib/tuile/component.rb +653 -323
  69. data/lib/tuile/component_background.rb +177 -0
  70. data/lib/tuile/component_util.rb +43 -0
  71. data/lib/tuile/event.rb +29 -0
  72. data/lib/tuile/event_queue.rb +18 -4
  73. data/lib/tuile/fake_event_queue.rb +1 -1
  74. data/lib/tuile/fake_screen.rb +120 -7
  75. data/lib/tuile/keys.rb +15 -6
  76. data/lib/tuile/layout_pass.rb +180 -0
  77. data/lib/tuile/listeners.rb +219 -0
  78. data/lib/tuile/mouse/router.rb +233 -0
  79. data/lib/tuile/mouse.rb +244 -0
  80. data/lib/tuile/point.rb +6 -0
  81. data/lib/tuile/rect.rb +33 -0
  82. data/lib/tuile/screen.rb +510 -138
  83. data/lib/tuile/screen_pane.rb +185 -67
  84. data/lib/tuile/strict_layout.rb +127 -0
  85. data/lib/tuile/styled_string.rb +144 -14
  86. data/lib/tuile/testing/gestures.rb +35 -0
  87. data/lib/tuile/testing.rb +316 -42
  88. data/lib/tuile/theme.rb +192 -53
  89. data/lib/tuile/theme_def.rb +4 -0
  90. data/lib/tuile/version.rb +1 -1
  91. data/lib/tuile.rb +53 -0
  92. data/sig/tuile.rbs +6084 -1507
  93. metadata +19 -17
  94. data/COMPARISON.md +0 -101
  95. data/DECISIONS.md +0 -8562
  96. data/TERMINOLOGY.md +0 -85
  97. data/ideas/arrow-key-navigation.md +0 -221
  98. data/ideas/binder.md +0 -177
  99. data/ideas/composite-field.md +0 -77
  100. data/ideas/focus-accent.md +0 -116
  101. data/ideas/form-layout.md +0 -151
  102. data/ideas/hover/probe.rb +0 -241
  103. data/ideas/hover/probe_spec.rb +0 -82
  104. data/ideas/hover.md +0 -909
  105. data/ideas/modal-backdrop.md +0 -24
  106. data/ideas/new-components.md +0 -144
  107. data/ideas/per-component-buffers.md +0 -55
  108. data/lib/tuile/mouse_event.rb +0 -68
  109. data/lib/tuile/vertical_scroll_bar.rb +0 -122
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tuile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Vysny
@@ -113,11 +113,8 @@ extra_rdoc_files: []
113
113
  files:
114
114
  - CHANGELOG.md
115
115
  - CODE_OF_CONDUCT.md
116
- - COMPARISON.md
117
- - DECISIONS.md
118
116
  - LICENSE.txt
119
117
  - README.md
120
- - TERMINOLOGY.md
121
118
  - book/01-first-app.md
122
119
  - book/02-repaint.md
123
120
  - book/03-layout.md
@@ -132,20 +129,11 @@ files:
132
129
  - examples/file_commander.rb
133
130
  - examples/hello_world.rb
134
131
  - examples/sampler.rb
135
- - ideas/arrow-key-navigation.md
136
- - ideas/binder.md
137
- - ideas/composite-field.md
138
- - ideas/focus-accent.md
139
- - ideas/form-layout.md
140
- - ideas/hover.md
141
- - ideas/hover/probe.rb
142
- - ideas/hover/probe_spec.rb
143
- - ideas/modal-backdrop.md
144
- - ideas/new-components.md
145
- - ideas/per-component-buffers.md
146
132
  - lib/tuile.rb
147
133
  - lib/tuile/ansi.rb
148
134
  - lib/tuile/buffer.rb
135
+ - lib/tuile/canvas.rb
136
+ - lib/tuile/canvas/backend.rb
149
137
  - lib/tuile/color.rb
150
138
  - lib/tuile/color_depth.rb
151
139
  - lib/tuile/component.rb
@@ -158,7 +146,11 @@ files:
158
146
  - lib/tuile/component/combo_box.rb
159
147
  - lib/tuile/component/confirm_window.rb
160
148
  - lib/tuile/component/date_field.rb
149
+ - lib/tuile/component/date_time_field.rb
150
+ - lib/tuile/component/fill.rb
161
151
  - lib/tuile/component/float_field.rb
152
+ - lib/tuile/component/form_item.rb
153
+ - lib/tuile/component/form_layout.rb
162
154
  - lib/tuile/component/has_bad_input.rb
163
155
  - lib/tuile/component/has_caption.rb
164
156
  - lib/tuile/component/has_content.rb
@@ -169,6 +161,7 @@ files:
169
161
  - lib/tuile/component/integer_field.rb
170
162
  - lib/tuile/component/label.rb
171
163
  - lib/tuile/component/layout.rb
164
+ - lib/tuile/component/layout/absolute.rb
172
165
  - lib/tuile/component/layout/box.rb
173
166
  - lib/tuile/component/layout/horizontal.rb
174
167
  - lib/tuile/component/layout/vertical.rb
@@ -185,6 +178,7 @@ files:
185
178
  - lib/tuile/component/popup.rb
186
179
  - lib/tuile/component/progress_bar.rb
187
180
  - lib/tuile/component/radio_group.rb
181
+ - lib/tuile/component/scroller.rb
188
182
  - lib/tuile/component/select.rb
189
183
  - lib/tuile/component/slot.rb
190
184
  - lib/tuile/component/tab_sheet.rb
@@ -194,27 +188,35 @@ files:
194
188
  - lib/tuile/component/text_field.rb
195
189
  - lib/tuile/component/text_view.rb
196
190
  - lib/tuile/component/time_field.rb
191
+ - lib/tuile/component/vertical_scroll_bar.rb
197
192
  - lib/tuile/component/window.rb
193
+ - lib/tuile/component_background.rb
194
+ - lib/tuile/component_util.rb
195
+ - lib/tuile/event.rb
198
196
  - lib/tuile/event_queue.rb
199
197
  - lib/tuile/fake_event_queue.rb
200
198
  - lib/tuile/fake_screen.rb
201
199
  - lib/tuile/final.rb
202
200
  - lib/tuile/fraction.rb
203
201
  - lib/tuile/keys.rb
202
+ - lib/tuile/layout_pass.rb
203
+ - lib/tuile/listeners.rb
204
204
  - lib/tuile/locale.rb
205
- - lib/tuile/mouse_event.rb
205
+ - lib/tuile/mouse.rb
206
+ - lib/tuile/mouse/router.rb
206
207
  - lib/tuile/point.rb
207
208
  - lib/tuile/rect.rb
208
209
  - lib/tuile/screen.rb
209
210
  - lib/tuile/screen_pane.rb
210
211
  - lib/tuile/size.rb
212
+ - lib/tuile/strict_layout.rb
211
213
  - lib/tuile/styled_string.rb
212
214
  - lib/tuile/terminal_background.rb
213
215
  - lib/tuile/testing.rb
216
+ - lib/tuile/testing/gestures.rb
214
217
  - lib/tuile/theme.rb
215
218
  - lib/tuile/theme_def.rb
216
219
  - lib/tuile/version.rb
217
- - lib/tuile/vertical_scroll_bar.rb
218
220
  - sig/tuile.rbs
219
221
  homepage: https://github.com/mvysny/tuile
220
222
  licenses:
data/COMPARISON.md DELETED
@@ -1,101 +0,0 @@
1
- # COMPARISON.md
2
-
3
- Tuile's neighbours: what else exists, and — the question this file exists to
4
- answer — how much of it you can actually *reach from Ruby* on an ordinary Linux
5
- box without building bindings first.
6
-
7
- The short version: of the three alternatives the README names, **none** is
8
- callable from Ruby via the distro package manager. What is callable is a pair
9
- of curses bindings that sit *below* Tuile, and the tty-toolkit that Tuile is
10
- already built on.
11
-
12
- ## The alternatives
13
-
14
- The three the README points here for:
15
-
16
- - **[tty-toolkit](https://ttytoolkit.org/)** (`tty-prompt`, `tty-cursor`, …) —
17
- low-level building blocks, not a framework: no component tree, no event loop,
18
- no invalidation. Tuile sits on top of `tty-cursor` / `tty-screen` and adds
19
- the framework layer.
20
- - **[vedeu](https://github.com/gavinlaking/vedeu)** — the closest Ruby
21
- comparable, unmaintained since 2017.
22
- - **[ratatui](https://github.com/ratatui/ratatui)** — the popular Rust TUI
23
- framework; its immediate-mode API is closer to `tty-prompt` than to Tuile's
24
- retained component tree.
25
-
26
- Beyond those, DECISIONS.md surveys **Textual**, **urwid**, **brick**,
27
- **Lipgloss**, **notcurses**, **FTXUI** and **Ink** — but as per-decision
28
- precedent inside `D_` entries (`D_bg_inherit`, `D_key_dispatch`,
29
- `D_box_layouts`, `D_list_items` are the dense ones), not as a roster. Look
30
- there for "what does Textual do about focus-first key dispatch", not for
31
- "should I use Textual".
32
-
33
- ## Reachable from Ruby, via apt
34
-
35
- Surveyed on Ubuntu 26.04 (resolute) in 2026-08, against the distro's own
36
- `/usr/bin/ruby` 3.3.8 — which matters, see the caveats below.
37
-
38
- | Candidate | apt package | Callable from Ruby? |
39
- |---|---|---|
40
- | vedeu | *no package at all* | — |
41
- | ratatui | `librust-ratatui-dev` (Rust source only) | no |
42
- | Textual | `python3-textual` | no |
43
- | urwid | `python3-urwid` | no |
44
- | notcurses | `libnotcurses-dev`, `notcurses-bin` | no bindings — you would write the FFI |
45
- | CDK, newt | `libcdk5-dev`, `libnewt-dev` | C and Python only |
46
- | tty-toolkit | `ruby-tty-prompt`, `-cursor`, `-screen`, `-reader`, `-color`, `-pastel` | **yes** — but this is Tuile's own substrate |
47
- | curses | `ruby-curses` | **yes** |
48
- | ncurses + panel/form/menu | `ruby-ncurses` | **yes** — the closest of the lot |
49
-
50
- `dialog` and `whiptail` are also packaged and can be shelled out to from Ruby,
51
- but a subprocess that paints one dialog and exits is a different tool from a
52
- framework that owns a running screen; they are out of scope here.
53
-
54
- ### The two curses bindings
55
-
56
- Neither is in the README's list, and between them they are the only way to
57
- reach anything Tuile-shaped from Ruby without a compiler and a binding project.
58
-
59
- - **`ruby-curses`** — the [ruby/curses](https://github.com/ruby/curses) gem,
60
- wide-char, shipping `curses.so` plus a gemspec under
61
- `rubygems-integration`, so `gem "curses"` resolves under Bundler with no
62
- build step. Strictly low-level: windows, `addstr`, `getch`. No widgets, no
63
- tree, no invalidation — *below* tty-toolkit, not beside it.
64
- - **`ruby-ncurses`** — the `ncursesw` gem
65
- ([sup-heliotrope fork](https://github.com/sup-heliotrope/ncursesw-ruby)), and
66
- the interesting one. Its extension links `libpanelw`, `libformw` **and**
67
- `libmenu`, and exports `new_form` / `new_menu` / `form_driver` /
68
- `menu_driver`; `examples/form.rb` ships in the package. So you get
69
- overlapping windows (Tuile's popup stack), field editing with validation, and
70
- list selection, out of the box.
71
-
72
- ### Why `ruby-ncurses` still is not a substitute
73
-
74
- The gap is the framework layer, and the framework layer is the whole of Tuile.
75
- ncurses forms and menus are a *fixed* widget set driven by a
76
- `form_driver(request)` call. What is missing, in Tuile's own terms:
77
-
78
- - no `parent` / `children` tree you compose your own components into — you
79
- cannot write a component, only configure theirs;
80
- - no top-down layout: nothing assigns a child its `rect`, so every rectangle is
81
- arithmetic you keep by hand (book ch3 for why Tuile made that a rule rather
82
- than an engine);
83
- - no invalidate-and-batch-repaint, so no minimal-diff flush — you decide when
84
- to `refresh` and pay for whatever you redraw;
85
- - no theme or inherited `bg_color`, no `HasValue` value seam a forms layer can
86
- iterate, no `FakeScreen` to assert painted cells against.
87
-
88
- You would be building Tuile *on top of* it, not replacing Tuile with it — and
89
- since `ncursesw-ruby` is a 1.4.x mirror of the C API, whatever you built would
90
- sit directly on `WINDOW*` semantics.
91
-
92
- ### Caveats on the apt route
93
-
94
- - **`ruby-ncurses` and `ruby-curses` are built against the distro's Ruby** —
95
- `Depends: libruby (<< 1:3.4~)` on resolute. They are invisible to any
96
- rbenv/rvm/chruby Ruby, and they break on a distro Ruby upgrade. The gems
97
- (`gem install curses` / `ncursesw`) compile against `libncurses-dev` and do
98
- not have that problem.
99
- - **The table above is a snapshot of one release.** Package availability is the
100
- fastest-rotting fact in this file; re-run `apt-cache policy <pkg>` before
101
- trusting a row.