I’ve been studying user interfaces and text rendering for so long I think I’ve lost count how many libraries I’ve tried from multiple different languages. I’ve tried Flutter (Dart) - lasted about 5 minutes because I didn’t like it - Windows Forms (my most proficient use case), Java’s Swing (for a brief time), Web tech (of course), Dear ImGui, RayGui, wxWidgets, libagar (briefly), and many more.
I can certainly understand why people could get frustrated with any one of these libraries and most people end up settling for a layout library and building their own widgets on top. This seems to be the way to go, right?
Well, I’ve decided to make a repo over on GitHub discussing what layout libraries and widget building would likely look like in the future.
I’ve pondered over this for long enough and it’s time to get my attention on this as it’s an area I’m most passionate about. Ironically, it’s not something I most enjoy fiddling about with, because UI should be trivial, but I have wondered why people always make the decision to build their own. Is it truly their way, or is it simply because the market just hasn’t filled the gaps that people crave?
Out-of-the-box pre-built widgets not reliant on a framework comes to mind. Dear ImGui comes closest to this solution, hence why it’s so popular, but here you have to contend with the fact that Dear ImGui is limited in one aspect: it’s aesthetic. Yes, you can tweak the colours, spacing and supply your own font, but that’s about it. If you want anything else, you’re better building your own custom UI engine - likely with a hand-rolled SDF shader and a layout engine like Clay.
Also, if you want IME because your audience is, let’s say, business customers and they’re worldwide, you end up back to retained mode UIs since they’re the most battle tested for IME text input.
Marketing, sales and purchasing departments like to be sold on functionality and features, but the biggest feature is the user experience, and this is primarily a UI concern. If you’re building apps sold to businesses at a large scale, IME is going to be top priority.
In my opinion, aesthetically pleasing UI will never beat a borked IME system. Most people choose to let the OS do the IME for them, which is a fair trade off for games, but not for general UI. If your audience is businesses, there are few choices on the market for UI at present:
- The Web - as unironic as this sounds, the web (unfortunately) offers the most standardised, complete and cross-platform solution for both UI and text input with full IME support. That means support for mid-flight character input, bidirectional text, and more.
- Gtk, Qt or wxWidgets - All these play on desktop native UI and abstract as necessary, with Qt probably the biggest of the three. It is because they use the native text input controls supplied by the OS they get IME basically for free.
That’s about as far as I know and I’m not aware of other complete solutions besides the native APIs supplied by each OS, but I’m not going to bother going there.
One argument can be said with all of this and it’s worth raising as it was mentioned in an interview involving Nic Barker, the creator of Clay, who said, and I quote:
Some people go as far as to create a native text input widget and draw it off-screen, only to then feed the results back into the frame loop.
A hacky solution, but works for IME support all the same. The question this raises: do people want the hacky solution or a seamless, high performant experience?
My final question I would then raise is probably the text input caching method. Piece Table/Tree? Gap buffer (unlikely)? Line-by-line split? Or whatever else that exists.
I think given the number of times I’ve seen people try and work out their own UI library, I think it is reasonable to say that these people fall into one of two camps:
- They’re doing it for fun and to learn, which is fair enough; or,
- They have tried dozens of solutions but none of them fit the bill (people like me)
I can’t fathom the idea of trying to build my own UI library with widgets and built-in IME text input, but considering there is no cross-platform solution outside the Web and not wanting to touch HTML/CSS/JavaScript and all the desktop Virtual JS Runtimes that come with it, it seems it’s worth discussing these points before attempting such an ambitious project. I did try it with my AI generated InterfaceAPI project, and in many ways is the solution, but I’ve come to accept two things from this experience:
- Most people do not like AI generated projects and don’t want anything to do with it, and I can understand why.
- As an R&D project testing the ability of AI, it was fun to learn and experience everything that I’ve discussed with AI and what works and what doesn’t.
In many ways, I think the next project will be to accommodate everything I’ve learned, sit down and take a serious deep dive into the problems that most people face with UI development:
- Text Rendering (lack of text input support in most cases, and where there is a lack of IME)
- Building a layout-less widget system relying only on rects (potentially) so that it can be dropped into any layout system of your choice
- Building stateful primitives that don’t rely on sync or reactivity to make data and UI work.
On that last point, most people I think probably like the ImGui paradigm for this because it is simply the case of passing in a pointer to a state you own. This makes the most sense and I would probably stick with this approach, it would be the case of working out if my other project would work well with this. Possible union:
ValueRef :: union($T : typeid) {
T,
Reference(T),
}
// for widgets that need a retained state, like text editors or graphs.
Reference :: struct($T : typeid) {
value : ^T,
change_counter : u64,
}
Sorry for the long post, just thought it would be worth discussing. I’d certainly be interested what people think and if it’s worth the pursuit on the points I’ve made above.