Selection Controls
Checkboxes, radio buttons, and dropdown selects — all with automatic layout helpers, group management, per-item enable/disable, and theme integration.
Selection Control Types
Malena provides five selection-related classes:
| Class | Purpose | Variant template |
|---|---|---|
ml::Checkbox | Single toggleable checkbox with a square indicator and text label | CheckboxWith<M> |
ml::CheckboxGroup | Self-contained group of checkboxes with automatic vertical layout | CheckboxGroupWith<M> |
ml::RadioButton | Single radio option with a circular indicator and text label | RadioButtonWith<M> |
ml::RadioGroup | Self-contained group that enforces single-selection among its buttons | RadioGroupWith<M> |
ml::Select | Dropdown with rich per-item content — icons, descriptions, sub-styles | SelectWith<M> |
All five follow the same Settings/Theme/Themeable layering. Pass applySettings(), applyTheme(), or applyStyle() a struct that derives from the appropriate base types.
Checkbox
A toggleable square indicator with a text label. Inherits CheckboxSettings (box size, gap, label padding) and CheckboxTheme (colors, font). The active app theme is applied automatically. An optional font passed to the constructor overrides the themed font.
ml::Checkbox cb("Enable notifications");
cb.setPosition({100.f, 150.f});
cb.onClick([&cb] {
bool checked = cb.isChecked();
updateSetting("notifications", checked);
});
addComponent(cb);
cb.check(); // force checked
cb.uncheck(); // force unchecked
cb.toggle(); // flip current state
bool on = cb.isChecked();
cb.setEnabled(false); // disable
bool en = cb.isEnabled();
cb.setLabel("Show FPS"); // change label text
| Flag | State | Meaning |
|---|---|---|
Flag::CHECKED | State::CHECKED | Checkbox is checked |
Flag::DISABLED | State::DISABLED | Interactions suppressed |
| — | State::IDLE | Default |
| — | State::HOVERED | Mouse is over the checkbox |
CheckboxGroup
Manages a list of checkboxes with automatic vertical layout. Adding options via addOption() creates and owns a Checkbox internally — style changes propagate to all owned items automatically. You can also register external checkboxes via add().
ml::CheckboxGroup prefs;
prefs.addOption("Auto-save", true); // pre-checked
prefs.addOption("Show grid", false);
prefs.addOption("Enable tooltips", true);
prefs.setPosition({100.f, 100.f});
prefs.onSelectionChanged([](const std::vector<std::string>& checked) {
for (const auto& label : checked)
std::cout << label << " is checked\n";
});
addComponent(prefs);
prefs.check(0); // check item at index 0
prefs.uncheck(1); // uncheck item at index 1
prefs.checkAll();
prefs.uncheckAll();
bool firstOn = prefs.isChecked(0);
auto labels = prefs.getCheckedLabels(); // vector<string>
auto indices = prefs.getCheckedIndices(); // vector<size_t>
prefs.setOptionEnabled(2, false); // disable "Enable tooltips"
RadioButton & RadioGroup
RadioButton is a standalone circular indicator. Use it when you need direct control. RadioGroup owns a set of buttons, enforces that only one can be selected at a time, and fires a single callback on change.
ml::RadioButton opt("Option A");
opt.setPosition({100.f, 150.f});
opt.select(); // force selected
bool sel = opt.isSelected();
opt.deselect();
opt.setEnabled(false);
opt.setLabel("Option A (locked)");
ml::RadioGroup quality;
quality.addOption("Low");
quality.addOption("Medium");
quality.addOption("High");
quality.selectFirst(); // select "Low" by default
quality.setPosition({100.f, 100.f});
quality.onSelectionChanged([](const std::string& label, std::size_t index) {
setGraphicsQuality(index);
});
addComponent(quality);
quality.select(2); // force "High" programmatically
std::string label = quality.getSelectedLabel(); // "High"
std::size_t idx = quality.getSelectedIndex(); // 2
ml::RadioButton* btn = quality.getSelected(); // pointer (or nullptr)
quality.setOptionEnabled(0, false); // disable "Low"
Select
A dropdown control with a trigger button and a floating panel. Each option has a label, a value, and an optional SelectOptionStyle that overrides colors, font, size, bold/italic, icon, and a secondary description line. Custom ml::Core components can also be used as option rows.
ml::Select resolution;
resolution.setPlaceholder("Choose resolution...");
resolution.setPosition({100.f, 100.f});
resolution.addOption("1920 × 1080", "1080p");
resolution.addOption("2560 × 1440", "1440p");
resolution.addOption("3840 × 2160", "4K");
resolution.onSelectionChanged([](const std::string& value, std::size_t index) {
applyResolution(value);
});
addComponent(resolution);
ml::SelectOptionStyle warnStyle;
warnStyle.color = sf::Color(220, 80, 80);
warnStyle.description = "May reduce performance";
resolution.addOption("7680 × 4320", "8K", warnStyle);
resolution.selectIndex(1); // select "1440p" by index
resolution.selectValue("4K"); // select by value string
resolution.clearSelection(); // deselect all
int idx = resolution.getSelectedIndex(); // -1 if none
std::string lbl = resolution.getSelectedLabel();
std::string val = resolution.getSelectedValue();
resolution.setOptionEnabled(2, false); // disable "4K"
resolution.setEnabled(false); // disable the whole control
// Open / close the panel programmatically
resolution.open();
resolution.close();
bool open = resolution.isOpen();