Merge branch 'main' of ssh://github.com/TwilitRealm/dusklight into rando-mod

This commit is contained in:
TakaRikka
2026-08-22 00:21:56 -07:00
16 changed files with 234 additions and 25 deletions
+16 -3
View File
@@ -808,7 +808,8 @@ ModResult ui_window_close(LoadedMod& mod, uint64_t handle) {
return MOD_OK;
}
ModResult ui_dialog_push(LoadedMod& mod, const UiDialogDesc& desc, uint64_t& outHandle) {
ModResult ui_dialog_push(
LoadedMod& mod, const UiDialogDesc& desc, UiPaneBuildFn build, uint64_t& outHandle) {
outHandle = 0;
if (!aurora::rmlui::is_initialized()) {
return MOD_UNAVAILABLE;
@@ -851,6 +852,16 @@ ModResult ui_dialog_push(LoadedMod& mod, const UiDialogDesc& desc, uint64_t& out
auto dialog = std::make_unique<ModDialog>(
std::move(props), [handle] { on_mod_dialog_destroyed(handle); });
if (build != nullptr) {
auto& pane = dialog->content_pane();
const uint64_t paneHandle = wrap_pane(mod, pane, nullptr);
invoke_mod_ui_callback(mod, "mod UI dialog build", [&](ModError* error) {
return build(mod.context.get(), paneHandle, desc.user_data, error);
});
if (!mod.active) {
return MOD_ERROR;
}
}
if (auto* slot = slot_from_handle(handle)) {
slot->document = dialog.get();
}
@@ -1338,7 +1349,8 @@ ModResult ui_dialog_push(ModContext* context, const UiDialogDesc* desc, UiDialog
*outDialog = 0;
}
auto* mod = mod_from_context(context);
if (mod == nullptr || desc == nullptr || desc->struct_size < sizeof(UiDialogDesc) ||
constexpr size_t kLegacyDescSize = offsetof(UiDialogDesc, build);
if (mod == nullptr || desc == nullptr || desc->struct_size < kLegacyDescSize ||
desc->title == nullptr || desc->body_rml == nullptr || desc->actions == nullptr ||
desc->action_count == 0 || desc->variant > UI_DIALOG_DANGER)
{
@@ -1349,8 +1361,9 @@ ModResult ui_dialog_push(ModContext* context, const UiDialogDesc* desc, UiDialog
return MOD_INVALID_ARGUMENT;
}
}
const UiPaneBuildFn build = desc->struct_size >= sizeof(UiDialogDesc) ? desc->build : nullptr;
uint64_t handle = 0;
const auto result = ui_impl::ui_dialog_push(*mod, *desc, handle);
const auto result = ui_impl::ui_dialog_push(*mod, *desc, build, handle);
if (result == MOD_OK && outDialog != nullptr) {
*outDialog = handle;
}
+4
View File
@@ -1,6 +1,7 @@
#include "dusk/settings.h"
#include <aurora/aurora.h>
#include "dusk/config.hpp"
#include "dusk/ui/ui.hpp"
#include "dusk/game_mode.hpp"
namespace dusk {
@@ -16,6 +17,7 @@ UserSettings g_userSettings = {
.rememberWindowSize {"video.rememberWindowSize", false},
.lastWindowWidth {"video.lastWindowWidth", 0},
.lastWindowHeight {"video.lastWindowHeight", 0},
.uiScale {"video.uiScale", 100},
},
.audio = {
@@ -228,6 +230,8 @@ void registerSettings() {
Register(g_userSettings.video.rememberWindowSize);
Register(g_userSettings.video.lastWindowWidth);
Register(g_userSettings.video.lastWindowHeight);
Register(g_userSettings.video.uiScale,
[](const int&, const int&) { dusk::ui::apply_scale(); });
// Audio
Register(g_userSettings.audio.masterVolume);
+1
View File
@@ -145,6 +145,7 @@ struct UserSettings {
ConfigVar<bool> rememberWindowSize;
ConfigVar<int> lastWindowWidth;
ConfigVar<int> lastWindowHeight;
ConfigVar<int> uiScale;
} video;
struct {
+49 -2
View File
@@ -1,5 +1,7 @@
#include "modal.hpp"
#include <algorithm>
namespace dusk::ui {
Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::move(props)) {
@@ -23,6 +25,9 @@ Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::mo
body->SetClass("modal-body", true);
body->SetInnerRML(mProps.bodyRml);
mContentRoot = append(mDialog, "div");
mContentRoot->SetClass("modal-content", true);
auto* actions = append(mDialog, "div");
actions->SetClass("modal-actions", true);
if (props.isVertical) {
@@ -36,12 +41,36 @@ Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::mo
mDoAud_seStartMenu(kSoundWindowOpen);
}
void Modal::update() {
if (mContentPane != nullptr) {
mContentPane->update();
}
if (mPendingAction) {
auto action = std::move(mPendingAction);
action(*this);
}
WindowSmall::update();
}
Pane& Modal::content_pane() {
if (mContentPane == nullptr) {
mContentRoot->SetClass("active", true);
mContentPane = std::make_unique<Pane>(mContentRoot, Pane::Type::Uncontrolled);
}
return *mContentPane;
}
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) {
if (!callback) {
return;
}
if (mContentPane != nullptr) {
mPendingAction = callback;
} else {
callback(*this);
}
});
@@ -68,6 +97,9 @@ void Modal::set_icon(const Rml::String& icon) {
}
bool Modal::focus() {
if (mContentPane != nullptr && mContentPane->focus()) {
return true;
}
if (!mButtons.empty()) {
return mButtons.front()->focus();
}
@@ -89,6 +121,22 @@ bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
return true;
}
auto* target = event.GetTargetElement();
if (mContentPane != nullptr && mContentPane->contains(target) && cmd == NavCommand::Down &&
!mButtons.empty() && mButtons.front()->focus())
{
mDoAud_seStartMenu(kSoundItemFocus);
return true;
}
if (mContentPane != nullptr && cmd == NavCommand::Up &&
std::ranges::any_of(
mButtons, [target](const auto& button) { return button->contains(target); }) &&
mContentPane->focus_last())
{
mDoAud_seStartMenu(kSoundItemFocus);
return true;
}
int direction = 0;
NavCommand prevCommand = mProps.isVertical ? NavCommand::Up : NavCommand::Left;
NavCommand nextCommand = mProps.isVertical ? NavCommand::Down : NavCommand::Right;
@@ -100,7 +148,6 @@ bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
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;
+8 -2
View File
@@ -1,6 +1,7 @@
#pragma once
#include "button.hpp"
#include "pane.hpp"
#include "window.hpp"
namespace dusk::ui {
@@ -20,13 +21,15 @@ public:
std::function<void(Modal&)> onDismiss;
Rml::String variant;
Rml::String icon = "";
bool isVertical;
bool isVertical = false;
};
explicit Modal(Props props);
void update() override;
bool focus() override;
Pane& content_pane();
void add_action(ModalAction action);
void set_body(const Rml::String& bodyRml);
void set_icon(const Rml::String& icon);
@@ -38,7 +41,10 @@ private:
void dismiss();
Props mProps;
std::vector<std::unique_ptr<Button> > mButtons;
Rml::Element* mContentRoot = nullptr;
std::unique_ptr<Pane> mContentPane;
std::function<void(Modal&)> mPendingAction;
std::vector<std::unique_ptr<Button>> mButtons;
};
} // namespace dusk::ui
+9
View File
@@ -163,6 +163,15 @@ bool Pane::focus() {
return false;
}
bool Pane::focus_last() {
for (auto child = mChildren.rbegin(); child != mChildren.rend(); ++child) {
if ((*child)->focus()) {
return true;
}
}
return false;
}
Rml::Element* Pane::add_section(const Rml::String& text) {
auto* elem = append(mRoot, "div");
elem->SetClass("section-heading", true);
+1
View File
@@ -17,6 +17,7 @@ public:
explicit Pane(Rml::Element* parent, Type type);
bool focus() override;
bool focus_last();
void update() override;
void set_selected_item(int index);
+7 -3
View File
@@ -52,6 +52,10 @@ Popover::Popover(Rml::Element* anchor, Side side, const Rml::String& windowClass
true);
}
Popover::~Popover() {
notify_close(false);
}
void Popover::show() {
Document::show();
reposition();
@@ -60,7 +64,7 @@ void Popover::show() {
}
void Popover::hide(bool close) {
notify_close();
notify_close(true);
mBody->RemoveAttribute("open");
mPendingClose = close;
}
@@ -136,13 +140,13 @@ void Popover::reposition() {
mBody->SetProperty(Rml::PropertyId::Top, Rml::Property{pos.y, Rml::Unit::PX});
}
void Popover::notify_close() {
void Popover::notify_close(bool restoreFocus) {
if (mOnClose) {
auto callback = std::move(mOnClose);
mOnClose = nullptr;
callback();
}
if (mAnchor != nullptr && mAnchor->IsVisible(true)) {
if (restoreFocus && mAnchor != nullptr && mAnchor->IsVisible(true)) {
mAnchor->Focus(true);
}
}
+2 -1
View File
@@ -14,6 +14,7 @@ public:
};
Popover(Rml::Element* anchor, Side side, const Rml::String& windowClass = "");
~Popover() override;
void show() override;
void hide(bool close) override;
@@ -32,7 +33,7 @@ protected:
private:
void reposition();
void notify_close();
void notify_close(bool restoreFocus);
Rml::Element* mAnchor = nullptr;
Side mSide;
+6
View File
@@ -770,6 +770,12 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
},
.isDisabled = [] { return IsMobile; },
});
config_int_select(leftPane, rightPane, getSettings().video.uiScale,
"UI Scale",
"Scales the Dusklight interface relative to the display's DPI scale. Has no effect on the game's UI and HUD.",
50, 200, 25, {}, {}, "%");
leftPane.add_section("Resolution");
graphics_tuner_control(*this, leftPane, rightPane,
getSettings().game.internalResolutionScale,
+12
View File
@@ -214,6 +214,8 @@ void handle_event(const SDL_Event& event) noexcept {
});
}
sConnectedGamepads.erase(event.gdevice.which);
} else if (event.type == SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED) {
apply_scale();
}
input::handle_event(event);
}
@@ -491,4 +493,14 @@ bool consume_menu_notification_request() noexcept {
return requested;
}
void apply_scale() noexcept {
const auto userScale = getSettings().video.uiScale.getValue();
auto scale = 0.0f;
if (userScale != 0) {
const auto displayScale = aurora::window::get_window_size().scale;
scale = static_cast<float>(userScale) / 100.0f * (displayScale > 0.0f ? displayScale : 1.0f);
}
aurora::rmlui::set_ui_scale(scale);
}
} // namespace dusk::ui
+2
View File
@@ -114,4 +114,6 @@ bool consume_menu_notification_request() noexcept;
const char* battery_icon(SDL_PowerState state, int level) noexcept;
const char* connection_state_icon(SDL_JoystickConnectionState state) noexcept;
void apply_scale() noexcept;
} // namespace dusk::ui
+1
View File
@@ -776,6 +776,7 @@ int game_main(int argc, char* argv[]) {
dusk::texture_replacements::reload();
dusk::ui::initialize();
dusk::ui::apply_scale();
dusk::ui::push_document(std::make_unique<dusk::ui::Overlay>(), true, true);
dusk::ui::push_document(std::make_unique<dusk::ui::TouchControls>(), false, true);
dusk::ui::push_document(std::make_unique<dusk::ui::MenuBar>(), false);