10 ms·
Ask HN: I'd like to practice coding GUI from scratch. Any recommendations?
Hi folks!
As the title says, I want to practice coding a GUI framework, probably in C++.
I read about a retained and an immediate modes, have a rough understanding how event loop works, and overall my goal is to practice architecture and optimization (especially cache-friendliness), and less so graphics and typography rendering, though I understand it's unavoidable to implement a rendering pipeline (I plan to start off with AGG or Skia graphics libraries).
The dummy app itself will be less about forms but more about data representation, e.g. an audio editor or a node-based system, where data should be updated and visualized in real time, and everything should feel responsive.
Could you please give some research directions? Maybe case studies, best practices, some interesting software, maybe to read more in detail about related architectures, etc.? Or maybe personal stories? I'm struggling to find related info which would not be focused on some framework, etc.
- smoyer 5y agoIf you want to start from scratch, I'd recommend coding along with Casey on https://handmadehero.org https://handmadehero.org. He develops an entire game starting with double-buffered pixel graphics and then moves on to sprite s with movement functions. The should give you plenty of background to be able to show a sound waveform (I'll offer one warning though ... Being able to edit sound I'm a way that still sounds good is much harder).
- scott01 5y agoWell, he pretty much inspired me to go into this direction, such a great series! I particularly enjoy episodes on memory management, though, admittedly, they're a bit over my current skill level.
- smoyer 5y agoA long time ago I wrote a CAD system that ran on DOS and generated G-Codes for CNC machines. One of the features is that it would show the tool's path and it cemented my love for trigonometry. You seem to have found something you love too - kudos for chasing it!
- svilen_dobrev 5y agothink about.. the various "hierarchies" / aspects / of the relations of the things in it. Event-passing is one ; Containment (x part-of y) is another ; Visual overlap yet another (now that depends on point of view) ; ... there are more.. depending on the purpose.
- scott01 5y agoThere're definitely keywords I'm going to Google :) As for hierarchy, I'd like to avoid having class hierarchies where everything is a subclass of Widget, etc. I guess I want to explore how much of the data required for rendering of such UI can lie in contiguous memory — hope it makes sense…
- ozim 5y agoStart with Bresenham's line algorithm :) if you want to go with "from scratch".
- Shared404 5y ago"First one must invent the universe". That being said, I'm interested to see the range of answers to OP's question, partially as I'm curious what HN considers "from scratch" and partially because I've thought about doing the same thing. Edit: Same thing making-gui-from-scratch, not the audio stuff.
- datavirtue 5y agoI started doing this in QuickBasic when I was 14 (trying to copy Windows 3.1 LOL). That little project taught me more about what I didn't know and it also revealed to me plainly, my inexperience with abstractions. Before that I had not really reflected on my own level of understanding about abstractions.
- Shared404 5y ago> Before that I had not really reflected on my own level of understanding about abstractions. This is the main reason I try to do this when I can. When building things for fun I try to do it from the lowest level of abstraction that I can so that I understand more of what the higher levels of abstraction cover up. I guess I just like turning unknown unknowns into known unknowns.
- cardiffspaceman 5y agoFrom scratch == floppy disk and magnetized needle. But seriously from scratch in this case is a canvas plus possibly some primitives for marking the canvas. Cairo provides these things. I used to have an old 2MB DOS notebook that I would fire up now and then to play with my ideas in this space. I could get mouse input through an INT op code of some sort, and there was the keyboard and getting access to video RAM. I have tried to play with the Linux kernel drivers underlying things like wayland and X but I lack the determination to see that through. Another post here someone listed the object model paradigms and that’s probably closer to what OP is interested in.
- jagger27 5y agoI find the SerenityOS userland code base quite approachable. It's all written in C++.
- scott01 5y agoThat looks like a good idea, probably can explore allocators, etc. from there. Thanks for that!
- imachine1980_ 5y agoi recommend opengl for this instead of trying whit GUIs, you could make easy small simulations and shot in your foot whit rendering pipelines fast and easy, opengl resource are all over the place, good luck.
- phtrivier 5y agoIf you have a mostly 2d UI in mind, you might to from something even simpler than opengl, like SDL or raylib - anything that lets you out pixels on a screen. My personal experience is that starting developing in opengl always ends up wasting hours getting the right libs installed to get potentially full 3d GPU acceleration - which might be beyond the point if you want to draw stuff. Casey muratorri is spot on in saying that not having a single, simple, unniversal and basic API to "open a window and draw pixels" is what we lost the most during the 90s. Anyway, try to bypass the not-interesting-to-you parts, and have fun !
- scott01 5y agoNoted, thanks! Yes, I was thinking more about 2D
- krapp 5y agoI would definitely suggest starting with SDL, because it is a "single, simple, universal and basic API to 'open a window and draw pixels'" and it recently added an API to draw geometry directly without OpenGL. It also gives you a flexible event system that can be used for messaging.
- thamer 5y agoI've written a fair share of GUI apps in C++ on multiple platforms, starting with Win32 API and MFC on Windows and later Qt on Linux. The way you write applications with these frameworks is different enough to have a significant impact on the structure and design of the UI layer. I don't have any suggestions for how to build such a framework, but I would encourage you to play around with a few existing frameworks to see how they are designed, what you like about them, and what ideas to avoid. For just one example, see the difference between managing the event loop entirely by hand with Win32[1] and using "signals and slots" in Qt[2]. There is a lot more to UI frameworks than this, and they vary on many more aspects. - [1] https://docs.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues https://docs.microsoft.com/en-us/windows/win32/winmsg/using-... - [2] https://doc.qt.io/qt-5/signalsandslots.html https://doc.qt.io/qt-5/signalsandslots.html
- scott01 5y agoThanks! I had a look at signals and slots. Is this similar to Smalltalk's idea of objects sending messages to each other? Like messages they don't know about can be ignored, or something like that (I only watched Alan Kay's videos on this topic, never programmed in Smalltalk myself). If I'm not mistaken, Objective-C had something similar and was also successful for UI, so maybe message passing mechanism is something to explore more…
- thamer 5y agoWith Qt you don't really have to deal with unexpected messages. A signal is triggered by an event, like a button click or a slider value changing, a checkbox being toggled, this kind of thing. A slot is just a place to receive it, it's a regular function or method with a compatible signature for the kind of event it's meant to process. There are no unexpected calls because you have to explicitly connect a signal to a slot, something like: QObject::connect(&button, &QPushButton::clicked, &mainWindowController, &MainWindowController::onButtonClicked); If no slot is connected, the signal just doesn't go anywhere. Something that's special with Qt is that signals and slots are declared in the class using custom syntax, e.g. slots: void onValueChanged(int value); signals: void valueChanged(int newValue); Yes here "signals:" and "slots:" look like the same kind of keyword as "public:" or "private:" in a class declaration, even though internally they're #defined as "public:" and "/**/" respectively. Qt makes use of a tool called MOC – the Meta Object Compiler – to generate code for signals and slots. It's not a pre-processor but a code generator, which has to run before you can actually compile the code. I think you could probably implement a similar system of event subscriptions without this additional code generation step. See this page for details: https://woboq.com/blog/how-qt-signals-slots-work.html https://woboq.com/blog/how-qt-signals-slots-work.html
- someweirdperson 5y agoFirst, you open a port to $DISPLAY... xlib is quite a pleasure to use though, and it probably doesn't qualify as a "framework" that you don't want to use.
- bitwize 5y agoX is deprecated and virtually abandonware at this point, so... username checks out.
- badsectoracula 5y agoXorg open source and open source software doesn't become 'abandonware'.
- bitwize 5y agoSure they do, once nobody develops for them anymore, which is almost the case for X11. Nobody wants to touch that moldy old code base. There's somebody keeping the lights on I guess, but for all intents and purposes, ALL of the developer effort is on Wayland now. Wayland will catch up with and surpass X.
- badsectoracula 5y agoPeople do develop Xorg (X11 is the protocol, Xorg is the software) and as long as there is at least one person "keeping the lights on" it will be developed. Hell, even if every single programmer on earth stops working on the codebase, it can still be resurrected at some point later if someone decides to work on. Open source software is resilient to 'death' and 'abandonment' issues plaguing closed source software. I'm writing this as someone who is using a window manager (Window Maker) whose original developers abandoned it for years, then someone else picked it up some years ago to continue development and i personally have contributed bug fixes and features to it years after both of those. OSS doesn't die for as long as there is someone out there who is interested on it.
- cracrecry 5y agoI have done lots of UI interfaces in different platforms. I have used Motif and X Windows, Win32, MFC, Gtk, Qt, Cocoa, simple Web interfaces, DirectX, OpenGL, Metal. I love Dear Imgui: https://github.com/ocornut/imgui https://github.com/ocornut/imgui It is the simplest thing in the world. If you are starting and are going to do 3D graphics anyway you don't need state(you just redraw the screen 60 times per second). Anything else is extremely sophisticated. I also loved Qt, but the policies got a little cumbersome, and went native. The big problem is that with state there is a lot of complexity involved that is dependent on a platform, and once you pick one it is hard to change. The big advantage of 3d graphics and dear imgui or any other open source software is that it works anywhere and you are not as dependent on a single company.
- scott01 5y agoI actually started tinkering with Dear Imgui, very cool library! From your experience, does this approach scale for complex apps with a lot of data updates, with dozens time series visualized, edited, etc., or am I overthinking?
- joeld42 5y agoIt does, but you have to do a few extra things beyond what you'd do for the typical stuff like in-game editors and debug tools. - Data update are the best part -- there's no synchronization needed with an IMGUI approach because the "model" and "view" are the same thing. - adjust the event loop so it only redraws on changes (e.g. mousemovement) rather than every frame (unless you're drawing every frame anyways for a game) - IMGUIs can have trouble with very large lists -- imagine you have a tree view with 20k objects, you're going to process each one of them each time through the gui, even though most of them are outside the visible list. But it's hard to only draw the "visible" ones since you don't know the future (e.g. imagine iterating a list where some items are hidden). Usually this isn't a big deal to work around, just keep it in mind. - Biggest problem i've run into with IMGUI style is layout. Since you are processing widgets as you go, you can't adjust to future things. For simple layouts like stacked property sheets this is fine, but once you get beyond that it can be complicated. I'm playing with some ideas now where I use a constraint based layout to come up with "reference boxes" up front that then the IMGUI can use to layout but it's still a pretty open problem.
- hawski 5y agoI would only like to urge you to think about accessibility. There are many custom GUI libraries out there, but almost all of them are made without thinking about accessibility. It kind of forces certain architecture, which may be hard to fit later. A11y APIs expose widgets in form of a tree. I thought about writing a cross platform GUI toolkit, that would start from being a cross platform accessibility library.
- scott01 5y agoTo be honest, I'm aiming to simply practice UI architecture and optimization, and it's unlikely that something will come out of it. But I didn't know about A11Y before — thank you for bringing this up, will probably check it later.
- exikyut 5y agoIf there's one angle I'd jump on the bandwagon of harping on about it's definitely this one because a) the subject doesn't get nearly the attention it needs and b) the heavyweight toolkits (Qt and Electron would probably be the mainstream contenders) seem to be where the objectively minimum-viable implementations are (although I could be wrong), which unfortunately seems to bring "learn how to leverage $toolkit_x" to the dependency table if you want to do accessibility well. Installing a screen reader like NVDA and observing how it interacts with the screen might be interesting to learn about the scope/depth of the accessibility APIs in general. (And then there's observing how screen readers handle different websites...) Imgui and similar generally have zero accessibility support whatsoever, although it's certainly not impossible to add - just a bunch of messages back and forth to the accessibility layers in the OS - but the support would wind up being a module, and a bolted-on one at that that would have very little uptake because everyone who didn't need it (for themselves) would just compile it out. Whereas with Qt and Electron it's kind of like rabbithoooooookaybackawayfromtheinternals and everyone just leaves all the bits in :P and the support just comes along for free. (An interesting study in the tradeoffs between minimalism, modularity, and the commoditization of support of niche use cases...) Also, regarding practice of UI architecture and optimization, I actually sometimes think about the idea of drive-by contributing to open source projects - they have pre-existing contexts and conventions that must be adjusted to (an important skill that is tricky to develop alone), and it's possible to approach them with an objective impartiality that is sometimes tricky to square with emotional investment in personal projects. This may be one approach to independently evolving mechanical abilities (structure, domain-specific mental modeling and problem-solving, best practices) separately from fundamental personal development, which may (seems to?) go a little slower.
- codr7 5y agoI'm keeping an eye on Skia to try out some vector based UI ideas I've been marinating for a while.
- PaulDavisThe1st 5y agoSkia is a drawing library. GUI frameworks/toolkits/libraries require drawing but also require an event handling framework, which Skia does not provide.
- codr7 5y agoI got the impression that the point was actually building something, not stacking frameworks.
- jasonhong 5y agoI'd recommend two things. The first is Brad Myers' Software Structures for User Interfaces course at Carnegie Mellon University, which focuses on the guts of how graphical user interfaces work. https://www.cs.cmu.edu/~bam/uicourse/05631fall2021/ https://www.cs.cmu.edu/~bam/uicourse/05631fall2021/ The second is Dan Olsen's book Developing User Interfaces, which has all of the details of how GUIs work, from graphics to interactor trees to events to dispatching. For some reason, it's absurdly expensive on Amazon right now. Both Dan Olsen and Brad Myers were early pioneers in GUIs and GUI tools, so you'd be learning from the masters.
- scott01 5y agoThat's just awesome info, thanks for this! Added to reading list.
- copperx 5y agoWhat a fantastic resource. Thank you.
- gaws 5y ago> The first is Brad Myers' Software Structures for User Interfaces course at Carnegie Mellon University, which focuses on the guts of how graphical user interfaces work. The videos are locked behind a login. Does one need to be a student?
- sumedh 5y ago> For some reason, it's absurdly expensive on Amazon right now. Amazon bots have noticed that your comment is on HN so lot of people might buy it, that is why they jacked up the price :)
- ricardo81 5y agoThe cached version Google has (from 6th Feb) has the same price.
- orangepanda 5y ago
- AussieWog93 5y agoI'd recommend actually building something with Dear ImGui (IMO, the best GUI framework in existence by a country mile). Merely reading about the differences between retained and immediate mode cannot do justice to the paradigm.
- loxias 5y ago> The dummy app itself will be less about forms but more about data representation, e.g. an audio editor or a node-based system, where data should be updated and visualized in real time, and everything should feel responsive. Would you be interested in a 'no restrictions, informal' collaboration? I have little to no experience writing GUIs, but your "dummy apps" sound to me like the sorts of things I could populate the 'guts' of, to make useful. For instance, I work a lot with audio signal processing, have considerable experience in that area, and am "half-assedly" (low priority side project) writing tools that would benefit from a GUI. My email is on my profile.
- gwmnxnp_516a 5y agoThe problem of creating GUIs libraries almost from scratch is the platform fragmentation, which means that a cross-platform GUI libraries would have to abstract away the Windows API win32, that is one of the most stable and most complete GUI libraries; MacOSX Objective-C Cocoa; Unix and Linux X11 - X Windows System, that lacks Win32 button and other higher level widgets, in this case it is better to use GTK as backend instead of targeting X11 directly that may even be replaced with Wayland on major Linux distribtions; Linux Wayland backend directly; Linux framebuffer for embedded Linux systems; or OpenGL for a immediate mode GUI like Imgui. Another trouble is that GTK is not so stable like Win32 and has many breaking changes on every release that may require anything depending on this library to be modified. The following design patterns are widely used with graphical user interfaces: observer-design pattern; model-view-controller; model-view-presentation; two-way-data binding; property binding; command design pattern; and composite design patterns for representing a collection of objects as single object. For understanding event loop it may be much easier to implement a Xterm or VT100 keyboard-driven terminal user interface TUI since this does not requiring dealing with too many backends.
- toast0 5y ago> in this case it is better to use GTK as backend instead of targeting X11 directly that may even be replaced with Wayland on major Linux distribtions; X11 can work on Windows (many Xservers available, since forever), MacOS (used to ship with one, but now you've got to install one), and you can run an Xwayland in Wayland. So it's as cross platform as you can get. Might not look great, but then cross platform doesn't usually look great anyway. If you're going to do X, avoid Xlib, it adds restrictive abstractions on top of X protocol and really confuses things. XCB is much closer to just reasonable interfaces to the protocol. Ultimately, X11 is a distributed systems communication protocol which happens to have graphical output as a side effect; understanding the communications part first lets you get the most out of it.
- criddell 5y agoForget cross-platform. There are no great cross-platform toolkits. Pick a platform and make the best application you can on that platform.
- deleted 5y ago[deleted]
- TheTon 5y agoA lot of folks have given you the advice to learn one or more existing frameworks (Dear ImGui, Qt, Cocoa, etc). This is good advice, but I don't think anyone has yet articulated why it's good advice. I'll try ... Good UI frameworks are composable, and progressively expose their API users (developers) to their constituent parts, which can include systems such as drawing/rendering, animation, compositing, event handling, text editing, view hierarchy, navigation, accessibility, and so forth. As you build more complex applications with a UI framework, you naturally find yourself customizing default behaviors or implementing new controls or functionality on top of the existing capabilities. You start to see how the framework itself is built just by using it. Once you reach expert level with a UI framework, you will have a conceptual understanding of how high level features of the framework are implemented in terms of the lower level functionality. As an expert, you will feel confident that you could implement a new type of control, or reimplement existing functionality such that your version is a perfect peer to the built-in functionality from the library author on all important axes (developer API, performance, user experience, etc). In some cases this might be a lot of work, but at least you should know generally how to go about it if you had to. See if you can get to expert level with at least 2 different styles of UI frameworks. At that point, you will be capable of building your own.
- PaulDavisThe1st 5y ago> At that point, you will be capable of building your own. But almost certainly should not do so.
- travisgriggs 5y agoWhy not? Doesn’t it depend on what your goals are?
- travisgriggs 5y agoLotsa good wisdom here > Good UI frameworks are composable, and progressively expose their API users (developers) to their constituent parts, which can include systems such as drawing/rendering, animation, compositing, event handling, text editing, view hierarchy, navigation, accessibility, and so forth. I’m curious what would be good examples and bad examples for you here? My first real UI kit was with VisualWorks Smalltalk many years ago. For me, this idea of composability and exposure was really strong here. It wasn’t always the greatest code, but all the source was exposed in the class library, and so you could just use the SelectionInList or you could dig into it, put breakpoints in it, rally take it apart and learn how it all worked at whatever level of abstraction you wanted to wade into. UIKit/Cocoa didn’t provide that level of exposure because it’s a closed source binary, but there was a time when the documentation was pretty good. And much of that still persists today. And much of it was honed by many years of NextStep development, so there’s a certain consistency to much ( but not all) of it. So it hasn’t been as good, but it’s been decent. Then there’s been Android. This has been the worst. Early to market. Continuously evolved. Chasing the latest trend in UIs. Historically sparse documentation, and when you do find stuff through searching, good luck figuring out the relevancy. So this has been the worst for me. I’d be curious which of the toolkits you’ve advanced in have been strong in your rubric, and which less so?
- worewood 5y agoI have tried to make bindings for GTK in Go way when its C interface didn't even support callbacks (so I used polling to capture events). Didn't go too far because there was a lot of repetitive work involved, but learned a lot in the process. If you see yourself doing something 3+ times, automate it early!
- nikolqy 5y agoYikes. Just use Java or like C#. They perform just as good, if not better than C++ since with C++, you gotta do some things a very specific way to make it work. If anything, use the QT framework. That seems to be the biggest one for C++.
- raphlinus 5y agohttp://www.cmyr.net/blog/gui-framework-ingredients.html http://www.cmyr.net/blog/gui-framework-ingredients.html has a bunch of what you'll need to know about building a GUI from scratch, especially if you're interested in any of the "hard parts" rather than making a toy. It's Rust rather than C++ but many of the principles are similar. Other than that, I do recommend the immediate mode GUI approach if you're writing everything yourself, as it's the lowest overall system complexity of all the approaches. It has a number of drawbacks, and things don't abstract/compose as easily as a standard object-oriented retained, or a newer React/SwiftUI approach, but exposing the raw parts has its upsides.
- em3rgent0rdr 5y agoRust world really needs a GUI...would be great if you helped out making a GUI for Rust: https://www.areweguiyet.com/ https://www.areweguiyet.com/ There is a start of a native Rust GUI which you could contribute to: https://github.com/linebender/druid https://github.com/linebender/druid
- gxt 5y agoSo much this, a UI that understands traits, structs and automatically displays a control for that type in both bulk edit and single form mode would get money from me.
- em3rgent0rdr 5y agoIt would also help you learn Rust, which will likely be a more in-demand skill than C++ in the future.
- lvass 5y agoIf you're looking into building toolkits for not-too-popular languages, I feel like Erlang should be interesting, the process model sounds like a perfect match to GUI components. I've never seen anyone trying to build that, for some reason. I have a feeling GUIs with borrow checkers are hard to get right, wouldn't advise building Rust toolkits as practice.
- PaulDavisThe1st 5y ago> If you're looking into building toolkits for not-too-popular languages, Best shade thrown on HN all week! Bravo.
- em3rgent0rdr 5y agoRust is expected to be more-commonly used, cause it better handles the large domain of C/C++ based code, as it is less error-prone, but still fast and energy-efficient, which. Linux kernel is starting to support Rust now. Rust for instance has no overhead of garbage collection, while Erlang does garbage collection at the end of every function.
- 5y ago
- smaddox 5y agoI highly recommend watching Casey Muratori's presentation on immediate mode GUIs, and his Handmade Hero series (links below). https://caseymuratori.com/blog_0001 https://caseymuratori.com/blog_0001 https://handmadehero.org/ https://handmadehero.org/
- heroku 5y agoCan someone comment on how https://github.com/aseprite/aseprite/ https://github.com/aseprite/aseprite/ works.
- bitwize 5y agoYeah. Don't. GUI frameworks are like cryptography: you never want to roll your own. You will spend endless time implementing all the widgets a typical UI framework has, tweaking it until it feels kinda right, and even then they won't feel totally right until you've done extensive user testing and acted on the resultant feedback. Hundreds or thousands of hours of work for something that won't be as good as Windows, macOS, or Qt. And I haven't even gotten started on internationalization or accessibility! Ohohohoho, boy. There's a reason why the best (only good, really) UI framework is proprietary to a large, multi-trillion-dollar company. In conclusion, just use your OS's native framework or one of the half-decent ones for Linux if you're working on Linux.
- 4silvertooth 5y agoI think you should checkout www.juce.com framework github https://github.com/juce-framework/JUCE https://github.com/juce-framework/JUCE.
- throwaway2037 5y agoI cannot believe that no one has mentioned HTML Canvas with JavaScript. I'm no fan-boi/gurl for JavaScript, but you can do some crazy and amazing things with HTML Canvas in a modern web browser. Plus, "everyone" seems to think that TypeScript is a pretty great advance on JavaScript, by adding a bunch of useful things, like stricter types. As an added bonus, it's easy to share the results with others -- all they need is a browser.
- ale42 5y agoI think the original question was about C++?
- throwaway2037 5y agoI checked the original question again. It says: <<probably in C++>> My point was to open the door to the amazing web browser-based GUI platform that is HTML Canvas + Java/TypeScript. :)
- elcritch 5y agoI've been enjoying hacking on Fidget as a side project! It's inspired by Figma and is written in pure Nim with an OpenGL backend. Previously I'd been dabbling with ImGui, but wanted something with an efficient event loop driven renderer. It's enjoyable writing in a compact language that's fast and provides memory management. Here's my fork of Fidget: https://github.com/elcritch/fidget https://github.com/elcritch/fidget I've uploaded a few youtube samples: https://www.youtube.com/playlist?list=PLfEcHAJujZRlloKeDj6iK7L-QLOaGtpqA https://www.youtube.com/playlist?list=PLfEcHAJujZRlloKeDj6iK... Based on what you're asking about you might be interested in following an example where I tied in Nim's async system into Fidget: https://github.com/elcritch/fidget/blob/devel/tests/progressbar/progressbar.nim https://github.com/elcritch/fidget/blob/devel/tests/progress...
- jazzfool 5y agoThere is no right way to design a GUI library, so ignore the people that insist you read a book and follow the paradigms it mentions to a T. In fact, we really need less of those OOP GUI libraries right now. Definitely try poke around with reactive, etc.
- scott01 5y agoSuper! Thanks everyone for your answers. A lot of things to explore!