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.
- package/CHANGELOG.md +65 -0
- package/LICENSE +21 -0
- package/README.md +535 -0
- package/bin/ge.js +112 -0
- package/package.json +62 -0
- package/python/pyeffic/__init__.py +9 -0
- package/python/pyeffic/__main__.py +6 -0
- package/python/pyeffic/analyzer.py +464 -0
- package/python/pyeffic/apisurface.py +238 -0
- package/python/pyeffic/autoselect.py +327 -0
- package/python/pyeffic/backends.py +87 -0
- package/python/pyeffic/bench.py +233 -0
- package/python/pyeffic/cli.py +184 -0
- package/python/pyeffic/compiler.py +421 -0
- package/python/pyeffic/config.py +383 -0
- package/python/pyeffic/dartgen.py +441 -0
- package/python/pyeffic/deploy.py +586 -0
- package/python/pyeffic/diagnostics.py +194 -0
- package/python/pyeffic/difftest.py +424 -0
- package/python/pyeffic/downloader.py +307 -0
- package/python/pyeffic/emitters/__init__.py +11 -0
- package/python/pyeffic/emitters/base.py +2359 -0
- package/python/pyeffic/emitters/cpp.py +266 -0
- package/python/pyeffic/emitters/csharp.py +342 -0
- package/python/pyeffic/emitters/dart.py +349 -0
- package/python/pyeffic/emitters/go.py +388 -0
- package/python/pyeffic/emitters/kotlin.py +314 -0
- package/python/pyeffic/emitters/rust.py +314 -0
- package/python/pyeffic/emitters/zig.py +411 -0
- package/python/pyeffic/ffi.py +49 -0
- package/python/pyeffic/frontends/__init__.py +94 -0
- package/python/pyeffic/frontends/hybrid.py +709 -0
- package/python/pyeffic/frontends/typescript.py +965 -0
- package/python/pyeffic/ge_cli.py +1148 -0
- package/python/pyeffic/golden.py +348 -0
- package/python/pyeffic/idents.py +206 -0
- package/python/pyeffic/modules.py +220 -0
- package/python/pyeffic/packer.py +222 -0
- package/python/pyeffic/pipeline.py +797 -0
- package/python/pyeffic/reactgen.py +966 -0
- package/python/pyeffic/researcher.py +177 -0
- package/python/pyeffic/scaffold.py +397 -0
- package/python/pyeffic/stdlib.py +246 -0
- package/python/pyeffic/styling.py +220 -0
- package/python/pyeffic/templates/desktop_gui/README.md +106 -0
- package/python/pyeffic/templates/desktop_gui/app/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/core/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/core/add.ge.py +13 -0
- package/python/pyeffic/templates/desktop_gui/app/core/factorial.ge.py +20 -0
- package/python/pyeffic/templates/desktop_gui/app/core/fibonacci.ge.py +25 -0
- package/python/pyeffic/templates/desktop_gui/app/core/gcd.ge.py +19 -0
- package/python/pyeffic/templates/desktop_gui/app/core/is_prime.ge.py +24 -0
- package/python/pyeffic/templates/desktop_gui/app/core/multiply.ge.py +13 -0
- package/python/pyeffic/templates/desktop_gui/app/core/power.ge.py +25 -0
- package/python/pyeffic/templates/desktop_gui/app/main.ge.py +49 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/buffer.ge.py +26 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/limits.ge.py +47 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/state.ge.py +44 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/layout.ge.py +64 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/render.ge.py +87 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/theme.ge.py +147 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/widgets.ge.py +105 -0
- package/python/pyeffic/templates/desktop_gui/desktop/__init__.py +1 -0
- package/python/pyeffic/templates/desktop_gui/desktop/main.ge.py +258 -0
- package/python/pyeffic/templates/desktop_gui/ge.toml +16 -0
- package/python/pyeffic/templates/desktop_gui/tests/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/tests/ge_loader.py +76 -0
- package/python/pyeffic/templates/desktop_gui/tests/test_app.py +173 -0
- package/python/pyeffic/templates/web_react/README.md +115 -0
- package/python/pyeffic/templates/web_react/app/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/app/core/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/app/core/add.ge.py +9 -0
- package/python/pyeffic/templates/web_react/app/core/factorial.ge.py +16 -0
- package/python/pyeffic/templates/web_react/app/core/fibonacci.ge.py +21 -0
- package/python/pyeffic/templates/web_react/app/core/is_prime.ge.py +20 -0
- package/python/pyeffic/templates/web_react/app/core/multiply.ge.py +9 -0
- package/python/pyeffic/templates/web_react/app/main.ge.py +25 -0
- package/python/pyeffic/templates/web_react/app/memory/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/app/memory/buffer.ge.py +25 -0
- package/python/pyeffic/templates/web_react/app/memory/limits.ge.py +51 -0
- package/python/pyeffic/templates/web_react/ge.toml +23 -0
- package/python/pyeffic/templates/web_react/tests/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/tests/ge_loader.py +68 -0
- package/python/pyeffic/templates/web_react/tests/test_app.py +105 -0
- package/python/pyeffic/templates/web_react/ui/main.ge.ui +33 -0
- package/python/pyeffic/templates/web_react/web/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/web/server.ge.py +78 -0
- package/python/pyeffic/ts2py.py +657 -0
- package/python/pyeffic/typecheck.py +232 -0
- package/python/pyeffic/ui.py +154 -0
- package/python/pyeffic/ui_dsl.py +618 -0
- package/python/pyeffic/widgets.py +87 -0
- package/scripts/README.md +42 -0
- 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
|
|
File without changes
|
|
@@ -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)
|
|
File without changes
|
|
@@ -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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|