Current state of GUI development in Rust?

I hope that Rust will offer a very lightweight cross-platform GUI using native widgets, but with a uniform API. (But perhaps following on from the fs module, platform-specific extensions.)

For example the Red language supports (bare-bones at the moment) GUIs, e.g., Red on Android, Red on macOS, Red on Windows.

1 Like

An interesting post from the author of Limit Theory. He is analyzing pros and cons of IMGUI (immediate mode GUI) and RMGUI (retained mode GUI) and proposes approach that combines pros of both of them (HMGUI - hybrid mode GUI). I think this potentially can be another way of GUI development in Rust.

1 Like

It's worth noting that Conrod is a hybrid-mode GUI library in pure rust (though it requires a rendering backend - glium is the standard one).

Hi,

I would strongly suggest coalescing around native components directly. This is substantially more efficient from a memory and processing standpoint, allows substantially more accessibility with things like screenreaders, and provides a more integrated experience with key bindings, screen themes & sizing, etc. If one wishes to write a HTML GUI, that is a different bag of worms and probably best served by a local app server and a web browser.

With respect to the OO system, I note that Common Lisp was doing GUI development in the 80s - CL has functions independent of its objects. That might be a fruitful paradigm.

thanks.

4 Likes

Using native components is not necessarily more efficient. Some versions of Qt for example get a single "real" window from the OS and draw everything (i.e., all the widgets). This can be a lot cheaper in memory (only one OS window handle per top-level window), and can be faster since Qt's drawing routines have sometimes been faster than the native ones.

The GUI I think would be a good inspiration is that of Blender. It is written in OpenGL (although I think a Vulkan port is underway?). This means that every widget is consistent across platforms (so not native looking, but easier for documentation, esp. video tutorials and screenshots). When I first tried Blender I found the UI difficult to read (light on dark) but found it had theming that works instantly and could be changed (in my case to dark on light). And best of all you can scale the UI and this works perfectly for text.

In an ideal world there'd be three GUI libraries, one native but with commonality of use across platforms, one per platform purely native and not necessarily cross-platform, and one non-native cross platform "the Rust GUI". In all cases though, a huge amount of work!

OTOH A lot of software gets written in Python using Tkinter which is very bare-bones, not very native, but cross-platform and fast and fairly easy to use. So maybe at least starting small would be good.

Anyway I hope people take up the GUI challenge for Rust: at the moment for GUI's I have to write hybrid applications with another language/library for the GUI (e.g., Python/Tkinter), since I haven't found any of the Rust GUI crates works or is otherwise satisfactory yet.

4 Likes

This sentence appears to contradict itself. You don't believe in heavy clients but you do believe in JS/HTML/CSS front-end? I'm not sure you can square that circle.

3 Likes

I prefer doing all my GUIs entirely in code. Also I prefer a single language (e.g., Rust), rather than four different ones (Rust/JS/HTML/CSS). However, Gtk, Qt, and wx are all very large these days because they all offer a lot more than "just" the GUI aspects. I'd like to use a lightweight GUI-only library.

5 Likes

Not without leaving behind a lot of users. I haven’t worked with a web-based GUI that didn’t make a hash out of accessibility, if it was considered at all.

4 Likes

It's been a few months since my last post here, so I wanted to write some updates for my framework azul:

While it's not 0.1-ready yet, it's getting there and I hope to release a 0.1 in December this year, possibly a beta in October / November - right now it doesn't look like the project is failing. In terms of performance, my expectations have been met - roughly 1 - 5 ms in terms of frame time and roughly 40MB - 50MB of RAM usage. This is roughly what a regular QT Quick app is using, so I think that's okay in terms of performance.

I also implemented hot-reloading CSS in debug mode (so that you can quickly iterate on the style without having to recompile the entire app) - see this video I made (sorry for the typos, I was a bit excited to see it work properly):

Here's a screenshot (after I fixed the box-shadows :wink:) - right now flex-direction: [row | row-reverse | column | column-reverse] is implemented and working:

.. and the RAM usage of the above app is ~43MB - 33MB of which is just webrender:

No more fixed positioning or hacky alignment issues, wohoo! Here is the accompanying Rust code (also see the hot_reload.css file in the same directory)

There are still some text alignment bugs, linear-gradient doesn't quite work as it's supposed to and some crashes regarding OpenGL, absolute / relative positioning + margins / padding are still missing. And the two-way data-binding / implicit layout API still needs work, otherwise implementing custom widgets will be a pain. But otherwise, it's working quite nicely already.

So my goal was to prove that a DOM-like tree approach + CSS don't have to be as heavyweight or slow as Electron or an entire browser. If you implement only a subset of it and care about performance, you can achieve a middle-ground between performance and ease-of-use.

In terms of borrow-checking, working with an immutable tree has turned out very nicely. Since the DOM tree is immutable, I can go wild with pointers and indices, since they are all valid. Right now the DOM is arena-based, so it's one block of contigouus memory, so it's quite efficient in terms of cache locality.

Layout (using the cassowary constraint system) is pretty fast, since cassowary also acts as a cache for layout constraints and variables - the only time that this is really stressed is when the DOM is heavily modified in comparison to the previous frame - because then I need to insert / remove layout constraints, which can cost a bit of performance (and by that I mean a few milliseconds). So the goal is to make that part faster by diffing the DOM and only adding / removing the relevant constraints, not all of them.

Rendering (the real rendering using webrender, not DOM construction) is quite fast too, but webrender has the overhead of 1ms to build and render any frame, so for games, this probably isn't the tool of choice if your frame budget is 16ms. But for a desktop CRUD app that doesn't have to render an entire world with physics and whatnot every frame, I think 4ms frame time is OK.

I am currently building my app (screenshot below) using azul as a way to prove that it can work and to test the API for papercuts (small problems like a type not re-exported correctly or something like that). I hope to finish this app next month, then I'll have more time to focus on finishing azul full-time.

The main benefit I see of azul over QT or something else is that it's pure Rust, you don't need a meta-compiler or a QML runtime or a third-party language (Python / Vala for GTK) to not rip your hair out over the API and azuls API is very idiomatic - for example in order to build a list with 15 items in a DOM, you can now just do (0..15).map(render_my_item).collect() - which is also more efficent than the procedural way (with a for-loop).

The biggest problem is actually the Rust compile time - waiting 15s for recompilation when you just want to insert a new DOM node or fix a typo is simply frustrating. But since azul is DOM-tree-based, it would be easy to make a XML-like format that can be hot-reloaded in debug mode - just like the CSS and then write a XML-to-Rust translator (for release mode). The important thing is debug mode - I am currently disallowing users to hot-reload in release mode, since that wouldn't make any sense, in release mode the CSS can't be changed.

There have been some feature requests for static CSS typing and a time-travel debugger when I demoed azul at a Rust meetup a month ago - I've kept these thoughts in the back of my head, but they may not make it in the 0.1 release. So yeah, just wanted to write an update on that, cheers.

40 Likes

Incredible work! This is exactly what I (and many others) are looking for in a GUI framework. HTML/CSS is wonderful in that it allows for easy prototyping and development, and probably is one of the reasons it took off (though I still enjoy toolkits like MS' XAML).

The biggest problem is actually the Rust compile time - waiting 15s for recompilation when you just want to insert a new DOM node or fix a typo is simply frustrating.

Instead of writing a transpiler, would you open to considering using a simple data format, like how Amethyst uses ron files? That way, hot reloading could be done without recompilation (although at the sacrifice of some type safety, which may or may not be a dealbreaker - though perhaps you could go a hybrid route at some point).

1 Like

Bring Back XUL! There is only XUL! A Rust implementation of XUL based on WebRender with the JS Part substituted with Rust/WASM and the XUL being embeddable in a Macro in Rust or Run-Time loadable would be awesome IMHO!

3 Likes

Hi,

just wanted you to know that I'm planning to write a small GUI app
(I've never ever done any GUI stuff) and am seriousely considering
using azul, despite not having more information than what you've
written in your post as I do not have access to the internet right now
(am on a trip trough north america, off the grid most of the time).

Your post sounds really good and I'm looking forward to have a closer
look in October when I'm back home.

So here I am trying to get a Desktop GUI working and in the process of learning Rust and having fights with the rust compiler on what is and isn't safe, I've managed to piece together a (limited functionality) library called skryn that is based on WebRender without having to rely on JS, CSS and XML.

There were three motivating factors in the library:

  1. It should give as much control as possible to have custom Elements implemented while ensuring thread safety (with the assumption that all GUI application are multi-threaded).
  2. Aligning text or childen should be painless.
  3. Mixing percentage unit lengths with fixed unit lengths among siblings should be pretty simple and be immediately understandable.

With those in mind here is what you will be able to do:

  1. Create Custom Elements
  2. Create Closures fired on ElementEvent safe to use in a multiple threads.
  3. Use the 4 unit of lengths for width and height which are Pixel(f32), Stretch(f32), Extent, Natural. (Explanation here)
  4. You can also use Pixel and Stretch for TRBL (pronounced 'trouble' and stands for Top, Right, Bottom and Left) properties. This replaces the concept of margin/padding. Natural doesn't have any meaning these properties while Extent just means use the entire bounding value for a given dimension and practically it didn't make sense to me.
  5. Use the provided Elements to compose you're own layouts.

This isn't a perfect implementation (yet ... or may never be) but I've written two examples on how I wanted to use it. Out of two, the calculator is here

Now, I'm looking for someone to help clean up some of the concepts, implementation, documentation an making use of WebRender to the fullest.

Thanks!
Fasih

12 Likes

Is no one else here aware of the Lazarus IDE for the Free Pascal compiler? If nothing else I think it's very solid proof (has been around for 15+ years and is always steadily improving) that the concept of a top level widget library that wraps different underlying frameworks depending on the platform is in fact totally feasible and capable of getting good results (Both Total and Double Commander are built with Lazarus, for instance.)

It is also for the record highly performant and definitely not what you'd generally call "heavyweight" or "bloated" when compared with other IDEs that include GUI framework integration.

"There is no existing IDE or framework specifically for C++ that does this truly well, and so it's a dead end concept" is not the same thing as "There is no existing IDE or framework that does this truly well, and so it's a dead end concept".

As a community I think we'd benefit quite a bit from generally striving to broaden our horizons beyond comparing everything to C++ and nothing else when looking for or considering precedent for different things in other languages.

10 Likes

The answer is absolutely not CSS or the more general often heard "just literally make everything a web application!", I can tell you that much.

I'm sorry, but it's not, for many reasons.

On a tangential note, I find the somewhat kneejerky distaste for all things "OOP" (often a rather unrealistic idea of OOP that usually involves thinking Java is a decent universally applicable example of it for some reason) to be particularly strange when it's coming from people who on the other hand are advocates of stuff like React which are in every way nothing more than simplified direct adaptations of the classic OOP "components n' callbacks" model for GUI development.

Right down to tiny details like using "onclick" as the canonical name for mouse button clicks, at that!

2 Likes

Instead of callbacks and such, how would you design a gui system? (just curious as I am not familiar with other ways of doing it due to limited experience with GUI)

I was actually saying that callbacks and such are basically the only logical way to go about things at the end of the day.

My point was just pretty much that all of the currently popular web-UI frameworks in reality function via essentially the exact same sort of straightforward callback/event-handler based model that stuff like WinForms has internally since the beginning of time, contrary to what's claimed by people who cite them as following some kind of significantly different totally-not-OOP-just-because-I-said-it's-not "Modern Way Of Doing Things" that makes them a clearly better paradigm to be inspired by.

1 Like

Any thoughts about doing something like Scenic for Elixir? ElixirConf 2018 - Introducing Scenic A Functional UI Framework - Boyd Multerer - YouTube

My biggest concern about something like that is accessibility, which was mentioned before.

Ok, I misunderstood. Thanks for clearing it up.

1 Like

I mean, it looks like a perfectly fine library. Again I'd say though based on examples like this one I found that it's just doing the same old thing every GUI lib in every language ultimately does, with the only differences being syntactic ones per Elixir itself, because why wouldn't it?

I think the accessibility point boils down to a simple question of "do we think a hypothetical fully from-scratch Rust UI framework can adequately implement something close to the level of accessibility features that would be available to it if it was instead wrapping an existing, established framework?"

2 Likes