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,289 @@
1
+ # LineChart - line chart with point markers
2
+ # Supports multiple series, grid, hover detection
3
+
4
+ class LineChart < BaseChart
5
+ def initialize(x_labels, series_data, series_names)
6
+ super()
7
+ @x_labels = x_labels
8
+ @series_data = series_data
9
+ @series_names = series_names
10
+ @show_points = true
11
+ @point_radius = 4.0
12
+ @line_width = 2.0
13
+ @show_grid = true
14
+ @data_min = 0.0
15
+ @data_max = 0.0
16
+ # Computed per-frame
17
+ @y_scale = nil
18
+ @y_ticks = nil
19
+ @x_step = 0.0
20
+ @num_points = 0
21
+ @num_series = 0
22
+ @y_range_min = 0.0
23
+ @y_range_max = 1.0
24
+ @chart_px = 0.0
25
+ @chart_py = 0.0
26
+ @chart_pw = 0.0
27
+ @chart_ph = 0.0
28
+ compute_data_range
29
+ end
30
+
31
+ def show_points(v)
32
+ @show_points = v
33
+ self
34
+ end
35
+
36
+ def point_radius(r)
37
+ @point_radius = r
38
+ self
39
+ end
40
+
41
+ def line_width(w)
42
+ @line_width = w
43
+ self
44
+ end
45
+
46
+ def show_grid(v)
47
+ @show_grid = v
48
+ self
49
+ end
50
+
51
+ def set_data(x_labels, series_data, series_names)
52
+ @x_labels = x_labels
53
+ @series_data = series_data
54
+ @series_names = series_names
55
+ compute_data_range
56
+ mark_dirty
57
+ update
58
+ end
59
+
60
+ def render_chart(painter, px, py, pw, ph)
61
+ return if @x_labels.length == 0
62
+ return if @series_data.length == 0
63
+ @chart_px = px
64
+ @chart_py = py
65
+ @chart_pw = pw
66
+ @chart_ph = ph
67
+ setup_line_counts
68
+ setup_line_ticks
69
+ setup_line_y_scale
70
+ setup_line_x_step
71
+ draw_y_axis(painter, px, py, pw, ph, @y_ticks, @y_scale)
72
+ draw_x_axis_line(painter, px, py, pw, ph)
73
+ draw_x_labels(painter)
74
+ draw_hover_line(painter)
75
+ draw_all_series(painter)
76
+ draw_line_legend(painter, px, py)
77
+ end
78
+
79
+ def setup_line_counts
80
+ @num_points = @x_labels.length
81
+ @num_series = @series_data.length
82
+ end
83
+
84
+ def setup_line_ticks
85
+ @y_ticks = compute_ticks(@data_min, @data_max, 5)
86
+ @y_range_min = @data_min
87
+ @y_range_max = @data_max
88
+ if @y_ticks.length > 0
89
+ @y_range_min = @y_ticks[0]
90
+ @y_range_max = @y_ticks[@y_ticks.length - 1]
91
+ end
92
+ end
93
+
94
+ def setup_line_y_scale
95
+ bottom = @chart_py + @chart_ph
96
+ @y_scale = LinearScale.new(@y_range_min, @y_range_max, bottom, @chart_py)
97
+ end
98
+
99
+ def setup_line_x_step
100
+ @x_step = 0.0
101
+ if @num_points > 1
102
+ divisor = (@num_points - 1) * 1.0
103
+ @x_step = @chart_pw / divisor
104
+ end
105
+ end
106
+
107
+ def draw_x_labels(painter)
108
+ lc = $theme.text_secondary
109
+ i = 0
110
+ while i < @num_points
111
+ draw_one_x_label(painter, i, lc)
112
+ i = i + 1
113
+ end
114
+ end
115
+
116
+ def draw_one_x_label(painter, i, lc)
117
+ i_f = i * 1.0
118
+ xx = @chart_px + i_f * @x_step
119
+ label = @x_labels[i]
120
+ lw = painter.measure_text_width(label, $theme.font_family, 11.0)
121
+ ascent = painter.get_text_ascent($theme.font_family, 11.0)
122
+ label_y = @chart_py + @chart_ph + 14.0 + ascent
123
+ painter.draw_text(label, xx - lw / 2.0, label_y, $theme.font_family, 11.0, lc)
124
+ end
125
+
126
+ def draw_hover_line(painter)
127
+ if @hover_index >= 0
128
+ if @hover_index < @num_points
129
+ hi_f = @hover_index * 1.0
130
+ hx = @chart_px + hi_f * @x_step
131
+ hc = painter.with_alpha($theme.accent, 80)
132
+ bottom = @chart_py + @chart_ph
133
+ painter.draw_line(hx, @chart_py, hx, bottom, hc, 1.0)
134
+ end
135
+ end
136
+ end
137
+
138
+ def draw_all_series(painter)
139
+ si = 0
140
+ while si < @num_series
141
+ c = series_color(si)
142
+ data = @series_data[si]
143
+ draw_series_lines(painter, data, c)
144
+ if @show_points
145
+ draw_series_points(painter, data, c)
146
+ end
147
+ si = si + 1
148
+ end
149
+ end
150
+
151
+ def draw_series_lines(painter, data, c)
152
+ j = 0
153
+ while j < @num_points - 1
154
+ j_f = j * 1.0
155
+ x1 = @chart_px + j_f * @x_step
156
+ y1 = @y_scale.map(data[j])
157
+ j1_f = (j + 1) * 1.0
158
+ x2 = @chart_px + j1_f * @x_step
159
+ y2 = @y_scale.map(data[j + 1])
160
+ painter.draw_line(x1, y1, x2, y2, c, @line_width)
161
+ j = j + 1
162
+ end
163
+ end
164
+
165
+ def draw_series_points(painter, data, c)
166
+ j = 0
167
+ while j < @num_points
168
+ draw_one_point(painter, data, j, c)
169
+ j = j + 1
170
+ end
171
+ end
172
+
173
+ def draw_one_point(painter, data, j, c)
174
+ j_f = j * 1.0
175
+ xx = @chart_px + j_f * @x_step
176
+ yy = @y_scale.map(data[j])
177
+ r = @point_radius
178
+ if @hover_index == j
179
+ r = @point_radius + 2.0
180
+ end
181
+ painter.fill_circle(xx, yy, r, c)
182
+ if @hover_index == j
183
+ draw_point_label(painter, data[j], xx, yy, r)
184
+ end
185
+ end
186
+
187
+ def draw_point_label(painter, val, xx, yy, r)
188
+ vl = format_axis_value(painter, val)
189
+ vw = painter.measure_text_width(vl, $theme.font_family, 10.0)
190
+ tc = $theme.text_primary
191
+ painter.draw_text(vl, xx - vw / 2.0, yy - r - 4.0, $theme.font_family, 10.0, tc)
192
+ end
193
+
194
+ def draw_line_legend(painter, px, py)
195
+ if @show_legend
196
+ if @series_names.length > 1
197
+ colors = []
198
+ si = 0
199
+ while si < @series_names.length
200
+ colors << series_color(si)
201
+ si = si + 1
202
+ end
203
+ draw_legend(painter, @series_names, colors, px + 8.0, py - 20.0)
204
+ end
205
+ end
206
+ end
207
+
208
+ def update_hover
209
+ return if @y_scale == nil
210
+ if @num_points <= 1
211
+ @hover_index = -1
212
+ return
213
+ end
214
+ mx = @mouse_x
215
+ px = plot_x
216
+ pw = plot_w
217
+ left_bound = px - @x_step / 2.0
218
+ right_bound = px + pw + @x_step / 2.0
219
+ if mx < left_bound
220
+ @hover_index = -1
221
+ return
222
+ end
223
+ if mx > right_bound
224
+ @hover_index = -1
225
+ return
226
+ end
227
+ find_nearest_point(mx, px)
228
+ end
229
+
230
+ def find_nearest_point(mx, px)
231
+ best = -1
232
+ best_dist = 999999.0
233
+ i = 0
234
+ while i < @num_points
235
+ i_f = i * 1.0
236
+ xx = px + i_f * @x_step
237
+ d = mx - xx
238
+ if d < 0.0
239
+ d = 0.0 - d
240
+ end
241
+ if d < best_dist
242
+ best_dist = d
243
+ best = i
244
+ end
245
+ i = i + 1
246
+ end
247
+ @hover_index = best
248
+ end
249
+
250
+ private
251
+
252
+ def compute_data_range
253
+ @data_min = 0.0
254
+ @data_max = 1.0
255
+ first = true
256
+ si = 0
257
+ while si < @series_data.length
258
+ ci = 0
259
+ while ci < @series_data[si].length
260
+ v = @series_data[si][ci]
261
+ if first
262
+ @data_min = v
263
+ @data_max = v
264
+ first = false
265
+ else
266
+ if v > @data_max
267
+ @data_max = v
268
+ end
269
+ if v < @data_min
270
+ @data_min = v
271
+ end
272
+ end
273
+ ci = ci + 1
274
+ end
275
+ si = si + 1
276
+ end
277
+ range = @data_max - @data_min
278
+ if range > 0.0
279
+ @data_max = @data_max + range * 0.1
280
+ @data_min = @data_min - range * 0.05
281
+ else
282
+ @data_max = @data_max + 1.0
283
+ end
284
+ end
285
+ end
286
+
287
+ def LineChart(x_labels, series_data, series_names)
288
+ LineChart.new(x_labels, series_data, series_names)
289
+ end
@@ -0,0 +1,219 @@
1
+ # PieChart - pie/donut chart widget
2
+ # Supports slice labels, percentages, hover, donut mode
3
+
4
+ PIE_PI = 3.14159265358979323846
5
+
6
+ class PieChart < BaseChart
7
+ def initialize(labels, values)
8
+ super()
9
+ @labels = labels
10
+ @values = values
11
+ @donut = false
12
+ @donut_ratio = 0.5
13
+ @show_pct = true
14
+ @show_labels = true
15
+ @start_angle = -90.0
16
+ # Computed per-frame
17
+ @cx = 0.0
18
+ @cy = 0.0
19
+ @radius = 20.0
20
+ @total = 0.0
21
+ end
22
+
23
+ def donut(v)
24
+ @donut = v
25
+ self
26
+ end
27
+
28
+ def donut_ratio(r)
29
+ @donut_ratio = r
30
+ self
31
+ end
32
+
33
+ def show_percentages(v)
34
+ @show_pct = v
35
+ self
36
+ end
37
+
38
+ def show_labels(v)
39
+ @show_labels = v
40
+ self
41
+ end
42
+
43
+ def start_angle(a)
44
+ @start_angle = a
45
+ self
46
+ end
47
+
48
+ def set_data(labels, values)
49
+ @labels = labels
50
+ @values = values
51
+ mark_dirty
52
+ update
53
+ end
54
+
55
+ def render_chart(painter, px, py, pw, ph)
56
+ return if @labels.length == 0
57
+ setup_pie(px, py, pw, ph)
58
+ return if @total <= 0.0
59
+ draw_slices(painter)
60
+ draw_donut_hole(painter)
61
+ draw_pie_legend(painter, px)
62
+ end
63
+
64
+ def setup_pie(px, py, pw, ph)
65
+ @total = compute_total
66
+ chart_size = pw
67
+ if ph < pw
68
+ chart_size = ph
69
+ end
70
+ @radius = chart_size / 2.0 - 10.0
71
+ if @radius < 20.0
72
+ @radius = 20.0
73
+ end
74
+ @cx = px + pw / 2.0
75
+ @cy = py + ph / 2.0
76
+ end
77
+
78
+ def compute_total
79
+ total = 0.0
80
+ i = 0
81
+ while i < @values.length
82
+ total = total + @values[i]
83
+ i = i + 1
84
+ end
85
+ total
86
+ end
87
+
88
+ def draw_slices(painter)
89
+ angle = @start_angle
90
+ i = 0
91
+ while i < @values.length
92
+ angle = draw_one_slice(painter, i, angle)
93
+ i = i + 1
94
+ end
95
+ end
96
+
97
+ def draw_one_slice(painter, i, angle)
98
+ fraction = @values[i] / @total
99
+ sweep = fraction * 360.0
100
+ c = series_color(i)
101
+ if @hover_index == i
102
+ c = painter.lighten_color(c, 0.3)
103
+ end
104
+ painter.fill_arc(@cx, @cy, @radius, angle, sweep, c)
105
+ if @show_pct
106
+ if fraction >= 0.03
107
+ draw_slice_label(painter, angle, sweep, fraction)
108
+ end
109
+ end
110
+ angle + sweep
111
+ end
112
+
113
+ def draw_slice_label(painter, angle, sweep, fraction)
114
+ mid_angle = angle + sweep / 2.0
115
+ rad = mid_angle * PIE_PI / 180.0
116
+ label_r = compute_label_radius
117
+ lx = @cx + label_r * painter.math_cos(rad)
118
+ ly = @cy + label_r * painter.math_sin(rad)
119
+ pct_val = fraction * 100.0
120
+ pct = painter.number_to_string(pct_val) + "%"
121
+ pw2 = painter.measure_text_width(pct, $theme.font_family, 11.0)
122
+ ascent = painter.get_text_ascent($theme.font_family, 11.0)
123
+ painter.draw_text(pct, lx - pw2 / 2.0, ly + ascent / 2.0, $theme.font_family, 11.0, 4294967295)
124
+ end
125
+
126
+ def compute_label_radius
127
+ if @donut
128
+ @radius * (1.0 + @donut_ratio) / 2.0
129
+ else
130
+ @radius * 0.65
131
+ end
132
+ end
133
+
134
+ def draw_donut_hole(painter)
135
+ if @donut
136
+ inner_r = @radius * @donut_ratio
137
+ painter.fill_circle(@cx, @cy, inner_r, $theme.bg_primary)
138
+ end
139
+ end
140
+
141
+ def draw_pie_legend(painter, px)
142
+ if @show_legend
143
+ legend_y = @cy + @radius + 16.0
144
+ colors = []
145
+ i = 0
146
+ while i < @labels.length
147
+ colors << series_color(i)
148
+ i = i + 1
149
+ end
150
+ draw_legend(painter, @labels, colors, px + 8.0, legend_y)
151
+ end
152
+ end
153
+
154
+ def update_hover
155
+ return if @painter == nil
156
+ mx = @mouse_x
157
+ my = @mouse_y
158
+ dx = mx - @cx
159
+ dy = my - @cy
160
+ dist = @painter.math_sqrt(dx * dx + dy * dy)
161
+ if dist > @radius
162
+ @hover_index = -1
163
+ return
164
+ end
165
+ if @donut
166
+ inner = @radius * @donut_ratio
167
+ if dist < inner
168
+ @hover_index = -1
169
+ return
170
+ end
171
+ end
172
+ find_hover_slice(dx, dy)
173
+ end
174
+
175
+ def find_hover_slice(dx, dy)
176
+ angle_rad = @painter.math_atan2(dy, dx)
177
+ angle_deg = angle_rad * 180.0 / PIE_PI
178
+ relative = angle_deg - @start_angle
179
+ relative = normalize_angle(relative)
180
+ total = compute_total
181
+ if total <= 0.0
182
+ @hover_index = -1
183
+ return
184
+ end
185
+ find_slice_at_angle(relative, total)
186
+ end
187
+
188
+ def normalize_angle(a)
189
+ while a < 0.0
190
+ a = a + 360.0
191
+ end
192
+ while a >= 360.0
193
+ a = a - 360.0
194
+ end
195
+ a
196
+ end
197
+
198
+ def find_slice_at_angle(relative, total)
199
+ cumulative = 0.0
200
+ i = 0
201
+ while i < @values.length
202
+ fraction = @values[i] / total
203
+ sweep = fraction * 360.0
204
+ if relative >= cumulative
205
+ if relative < cumulative + sweep
206
+ @hover_index = i
207
+ return
208
+ end
209
+ end
210
+ cumulative = cumulative + sweep
211
+ i = i + 1
212
+ end
213
+ @hover_index = -1
214
+ end
215
+ end
216
+
217
+ def PieChart(labels, values)
218
+ PieChart.new(labels, values)
219
+ end
@@ -0,0 +1,77 @@
1
+ # Chart Scales - domain-to-pixel coordinate mapping
2
+ # Pure math classes, no UI dependency
3
+ # IMPORTANT: In constructors, use local params (not @field) to avoid JVM field type issues
4
+
5
+ class LinearScale
6
+ def initialize(domain_min, domain_max, range_min, range_max)
7
+ @domain_min = domain_min
8
+ @domain_max = domain_max
9
+ @range_min = range_min
10
+ @range_max = range_max
11
+ span = domain_max - domain_min
12
+ if span == 0.0
13
+ @factor = 0.0
14
+ else
15
+ @factor = (range_max - range_min) / span
16
+ end
17
+ end
18
+
19
+ def map(value)
20
+ @range_min + (value - @domain_min) * @factor
21
+ end
22
+
23
+ def domain_min
24
+ @domain_min
25
+ end
26
+
27
+ def domain_max
28
+ @domain_max
29
+ end
30
+
31
+ def range_min
32
+ @range_min
33
+ end
34
+
35
+ def range_max
36
+ @range_max
37
+ end
38
+ end
39
+
40
+ class BandScale
41
+ def initialize(count, range_min, range_max, padding)
42
+ @count = count
43
+ @range_min = range_min
44
+ @range_max = range_max
45
+ @padding = padding
46
+ total = range_max - range_min
47
+ @band_width = compute_band_width(count, total, padding)
48
+ end
49
+
50
+ def compute_band_width(count, total, padding)
51
+ if count > 0.0
52
+ slots = count + 1.0
53
+ pad_total = padding * slots
54
+ usable = total - pad_total
55
+ bw = usable / count
56
+ if bw < 1.0
57
+ bw = 1.0
58
+ end
59
+ bw
60
+ else
61
+ total
62
+ end
63
+ end
64
+
65
+ def map(index)
66
+ idx = index * 1.0
67
+ @range_min + @padding + idx * (@band_width + @padding)
68
+ end
69
+
70
+ def band_width
71
+ @band_width
72
+ end
73
+
74
+ def count
75
+ @count
76
+ end
77
+ end