top | item 42450963

Show HN: Brisk – Cross-Platform C++ GUI Framework: Declarative, Reactive, Fast

84 points| danlcaza | 1 year ago |github.com

Brisk is an open-source C++ GUI framework with a declarative approach, offering powerful data bindings, GPU-accelerated graphics, and dynamic widget management. It supports macOS, Linux, Windows, and simplifies UI creation with modern paradigms and CSS-like layouts. Initially developed for a graphics-intensive project with a complex and dynamic GUI, the framework is currently under active development.

79 comments

order

gpderetta|1 year ago

All those naked 'new's in the example make me nervous. I see that the library uses exceptions, if one of the widget constructor throws while composing the overall widget hierarchy, it would leak memory.

You should be able to make it work with a value-based interface and allocating behind the scenes (this would also enable a few optimization opportunities).

danlcaza|1 year ago

Thank you for the feedback. The framework was originally built with exceptions always disabled, and it is currently being reworked to support both modes: exceptions enabled and disabled. Some approaches definitely need to be reconsidered.

An alternative approach is to use the rcnew macro, which wraps a pointer in a shared_ptr under the hood. Details on the implementation of rcnew can be found at: https://www.kfr.dev/blog/three-cpp-tricks/

mdaniel|1 year ago

Since it's cited as cross-platform, including non-Windows screenshots would be helpful https://github.com/brisklib/brisk#screenshots

Also, I wasn't able to readily find any information about keybindings for the widgets, e.g. the way some frameworks use "&Monday" to make alt-m act on that checkbox https://github.com/brisklib/brisk/blob/v0.9.3/examples/showc...

I did see your "unhandled" event handler doing its own keybinding dispatch <https://github.com/brisklib/brisk/blob/v0.9.3/examples/calc/...> but I hope that's not the normal way to do keybinding

danlcaza|1 year ago

Good point about the non-Windows screenshots, but the Brisk library apps look exactly the same (except for window decorations and DPI scaling) on any supported OS due to its custom pixel-perfect graphics engine and its own font engine (based on FreeType and HarfBuzz, of course). Key bindings are not supported at the moment. The calc example shows a possible workaround for this.

rubymamis|1 year ago

While I welcome new cross-platform GUI Frameworks, I wonder why not use a declarative UI similar to QML? Even Slint[1] (which is built in Rust) uses such syntax for its UI.

[1] https://slint.dev

CyberDildonics|1 year ago

It isn't really that important to have a declarative UI, making the UI is rarely the time consuming or difficult part of making a program. An extra markup language for a UI adds bloat and ambiguity. Now you're learning a different ad hoc language and trying to get around its quirks just to be able to feed in data that could have been done directly with functions.

igortg|1 year ago

I second that. I used Dash for a while. Although it's nice to have everything wired up for free, the code quickly becomes a mess as soon as you try some more complex things (or you put everything in one function and got a big super nested structure, or you build a lot of small components and quickly get lost in a sea of small functions).

I'd rather build the HTML myself.

[1]: https://dash.plotly.com/

joeld42|1 year ago

This looks really good. It's nice to see some options like this (and slint) appearing for cross-platform desktop GUI. I'm pretty skeptical of "modern" c++ but this looks like a good example of using it where it makes sense.

The data binding looks particularly clever. That's usually the Achilles heel of GUI toolkits (for me at least) and that looks like a clever and novel solution if it works.

danlcaza|1 year ago

Thank you for the feedback. C++ isn't a language that makes data binding implementation easy, but C++20 introduces some useful features that could be leveraged for this purpose.

criddell|1 year ago

How well integrated with the underlying platform is it? For example, on Windows do you take advantage of accessibility APIs for things like screen readers?

apitman|1 year ago

I don't think open source GUI toolkit developers should be expected to handle accessibility until OS vendors spend some of their billions of dollars to develop a reasonable cross-platform API.

danlcaza|1 year ago

Accessibility features are planned and will be included in one of the upcoming major releases.

hilti|1 year ago

"However, for those who wish to use Brisk in proprietary or closed-source applications, a commercial license is also available."

Unfortunately there is no public information on the pricing.

danlcaza|1 year ago

The pricing information will be made public at the time of the next Beta release. Currently, the framework is refining Linux support, with plans to include mobile platforms as well.

Night_Thastus|1 year ago

As someone who lives and breathes QT at the moment - what would you says the main differences are? What does Brisk offer that QT doesn't and vice-versa?

Though unfortunately since it's not lGPL or MIT, it doesn't look like I could use it anyways.

jenadine|1 year ago

> Though unfortunately since it's not lGPL or MIT, it doesn't look like I could use it anyways.

Why not. They also intend to have a commercial license. Don't event want to consider paying?

taraharris|1 year ago

I spent a very long time giving SolveSpace a native Haiku UI. I'm going to keep doing this kind of thing because there's nothing I personally dislike more than apps that don't use the platform's native UI.

I don't care that my approach is harder for the developer, because the thing I care about is consistency and convenience for the user.

I know the thing you built is neat (I've spent quite a few years working on almost the same thing), but I guess this is why I gave up on pushing my own solution

fsloth|1 year ago

” nothing I personally dislike more than apps that don't use the platform's native UI”

I’m not sure if this is universally applicable dogma. Games generally apply their own UI regardless of platform.

Web apps generally do as well.

I do realize there is space for apps with least surprise per platform, but it’s not obvious to me if an app benefits from platform standard UI any quantifiable way.

danlcaza|1 year ago

There are many professional applications (not games) that use custom-drawn UIs. Examples include video editing software, 3D modeling tools, and professional audio plug-ins. These applications may rely on a significant amount of platform-specific APIs for better OS integration, yet they maintain a consistent appearance across all supported platforms.

pkphilip|1 year ago

If you are going for declarative UIs, please consider using a separate file for storing the UI and a "code behind" which is the C/C++ source file for that screen. This external file can be written in a form suitable for IDEs to read/write the form properties including all of the components in the form in the hierarchy in which they are put in during the design of the form.

The powerful approach used by Delphi for this is something I have never seen any other language use - where you could create your own components and these components could persist their properties into this external file used for storing the details about the form. So when the IDE loads the design from the external file, it would call the components to read the properties from the file to repopulate itself. This allowed for very powerful and deep components to be developed in Delphi

NoZZz|1 year ago

I don't want to be a party pooper here, but, I am so that's how it comes out. In code declaration of user interfaces was old hat in Qt, and wxWidgets Why no interpreter? Recompiling to fritz with UI is just a bore.

danlcaza|1 year ago

Specifying things declaratively within the language itself goes far beyond simply constructing widgets by calling library functions.

This technique is utilized in modern frameworks like Jetpack Compose, Flutter and SwiftUI and unlocks several powerful features, such as flexible data binding and the ability to rebuild the widget tree on demand, features that would be quite difficult to implement in other libraries.

clarge1120|1 year ago

Nice to see someone taking a swing at a C++ GUI framework. Implementing a real on is not for the weak. If it's really works, it'll be expensive to license.

ks2048|1 year ago

I've only dabbled a bit in 3D graphics (OpenGL, THREE.js, swift SceneKit). When these 2D GUIs say "GPU-accelerated", does that mean they are doing the same thing you would do for 3D - build triangular meshes, materials, etc - and then just essentially point an orthographic camera at this "scene"? Or what kind of low-level GPU APIs (eg WebGPU) are used?

delta_p_delta_x|1 year ago

> When these 2D GUIs say "GPU-accelerated", does that mean they are doing the same thing you would do for 3D

Yes. Nowadays all modern desktop interfaces—Aero/Metro/WinUI2/3 on Windows, Aqua/Cocoa on macOS, KDE, GNOME, XFCE, LXDE, and even some window managers on Linux—are 'GPU-accelerated'.

Every window is a quad of two triangles. There's no real vertex shading since it's all orthographic as you mentioned. The framebuffer for each window is exactly the x:y resolution for that window (macOS does some interesting 1:2 resizing here sometimes). The 'fragment shaders' is where the GUI toolkit comes in, writes to these buffers, and does any decorating where needed.

The final framebuffer is exactly the resolution of the entire monitor (again, macOS may do some weird 1:2 resizing).

The framebuffers of all windows on-screen are composed into this one. This is where things like transparency effects, the window and scroll controls, drop shadows, any 'rounding off' masks (used to great extent in macOS), and funky 'frosted glass'/'reflection' effects come in. This gives the effect of windows behind/in front of other windows. This is also when partially/fully off-screen windows are clipped/culled against the viewport frustum (not really a frustum but more a cuboid since it's not a perspective).

Once all this is done, you have a frame that's ready to be piped down the display cable into the display.

There are some other facets muddying the water like HDCP DRM protection for the entire framebuffer or some window framebuffers, variable-rate refresh, and so on. The former is how PrintScreen on Windows returns a black screen for some windows—that's HDCP in action.

joeld42|1 year ago

Most of the drawing work of a GUI is drawing text, shape paths, and images. A GPU-accelerated UI layer draws these using GPU commands. It's not exactly the same as making an ortho 2D scene, but conceptually that's pretty much it. Often it means using crude geometry (such as a quad per glyph in a text renderer, or a "ribbon" of quads to cover a curve) and using a shader to draw the glyph or curve itself.

For a simple example, think of a rounded rect. Typically this would draw as a quad (a pair of triangles), and a shader would calculate the rounded corners.

There's also a lot of compositing and clipping that happens in a UI (e.g. a large widget inside a scrollbox) which is challenging to do on GPU as these get nested.

danlcaza|1 year ago

Modern 3D rendering APIs (like Metal, D3D12 and Vulkan and D3D11 to some extent) offer far more flexibility than the traditional triangles-and-materials approach. Rendering in Brisk leverages complex shaders that directly process drawing commands on GPU, avoiding the intermediate step of converting them into a list of triangles.

For text rendering, Brisk uses FreeType to render glyphs on the CPU and caches these glyphs in a GPU-accessible texture, which is reused for improved performance. This approach is common among GUI toolkits for handling graphics and fonts.

In addition to this, Brisk employs SDF (signed distance field) graphics wherever possible, which are entirely computed in shaders.

gosub100|1 year ago

I think it just means the texture image for the widgets are loaded into gpu memory space instead of a traditional framebuffer that gets copied to the gpu.

I dabbled in 3D for a while too and was astonished how much 2D stuff there is for it.

wczekalski|1 year ago

My friend and I used to build a cross platform UI library in OCaml called… brisk. We didn’t make it production ready so i am sure the naming is a coincidence https://github.com/briskml/brisk.

danlcaza|1 year ago

Unfortunately, I didn't come across your library when checking for name collisions. You're right, this is purely a coincidence.

samiv|1 year ago

The one thing I have to wonder is:

  How many people really want to spend time programming their UIs?
I use Qt myself and one of the best things about the framework and toolkit is the UI tooling that allows me to drag and drop and visually create my UIs in the UI Designer app.

I find that for any non-trivial application this type of boilerplate is best done with good tooling that just works and lets the UI to be knocked up fast and efficiently.

I also wrote an UI system for my game engine but it's completely drag & drop in the editor. Styling (skinning) is also via UI builder.

Source:

https://github.com/ensisoft/detonator/tree/master/uikit

Live demo:

https://ensisoft.com/demos/ui/game.html

Question, how do you handle arbitrary clipping masks ? In my solution clipping masks require evaluating all the widget parent's clipping rects and writing them to stencil buffer before rendering the current widget. This is unfortunately quite slow...

rubymamis|1 year ago

> I use Qt myself and one of the best things about the framework and toolkit is the UI tooling that allows me to drag and drop and visually create my UIs in the UI Designer app.

But then it's not trivial to write responsive/adaptive applications. In contrast, QML makes it extremely easy to build such apps.

I used to build UIs in the designer as well[1] but after studying QML there's no going back. Here's a new project I program solely in QML (and C++ for the logic)[2].

[1] https://github.com/nuttyartist/notes

[2] https://www.get-vox.com/

SaintSeiya|1 year ago

I'll wait for the new gen of developers to re-discover WYSIWYG cross-platform GUI frameworks such as C++ Builder / Lazarus / Delphi like we had in the 90s

hgs3|1 year ago

Nice project! Do you think you'd ever support a "live preview" or "hot reloading" of the UI or is that beyond the scope of the project?

danlcaza|1 year ago

This is definitely a great feature for future versions and is already in our backlog, though it will require significant effort to implement. Thank you.

feverzsj|1 year ago

To make it really declarative and exception safe, you need to wrap widget creation in function and return smart pointer.

mllev|1 year ago

Great job, looks like a huge amount of work.

gitprolinux|1 year ago

Very nice, can't wait if you could make it compatible with a Python3 wrapper.

DrBenCarson|1 year ago

Incredible to see people working on this so kudos

Why would someone use C++ and not Rust in 2024? Familiarity and experience?

baudaux|1 year ago

I see that WebGPU is used so it is a good candidate for being tried in https://exaequos.com, the OS I am creating and that fully runs in the web browser