(brought to you by boringcactus)
A year and a half ago I looked at a bunch of different Rust GUI libraries; that's a long time, so let's see if things have changed.
looked at a bunch of different Rust GUI libraries
As before, some context:
The short version, if you're in a hurry:
┌─────────────────────┬─────────────┬─────────────────────┬────────────────────┐ │ library │ easy setup? │ nonzero │ overall vibe check │ │ │ │ accessibility? │ │ ╞═════════════════════╪═════════════╪═════════════════════╪════════════════════╡ │ Azul │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ Conrod │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ core-foundation │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ druid │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ egui │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ fltk │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ GTK │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ Iced │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ imgui │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ iui │ ✅ │ ✅ │ 👍 │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ KAS │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ lvgl │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ native-windows-gui │ ✅ │ ✅ │ 🤷 │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ OrbTk │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ qmetaobject-rs │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ qt_widgets │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ relm │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ rust-qt-binding- │ ❌ │ │ │ │ generator │ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ sciter-rs │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ SixtyFPS │ ✅ │ ❌ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ tauri │ ❌ │ │ │ ├─────────────────────┼─────────────┼─────────────────────┼────────────────────┤ │ vgtk │ ❌ │ │ │ └─────────────────────┴─────────────┴─────────────────────┴────────────────────┘
The installation guide says you need to separately download the precompiled library and make sure it's in the right folder and ughhhh that's more setup than adding it to `Cargo.toml` and i literally put in my rules that that's more work than i want to do. Rust already has a build system, I don't want to have to fuck with things independently of that.
My previous adventures in Rust GUI development have led me to Conrod several times, and most of those times it's been a hassle, but we'll see if things have changed since then. The hello world tutorial appears to actually say which backends to use, which is a welcome and sorely-needed improvement.
Wait, what did that say there?
At the time of writing (September 2017),
Ok hold up, how outdated is this? It said to depend on `conrod 0.55.0`, but it looks like the latest version is actually `0.75.0`. And there is no `conrod 0.75.0`, apparently, because they split the crate into several different crates as of 0.62.0; allegedly I am "most likely looking for `conrod_core`." So the guide, which is *part of `conrod_core`*, is so out of date that it uses the wrong name for itself. If I just use `conrod_core 0.75.0` where the guide said to use `conrod 0.55.0` my issues have not ceased, though:
error: failed to select a version for `conrod_core`. ... required by package `conrod-demo v0.1.0 (D:\Melody\Projects\misc\gui-survey-2021\conrod-demo)` versions that meet the requirements `^0.75.0` are: 0.75.0 the package `conrod-demo` depends on `conrod_core`, with features: `glium` but `conrod_core` does not have these features.
So the officially-recommended backends don't exist anymore, or at least they no longer exist in the same way and it's my job to figure out how to get them back. I don't want to debug the official tutorial that's linked in the README. As such, Conrod appears to not be for me.
"Bindings to Core Foundation for macOS" are cool if I'm using macOS. As established, I'm not.
Previously, druid was one of the two libraries I was most impressed by; let's see if that still holds. The "this is outdated, and should be replaced with a walkthrough of getting a simple app built and running" message in the official guide persists, and upon further inspection there's been one release since my last blog post, with few new features.
The "hello world" code in the guide has broken - something that used to take a value now takes a closure returning that value - but that's an easy fix.
A harder fix, though, is that in the official "hello world" example, Windows Narrator can't find the text "hello world". In my last post, I treated accessibility as an afterthought, to the point where I had to go in several months later and retroactively check for and add information about screen reader support; this was the wrong decision for me, and it's the wrong decision for druid. They list "Offer robust accessibility support" under their goals; maybe one day they'll get there.
This is the first entry on Are We GUI Yet that wasn't there last year, and it was seeing something about this on Twitter that got me interested in revisiting this topic in the first place. There's an official template that comes with some (bash, and thereby more-painful-on-Windows, but what can you do) scripts for managing WASM builds, but I'm not interested in WASM at this point, so I'll just yoink the code and undo the multi-track drifting that allows WASM builds (which they probably don't actually need to do because wasm-bindgen can just do the right thing on binary crates due to work that i did almost exactly two years ago now, but whatever).
It runs correctly, which is good, but out of the box, Windows Narrator can't tell what's going on. There is, however, work-in-progress screen reading support which we can opt into with the `screen_reader` feature. Unfortunately, this appears not to do anything, at least for me with my current setup and near-zero knowledge of egui. Hopefully this becomes more robust soon.
work-in-progress screen reading support
The presence of the `fltk-bundled` feature is very much appreciated. Unfortunately, it doesn't make up for a lack of screen reader accessibility.
The GTK project appears to be putting a lot of effort towards providing good Rust bindings. Unfortunately,
warning: Could not run `"pkg-config" "--libs" "--cflags" "glib-2.0" "glib-2.0 >= 2.48"`
Full disclosure: I have tried several times to get GTK 3 or 4 working for development on this computer. I have failed several times, and succeeded none. I am disinclined to try and fail again.
Iced was one of the two projects I was impressed by last time around. Unfortunately, that was before I started caring about accessibility as much; the counter example, when ran as a native binary, gives no information to Narrator.
The README doesn't have a self-contained example, but there's a hello world example that looks pretty reasonable. But that `mod support;` declaration looks like it's probably abstracting out some complexity, let me just—oh god my eyes that's a lot of boilerplate. Am I supposed to copy and paste all that logic into my code? If so, why is it not just part of the library already? If not, why do all the examples have it?
As stated, I don't already have a graphics pipeline set up, so I think I am not the target audience for imgui.
This one's also a new addition compared to my previous writeup. And I'll be damned, it actually works! Didn't have to mess around with compilers, worked just fine with Narrator.
It's been three years since the last crates.io release, but I'm writing this in the same order you're reading it, so this is the first one I've seen that actually has any accessibility support whatsoever. If more than a handful of other libraries can clear that not-very-high bar, I'll fill in a more robust comparison, but for now this is pretty damn good.
Runs fine, doesn't give Narrator any info.
Setting up `DEP_LV_CONFIG_PATH` is 1. more work than just adding it to `Cargo.toml` and 2. apparently some bullshit based on C header configuration??
Unsurprisingly, this works like a charm on Windows. No installation problems, no accessibility problems, no worries. It does, of course, only work on Windows, though, and I would love to wind up with code that theoretically should be cross-platform.
Works, no accessibility.
Error: Failed to execute qmake. Make sure 'qmake' is in your path!
failed to run command: "qmake" "-query" "QT_VERSION"
LINK : fatal error LNK1181: cannot open input file 'gtk-3.lib'
installing Qt is more work than i want to have to do.
downloading the SDK independent of Cargo is more work than i want to have to do.
works, no accessibility
whatever the hell any of this is is more work than i want to have to do. it looks like this wants you to have both npm/yarn and Cargo? and i don't think i like the implications of that.
whatever the hell any of this is
Could not run `"pkg-config" "--libs" "--cflags" "glib-2.0" "glib-2.0 >= 2.44"`
what the goddamn hell is this supposed to be?
what the goddamn hell is this supposed to be
the basic example is doing shader fuckery! that doesn't seem basic to me!
Well, shit. Turns out if you want low-fuss Windows setup, nonzero accessibility, and theoretical cross-platform support, and you want them in the present rather than the future, there's only one option (at least among the things listed on Are We GUI Yet). Shout out to iui, in all its three-year-old-latest-release no-way-to-draw-images(-at-least-that-I-can-find) glory. Honorable mention to egui for having put in at least some effort towards accessibility; if I revisit this topic in another year or two, I suspect I'll be very impressed with egui. Additional reference to SixtyFPS who have made an entire other markup language for specifying UI structure; I'm not sure it's a good or necessary approach, but it's eye-catching, and maybe at some point they'll start working on accessibility and I'll take a more thorough look. (I'm not entirely sure the extent to which German and/or EU law requires commercial products meet accessibility standards, but if SixtyFPS is doing commercial licensing, they'd better have looked into that.)
I've worked with Python and Rust a lot, and those are my two languages of choice for new personal projects these days. Python, as an interpreted language, does not really go out of its way to give you binaries that you can just hand to end users; it's possible, but as of the last time I checked, the tools were all varying shades of pains in the ass to use. Rust seems like it'd be far better suited for end-user application development, since at the end you have a .exe or whatever that you can hand off to anybody. It looks like the Rust ecosystem doesn't really have a solid foundation for GUI development, despite being a good language for GUI development. Python is set up such that it's easier to write tools for other developers (who are likely to have a Python interpreter installed) than for end users (who are not), and developers tend to prefer CLI programs to GUI ones, so it would be reasonable to expect GUI tools in Python to be worse than they are in Rust, right?
Let's check in on that:
# after `pip install wxPython` and no other fuckery: import wx app = wx.App() frame = wx.Frame(None, title="wxPython Example") panel = wx.Panel(frame) text = wx.StaticText(panel, label="Hello World!") frame.Show() app.MainLoop()
This was easy to set up on Windows, correctly provides accessibility data to Windows Narrator, and was really concise to implement. So if I want a nice, powerful, elegant GUI library without losing my mind trying to set it up, I can have that, as long as I don't need other people to be able to conveniently run the program I make. How the goddamn fuck did we get here?
Unfortunately, I know the answer to that one. wxWidgets, the library wxPython is binding to, is a C++ library that is used primarily by inheriting from wxWidgets's classes. Rust bindings to C++ libraries are difficult to create in the best of scenarios, and inheritance is among the worst of scenarios, because Rust does not have any concepts to which C++ inheritance maps cleanly. The wxPython bindings are maintained by the wxWidgets team themselves, and Python is designed to be extended by C/C++ code. Rust's FFI with C is fine, but bindgen is really bad at handling C++ as used by wxWidgets, and manually authoring the thousands of bindings and then providing a safe abstraction over them would be extraordinarily not a good time.
So if wxWidgets isn't feasible to use from Rust, what about some other library? Well, the only reason wxPython is as easy to install as it is is that the maintainers made sure it comes with the fully-compiled wxWidgets binaries, especially on Windows where everything of that sort is harder to do by hand after the fact. Some Rust bindings to C libraries, like SDL2 or the aforementioned FLTK, will build the libraries they depend on automatically, encapsulating all that complexity and letting me just use them; most, like GTK, do not. I'm not sure if there's a technical reason gtk-rs and the rest of these can't do that (or, for bonus points, just download a precompiled binary from the official releases and save a bunch of time), or if it's just that nobody's asked for it. Linux (and to some extent Mac I suppose) devs are accustomed to niceties like `pkg-config` and actual package managers that make it easy to install a C library; on Windows, we don't have that (unless we're working inside MSYS2 or what have you, but that's its own mess sometimes). So please: if you're writing Rust bindings to a C library, do your Windows users a favor, and give us a `bundled` feature.