ui.hphp

Native desktop windows with buttons, inputs, lists, sliders, menus, timers and dialogs — a friendly HolyPHP API over a hand-written Win32 layer in the runtime. No external dependencies: hphp build links everything into one ~315 KB exe.

stdlib — embedded Win32 native event-driven chainable widgets

Hello GUI

import "ui.hphp";

$app = new App("My App", 640, 420);
$btn = $app->button("Click me", 16, 40);
$name = $app->input("world", 16, 80);

$btn->onClick = function() use ($app, $name) {
    $app->msg("Hello, " . $name->value() . "!");
};

$app->run();   // real desktop event loop

App

new App(string $title = "HolyPHP App", int $w = 800, int $h = 600)
MethodReturnsMeaning
title($t) / size($w,$h) / pos($x,$y)Appwindow geometry (chainable)
run()voidblocking event loop
tick($ms = 15)voidpump events once (own loop)
alive()boolwindow still open?
close()voidclose the window
every($ms, $fn)voidtimer — runs $fn periodically
onClose($fn)voidruns when the window closes

Widgets — created through the App

FactoryWidgetExtras
$app->button($text, $x, $y, $w = 120, $h = 30)Button$w->onClick
$app->label($text, $x, $y, ...)Label
$app->input($text, $x, $y, ...)Inputvalue() / setValue() / $w->onChange
$app->checkbox($text, $x, $y, ...)Checkboxchecked() / setChecked()
$app->listBox($x, $y, $w, $h)ListBoxadd/clear/remove/selected/select/selectedText
$app->comboBox($x, $y, $w, $h)ComboBoxsame API as ListBox
$app->progress($x, $y, $w)ProgressBarset(pct) / get()
$app->slider($x, $y, $w)Sliderset(pos) / get() / $w->onChange(int $v)
$app->group($text, $x, $y, $w, $h)Groupframed container
$app->panel($x, $y, $w, $h)Panelflat container

All widgets inherit from UIObject: chainable text(), getText(), show(), enable(), move(), focus(), font($size, $bold), bg($rgb).

Slider events fire live

$slider = $app->slider(430, 70, 180);
$sliderLbl = $app->label("slider: 50", 430, 104);

$slider->onChange = function(int $v) use ($sliderLbl) {
    $sliderLbl->text("slider: " . $v);   // fires while dragging
};

Menus

$file = $app->menu("&File");
$file->item("&Open\tCtrl+O", function() use ($app) {
    $f = $app->openFile("Text|*.txt|All|*.*");
    if ($f != "") { $app->msg("picked " . $f); }
});
$file->separator();
$file->item("E&xit", function() use ($app) { $app->close(); });

Dialogs & system

void msg(string $text, string $title = "HolyPHP") void warn(string $text, string $title) void error(string $text, string $title) bool question(string $text, string $title) string openFile(string $patterns = "All files|*.*") // "" = cancelled string saveFile(string $patterns) string pickFolder() int pickColor(int $initial = 0xffffff) // 0xRRGGBB, -1 = cancelled

Timers & counters

$frame = 0;
$app->every(100, function() use (&$frame, $app) {   // by-ref capture!
    $frame = $frame + 1;
    if ($frame % 10 == 0) { $app->title("frames: " . $frame); }
});

Full tour

examples/ui_demo.hphp exercises every feature — buttons, inputs, checkbox gating, list box, combo, progress + slider, groups, menus, timers and dialogs:

hphp build examples/ui_demo.hphp -o ui_demo.exe
./ui_demo.exe

How it works

The Win32 layer lives in the runtime (hphp_ui.c): a handle table, a window proc that routes events to HolyPHP closures, and guarded callback invocation — an exception inside a handler prints and keeps the app alive instead of unwinding through C. Callbacks run on the GUI thread; long work belongs in a timer.

Tip: $w->onClick / $w->onChange are plain closure properties — assign any closure, capture anything with use.