Display the real title screen behind the prelaunch menu (#638)

* Start game execution as soon as a disk image is available

* Do not update dDemo_c if prelaunch document is visible

* Prevent intro music until prelaunch has popped

* Replace "Start Game" references with "Play"

* Make prelaunch layout respect mirror mode

* Add drop shadow to prelaunch disk-status and version-info

* Remove ImGui prelaunch

* Add "Change Disk Image" button to prelaunch options

* Actually validate discs and make prelaunch very betterer :)

* Check your build before pushing dumbass, and go to sleep

* "Disc" consistency, adjust restart notice logic

* Better LanguageSelect logic

* Add restart notice to SaveTypeSelect

* Added wind sounds to the pre-launch menu

* Add Modal document, use it for disc verification

* Consolidate Modal and PresetWindow

* Squash various bugs, rearrange document flow

* Allow Window inheritors to opt-out of being toggleable

* Tweak focus behavior/syntax

* Implement "Restart Now" option

* Tweaks

* Remove a bunch of dynamic_cast

* Update README.md

---------

Co-authored-by: Luke Street <luke@street.dev>
This commit is contained in:
Irastris
2026-05-05 14:18:25 -04:00
committed by GitHub
parent 7300c0e0f5
commit 08321699cd
27 changed files with 911 additions and 485 deletions
+75
View File
@@ -0,0 +1,75 @@
#include "modal.hpp"
namespace dusk::ui {
Modal::Modal(Props props)
: WindowSmall("modal", "modal-dialog"), mProps(std::move(props)) {
auto* title = append(mDialog, "div");
title->SetClass("preset-title", true);
title->SetInnerRML(mProps.title);
auto* body = append(mDialog, "div");
body->SetClass("preset-intro", true);
body->SetInnerRML(mProps.bodyRml);
auto* actions = append(mDialog, "div");
actions->SetClass("modal-actions", true);
for (auto& action : mProps.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));
}
}
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(Z2SE_SY_CURSOR_CANCEL);
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(Z2SE_SY_NAME_CURSOR);
return true;
}
return false;
}
}
return false;
}
} // namespace dusk::ui