konpeito 0.8.0 → 0.9.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 +4 -4
- data/CHANGELOG.md +27 -1
- data/lib/konpeito/codegen/llvm_generator.rb +87 -11
- data/lib/konpeito/codegen/mruby_backend.rb +2 -0
- data/lib/konpeito/codegen/mruby_helpers.c +107 -0
- data/lib/konpeito/stdlib/clay/clay.rb +10 -0
- data/lib/konpeito/stdlib/clay/clay.rbs +42 -0
- data/lib/konpeito/stdlib/clay/clay_native.c +252 -29
- data/lib/konpeito/stdlib/clay_tui/clay_tui.rbs +6 -0
- data/lib/konpeito/stdlib/clay_tui/clay_tui_native.c +108 -28
- data/lib/konpeito/stdlib/kui/kui.rb +126 -595
- data/lib/konpeito/stdlib/kui/kui.rbs +144 -2
- data/lib/konpeito/stdlib/kui/kui_charts.rb +409 -0
- data/lib/konpeito/stdlib/kui/kui_charts.rbs +8 -0
- data/lib/konpeito/stdlib/kui/kui_containers.rb +202 -0
- data/lib/konpeito/stdlib/kui/kui_data.rb +284 -0
- data/lib/konpeito/stdlib/kui/kui_events.rb +10 -0
- data/lib/konpeito/stdlib/kui/kui_forms.rb +563 -0
- data/lib/konpeito/stdlib/kui/kui_gui.rb +117 -13
- data/lib/konpeito/stdlib/kui/kui_interactive.rb +428 -0
- data/lib/konpeito/stdlib/kui/kui_layouts.rb +150 -0
- data/lib/konpeito/stdlib/kui/kui_markdown.rb +1765 -0
- data/lib/konpeito/stdlib/kui/kui_markdown.rbs +6 -0
- data/lib/konpeito/stdlib/kui/kui_nav.rb +158 -0
- data/lib/konpeito/stdlib/kui/kui_overlay.rb +355 -0
- data/lib/konpeito/stdlib/kui/kui_state.rb +20 -0
- data/lib/konpeito/stdlib/kui/kui_state.rbs +5 -0
- data/lib/konpeito/stdlib/kui/kui_theme.rb +367 -5
- data/lib/konpeito/stdlib/kui/kui_theme.rbs +3 -3
- data/lib/konpeito/stdlib/kui/kui_tui.rb +92 -12
- data/lib/konpeito/version.rb +1 -1
- data/vendor/clay/clay_renderer_raylib.c +1 -1
- metadata +14 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d513cebc5d3b0574c814b92901fbe2f4154e4ffc905da31c095abf9375bcaf34
|
|
4
|
+
data.tar.gz: 8becb035b3dc4e7aa9f2cb482fa658fcf4551ceeb734fba5c7727eb87e06babd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e37567409349ff5fe6c87802b89ffe2ecef3cd7b4b74fc332df6534e5c5e144b0d527d9f2d67d39c532dd117ebe35aa654e2779a4c10f6191f96b0a8fa9bb168
|
|
7
|
+
data.tar.gz: aef79cd03516814b259747bf9eaa0b449d692ca6568b6ecf9c4939e05ce279d7343d65caf8ceccc74e63094839e318bf5a855ea8b2d75e54f83d6e1e7f5ef6e8
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,32 @@ All notable changes to Konpeito will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.9.0] - 2026-03-16
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **KUI widget expansion** (25→66 widgets): badge, avatar, progress_steps, number_stepper,
|
|
12
|
+
segmented_control, accordion, dropdown, tooltip, toast, alert/confirm dialog, slider,
|
|
13
|
+
switch, rating, textarea, color_picker, date_picker, grid, zstack, scaffold, wrap_panel,
|
|
14
|
+
nav_bar, bottom_nav, drawer, bottom_sheet, list_section, sortable_header, timeline,
|
|
15
|
+
skeleton, carousel_dots, and nested yield fix in mruby backend
|
|
16
|
+
- **KUI Markdown renderer** with live window resize support
|
|
17
|
+
- **KUI chart rendering**: bar, line, and pie charts
|
|
18
|
+
- **KUI Castella-style theming**: style composition and theme presets
|
|
19
|
+
(dark, light, solarized, etc.)
|
|
20
|
+
- **Basic IME support**: UTF-8 text buffers and CJK font loading
|
|
21
|
+
- **TUI Markdown demo** and TUI build resize stubs
|
|
22
|
+
- **Pomodoro Timer** KUI utility app
|
|
23
|
+
- **KUI framework extensions** and two new example apps (café menu, dashboard)
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **case/when with integer constants** crashed with SIGSEGV
|
|
27
|
+
- **Large draw functions** caused SIGSEGV in Pomodoro Timer (resolved by function splitting)
|
|
28
|
+
- **Unboxed captures in escape-cells** caused GC SIGSEGV (now boxed before capture)
|
|
29
|
+
- **Nested yield+block** caused SIGSEGV (re-enabled yield target stack)
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- KUI tutorial updated with new widget features
|
|
33
|
+
- KUI documentation clarified as immediate-mode UI framework
|
|
9
34
|
|
|
10
35
|
## [0.8.0] - 2026-03-14
|
|
11
36
|
|
|
@@ -379,6 +404,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
379
404
|
- `%a{extern}` - external C struct wrappers
|
|
380
405
|
- `%a{simd}` - SIMD vectorization
|
|
381
406
|
|
|
407
|
+
[0.9.0]: https://github.com/i2y/konpeito/compare/v0.8.0...v0.9.0
|
|
382
408
|
[0.8.0]: https://github.com/i2y/konpeito/compare/v0.7.1...v0.8.0
|
|
383
409
|
[0.7.1]: https://github.com/i2y/konpeito/compare/v0.7.0...v0.7.1
|
|
384
410
|
[0.7.0]: https://github.com/i2y/konpeito/compare/v0.6.0...v0.7.0
|
|
@@ -823,6 +823,13 @@ module Konpeito
|
|
|
823
823
|
# We'll use rb_yield_values2 instead: VALUE rb_yield_values2(int argc, const VALUE *argv)
|
|
824
824
|
@rb_yield_values2 = @mod.functions.add("rb_yield_values2", [LLVM::Int32, LLVM::Pointer(value_type)], value_type)
|
|
825
825
|
|
|
826
|
+
# Nested yield: yield to the enclosing method's block from inside a block callback
|
|
827
|
+
@konpeito_yield_to_method_block = @mod.functions.add("konpeito_yield_to_method_block", [value_type], value_type)
|
|
828
|
+
@konpeito_yield_to_method_block_values = @mod.functions.add("konpeito_yield_to_method_block_values",
|
|
829
|
+
[LLVM::Int32, LLVM::Pointer(value_type)], value_type)
|
|
830
|
+
@konpeito_push_yield_target = @mod.functions.add("konpeito_push_yield_target", [], LLVM::Type.void)
|
|
831
|
+
@konpeito_pop_yield_target = @mod.functions.add("konpeito_pop_yield_target", [], LLVM::Type.void)
|
|
832
|
+
|
|
826
833
|
# int rb_block_given_p(void) - check if block is given
|
|
827
834
|
@rb_block_given_p = @mod.functions.add("rb_block_given_p", [], LLVM::Int32)
|
|
828
835
|
|
|
@@ -1767,6 +1774,15 @@ module Konpeito
|
|
|
1767
1774
|
@builder.store(arena_idx, @mruby_gc_arena_alloca)
|
|
1768
1775
|
end
|
|
1769
1776
|
|
|
1777
|
+
# For mruby: if this function has yield inside block callbacks (nested yield),
|
|
1778
|
+
# push the current method's block as the yield target so that nested callbacks
|
|
1779
|
+
# can yield to the correct block instead of the innermost callback.
|
|
1780
|
+
@needs_yield_target_pop = false
|
|
1781
|
+
if @runtime == :mruby && function_has_nested_yield?(hir_func)
|
|
1782
|
+
@builder.call(@konpeito_push_yield_target)
|
|
1783
|
+
@needs_yield_target_pop = true
|
|
1784
|
+
end
|
|
1785
|
+
|
|
1770
1786
|
# Insert profiling entry probe after parameter setup
|
|
1771
1787
|
insert_profile_entry_probe(hir_func)
|
|
1772
1788
|
|
|
@@ -1796,6 +1812,10 @@ module Konpeito
|
|
|
1796
1812
|
# For the mruby backend, restores the arena to the saved index and
|
|
1797
1813
|
# protects the return value from GC before returning.
|
|
1798
1814
|
def emit_ret(value)
|
|
1815
|
+
# Pop yield target before return if this function pushed one
|
|
1816
|
+
if @needs_yield_target_pop
|
|
1817
|
+
@builder.call(@konpeito_pop_yield_target)
|
|
1818
|
+
end
|
|
1799
1819
|
if @mruby_gc_arena_alloca
|
|
1800
1820
|
idx = @builder.load2(LLVM::Int32, @mruby_gc_arena_alloca, "_arena_r")
|
|
1801
1821
|
@builder.call(@konpeito_gc_arena_restore, idx)
|
|
@@ -1807,6 +1827,32 @@ module Konpeito
|
|
|
1807
1827
|
@builder.ret(value)
|
|
1808
1828
|
end
|
|
1809
1829
|
|
|
1830
|
+
# Check if a function has yield inside any block callback body (nested yield).
|
|
1831
|
+
# Direct yield in the function body does NOT count (that uses rb_yield normally).
|
|
1832
|
+
def function_has_nested_yield?(hir_func)
|
|
1833
|
+
hir_func.body.each do |bb|
|
|
1834
|
+
bb.instructions.each do |inst|
|
|
1835
|
+
if inst.is_a?(HIR::Call) && inst.block
|
|
1836
|
+
return true if block_body_contains_yield?(inst.block)
|
|
1837
|
+
end
|
|
1838
|
+
end
|
|
1839
|
+
end
|
|
1840
|
+
false
|
|
1841
|
+
end
|
|
1842
|
+
|
|
1843
|
+
# Recursively check if a block body contains a Yield instruction.
|
|
1844
|
+
def block_body_contains_yield?(block_def)
|
|
1845
|
+
block_def.body.each do |bb|
|
|
1846
|
+
bb.instructions.each do |inst|
|
|
1847
|
+
return true if inst.is_a?(HIR::Yield)
|
|
1848
|
+
if inst.is_a?(HIR::Call) && inst.block
|
|
1849
|
+
return true if block_body_contains_yield?(inst.block)
|
|
1850
|
+
end
|
|
1851
|
+
end
|
|
1852
|
+
end
|
|
1853
|
+
false
|
|
1854
|
+
end
|
|
1855
|
+
|
|
1810
1856
|
# Topologically sort blocks based on phi dependencies
|
|
1811
1857
|
# Ensures blocks are generated after the blocks their phi nodes reference
|
|
1812
1858
|
def sort_blocks_by_phi_dependencies(blocks)
|
|
@@ -4814,11 +4860,19 @@ module Konpeito
|
|
|
4814
4860
|
if use_escape_cells
|
|
4815
4861
|
esc_ary = @builder.call(@rb_ary_new_capa, LLVM::Int64.from_i(all_captures.size), "blk_esc_ary")
|
|
4816
4862
|
all_captures.each do |cap|
|
|
4863
|
+
cap_type = capture_types[cap.name] || :value
|
|
4817
4864
|
val = if @variable_allocas[cap.name]
|
|
4818
4865
|
@builder.load2(value_type, @variable_allocas[cap.name], "blk_esc_#{cap.name}")
|
|
4819
4866
|
else
|
|
4820
4867
|
qnil
|
|
4821
4868
|
end
|
|
4869
|
+
# Box unboxed values before pushing to the escape-cells Ruby Array.
|
|
4870
|
+
# The GC scans array elements as mrb_values; a raw unboxed integer
|
|
4871
|
+
# (e.g., from NativeArray) without fixnum tag bits would be
|
|
4872
|
+
# misinterpreted as a heap pointer → SIGSEGV in gc_mark_children.
|
|
4873
|
+
if cap_type != :value
|
|
4874
|
+
val = convert_value(val, cap_type, :value)
|
|
4875
|
+
end
|
|
4822
4876
|
@builder.call(@rb_ary_push, esc_ary, val)
|
|
4823
4877
|
end
|
|
4824
4878
|
|
|
@@ -4916,8 +4970,9 @@ module Konpeito
|
|
|
4916
4970
|
# Set @in_block_callback so nested proc creation uses GC-safe escape-cells mode.
|
|
4917
4971
|
# Reset mruby constant cache — LLVM values are scoped per function, so
|
|
4918
4972
|
# cached %qnil/%qtrue from the parent function are invalid here.
|
|
4919
|
-
# Clear GC arena alloca — callbacks don't own their own arena scope.
|
|
4920
4973
|
@in_block_callback = true
|
|
4974
|
+
|
|
4975
|
+
# Clear GC arena alloca — callbacks run under the caller's arena scope.
|
|
4921
4976
|
@mruby_gc_arena_alloca = nil
|
|
4922
4977
|
@variables = {}
|
|
4923
4978
|
@variable_types = {}
|
|
@@ -4936,13 +4991,21 @@ module Konpeito
|
|
|
4936
4991
|
captures.each_with_index do |capture, i|
|
|
4937
4992
|
val = @builder.call(@rb_ary_entry, ary_val,
|
|
4938
4993
|
LLVM::Int64.from_i(i), "esc_#{capture.name}")
|
|
4994
|
+
# Values were boxed when pushed to the escape-cells array
|
|
4995
|
+
# (to prevent GC from misinterpreting raw unboxed integers as
|
|
4996
|
+
# heap pointers). Unbox them back to their original type.
|
|
4997
|
+
cap_type = capture_types[capture.name] || :value
|
|
4998
|
+
if cap_type != :value
|
|
4999
|
+
val = convert_value(val, :value, cap_type)
|
|
5000
|
+
end
|
|
4939
5001
|
# Store in an alloca so LoadLocal/StoreLocal can use it normally.
|
|
4940
5002
|
# Writes to this alloca stay local (no back-write to the GC array),
|
|
4941
5003
|
# which is correct for snapshots from a returned outer scope.
|
|
4942
|
-
|
|
5004
|
+
llvm_type = type_tag_to_llvm_type(cap_type)
|
|
5005
|
+
cap_alloca = @builder.alloca(llvm_type, "esc_alloca_#{capture.name}")
|
|
4943
5006
|
@builder.store(val, cap_alloca)
|
|
4944
5007
|
@variable_allocas[capture.name] = cap_alloca
|
|
4945
|
-
@variable_types[capture.name] =
|
|
5008
|
+
@variable_types[capture.name] = cap_type
|
|
4946
5009
|
end
|
|
4947
5010
|
else
|
|
4948
5011
|
# data2 is a pointer to array of VALUE* (pointers to captured variables).
|
|
@@ -5149,10 +5212,7 @@ module Konpeito
|
|
|
5149
5212
|
# Return the last value in the block, or Qnil
|
|
5150
5213
|
# For while_exit blocks, the last instruction loads the break value
|
|
5151
5214
|
if last_instr
|
|
5152
|
-
|
|
5153
|
-
# Box unboxed values before returning
|
|
5154
|
-
result_type = :value # Default
|
|
5155
|
-
@builder.ret(result_val)
|
|
5215
|
+
@builder.ret(last_instr)
|
|
5156
5216
|
else
|
|
5157
5217
|
@builder.ret(qnil)
|
|
5158
5218
|
end
|
|
@@ -7982,15 +8042,20 @@ module Konpeito
|
|
|
7982
8042
|
end
|
|
7983
8043
|
|
|
7984
8044
|
def generate_yield(inst)
|
|
8045
|
+
# When yield is inside a block callback, use the yield target stack
|
|
8046
|
+
# to reach the enclosing method's block instead of the innermost callback.
|
|
8047
|
+
yield_fn = @in_block_callback ? @konpeito_yield_to_method_block : @rb_yield
|
|
8048
|
+
yield_values_fn = @in_block_callback ? @konpeito_yield_to_method_block_values : @rb_yield_values2
|
|
8049
|
+
|
|
7985
8050
|
result = if inst.args.empty?
|
|
7986
8051
|
# yield with no arguments - pass Qnil
|
|
7987
|
-
@builder.call(
|
|
8052
|
+
@builder.call(yield_fn, qnil)
|
|
7988
8053
|
elsif inst.args.size == 1
|
|
7989
8054
|
# yield with single argument — must be boxed VALUE for rb_yield
|
|
7990
8055
|
arg_value = get_value_as_ruby(inst.args.first)
|
|
7991
|
-
@builder.call(
|
|
8056
|
+
@builder.call(yield_fn, arg_value)
|
|
7992
8057
|
else
|
|
7993
|
-
# yield with multiple arguments
|
|
8058
|
+
# yield with multiple arguments
|
|
7994
8059
|
argc = LLVM::Int32.from_i(inst.args.size)
|
|
7995
8060
|
|
|
7996
8061
|
# Allocate array on stack
|
|
@@ -8004,7 +8069,7 @@ module Konpeito
|
|
|
8004
8069
|
|
|
8005
8070
|
# Cast to VALUE*
|
|
8006
8071
|
argv_ptr = @builder.bit_cast(argv, LLVM::Pointer(value_type))
|
|
8007
|
-
@builder.call(
|
|
8072
|
+
@builder.call(yield_values_fn, argc, argv_ptr)
|
|
8008
8073
|
end
|
|
8009
8074
|
|
|
8010
8075
|
@variables[inst.result_var] = result if inst.result_var
|
|
@@ -8889,6 +8954,10 @@ module Konpeito
|
|
|
8889
8954
|
# String === arg: Use rb_str_equal
|
|
8890
8955
|
return inline_string_case_eq(receiver, arg)
|
|
8891
8956
|
elsif receiver_hir.is_a?(HIR::ConstantLookup)
|
|
8957
|
+
if is_integer_type?(receiver_hir.type)
|
|
8958
|
+
# Integer constant (e.g. OP_ADD = 1) === arg: VALUE equality check
|
|
8959
|
+
return inline_value_case_eq(receiver, arg)
|
|
8960
|
+
end
|
|
8892
8961
|
# Class/Module === arg: Use rb_obj_is_kind_of
|
|
8893
8962
|
return inline_class_case_eq(receiver, arg)
|
|
8894
8963
|
end
|
|
@@ -8926,6 +8995,13 @@ module Konpeito
|
|
|
8926
8995
|
@builder.select(result_bool, qtrue, qfalse)
|
|
8927
8996
|
end
|
|
8928
8997
|
|
|
8998
|
+
# Inline VALUE equality check for integer constants (e.g. OP_ADD = 1)
|
|
8999
|
+
# Since CRuby/mruby Fixnums are immediate values, VALUE equality == numeric equality
|
|
9000
|
+
def inline_value_case_eq(receiver, arg)
|
|
9001
|
+
eq_bool = @builder.icmp(:eq, receiver, arg)
|
|
9002
|
+
@builder.select(eq_bool, qtrue, qfalse)
|
|
9003
|
+
end
|
|
9004
|
+
|
|
8929
9005
|
# Inline String === arg comparison
|
|
8930
9006
|
def inline_string_case_eq(receiver, arg)
|
|
8931
9007
|
# Use rb_str_equal which returns Qtrue/Qfalse
|
|
@@ -129,6 +129,8 @@ module Konpeito
|
|
|
129
129
|
lines << "/* Block stack for rb_yield/rb_block_given_p support */"
|
|
130
130
|
lines << "extern void konpeito_push_block(mrb_value block);"
|
|
131
131
|
lines << "extern void konpeito_pop_block(void);"
|
|
132
|
+
lines << "extern void konpeito_push_yield_target(void);"
|
|
133
|
+
lines << "extern void konpeito_pop_yield_target(void);"
|
|
132
134
|
lines << ""
|
|
133
135
|
|
|
134
136
|
# Collect NativeClasses from RBS loader
|
|
@@ -96,6 +96,90 @@ void konpeito_pop_block(void) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/* Forward declarations for yield target stack and nested yield support */
|
|
100
|
+
static mrb_value konpeito_get_block(void);
|
|
101
|
+
static konpeito_native_cb_entry *konpeito_get_native_cb(void);
|
|
102
|
+
mrb_value rb_yield(mrb_value val);
|
|
103
|
+
mrb_value rb_yield_values2(int argc, const mrb_value *argv);
|
|
104
|
+
|
|
105
|
+
/* ================================================================
|
|
106
|
+
* Yield target stack for nested yield
|
|
107
|
+
*
|
|
108
|
+
* When a method receives a block and its body (via nested block
|
|
109
|
+
* callbacks) calls yield, the global block stack top points to the
|
|
110
|
+
* innermost callback, not the method's block.
|
|
111
|
+
*
|
|
112
|
+
* The yield target stack captures the block at method entry so that
|
|
113
|
+
* yield inside any nested callback can find the correct target.
|
|
114
|
+
* ================================================================ */
|
|
115
|
+
|
|
116
|
+
static mrb_value konpeito_yield_target_block[KONPEITO_MAX_BLOCK_STACK];
|
|
117
|
+
static konpeito_native_cb_entry konpeito_yield_target_native[KONPEITO_MAX_BLOCK_STACK];
|
|
118
|
+
static int konpeito_yield_target_depth = 0;
|
|
119
|
+
|
|
120
|
+
void konpeito_push_yield_target(void) {
|
|
121
|
+
if (konpeito_yield_target_depth < KONPEITO_MAX_BLOCK_STACK) {
|
|
122
|
+
/* Capture the current top of block_stack as the yield target */
|
|
123
|
+
konpeito_yield_target_block[konpeito_yield_target_depth] = konpeito_get_block();
|
|
124
|
+
konpeito_native_cb_entry *native = konpeito_get_native_cb();
|
|
125
|
+
if (native) {
|
|
126
|
+
konpeito_yield_target_native[konpeito_yield_target_depth] = *native;
|
|
127
|
+
} else {
|
|
128
|
+
konpeito_yield_target_native[konpeito_yield_target_depth].func = NULL;
|
|
129
|
+
}
|
|
130
|
+
konpeito_yield_target_depth++;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
void konpeito_pop_yield_target(void) {
|
|
135
|
+
if (konpeito_yield_target_depth > 0) {
|
|
136
|
+
konpeito_yield_target_depth--;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Yield to the enclosing method's block (not the immediate callback).
|
|
141
|
+
* Used by yield inside block callbacks to propagate correctly. */
|
|
142
|
+
mrb_value konpeito_yield_to_method_block(mrb_value val) {
|
|
143
|
+
mrb_state *mrb = konpeito_mrb_state;
|
|
144
|
+
|
|
145
|
+
if (konpeito_yield_target_depth > 0) {
|
|
146
|
+
konpeito_native_cb_entry *target =
|
|
147
|
+
&konpeito_yield_target_native[konpeito_yield_target_depth - 1];
|
|
148
|
+
if (target->func) {
|
|
149
|
+
mrb_value argv[1];
|
|
150
|
+
argv[0] = val;
|
|
151
|
+
return target->func(val, target->data2, 1, argv);
|
|
152
|
+
}
|
|
153
|
+
mrb_value block = konpeito_yield_target_block[konpeito_yield_target_depth - 1];
|
|
154
|
+
if (!mrb_nil_p(block)) {
|
|
155
|
+
return mrb_funcall(mrb, block, "call", 1, val);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Fallback to normal yield */
|
|
160
|
+
return rb_yield(val);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
mrb_value konpeito_yield_to_method_block_values(int argc, const mrb_value *argv) {
|
|
164
|
+
mrb_state *mrb = konpeito_mrb_state;
|
|
165
|
+
|
|
166
|
+
if (konpeito_yield_target_depth > 0) {
|
|
167
|
+
konpeito_native_cb_entry *target =
|
|
168
|
+
&konpeito_yield_target_native[konpeito_yield_target_depth - 1];
|
|
169
|
+
if (target->func) {
|
|
170
|
+
mrb_value yielded = (argc > 0) ? argv[0] : mrb_nil_value();
|
|
171
|
+
return target->func(yielded, target->data2, argc, argv);
|
|
172
|
+
}
|
|
173
|
+
mrb_value block = konpeito_yield_target_block[konpeito_yield_target_depth - 1];
|
|
174
|
+
if (!mrb_nil_p(block)) {
|
|
175
|
+
mrb_sym call_sym = mrb_intern_cstr(mrb, "call");
|
|
176
|
+
return mrb_funcall_argv(mrb, block, call_sym, argc, argv);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return rb_yield_values2(argc, argv);
|
|
181
|
+
}
|
|
182
|
+
|
|
99
183
|
static mrb_value konpeito_get_block(void) {
|
|
100
184
|
if (konpeito_block_stack_depth > 0) {
|
|
101
185
|
return konpeito_block_stack[konpeito_block_stack_depth - 1];
|
|
@@ -1052,3 +1136,26 @@ void konpeito_mrb_data_init(mrb_value obj, void *ptr, const mrb_data_type *type)
|
|
|
1052
1136
|
|
|
1053
1137
|
/* mrb_top_self wrapper */
|
|
1054
1138
|
mrb_value konpeito_mrb_top_self(mrb_state *mrb) { return mrb_top_self(mrb); }
|
|
1139
|
+
|
|
1140
|
+
/* ================================================================
|
|
1141
|
+
* Live resize bridge — calls Ruby _kui_resize_frame() from C
|
|
1142
|
+
* ================================================================ */
|
|
1143
|
+
|
|
1144
|
+
/* Forward declaration from clay_native.c */
|
|
1145
|
+
typedef void (*clay_frame_fn)(void);
|
|
1146
|
+
extern void konpeito_clay_set_resize_frame_fn(clay_frame_fn fn);
|
|
1147
|
+
|
|
1148
|
+
static void konpeito_resize_frame_bridge(void) {
|
|
1149
|
+
mrb_state *mrb = konpeito_mrb_state;
|
|
1150
|
+
if (!mrb) return;
|
|
1151
|
+
int ai = mrb_gc_arena_save(mrb);
|
|
1152
|
+
mrb_funcall(mrb, mrb_top_self(mrb), "_kui_resize_frame", 0);
|
|
1153
|
+
if (mrb->exc) {
|
|
1154
|
+
mrb->exc = NULL; /* swallow errors during resize */
|
|
1155
|
+
}
|
|
1156
|
+
mrb_gc_arena_restore(mrb, ai);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
void konpeito_register_resize_callback(void) {
|
|
1160
|
+
konpeito_clay_set_resize_frame_fn(konpeito_resize_frame_bridge);
|
|
1161
|
+
}
|
|
@@ -26,6 +26,7 @@ module Clay
|
|
|
26
26
|
def self.layout(dir, pl, pr, pt, pb, gap, swt, swv, sht, shv, ax, ay) end
|
|
27
27
|
def self.bg(r, g, b, a, corner_radius) end
|
|
28
28
|
def self.border(r, g, b, a, top, right, bottom, left, corner_radius) end
|
|
29
|
+
def self.set_custom(chart_id) end
|
|
29
30
|
def self.scroll(horizontal, vertical) end
|
|
30
31
|
def self.floating(ox, oy, z, att_elem, att_parent) end
|
|
31
32
|
|
|
@@ -33,6 +34,7 @@ module Clay
|
|
|
33
34
|
def self.text(text, font_id, font_size, r, g, b, a, wrap) end
|
|
34
35
|
def self.set_measure_text_raylib() end
|
|
35
36
|
def self.load_font(path, size) end
|
|
37
|
+
def self.load_font_cjk(path, size) end
|
|
36
38
|
|
|
37
39
|
# Render Command Access
|
|
38
40
|
def self.cmd_type(index) end
|
|
@@ -48,10 +50,18 @@ module Clay
|
|
|
48
50
|
def self.cmd_font_id(index) end
|
|
49
51
|
def self.cmd_font_size(index) end
|
|
50
52
|
def self.cmd_corner_radius(index) end
|
|
53
|
+
def self.cmd_ix(index) end
|
|
54
|
+
def self.cmd_iy(index) end
|
|
55
|
+
def self.cmd_iw(index) end
|
|
56
|
+
def self.cmd_ih(index) end
|
|
57
|
+
def self.cmd_custom_data(index) end
|
|
51
58
|
def self.cmd_border_width_top(index) end
|
|
52
59
|
|
|
53
60
|
# Bulk Rendering
|
|
54
61
|
def self.render_raylib() end
|
|
62
|
+
def self.set_bg_color(r, g, b) end
|
|
63
|
+
def self.is_resizing() end
|
|
64
|
+
def self.register_resize_callback() end
|
|
55
65
|
|
|
56
66
|
# Scroll
|
|
57
67
|
def self.update_scroll(dx, dy, dt) end
|
|
@@ -70,6 +70,10 @@ module Clay
|
|
|
70
70
|
%a{cfunc: "konpeito_clay_border"}
|
|
71
71
|
def self.border: (Float r, Float g, Float b, Float a, Integer top, Integer right, Integer bottom, Integer left, Float corner_radius) -> void
|
|
72
72
|
|
|
73
|
+
# Custom element (chart placeholder)
|
|
74
|
+
%a{cfunc: "konpeito_clay_set_custom"}
|
|
75
|
+
def self.set_custom: (Integer chart_id) -> void
|
|
76
|
+
|
|
73
77
|
# Scroll/clip configuration
|
|
74
78
|
%a{cfunc: "konpeito_clay_scroll"}
|
|
75
79
|
def self.scroll: (Integer horizontal, Integer vertical) -> void
|
|
@@ -92,6 +96,10 @@ module Clay
|
|
|
92
96
|
%a{cfunc: "konpeito_clay_load_font"}
|
|
93
97
|
def self.load_font: (String path, Integer size) -> Integer
|
|
94
98
|
|
|
99
|
+
# Load a font file with CJK glyph ranges and return its font_id
|
|
100
|
+
%a{cfunc: "konpeito_clay_load_font_cjk"}
|
|
101
|
+
def self.load_font_cjk: (String path, Integer size) -> Integer
|
|
102
|
+
|
|
95
103
|
# ── Render Command Access ──
|
|
96
104
|
|
|
97
105
|
%a{cfunc: "konpeito_clay_cmd_type"}
|
|
@@ -133,6 +141,22 @@ module Clay
|
|
|
133
141
|
%a{cfunc: "konpeito_clay_cmd_corner_radius"}
|
|
134
142
|
def self.cmd_corner_radius: (Integer index) -> Float
|
|
135
143
|
|
|
144
|
+
# Integer bounding box accessors (for chart rendering)
|
|
145
|
+
%a{cfunc: "konpeito_clay_cmd_ix"}
|
|
146
|
+
def self.cmd_ix: (Integer index) -> Integer
|
|
147
|
+
|
|
148
|
+
%a{cfunc: "konpeito_clay_cmd_iy"}
|
|
149
|
+
def self.cmd_iy: (Integer index) -> Integer
|
|
150
|
+
|
|
151
|
+
%a{cfunc: "konpeito_clay_cmd_iw"}
|
|
152
|
+
def self.cmd_iw: (Integer index) -> Integer
|
|
153
|
+
|
|
154
|
+
%a{cfunc: "konpeito_clay_cmd_ih"}
|
|
155
|
+
def self.cmd_ih: (Integer index) -> Integer
|
|
156
|
+
|
|
157
|
+
%a{cfunc: "konpeito_clay_cmd_custom_data"}
|
|
158
|
+
def self.cmd_custom_data: (Integer index) -> Integer
|
|
159
|
+
|
|
136
160
|
%a{cfunc: "konpeito_clay_cmd_border_width_top"}
|
|
137
161
|
def self.cmd_border_width_top: (Integer index) -> Integer
|
|
138
162
|
|
|
@@ -142,6 +166,18 @@ module Clay
|
|
|
142
166
|
%a{cfunc: "konpeito_clay_render_raylib"}
|
|
143
167
|
def self.render_raylib: () -> void
|
|
144
168
|
|
|
169
|
+
# Store background color for live resize re-render
|
|
170
|
+
%a{cfunc: "konpeito_clay_set_bg_color"}
|
|
171
|
+
def self.set_bg_color: (Integer r, Integer g, Integer b) -> void
|
|
172
|
+
|
|
173
|
+
# Check if currently in a resize callback
|
|
174
|
+
%a{cfunc: "konpeito_clay_is_resizing"}
|
|
175
|
+
def self.is_resizing: () -> Integer
|
|
176
|
+
|
|
177
|
+
# Register live resize callback bridge
|
|
178
|
+
%a{cfunc: "konpeito_register_resize_callback"}
|
|
179
|
+
def self.register_resize_callback: () -> void
|
|
180
|
+
|
|
145
181
|
# ── Scroll Update ──
|
|
146
182
|
|
|
147
183
|
%a{cfunc: "konpeito_clay_update_scroll"}
|
|
@@ -210,4 +246,10 @@ module Clay
|
|
|
210
246
|
|
|
211
247
|
%a{cfunc: "konpeito_clay_text_char"}
|
|
212
248
|
def self.text_char: (Integer ch, Integer fid, Integer fsz, Float r, Float g, Float b) -> void
|
|
249
|
+
|
|
250
|
+
%a{cfunc: "konpeito_clay_textbuf_get_char"}
|
|
251
|
+
def self.textbuf_get_char: (Integer id, Integer pos) -> Integer
|
|
252
|
+
|
|
253
|
+
%a{cfunc: "konpeito_clay_textbuf_set_str"}
|
|
254
|
+
def self.textbuf_set_str: (Integer id, String str, Integer len) -> void
|
|
213
255
|
end
|