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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# MultilineText widget - displays multiline text with optional word wrapping
|
|
2
|
+
# Port of Castella MultilineText
|
|
3
|
+
|
|
4
|
+
class MultilineText < Widget
|
|
5
|
+
def initialize(text)
|
|
6
|
+
super()
|
|
7
|
+
@text = text
|
|
8
|
+
@font_family = nil
|
|
9
|
+
@font_size_val = 14.0
|
|
10
|
+
@color_val = 0xFFC0CAF5
|
|
11
|
+
@custom_color = false
|
|
12
|
+
@kind_val = 0
|
|
13
|
+
@padding_val = 8.0
|
|
14
|
+
@line_spacing = 4.0
|
|
15
|
+
@wrap_enabled = false
|
|
16
|
+
@border_width_val = 1.0
|
|
17
|
+
@width_policy = EXPANDING
|
|
18
|
+
@height_policy = CONTENT
|
|
19
|
+
@cached_lines = []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def font_family(f)
|
|
23
|
+
@font_family = f
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def resolved_font_family
|
|
28
|
+
if @font_family != nil
|
|
29
|
+
@font_family
|
|
30
|
+
else
|
|
31
|
+
$theme.font_family
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def font_size(s)
|
|
36
|
+
@font_size_val = s
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def color(c)
|
|
41
|
+
@color_val = c
|
|
42
|
+
@custom_color = true
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def kind(k)
|
|
47
|
+
@kind_val = k
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def padding(p)
|
|
52
|
+
@padding_val = p
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def line_spacing(s)
|
|
57
|
+
@line_spacing = s
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def wrap_text(w)
|
|
62
|
+
@wrap_enabled = w
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def set_text(t)
|
|
67
|
+
@text = t
|
|
68
|
+
@cached_lines = []
|
|
69
|
+
mark_dirty
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def get_text
|
|
73
|
+
@text
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def measure(painter)
|
|
77
|
+
lines = split_lines(painter)
|
|
78
|
+
@cached_lines = lines
|
|
79
|
+
if lines.length == 0
|
|
80
|
+
return Size.new(@padding_val * 2.0, @padding_val * 2.0)
|
|
81
|
+
end
|
|
82
|
+
ff = resolved_font_family
|
|
83
|
+
max_w = 0.0
|
|
84
|
+
i = 0
|
|
85
|
+
while i < lines.length
|
|
86
|
+
lw = painter.measure_text_width(lines[i], ff, @font_size_val)
|
|
87
|
+
if lw > max_w
|
|
88
|
+
max_w = lw
|
|
89
|
+
end
|
|
90
|
+
i = i + 1
|
|
91
|
+
end
|
|
92
|
+
w = max_w + (@padding_val + @border_width_val) * 2.0
|
|
93
|
+
h = @font_size_val * lines.length + @line_spacing * (lines.length - 1) + @padding_val * 2.0 + @border_width_val * 2.0
|
|
94
|
+
Size.new(w, h)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def redraw(painter, completely)
|
|
98
|
+
lines = split_lines(painter)
|
|
99
|
+
@cached_lines = lines
|
|
100
|
+
|
|
101
|
+
# Background
|
|
102
|
+
bg_c = $theme.bg_primary
|
|
103
|
+
brd_c = $theme.border
|
|
104
|
+
painter.fill_rect(0.0, 0.0, @width, @height, bg_c)
|
|
105
|
+
painter.stroke_rect(0.0, 0.0, @width, @height, brd_c, @border_width_val)
|
|
106
|
+
|
|
107
|
+
# Text
|
|
108
|
+
ff = resolved_font_family
|
|
109
|
+
c = @custom_color ? @color_val : $theme.text_color_for_kind(@kind_val)
|
|
110
|
+
ascent = painter.get_text_ascent(ff, @font_size_val)
|
|
111
|
+
y = @padding_val + @border_width_val + ascent
|
|
112
|
+
i = 0
|
|
113
|
+
while i < lines.length
|
|
114
|
+
painter.draw_text(lines[i], @padding_val + @border_width_val, y, ff, @font_size_val, c)
|
|
115
|
+
y = y + @font_size_val + @line_spacing
|
|
116
|
+
i = i + 1
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def split_lines(painter)
|
|
121
|
+
raw_lines = @text.split("\n")
|
|
122
|
+
if !@wrap_enabled
|
|
123
|
+
return raw_lines
|
|
124
|
+
end
|
|
125
|
+
# Word wrapping
|
|
126
|
+
ff = resolved_font_family
|
|
127
|
+
line_width = @width - (@padding_val + @border_width_val) * 2.0
|
|
128
|
+
if line_width <= 0.0
|
|
129
|
+
return raw_lines
|
|
130
|
+
end
|
|
131
|
+
result = []
|
|
132
|
+
ri = 0
|
|
133
|
+
while ri < raw_lines.length
|
|
134
|
+
line = raw_lines[ri]
|
|
135
|
+
words = line.split(" ")
|
|
136
|
+
if words.length == 0
|
|
137
|
+
result.push("")
|
|
138
|
+
ri = ri + 1
|
|
139
|
+
next
|
|
140
|
+
end
|
|
141
|
+
current_words = []
|
|
142
|
+
current_width = 0.0
|
|
143
|
+
wi = 0
|
|
144
|
+
while wi < words.length
|
|
145
|
+
word = words[wi]
|
|
146
|
+
word_w = painter.measure_text_width(word, ff, @font_size_val)
|
|
147
|
+
space_w = 0.0
|
|
148
|
+
if current_words.length > 0
|
|
149
|
+
space_w = painter.measure_text_width(" ", ff, @font_size_val)
|
|
150
|
+
end
|
|
151
|
+
if current_width + space_w + word_w > line_width
|
|
152
|
+
if current_words.length > 0
|
|
153
|
+
result.push(current_words.join(" "))
|
|
154
|
+
current_words = [word]
|
|
155
|
+
current_width = word_w
|
|
156
|
+
else
|
|
157
|
+
# Single word wider than line - just include it
|
|
158
|
+
result.push(word)
|
|
159
|
+
current_words = []
|
|
160
|
+
current_width = 0.0
|
|
161
|
+
end
|
|
162
|
+
else
|
|
163
|
+
current_words.push(word)
|
|
164
|
+
current_width = current_width + space_w + word_w
|
|
165
|
+
end
|
|
166
|
+
wi = wi + 1
|
|
167
|
+
end
|
|
168
|
+
if current_words.length > 0
|
|
169
|
+
result.push(current_words.join(" "))
|
|
170
|
+
end
|
|
171
|
+
ri = ri + 1
|
|
172
|
+
end
|
|
173
|
+
result
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Top-level helper
|
|
178
|
+
def MultilineText(text)
|
|
179
|
+
MultilineText.new(text)
|
|
180
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# NetImage widget - displays an image from a network URL
|
|
2
|
+
# Port of Castella NetImage
|
|
3
|
+
|
|
4
|
+
class NetImageWidget < Widget
|
|
5
|
+
def initialize(url)
|
|
6
|
+
super()
|
|
7
|
+
@url = url
|
|
8
|
+
@image_id = 0
|
|
9
|
+
@img_width = 0.0
|
|
10
|
+
@img_height = 0.0
|
|
11
|
+
@fit_mode = IMAGE_FIT_CONTAIN
|
|
12
|
+
@width_policy = CONTENT
|
|
13
|
+
@height_policy = CONTENT
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fit(mode)
|
|
17
|
+
@fit_mode = mode
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def set_url(url)
|
|
22
|
+
@url = url
|
|
23
|
+
@image_id = 0
|
|
24
|
+
@img_width = 0.0
|
|
25
|
+
@img_height = 0.0
|
|
26
|
+
mark_dirty
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def load_if_needed(painter)
|
|
30
|
+
if @image_id == 0
|
|
31
|
+
@image_id = painter.load_net_image(@url)
|
|
32
|
+
if @image_id != 0
|
|
33
|
+
@img_width = painter.get_image_width(@image_id) * 1.0
|
|
34
|
+
@img_height = painter.get_image_height(@image_id) * 1.0
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def measure(painter)
|
|
40
|
+
load_if_needed(painter)
|
|
41
|
+
if @image_id != 0
|
|
42
|
+
Size.new(@img_width, @img_height)
|
|
43
|
+
else
|
|
44
|
+
Size.new(100.0, 100.0)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def redraw(painter, completely)
|
|
49
|
+
load_if_needed(painter)
|
|
50
|
+
if @image_id == 0
|
|
51
|
+
# Draw placeholder while loading or on error
|
|
52
|
+
painter.fill_round_rect(0.0, 0.0, @width, @height, 4.0, 0x40FFFFFF)
|
|
53
|
+
painter.stroke_round_rect(0.0, 0.0, @width, @height, 4.0, 0x80FFFFFF, 1.0)
|
|
54
|
+
return
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if @fit_mode == IMAGE_FIT_FILL
|
|
58
|
+
painter.draw_image(@image_id, 0.0, 0.0, @width, @height)
|
|
59
|
+
elsif @fit_mode == IMAGE_FIT_CONTAIN
|
|
60
|
+
draw_fitted(painter, true)
|
|
61
|
+
else
|
|
62
|
+
draw_fitted(painter, false)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def draw_fitted(painter, contain)
|
|
67
|
+
if @img_width < 1.0 || @img_height < 1.0 || @width < 1.0 || @height < 1.0
|
|
68
|
+
return
|
|
69
|
+
end
|
|
70
|
+
img_aspect = @img_width / @img_height
|
|
71
|
+
widget_aspect = @width / @height
|
|
72
|
+
|
|
73
|
+
if contain
|
|
74
|
+
if img_aspect > widget_aspect
|
|
75
|
+
new_w = @width
|
|
76
|
+
new_h = @width / img_aspect
|
|
77
|
+
else
|
|
78
|
+
new_h = @height
|
|
79
|
+
new_w = @height * img_aspect
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
if img_aspect > widget_aspect
|
|
83
|
+
new_h = @height
|
|
84
|
+
new_w = @height * img_aspect
|
|
85
|
+
else
|
|
86
|
+
new_w = @width
|
|
87
|
+
new_h = @width / img_aspect
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
dx = (@width - new_w) / 2.0
|
|
92
|
+
dy = (@height - new_h) / 2.0
|
|
93
|
+
painter.draw_image(@image_id, dx, dy, new_w, new_h)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Top-level helper
|
|
98
|
+
def NetImage(url)
|
|
99
|
+
NetImageWidget.new(url)
|
|
100
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# ProgressBar widget - progress indicator
|
|
2
|
+
# Port of Castella ProgressBar
|
|
3
|
+
|
|
4
|
+
class ProgressBar < Widget
|
|
5
|
+
def initialize
|
|
6
|
+
super()
|
|
7
|
+
@value = 0.0
|
|
8
|
+
@width_policy = EXPANDING
|
|
9
|
+
@height_policy = FIXED
|
|
10
|
+
@height = 8.0
|
|
11
|
+
# Colors (Tokyo Night)
|
|
12
|
+
@track_color = 0xFF414868
|
|
13
|
+
@fill_color = 0xFF7AA2F7
|
|
14
|
+
@radius = 4.0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def with_value(v)
|
|
18
|
+
if v < 0.0
|
|
19
|
+
@value = 0.0
|
|
20
|
+
elsif v > 1.0
|
|
21
|
+
@value = 1.0
|
|
22
|
+
else
|
|
23
|
+
@value = v
|
|
24
|
+
end
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set_value(v)
|
|
29
|
+
if v < 0.0
|
|
30
|
+
v = 0.0
|
|
31
|
+
end
|
|
32
|
+
if v > 1.0
|
|
33
|
+
v = 1.0
|
|
34
|
+
end
|
|
35
|
+
if v != @value
|
|
36
|
+
@value = v
|
|
37
|
+
mark_dirty
|
|
38
|
+
update
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_value
|
|
43
|
+
@value
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def fill_color(c)
|
|
47
|
+
@fill_color = c
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def measure(painter)
|
|
52
|
+
Size.new(200.0, 8.0)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def redraw(painter, completely)
|
|
56
|
+
# Track background
|
|
57
|
+
painter.fill_round_rect(0.0, 0.0, @width, @height, @radius, @track_color)
|
|
58
|
+
|
|
59
|
+
# Fill
|
|
60
|
+
fill_w = @width * @value
|
|
61
|
+
if fill_w > 0.0
|
|
62
|
+
painter.fill_round_rect(0.0, 0.0, fill_w, @height, @radius, @fill_color)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Top-level helper
|
|
68
|
+
def ProgressBar()
|
|
69
|
+
ProgressBar.new
|
|
70
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# RadioButtons widget - exclusive selection from a list
|
|
2
|
+
# Port of Castella RadioButtons
|
|
3
|
+
# Single widget that renders all options (avoids cross-class method calls)
|
|
4
|
+
|
|
5
|
+
class RadioButtons < Widget
|
|
6
|
+
def initialize(options)
|
|
7
|
+
super()
|
|
8
|
+
@options = options
|
|
9
|
+
@option_count = options.length
|
|
10
|
+
@selected = 0
|
|
11
|
+
@change_handler = nil
|
|
12
|
+
@hovered_index = -1
|
|
13
|
+
@width_policy = EXPANDING
|
|
14
|
+
@height_policy = CONTENT
|
|
15
|
+
# Colors (Tokyo Night)
|
|
16
|
+
@text_color = 0xFFC0CAF5
|
|
17
|
+
@ring_color = 0xFF565F89
|
|
18
|
+
@selected_color = 0xFF7AA2F7
|
|
19
|
+
@font_size_val = 14.0
|
|
20
|
+
@item_height = 32.0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def with_selected(index)
|
|
24
|
+
@selected = index
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def on_change(&block)
|
|
29
|
+
@change_handler = block
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_selected
|
|
34
|
+
@selected
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def measure(painter)
|
|
38
|
+
max_w = 0.0
|
|
39
|
+
i = 0
|
|
40
|
+
while i < @option_count
|
|
41
|
+
tw = painter.measure_text_width(@options[i], $theme.font_family, @font_size_val)
|
|
42
|
+
w = tw + 32.0
|
|
43
|
+
if w > max_w
|
|
44
|
+
max_w = w
|
|
45
|
+
end
|
|
46
|
+
i = i + 1
|
|
47
|
+
end
|
|
48
|
+
Size.new(max_w, @item_height * @option_count)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def redraw(painter, completely)
|
|
52
|
+
circle_r = 7.0
|
|
53
|
+
i = 0
|
|
54
|
+
while i < @option_count
|
|
55
|
+
iy = @item_height * i
|
|
56
|
+
cx = circle_r + 4.0
|
|
57
|
+
cy = iy + @item_height / 2.0
|
|
58
|
+
|
|
59
|
+
# Outer ring
|
|
60
|
+
painter.fill_circle(cx, cy, circle_r, @ring_color)
|
|
61
|
+
painter.fill_circle(cx, cy, circle_r - 1.5, 0xFF1A1B26)
|
|
62
|
+
|
|
63
|
+
# Selected dot
|
|
64
|
+
if @selected == i
|
|
65
|
+
painter.fill_circle(cx, cy, 4.0, @selected_color)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Label
|
|
69
|
+
ascent = painter.get_text_ascent($theme.font_family, @font_size_val)
|
|
70
|
+
text_x = cx + circle_r + 8.0
|
|
71
|
+
th = painter.measure_text_height($theme.font_family, @font_size_val)
|
|
72
|
+
text_y = iy + (@item_height - th) / 2.0 + ascent
|
|
73
|
+
painter.draw_text(@options[i], text_x, text_y, $theme.font_family, @font_size_val, @text_color)
|
|
74
|
+
|
|
75
|
+
i = i + 1
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def mouse_down(ev)
|
|
80
|
+
index = (ev.pos.y / @item_height).to_i
|
|
81
|
+
if index >= 0 && index < @option_count && index != @selected
|
|
82
|
+
@selected = index
|
|
83
|
+
@change_handler.call(@selected) if @change_handler
|
|
84
|
+
mark_dirty
|
|
85
|
+
update
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Top-level helper
|
|
91
|
+
def RadioButtons(options)
|
|
92
|
+
RadioButtons.new(options)
|
|
93
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Slider widget - draggable range input
|
|
2
|
+
# Port of Castella Slider
|
|
3
|
+
|
|
4
|
+
class Slider < Widget
|
|
5
|
+
def initialize(min_val, max_val)
|
|
6
|
+
super()
|
|
7
|
+
@min_val = min_val
|
|
8
|
+
@max_val = max_val
|
|
9
|
+
@value = min_val
|
|
10
|
+
@dragging = false
|
|
11
|
+
@change_handler = nil
|
|
12
|
+
@width_policy = EXPANDING
|
|
13
|
+
@height_policy = FIXED
|
|
14
|
+
@height = 30.0
|
|
15
|
+
# Colors (Tokyo Night)
|
|
16
|
+
@track_color = 0xFF414868
|
|
17
|
+
@fill_color = 0xFF7AA2F7
|
|
18
|
+
@thumb_color = 0xFFC0CAF5
|
|
19
|
+
@thumb_hover = 0xFFFFFFFF
|
|
20
|
+
@hovered = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def with_value(v)
|
|
24
|
+
if v < @min_val
|
|
25
|
+
@value = @min_val
|
|
26
|
+
elsif v > @max_val
|
|
27
|
+
@value = @max_val
|
|
28
|
+
else
|
|
29
|
+
@value = v
|
|
30
|
+
end
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def on_change(&block)
|
|
35
|
+
@change_handler = block
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def get_value
|
|
40
|
+
@value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def measure(painter)
|
|
44
|
+
Size.new(200.0, 30.0)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def redraw(painter, completely)
|
|
48
|
+
thumb_r = 8.0
|
|
49
|
+
track_h = 4.0
|
|
50
|
+
track_y = (@height - track_h) / 2.0
|
|
51
|
+
track_x = thumb_r
|
|
52
|
+
track_w = @width - thumb_r * 2.0
|
|
53
|
+
if track_w < 0.0
|
|
54
|
+
track_w = 0.0
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Track background
|
|
58
|
+
painter.fill_round_rect(track_x, track_y, track_w, track_h, 2.0, @track_color)
|
|
59
|
+
|
|
60
|
+
# Fill (progress)
|
|
61
|
+
ratio = 0.0
|
|
62
|
+
range = @max_val - @min_val
|
|
63
|
+
if range > 0.0
|
|
64
|
+
ratio = (@value - @min_val) / range
|
|
65
|
+
end
|
|
66
|
+
fill_w = track_w * ratio
|
|
67
|
+
if fill_w > 0.0
|
|
68
|
+
painter.fill_round_rect(track_x, track_y, fill_w, track_h, 2.0, @fill_color)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Thumb circle
|
|
72
|
+
thumb_x = track_x + fill_w
|
|
73
|
+
thumb_y = @height / 2.0
|
|
74
|
+
tc = @hovered ? @thumb_hover : @thumb_color
|
|
75
|
+
painter.fill_circle(thumb_x, thumb_y, thumb_r, tc)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def mouse_down(ev)
|
|
79
|
+
@dragging = true
|
|
80
|
+
update_from_pos(ev.pos.x)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def mouse_drag(ev)
|
|
84
|
+
if @dragging
|
|
85
|
+
update_from_pos(ev.pos.x)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def mouse_up(ev)
|
|
90
|
+
@dragging = false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def mouse_over
|
|
94
|
+
@hovered = true
|
|
95
|
+
mark_dirty
|
|
96
|
+
update
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def mouse_out
|
|
100
|
+
@hovered = false
|
|
101
|
+
mark_dirty
|
|
102
|
+
update
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def update_from_pos(x)
|
|
106
|
+
thumb_r = 8.0
|
|
107
|
+
track_x = thumb_r
|
|
108
|
+
track_w = @width - thumb_r * 2.0
|
|
109
|
+
if track_w <= 0.0
|
|
110
|
+
return
|
|
111
|
+
end
|
|
112
|
+
ratio = (x - track_x) / track_w
|
|
113
|
+
if ratio < 0.0
|
|
114
|
+
ratio = 0.0
|
|
115
|
+
end
|
|
116
|
+
if ratio > 1.0
|
|
117
|
+
ratio = 1.0
|
|
118
|
+
end
|
|
119
|
+
range = @max_val - @min_val
|
|
120
|
+
new_val = @min_val + ratio * range
|
|
121
|
+
if new_val != @value
|
|
122
|
+
@value = new_val
|
|
123
|
+
@change_handler.call(@value) if @change_handler
|
|
124
|
+
mark_dirty
|
|
125
|
+
update
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Top-level helper
|
|
131
|
+
def Slider(min_val, max_val)
|
|
132
|
+
Slider.new(min_val, max_val)
|
|
133
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Switch widget - ON/OFF toggle
|
|
2
|
+
# Port of Castella Switch
|
|
3
|
+
|
|
4
|
+
class Switch < Widget
|
|
5
|
+
def initialize
|
|
6
|
+
super()
|
|
7
|
+
@on = false
|
|
8
|
+
@change_handler = nil
|
|
9
|
+
@width_policy = CONTENT
|
|
10
|
+
@height_policy = CONTENT
|
|
11
|
+
# Colors (Tokyo Night)
|
|
12
|
+
@on_color = 0xFF7AA2F7
|
|
13
|
+
@off_color = 0xFF414868
|
|
14
|
+
@knob_color = 0xFFFFFFFF
|
|
15
|
+
@hovered = false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def with_on(v)
|
|
19
|
+
@on = v
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def on_change(&block)
|
|
24
|
+
@change_handler = block
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def is_on
|
|
29
|
+
@on
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def measure(painter)
|
|
33
|
+
Size.new(44.0, 24.0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def redraw(painter, completely)
|
|
37
|
+
w = 44.0
|
|
38
|
+
h = 24.0
|
|
39
|
+
r = h / 2.0
|
|
40
|
+
|
|
41
|
+
# Track
|
|
42
|
+
track_color = @on ? @on_color : @off_color
|
|
43
|
+
painter.fill_round_rect(0.0, 0.0, w, h, r, track_color)
|
|
44
|
+
|
|
45
|
+
# Knob
|
|
46
|
+
knob_r = 9.0
|
|
47
|
+
knob_y = h / 2.0
|
|
48
|
+
knob_x = 0.0
|
|
49
|
+
if @on
|
|
50
|
+
knob_x = w - r
|
|
51
|
+
else
|
|
52
|
+
knob_x = r
|
|
53
|
+
end
|
|
54
|
+
painter.fill_circle(knob_x, knob_y, knob_r, @knob_color)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def mouse_up(ev)
|
|
58
|
+
if @on
|
|
59
|
+
@on = false
|
|
60
|
+
else
|
|
61
|
+
@on = true
|
|
62
|
+
end
|
|
63
|
+
@change_handler.call(@on) if @change_handler
|
|
64
|
+
mark_dirty
|
|
65
|
+
update
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def mouse_over
|
|
69
|
+
@hovered = true
|
|
70
|
+
mark_dirty
|
|
71
|
+
update
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def mouse_out
|
|
75
|
+
@hovered = false
|
|
76
|
+
mark_dirty
|
|
77
|
+
update
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Top-level helper
|
|
82
|
+
def Switch()
|
|
83
|
+
Switch.new
|
|
84
|
+
end
|