konpeito 0.1.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 (180) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +75 -0
  4. data/CONTRIBUTING.md +123 -0
  5. data/LICENSE +21 -0
  6. data/README.md +257 -0
  7. data/Rakefile +11 -0
  8. data/bin/konpeito +6 -0
  9. data/konpeito.gemspec +43 -0
  10. data/lib/konpeito/ast/typed_ast.rb +620 -0
  11. data/lib/konpeito/ast/visitor.rb +78 -0
  12. data/lib/konpeito/cache/cache_manager.rb +230 -0
  13. data/lib/konpeito/cache/dependency_graph.rb +192 -0
  14. data/lib/konpeito/cache.rb +8 -0
  15. data/lib/konpeito/cli/base_command.rb +187 -0
  16. data/lib/konpeito/cli/build_command.rb +220 -0
  17. data/lib/konpeito/cli/check_command.rb +104 -0
  18. data/lib/konpeito/cli/config.rb +231 -0
  19. data/lib/konpeito/cli/deps_command.rb +128 -0
  20. data/lib/konpeito/cli/doctor_command.rb +340 -0
  21. data/lib/konpeito/cli/fmt_command.rb +199 -0
  22. data/lib/konpeito/cli/init_command.rb +312 -0
  23. data/lib/konpeito/cli/lsp_command.rb +40 -0
  24. data/lib/konpeito/cli/run_command.rb +150 -0
  25. data/lib/konpeito/cli/test_command.rb +248 -0
  26. data/lib/konpeito/cli/watch_command.rb +212 -0
  27. data/lib/konpeito/cli.rb +301 -0
  28. data/lib/konpeito/codegen/builtin_methods.rb +229 -0
  29. data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
  30. data/lib/konpeito/codegen/debug_info.rb +352 -0
  31. data/lib/konpeito/codegen/inliner.rb +486 -0
  32. data/lib/konpeito/codegen/jvm_backend.rb +197 -0
  33. data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
  34. data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
  35. data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
  36. data/lib/konpeito/codegen/monomorphizer.rb +359 -0
  37. data/lib/konpeito/codegen/profile_runtime.c +341 -0
  38. data/lib/konpeito/codegen/profiler.rb +99 -0
  39. data/lib/konpeito/compiler.rb +592 -0
  40. data/lib/konpeito/dependency_resolver.rb +296 -0
  41. data/lib/konpeito/diagnostics/collector.rb +127 -0
  42. data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
  43. data/lib/konpeito/diagnostics/renderer.rb +144 -0
  44. data/lib/konpeito/formatter/formatter.rb +1214 -0
  45. data/lib/konpeito/hir/builder.rb +7167 -0
  46. data/lib/konpeito/hir/nodes.rb +2465 -0
  47. data/lib/konpeito/lsp/document_manager.rb +820 -0
  48. data/lib/konpeito/lsp/server.rb +183 -0
  49. data/lib/konpeito/lsp/transport.rb +38 -0
  50. data/lib/konpeito/parser/prism_adapter.rb +65 -0
  51. data/lib/konpeito/platform.rb +103 -0
  52. data/lib/konpeito/profile/report.rb +136 -0
  53. data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
  54. data/lib/konpeito/stdlib/compression/compression.rb +72 -0
  55. data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
  56. data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
  57. data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
  58. data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
  59. data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
  60. data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
  61. data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
  62. data/lib/konpeito/stdlib/http/extconf.rb +19 -0
  63. data/lib/konpeito/stdlib/http/http.rb +125 -0
  64. data/lib/konpeito/stdlib/http/http.rbs +57 -0
  65. data/lib/konpeito/stdlib/http/http_native.c +440 -0
  66. data/lib/konpeito/stdlib/json/extconf.rb +17 -0
  67. data/lib/konpeito/stdlib/json/json.rb +44 -0
  68. data/lib/konpeito/stdlib/json/json.rbs +33 -0
  69. data/lib/konpeito/stdlib/json/json_native.c +286 -0
  70. data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
  71. data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
  72. data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
  73. data/lib/konpeito/stdlib/ui/ui.rb +318 -0
  74. data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
  75. data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
  76. data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
  77. data/lib/konpeito/type_checker/inferrer.rb +565 -0
  78. data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
  79. data/lib/konpeito/type_checker/type_resolver.rb +276 -0
  80. data/lib/konpeito/type_checker/types.rb +1434 -0
  81. data/lib/konpeito/type_checker/unification.rb +323 -0
  82. data/lib/konpeito/ui/animation/animated_state.rb +80 -0
  83. data/lib/konpeito/ui/animation/easing.rb +59 -0
  84. data/lib/konpeito/ui/animation/value_tween.rb +66 -0
  85. data/lib/konpeito/ui/app.rb +379 -0
  86. data/lib/konpeito/ui/box.rb +38 -0
  87. data/lib/konpeito/ui/castella.rb +70 -0
  88. data/lib/konpeito/ui/castella_native.rb +76 -0
  89. data/lib/konpeito/ui/chart/area_chart.rb +305 -0
  90. data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
  91. data/lib/konpeito/ui/chart/base_chart.rb +210 -0
  92. data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
  93. data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
  94. data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
  95. data/lib/konpeito/ui/chart/line_chart.rb +289 -0
  96. data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
  97. data/lib/konpeito/ui/chart/scales.rb +77 -0
  98. data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
  99. data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
  100. data/lib/konpeito/ui/column.rb +271 -0
  101. data/lib/konpeito/ui/core.rb +2199 -0
  102. data/lib/konpeito/ui/dsl.rb +443 -0
  103. data/lib/konpeito/ui/frame.rb +171 -0
  104. data/lib/konpeito/ui/frame_native.rb +494 -0
  105. data/lib/konpeito/ui/markdown/ast.rb +124 -0
  106. data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
  107. data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
  108. data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
  109. data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
  110. data/lib/konpeito/ui/markdown/parser.rb +805 -0
  111. data/lib/konpeito/ui/markdown/renderer.rb +639 -0
  112. data/lib/konpeito/ui/markdown/theme.rb +165 -0
  113. data/lib/konpeito/ui/render_node.rb +260 -0
  114. data/lib/konpeito/ui/row.rb +207 -0
  115. data/lib/konpeito/ui/spacer.rb +18 -0
  116. data/lib/konpeito/ui/style.rb +799 -0
  117. data/lib/konpeito/ui/theme.rb +563 -0
  118. data/lib/konpeito/ui/themes/material.rb +35 -0
  119. data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
  120. data/lib/konpeito/ui/widgets/button.rb +103 -0
  121. data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
  122. data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
  123. data/lib/konpeito/ui/widgets/container.rb +91 -0
  124. data/lib/konpeito/ui/widgets/data_table.rb +667 -0
  125. data/lib/konpeito/ui/widgets/divider.rb +29 -0
  126. data/lib/konpeito/ui/widgets/image.rb +105 -0
  127. data/lib/konpeito/ui/widgets/input.rb +485 -0
  128. data/lib/konpeito/ui/widgets/markdown.rb +57 -0
  129. data/lib/konpeito/ui/widgets/modal.rb +163 -0
  130. data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
  131. data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
  132. data/lib/konpeito/ui/widgets/net_image.rb +100 -0
  133. data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
  134. data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
  135. data/lib/konpeito/ui/widgets/slider.rb +133 -0
  136. data/lib/konpeito/ui/widgets/switch.rb +84 -0
  137. data/lib/konpeito/ui/widgets/tabs.rb +157 -0
  138. data/lib/konpeito/ui/widgets/text.rb +110 -0
  139. data/lib/konpeito/ui/widgets/tree.rb +426 -0
  140. data/lib/konpeito/version.rb +5 -0
  141. data/lib/konpeito.rb +109 -0
  142. data/test_native_array.rb +172 -0
  143. data/test_native_array_class.rb +197 -0
  144. data/test_native_class.rb +151 -0
  145. data/tools/konpeito-asm/build.sh +65 -0
  146. data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
  147. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
  148. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
  149. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
  150. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
  151. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
  152. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
  153. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
  154. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
  155. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
  156. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
  157. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
  158. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
  159. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
  160. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
  161. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
  162. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
  163. data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
  164. data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
  165. data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
  166. data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
  167. data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
  168. data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
  169. data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
  170. data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
  171. data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
  172. data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
  173. data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
  174. data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
  175. data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
  176. data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
  177. data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
  178. data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
  179. data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
  180. metadata +267 -0
@@ -0,0 +1,165 @@
1
+ # Markdown theme - color and size tokens for markdown rendering
2
+ # Integrates with the global $theme
3
+
4
+ class MarkdownTheme
5
+ def initialize
6
+ # Text colors - derive from global theme
7
+ @text_color = $theme.text_primary
8
+ @heading_color = $theme.accent
9
+ @link_color = $theme.accent
10
+ @code_color = $theme.warning
11
+ @emphasis_color = 0xFF9AA5CE # Slightly muted blue for italic
12
+ @strikethrough_color = $theme.text_secondary
13
+
14
+ # Background colors
15
+ @code_bg_color = $theme.bg_secondary
16
+ @code_inline_bg = $theme.bg_secondary
17
+ @blockquote_bg = $theme.accent
18
+
19
+ # Heading sizes
20
+ @h1_size = 28.0
21
+ @h2_size = 24.0
22
+ @h3_size = 20.0
23
+ @h4_size = 18.0
24
+ @h5_size = 16.0
25
+ @h6_size = 14.0
26
+ @base_font_size = 14.0
27
+
28
+ # Table colors
29
+ @table_header_bg = $theme.bg_secondary
30
+ @table_border_color = $theme.text_secondary
31
+ @checkbox_checked_color = $theme.success
32
+ @checkbox_unchecked_color = $theme.text_secondary
33
+
34
+ # Mermaid colors
35
+ @mermaid_node_fill = 0xFF4A90D9
36
+ @mermaid_node_stroke = 0xFF2C5F8A
37
+ @mermaid_node_text = 0xFFFFFFFF
38
+ @mermaid_edge_color = $theme.text_secondary
39
+ @mermaid_subgraph_bg = 0x20FFFFFF
40
+ @mermaid_subgraph_border = $theme.text_secondary
41
+ @mermaid_font_size = 12.0
42
+
43
+ # Spacing
44
+ @paragraph_spacing = 8.0
45
+ @block_spacing = 12.0
46
+ @list_indent = 24.0
47
+ @blockquote_indent = 20.0
48
+ end
49
+
50
+ def text_color
51
+ @text_color
52
+ end
53
+
54
+ def heading_color
55
+ @heading_color
56
+ end
57
+
58
+ def link_color
59
+ @link_color
60
+ end
61
+
62
+ def code_color
63
+ @code_color
64
+ end
65
+
66
+ def emphasis_color
67
+ @emphasis_color
68
+ end
69
+
70
+ def strikethrough_color
71
+ @strikethrough_color
72
+ end
73
+
74
+ def code_bg_color
75
+ @code_bg_color
76
+ end
77
+
78
+ def code_inline_bg
79
+ @code_inline_bg
80
+ end
81
+
82
+ def blockquote_bg
83
+ @blockquote_bg
84
+ end
85
+
86
+ def base_font_size
87
+ @base_font_size
88
+ end
89
+
90
+ def paragraph_spacing
91
+ @paragraph_spacing
92
+ end
93
+
94
+ def block_spacing
95
+ @block_spacing
96
+ end
97
+
98
+ def list_indent
99
+ @list_indent
100
+ end
101
+
102
+ def blockquote_indent
103
+ @blockquote_indent
104
+ end
105
+
106
+ def table_header_bg
107
+ @table_header_bg
108
+ end
109
+
110
+ def table_border_color
111
+ @table_border_color
112
+ end
113
+
114
+ def checkbox_checked_color
115
+ @checkbox_checked_color
116
+ end
117
+
118
+ def checkbox_unchecked_color
119
+ @checkbox_unchecked_color
120
+ end
121
+
122
+ def mermaid_node_fill
123
+ @mermaid_node_fill
124
+ end
125
+
126
+ def mermaid_node_stroke
127
+ @mermaid_node_stroke
128
+ end
129
+
130
+ def mermaid_node_text
131
+ @mermaid_node_text
132
+ end
133
+
134
+ def mermaid_edge_color
135
+ @mermaid_edge_color
136
+ end
137
+
138
+ def mermaid_subgraph_bg
139
+ @mermaid_subgraph_bg
140
+ end
141
+
142
+ def mermaid_subgraph_border
143
+ @mermaid_subgraph_border
144
+ end
145
+
146
+ def mermaid_font_size
147
+ @mermaid_font_size
148
+ end
149
+
150
+ def heading_size(level)
151
+ if level == 1
152
+ @h1_size
153
+ elsif level == 2
154
+ @h2_size
155
+ elsif level == 3
156
+ @h3_size
157
+ elsif level == 4
158
+ @h4_size
159
+ elsif level == 5
160
+ @h5_size
161
+ else
162
+ @h6_size
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,260 @@
1
+ # rbs_inline: enabled
2
+
3
+ # RenderNode system - layout/paint dirty tracking and z-order caching
4
+ # Port of ~/castella/castella/render/node.py and layout_node.py
5
+
6
+ # Base render node with fine-grained dirty tracking
7
+ class RenderNodeBase
8
+ #: (untyped widget) -> void
9
+ def initialize(widget)
10
+ @widget = widget
11
+ @layout_dirty = true
12
+ @paint_dirty = true
13
+ @subtree_dirty = false
14
+ @measured_size = nil
15
+ end
16
+
17
+ #: () -> untyped
18
+ def get_widget
19
+ @widget
20
+ end
21
+
22
+ # ===== Dirty Tracking =====
23
+
24
+ #: () -> bool
25
+ def is_layout_dirty
26
+ @layout_dirty
27
+ end
28
+
29
+ #: () -> bool
30
+ def is_paint_dirty
31
+ @paint_dirty
32
+ end
33
+
34
+ #: () -> void
35
+ def mark_layout_dirty
36
+ @layout_dirty = true
37
+ @paint_dirty = true
38
+ @measured_size = nil
39
+ end
40
+
41
+ #: () -> void
42
+ def mark_paint_dirty
43
+ @paint_dirty = true
44
+ end
45
+
46
+ #: () -> bool
47
+ def is_subtree_dirty
48
+ @subtree_dirty
49
+ end
50
+
51
+ #: () -> void
52
+ def mark_subtree_dirty
53
+ @subtree_dirty = true
54
+ end
55
+
56
+ #: () -> void
57
+ def clear_dirty
58
+ @layout_dirty = false
59
+ @paint_dirty = false
60
+ @subtree_dirty = false
61
+ end
62
+
63
+ # ===== Layout =====
64
+
65
+ #: (untyped painter) -> Size
66
+ def cached_measure(painter)
67
+ if @measured_size == nil || @layout_dirty
68
+ @measured_size = @widget.measure(painter)
69
+ end
70
+ @measured_size
71
+ end
72
+
73
+ # ===== Hit Testing =====
74
+
75
+ #: (Point point) -> bool
76
+ def hit_test(point)
77
+ @widget.contain(point)
78
+ end
79
+ end
80
+
81
+ # Layout render node with z-order caching and child management
82
+ class LayoutRenderNode < RenderNodeBase
83
+ #: (untyped widget) -> void
84
+ def initialize(widget)
85
+ super(widget)
86
+ @children = []
87
+ @sorted_children = nil
88
+ @z_order_dirty = true
89
+ end
90
+
91
+ # ===== Child Management =====
92
+
93
+ #: (untyped child) -> void
94
+ def add_child(child)
95
+ @children << child
96
+ @z_order_dirty = true
97
+ mark_layout_dirty
98
+ end
99
+
100
+ #: (untyped child) -> void
101
+ def remove_child(child)
102
+ i = 0
103
+ while i < @children.length
104
+ if @children[i] == child
105
+ @children.delete_at(i)
106
+ @z_order_dirty = true
107
+ mark_layout_dirty
108
+ return
109
+ end
110
+ i = i + 1
111
+ end
112
+ end
113
+
114
+ #: () -> void
115
+ def clear_children
116
+ @children = []
117
+ @sorted_children = nil
118
+ @z_order_dirty = true
119
+ mark_layout_dirty
120
+ end
121
+
122
+ #: () -> Integer
123
+ def child_count
124
+ @children.length
125
+ end
126
+
127
+ #: () -> Array
128
+ def get_children
129
+ @children
130
+ end
131
+
132
+ # ===== Z-Order Management =====
133
+
134
+ #: () -> void
135
+ def invalidate_z_order
136
+ @z_order_dirty = true
137
+ @sorted_children = nil
138
+ end
139
+
140
+ #: () -> Array
141
+ def get_sorted_children
142
+ if @z_order_dirty || @sorted_children == nil
143
+ # Copy children list
144
+ @sorted_children = []
145
+ i = 0
146
+ while i < @children.length
147
+ @sorted_children << @children[i]
148
+ i = i + 1
149
+ end
150
+ # Sort by z_index (bubble sort - children count is typically small)
151
+ changed = true
152
+ while changed
153
+ changed = false
154
+ j = 0
155
+ while j < @sorted_children.length - 1
156
+ if @sorted_children[j].get_z_index > @sorted_children[j + 1].get_z_index
157
+ tmp = @sorted_children[j]
158
+ @sorted_children[j] = @sorted_children[j + 1]
159
+ @sorted_children[j + 1] = tmp
160
+ changed = true
161
+ end
162
+ j = j + 1
163
+ end
164
+ end
165
+ @z_order_dirty = false
166
+ end
167
+ @sorted_children
168
+ end
169
+
170
+ # Paint order: lower z-index first (background to foreground)
171
+ #: () -> Array
172
+ def iter_paint_order
173
+ get_sorted_children
174
+ end
175
+
176
+ # Hit test order: higher z-index first (foreground to background)
177
+ #: () -> Array
178
+ def iter_hit_test_order
179
+ sorted = get_sorted_children
180
+ result = []
181
+ i = sorted.length - 1
182
+ while i >= 0
183
+ result << sorted[i]
184
+ i = i - 1
185
+ end
186
+ result
187
+ end
188
+
189
+ # ===== Dirty Propagation =====
190
+
191
+ #: () -> bool
192
+ def is_any_child_dirty
193
+ i = 0
194
+ while i < @children.length
195
+ if @children[i].is_dirty
196
+ return true
197
+ end
198
+ i = i + 1
199
+ end
200
+ false
201
+ end
202
+ end
203
+
204
+ # Scrollable layout render node with viewport culling
205
+ class ScrollableLayoutRenderNode < LayoutRenderNode
206
+ #: (untyped widget) -> void
207
+ def initialize(widget)
208
+ super(widget)
209
+ @scroll_x = 0.0
210
+ @scroll_y = 0.0
211
+ @viewport_width = 0.0
212
+ @viewport_height = 0.0
213
+ @viewport_set = false
214
+ end
215
+
216
+ #: () -> Float
217
+ def get_scroll_x
218
+ @scroll_x
219
+ end
220
+
221
+ #: (Float v) -> void
222
+ def set_scroll_x(v)
223
+ if @scroll_x != v
224
+ @scroll_x = v
225
+ mark_paint_dirty
226
+ end
227
+ end
228
+
229
+ #: () -> Float
230
+ def get_scroll_y
231
+ @scroll_y
232
+ end
233
+
234
+ #: (Float v) -> void
235
+ def set_scroll_y(v)
236
+ if @scroll_y != v
237
+ @scroll_y = v
238
+ mark_paint_dirty
239
+ end
240
+ end
241
+
242
+ #: (Float w, Float h) -> void
243
+ def set_viewport_size(w, h)
244
+ @viewport_width = w
245
+ @viewport_height = h
246
+ @viewport_set = true
247
+ end
248
+
249
+ #: (untyped child) -> bool
250
+ def is_child_visible(child)
251
+ if !@viewport_set
252
+ return true
253
+ end
254
+ cx = child.get_x - @scroll_x
255
+ cy = child.get_y - @scroll_y
256
+ cw = child.get_width
257
+ ch = child.get_height
258
+ !(cx + cw < 0.0 || cx > @viewport_width || cy + ch < 0.0 || cy > @viewport_height)
259
+ end
260
+ end
@@ -0,0 +1,207 @@
1
+ # rbs_inline: enabled
2
+
3
+ # Row layout - horizontal arrangement of children
4
+ # Port of Castella LinearLayout (horizontal axis)
5
+
6
+ class Row < Layout
7
+ def initialize
8
+ super
9
+ @spacing = 0.0
10
+ @is_scrollable = false
11
+ @scroll_offset = 0.0
12
+ @content_width = 0.0
13
+ @pin_right = false
14
+ end
15
+
16
+ #: (Float s) -> Row
17
+ def spacing(s)
18
+ @spacing = s
19
+ self
20
+ end
21
+
22
+ #: () -> Row
23
+ def scrollable
24
+ @is_scrollable = true
25
+ self
26
+ end
27
+
28
+ #: () -> Row
29
+ def pin_to_end
30
+ @pin_right = true
31
+ self
32
+ end
33
+
34
+ #: () -> bool
35
+ def is_scrollable
36
+ @is_scrollable
37
+ end
38
+
39
+ #: (bool is_direction_x) -> bool
40
+ def has_scrollbar(is_direction_x)
41
+ if is_direction_x
42
+ @is_scrollable
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ #: () -> Float
49
+ def get_scroll_offset
50
+ @scroll_offset
51
+ end
52
+
53
+ #: (Float v) -> void
54
+ def set_scroll_offset(v)
55
+ @scroll_offset = v
56
+ mark_dirty
57
+ update
58
+ end
59
+
60
+ #: (untyped painter) -> Size
61
+ def measure(painter)
62
+ total_w = 0.0
63
+ max_h = 0.0
64
+ i = 0
65
+ while i < @children.length
66
+ cs = @children[i].measure(painter)
67
+ total_w = total_w + cs.width
68
+ total_w = total_w + @spacing if i > 0
69
+ max_h = cs.height if cs.height > max_h
70
+ i = i + 1
71
+ end
72
+ Size.new(total_w, max_h)
73
+ end
74
+
75
+ #: (untyped painter) -> void
76
+ def relocate_children(painter)
77
+ remaining = @width
78
+ expanding_total_flex = 0
79
+
80
+ # First pass: measure FIXED/CONTENT children, collect EXPANDING
81
+ i = 0
82
+ while i < @children.length
83
+ c = @children[i]
84
+ if c.get_width_policy != EXPANDING
85
+ # Set height before measure so height-dependent layouts work
86
+ if c.get_height_policy == EXPANDING
87
+ c.resize_wh(c.get_width, @height)
88
+ end
89
+ cs = c.measure(painter)
90
+ c.resize_wh(cs.width, @height)
91
+ remaining = remaining - cs.width
92
+ else
93
+ expanding_total_flex = expanding_total_flex + c.get_flex
94
+ end
95
+ remaining = remaining - @spacing if i > 0
96
+ i = i + 1
97
+ end
98
+
99
+ if remaining < 0.0
100
+ remaining = 0.0
101
+ end
102
+
103
+ # Second pass: distribute remaining space, position all
104
+ cx = @x
105
+ if @is_scrollable
106
+ cx = cx - @scroll_offset
107
+ end
108
+ total_content_w = 0.0
109
+ i = 0
110
+ while i < @children.length
111
+ c = @children[i]
112
+ if c.get_width_policy == EXPANDING
113
+ w = 0.0
114
+ if expanding_total_flex > 0 && remaining > 0.0
115
+ w = remaining * c.get_flex / expanding_total_flex
116
+ end
117
+ c.resize_wh(w, @height)
118
+ else
119
+ if c.get_height_policy == EXPANDING
120
+ c.resize_wh(c.get_width, @height)
121
+ end
122
+ end
123
+ c.move_xy(cx, @y)
124
+ cx = cx + c.get_width + @spacing
125
+ total_content_w = total_content_w + c.get_width
126
+ total_content_w = total_content_w + @spacing if i > 0
127
+ i = i + 1
128
+ end
129
+ @content_width = total_content_w
130
+
131
+ # Auto-scroll to end when pinned
132
+ if @pin_right && @is_scrollable
133
+ max_scroll = @content_width - @width
134
+ if max_scroll > 0.0
135
+ @scroll_offset = max_scroll
136
+ end
137
+ end
138
+ end
139
+
140
+ #: (untyped painter, bool completely) -> void
141
+ def redraw(painter, completely)
142
+ relocate_children(painter)
143
+ redraw_children(painter, completely)
144
+ draw_scrollbar(painter) if @is_scrollable
145
+ end
146
+
147
+ #: (untyped painter) -> void
148
+ def draw_scrollbar(painter)
149
+ viewport_w = @width
150
+ content_w = @content_width
151
+ return if content_w <= viewport_w
152
+
153
+ bar_height = 8.0
154
+ thumb_color = 0xC0AAAAAA
155
+
156
+ # Thumb
157
+ thumb_w = viewport_w * viewport_w / content_w
158
+ if thumb_w < 20.0
159
+ thumb_w = 20.0
160
+ end
161
+ thumb_x = (@scroll_offset / content_w) * viewport_w
162
+ if thumb_x + thumb_w > viewport_w
163
+ thumb_x = viewport_w - thumb_w
164
+ end
165
+ painter.fill_round_rect(thumb_x, @height - bar_height + 2.0, thumb_w, bar_height - 4.0, 2.0, thumb_color)
166
+ end
167
+
168
+ #: (WheelEvent ev) -> void
169
+ def mouse_wheel(ev)
170
+ if @is_scrollable
171
+ scroll_speed = 30.0
172
+ @scroll_offset = @scroll_offset - ev.delta_y * scroll_speed
173
+ # Clamp scroll offset
174
+ max_scroll = @content_width - @width
175
+ if max_scroll < 0.0
176
+ max_scroll = 0.0
177
+ end
178
+ if @scroll_offset < 0.0
179
+ @scroll_offset = 0.0
180
+ end
181
+ if @scroll_offset > max_scroll
182
+ @scroll_offset = max_scroll
183
+ end
184
+ # Toggle pin_to_end: disable on scroll left, re-enable at end
185
+ if ev.delta_y > 0.0
186
+ @pin_right = false
187
+ end
188
+ if max_scroll > 0.0 && @scroll_offset >= max_scroll
189
+ @pin_right = true
190
+ end
191
+ mark_dirty
192
+ update
193
+ end
194
+ end
195
+ end
196
+
197
+ # Top-level helper
198
+ #: (*untyped children) -> Row
199
+ def Row(*children)
200
+ row = Row.new
201
+ i = 0
202
+ while i < children.length
203
+ row.add(children[i])
204
+ i = i + 1
205
+ end
206
+ row
207
+ end
@@ -0,0 +1,18 @@
1
+ # rbs_inline: enabled
2
+
3
+ # Spacer - flexible space widget
4
+ # Port of Castella Spacer
5
+
6
+ class Spacer < Widget
7
+ def initialize
8
+ super
9
+ @width_policy = EXPANDING
10
+ @height_policy = EXPANDING
11
+ end
12
+ end
13
+
14
+ # Top-level helper
15
+ #: () -> Spacer
16
+ def Spacer()
17
+ Spacer.new
18
+ end