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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/lib/konpeito/codegen/llvm_generator.rb +87 -11
  4. data/lib/konpeito/codegen/mruby_backend.rb +2 -0
  5. data/lib/konpeito/codegen/mruby_helpers.c +107 -0
  6. data/lib/konpeito/stdlib/clay/clay.rb +10 -0
  7. data/lib/konpeito/stdlib/clay/clay.rbs +42 -0
  8. data/lib/konpeito/stdlib/clay/clay_native.c +252 -29
  9. data/lib/konpeito/stdlib/clay_tui/clay_tui.rbs +6 -0
  10. data/lib/konpeito/stdlib/clay_tui/clay_tui_native.c +108 -28
  11. data/lib/konpeito/stdlib/kui/kui.rb +126 -595
  12. data/lib/konpeito/stdlib/kui/kui.rbs +144 -2
  13. data/lib/konpeito/stdlib/kui/kui_charts.rb +409 -0
  14. data/lib/konpeito/stdlib/kui/kui_charts.rbs +8 -0
  15. data/lib/konpeito/stdlib/kui/kui_containers.rb +202 -0
  16. data/lib/konpeito/stdlib/kui/kui_data.rb +284 -0
  17. data/lib/konpeito/stdlib/kui/kui_events.rb +10 -0
  18. data/lib/konpeito/stdlib/kui/kui_forms.rb +563 -0
  19. data/lib/konpeito/stdlib/kui/kui_gui.rb +117 -13
  20. data/lib/konpeito/stdlib/kui/kui_interactive.rb +428 -0
  21. data/lib/konpeito/stdlib/kui/kui_layouts.rb +150 -0
  22. data/lib/konpeito/stdlib/kui/kui_markdown.rb +1765 -0
  23. data/lib/konpeito/stdlib/kui/kui_markdown.rbs +6 -0
  24. data/lib/konpeito/stdlib/kui/kui_nav.rb +158 -0
  25. data/lib/konpeito/stdlib/kui/kui_overlay.rb +355 -0
  26. data/lib/konpeito/stdlib/kui/kui_state.rb +20 -0
  27. data/lib/konpeito/stdlib/kui/kui_state.rbs +5 -0
  28. data/lib/konpeito/stdlib/kui/kui_theme.rb +367 -5
  29. data/lib/konpeito/stdlib/kui/kui_theme.rbs +3 -3
  30. data/lib/konpeito/stdlib/kui/kui_tui.rb +92 -12
  31. data/lib/konpeito/version.rb +1 -1
  32. data/vendor/clay/clay_renderer_raylib.c +1 -1
  33. metadata +14 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed1949148547cf4716d3405d71d9d79413d84201a699fefe98512ddb4202808e
4
- data.tar.gz: cbcc7ecbea2a4c6edeab12fd5f20d5221e9dca2e379906c728d37e16b0168bea
3
+ metadata.gz: d513cebc5d3b0574c814b92901fbe2f4154e4ffc905da31c095abf9375bcaf34
4
+ data.tar.gz: 8becb035b3dc4e7aa9f2cb482fa658fcf4551ceeb734fba5c7727eb87e06babd
5
5
  SHA512:
6
- metadata.gz: 8ad8a635a74b09378cacf342e14a9fdba84434d29d3657071a72fb42d800dd8cfe84bc5a9f66ca81fd48852b880f6896c8a4aff5d83c12be03a8cbf8208b5b5d
7
- data.tar.gz: f1635c6083bd97079fff23d07e3fe5232eadaffc21aeccdc6718689569da8afe50eba3252a188eb2aff42318317ed0ec18e5d2e1b190ac63679c0b354a27c11d
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
- ## [Unreleased]
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
- cap_alloca = @builder.alloca(value_type, "esc_alloca_#{capture.name}")
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] = capture_types[capture.name] || :value
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
- result_val = last_instr
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(@rb_yield, qnil)
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(@rb_yield, arg_value)
8056
+ @builder.call(yield_fn, arg_value)
7992
8057
  else
7993
- # yield with multiple arguments - use rb_yield_values2
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(@rb_yield_values2, argc, argv_ptr)
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