ml::docs | Your First App Manifests Events Messaging Plugins Scenes Resources
See all tutorials →
Beginner 6 sections ~9 min C++17/20

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.

UtilitySolves
ml::FileDialogNative open and save dialogs
ml::jsonReading and writing JSON
ml::withClipViewDrawing clipped to a rectangle
ml::ShaderLibraryReady-made GLSL effects
ml::TextureSlicerCutting 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);
CallReturns
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);
EffectDoes
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.