LibUI
LibUI is a procedural Ruby binding for libui-ng, a native GUI library for Windows, macOS, and Linux. It uses Fiddle and keeps the C API's names and structure, with Ruby-friendly values where they help.
Release lines
This README describes the main branch and the 0.3.x series, which track the
newer libui-ng dev API. The 0.2.x series is maintained separately on
0.2-stable for compatibility
with the older libui-ng pre-build API. Existing 0.2.x applications can stay on
that series while it receives fixes and compatible additions.
Screenshots
| Windows | macOS | Linux |
|---|---|---|
![]() |
![]() |
![]() |
Install
gem install libui
To install a prerelease version, use gem install libui --pre. Gems for
supported platforms include the libui-ng shared library. For a local libui-ng
build, set LIBUIDIR to the directory containing its .dll, .dylib, or
.so file. On Windows, the library may also need the
Visual C++ Redistributable.
Quick start
require 'libui'
UI = LibUI
UI.init
window = UI.new_window('Hello', 300, 100, 0)
= UI.('Click me')
UI.() do
UI.msg_box(window, 'Hello', 'Button clicked')
end
UI.window_set_child(window, )
UI.window_on_closing(window) do
UI.quit
1
end
UI.control_show(window)
UI.main
UI.uninit
Run the example with ruby hello.rb. Explore examples for
individual controls and examples2 for larger applications.
API
Names follow libui-ng with ui removed and CamelCase converted to
snake_case: uiNewWindow becomes LibUI.new_window. Event callbacks accept
a block or Proc; LibUI retains them for the native owner's lifetime. The
libui-ng API reference documents the
underlying controls and functions. LibUI::FFI exposes the original C bindings
when needed.
Ruby values
Native controls, images, attributes, and text layouts are still represented by Fiddle pointers. Common getters and setters use Ruby values:
- Text and file dialog results are strings; a canceled file dialog returns
nil. - Size, position, color, and table selection results are arrays.
- Date and time picker methods use Ruby
Time,DateTime, orDatevalues. - Font getters return
LibUI::Fontvalues.
For example, inside a running UI session:
width, height = UI.window_content_size(window)
rows = UI.table_get_selection(table)
UI.table_set_selection(table, [1, 3])
UI.table_set_selection(table, []) # Clear the selection
path = UI.open_file(window) # A String, or nil if canceled
UI.date_time_picker_set_time(picker, Time.now)
selected_time = UI.date_time_picker_time(picker)
Selection indices must exist in the table model; the selection mode controls
how many rows may be selected. LibUI.version returns the loaded libui-ng build
identifier as a string; LibUI::VERSION is the gem version.
Drawing and tables
The Ruby value classes Font, Brush, StrokeParams, and Matrix hide native
structs. AreaHandler and TableModel manage their callbacks. A drawing area
can use Ruby objects instead of manually allocating native structs:
brush = UI::Brush.new(color: [0.4, 0.4, 0.8, 1.0])
handler = UI::AreaHandler.new(draw: ->(event) do
UI::Path.open do |path|
path.add_rectangle(0, 0, event.area_width, event.area_height).end_path
event.context.fill(path, brush)
end
end)
area = UI.new_area(handler)
Path.open frees the drawing path when the block exits. For a table, provide
Ruby rows and their libui-ng column types:
rows = [%w[cat meow], %w[dog woof]]
model = UI::TableModel.new(column_types: [UI::TableValueTypeString] * 2,
rows: rows)
table = UI.new_table(model: model)
UI.table_append_text_column(table, 'Animal', 0, -1)
UI.table_append_text_column(table, 'Sound', 1, -1)
# After destroying the table: model.free
See basic_area.rb, basic_draw_text.rb, and basic_table.rb for complete programs.
Images
Apart from library configuration, image_append_rgba is the only procedural
helper without a direct C counterpart. The C API's uiImageAppend requires
premultiplied RGBA bytes; LibUI.image_append has the same requirement.
image_append_rgba(image, bytes, width, height) accepts ordinary RGBA bytes,
converts a copy, and calls image_append:
image = UI.new_image(width, height)
UI.image_append_rgba(image, rgba_bytes, width, height)
See basic_table_image.rb for an example using PNG data in a table.
Ownership
Native controls follow libui-ng's parent-child ownership rules. Destroy a
top-level control with control_destroy; destroying a parent also destroys its
children. Standalone resources such as images and text layouts have matching
free_* methods. Free a TableModel after the table using it has been
destroyed. Path.open handles path cleanup.
Development
git clone https://github.com/kojix2/LibUI.git
cd LibUI
bundle install
bundle exec rake vendor:auto
bundle exec rake test
The tests need a GUI display. On macOS with JRuby, set
JRUBY_OPTS=-J-XstartOnFirstThread. bundle exec rake vendor:clean removes
downloaded binaries. The RubyGems release workflow
builds and publishes gems from version tags using trusted publishing.
Related projects and contributing
For an object-oriented DSL built on LibUI, see Glimmer DSL for LibUI. LibUI was inspired by libui-ruby. Bug reports and pull requests are welcome in the GitHub repository.


