Beginner
Utilities
File dialogs, JSON, clipped drawing, a shader library and sprite-sheet slicing — the small pieces most applications need eventually.
Introduction
Five Small Utilities
A handful of small utilities that solve problems most applications hit eventually.
| Utility | Solves |
|---|---|
ml::FileDialog | Native open and save dialogs |
ml::json | Reading and writing JSON |
ml::withClipView | Drawing clipped to a rectangle |
ml::ShaderLibrary | Ready-made GLSL effects |
ml::TextureSlicer | Cutting a sprite sheet into frames |
1Files
ml::FileDialog
Native dialogs, so they look and behave the way the platform's do.
#include <Malena/Utilities/FileDialog.h>
const std::string path = ml::FileDialog::open(
{ { "Quiz files", "quiz" }, { "All files", "*" } });
if (!path.empty())
loadQuiz(path);
| Call | Returns |
|---|---|
FileDialog::open(filters, defaultPath) | One path, or "" if cancelled. |
FileDialog::save(filters, defaultPath) | A path to write to, or "". |
FileDialog::openMultiple(filters, defaultPath) | A vector of paths; empty if cancelled. |
An empty string means cancelled, not failed. Always check before using the result — treating a cancel as a path is how you end up trying to open
"" and reporting a confusing error to the user.2Data
ml::json
ml::json is nlohmann's JSON type, brought into the ml namespace so you are not repeating a long qualification.
#include <Malena/Utilities/Json.h>
ml::json config;
config["fullscreen"] = true;
config["recent"] = { "a.quiz", "b.quiz" };
const std::string text = config.dump(2); // pretty-printed
ml::json parsed = ml::json::parse(text);
Use
value(key, fallback) rather than operator[] when reading anything that might be absent — a missing key with [] throws, and on a config file written by an older version of your app that is a crash on startup.const bool fullscreen = parsed.value("fullscreen", false); // safe
3Drawing
withClipView
withClipView restricts drawing to a rectangle — the mechanism behind scrolling panes, where content must stop at the edge rather than spilling over its neighbours.
ml::withClipView(target, viewportRect, [&]{
for (auto& row : rows)
target.draw(row); // nothing escapes viewportRect
});
It saves and restores the target's view around your callback, so it nests correctly and leaves the target as it found it — including if your drawing code throws.
4Effects
ShaderLibrary
ShaderLibrary returns GLSL source for common effects, so you are not writing shader code to get a standard result.
sf::Shader shader;
shader.loadFromMemory(std::string(ml::ShaderLibrary::fadeEdges()),
sf::Shader::Type::Fragment);
| Effect | Does |
|---|---|
fadeEdges() | Fades content out at the edges — soft scroll boundaries. |
scaleCenter() | Scales about the centre. |
blurUnfocused() | Blurs what is not focused. |
coverflow3D() | Perspective tilt for carousels. |
colorTint() | Tints toward a colour. |
waveDistortion() | Sine distortion. |
depthOfField() | Depth-based blur. |
Each returns a
std::string_view over a static string, so there is no copy and nothing to own — but loadFromMemory wants a std::string, hence the explicit construction above.5Textures
TextureSlicer
TextureSlicer cuts a sprite sheet into frame rectangles.
// A 4x4 sheet -> every frame
ml::ImageRects frames = ml::TextureSlicer::getImageRects(sheet, 4, 4);
// Or one frame by grid coordinate
ml::ImageRects one = ml::TextureSlicer::getImageRects(sheet, sf::Vector2i{2, 1});
Slice once and keep the result. Recomputing rectangles every frame is wasted work — the sheet does not change, so neither do its rectangles.