Files
dusklight/src/dusk/ui/component.hpp
T
Irastris 08321699cd 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>
2026-05-05 12:18:25 -06:00

88 lines
2.5 KiB
C++

#pragma once
#include "event.hpp"
#include "ui.hpp"
#include <RmlUi/Core.h>
#include <memory>
#include <utility>
#include <vector>
namespace Rml {
class Element;
}
namespace dusk::ui {
class Component {
public:
Component() = default;
explicit Component(Rml::Element* root);
virtual ~Component();
Component(const Component&) = delete;
Component& operator=(const Component&) = delete;
virtual void update();
virtual bool focus();
virtual bool selected() const { return mRoot->IsPseudoClassSet("selected"); }
virtual void set_selected(bool selected);
virtual bool disabled() const { return mRoot->IsPseudoClassSet("disabled"); }
virtual void set_disabled(bool disabled);
void listen(Rml::Element* element, Rml::EventId event, ScopedEventListener::Callback callback,
bool capture = false);
bool contains(Rml::Element* element) const;
template <typename T, typename... Args>
requires std::is_base_of_v<Component, T> T& add_child(Args&&... args) {
auto child = std::make_unique<T>(mRoot, std::forward<Args>(args)...);
T& ref = *child;
mChildren.emplace_back(std::move(child));
return ref;
}
Rml::Element* root() const { return mRoot; }
protected:
void clear_children();
Rml::Element* mRoot = nullptr;
std::vector<std::unique_ptr<Component> > mChildren;
std::vector<std::unique_ptr<ScopedEventListener> > mListeners;
};
template <class Derived>
class FluentComponent : public Component {
public:
using Component::Component;
Derived& listen(
Rml::EventId event, ScopedEventListener::Callback callback, bool capture = false) {
Component::listen(mRoot, event, std::move(callback), capture);
return static_cast<Derived&>(*this);
}
Derived& on_nav_command(std::function<bool(Rml::Event&, NavCommand)> callback) {
listen(Rml::EventId::Click, [this, callback](Rml::Event& event) {
if (!disabled() && callback(event, NavCommand::Confirm)) {
event.StopPropagation();
}
});
listen(Rml::EventId::Keydown, [this, callback = std::move(callback)](Rml::Event& event) {
if (disabled()) {
return;
}
const auto cmd = map_nav_event(event);
if (cmd != NavCommand::None && callback(event, cmd)) {
event.StopPropagation();
}
});
return static_cast<Derived&>(*this);
}
};
} // namespace dusk::ui