
Nuklear: A small ANSI C GUI toolkit - ingve
https://github.com/vurtun/nuklear
======
stonogo
Shame that you specify pixels in the function calls themselves. If it were
really abstracted, it would have an arbitrary 'size unit' which the glue code
could translate on the backend.

In a world where one user has a 1366x768 screen and her neighbor has a 4k
display, we need to move past interface code specifying pixel sizes up front,
both on the web and off.

~~~
unexistance
I always have an idea in my mind that we should scale / show the interface
based on font-size, adjusting borders / button accordingly

p/s: obviously I have NO idea how easy / complex this would be, just an idea
given that sometimes text contained in an element bleeds / overflows /
outright missing

~~~
ktRolster
Problem is, we still have jpgs. As long as we have raster images (instead of
vector images), we'll be laying some things out based on pixels.

And as long as we have photographs, we're going to have raster images, for the
foreseeable future.

~~~
adrianN
Rasterizing vector images to different sizes without getting blurry results is
not trivial.

~~~
iso-8859-1
If all targets have a relatively high DPI, does that still hold? Wouldn't it
be more correct to say "it isn't trivial to rasterize vector images for low-
DPI displays?"

------
richard_todd
It looks cool, though the claim about having no platform dependent code must
be false... either they have it or they depend on someone who does. Since it's
all in one file and I'm on an iPad right now, I didn't try to discern which
case it is.

What is the appeal of the implementation hiding in the header file? Is it a
'thing' nowadays? It makes every file that includes it read all 15k lines, and
makes you put a special #define in one of your source files, just to avoid
having a C file. That doesn't feel like a good trade-off to me. If I used this
code in a project, I'd build a static library out of it first thing, and go
about my business.

~~~
flohofwoe
Sean Barrett (of stb headers fame) has written about the reasons for header-
only libraries here:

[https://github.com/nothings/stb/blob/master/docs/stb_howto.t...](https://github.com/nothings/stb/blob/master/docs/stb_howto.txt)

If compile-time is a concern (it isn't in my experience, at least if the rest
of the project is C++ code), you can still wrap the library-header into your
own header and put include-guards around it :)

PS: also see here: [https://github.com/nothings/stb#why-single-file-
headers](https://github.com/nothings/stb#why-single-file-headers)

~~~
Avshalom
Because apparently archived files are just too much for Windows devs?

~~~
flohofwoe
Did you ever try to link with externally compiled libraries on Windows? :)

It's an absolute mess, the lib files are incompatible between Visual Studio
versions, whether threaded/non-threaded/DLL/static MSVC runtime is used,
whether linktime-code-generation is used, if there's C++ code in it, a release
lib cannot be linked against a debug executable, etc etc etc...

Only sane solution is to drop the sources directly into your project. Whether
it's just a header or a header/source pair is just a small detail, admittedly.

~~~
richard_todd
Putting external library source files directly into my project does not sound
sane at all, and it is definitely not the only option for static libs on
Windows. You can also make the library project a component of your solution,
and add a reference to it in dependent project(s). That way, they have proper
separation but are all built from source.

Having now read the rationale for single header libraries, I am completely
unconvinced. These people either don't know how their tools work, or are
making bad choices to coddle people who don't. Even forgetting the wasted time
parsing the #ifdef'ed out implementation section over and over, it screws up
separate compilation. Every time you tweak the implementation section, all the
files that #include it will recompile for no good reason.

~~~
flohofwoe
I was convinced of the header-only approach when I replaced DevIL, libpng and
libjpeg (all of them made of a myriad of source files and build options, not
to mention using non-portable build systems that don't really work out of the
box on Windows) with 3 stb headers: stb_image.h, stb_image_resize.h and
stb_image_write.h

Even if the compile time is affected (which I never noticed) this is only a
minor inconvenience compared to the wins those 3 header files provide.

~~~
acqq
It's not either "build-system dependent mess" or "everything in header." The
alternative to "everything in header" is "header file has interface, .c file
has implementation." Then you add the .c file to your project, include the .h
file, and it works better than "everything in .h" since instead of 20,000
lines all other .c files in user projects have to see only a few hundred
lines, which compiles faster. And that's how C projects were supposed to be
organized since the beginnings. You don't have to have dynamically bound files
if that isn't needed. Some licenses insist on dynamical linking, but when you
make your library, your decisions on how it's linked are independent of your
decision to stuff the implementation in .h.

------
atemerev
An alternative (in C++, but with C API maintained):

[https://github.com/ocornut/imgui](https://github.com/ocornut/imgui)

~~~
aoloe
the difference being that, when i saw nuklear's README, i just wanted to learn
enough C to be able to use it... with imgui the first reaction was (the first
time i saw it), that i won't be able to use it for software targeting non-
geeks. (and i really would like to have a good lightweight UI framework for
C++!)

it might be just the screenshots, i've not tried any of both, but comparing
the two README files, i cannot say that they are real alternatives.

even if -- very likely -- both are very good toolkits!

------
swah
A really enjoyable talk on the topic by Casey Muratori
([http://handmadehero.org](http://handmadehero.org)):
[http://mollyrocket.com/861](http://mollyrocket.com/861)

------
buserror
Looks like a great piece of tool! Very often you want to throw something
together and the development grind to a complete halt because having to fiddle
with the UI integration. Problem solved!

X11 example doesn't seem to run here, on my debian sid+nvidia blobs drivers.
The GL* do work tho, abeit with un unreadable font (I'm on a 32" 3180x2160
screen)

X Error of failed request: BadMatch (invalid parameter attributes) Major
opcode of failed request: 70 (X_PolyFillRectangle) Serial number of failed
request: 29 Current serial number in output stream: 102

------
wtbob
Really pretty. Given how small it is, I wonder how difficult porting it to
other languages would be; it might make a decent little reference spec for
lightweight GUIs.

------
dmytroi
Would be awesome to combine it with something like
[https://bitbucket.org/rmitton/tigr](https://bitbucket.org/rmitton/tigr) which
is a small and tidy window creation/input processing lib, because I find glfw
and SDL too bulky for casual C/C++ programming.

~~~
vurtun
There is nothing really dependent on any of the provided demos. As long as you
are able to provide an OS window, input and a way to either draw basic shapes
or vertexes you are good to go.

------
hardwaresofton
Rust bindings might solve rust's lack of a prominent GUI toolkit...

Or a straight port to Rust (either imgui or nuklear)

~~~
FreeFull
Rust has GTK and qtquick bindings, and there is also
[https://github.com/pistondevelopers/conrod](https://github.com/pistondevelopers/conrod)
which also uses immediate mode. Nuklear looks like it's more capable right now
than conrod, though, so Rust bindings could still be good to have.

------
chris_wot
In case anyone wants to see a C++ framework that evolved over time and then
was inextricably tangled up in the one application that really used it, check
out OpenOffice/LibreOffice's Visual Component Library (VCL).

A demo program can be found here:

[https://cgit.freedesktop.org/libreoffice/core/tree/vcl/workb...](https://cgit.freedesktop.org/libreoffice/core/tree/vcl/workben/mtfdemo.cxx)

A more complex, feature complete demo can be found here:

[https://cgit.freedesktop.org/libreoffice/core/tree/vcl/workb...](https://cgit.freedesktop.org/libreoffice/core/tree/vcl/workben/vcldemo.cxx)

------
ktRolster
When I look at GUI APIs, the first question I ask is, "How easy is it to get
things where I want them on the screen/page?" Because that is the fundamental
problem for any layout engine.

~~~
Keyframe
That's an easy question to ask if you know the screen aspect and resolution.
What if you don't know either or both? The question suddenly shifts to "Where
do I want things on screens?" and suddenly it's not about library anymore.

~~~
ktRolster
_That 's an easy question to ask if you know the screen aspect and
resolution._

Surprisingly, in a lot of GUI libraries, it's not an easy thing.

------
generic_user
This looks quite nice. But they did fib a bit about no dependencies. It is
apparently built on top of GLFW3 which is a nice, small C library that gives
you a native window and input handling.

~~~
i336_
There's also a pure X11 version, which only pulls in what X requires:

    
    
      $ make
      gcc main.c -std=c89 -pedantic -O2 -D_POSIX_C_SOURCE=200809L -o bin/zahnrad -lX11 -lm
      $ ldd bin/zahnrad 
               linux-vdso.so.1 (0x00007ffe32df9000)
               libX11.so.6 => /usr/lib/libX11.so.6 (0x00007f8468746000)
               libm.so.6 => /usr/lib/libm.so.6 (0x00007f8468441000)
               libc.so.6 => /usr/lib/libc.so.6 (0x00007f84680a0000)
               libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00007f8467e7d000)
               libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f8467c79000)
               /lib64/ld-linux-x86-64.so.2 (0x00007f8468a88000)
               libXau.so.6 => /usr/lib/libXau.so.6 (0x00007f8467a75000)
               libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00007f846786f000)

~~~
generic_user
Cross platform is a key feature. Thats why glfw is so nice. Unless you want to
write the grungy windows bits for all your platforms I don't see any problem
with useing glfw. Its a solid library.

~~~
flohofwoe
GLFW is great, but it's limited to GL or Vulkan as 3D backend. There's a
context-less mode now (created for Vulkan I think), but I haven't seen GLFW
used together with D3D or Metal yet. It's fairly easy to rip the relevant
window- and input-handling code out though.

------
gjem97
A couple of tweaks needed to get the example in the README to compile: wrong
number of arguments in call to nk_button_text(), and need to take the address
of ctx in the call to nk_end().

------
iso-8859-1
Can I use this on DOS? I am looking for a successor for [http://intron-
trans.hu/agui.html](http://intron-trans.hu/agui.html)

~~~
joeld42
Yes, you'd have to implement the drawing and input handling code but this
seems like it would be a good fit. You need to implement a fair number of
drawing primitives, but certainly less work than a whole GUI.

------
cm3
I haven't tried this one yet, but I've tried another immediate mode ui library
before and it seemed to busy loop a single cpu core. Is that normal for IM
GUIs?

~~~
protomikron
You may test it. It is straight-forward do build, e.g. I tested the sdl2 demo
(demo/sdl/) and CPU usage was <10%.

I did not dig further, but I like the general idea, as GUI toolkits are
biiiiig.

~~~
cm3
I'll give it a try but <10% for an otherwise idle gui sounds like an
architectural flaw/disadvantage. An idle gtk2 window sits at 0% cpu.

~~~
cm3
Tried and it's 2%. Not quite gtk's 0%, but better than my last test of an
immediate mode ui.

------
paulofalcao
Another cool one
[https://github.com/fruxo/turbobadger](https://github.com/fruxo/turbobadger)

------
netgusto
Any hint on how to compile any of the demos on OSX ?

~~~
fdb
I've got it running on OS X with some modifications:

\- In the Makefile, use

    
    
      LIBS = -lglfw3 -framework OpenGL -lm -lGLEW
    

\- In the main.c file of the project, change headers to use <OpenGL/gl.h> and
<OpenGL/glu.h>

\- In the shader code, change "#version 300 es" to "#version 400" for both the
vertex and fragment shader.

I'll try to make a PR with conditionals if I can find the time today.

------
kazinator
"Use at your own risk" is not an adequate license, I'm afraid.

Someone concerned about licensing can't touch this with a ten foot pole.

~~~
iso-8859-1
What do you mean? It says public domain in the README.

------
chmike
Unfortunately, the font looks very fuzzy (out of focus) when running the
extended example. Is there a way to fix that ?

------
ktRolster
nuklear.h is 20,000 lines long. Is the whole thing written in the header file?

~~~
mmozeiko
Yes! [https://github.com/nothings/stb#why-single-file-
headers](https://github.com/nothings/stb#why-single-file-headers)

~~~
optforfon
I'm confused by the reasoning... why can't you just statically link your
distributed exe?

~~~
joeld42
Static linking is "easy" on any particular platform for a particular target.
But build systems and IDE and all that junk make things more complicated. You
might want to build the library with the same flags as your main app, for
example. You might have several target architectures you need to build and
link against (i386, x64, amd) x (debug, release, QA). Etc, etc.. It also makes
it easier for the compiler to inline things.

Header only libs just make all these problems go away, and (IMO) there's not
really any downside.

~~~
DSMan195276
> and (IMO) there's not really any downside.

Well, the downside is that it's literally in _one_ header file. Besides being
gigantic, it's extremely annoying to search and parse by hand - this is an
issue when that's also serving as the documentation. Especially in this case,
it would be much nicer to have a "nuklear" folder with a bunch of separate
(appropriately named) headers. The single `nulkear.h` header could just
`#include` them as necessary.

~~~
CamperBob2
It's a lot easier to search and comprehend 20,000 lines in one header file
than 1,000 lines in each of 20 separate header files.

~~~
DSMan195276
I respectfully disagree. If they are separated into thoughtful modules, then
it would be much easier to parse by simply looking at the file and folder
names and going from there. This will especially be true when this expands
past it's current state, and it becomes impossible (Or more impossible) to see
what uses what.

IMO, 20,000 is already way to much, but when that reaches 100,000 even just
editing it will be a chore, let alone using it. It will simply be
unmaintainable and unusable. I say this having worked on code bases which have
reached that point and attempted to deal with the issues it creates. There's a
reason every decently sized code base out there uses multiple files and a
hierarchy. It's a natural way to create modular code, and modular code is
simply better code.

~~~
CamperBob2
It depends on the editor, I think. It's criminal that so many editors still
can't do what BRIEF did 20+ years ago, and give you a quick and easy way to
surf through all C/C++ functions in the current translation unit. (e.g.,
[http://i.imgur.com/dmlCCpH.png](http://i.imgur.com/dmlCCpH.png) ).

That's why I still use a buggy BRIEF clone instead of a modern IDE. If I were
forced to use someone else's idea of a code browser that was architected
around files rather than subroutines, I'd probably be more inclined to agree
with you.

The idea that the most appropriate way to organize source code happens to
correspond to something that a (likely-long-dead) OS implementer chose to call
a "file" is a notion that doesn't get challenged often enough.

~~~
ktRolster
Eclipse does that.

~~~
CamperBob2
Yeah, there are plenty of editors that do, but none that I'd want to use on a
day-to-day basis.

------
joeld42
Nice job! This looks great.

------
ausjke
the SDL demo has lots of dependencies obviously, so it's really not something
self-contained. I'm always excited any neat GUI for C, but this one seems like
just a layer on top of existing GUI libraries, what's special about it? Please
shed some light.

If it's really light-weight and self-contained it will be very useful for some
embedded systems with a screen.

    
    
      $ldd bin/demo 
    	linux-vdso.so.1 =>  (0x00007fff46f49000)
    	libSDL2-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0 (0x00007f3587140000)
    	libGL.so.1 => /usr/lib/fglrx/libGL.so.1 (0x00007f3586f5e000)
    	libGLEW.so.1.6 => /usr/lib/x86_64-linux-gnu/libGLEW.so.1.6 (0x00007f3586cf2000)
    	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3586934000)
    	libasound.so.2 => /usr/lib/x86_64-linux-gnu/libasound.so.2 (0x00007f3586647000)
    	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f358634a000)
    	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f3586146000)
    	libpulse-simple.so.0 => /usr/lib/x86_64-linux-gnu/libpulse-simple.so.0 (0x00007f3585f42000)
    	libpulse.so.0 => /usr/lib/x86_64-linux-gnu/libpulse.so.0 (0x00007f3585cf9000)
    	libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f35859c4000)
    	libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f35857b3000)
    	libXcursor.so.1 => /usr/lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007f35855a8000)
    	libXinerama.so.1 => /usr/lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007f35853a5000)
    	libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f3585195000)
    	libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007f3584f8c000)
    	libXss.so.1 => /usr/lib/x86_64-linux-gnu/libXss.so.1 (0x00007f3584d88000)
    	libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f3584b83000)
    	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3584965000)
    	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f358475d000)
    	libatiuki.so.1 => /usr/lib/fglrx/libatiuki.so.1 (0x00007f3584640000)
    	/lib64/ld-linux-x86-64.so.2 (0x00007f3587469000)
    	libpulsecommon-1.1.so => /usr/lib/x86_64-linux-gnu/libpulsecommon-1.1.so (0x00007f35843e1000)
    	libjson.so.0 => /usr/lib/x86_64-linux-gnu/libjson.so.0 (0x00007f35841d9000)
    	libdbus-1.so.3 => /lib/x86_64-linux-gnu/libdbus-1.so.3 (0x00007f3583f94000)
    	libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f3583d76000)
    	libXrender.so.1 => /usr/lib/x86_64-linux-gnu/libXrender.so.1 (0x00007f3583b6c000)
    	libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f3583965000)
    	libwrap.so.0 => /lib/x86_64-linux-gnu/libwrap.so.0 (0x00007f358375c000)
    	libsndfile.so.1 => /usr/lib/x86_64-linux-gnu/libsndfile.so.1 (0x00007f35834f5000)
    	libasyncns.so.0 => /usr/lib/x86_64-linux-gnu/libasyncns.so.0 (0x00007f35832ef000)
    	libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f35830ec000)
    	libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f3582ee5000)
    	libnsl.so.1 => /lib/x86_64-linux-gnu/libnsl.so.1 (0x00007f3582ccb000)
    	libFLAC.so.8 => /usr/lib/x86_64-linux-gnu/libFLAC.so.8 (0x00007f3582a81000)
    	libvorbisenc.so.2 => /usr/lib/x86_64-linux-gnu/libvorbisenc.so.2 (0x00007f35825b1000)
    	libvorbis.so.0 => /usr/lib/x86_64-linux-gnu/libvorbis.so.0 (0x00007f3582385000)
    	libogg.so.0 => /usr/lib/x86_64-linux-gnu/libogg.so.0 (0x00007f358217e000)
    	libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f3581f61000)

~~~
flohofwoe
I have only experience with dear-imgui so far (mentioned in the readme), but
nuklear should be very similar in its requirements. You basically just need a
GL context (or other 3D APIs equivalent) to write a wrapper for, SDL is sort
of overkill for this.

In my case I integrated imgui with my "weekend engine" Oryol, which has a very
slim wrapper around 3D APIs, and I have this running in WebGL (via emscripten)
and GLES2 on Raspberry Pi 2 (should also work on the original Pi). The
resulting executables are small enough for most 32-bit embedded platforms (a
couple hundred KBytes), and have a much shorter list of system dependencies.
On Raspberry Pi it doesn't even need a window system, it runs straight from
the Linux terminal and uses the Pi's EGL wrapper.

For instance here's the WebGL imgui demo (325 kByte):
[http://floooh.github.io/oryol/asmjs/ImGuiDemo.html](http://floooh.github.io/oryol/asmjs/ImGuiDemo.html)

~~~
ausjke
cool, checking it out now

------
b6
The author of Nuklear mentions it in the readme, but in case people don't spot
it, there's another cool project in this family, imgui:
[https://github.com/ocornut/imgui](https://github.com/ocornut/imgui)

------
jlebrech
It would be nice if a GUI toolkit just targeted ncurses and you could further
skin it to run in the browser, gtk or kde separately. a bit like react-native.

~~~
funkaster
well, this library seems to be render agnostic:

[https://github.com/vurtun/nuklear/blob/master/nuklear.h#L133...](https://github.com/vurtun/nuklear/blob/master/nuklear.h#L1338)

So _in theory_ you could just write the rendering code for ncurses, browser,
etc.

------
aceperry
I'm glad they didn't name it "nu-kew-lar."

