August 19, 2021 by Olivier Goffart and Simon Hausmann
Announcing SixtyFPS 0.1
We're proud to announce the SixtyFPS 0.1 series. The 0.1 series, to us, signifies that our toolkit is graduating from "lab mode" to "development mode". We are now confident that our toolkit can be used in products. Based on semantic versioning principles, all 0.1.x releases will maintain compatibility.
The 0.1 Series
We've implemented plenty of new features and fixed many bugs. Thank you to all the early adopters who provided high-quality bug reports and feedback. We also reached 1000 stars on GitHub 🤩.
What's SixtyFPS
SixtyFPS is a fresh, new graphical toolkit for desktop apps and embedded devices.
We're building a product to make UI development faster and easier, no matter what programming language, platform, or form-factor. Our toolkit consists of the following key components:
- A design-friendly markup language for UI elements
- A run-time library with APIs in C++, Rust and JavaScript
- An optimizing compiler to compile designs to native C++/Rust code
SixtyFPS is actively developed on GitHub. We provide three options for licensing:
- Open Source under the GPL
- Ambassador Program with free commercial licensing for small businesses
- Commercial license
Highlights
We last caught up with you on the 0.0.6 release. Here are the highlights between then and the just released v0.1.1; full details available in our change log.
A new style
We've written a new, beautiful widget style that implements Microsoft's fluent design. This replaces our previous attempt at a distinct style, jokingly called the "ugly" style.
SixtyFPS can also style widgets according to the platform's native look, if you have Qt installed.
These screenshots also show the new TabWidget
.
New API for custom rendering
When working with images, the
Image
element's source
specifies where it's stored. When this property is exposed to
Rust or
C++,
the type is sixtyfps::Image
.
You can create sixtyfps::Image
from a file system path or from a pixel buffer.
Use this API to create images dynamically at run-time with Rust code or integrate other crates that produce graphics
into your SixtyFPS UI. Our new plotter example
demonstrates this use-case with the plotters crate:
Various improvements to the .60 markup language
Our markup language is used by designers and developers, and it's intuitive and type-safe. We observed that when declaring two-way bindings to forward a property, it can be cumbersome to repeat the property type. Now, we've gotten rid of this requirement - you can declare two-way bindings for properties and callbacks using a shorter syntax:
export Application := Window {
property action <=> button.text;
callback triggered <=> button.clicked;
button := Button { }
}
Layout improvements
For consistency across all items, layout elements now have their own x
and y
properties.
We've changed the default spacing
and padding
to be zero. The style-provided counterparts
HorizontalBox
, VerticalBox
, and GridBox
come with defaults that give a natural spacing and padding between widgets.
The layout constraints of elements, such as their minimum or maximum size, are now consistently propagated throughout the hierarchy of elements.
This includes support for "height-for-width" for Text
and Image
elements.
To set the preferred size when a Window
is first shown, use the preferred-width
and preferred-height
properties.
Setting the width
and height
properties locks the window's size; free resizing by the user is then disabled.
Threading support improvements
To keep the application GUI fluid, it's important to perform long lasting operations in a different thread and not block the GUI thread. For platform specific reasons, the SixtyFPS UI must "live" in the main thread, other threads need to synchronize or communicate with it. In SixtyFPS version 0.1, we added helper functions in the Rust and C++ API to help to communicate between worker threads and the UI thread. Here's how to use them in Rust:
// Create a handle to `MyWindow`, the type generated by the `sixtyfps!` macro
let window_handle = MyWindow::new();
// ... set properties and callbacks on window_handle ...
// pass a weak handle to the window to a worker thread
let handle_weak = window_handle.as_weak();
let thread = std::thread::spawn(move || {
// ... Do some computation in the thread ...
let result = { /* ... */ };
// now forward the data to the main thread using sixtyfps::weak::upgrade_in_event_loop
handle_weak.upgrade_in_event_loop(move |handle| {
// this code here is run in the main UI thread
handle.set_status_text(result);
});
});
// run the event loop in the UI thread
handle.run();
// Create a handle to `MyWindow`, the type
// generated by the `sixtyfps!` macro
let window_handle = MyWindow::new();
// ...
// set properties and callbacks on
// window_handle ...
// pass a weak handle to the window to a
// worker thread
let handle_weak = window_handle.as_weak();
let thread = std::thread::spawn(move || {
// ... Do some computation in the
// thread ...
let result = { /* ... */ };
// now forward the data to the main
// thread using
// sixtyfps::weak::upgrade_in_event_loop
handle_weak.upgrade_in_event_loop(
move |handle| {
// this code here is run in the main
// UI thread
handle.set_status_text(result);
});
});
// run the event loop in the UI thread
handle.run();
For more details, check out the documentation for Rust and for C++. For real threaded application code, check out Cargo-UI.
What’s next?
SixtyFPS is already happily used by customers on embedded devices. We plan on building up the Desktop support in subsequent releases to reach the level of integration we're aiming for.
C++
For use with C++ we provide a CMake integration that takes care of the installation.
C++/CMake Install DocsVisual Studio Code
Install for VS Code that provides syntax highlighting, a live preview and more.
Install ExtensionVideo Tutorial
If you'd like to learn SixtyFPS by watching a video, check out our tutorial on YouTube.
Watch 🎥We hope you'll enjoy developing with SixtyFPS and we look forward to your feedback. You can post a message in our GitHub Discussions Forum or chat with us on our Mattermost instance. For fresh news follow us on Twitter: @sixtyfpsui.
Slint is a Rust-based toolkit for creating reactive and fluent user interfaces across a range of targets, from embedded devices with limited resources to powerful mobile devices and desktop machines. Supporting Android, Windows, Mac, Linux, and bare-metal systems, Slint features an easy-to-learn domain-specific language (DSL) that compiles into native code, optimizing for the target device's capabilities. It facilitates collaboration between designers and developers on shared projects and supports business logic development in Rust, C++, JavaScript, or Python.