Development
Hyprtoolkit is a pure C++ toolkit. It relies on modern C++ in the Hyprland style (with hyprutils, etc).
It’s recommended you are familiar with C++ before developing an app.
Getting Started
If you prefer living off of examples, see the tests/ directory in the hyprtoolkit repo.
Start by creating a backend and opening a window:
// in this example we are doing this to skip Hyprtoolkit::
using namespace Hyprtoolkit;
auto backend = CBackend::create();
auto window = CWindowBuilder::begin()->appTitle("Hello")->appClass("hyprtoolkit")->commence();this will create (but not yet open) a window handle for you.
Hyprtoolkit is a retained mode toolkit, so you can define your layout with C++ and forget about it.
First thing we need is a background rectangle, by doing this:
window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return backend->getPalette()->m_colors.background; })->commence());[!NOTE] Remember to always use the palette when possible for your app to adhere to the user’s theme.
All elements are under hyprtoolkit/elements/, you can browse through them. Let’s add a simple layout with
some buttons:
auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_PERCENT, {1.F, 1.F}})->commence();
layout->setMargin(3);
window->m_rootElement->addChild(layout);
layout->addChild(CButtonBuilder::begin()
->label("Do something")
->onMainClick([](SP<CButtonElement> el) { std::println("Did something!"); })
->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}})
->commence()
);
layout->addChild(CButtonBuilder::begin()
->label("Do something else")
->onMainClick([](SP<CButtonElement> el) { std::println("Did something else!"); })
->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}})
->commence()
);This adds a column layout (elements are stacked on top of each other) with two buttons. These buttons have automatic sizing, so will fit their contents.
Once you are done, add a close callback, open the window and enter the main loop:
window->m_events.closeRequest.listenStatic([w = WP<IWindow>{window}] {
w->close();
backend->destroy();
});
window->open();
backend->enterLoop();Layout System
The layout system relies on absolute and layout positioning modes. Let’s zoom into both:
Absolute Mode
This happens when the parent of your element is anything but a ColumnLayout or a RowLayout. Children are positioned within their parent, according to their
position mode. You can set it with setPositionMode and add offsets with setAbsolutePosition.
For example:
setPositionModewithCENTERwill center the child inside the parent.setPositionModewithABSOLUTEwill make it be in the top left corner.- Adding
setAbsolutePositionto the above with{200, 200}will move it 200 layout px down and right from the top left corner of the parent.
Layout Mode
This happens when the parent of your element is a layout. These will attempt to position your child elements. They work similarly to CSS’s flex and qt’s RowLayout and ColumnLayout,
but will not wrap. If elements overflow and cannot shrink, they will disappear.
RowLayout positions elements next to each other side-by-side, while ColumnLayout does it top-bottom.
Size
All elements carry a SizeType. This tells the layout system how to size the element.
ABSOLUTEtakes layout px as size and makes the element rigid.PERCENTtakes a percentage in the form of(0, 0) - (1, 1)and will be the size of the parent multiplied by the percentage.AUTOignores the passed vector (leave it empty) and instead will always attempt to contain the children*
[!NOTE] Some elements will force their own sizing, e.g.
Text.
Leave themAUTOto avoid confusion.
Elements
Most elements are self-explanatory. You can explore their builder functions to see what styling / behavior options they support.
Each element is created with a Builder which is there to maintain ABI stability. After you call ->commence(), you
will get a SP to the newly created object.
You can rebuild the object at any time by calling ->rebuild() and you’ll get a builder again.
Remember to call commence() after you are done to apply the changes!
You do not need to keep the SP after adding the element to the tree with addChild.
Other
Other, miscellaneous stuff
System Icons
Use the CBackend::systemIcons() function to obtain a reference to ISystemIconFactory which allows
you to query system icons by name.
You can check the obtained result object to see if the icon was found.
Then, you can take that object and slap it into an ImageElement to add it to your layout.
Additional FDs
If you have an app that depends on some other loop, e.g. pipewire, dbus, etc. you need to remember
that hyprtoolkit is strictly single-threaded for layout and rendering.
You cannot edit the layout from another thread.
For this, use CBackend::addFd() to add a FD to the loop alongside a function that will be called once the fd
is readable.
This function will be called from the main thread, so you can do whatever you want in there.