UI: Rework Document close handling again

This commit is contained in:
Luke Street
2026-05-02 12:10:14 -06:00
parent 6f20f4d629
commit f148e0ebc1
12 changed files with 76 additions and 104 deletions
+5 -10
View File
@@ -35,7 +35,6 @@ Document::Document(const Rml::String& source) : mDocument(load_document(source))
listen(Rml::EventId::Mouseover, blockUnlessVisible, true);
listen(Rml::EventId::Click, blockUnlessVisible, true);
listen(Rml::EventId::Scroll, blockUnlessVisible, true);
listen(Rml::EventId::Focus, blockUnlessVisible, true);
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
const auto cmd = map_nav_event(event);
@@ -65,10 +64,13 @@ void Document::show() {
}
}
void Document::hide() {
void Document::hide(bool close) {
if (mDocument != nullptr) {
mDocument->Hide();
}
if (close) {
mClosed = true;
}
}
void Document::update() {}
@@ -89,13 +91,6 @@ void Document::listen(Rml::Element* element, Rml::EventId event,
std::make_unique<ScopedEventListener>(element, event, std::move(callback), capture));
}
bool Document::can_destroy() const {
if (mDocument == nullptr) {
return true;
}
return *mDocument->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Hidden;
}
bool Document::visible() const {
if (mDocument == nullptr) {
return false;
@@ -105,7 +100,7 @@ bool Document::visible() const {
bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) {
if (cmd == NavCommand::Menu) {
toggle_top_document();
toggle();
return true;
}
return false;
+16 -2
View File
@@ -14,7 +14,7 @@ public:
Document& operator=(const Document&) = delete;
virtual void show();
virtual void hide();
virtual void hide(bool close);
virtual void update();
virtual bool focus();
virtual bool visible() const;
@@ -24,14 +24,28 @@ public:
void listen(Rml::EventId event, ScopedEventListener::Callback callback, bool capture = false) {
listen(mDocument, event, std::move(callback), capture);
}
void toggle() {
if (visible()) {
hide(false);
} else {
show();
}
}
void pop() {
hide(true);
show_top_document();
}
bool can_destroy() const;
bool pending_close() const { return mPendingClose; }
bool closed() const { return mClosed; }
protected:
virtual bool handle_nav_command(Rml::Event& event, NavCommand cmd);
Rml::ElementDocument* mDocument;
std::vector<std::unique_ptr<ScopedEventListener> > mListeners;
bool mPendingClose = false;
bool mClosed = false;
};
} // namespace dusk::ui
+9 -7
View File
@@ -208,7 +208,7 @@ Overlay::Overlay(OverlayProps props)
if (auto* footer = mDocument->GetElementById("footer")) {
auto& returnButton = add_component<Button>(footer, "\xE2\x86\x90 Return", "footer-button")
.on_pressed(pop_document);
.on_pressed([this] { pop(); });
returnButton.root()->SetClass("return", true);
auto& resetButton =
add_component<Button>(footer, "Reset to default", "footer-button").on_pressed([this] {
@@ -220,11 +220,10 @@ Overlay::Overlay(OverlayProps props)
// Hide document after transition completion
mRoot = mDocument->GetElementById("root");
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
if (event.GetTargetElement() == mRoot &&
*mRoot->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible &&
!mRoot->HasAttribute("open"))
if (event.GetTargetElement() == mRoot && !mRoot->HasAttribute("open") &&
Document::visible())
{
Document::hide();
Document::hide(mPendingClose);
}
});
}
@@ -234,8 +233,11 @@ void Overlay::show() {
mRoot->SetAttribute("open", "");
}
void Overlay::hide() {
void Overlay::hide(bool close) {
mRoot->RemoveAttribute("open");
if (close) {
mPendingClose = true;
}
}
void Overlay::update() {
@@ -260,7 +262,7 @@ bool Overlay::visible() const {
bool Overlay::handle_nav_command(Rml::Event& event, NavCommand cmd) {
if (cmd == NavCommand::Cancel) {
pop_document();
pop();
return true;
}
return Document::handle_nav_command(event, cmd);
+1 -2
View File
@@ -60,7 +60,7 @@ public:
explicit Overlay(OverlayProps props);
void show() override;
void hide() override;
void hide(bool close) override;
void update() override;
bool focus() override;
bool visible() const override;
@@ -85,7 +85,6 @@ private:
int mDefaultValue = 0;
std::vector<std::unique_ptr<Component> > mComponents;
Rml::Element* mRoot;
bool mDismissed = false;
};
} // namespace dusk::ui
+8 -16
View File
@@ -41,17 +41,14 @@ Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("pop
mTabBar->add_tab("Reset", [this] {
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
mTabBar->set_active_tab(-1);
hide();
hide(false);
});
mTabBar->add_tab("Exit", [] { IsRunning = false; });
// Hide document after transition completion
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
if (event.GetTargetElement() == mRoot &&
*mRoot->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible &&
!mRoot->HasAttribute("open"))
{
Document::hide();
if (event.GetTargetElement() == mRoot && !mRoot->HasAttribute("open") && Document::visible()) {
Document::hide(mPendingClose);
}
});
@@ -65,8 +62,11 @@ void Popup::show() {
mTabBar->set_active_tab(-1);
}
void Popup::hide() {
void Popup::hide(bool close) {
mRoot->RemoveAttribute("open");
if (close) {
mPendingClose = true;
}
}
void Popup::update() {
@@ -99,21 +99,13 @@ void Popup::update_safe_area() noexcept {
Rml::PropertyId::PaddingLeft, Rml::Property(safeInsets.left, Rml::Unit::PX));
}
void Popup::toggle() {
if (visible()) {
hide();
} else {
show();
}
}
bool Popup::visible() const {
return mRoot->HasAttribute("open");
}
bool Popup::handle_nav_command(Rml::Event& event, NavCommand cmd) {
if (cmd == NavCommand::Cancel) {
hide();
hide(false);
return true;
}
return Document::handle_nav_command(event, cmd);
+1 -4
View File
@@ -16,13 +16,11 @@ public:
Popup& operator=(const Popup&) = delete;
void show() override;
void hide() override;
void hide(bool close) override;
void update() override;
bool focus() override;
bool visible() const override;
void toggle();
protected:
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
@@ -33,7 +31,6 @@ private:
std::unique_ptr<TabBar> mTabBar;
std::unique_ptr<Button> mCloseButton;
Insets mTabBarPadding;
bool mVisible = false;
};
} // namespace dusk::ui
+15 -11
View File
@@ -114,13 +114,13 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
const bool hasValidPath = is_selected_path_valid();
mMenuButtons.push_back(
std::make_unique<Button>(menuList, hasValidPath ? "Start Game" : "Select Disk Image"));
mMenuButtons.back()->on_pressed([] {
mMenuButtons.back()->on_pressed([this] {
if (!is_selected_path_valid()) {
open_iso_picker();
return;
}
IsGameLaunched = true;
pop_document();
hide(true);
});
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
@@ -144,7 +144,7 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
return;
}
if (target == mDocument && !mDocument->HasAttribute("open")) {
Document::hide();
Document::hide(true);
} else if (target->GetTagName() == "button" && !target->IsClassSet("anim-done")) {
target->SetClass("anim-done", true);
}
@@ -157,8 +157,12 @@ void Prelaunch::show() {
mRoot->SetAttribute("open", "");
}
void Prelaunch::hide() {
if (IsGameLaunched) {
void Prelaunch::hide(bool close) {
if (close) {
if (!mEntranceAnimationStarted) {
// Close document immediately
Document::hide(true);
}
mDocument->RemoveAttribute("open");
} else {
mRoot->RemoveAttribute("open");
@@ -169,18 +173,18 @@ void Prelaunch::update() {
ensure_initialized();
refresh_path_state();
if (!mEntranceAnimationStarted && mDocument != nullptr) {
mDocument->SetClass("animate-in", true);
mEntranceAnimationStarted = true;
}
auto& state = prelaunch_state();
const bool hasValidPath = is_selected_path_valid();
if (hasValidPath && getSettings().backend.skipPreLaunchUI) {
pop_document();
hide(true);
IsGameLaunched = true;
}
if (!mEntranceAnimationStarted && mDocument != nullptr) {
mDocument->SetClass("animate-in", true);
mEntranceAnimationStarted = true;
}
if (!mMenuButtons.empty()) {
mMenuButtons[0]->set_text(hasValidPath ? "Start Game" : "Select Disk Image");
}
+1 -1
View File
@@ -14,7 +14,7 @@ public:
Prelaunch();
void show() override;
void hide() override;
void hide(bool close) override;
void update() override;
bool focus() override;
bool visible() const override;
+13 -39
View File
@@ -6,6 +6,7 @@
#include <algorithm>
#include <filesystem>
#include <ranges>
#include "aurora/lib/window.hpp"
#include "input.hpp"
@@ -19,12 +20,7 @@ void load_font(const char* filename, bool fallback = false) {
}
bool sInitialized = false;
struct OpenDocument {
std::unique_ptr<Document> doc;
bool pendingDestroy = false;
};
std::vector<OpenDocument> sDocuments;
std::vector<std::unique_ptr<Document> > sDocuments;
} // namespace
@@ -54,8 +50,8 @@ void shutdown() noexcept {
}
Document& push_document(std::unique_ptr<Document> doc, bool show) noexcept {
if (auto* doc = top_document()) {
doc->hide();
if (auto* top = top_document()) {
top->hide(false);
}
Document& ret = *doc;
sDocuments.push_back({std::move(doc)});
@@ -66,43 +62,22 @@ Document& push_document(std::unique_ptr<Document> doc, bool show) noexcept {
return ret;
}
void pop_document() noexcept {
for (auto it = sDocuments.rbegin(); it != sDocuments.rend(); ++it) {
if (!it->pendingDestroy) {
it->doc->hide();
it->pendingDestroy = true;
break;
}
}
void show_top_document() noexcept {
if (auto* doc = top_document()) {
doc->show();
}
sync_input_block();
}
void toggle_top_document() noexcept {
auto* doc = top_document();
if (doc == nullptr) {
return;
}
if (doc->visible()) {
doc->hide();
} else {
doc->show();
}
sync_input_block();
}
bool any_document_visible() noexcept {
return std::any_of(sDocuments.begin(), sDocuments.end(),
[](const OpenDocument& doc) { return doc.doc != nullptr && doc.doc->visible(); });
[](const auto& doc) { return doc && doc->visible(); });
}
Document* top_document() noexcept {
for (auto it = sDocuments.rbegin(); it != sDocuments.rend(); ++it) {
if (!it->pendingDestroy) {
return it->doc.get();
for (auto& doc : std::views::reverse(sDocuments)) {
if (!doc->closed() && !doc->pending_close()) {
return doc.get();
}
}
return nullptr;
@@ -111,12 +86,11 @@ Document* top_document() noexcept {
void update() noexcept {
update_input();
for (const auto& doc : sDocuments) {
doc.doc->update();
doc->update();
}
sDocuments.erase(
std::remove_if(sDocuments.begin(), sDocuments.end(),
[](const OpenDocument& doc) { return doc.pendingDestroy && doc.doc->can_destroy(); }),
sDocuments.end());
const auto [first, last] =
std::ranges::remove_if(sDocuments, [](const auto& doc) { return doc->closed(); });
sDocuments.erase(first, last);
sync_input_block();
}
+1 -2
View File
@@ -33,8 +33,7 @@ void handle_event(const SDL_Event& event) noexcept;
void update() noexcept;
Document& push_document(std::unique_ptr<Document> doc, bool show = true) noexcept;
void pop_document() noexcept;
void toggle_top_document() noexcept;
void show_top_document() noexcept;
bool any_document_visible() noexcept;
Document* top_document() noexcept;
+5 -8
View File
@@ -64,11 +64,8 @@ Window::Window() : Document(kDocumentSource), mRoot(mDocument->GetElementById("w
// Hide document after transition completion
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
if (event.GetTargetElement() == mRoot &&
*mRoot->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible &&
!mRoot->HasAttribute("open"))
{
Document::hide();
if (event.GetTargetElement() == mRoot && !mRoot->HasAttribute("open") && Document::visible()) {
Document::hide(mPendingClose);
}
});
@@ -92,9 +89,9 @@ void Window::show() {
mRoot->SetAttribute("open", "");
}
void Window::hide() {
void Window::hide(bool close) {
mRoot->RemoveAttribute("open");
// Document will be hidden after transition
mPendingClose = close;
}
void Window::update() {
@@ -175,7 +172,7 @@ bool Window::handle_nav_command(Rml::Event& event, NavCommand cmd) {
}
}
if (cmd == NavCommand::Cancel) {
pop_document();
pop();
return true;
}
if (mTabBar->handle_nav_command(event, cmd)) {
+1 -2
View File
@@ -24,7 +24,7 @@ public:
Window& operator=(const Window&) = delete;
void show() override;
void hide() override;
void hide(bool close) override;
void update() override;
bool focus() override;
bool visible() const override;
@@ -50,7 +50,6 @@ protected:
std::unique_ptr<TabBar> mTabBar;
std::vector<std::unique_ptr<Component> > mContentComponents;
Insets mBodyPadding;
bool mVisible = false;
};
} // namespace dusk::ui