# kotlin-libui
**Repository Path**: mirrors_RaiMan/kotlin-libui
## Basic Information
- **Project Name**: kotlin-libui
- **Description**: Kotlin/Native interop to libui: a portable GUI library
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-04-30
- **Last Updated**: 2025-09-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
kotlin-libui
============
[Kotlin/Native](https://github.com/JetBrains/kotlin-native) bindings to the
[libui](https://github.com/andlabs/libui.git) C library.
[](https://travis-ci.org/msink/kotlin-libui)
[](https://ci.appveyor.com/project/msink/kotlin-libui)
libui is a C lightweight multi-platform UI library using native widgets on Linux (Gtk3), macOS, and Windows.
Using this bindings you can develop cross-platform but native-looking GUI programs, written in Kotlin,
and compiled to small native executable file.
## Using
To use this library in your project you can clone [Hello World](https://github.com/msink/hello-libui.git)
application and use it as starting point.
## Building
Cross-platform build is automated using [Travis](https://travis-ci.org) for Linux and macOS targets, and
[AppVeyor](https://ci.appveyor.com) for Windows targets. Just create release on GitHub, and executable files
for all 3 major desktop platforms will be compiled and attached to release.
For local build use `./gradlew build` on Linux or macOS, or `gradlew build` on Windows.
In this case only one - native for your platform - file will be built.
The script below builds kotlin-libui then builds and runs the sample `hello-ktx`:
```
#clone this project
git clone https://github.com/msink/kotlin-libui.git
#build libui.klib
cd kotlin-libui/libui
../gradlew build
#build and run the hello-ktx sample
cd ../samples/hello-ktx/
../../gradlew run
```
You can use IntelliJ IDEA CE/UE or CLion EAP for code navigation and code completion, debugging works only in CLion.
## Status
**Warning:** currently it is just a prototype - works in most cases, but not protected from errors.
And as both libui and Kotlin/Native are currently in alpha stage, anything can change.
Well, I'm also not sure about DSL syntax - it works, and for now is good enough.
Let's leave it as is for a while.
If anyone have ideas - Issues and PullRequests are welcome.
## Hello World
Let's start from minimal sample application - single button and single scrollable text area.
Screenshots:



C implementation:
``` c
#include "ui.h"
static int onClosing(uiWindow *window, void *data)
{
uiQuit();
return 1;
}
static void saySomething(uiButton *button, void *data)
{
uiMultilineEntryAppend(uiMultilineEntry(data),
"Hello, World! Ciao, mondo!\n"
"Привет, мир! 你好,世界!\n\n");
}
int main(void)
{
uiInitOptions options;
uiWindow *window;
uiBox *box;
uiButton *button;
uiMultilineEntry *scroll;
memset(&options, 0, sizeof(options));
if (uiInit(&options) != NULL)
abort();
window = uiNewWindow("Hello", 320, 240, 0);
uiWindowSetMargined(window, 1);
box = uiNewVerticalBox();
uiBoxSetPadded(box, 1);
uiWindowSetChild(window, uiControl(box));
scroll = uiNewMultilineEntry();
uiMultilineEntrySetReadOnly(scroll, 1);
button = uiNewButton("libui говорит: click me!");
uiButtonOnClicked(button, saySomething, scroll);
uiBoxAppend(box, uiControl(button), 0);
uiBoxAppend(box, uiControl(scroll), 1);
uiWindowOnClosing(window, onClosing, NULL);
uiControlShow(uiControl(window));
uiMain();
return 0;
}
```
Direct translation to Kotlin:
``` kt
import kotlinx.cinterop.*
import libui.*
fun main(args: Array) = memScoped {
val options = alloc()
val error = uiInit(options.ptr)
if (error != null) throw Error("Error: '${error.toKString()}'")
val window = uiNewWindow("Hello", 320, 240, 0)
uiWindowSetMargined(window, 1)
val box = uiNewVerticalBox()
uiBoxSetPadded(box, 1)
uiWindowSetChild(window, box?.reinterpret())
val scroll = uiNewMultilineEntry()
uiMultilineEntrySetReadOnly(scroll, 1)
val button = uiNewButton("libui говорит: click me!")
fun saySomething(button: CPointer?, data: COpaquePointer?) {
uiMultilineEntryAppend(data?.reinterpret(),
"Hello, World! Ciao, mondo!\n" +
"Привет, мир! 你好,世界!\n\n")
}
uiButtonOnClicked(button, staticCFunction(::saySomething), scroll)
uiBoxAppend(box, button?.reinterpret(), 0)
uiBoxAppend(box, scroll?.reinterpret(), 1)
fun onClosing(window: CPointer?, data: COpaquePointer?): Int {
uiQuit()
return 1
}
uiWindowOnClosing(window, staticCFunction(::onClosing), null)
uiControlShow(window?.reinterpret())
uiMain()
uiUninit()
}
```
While this works, it's far from idiomatic Kotlin.
OK, let's wrap all that noisy function calls, with final goal to get something similar to [TornadoFX](https://github.com/edvin/tornadofx):
``` kt
import libui.*
fun main(args: Array) = appWindow(
title = "Hello",
width = 320,
height = 240
) {
vbox {
lateinit var scroll: TextArea
button("libui говорит: click me!") {
action {
scroll.append("""
|Hello, World! Ciao, mondo!
|Привет, мир! 你好,世界!
|
|""".trimMargin())
}
}
scroll = textarea {
readonly = true
stretchy = true
}
}
}
```
## More samples
- [simple form](samples/form)
- [controls gallery](samples/controlgallery)
- [histogram](samples/histogram)
- [drawtext](samples/drawtext)
- [datetime](samples/datetime)
- [timer](samples/timer)
- [logo](samples/logo)
- [table](samples/table)
## Documentation
See [autogenerated documentation](docs/index.md), samples and comments in source code.
### Lifecycle management
Kotlin memory management differs from native C model, so all libui objects are wrapped in Kotlin objects
inherited from [Disposable](docs/libui.ktx/-disposable/index.md), and direct using of libui functions is
not recommended in most cases.
Disposable objects must be disposed by calling [dispose](docs/libui.ktx/-disposable/dispose.md)() method,
before program ends. Most objects are attached as a child to some other object, in this case parent is
responsible to dispose all its children, recursively. As DSL builders automatically add created object to
some container - in most cases you do not have to worry about lifecycle management. But if you want to do
something not supported by DSL builders - you can create Disposable object directly, and in this case
*you* are responsible to dispose or attach it at some point.