UIng
UIng is a Crystal binding for libui-ng
Windows | Mac | Linux |
---|---|---|
![]() |
![]() |
![]() |
Installation
Add the dependency to your shard.yml
:
dependencies:
uing:
github: kojix2/uing
The required libui library is automatically downloaded via postinstall.
To download manually: crystal run download.cr
Usage
require "uing"
UIng.init
window = UIng::Window.new("Hello World", 300, 200)
window.on_closing do
UIng.quit
true
end
button = UIng::Button.new("Click me")
button.on_clicked do
UIng.msg_box(window, "Info", "Button clicked!")
end
window.set_child(button)
window.show
UIng.main
UIng.uninit
DSL style
require "uing"
UIng.init do
UIng::Window.new("Hello World", 300, 200) { |win|
on_closing { UIng.quit; true }
set_child {
UIng::Button.new("Click me") {
on_clicked {
UIng.msg_box(win, "Info", "Button clicked!")
}
}
}
show
}
UIng.main
end
For more examples, see examples.
API Levels
Level | Defined in | Example | Description |
---|---|---|---|
High-Level | src/uing/*.cr |
button.on_clicked { } , etc. |
Object-oriented API |
Low-Level | src/uing/lib_ui/lib_ui.cr |
UIng::LibUI.new_button , etc. |
Direct bindings to libui |
- Almost all basic control functions such as
Window
,Label
, andButton
are covered. - APIs for advanced controls such as
Table
andArea
are also provided. However, these are still under development and there may still be memory management issues.
Memory Safety
-
Most callbacks are stored as instance variables of their respective controls, which protects them from garbage collection (GC). Some callbacks are stored as UIng class variables, which serves the same purpose.
-
Instances of a control are passed as arguments to a parent control's append or set_child method. This establishes a reference from the parent to the child, creating a reference chain such as Window -> Box -> Button. This chain prevents the Garbage Collector (GC) from collecting the Button object (and its callbacks), thus avoiding a segmentation fault as long as the Window is present.
-
Some root components, such as Window and Menu, are stored as class variables to ensure protection from GC. This may cause memory leaks, but is acceptable for now.
-
The use of
finalize
is intentionally avoided in certain cases because the non-deterministic timing of memory deallocation by the GC is often incompatible with libui. Instead, RAII-style API is provided that automatically calls the free method upon exiting a block, relieving users of the need to call free manually.
Windows Setup
Hide Console Window
MinGW:
crystal build app.cr --link-flags "-mwindows"
MSVC:
crystal build app.cr --link-flags=/SUBSYSTEM:WINDOWS
MSVC Setup
Use Developer Command Prompt or add Windows Kits path:
$env:Path += ";C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64"
Closures in Low-Level Contexts
-
Many methods support Crystal closures because the underlying libui-ng functions accept a
data
parameter. -
In some low-level APIs, such as function pointers assigned to struct members, no
data
can be passed. UIng works around this by using struct inheritance and boxed data to support closures in these cases. -
This approach is used in controls like
Table
andArea
.
Development
UIng::LibUI
is the module for direct C bindings- Initially, crystal_lib was used to generate low-level bindings - However, it required many manual conversions, such as changing LibC::Int to Bool. Currently, it is better to use AI.
- When adding new UI components, follow the established callback management patterns
- libui libraries are generated using GitHub Actions at kojix2/libui-ng in the pre-build branch.
Contributing
- Fork this repository
- Report bugs and submit pull requests
- Improve documentation
- Test memory safety improvements
License
MIT License
This project includes code generated using AI.