gelang 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 (96) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/LICENSE +21 -0
  3. package/README.md +535 -0
  4. package/bin/ge.js +112 -0
  5. package/package.json +62 -0
  6. package/python/pyeffic/__init__.py +9 -0
  7. package/python/pyeffic/__main__.py +6 -0
  8. package/python/pyeffic/analyzer.py +464 -0
  9. package/python/pyeffic/apisurface.py +238 -0
  10. package/python/pyeffic/autoselect.py +327 -0
  11. package/python/pyeffic/backends.py +87 -0
  12. package/python/pyeffic/bench.py +233 -0
  13. package/python/pyeffic/cli.py +184 -0
  14. package/python/pyeffic/compiler.py +421 -0
  15. package/python/pyeffic/config.py +383 -0
  16. package/python/pyeffic/dartgen.py +441 -0
  17. package/python/pyeffic/deploy.py +586 -0
  18. package/python/pyeffic/diagnostics.py +194 -0
  19. package/python/pyeffic/difftest.py +424 -0
  20. package/python/pyeffic/downloader.py +307 -0
  21. package/python/pyeffic/emitters/__init__.py +11 -0
  22. package/python/pyeffic/emitters/base.py +2359 -0
  23. package/python/pyeffic/emitters/cpp.py +266 -0
  24. package/python/pyeffic/emitters/csharp.py +342 -0
  25. package/python/pyeffic/emitters/dart.py +349 -0
  26. package/python/pyeffic/emitters/go.py +388 -0
  27. package/python/pyeffic/emitters/kotlin.py +314 -0
  28. package/python/pyeffic/emitters/rust.py +314 -0
  29. package/python/pyeffic/emitters/zig.py +411 -0
  30. package/python/pyeffic/ffi.py +49 -0
  31. package/python/pyeffic/frontends/__init__.py +94 -0
  32. package/python/pyeffic/frontends/hybrid.py +709 -0
  33. package/python/pyeffic/frontends/typescript.py +965 -0
  34. package/python/pyeffic/ge_cli.py +1148 -0
  35. package/python/pyeffic/golden.py +348 -0
  36. package/python/pyeffic/idents.py +206 -0
  37. package/python/pyeffic/modules.py +220 -0
  38. package/python/pyeffic/packer.py +222 -0
  39. package/python/pyeffic/pipeline.py +797 -0
  40. package/python/pyeffic/reactgen.py +966 -0
  41. package/python/pyeffic/researcher.py +177 -0
  42. package/python/pyeffic/scaffold.py +397 -0
  43. package/python/pyeffic/stdlib.py +246 -0
  44. package/python/pyeffic/styling.py +220 -0
  45. package/python/pyeffic/templates/desktop_gui/README.md +106 -0
  46. package/python/pyeffic/templates/desktop_gui/app/__init__.py +0 -0
  47. package/python/pyeffic/templates/desktop_gui/app/core/__init__.py +0 -0
  48. package/python/pyeffic/templates/desktop_gui/app/core/add.ge.py +13 -0
  49. package/python/pyeffic/templates/desktop_gui/app/core/factorial.ge.py +20 -0
  50. package/python/pyeffic/templates/desktop_gui/app/core/fibonacci.ge.py +25 -0
  51. package/python/pyeffic/templates/desktop_gui/app/core/gcd.ge.py +19 -0
  52. package/python/pyeffic/templates/desktop_gui/app/core/is_prime.ge.py +24 -0
  53. package/python/pyeffic/templates/desktop_gui/app/core/multiply.ge.py +13 -0
  54. package/python/pyeffic/templates/desktop_gui/app/core/power.ge.py +25 -0
  55. package/python/pyeffic/templates/desktop_gui/app/main.ge.py +49 -0
  56. package/python/pyeffic/templates/desktop_gui/app/memory/__init__.py +0 -0
  57. package/python/pyeffic/templates/desktop_gui/app/memory/buffer.ge.py +26 -0
  58. package/python/pyeffic/templates/desktop_gui/app/memory/limits.ge.py +47 -0
  59. package/python/pyeffic/templates/desktop_gui/app/memory/state.ge.py +44 -0
  60. package/python/pyeffic/templates/desktop_gui/app/ui/__init__.py +0 -0
  61. package/python/pyeffic/templates/desktop_gui/app/ui/layout.ge.py +64 -0
  62. package/python/pyeffic/templates/desktop_gui/app/ui/render.ge.py +87 -0
  63. package/python/pyeffic/templates/desktop_gui/app/ui/theme.ge.py +147 -0
  64. package/python/pyeffic/templates/desktop_gui/app/ui/widgets.ge.py +105 -0
  65. package/python/pyeffic/templates/desktop_gui/desktop/__init__.py +1 -0
  66. package/python/pyeffic/templates/desktop_gui/desktop/main.ge.py +258 -0
  67. package/python/pyeffic/templates/desktop_gui/ge.toml +16 -0
  68. package/python/pyeffic/templates/desktop_gui/tests/__init__.py +0 -0
  69. package/python/pyeffic/templates/desktop_gui/tests/ge_loader.py +76 -0
  70. package/python/pyeffic/templates/desktop_gui/tests/test_app.py +173 -0
  71. package/python/pyeffic/templates/web_react/README.md +115 -0
  72. package/python/pyeffic/templates/web_react/app/__init__.py +0 -0
  73. package/python/pyeffic/templates/web_react/app/core/__init__.py +0 -0
  74. package/python/pyeffic/templates/web_react/app/core/add.ge.py +9 -0
  75. package/python/pyeffic/templates/web_react/app/core/factorial.ge.py +16 -0
  76. package/python/pyeffic/templates/web_react/app/core/fibonacci.ge.py +21 -0
  77. package/python/pyeffic/templates/web_react/app/core/is_prime.ge.py +20 -0
  78. package/python/pyeffic/templates/web_react/app/core/multiply.ge.py +9 -0
  79. package/python/pyeffic/templates/web_react/app/main.ge.py +25 -0
  80. package/python/pyeffic/templates/web_react/app/memory/__init__.py +0 -0
  81. package/python/pyeffic/templates/web_react/app/memory/buffer.ge.py +25 -0
  82. package/python/pyeffic/templates/web_react/app/memory/limits.ge.py +51 -0
  83. package/python/pyeffic/templates/web_react/ge.toml +23 -0
  84. package/python/pyeffic/templates/web_react/tests/__init__.py +0 -0
  85. package/python/pyeffic/templates/web_react/tests/ge_loader.py +68 -0
  86. package/python/pyeffic/templates/web_react/tests/test_app.py +105 -0
  87. package/python/pyeffic/templates/web_react/ui/main.ge.ui +33 -0
  88. package/python/pyeffic/templates/web_react/web/__init__.py +0 -0
  89. package/python/pyeffic/templates/web_react/web/server.ge.py +78 -0
  90. package/python/pyeffic/ts2py.py +657 -0
  91. package/python/pyeffic/typecheck.py +232 -0
  92. package/python/pyeffic/ui.py +154 -0
  93. package/python/pyeffic/ui_dsl.py +618 -0
  94. package/python/pyeffic/widgets.py +87 -0
  95. package/scripts/README.md +42 -0
  96. package/scripts/check-toolchains.py +85 -0
@@ -0,0 +1,13 @@
1
+ """Core function: multiply. Compiled to C++ for performance.
2
+
3
+ One function per file (C++ Core Guidelines SF.1-SF.5): each function is a
4
+ separate compilation unit with a clear dependency list.
5
+ """
6
+ from __future__ import annotations
7
+ from pyeffic.backends import cpp
8
+
9
+
10
+ @cpp
11
+ def multiply(a: int, b: int) -> int:
12
+ """Multiply two integers."""
13
+ return a * b
@@ -0,0 +1,25 @@
1
+ """Core function: power. Compiled to C++ for performance.
2
+
3
+ One function per file (C++ Core Guidelines SF.1-SF.5): each function is a
4
+ separate compilation unit with a clear dependency list.
5
+ """
6
+ from __future__ import annotations
7
+ from pyeffic.backends import cpp
8
+
9
+
10
+ @cpp
11
+ def power(base: int, exp: int) -> int:
12
+ """Fast exponentiation: base raised to exp."""
13
+ if exp == 0:
14
+ return 1
15
+ if exp < 0:
16
+ return 0
17
+ result: int = 1
18
+ b: int = base
19
+ e: int = exp
20
+ while e > 0:
21
+ if e % 2 == 1:
22
+ result = result * b
23
+ b = b * b
24
+ e = e // 2
25
+ return result
@@ -0,0 +1,49 @@
1
+ """{app_name} — application aggregator.
2
+
3
+ Single import surface for platform entry points. Import order matters:
4
+ theme before layout/widgets/render, so the C++ preamble declares the
5
+ Win32 SDK before anything that uses it.
6
+
7
+ Layers:
8
+ app/memory/ Rust — bounded state, buffers, limits
9
+ app/core/ C++ — computation (one function per file)
10
+ app/ui/ C++ — theme, layout, widgets, render
11
+ """
12
+ from __future__ import annotations
13
+
14
+ # --- Memory layer (Rust) ---
15
+ from app.memory.limits import (
16
+ mem_input_min, mem_input_max, mem_clamp_input, mem_step_up, mem_step_down,
17
+ )
18
+ from app.memory.buffer import (
19
+ mem_buffer_capacity, mem_digits_capacity, mem_state_slots,
20
+ )
21
+ from app.memory.state import (
22
+ mem_initial_input, mem_initial_result, mem_initial_op,
23
+ mem_op_count, mem_next_op, mem_normalize_input,
24
+ )
25
+
26
+ # --- Core functions (C++) ---
27
+ from app.core.add import add
28
+ from app.core.multiply import multiply
29
+ from app.core.factorial import factorial
30
+ from app.core.fibonacci import fibonacci
31
+ from app.core.is_prime import is_prime
32
+ from app.core.gcd import gcd
33
+ from app.core.power import power
34
+
35
+ # --- UI layer (C++), theme first ---
36
+ from app.ui.theme import (
37
+ ui_color_bg, ui_color_panel, ui_color_card, ui_color_accent,
38
+ ui_color_text, ui_color_text_dim, ui_color_success, ui_color_warning,
39
+ ui_color_grid, ui_font_title, ui_font_heading, ui_font_body, ui_font_small,
40
+ ui_space_xs, ui_space_sm, ui_space_md, ui_space_lg, ui_radius,
41
+ )
42
+ from app.ui.layout import (
43
+ ui_sidebar_width, ui_content_x, ui_card_x, ui_card_y,
44
+ ui_card_width, ui_card_height, ui_controls_y, ui_row_y, ui_center_x,
45
+ )
46
+ from app.ui.widgets import (
47
+ ui_draw_panel, ui_draw_card, ui_draw_text, ui_draw_number, ui_draw_grid,
48
+ )
49
+ from app.ui.render import ui_draw_frame
@@ -0,0 +1,26 @@
1
+ """Memory buffers — fixed-size capacities. Compiled to Rust.
2
+
3
+ The app formats numbers into fixed-size stack buffers instead of
4
+ heap-allocating Strings. These functions expose the capacities so the
5
+ Rust shell and the C++ UI layer agree on the same bounds.
6
+ """
7
+ from __future__ import annotations
8
+ from pyeffic.backends import rust
9
+
10
+
11
+ @rust
12
+ def mem_buffer_capacity() -> int:
13
+ """Capacity of a general text buffer (bytes)."""
14
+ return 64
15
+
16
+
17
+ @rust
18
+ def mem_digits_capacity() -> int:
19
+ """Capacity of the scratch buffer used for integer digits."""
20
+ return 20
21
+
22
+
23
+ @rust
24
+ def mem_state_slots() -> int:
25
+ """Number of fixed app-state slots (input, result, op)."""
26
+ return 3
@@ -0,0 +1,47 @@
1
+ """Memory limits — bounded ranges for app state. Compiled to Rust.
2
+
3
+ This is the memory-safety boundary of the app. Every value that can grow
4
+ is bounded here so no computation can overflow or allocate without limit.
5
+
6
+ Rust design principle: "bound everything that can grow".
7
+ """
8
+ from __future__ import annotations
9
+ from pyeffic.backends import rust
10
+
11
+
12
+ @rust
13
+ def mem_input_min() -> int:
14
+ """Minimum allowed input value."""
15
+ return 0
16
+
17
+
18
+ @rust
19
+ def mem_input_max() -> int:
20
+ """Maximum allowed input value.
21
+
22
+ Kept at 20 so factorial(n) fits in a signed 64-bit integer
23
+ (21! overflows i64). Bounding here prevents overflow at the source.
24
+ """
25
+ return 20
26
+
27
+
28
+ @rust
29
+ def mem_clamp_input(value: int) -> int:
30
+ """Clamp a value into the allowed input range."""
31
+ if value < mem_input_min():
32
+ return mem_input_min()
33
+ if value > mem_input_max():
34
+ return mem_input_max()
35
+ return value
36
+
37
+
38
+ @rust
39
+ def mem_step_up(value: int) -> int:
40
+ """Increment a value, clamped to the max."""
41
+ return mem_clamp_input(value + 1)
42
+
43
+
44
+ @rust
45
+ def mem_step_down(value: int) -> int:
46
+ """Decrement a value, clamped to the min."""
47
+ return mem_clamp_input(value - 1)
@@ -0,0 +1,44 @@
1
+ """Memory state — bounded application state. Compiled to Rust.
2
+
3
+ The GUI keeps a fixed number of scalar slots. No collections grow at
4
+ runtime, so memory use is constant regardless of how long the app runs.
5
+ """
6
+ from __future__ import annotations
7
+ from pyeffic.backends import rust
8
+ from app.memory.limits import mem_clamp_input
9
+
10
+
11
+ @rust
12
+ def mem_initial_input() -> int:
13
+ """Initial input value at startup."""
14
+ return 10
15
+
16
+
17
+ @rust
18
+ def mem_initial_result() -> int:
19
+ """Initial result value at startup."""
20
+ return 0
21
+
22
+
23
+ @rust
24
+ def mem_initial_op() -> int:
25
+ """Initial operation code (0 = factorial)."""
26
+ return 0
27
+
28
+
29
+ @rust
30
+ def mem_op_count() -> int:
31
+ """Number of supported operations."""
32
+ return 4
33
+
34
+
35
+ @rust
36
+ def mem_next_op(op: int) -> int:
37
+ """Cycle to the next operation code."""
38
+ return (op + 1) % mem_op_count()
39
+
40
+
41
+ @rust
42
+ def mem_normalize_input(value: int) -> int:
43
+ """Normalize an input value into the bounded range."""
44
+ return mem_clamp_input(value)
@@ -0,0 +1,64 @@
1
+ """UI layout — geometry math. Compiled to C++.
2
+
3
+ Pure coordinate math: no drawing, no state. Kept separate from
4
+ widgets.ge.py so layout can be reasoned about (and tested) on its own.
5
+
6
+ Depends on: theme.ge.py
7
+ """
8
+ from __future__ import annotations
9
+ from pyeffic.backends import cpp
10
+ from app.ui.theme import ui_space_md, ui_space_lg
11
+
12
+
13
+ @cpp
14
+ def ui_sidebar_width() -> int:
15
+ """Sidebar width in pixels."""
16
+ return 300
17
+
18
+
19
+ @cpp
20
+ def ui_content_x() -> int:
21
+ """Left edge of the content area."""
22
+ return ui_sidebar_width() + ui_space_md()
23
+
24
+
25
+ @cpp
26
+ def ui_card_x() -> int:
27
+ """Main card left edge."""
28
+ return ui_content_x()
29
+
30
+
31
+ @cpp
32
+ def ui_card_y() -> int:
33
+ """Main card top edge."""
34
+ return ui_space_lg() + 60
35
+
36
+
37
+ @cpp
38
+ def ui_card_width(window_width: int) -> int:
39
+ """Main card width."""
40
+ return window_width - ui_card_x() - ui_space_md()
41
+
42
+
43
+ @cpp
44
+ def ui_card_height(window_height: int) -> int:
45
+ """Main card height."""
46
+ return window_height - ui_card_y() - 60
47
+
48
+
49
+ @cpp
50
+ def ui_controls_y(window_height: int) -> int:
51
+ """Y position of the controls hint block."""
52
+ return window_height - 140
53
+
54
+
55
+ @cpp
56
+ def ui_row_y(row: int) -> int:
57
+ """Y position of sidebar row `row`."""
58
+ return 80 + row * 34
59
+
60
+
61
+ @cpp
62
+ def ui_center_x(container_x: int, container_w: int, item_w: int) -> int:
63
+ """X position that centers an item inside a container."""
64
+ return container_x + (container_w - item_w) / 2
@@ -0,0 +1,87 @@
1
+ """UI render — frame orchestrator. Compiled to C++.
2
+
3
+ Draws one complete frame. Called from the Rust shell on WM_PAINT with the
4
+ raw HDC handle. Composition order:
5
+
6
+ background -> grid -> sidebar -> sidebar text -> card -> card content -> footer
7
+
8
+ Depends on: theme.ge.py, layout.ge.py, widgets.ge.py
9
+ """
10
+ from __future__ import annotations
11
+ from pyeffic.backends import cpp
12
+ from app.ui.theme import (
13
+ ui_color_bg, ui_color_panel, ui_color_accent, ui_color_text,
14
+ ui_color_text_dim, ui_color_success, ui_color_grid,
15
+ ui_font_title, ui_font_body, ui_font_small,
16
+ )
17
+ from app.ui.layout import (
18
+ ui_sidebar_width, ui_content_x, ui_card_x, ui_card_y,
19
+ ui_card_width, ui_card_height, ui_controls_y, ui_row_y,
20
+ )
21
+ from app.ui.widgets import (
22
+ ui_draw_panel, ui_draw_card, ui_draw_text, ui_draw_number, ui_draw_grid,
23
+ )
24
+
25
+
26
+ @cpp
27
+ def ui_draw_frame(hdc_val: int, width: int, height: int,
28
+ input_val: int, result_val: int, op: int) -> int:
29
+ """Draw the whole application frame."""
30
+ ge_inline("cpp", """
31
+ HDC hdc = (HDC)(intptr_t)hdc_val;
32
+
33
+ ui_draw_panel(hdc_val, 0, 0, width, height, ui_color_bg());
34
+ ui_draw_grid(hdc_val, width, height, 40, ui_color_grid());
35
+ ui_draw_panel(hdc_val, 0, 0, ui_sidebar_width(), height, ui_color_panel());
36
+
37
+ ui_draw_text(hdc_val, "{app_name}", 16, 16, ui_sidebar_width() - 32,
38
+ ui_font_title(), ui_color_accent(), 1);
39
+ ui_draw_text(hdc_val, "Rust memory + C++ functions", 16, 50,
40
+ ui_sidebar_width() - 32, ui_font_small(), ui_color_text_dim(), 0);
41
+
42
+ ui_draw_text(hdc_val, "Input", 16, ui_row_y(0), 90,
43
+ ui_font_small(), ui_color_text_dim(), 0);
44
+ ui_draw_number(hdc_val, input_val, 110, ui_row_y(0), 170,
45
+ ui_font_body(), ui_color_text(), 1);
46
+
47
+ const char* op_names[4] = { "factorial", "fibonacci", "is_prime", "gcd" };
48
+ const char* op_label = (op >= 0 && op < 4) ? op_names[op] : "?";
49
+ ui_draw_text(hdc_val, "Operation", 16, ui_row_y(1), 90,
50
+ ui_font_small(), ui_color_text_dim(), 0);
51
+ ui_draw_text(hdc_val, op_label, 110, ui_row_y(1), 170,
52
+ ui_font_small(), ui_color_warning(), 0);
53
+
54
+ ui_draw_text(hdc_val, "Result", 16, ui_row_y(2), 90,
55
+ ui_font_small(), ui_color_text_dim(), 0);
56
+ ui_draw_number(hdc_val, result_val, 110, ui_row_y(2), 170,
57
+ ui_font_body(), ui_color_success(), 1);
58
+
59
+ int cy = ui_controls_y(height);
60
+ ui_draw_text(hdc_val, "Controls", 16, cy, ui_sidebar_width() - 32,
61
+ ui_font_body(), ui_color_text(), 1);
62
+ ui_draw_text(hdc_val, "Up / Down change input", 16, cy + 26,
63
+ ui_sidebar_width() - 32, ui_font_small(), ui_color_text_dim(), 0);
64
+ ui_draw_text(hdc_val, "Enter run operation", 16, cy + 44,
65
+ ui_sidebar_width() - 32, ui_font_small(), ui_color_text_dim(), 0);
66
+ ui_draw_text(hdc_val, "F / P / G fib / prime / gcd", 16, cy + 62,
67
+ ui_sidebar_width() - 32, ui_font_small(), ui_color_text_dim(), 0);
68
+ ui_draw_text(hdc_val, "Esc quit", 16, cy + 80,
69
+ ui_sidebar_width() - 32, ui_font_small(), ui_color_text_dim(), 0);
70
+
71
+ ui_draw_card(hdc_val, ui_card_x(), ui_card_y(),
72
+ ui_card_width(width), ui_card_height(height));
73
+ ui_draw_text(hdc_val, "C++ Core Function", ui_card_x(), ui_card_y() + 20,
74
+ ui_card_width(width), ui_font_body(), ui_color_text(), 1);
75
+ ui_draw_text(hdc_val, "Computed in C++ - drawn in C++ - driven by Rust",
76
+ ui_card_x(), ui_card_y() + 50, ui_card_width(width),
77
+ ui_font_small(), ui_color_text_dim(), 0);
78
+ ui_draw_number(hdc_val, result_val, ui_card_x(), ui_card_y() + 100,
79
+ ui_card_width(width), ui_font_title(), ui_color_success(), 1);
80
+
81
+ ui_draw_text(hdc_val, "{app_name} v0.1.0 - Rust + C++ Desktop",
82
+ ui_content_x(), height - 30, ui_card_width(width),
83
+ ui_font_small(), ui_color_text_dim(), 0);
84
+
85
+ return 0;
86
+ """)
87
+ return 0
@@ -0,0 +1,147 @@
1
+ """UI theme — design tokens. Compiled to C++.
2
+
3
+ Modern dark theme (Fluent-2 / Tailwind-inspired palette).
4
+ This file owns the Win32 includes for the whole C++ layer.
5
+
6
+ UI layer structure (one concern per file):
7
+ theme.ge.py — colors, font sizes, spacing (this file)
8
+ layout.ge.py — geometry math
9
+ widgets.ge.py — drawing primitives
10
+ render.ge.py — frame orchestrator
11
+ """
12
+ from __future__ import annotations
13
+ from pyeffic.backends import cpp
14
+
15
+ # Win32 SDK includes — injected at file scope, before all functions.
16
+ ge_preamble("cpp", """
17
+ #include <windows.h>
18
+ #include <windowsx.h>
19
+ #include <cstdint>
20
+ #include <cstdio>
21
+ #include <cstring>
22
+ #pragma comment(lib, "user32.lib")
23
+ #pragma comment(lib, "gdi32.lib")
24
+ """)
25
+
26
+
27
+ # --- Colors ---
28
+
29
+ @cpp
30
+ def ui_color_bg() -> int:
31
+ """Window background (deep slate)."""
32
+ ge_inline("cpp", "return (int)RGB(15, 23, 42);")
33
+ return 0
34
+
35
+
36
+ @cpp
37
+ def ui_color_panel() -> int:
38
+ """Sidebar panel background."""
39
+ ge_inline("cpp", "return (int)RGB(30, 41, 59);")
40
+ return 0
41
+
42
+
43
+ @cpp
44
+ def ui_color_card() -> int:
45
+ """Card background."""
46
+ ge_inline("cpp", "return (int)RGB(30, 41, 59);")
47
+ return 0
48
+
49
+
50
+ @cpp
51
+ def ui_color_accent() -> int:
52
+ """Primary accent (blue)."""
53
+ ge_inline("cpp", "return (int)RGB(96, 165, 250);")
54
+ return 0
55
+
56
+
57
+ @cpp
58
+ def ui_color_text() -> int:
59
+ """Primary text."""
60
+ ge_inline("cpp", "return (int)RGB(241, 245, 249);")
61
+ return 0
62
+
63
+
64
+ @cpp
65
+ def ui_color_text_dim() -> int:
66
+ """Muted text."""
67
+ ge_inline("cpp", "return (int)RGB(148, 163, 184);")
68
+ return 0
69
+
70
+
71
+ @cpp
72
+ def ui_color_success() -> int:
73
+ """Success / result (green)."""
74
+ ge_inline("cpp", "return (int)RGB(74, 222, 128);")
75
+ return 0
76
+
77
+
78
+ @cpp
79
+ def ui_color_warning() -> int:
80
+ """Warning (amber)."""
81
+ ge_inline("cpp", "return (int)RGB(251, 191, 36);")
82
+ return 0
83
+
84
+
85
+ @cpp
86
+ def ui_color_grid() -> int:
87
+ """Background grid dots."""
88
+ ge_inline("cpp", "return (int)RGB(51, 65, 85);")
89
+ return 0
90
+
91
+
92
+ # --- Font sizes ---
93
+
94
+ @cpp
95
+ def ui_font_title() -> int:
96
+ """Title font size."""
97
+ return 24
98
+
99
+
100
+ @cpp
101
+ def ui_font_heading() -> int:
102
+ """Heading font size."""
103
+ return 18
104
+
105
+
106
+ @cpp
107
+ def ui_font_body() -> int:
108
+ """Body font size."""
109
+ return 15
110
+
111
+
112
+ @cpp
113
+ def ui_font_small() -> int:
114
+ """Caption font size."""
115
+ return 13
116
+
117
+
118
+ # --- Spacing / radius ---
119
+
120
+ @cpp
121
+ def ui_space_xs() -> int:
122
+ """Extra-small spacing."""
123
+ return 4
124
+
125
+
126
+ @cpp
127
+ def ui_space_sm() -> int:
128
+ """Small spacing."""
129
+ return 8
130
+
131
+
132
+ @cpp
133
+ def ui_space_md() -> int:
134
+ """Medium spacing."""
135
+ return 16
136
+
137
+
138
+ @cpp
139
+ def ui_space_lg() -> int:
140
+ """Large spacing."""
141
+ return 24
142
+
143
+
144
+ @cpp
145
+ def ui_radius() -> int:
146
+ """Corner radius."""
147
+ return 12
@@ -0,0 +1,105 @@
1
+ """UI widgets — drawing primitives. Compiled to C++.
2
+
3
+ Each function draws exactly one primitive onto a raw HDC passed from the
4
+ Rust shell. No application state lives here.
5
+
6
+ Depends on: theme.ge.py
7
+ """
8
+ from __future__ import annotations
9
+ from pyeffic.backends import cpp
10
+ from app.ui.theme import (
11
+ ui_color_card, ui_color_accent, ui_radius,
12
+ )
13
+
14
+
15
+ @cpp
16
+ def ui_draw_panel(hdc_val: int, x: int, y: int, w: int, h: int, color: int) -> int:
17
+ """Fill a rectangle."""
18
+ ge_inline("cpp", """
19
+ HDC hdc = (HDC)(intptr_t)hdc_val;
20
+ RECT rc = { (LONG)x, (LONG)y, (LONG)(x + w), (LONG)(y + h) };
21
+ HBRUSH brush = CreateSolidBrush((COLORREF)color);
22
+ FillRect(hdc, &rc, brush);
23
+ DeleteObject(brush);
24
+ return 0;
25
+ """)
26
+ return 0
27
+
28
+
29
+ @cpp
30
+ def ui_draw_card(hdc_val: int, x: int, y: int, w: int, h: int) -> int:
31
+ """Draw a rounded card with an accent border."""
32
+ ge_inline("cpp", """
33
+ HDC hdc = (HDC)(intptr_t)hdc_val;
34
+ HBRUSH brush = CreateSolidBrush((COLORREF)ui_color_card());
35
+ HPEN pen = CreatePen(PS_SOLID, 2, (COLORREF)ui_color_accent());
36
+ HBRUSH old_brush = (HBRUSH)SelectObject(hdc, brush);
37
+ HPEN old_pen = (HPEN)SelectObject(hdc, pen);
38
+ RoundRect(hdc, (int)x, (int)y, (int)(x + w), (int)(y + h),
39
+ ui_radius() * 2, ui_radius() * 2);
40
+ SelectObject(hdc, old_brush);
41
+ SelectObject(hdc, old_pen);
42
+ DeleteObject(brush);
43
+ DeleteObject(pen);
44
+ return 0;
45
+ """)
46
+ return 0
47
+
48
+
49
+ @cpp
50
+ def ui_draw_text(hdc_val: int, text: str, x: int, y: int, w: int,
51
+ size: int, color: int, bold: int) -> int:
52
+ """Draw centered single-line text."""
53
+ ge_inline("cpp", """
54
+ HDC hdc = (HDC)(intptr_t)hdc_val;
55
+ HFONT font = CreateFontA((int)size, 0, 0, 0, bold ? FW_BOLD : FW_NORMAL,
56
+ FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
57
+ CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,
58
+ DEFAULT_PITCH | FF_SWISS, "Segoe UI");
59
+ HFONT old = (HFONT)SelectObject(hdc, font);
60
+ SetBkMode(hdc, TRANSPARENT);
61
+ SetTextColor(hdc, (COLORREF)color);
62
+ RECT rc = { (LONG)x, (LONG)y, (LONG)(x + w), (LONG)(y + size + 10) };
63
+ DrawTextA(hdc, text.c_str(), -1, &rc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
64
+ SelectObject(hdc, old);
65
+ DeleteObject(font);
66
+ return 0;
67
+ """)
68
+ return 0
69
+
70
+
71
+ @cpp
72
+ def ui_draw_number(hdc_val: int, value: int, x: int, y: int, w: int,
73
+ size: int, color: int, bold: int) -> int:
74
+ """Draw an integer using a fixed-size stack buffer (no heap allocation)."""
75
+ ge_inline("cpp", """
76
+ HDC hdc = (HDC)(intptr_t)hdc_val;
77
+ char buf[64];
78
+ snprintf(buf, sizeof(buf), "%lld", (long long)value);
79
+ HFONT font = CreateFontA((int)size, 0, 0, 0, bold ? FW_BOLD : FW_NORMAL,
80
+ FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
81
+ CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,
82
+ DEFAULT_PITCH | FF_SWISS, "Segoe UI");
83
+ HFONT old = (HFONT)SelectObject(hdc, font);
84
+ SetBkMode(hdc, TRANSPARENT);
85
+ SetTextColor(hdc, (COLORREF)color);
86
+ RECT rc = { (LONG)x, (LONG)y, (LONG)(x + w), (LONG)(y + size + 10) };
87
+ DrawTextA(hdc, buf, -1, &rc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
88
+ SelectObject(hdc, old);
89
+ DeleteObject(font);
90
+ return 0;
91
+ """)
92
+ return 0
93
+
94
+
95
+ @cpp
96
+ def ui_draw_grid(hdc_val: int, width: int, height: int, spacing: int, color: int) -> int:
97
+ """Draw a dotted background grid."""
98
+ ge_inline("cpp", """
99
+ HDC hdc = (HDC)(intptr_t)hdc_val;
100
+ for (int gx = 0; gx < (int)width; gx += (int)spacing)
101
+ for (int gy = 0; gy < (int)height; gy += (int)spacing)
102
+ SetPixel(hdc, gx, gy, (COLORREF)color);
103
+ return 0;
104
+ """)
105
+ return 0