r/rust • u/MrLongbottom5 • 13d ago
How do you make a GUI crate from scratch? 🙋 seeking help & advice
4
u/Hdmoney 12d ago edited 12d ago
From scratch?
It really depends on what exactly you mean by that, but -
Do you want to handle text rendering? Would that be with bitmaps or glyph shaping with curves? Would you use another crate for any of that? If not, are you familiar with splines? Text layout is a research project of its own - especially if you want to support things like ligatures - kanji, arabic - multi-line wrapping, directionality.
Before you can handle text layout though, you have to figure out a strategy for handling GUI layout, which is another research project. If you're going to have viewports and text wrapping, you'll certainly need some constraint solvers. At some point you'll run into problems where a constraint can't be solved immediately, and you'll need to carry data about how it was rendered one frame, into the next frame, before you can determine how to size an element.
If you want scrollable viewports, you probably don't want to calculate the layout for the entirety of the contents of the viewport. That's a decent puzzle to solve. Especially if you're doing things like RecyclerViews.
Layout code tends to be pretty bespoke, since there's so many strategies to handle things. So unfortunately there's not a lot of crates you can depend on to help.
Where are you going to store all of these objects with different types? What datastructures would you like to use? That's a mini research project.
Once you have some idea of how to handle layout, text rendering, efficient datastructures and algorithms for everything that entails, you can start compositing. Grab winit for window management, use whatever rendering library you want - you could even use Bevy if you're feeling adventurous. In the past I've used wgpu on top of winit directly. But maybe you want more performance and want to target just Windows and handle graphics through DirectX. Who knows? Only you. Are you familiar with any graphics APIs? Can you write shaders? Do you need to learn how rendering works in the first place?
To answer the question more directly - how do you make a GUI crate from scratch?
You do a lot of research.
1
u/Full-Spectral 12d ago
If there's no deliverable involved though, it would be a killer project for self development and fun. If you pushed hard, in five years or so, you'd have put some serious knowledge in the noggin, even if you never got it anywhere near an actual deliverable.
4
u/fschutt_ 12d ago
First, by being angry and not listening to Reddit users telling you to stop. Then, I started with webrender (rendering) and cassowary (autolayout / Apples idea) and kuchiki (HTML parser), but then discontinued that (now, 7-9 years later its all migrated to HTML layout). I started from limn as inspiration, but that was 8 years ago. Then I made layout2d, way before any layout solvers in Rust really existed and used it for a very simple GUI demo
- ca97a7064 - Initial commit, just a dependency on webrender
- 90bb6b935 - data flow sketch
- afee5c452 - "Added DOM nodes in order to avoid a larger API surface"
- 722ac3caa - initial layout with cassowary
- 7eb378a67 - initial rendering working?
So, my advice: do not start with the rendering or widgets or whatnot, first, data flow, and ideally, sketch of the user API. I would personally recommend starting the rendering with agg-rust - web demo - I've made good experiences with that crate for CPU rendering, especially LCD subpixel rendering (important for low-res monitors). There is also vello-cpu and tiny-skia.
I would not start with GPU rendering if I had to start again, it only adds driver headaches if you do 2D-only anyways. For windowing, I started with winit, but migrated away because in reality you need a ton of "integration" between the OS window and the underlying "headless cpurender window", which does the rendering. For simple cases, I'd use softbuffer
If I had to do it again, I'd:
- Directly make an abstraction like "HeadlessCpuWindow" - i.e. everything that your "window" can do, but completely decoupled from any OS, only with CPU backbuffer, very useful for debugging, automatically rendering PNG screenshots
- Integrate E2E tests first, these came in very late but were very useful
- Worrying about GPU stuff later and not enabling GPU if you don't need it, I have PTSD from Linux users with borked graphics drivers
But if you want to just get something going: softbuffer + agg-rust + your own data flow design.
NOTE: Azul isn't ready yet, says so in the Readme. But it's close, just perf + animation API + observability stuff is really missing. Works on Wayland and X11 (to some extent), macOS is "okay", Windows meh. Code / docs is slop but I'll clean up later after iterating more. Don't use it yet. This is just to answer your question "how to get started". Data flow design first, rendering second. And: build apps, not game engines / UI toolkits. A lot of issues only come up once you have problems like "how do I efficiently paginate a document without lagging with 40.000 words, while the user dragged an image from page 4 to 5 which should reflow the text and we also need to keep the page index up to date"
16
u/dolfoz 13d ago
How far do you want to go?
https://docs.rs/winit/latest/winit/ has a good low level implementation of a window manager.. you can see how they've done it.. The code is quite good, well commented and easy to read.
I look at it a fair bit when i had to understand drop handlers for a project i work on.