aboutsummaryrefslogtreecommitdiff
path: root/_posts/2021-10-24-2021-survey-of-rust-gui-libraries.md
blob: 3375637e88d88876a2fe27af2582ff32a4204b45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
---
title: A 2021 Survey of Rust GUI Libraries
---

A year and a half ago I [looked at a bunch of different Rust GUI libraries](_posts/2020-08-21-survey-of-rust-gui-libraries.md); that's a long time, so let's see if things have changed.

As before, some context:

- List of libraries is drawn from [Are We GUI Yet](https://www.areweguiyet.com/).
- I work on Windows, and I am lazy; as such, any library that requires more setup on Windows than "add it to `Cargo.toml`" is disqualified.
- I'm interested in making desktop application UIs, not game UIs.
  As such, I don't already have a graphics pipeline set up, so if I have to decide between vulkano and glium before I can get going, and the library documentation doesn't tell me which one is the right one to choose, I'm moving on.
  If you make me learn game dev before I can use your UI library, I am not the target audience for your UI library.
- Accessibility should not be an afterthought.
  I don't currently need accessibility tools like screen readers, but some people do, and I may find myself among them at some time.
  I'm not experienced enough to evaluate in depth the quality of accessibility features, but I know how to turn on Windows Narrator and see if it can tell what's going on in an application window or not.
  If I have Hello World running in your library, but Narrator can't tell that it says Hello World, you have zero accessibility support, and therefore I have zero interest in your library.
- These are all my opinions.
  Even if you also work on Windows and are lazy, and also don't want to learn the practical difference between Vulkan and OpenGL, and also care about accessibility, you are not me, so my opinions might not match yours.
- This shit is really difficult.
  I've tried writing Rust bindings for wxWidgets, because I like wxPython when I'm working in Python, and for Tk, because tkinter is kinda neat too.
  Neither of those went anywhere, because I don't have the skill or patience to do that.
  All of the libraries I'm about to review were written by people who put a lot of time and energy into making them, and even if the results don't meet my needs or tastes, I'm glad they've done the work.

The short version, if you're in a hurry:

|library                                                |easy setup?|nonzero accessibility?|overall vibe check|
|-------------------------------------------------------|-----------|----------------------|------------------|
|[Azul](#azul)                                          |❌          |                      |                  |
|[Conrod](#conrod)                                      |❌          |                      |                  |
|[core-foundation](#core-foundation)                    |❌          |                      |                  |
|[druid](#druid)                                        |✅          |❌                     |                  |
|[egui](#egui)                                          |✅          |❌                     |                  |
|[fltk](#fltk)                                          |✅          |❌                     |                  |
|[GTK](#gtk)                                            |❌          |                      |                  |
|[Iced](#iced)                                          |✅          |❌                     |                  |
|[imgui](#imgui)                                        |❌          |                      |                  |
|[iui](#iui)                                            |✅          |✅                     |👍                 |
|[KAS](#kas)                                            |✅          |❌                     |                  |
|[lvgl](#lvgl)                                          |❌          |                      |                  |
|[native-windows-gui](#native-windows-gui)              |✅          |✅                     |🤷                 |
|[OrbTk](#orbtk)                                        |✅          |❌                     |                  |
|[qmetaobject-rs](#qmetaobject-rs)                      |❌          |                      |                  |
|[qt_widgets](#qt_widgets)                              |❌          |                      |                  |
|[relm](#relm)                                          |❌          |                      |                  |
|[rust-qt-binding-generator](#rust-qt-binding-generator)|❌          |                      |                  |
|[sciter-rs](#sciter-rs)                                |❌          |                      |                  |
|[SixtyFPS](#sixtyfps)                                  |✅          |❌                     |                  |
|[tauri](#tauri)                                        |❌          |                      |                  |
|[vgtk](#vgtk)                                          |❌          |                      |                  |
|[WebRender](#webrender)                                |❌          |                      |                  |

## [Azul](https://azul.rs/)

The [installation guide](https://azul.rs/guide/1.0.0-alpha1/Installation) 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.

## [Conrod](https://github.com/pistondevelopers/conrod)

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](https://docs.rs/conrod_core/0.75.0/conrod_core/guide/chapter_3/index.html) 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](https://crates.io/crates/conrod) 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:

```text
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.

## [core-foundation](https://github.com/servo/core-foundation-rs)

"Bindings to Core Foundation for macOS" are cool if I'm using macOS.
As established, I'm not.

## [druid](https://linebender.org/druid/)

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](https://linebender.org/druid/get_started.html) 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.

## [egui](https://github.com/emilk/egui)

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](https://github.com/rustwasm/wasm-bindgen/pull/1843), 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](https://github.com/emilk/egui/issues/167) 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.

## [FLTK](https://github.com/fltk-rs/fltk-rs)

The presence of the `fltk-bundled` feature is very much appreciated.
Unfortunately, it doesn't make up for a lack of screen reader accessibility.

## [GTK](https://gtk-rs.org/)

The GTK project appears to be putting a lot of effort towards providing good Rust bindings.
Unfortunately,

```text
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](https://github.com/iced-rs/iced)

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.

## [imgui](https://github.com/imgui-rs/imgui-rs)

The README doesn't have a self-contained example, but there's a [hello world example](https://github.com/imgui-rs/imgui-rs/blob/v0.8.0/imgui-examples/examples/hello_world.rs) 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](https://github.com/imgui-rs/imgui-rs/blob/v0.8.0/imgui-examples/examples/support/mod.rs) 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.

## [iui](https://github.com/rust-native-ui/libui-rs)

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.

## [KAS](https://github.com/kas-gui/kas)

Runs fine, doesn't give Narrator any info.

## [lvgl](https://github.com/rafaelcaricio/lvgl-rs)

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??

## [native-windows-gui](https://github.com/gabdube/native-windows-gui)

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.

## [OrbTk](https://github.com/redox-os/orbtk)

Works, no accessibility.

## [qmetaobject-rs](https://github.com/woboq/qmetaobject-rs)

```text
Error: Failed to execute qmake. Make sure 'qmake' is in your path!
```

## [qt_widgets](https://rust-qt.github.io/)

```text
failed to run command: "qmake" "-query" "QT_VERSION"
```

## [relm](https://github.com/antoyo/relm)

```text
LINK : fatal error LNK1181: cannot open input file 'gtk-3.lib'
```

## [rust-qt-binding-generator](https://invent.kde.org/sdk/rust-qt-binding-generator)

installing Qt is more work than i want to have to do.

## [sciter-rs](https://github.com/sciter-sdk/rust-sciter)

downloading the SDK independent of Cargo is more work than i want to have to do.

## [SixtyFPS](https://sixtyfps.io/)

works, no accessibility

## [Tauri](https://tauri.studio/en/)

[whatever the hell any of this is](https://tauri.studio/en/docs/usage/development/integration#1-start-a-new-tauri-project) 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.

## [vgtk](https://github.com/bodil/vgtk)

```text
Could not run `"pkg-config" "--libs" "--cflags" "glib-2.0" "glib-2.0 >= 2.44"`
```

## [WebRender](https://github.com/servo/webrender)

[what the goddamn hell is this supposed to be](https://github.com/servo/webrender/blob/master/examples/common/boilerplate.rs)?

the basic example is doing shader fuckery!
that doesn't seem basic to me!

## summary

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](https://github.com/rust-native-ui/libui-rs), in all its three-year-old-latest-release no-way-to-draw-images(-at-least-that-I-can-find) glory.
Honorable mention to [egui](https://github.com/emilk/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](https://sixtyfps.io/) 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.)

## whining

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:

```python
# 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.