summaryrefslogtreecommitdiff
path: root/bindings
diff options
context:
space:
mode:
authorSteven Van Dorp <steven@vandorp.lu>2026-02-06 10:00:08 +0100
committerSteven Van Dorp <steven@vandorp.lu>2026-02-06 10:00:08 +0100
commit0d8aeb6464103ec8e35c10c448bf08b0b9edc156 (patch)
tree80ab47bf3e0f137856d8494753e774c8456c85c8 /bindings
Initial CommitHEADmaster
Diffstat (limited to 'bindings')
-rw-r--r--bindings/main.c29
-rw-r--r--bindings/main.py74
-rw-r--r--bindings/minimgui.h76
-rw-r--r--bindings/minimgui.py129
-rwxr-xr-xbindings/run_c.sh9
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
+