
Puny GUI – A tiny cross platform GUI Kit in Janet - ahungry
https://ahungry.com/blog/2020-04-24-Puny-GUI-Puppy-Finder.html
======
overgard
GUI frameworks are big because they do a lot. These minimalist things usually
only work until you reach the limits of what they can do and then you have to
rewrite in something like Qt anyway, or sacrifice what your users want in a
GUI for your own code aesthetics.

~~~
davidcuddeback
It’s be helpful to have some concrete examples of where one might run into
limits with the minimalist frameworks and why a larger framework is required
to overcome those limits.

~~~
overgard
file open/save dialogs, i18n, drag and drop, image formats, web views, any
sort of accessibility, themability that actually fits into native platforms,
sometimes the ability to open new windows, many common controls that we just
take for granted now that you have to implement yourself, sometimes limited
amount of events you can reasonably handle based on the design of the api (IM
gui's for instance).

I wouldn't say never use an minimalist framework. It can be handy for embedded
debugging tools or for toy projects. But I wouldn't use one of these things
for an application that I thought might have a few thousand users and some
sort of life span.

~~~
davidcuddeback
Thanks for the list. I'll keep these in mind for my next GUI project. I've
used Qt a few times for hobby projects, but was thinking about trying
something else for my next GUI project.

------
FraKtus
I disagree with the author, it's really easy to test the examples of Nuklear.

I made applications with Nuklear that runs on Android, iOS, macOS, Windows and
share the same main C code. For me, it's a dream come true if you create a
cross-platform application that needs a simple GUI.

Dear ImGui is also fantastic and more complete than Nuklear.

What I like a lot with Nukear and Dear Imgui is that you have a GUI that is
GPU accelerated and so can be updated at 60 FPS without burning resources.

~~~
DagAgren
You're still going to be updating at 60 FPS which will absolutely murder your
battery on a mobile device.

These are meant for use in games that already do this. They are not suitable
for building regular apps.

~~~
maeln
They are perfectly suitable for regular app. You don't need to update them at
60fps, you have the entire control of the rendering state, so you could decide
to update the gui whenever it is needed and not at a constant fps.

------
pierrec
" _The solution (hint: there wasn 't one until now)..._" That's quite the bold
statement. I actually thought of IUP/Lua when I saw this line, and it turns
out you precisely used IUP for the UI portion of your framework! Except you
didn't use the Lua binding, instead you created a Janet binding.

Using something like luastatic[1], with whatever Lua libraries you want
(including IUP), you can get something pretty similar to this system, except
of course you'd be using Lua instead of Janet. Janet is really interesting and
that alone justifies this framework very well.

[1]: [https://github.com/ers35/luastatic](https://github.com/ers35/luastatic)

~~~
ahungry
Yea, sometimes when I get to rambling I can be a little bit overly
opinionated/bold in some statements. Python tktinkter is also in a similar
vein - what I am putting out is more of an aggregation of other's hard work
(cross platform packaging?) more so than anything I've directly innovated.

However, even in the python sample, I couldn't find anything that was just
"Download, Unzip, Modify" to start creating (all seem to have cumbersome
install steps or hoops to jump through - I basically wanted something that was
0 configuration/installation, for fast iteration and development).

~~~
macmac
Speaking of aggregation, what motivated the license choice? It appears that
only one dependency (Mongooos is GPL), and the choice of GPL will seriously
inhibit any adoption of a toolkit like this.

~~~
ahungry
I may replace mongoose and change license when done to MIT (pending completion
of work on my own much smaller server implementation)

------
liuliu
Seems to be based on iup that supports both Windows and Linux?
[http://webserver2.tecgraf.puc-rio.br/iup/](http://webserver2.tecgraf.puc-
rio.br/iup/)

The new crop of immediate mode cross platform GUI libraries are more
interesting (such as nuklear and Dear Imgui). I also did some experimentation
with these libs a few days ago: [https://liuliu.me/eyes/write-cross-platform-
gui-in-swift-lik...](https://liuliu.me/eyes/write-cross-platform-gui-in-swift-
like-it-is-1998/)

~~~
mwcampbell
> The new crop of immediate mode cross platform GUI libraries are more
> interesting (such as nuklear and Dear Imgui).

They're also completely inaccessible to blind people (using screen readers)
and probably some people with other disabilities as well. IUP is at least
partially based on platform controls. I'll take usable over interesting.

~~~
flohofwoe
This wouldn't be a problem if the underlying operating system APIs wouldn't
treat accessibility as an opaque "feature" baked into their UI frameworks.

There should/could be open accessibility APIs in each OS which sit between
(e.g.) screenreader software and custom UI frameworks.

~~~
mwcampbell
Some platforms do have APIs like that. For example, on Windows, UI Automation
is not tied to any particular UI framework; the UIA tree just needs to be
associated with an HWND (Win32 window handle). But implementing these APIs is
a lot of work. And I imagine it would be especially challenging for an
immediate-mode toolkit, because an API like UI Automation is based on a
retained tree of objects that the screen reader or other assistive technology
can query on demand. So I figure applications are more likely to be accessible
if I warn developers away from such toolkits altogether.

------
csb6
For anyone needing a simple and fast cross-platform toolkit for C++, FLTK is
really good. It is easy to build and statically link only the parts you need,
and the API/widget selection is pretty good. It looks a little old
school/non/native, but it has been useful for me.

~~~
Rochus
FLTK is just very spartan compared to e.g. Qt; from my point of view it is
only useful for very simple GUIs; I hardly have any applications anymore that
do not need item views or rich text.

~~~
MaxBarraclough
If you want a halfway house, there's the FOX Toolkit. [http://fox-
toolkit.org/](http://fox-toolkit.org/)

It's not so active these days, admittedly.

~~~
Rochus
Well, there is also Tcl/Tk and some others, but they are all at most half as
powerful as Qt. An interesting alternative could be Flutter; however, you have
to write (at least) the GUI in Dart, which is not everyone's cup of tea.

~~~
MaxBarraclough
TCL is interpreted, so presumably it's not as lightweight as FLTK and FOX. I
don't imagine Flutter is nearly as lightweight either.

~~~
Rochus
Tk is just a shared library accessible by any compiled language; there are
many C/C++ cross-platform applications using it; it was actually also the
first GUI toolkit used by Python; it's true that it includes Tcl which is a
scripting language, but that doesn't matter much. It's nearly as lightweight
as FLTK and Fox toolkit.

Applications AOT compiled with the Flutter SKD are surprisingly lean (i.e.
compared to Node/Electron) and not much larger than Qt applications.

------
vidugavia
Cool. I fell in love with Janet during last advent of code, so I'll definitely
give it a try

------
ashkankiani
With opengl, libuv, and libcurl, and Dear Imgui, I can write a C program
resulting in a binary that's about 400kB unstripped, to put 5MB in
perspective. And for a simple program like what you wrote, I don't even bother
trying to free the memory myself sometimes, I just let the OS free it when I
exit. With that design choice in mind, the end code is like <1000 lines, and a
decent bit is reused snippets.

In the end, this feels like a an appraisal of IUP and Janet more than a demo
of anything new. If that's the case, then familiarity with your stack is more
important for this kind of productivity than anything else, so trying
something new is less appealing to me.

But I was curious about Janet, so seeing some examples was nice.

~~~
ahungry
Dear imgui looks very cool (I had missed that one), and like nuklear, a strong
candidate for very customized look and feel - but I think it glosses over
things much like nuklear does, by showing what seems to be small/simple
samples, and prefixing it with a statement such as "after it's set up" (and it
doesn't bother to show the other 1000 lines said setup required).

But you are spot-on that this is more showcasing the joining of various other
things out there, rather than anything innovative (although I do plan to add
more and extend the existing convenience wrappers, such as wrapping the IUP
calls in a hiccup-like DSL using Janet macros).

~~~
exDM69
Those "1000 lines of boilerplate" is why imgui and nuklear are so popular. If
you're on a commonly used platform, say SDL and OpenGl, you can just copy all
or most of it. But the magic here is that imgui and nuklear will integrate
into any engine or rendering api you can imagine.

To simplify a little, you pass these libraries the events from the windowing
system and it gives you a list of triangles back. Then you feed the triangles
to the GPU and you're done. All the logic (and nothing but the logic) is done
by the GUI library.

This is why dear imgui is perhaps the most popular GUI library in the world.
It's used in a lot of game development tools, etc.

If anyone is interested in the topic, I am writing a lightweight flexbox-based
retained mode GUI layout rendering library that integrates like imgui/nuklear.
Give me a shout if you want to know more.

~~~
pinum
I'm interested!

~~~
exDM69
I haven't shared the code in public but if you give your GitHub username, I
can share it to you (and others who are interested) and you can reach out via
email (address in commit log).

I got inspired by Raph Levien's talk on Rust and GUI layout [0] and realized
that a simple flexbox layout algorithm can be implemented really efficiently.

So I started making a prototype in C (also a small proto in Rust), using a
densely packed array to implement a DOM-like tree. The tree nodes have short
strings, boxes (with border, padding, etc), images (texture coordinates in an
atlas), layout constraints, containers, etc. Flexbox layout is applied to the
tree in linear time (and constant memory!) and then the tree is traversed to
output an ordered list of axis aligned rectangles.

The output list can be fed to the GPU, where a special (but simple) shader
draws clipped triangles that get applied with textures, msdf font, etc. The
whole GUI gets rendered with a single draw call.

This all can be done with very fast performance (sub-millisecond for layout
and rendering, excluding GPU latency). There are other implementation details
that make it efficient for cache (sizeof(node) == cache line), no recursion,
no memory allocation, no unbounded loops, no system calls, etc.

I'm fairly convinced that this approach should be enough to cover 80% of
modern GUI paradigms. However I don't have the time or the interest to build a
complete widget set GUI library.

Right now I'm sporadically working on the project with a goal to make a game
UI with clickable, scrollable and scalable text and images with a modern
layout. Right now all I have to show is some ugly text and rectangles (but
with a _very_ nice layout), but it's a start for a project with potential.

[0] [https://youtu.be/4YTfxresvS8](https://youtu.be/4YTfxresvS8)

~~~
pinum
I'd love to take a look, thank you! Github: [edit removed]

~~~
exDM69
Invite sent

------
9214
Interesting pitch for Janet. Here [1] is a quick rewrite in Red language,
which lives up to the author's requirements: 10 LOC, native support for all 3
major platforms, can be shipped as a single binary, and all that's required is
a 1MB toolchain.

[1]
[https://gist.github.com/9214/dfa15d37342065dbf368eae35abcdc3...](https://gist.github.com/9214/dfa15d37342065dbf368eae35abcdc37)

------
crispinb
_However, the elephant in the room (which I also like to ignore as a Clojure
enthusiast) is that the start up time of a Java based GUI app is too slow
(this is exacerbated even moreso when Clojure is involved)_

I'm expecting a GraalVM rejoinder from someone. For anyone who's used GraalVM
(particularly with Clojure) - what are the downsides and limitations?

~~~
brabel
A JavaFX hello world app starts in around 1 second on a modern computer.
Here's a small demo of a self-updating JavaFX app where you can see it being
started, then built again, then re-launched with the new version:
[https://github.com/renatoathaydes/keepup/blob/master/docs/im...](https://github.com/renatoathaydes/keepup/blob/master/docs/images/keepup-
demo.gif)

If the author's app takes 10 seconds to boot, I am afraid they need to blame
either Clojure or their own code for that.

~~~
brodo
I'm building a TornadoFX app with Kotlin now and it also starts in about a
second. Also there is FXLauncher (
[https://github.com/edvin/fxlauncher](https://github.com/edvin/fxlauncher) )
which provides a native package and an auto updater for macOS, Windows and
Linux.

~~~
MaxBarraclough
How's TornadoFX in terms of 'lightweightness'? Presumably worse than Qt but
still much lighter than Electron?

------
_emacsomancer_
What about macOS? So far Racket seems like the easiest solution for a lisp
with easy cross-platform GUI support (Linux, Mac, Windows). It would be nice
to have more easy choices, but also nice if all 3 major platforms were
supported.

~~~
DagAgren
In reality, if you want to actually make a serious, usable and comfortable
GUI, there is no cross-platform solution. There are many attempts, but none
will let you create a GUI that actually fulfils all those requirements.

If you are making something serious, you will have to implement at least the
GUI layer separately for all platforms.

~~~
BubRoss
Why do I keep seeing people say this? People have been doing this for 30
years.

Fltk will let you do it in 700KB with no dependencies. (100KB if you're
crafty). Juce, Qt, pyQt, opengl+imgui, opengl+nanogui all work well. There is
also gtk, Tk, wxWindows ...

Where are you getting this idea from?

~~~
badsectoracula
The idea isn't that you can't have some windows with text and buttons
displayed with the same code on all platforms but that these windows, text and
buttons wont look and behave like they are supposed to and expected by the
users of each platform.

Now, outside of macOS this might not be much of a problem since Windows users
were beaten into submission to accept any arbitrary look and behavior and
Linux users never had a choice anyway.

~~~
BubRoss
I've never seen this actually be a problem other than people complaining about
buttons looking different.

If you are worried about the shading on your buttons then you must have had
all your problems solved already.

~~~
badsectoracula
"People complaining about buttons looking different" is a problem.

But it isn't just "buttons looking different", it is also "buttons behaving
different". As an example (that i often find annoying in programs with long
lists), under Windows Qt scrollbars do not behave like native Windows
scrollbars: shift click in Windows should cause the scrollbar to scroll at the
point you clicked (like middle click on most X toolkits) but Qt ignores that.

Also it is "buttons not integrating properly". On macOS it is very common for
example to have system-wide addons (services i think they are called) that add
additional functionality to text fields, like "search with google", "text to
speech", "show definition", etc. This doesn't work when a toolkit does its own
text field controls. You can also see a similar thing on Windows: GTK+
applications (e.g. GIMP) ignore the emoji panel in their text fields that
appear with Windows+; but native text fields work fine with it.

Now note that i'm not saying this is something that matters for all sorts of
applications or is always a deal breaker (especially nowadays that, as i wrote
above, most users outside of macOS have been conditioned to accept these), but
it isn't something that you can handwave away as "having a different shade"
either.

~~~
mwcampbell
> Now note that i'm not saying this is something that matters for all sorts of
> applications or is always a deal breaker

The more serious issue that nobody here has yet mentioned is lack of
accessibility, e.g. for blind users with screen readers, in many toolkits. I
say that _is_ a deal-breaker if you're developing any kind of application that
someone is going to use in their job, education, or other important tasks,
unless the task is already inherently visual in nature. Qt has passable
accessibility on Windows, Mac,and desktop Linux. GTK is accessible as part of
GNOME. Electron, for all its faults, is as accessible as Chrome (pretty good
these days). FLTK, FOX, Nuklear, TK, and a thousand other toolkits have zero
accessibility. I've grown weary of bringing this up, and some of you may be
tired of seeing it, but I feel compelled to do everything I can to make sure
nobody overlooks this point, lest someone develops an inaccessible application
that prevents someone else from doing a job, taking a course, etc.

Edit: I realize that was a rant. What rubbed me the wrong way about your
comment was the suggestion that the problems with cross-platform toolkits are
mainly cosmetic things or extra functionality that only spoiled Mac users care
about.

~~~
badsectoracula
Uh, i think you need to read again what i wrote as i explicitly write that
there are more issues than just cosmetic things and accessibility is one of
these - i just brought simple examples that anyone can test by themselves
right now.

But also yes, not every program has to care about these, including
accessibility. An image editor or a level editor for some game or some
internal and/or throwaway tool that has a very explicit "audience" has no
reason to bother about these.

------
bmn__
Subtracting all the delusional fluff about small sizes, this article is about
a Janet binding to Gtk3.

ldd app.bin|rg -o '/usr/lib[^ ]+'|xargs stat -L -c %s|perl -lne'$s += $_; END
{print $s}'

38120904

~~~
mwcampbell
Actually it's about a Janet binding to IUP. The key difference is that on
Windows, IUP uses native controls, whereas GTK does not.

------
coleifer
Tcl/Tk dabs on your gui frameworks from the unreachable pinnacle of the
heavens.

------
andrewnc
I love new programming languages, I'll have to give Janet a go and see how I
like it

~~~
postalrat
Any language that has really impressed or surprised you?

~~~
andrewnc
I've really enjoyed J so far. Pointless has been fun. Brat was an interesting
one to work with. Pony and Nim are both pleasant. Hy was a fun way to do Numpy
lisp.

I'm digging in to Chaos and then Janet after that.

~~~
andrewnc
I blog about fun, lesser known, languages on my site.

------
asimjalis
Neat. Are there screenshots?

------
CharlesMerriam2
How about English? This is just programed as:

> Puppy is an app

OK, you run 'Puppy'. It doesn't do anything.

> RandomHost is
> '[https://dog.ceo/api/breeds/image/random'](https://dog.ceo/api/breeds/image/random')

OK, 'RandomHost' is a constant, looks like a URL

> Get an image from RandomHost

OK, I think you meant Set Message to Read RandomHost retreiving UUENCODE.

> No. Get an image using json

Not the previous thing. I think you meant Set Message to Read RandomHost
retrieving JSON, field Message.

> Get Image at Message

OK. I think you meant Read the URL Message and retrieve an image file

> Show the Image

OK. Displaying the Image on the screen

> Add Repeat Button

OK. Displaying a button named 'Repeat'

> App is While on Repeat, do the Display.

OK. App is set. Do display, Wait for Repeat button, Loop

> Puppy?

Puppy is an application:

    
    
        Repeat
    
            RandomHost = 'https://dog.ceo/api/breeds/image/random'
    
            Message = fetch(RandomHost, JSON)."message"
    
            anImage = fetch(Message, DATA).ensure(IMAGE_TYPE)
    
            Display.reset(Items [
                      Image:  An Image,
                      Button: Repeat text "Repeat"
                      ])
    
            ClientSideWait Repeat.onPress
    
         Forever
    

> Problems?

Your app can run.

You have eight error conditions to discuss. Use 'Talk about errors' to decide
how to handle them. Right now, the answer is 'ignore first, or just explode'.

>Push

Pushing transcript to GitLab.... Building App.... Pushing Build to GitLab.

> Move button above image.

