diff options
| author | Steven Van Dorp <steven@vandorp.lu> | 2026-02-06 10:00:08 +0100 |
|---|---|---|
| committer | Steven Van Dorp <steven@vandorp.lu> | 2026-02-06 10:00:08 +0100 |
| commit | 0d8aeb6464103ec8e35c10c448bf08b0b9edc156 (patch) | |
| tree | 80ab47bf3e0f137856d8494753e774c8456c85c8 /bindings | |
Diffstat (limited to 'bindings')
| -rw-r--r-- | bindings/main.c | 29 | ||||
| -rw-r--r-- | bindings/main.py | 74 | ||||
| -rw-r--r-- | bindings/minimgui.h | 76 | ||||
| -rw-r--r-- | bindings/minimgui.py | 129 | ||||
| -rwxr-xr-x | bindings/run_c.sh | 9 |
5 files changed, 317 insertions, 0 deletions
diff --git a/bindings/main.c b/bindings/main.c new file mode 100644 index 0000000..0c0aee4 --- /dev/null +++ b/bindings/main.c @@ -0,0 +1,29 @@ +#include "minimgui.h" + +Context ui; +bool init () { + ui = context_init(); + return true; +} + +float time = 0; +bool loop (float dt) { + rectangle(ui, ((Rect){ + .x = time / 10, + .y = 0.1f, + .w = 0.2f, + .h = 0.2f + }), .color = color_hex(0xffff0000)); + time += dt; + return true; +} + +void deinit () { + context_deinit(ui); +} + +int main () { + run(init, loop, deinit); + return 0; +} + diff --git a/bindings/main.py b/bindings/main.py new file mode 100644 index 0000000..fbb8bb9 --- /dev/null +++ b/bindings/main.py @@ -0,0 +1,74 @@ +# class +import minimgui as ui + +class App: + def __init__(self): + self.time = 0 + + def loop(self, dt): + self.time += dt + ui.rectangle( + self.time, 0.1, + 0.2, 0.2, + color = 0x0000ffff + ) + +ui.run(App().loop) + +# global +""" +import minimgui as ui + +time = 0 +def loop(dt): + global time + time += dt + ui.rectangle( + time, 0.1, + 0.2, 0.2, + color = 0x0000ffff + ) + +ui.run() +""" + +# closure +""" +import minimgui as ui + +def app(): + time = 0 + def loop(dt): + nonlocal time + time += dt + ui.rectangle( + time, 0.1, + 0.2, 0.2, + color = 0x0000ffff + ) + return loop + +ui.run(app()) +""" + +# dataclass +""" +import minimgui as ui +from dataclasses import dataclass + +@dataclass +class State: + time: float = 0.0 +state = State() + +def loop(dt): + state.time += dt + ui.rectangle( + state.time, 0.1, + 0.2, 0.2, + color = 0x0000ffff + ) + +ui.run() +""" + diff --git a/bindings/minimgui.h b/bindings/minimgui.h new file mode 100644 index 0000000..3d3c94c --- /dev/null +++ b/bindings/minimgui.h @@ -0,0 +1,76 @@ +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +/*=== DEF START ===*/ + +typedef struct { + float x, y; +} V2; + +typedef struct { + float x, y; + float w, h; +} Rect; + +typedef struct { + float a, r, g, b; +} Color; + +typedef void* Image; + +typedef bool(*const InitFn)(); +typedef bool(*const LoopFn)(float dt); +typedef void(*const DeinitFn)(); +void run ( + InitFn const init_fn, + LoopFn const loop_fn, + DeinitFn const deinit_fn +); + +typedef void* Context; +Context context_init(void); +void context_deinit(Context ctx); + +typedef struct { + Color color; + Image image; + bool* hover; + bool consume_hover; + bool ignore_hover_if_consumed; + bool begin_drag_if_hover_and; + bool end_drag_if; + V2** drag; +} RectangleOptions_; +bool rectangle_(Context ctx, Rect rect, RectangleOptions_ o); +/*=== DEF END ===*/ + +#if defined(__GNUC__) || defined(__clang__) +#define PURE __attribute__((pure)) +#else +#define PURE +#endif + +PURE Color color_hex(uint64_t argb) { + uint8_t* arr = (uint8_t*)&argb; + return (Color){ + .a = ((float)arr[0]) / 255.0f, + .r = ((float)arr[1]) / 255.0f, + .g = ((float)arr[2]) / 255.0f, + .b = ((float)arr[3]) / 255.0f, + }; +} + +#define rectangle(ctx, rect, ...) \ + rectangle_(ctx, rect, (RectangleOptions_){ \ + .color = color_hex(0xffffffff), \ + .image = NULL, \ + .hover = NULL, \ + .consume_hover = true, \ + .ignore_hover_if_consumed = true, \ + .begin_drag_if_hover_and = false, \ + .end_drag_if = false, \ + .drag = NULL, \ + __VA_ARGS__ \ + }) + diff --git a/bindings/minimgui.py b/bindings/minimgui.py new file mode 100644 index 0000000..4538247 --- /dev/null +++ b/bindings/minimgui.py @@ -0,0 +1,129 @@ +from cffi import FFI + +ffi = FFI() +ffi.cdef(""" +typedef struct { + float x, y; +} V2; + +typedef struct { + float x, y; + float w, h; +} Rect; + +typedef struct { + float a, r, g, b; +} Color; + +typedef void* Image; + +typedef bool(*const InitFn)(); +typedef bool(*const LoopFn)(float dt); +typedef void(*const DeinitFn)(); +void run ( + InitFn const init_fn, + LoopFn const loop_fn, + DeinitFn const deinit_fn +); + +typedef void* Context; +Context context_init(void); +void context_deinit(Context ctx); + +typedef struct { + Color color; + Image image; + bool* hover; + bool consume_hover; + bool ignore_hover_if_consumed; + bool begin_drag_if_hover_and; + bool end_drag_if; + V2** drag; +} RectangleOptions_; +bool rectangle_(Context ctx, Rect rect, RectangleOptions_ o); +""") +lib = ffi.dlopen("../zig-out/lib/libminimgui.so") + +class Context: + def __init__(self): + self.ctx = lib.context_init() + + def deinit(self): + lib.context_deinit(self.ctx) + + def rectangle(self, *args, color = {"a": 1.0, "r": 1.0, "g": 1.0, "b": 1.0}): + if len(args) == 4: + x, y, w, h = args + rect = { + "x": x, + "y": y, + "w": w, + "h": h + } + elif len(args) == 1: + rect = args[0] + + lib.rectangle_(self.ctx, rect, { + "color": to_color(color) + }) + +# bgra +def color_hex(x): + a = (x >> 24) & 0xFF + r = (x >> 16) & 0xFF + g = (x >> 8) & 0xFF + b = x & 0xFF + return (a / 255.0, r / 255.0, g / 255.0, b / 255.0) +def to_color(color): + if isinstance(color, int): + return color_hex(color) + else: + return color + +def run(*args): + if len(args) == 3: + init_fn = args[0] + loop_fn = args[1] + deinit_fn = args[2] + elif len(args) <= 1: + def init_fn(): + global global_context + global_context = Context() + def deinit_fn(): + global_context.deinit() + if len(args) == 1: + loop_fn = args[0] + else: + import sys + main = sys.modules["__main__"] + loop_fn = getattr(main, "loop", None) + + @ffi.callback("InitFn") + def _init(): + res = init_fn() + if res is None or res is True: + return True + elif res is False: + return False + else: + raise ValueError("minimgui.init() must return None or True") + + @ffi.callback("LoopFn") + def _loop(dt): + res = loop_fn(dt) + if res is None or res is True: + return True + elif res is False: + return False + else: + raise ValueError("minimgui.loop() must return None or True") + + @ffi.callback("DeinitFn") + def _deinit(): + deinit_fn() + + lib.run(_init, _loop, _deinit) + +def __getattr__(name): + return getattr(global_context, name) + diff --git a/bindings/run_c.sh b/bindings/run_c.sh new file mode 100755 index 0000000..a726818 --- /dev/null +++ b/bindings/run_c.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +gcc --std=c99 -g \ + -Wall -Wextra -Wpedantic \ + -Wno-override-init \ + main.c \ + -L../zig-out/lib -lminimgui +export LD_LIBRARY_PATH=../zig-out/lib/;./a.out + |
