Files
dusklight/src/dusk/ui/modal.cpp
T
2026-07-13 16:55:08 -07:00

146 lines
3.9 KiB
C++

#include "modal.hpp"
#include "string_button.hpp"
namespace dusk::ui {
Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::move(props)) {
if (!mProps.variant.empty()) {
mRoot->SetClass(mProps.variant, true);
}
auto* header = append(mDialog, "div");
header->SetClass("modal-header", true);
auto* title = append(header, "div");
title->SetClass("modal-title", true);
title->SetInnerRML(mProps.title);
if (!mProps.icon.empty()) {
auto* icon = append(header, "icon");
icon->SetClass(mProps.icon, true);
}
auto* body = append(mDialog, "div");
body->SetClass("modal-body", true);
body->SetInnerRML(mProps.bodyRml);
auto* actions = append(mDialog, "div");
actions->SetClass("modal-actions", true);
for (auto& action : mProps.actions) {
add_action(std::move(action));
}
mDoAud_seStartMenu(kSoundWindowOpen);
}
void Modal::add_action(ModalAction action) {
auto* actions = mDialog->QuerySelector(".modal-actions");
auto btn = std::make_unique<Button>(actions, action.label);
btn->root()->SetClass("modal-btn", true);
btn->on_pressed([this, callback = std::move(action.onPressed)] {
if (callback) {
callback(*this);
}
});
mButtons.push_back(std::move(btn));
}
void Modal::set_body(const Rml::String& bodyRml) {
mDialog->QuerySelector(".modal-body")->SetInnerRML(bodyRml);
}
void Modal::set_icon(const Rml::String& icon) {
auto* iconElem = mDialog->QuerySelector("icon");
if (icon.empty()) {
if (iconElem != nullptr) {
iconElem->GetParentNode()->RemoveChild(iconElem);
}
return;
}
if (iconElem == nullptr) {
// The constructor only creates the icon element when Props.icon is set.
iconElem = append(mDialog->QuerySelector(".modal-header"), "icon");
}
iconElem->SetClassNames(icon);
}
bool Modal::focus() {
if (!mButtons.empty()) {
return mButtons.front()->focus();
}
return false;
}
void Modal::dismiss() {
if (mProps.onDismiss) {
mProps.onDismiss(*this);
return;
}
pop();
}
bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
if (cmd == NavCommand::Cancel || cmd == NavCommand::Menu) {
mDoAud_seStartMenu(kSoundWindowClose);
dismiss();
return true;
}
int direction = 0;
if (cmd == NavCommand::Left) {
direction = -1;
} else if (cmd == NavCommand::Right) {
direction = 1;
} else {
return false;
}
auto* target = event.GetTargetElement();
for (int i = 0; i < static_cast<int>(mButtons.size()); ++i) {
if (mButtons[i]->contains(target)) {
const int next = i + direction;
if (next >= 0 && next < static_cast<int>(mButtons.size()) && mButtons[next]->focus()) {
mDoAud_seStartMenu(kSoundItemFocus);
return true;
}
return false;
}
}
return false;
}
TextInputModal::TextInputModal(Props props) : Modal(props) {
auto modalBody = mDialog->QuerySelector(".modal-body");
mInput = std::make_unique<StringButton>(modalBody, StringButton::Props{
.getValue = [this]{return mInputText;},
.setValue = [this](Rml::String value) { mInputText = value; },
});
mInput->start_editing();
}
bool TextInputModal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
auto retVal = Modal::handle_nav_command(event, cmd);
if (!retVal) {
if (mInput->root()->IsPseudoClassSet("focus") && cmd == NavCommand::Down) {
mButtons[0]->focus();
retVal = true;
} else if (!mInput->root()->IsPseudoClassSet("focus") && cmd == NavCommand::Up) {
mInput->focus();
retVal = true;
}
}
return retVal;
}
void TextInputModal::update() {
mInput->update();
Document::update();
}
} // namespace dusk::ui