
Nuklear: A single-header ANSI C GUI library - mpweiher
https://github.com/vurtun/nuklear
======
zevv
I really do not understand why 'single header' is considered a good thing, but
I see this more and more often on libraries. What is the reason all the code
is put in the header file?

~~~
svdree
Sean Barrett (who I think popularized the idea) has a FAQ on this
([https://github.com/nothings/stb](https://github.com/nothings/stb)) where he
justifies it by pointing at difficulties with deploying libraries on Windows.
Which is a fair point, but by going straight to header-only he skips the step
where you can also just distribute a bunch of headers and .C files. The
convenience of only having to include a single header is nice for quick
weekend projects, but for anything bigger you're dealing with dependencies and
build issues anyway.

I get some of the reasons that you would initially start out with a header-
only implementation, but when your library grows, you probably want to split
it at some point. For me personally, that point would be some time before the
header reached 25k (!!) lines.

~~~
flohofwoe
Some advantages of header-only vs .h/.c pair:

\- you can build simple tools contained in a single .c file, and you dont't
need a build system for this (e.g. just call "cc tool.c -o tool" instead of
mucking around with Makefiles or cmake)

\- the library can be configured with macros before including the
implementation (e.g. provide your own malloc, assert, etc...), with the
implementation in a .c file, these config macros must be provided via command
line args, which implies a build system

\- you can put the implementations for all header-only libs used in a project
into a single .c file instead of compiling the multiple .c implementation
files, this might speed up compilation

Single-header libs have some of the advantages that a proper module system
would bring to C and C++ (e.g. extremely simple integration into own project
and increased compile speed), but without all the complexity of implanting a
module system into C or C++.

~~~
rixed
Make is so simple that it can actually build you single file project without a
makefile with less characters to type:

make tool

Et voilà.

~~~
rlabrecque
Errr, I actually have to spend 5 minutes googling how to install make on
Windows, then getting mingw and hating myself. So no, no it's really not that
simple in general.

~~~
to3m
[https://github.com/tom-
seddon/b2/blob/master/snmake.exe](https://github.com/tom-
seddon/b2/blob/master/snmake.exe) \- standalone build of GNU Make 3.80. Has a
couple of hacks in it to better support Windows-style paths with colons in it.
I think this came from the SN Systems Playstation2 SDK. Thanks to the GPL, you
can have it too.

(I have no idea whether this will successfully run a C compiler for you on
Windows, though. I mostly use it to run Makefiles with phony targets as a
cross-platform replacement for shell scripts.)

~~~
angelsl
Oh no, Make 3.80...

Why not build a more recent version? This thing is 15 years old!

~~~
kqr
This sounds like something one should ask people who do not write portable
makefiles, rather than porters of Make, which has been standardised for quite
a while now.

~~~
to3m
They added some useful stuff in subsequent versions... my recollection (though
this is going back a while now) is that even only 3.81 was a worthwhile
upgrade over 3.80!

However I have better things to do than try to figure out how to build
GNUstuff myself on Windows.

------
gnud
I'm guessing this deals with accessibility the same way most other 'light' UI
toolkits do - by not dealing with it at all?

~~~
chj
How do you handle accessibility across Win/Mac/Linux?

~~~
gnud
Well, you could use Qt...

------
mattlondon
Golang bindings: [https://github.com/golang-
ui/nuklear](https://github.com/golang-ui/nuklear)

Never used it myself, but looks interesting considering the current state of
go's UI programming options (i.e. fairly limited at the moment)

------
hjek
It's even got bindings for Chicken Scheme: [http://wiki.call-
cc.org/eggref/4/nuklear](http://wiki.call-cc.org/eggref/4/nuklear)

~~~
TeMPOraL
Also some for Common Lisp:

[https://github.com/borodust/bodge-nuklear](https://github.com/borodust/bodge-
nuklear)

They are purpose-built for a particular engine though, so I'm not sure how
generally usable they are.

~~~
borodust
This one is a generic but full thin wrapper over Nuklear. It's not tied to cl-
bodge in any way :) [https://github.com/borodust/nuklear-
blob](https://github.com/borodust/nuklear-blob) is an asdf system with
loadable compiled shared libraries for it. Hopefully, it soon will be in the
main quicklisp distribution.

------
pka
> No global or hidden state

Does that mean that one can detach an input field, save its state somewhere,
create a new one and attach it somewhere else again and have it appear exactly
as it was before (i.e. cursor position, selection, focus, etc)?

That's one of the pain points with VDOM frameworks (i.e. need to diff around
UI components which shouldn't lose state), so I'm curious if this library gets
it right.

~~~
TeMPOraL
There is no "input field", the UI state is entirely on your end :).

This is _immediate mode_ UI. It handles inputs and renders simultaneously.
Consider a line from the example in the README:

    
    
      nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
    

That line is responsible for both drawing the slider (at a place determined by
value, with min = 0, max = 1, step = 0.1) _and_ setting the variable `value`
to whatever position user is currently dragging the slider to.

Or:

    
    
      if (nk_button_label(&ctx, "button")) {
            /* event handling */
      }
    

That _simultaneously_ draws the button _and_ executes the conditional if the
button was just pressed.

Immediate mode GUIs are used in games, where you think in terms of drawing
frames, each visible for a fraction of a second. When using such GUI, you
usually "clear" it at the beginning of the frame, feed it with input from
current frame, then build up the UI at the same time as you're drawing it[0].

So basically, you're in total control of the state; there is no persistent
"input field", you recreate it each frame with a function call, and it's up to
you whether or not it's meaningfully the same input field as it was the last
frame.

\--

[0] - most times, like in this case, "drawing" means you "build up" a list of
display commands which then you feed to the renderer at the end - this lets an
immediate mode GUI be independent of whatever graphics library you're using.

~~~
jstimpfle
> It handles inputs and renders simultaneously.

I'm not sure that's the point. I think it's a good idea to decouple input and
output (render).

The point of IMGUI vs traditional toolkits is, I think, rather that you don't
have to communicate through an API to manipulate and sync state with the
framework/library. The latter imposes lots of communication overhead and
second guessing, and can't offer the same level of control.

~~~
billsix
When you say, draw a button in an immediate mode gui, the widget is drawn for
this frame, which has not yet been flushed to the monitor. Yet the draw button
function returns true or false on whether it was clicked. But how can that be,
this button has not yet been flush to the display?

The imgui framework handles the previous frames events when drawing the
current frame.

This implies that the only concept you really need to know using an immediate
mode GUI framework, is that internally to the framework it needs some
mechanism to identify objects between frames.

~~~
mellinoe
> Yet the draw button function returns true or false on whether it was
> clicked. But how can that be, this button has not yet been flush to the
> display?

A button being clicked doesn't really have anything to do with whether it's
been drawn or not. The relevant information is whether the user has hovered
the button with their mouse and (mouse position), and whether the mouse button
is pressed (mouse button state), both of which are usually provided to the
system on a per-frame basis. I've not used Nuklear, but this is how dear imgui
works. If the GUI system knows where you are clicking, and must know the
position of the button it's drawing (in order to render it), then it should be
able to tell if it's being pressed.

~~~
billsix
I am unsure about where we disagree. What you quoted from me was a set up for
my subsequent, unquoted argument.

Buttons don't fly around the screen over time. If a user clicked on the screen
1.0/144 seconds ago (assuming a 144 htz monitor), the user likely clicked on
the button which is about to be redrawn.

~~~
mellinoe
I guess I don't understand why this would be true:

> The imgui framework handles the previous frames events when drawing the
> current frame.

I'm not terribly familiar with the inner workings of these libraries, though,
so I could be wrong. Since you pass in the input state for each frame, it's my
understanding that they just process the current frame's "events" during that
frame. It would be a little weird if you passed some mouse click event into
the system and your Button() call returned true the NEXT frame (I think that's
what you're suggesting).

~~~
billsix
That is what I'm suggesting.

Before I used immediate mode GUIs, I was familiar with using Qt, wx, and gtk.
Never did X windows. So I never handled events directly, just indirectly
programmed what would happen upon the event occuring.

I had been under the likely incorrect assumption that those frameworks, in
order to correctly associate say a mouse click to a button, had a mapping of
the previous frame's screen-space coordinates of all widgets, and when a click
happened, they associated the click with the previously drawn widget. Because
that is what was on the screen when the mouse was clicked.

Immediate mode GUIs baffled me. How could the drawing of a button, which has
not yet been flushed to the monitor, return true or false depending upon
whether or not it was clicked? The button is not yet on the monitor!!! After
thinking about it for 10 minutes, buttons don't fly all over the screen.
Whatever the bounding box for the button for this frame is likely the bounding
box it had last frame. So the association is easy, assuming the imgui
framework can keep track of object identity across frames.

Perhaps, I am just ignorant of how qt, gtk, and wx, actually work.

------
billsix
For python fans, I've been working on pyNuklear

[https://github.com/billsix/pyNuklear](https://github.com/billsix/pyNuklear)

~~~
technomalogical
My first thought: I wonder if I can invoke this with ctypes from Python? I'll
check this out, thanks!

~~~
billsix
My plan of action is result-driven: incrementally port nuklear's demo
overview.c file to python. Each new piece of that requires adding more ctypes
bindings.

Help/patches are welcome, as I only have limited free time to implement this.

------
ericjang
Nice. I also recommend checking out Nanogui (C++) by Wenzel Jakob:
[https://github.com/wjakob/nanogui](https://github.com/wjakob/nanogui)

~~~
billsix
The reason that I love immediate mode GUIs like nuklear and dearimgui is that,
unlike callback based GUIs like nanogui, qt, gtk, wxwidgets etc, I do not need
to learn how the framework Works internally in order to use it effectively.

The lack of callbacks in particular, means that I do not need to worry about
memory management very much. Or, I should say, I don't have to defer memory
management to later.

I own books on wxwidgets and on qt. To be honest, although I've read them
fully, I still don't quite know how to use them well, nor how would I teach
teammates how to even if I did.

Using a tool like dearimgui or nuklear, I have no books, but 95% of the time I
can just copy example code from the demo into my app, modify it slightly for
my needs, and call it a day.

------
mwcampbell
Before you use this in your next important application, please read the
comment on accessibility that I posted the other day on the LCUI thread:
[https://news.ycombinator.com/item?id=16329640](https://news.ycombinator.com/item?id=16329640)

~~~
bastijn
Accessibility is always important to mention, which is why we should thank you
for reminding us. In return, you have to understand that not every next
important application will be used by blind people or people with
disabilities, and as of such there is still room for people to develop new UI
toolkits if they so please.

Again, thanks for reminding everybody. People need to think about it. Your
advice could be toned down a bit to “please think about your audience, if you
expect people with disabilities to be part of it think twice when making your
own UI toolkit, or at least factor in the costs to build in accessibility
features.”

~~~
mwcampbell
Thanks for your feedback. I do try to control the tone of my comments on this
subject, because I get emotional about it, but I know a vitriolic comment
isn't helpful. Still, I find it hard to moderate the scope of my advice.
Several years ago, a blind acquaintance of mine briefly lost his job because
some developer didn't pay enough attention to accessibility in an application
that he was required to use. His employer re-hired him shortly afterward,
because they found another role for him. But in the interim, he went through
all the feelings associated with losing one's job, and he was lucky to regain
employment so soon. I don't ever want anyone to go through that again because
some developer used an inaccessible GUI toolkit, even if that toolkit was
meant only for games. That's why I'm as vocal as I am here.

~~~
billsix
> Several years ago, a blind acquaintance of mine briefly lost his job because
> some developer didn't pay enough attention to accessibility in an
> application that he was required to use

Can you explain in more detail? As a person ignorant of these types of issues,
I'm having a hard time understanding the connection between the lack of
accessibility in an app to the firing of a blind employee.

~~~
mwcampbell
Sure. We're getting off on a tangent now, but I guess that's why people can
collapse subthreads.

Here's what happened as I remember it. The blind employee, Darrell, was
providing technical support for a client company on behalf of his employer. At
some point after he had taken on this role, the client added a requirement
that anyone who worked with them had to use the Seibel CRM system in "high
interactivity" mode. If I recall correctly from talking to Darrell, the high
interactivity version of Seibel at this time (2006) used the Microsoft JVM.
That, combined with the fact that the app implemented some custom controls
with no regard for accessibility, made it completely unusable to him. So his
employer laid him off. Luckily for him, they rehired him shortly after that,
but only because they found a whole new role for him. One can question whether
the real problem was the app developer, the client, or the employer. But the
inaccessibility of the app was a critical factor.

------
ComputerGuru
Reposting from a previous thread:

I have not had a chance to try it out for myself yet, but I have recently
learned that webkit includes a direct-to-opengl renderer such that one can
skip the Qt or GTK backend and write HTML/CSS/JS that outputs to the
framebuffer directly.

------
skibz
An earlier discussion:
[https://news.ycombinator.com/item?id=11522452](https://news.ycombinator.com/item?id=11522452)

~~~
book_mentioned
Most likely re-submitted after being mentioned 2 days ago.

[https://news.ycombinator.com/item?id=16327918#16328912](https://news.ycombinator.com/item?id=16327918#16328912)

------
niutech
Check out these alternative C++ GUI libs running in a web browser using
WebAssembly:

\- AssortedWidgets: [https://shi-yan.github.io/AssortedWidgets/](https://shi-
yan.github.io/AssortedWidgets/)

\- Dear ImGUI:
[https://pbrfrat.com/post/imgui_in_browser.html](https://pbrfrat.com/post/imgui_in_browser.html)

------
frostburg
I used it once to provide a simple GUI for a some simulated annealing I had
written in C, was more straightforward than I expected.

------
thecodeboy
Wow! This is the first time I'm seeing a project having two licenses. MIT and
unlicense. You can choose whichever you want.

------
akmittal
It looks quite nice also. Last time I saw it I wanted to port to to Go(not
bindings) but could not find details docs about implementation. Anyone know
how it is drawing OpenGL or native?

~~~
badsectoracula
It is API agnostic, you have to provide the functionality. There are some
examples using various APIs here:
[https://github.com/vurtun/nuklear/tree/master/demo](https://github.com/vurtun/nuklear/tree/master/demo)

------
FraKtus
I love it because I can write applications for iOS macOS android windows and
have most of the code identical. There is no need of resources to make that
easy. Almost too good to be true.

~~~
FraKtus
I could make an iOS application that is only 1 MB in size thanks to Nuklear..
More and more users will not want to try an app if it feels bloated. Nuklear
allows to generate tiny binaries, I appreciate that.

------
faragon
Amazing. A great candidate to be included into suckless.org [1], in my
opinion.

[1] [https://suckless.org/rocks](https://suckless.org/rocks)

------
alok-g
Question: How easy or difficult would it be to make responsive UI's with this?

Also, what would the performance be like as compared to native OS GUI
controls?

------
aphextron
Is there a good reason for having logic in an H file?

~~~
rightbyte
Nope, but less typing of #include:s? Easier to send by mail? He seems to use
defines to keeps function and variable definitions to one in the program it's
included in.

------
random_upvoter
As a small criticism, looking at the project page I get no clue whether this
library works on Microsoft Windows.

~~~
billsix
Yes it works on windows.

Hopefully this does not come across as rude, but from the readme

"It was designed as a simple embeddable user interface for application and
does not have any dependencies, a default renderbackend or OS window and input
handling but instead provides a very modular library approach by using simple
input state for input and draw commands describing primitive shapes as output.
So instead of providing a layered library that tries to abstract over a number
of platform and render backends it only focuses on the actual UI."

Under the demo folder, there are examples.

Nuklear works with opengl 2 and 3 both with sdl2 and glfw (both of which
support windows) it works with direct 3d 9 and 11, with gdi (windows specific
libraries)

~~~
random_upvoter
Yes, I did see the readme and I do remember thinking "so does this means it
runs on Windows as well?". It's not unheard of for linux-specific projects to
simply ignore the existence of Microsoft world.

So I cloned the repository and opened up nuklear.h. If this library supports
Windows, then CERTAINLY this file has to include "Windows.h", somewhere,
right? Uhm.. no, it does not. Bad sign, I thought.

So, still confused, I thought "so let's look into this folder called
"example". I look into canvas.c and I notice "#include <GL/glew.h>". So I
thought "Oh dear, this is gonna be a bother to compile on Windows, forget it".
As luck would have it, I never looked into the folder called "demo".

So at that point I honestly believed that this library was only sort of "semi-
supported" on Windows, as often happens with these kind of projects. You know,
the usual "if you're a bit of a masochist and you're willing to muck around
with mingw and download glib.tar.gz stuff, you may get this to work". The fact
that the GUI has a definite linux look reinforced that impression.

What I'm saying is, all my confusion could have been solved by just one line
in the readme explicitely stating "this builds on Microsoft Windows using
Visual Studio and a direct X backend, etc...". A little bit of redundancy, it
helps sometimes.

~~~
merlish
That would be a bit inaccurate though - the core library doesn't have a
backend. The example you found e.g. implements an OpenGL backend.

It doesn't reference any external libraries (maybe C runtime). IIRC it does
not assume you have a malloc() function by default; you provide one or use a
#define before include to tell the header it can rely on standard malloc.

------
xmichael99
C# Wrapper please!

~~~
merlish
There should be a link on the page. I started binding it to C# over Christmas
out of frustration of one not existing, and someone else quickly picked it up
and made a cleaner binding that I recommend more. Google NuklearDotNet for the
latter.

------
akvadrako
You can't build a "ANSI C GUI library", because ANSI C has no graphical
capabilities.

~~~
badsectoracula
You can if you rely on the library's users to provide the non-ANSI
functionality (like Nuklear does - you have to provide the graphics and input
functionality).

~~~
akvadrako
I would say the requirements of the functionality you have to provide define
what kind of library it is. It's a very different thing if it's a raw
framebuffer, OpenGL context, Carbon API, a terminal or something like WASM.

