diff --git a/src/dusk/ui/component.hpp b/src/dusk/ui/component.hpp index d955b58c0a..0c49ce3254 100644 --- a/src/dusk/ui/component.hpp +++ b/src/dusk/ui/component.hpp @@ -66,15 +66,6 @@ public: return static_cast(*this); } - Derived& on_focus(ScopedEventListener::Callback callback) { - return listen( - Rml::EventId::Focus, [this, callback = std::move(callback)](Rml::Event& event) { - if (!disabled()) { - callback(event); - } - }); - } - Derived& on_nav_command(std::function callback) { listen(Rml::EventId::Click, [this, callback](Rml::Event& event) { if (!disabled() && callback(event, NavCommand::Confirm)) { diff --git a/src/dusk/ui/controller_config.cpp b/src/dusk/ui/controller_config.cpp index 393f2e2e4f..9a3238725e 100644 --- a/src/dusk/ui/controller_config.cpp +++ b/src/dusk/ui/controller_config.cpp @@ -246,18 +246,16 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) { mRightPane = &rightPane; mActivePort = port; - auto showPage = [this, &rightPane, port](Page page) { - mPage = page; - render_page(rightPane, port, page); - }; - auto addPageButton = [&leftPane, showPage](Page page, Rml::String key, auto getValue) { - leftPane - .add_select_button({ - .key = std::move(key), - .getValue = std::move(getValue), - }) - .on_focus([showPage, page](Rml::Event&) { showPage(page); }) - .on_pressed([showPage, page] { showPage(page); }); + auto addPageButton = [this, &leftPane, &rightPane, port]( + Page page, Rml::String key, auto getValue) { + leftPane.register_control(leftPane.add_select_button({ + .key = std::move(key), + .getValue = std::move(getValue), + }), + rightPane, [this, port, page](Pane& pane) { + mPage = page; + render_page(pane, port, page); + }); }; addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }); @@ -266,47 +264,43 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) { addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }); leftPane.add_section("Options"); - leftPane - .add_child(BoolButton::Props{ - .key = "Enable Dead Zones", - .getValue = - [port] { - PADDeadZones* deadZones = PADGetDeadZones(port); - return deadZones != nullptr && deadZones->useDeadzones; - }, - .setValue = - [port](bool value) { - if (PADDeadZones* deadZones = PADGetDeadZones(port)) { - deadZones->useDeadzones = value; - PADSerializeMappings(); - } - }, - .isDisabled = [port] { return PADGetDeadZones(port) == nullptr; }, - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text("Apply configured dead zones to the sticks and analog triggers."); + leftPane.register_control(leftPane.add_child(BoolButton::Props{ + .key = "Enable Dead Zones", + .getValue = + [port] { + PADDeadZones* deadZones = PADGetDeadZones(port); + return deadZones != nullptr && deadZones->useDeadzones; + }, + .setValue = + [port](bool value) { + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + deadZones->useDeadzones = value; + PADSerializeMappings(); + } + }, + .isDisabled = [port] { return PADGetDeadZones(port) == nullptr; }, + }), + rightPane, [](Pane& pane) { + pane.add_text("Apply configured dead zones to the sticks and analog triggers."); }); - leftPane - .add_child(BoolButton::Props{ - .key = "Emulate Triggers", - .getValue = - [port] { - PADDeadZones* deadZones = PADGetDeadZones(port); - return deadZones != nullptr && deadZones->emulateTriggers; - }, - .setValue = - [port](bool value) { - if (PADDeadZones* deadZones = PADGetDeadZones(port)) { - deadZones->emulateTriggers = value; - PADSerializeMappings(); - } - }, - .isDisabled = [port] { return PADGetDeadZones(port) == nullptr; }, - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text("Treat analog trigger movement as digital L and R button input."); + leftPane.register_control(leftPane.add_child(BoolButton::Props{ + .key = "Emulate Triggers", + .getValue = + [port] { + PADDeadZones* deadZones = PADGetDeadZones(port); + return deadZones != nullptr && deadZones->emulateTriggers; + }, + .setValue = + [port](bool value) { + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + deadZones->emulateTriggers = value; + PADSerializeMappings(); + } + }, + .isDisabled = [port] { return PADGetDeadZones(port) == nullptr; }, + }), + rightPane, [](Pane& pane) { + pane.add_text("Treat analog trigger movement as digital L and R button input."); }); render_page(rightPane, port, mPage); diff --git a/src/dusk/ui/editor.cpp b/src/dusk/ui/editor.cpp index 49135099db..1ba44f0a27 100644 --- a/src/dusk/ui/editor.cpp +++ b/src/dusk/ui/editor.cpp @@ -1295,73 +1295,71 @@ EditorWindow::EditorWindow() { auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Player"); - leftPane - .add_child(StringButton::Props{ - .key = "Player Name", - .getValue = get_player_name, - .setValue = set_player_name, - .maxLength = 16, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(StringButton::Props{ - .key = "Horse Name", - .getValue = get_horse_name, - .setValue = set_horse_name, - .maxLength = 16, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control(leftPane.add_child(StringButton::Props{ + .key = "Player Name", + .getValue = get_player_name, + .setValue = set_player_name, + .maxLength = 16, + }), + rightPane, {}); + leftPane.register_control(leftPane.add_child(StringButton::Props{ + .key = "Horse Name", + .getValue = get_horse_name, + .setValue = set_horse_name, + .maxLength = 16, + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Max Health", .getValue = [] { return get_player_status()->getMaxLife(); }, .setValue = [](int value) { return get_player_status()->setMaxLife(value); }, .max = UINT16_MAX, // TODO: actual max - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Health", .getValue = [] { return get_player_status()->getLife(); }, .setValue = [](int value) { return get_player_status()->setLife(value); }, .max = UINT16_MAX, // TODO: actual max - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Rupees", .getValue = [] { return get_player_status()->getRupee(); }, .setValue = [](int value) { return get_player_status()->setRupee(value); }, .max = get_player_status()->getRupeeMax(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Max Oil", .getValue = [] { return get_player_status()->getMaxOil(); }, .setValue = [](int value) { return get_player_status()->setMaxOil(value); }, .max = UINT16_MAX, // TODO: actual max - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Oil", .getValue = [] { return get_player_status()->getOil(); }, .setValue = [](int value) { return get_player_status()->setOil(value); }, .max = UINT16_MAX, // TODO: actual max - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); leftPane.add_section("Equipment"); const auto genSelectItemComboBox = [&leftPane, &rightPane]( const Rml::String& label, u8& selectItemData) { - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = label, .getValue = [&selectItemData] { return item_label_for_slot(selectItemData); }, - }) - .on_focus([&rightPane, &selectItemData](Rml::Event&) { - populate_select_item_picker(rightPane, selectItemData); + }), + rightPane, [&selectItemData](Pane& pane) { + populate_select_item_picker(pane, selectItemData); }); }; genSelectItemComboBox("Equip X", get_player_status()->mSelectItem[0]); @@ -1369,80 +1367,80 @@ EditorWindow::EditorWindow() { genSelectItemComboBox("Combo Equip X", get_player_status()->mMixItem[0]); genSelectItemComboBox("Combo Equip Y", get_player_status()->mMixItem[1]); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Clothes", .getValue = [] { return get_item_name(get_player_status()->mSelectEquip[0]); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_select_clothes_picker(rightPane); }); - leftPane - .add_select_button({ + }), + rightPane, [](Pane& pane) { populate_select_clothes_picker(pane); }); + leftPane.register_control( + leftPane.add_select_button({ .key = "Sword", .getValue = [] { return get_item_name(get_player_status()->mSelectEquip[1]); }, - }) - .on_focus([&rightPane](Rml::Event&) { + }), + rightPane, [](Pane& pane) { populate_select_equip_picker( - rightPane, get_player_status()->mSelectEquip[1], swordEntries); + pane, get_player_status()->mSelectEquip[1], swordEntries); }); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Shield", .getValue = [] { return get_item_name(get_player_status()->mSelectEquip[2]); }, - }) - .on_focus([&rightPane](Rml::Event&) { + }), + rightPane, [](Pane& pane) { populate_select_equip_picker( - rightPane, get_player_status()->mSelectEquip[2], shieldEntries); + pane, get_player_status()->mSelectEquip[2], shieldEntries); }); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Scent", .getValue = [] { return get_item_name(get_player_status()->mSelectEquip[3]); }, - }) - .on_focus([&rightPane](Rml::Event&) { + }), + rightPane, [](Pane& pane) { populate_select_equip_picker( - rightPane, get_player_status()->mSelectEquip[3], smellEntries); + pane, get_player_status()->mSelectEquip[3], smellEntries); }); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Wallet Size", .getValue = [] { return walletSizeNames[get_player_status()->getWalletSize()]; }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_wallet_picker(rightPane); }); - leftPane - .add_select_button({ + }), + rightPane, [](Pane& pane) { populate_wallet_picker(pane); }); + leftPane.register_control( + leftPane.add_select_button({ .key = "Form", .getValue = [] { return formNames[get_player_status()->getTransformStatus()]; }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_form_picker(rightPane); }); + }), + rightPane, [](Pane& pane) { populate_form_picker(pane); }); leftPane.add_section("World"); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Day", .getValue = [] { return get_player_status_b()->getDate(); }, .setValue = [](int value) { get_player_status_b()->setDate(static_cast(value)); }, .max = UINT16_MAX, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Hour", .getValue = [] { return dKy_getdaytime_hour(); }, .setValue = [](int value) { set_clock_time(value, dKy_getdaytime_minute()); }, .max = 23, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Minute", .getValue = [] { return dKy_getdaytime_minute(); }, .setValue = [](int value) { set_clock_time(dKy_getdaytime_hour(), value); }, .max = 59, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Transform Level", .getValue = [] { @@ -1455,10 +1453,10 @@ EditorWindow::EditorWindow() { static_cast((1u << value) - 1u); }, .max = 3, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Twilight Clear Level", .getValue = [] { @@ -1471,8 +1469,8 @@ EditorWindow::EditorWindow() { static_cast((1u << value) - 1u); }, .max = 3, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); }); add_tab("Location", [this](Rml::Element* content) { @@ -1481,33 +1479,36 @@ EditorWindow::EditorWindow() { leftPane.add_section("Save Location"); leftPane - .add_select_button({ - .key = "Stage", - .getValue = - [] { - return stage_label_for_file(fixed_string(get_player_return_place()->mName)); - }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_stage_picker( - rightPane, [] { return fixed_string(get_player_return_place()->mName); }, - [](const char* stageFile) { - set_fixed_string(get_player_return_place()->mName, Rml::String(stageFile)); - }); - }) + .register_control(leftPane.add_select_button({ + .key = "Stage", + .getValue = + [] { + return stage_label_for_file( + fixed_string(get_player_return_place()->mName)); + }, + }), + rightPane, + [](Pane& pane) { + populate_stage_picker( + pane, [] { return fixed_string(get_player_return_place()->mName); }, + [](const char* stageFile) { + set_fixed_string( + get_player_return_place()->mName, Rml::String(stageFile)); + }); + }) .set_disabled(true); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Room", .getValue = [] { return get_player_return_place()->mRoomNo; }, .setValue = [](int value) { get_player_return_place()->mRoomNo = static_cast(value); }, .min = std::numeric_limits::min(), .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Spawn ID", .getValue = [] { return get_player_return_place()->mPlayerStatus; }, .setValue = @@ -1515,74 +1516,76 @@ EditorWindow::EditorWindow() { get_player_return_place()->mPlayerStatus = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); leftPane.add_section("Horse Location"); - leftPane - .add_child(StringButton::Props{ - .key = "Horse Position", - .getValue = - [] { - const auto* horsePlace = get_horse_place(); - return fmt::format("{}, {}, {}", static_cast(horsePlace->mPos.x), - static_cast(horsePlace->mPos.y), - static_cast(horsePlace->mPos.z)); - }, - .setValue = - [](Rml::String value) { - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - if (parse_vec3(value, x, y, z)) { - auto* horsePlace = get_horse_place(); - horsePlace->mPos.x = x; - horsePlace->mPos.y = y; - horsePlace->mPos.z = z; - } - }, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control(leftPane.add_child(StringButton::Props{ + .key = "Horse Position", + .getValue = + [] { + const auto* horsePlace = get_horse_place(); + return fmt::format("{}, {}, {}", + static_cast(horsePlace->mPos.x), + static_cast(horsePlace->mPos.y), + static_cast(horsePlace->mPos.z)); + }, + .setValue = + [](Rml::String value) { + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + if (parse_vec3(value, x, y, z)) { + auto* horsePlace = get_horse_place(); + horsePlace->mPos.x = x; + horsePlace->mPos.y = y; + horsePlace->mPos.z = z; + } + }, + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Horse Angle", .getValue = [] { return get_horse_place()->mAngleY; }, .setValue = [](int value) { get_horse_place()->mAngleY = static_cast(value); }, .min = std::numeric_limits::min(), .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); leftPane - .add_select_button({ - .key = "Horse Stage", - .getValue = - [] { return stage_label_for_file(fixed_string(get_horse_place()->mName)); }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_stage_picker( - rightPane, [] { return fixed_string(get_horse_place()->mName); }, - [](const char* stageFile) { - set_fixed_string(get_horse_place()->mName, Rml::String(stageFile)); - }); - }) + .register_control( + leftPane.add_select_button({ + .key = "Horse Stage", + .getValue = + [] { return stage_label_for_file(fixed_string(get_horse_place()->mName)); }, + }), + rightPane, + [](Pane& pane) { + populate_stage_picker( + pane, [] { return fixed_string(get_horse_place()->mName); }, + [](const char* stageFile) { + set_fixed_string(get_horse_place()->mName, Rml::String(stageFile)); + }); + }) .set_disabled(true); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Horse Room", .getValue = [] { return get_horse_place()->mRoomNo; }, .setValue = [](int value) { get_horse_place()->mRoomNo = static_cast(value); }, .min = std::numeric_limits::min(), .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Horse Spawn ID", .getValue = [] { return get_horse_place()->mSpawnId; }, .setValue = [](int value) { get_horse_place()->mSpawnId = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); }); add_tab("Inventory", [this](Rml::Element* content) { @@ -1590,44 +1593,41 @@ EditorWindow::EditorWindow() { auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Item Wheel"); - leftPane.add_button("Default All") - .on_pressed([&rightPane] { - for (int slot = 0; slot < 24; ++slot) { - dComIfGs_setItem(slot, get_slot_default(slot)); - } - rightPane.clear(); - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane.add_button("Clear All") - .on_pressed([&rightPane] { - for (int slot = 0; slot < 24; ++slot) { - dComIfGs_setItem(slot, dItemNo_NONE_e); - } - rightPane.clear(); - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + leftPane.register_control(leftPane.add_button("Default All").on_pressed([&rightPane] { + for (int slot = 0; slot < 24; ++slot) { + dComIfGs_setItem(slot, get_slot_default(slot)); + } + rightPane.clear(); + }), + rightPane, {}); + leftPane.register_control(leftPane.add_button("Clear All").on_pressed([&rightPane] { + for (int slot = 0; slot < 24; ++slot) { + dComIfGs_setItem(slot, dItemNo_NONE_e); + } + rightPane.clear(); + }), + rightPane, {}); for (int slot = 0; slot < 24; ++slot) { - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = fmt::format("Slot {0:02d}", slot), .getValue = [slot] { return get_item_name(get_player_item()->mItems[slot]); }, - }) - .on_focus([&rightPane, slot]( - Rml::Event&) { populate_item_slot_picker(rightPane, slot); }); + }), + rightPane, [slot](Pane& pane) { populate_item_slot_picker(pane, slot); }); } leftPane.add_section("Amounts"); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Arrows Amount", .getValue = [] { return get_player_item_record()->mArrowNum; }, .setValue = [](int value) { get_player_item_record()->mArrowNum = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Slingshot Amount", .getValue = [] { return get_player_item_record()->mPachinkoNum; }, .setValue = @@ -1635,11 +1635,11 @@ EditorWindow::EditorWindow() { get_player_item_record()->mPachinkoNum = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); for (int bag = 0; bag < 3; ++bag) { - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = fmt::format("Bomb Bag {} Amount", bag + 1), .getValue = [bag] { return get_player_item_record()->mBombNum[bag]; }, .setValue = @@ -1647,12 +1647,12 @@ EditorWindow::EditorWindow() { get_player_item_record()->mBombNum[bag] = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); } for (int bottle = 0; bottle < 4; ++bottle) { - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = fmt::format("Bottle {} Amount", bottle + 1), .getValue = [bottle] { return get_player_item_record()->mBottleNum[bottle]; }, .setValue = @@ -1660,175 +1660,165 @@ EditorWindow::EditorWindow() { get_player_item_record()->mBottleNum[bottle] = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); } leftPane.add_section("Capacities"); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Arrows Max", .getValue = [] { return get_player_item_max()->mItemMax[0]; }, .setValue = [](int value) { get_player_item_max()->mItemMax[0] = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Normal Bombs Max", .getValue = [] { return get_player_item_max()->mItemMax[1]; }, .setValue = [](int value) { get_player_item_max()->mItemMax[1] = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Water Bombs Max", .getValue = [] { return get_player_item_max()->mItemMax[2]; }, .setValue = [](int value) { get_player_item_max()->mItemMax[2] = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Bomblings Max", .getValue = [] { return get_player_item_max()->mItemMax[3]; }, .setValue = [](int value) { get_player_item_max()->mItemMax[3] = static_cast(value); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); leftPane.add_section("Flags"); - leftPane - .add_select_button({ - .key = "Obtained Items", - .getValue = [] { return "Edit"; }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_item_flag_picker(rightPane); }); + leftPane.register_control(leftPane.add_select_button({ + .key = "Obtained Items", + .getValue = [] { return "Edit"; }, + }), + rightPane, [](Pane& pane) { populate_item_flag_picker(pane); }); }); add_tab("Collection", [this](Rml::Element* content) { auto& leftPane = add_child(content, Pane::Type::Controlled); auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Equipment"); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Swords", .getValue = [] { return count_label( count_item_first_bits(swordEntries), swordEntries.size()); }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_toggle_group(rightPane, item_toggle_entries(swordEntries)); - }); - leftPane - .add_select_button({ + }), + rightPane, + [](Pane& pane) { populate_toggle_group(pane, item_toggle_entries(swordEntries)); }); + leftPane.register_control( + leftPane.add_select_button({ .key = "Shields", .getValue = [] { return count_label( count_item_first_bits(shieldEntries), shieldEntries.size()); }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_toggle_group(rightPane, item_toggle_entries(shieldEntries)); - }); - leftPane - .add_select_button({ - .key = "Clothing", - .getValue = [] { return count_label(count_clothing(), 4); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_collect_clothes_picker(rightPane); }); + }), + rightPane, + [](Pane& pane) { populate_toggle_group(pane, item_toggle_entries(shieldEntries)); }); + leftPane.register_control(leftPane.add_select_button({ + .key = "Clothing", + .getValue = [] { return count_label(count_clothing(), 4); }, + }), + rightPane, [](Pane& pane) { populate_collect_clothes_picker(pane); }); leftPane.add_section("Key Items"); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Fused Shadows", .getValue = [] { return count_label( count_collect_crystals(fusedShadowEntries), fusedShadowEntries.size()); }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_toggle_group( - rightPane, collect_crystal_toggle_entries(fusedShadowEntries)); + }), + rightPane, [](Pane& pane) { + populate_toggle_group(pane, collect_crystal_toggle_entries(fusedShadowEntries)); }); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Mirror Shards", .getValue = [] { return count_label( count_collect_mirrors(mirrorShardEntries), mirrorShardEntries.size()); }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_toggle_group(rightPane, collect_mirror_toggle_entries(mirrorShardEntries)); + }), + rightPane, [](Pane& pane) { + populate_toggle_group(pane, collect_mirror_toggle_entries(mirrorShardEntries)); }); leftPane.add_section("Health & Souls"); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Poe Souls", .getValue = [] { return fmt::format("{} / 60", dComIfGs_getPohSpiritNum()); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_poe_souls_picker(rightPane); }); - leftPane - .add_select_button({ - .key = "Max Life", - .getValue = [] { return max_life_label(); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_max_life_picker(rightPane); }); + }), + rightPane, [](Pane& pane) { populate_poe_souls_picker(pane); }); + leftPane.register_control(leftPane.add_select_button({ + .key = "Max Life", + .getValue = [] { return max_life_label(); }, + }), + rightPane, [](Pane& pane) { populate_max_life_picker(pane); }); leftPane.add_section("Golden Bugs"); for (const auto& bug : bugSpeciesEntries) { - leftPane - .add_select_button({ - .key = bug.name, - .getValue = [bug] { return bug_species_label(bug); }, - }) - .on_focus([&rightPane, bug]( - Rml::Event&) { populate_bug_species_picker(rightPane, bug); }); + leftPane.register_control(leftPane.add_select_button({ + .key = bug.name, + .getValue = [bug] { return bug_species_label(bug); }, + }), + rightPane, [bug](Pane& pane) { populate_bug_species_picker(pane, bug); }); } leftPane.add_section("Skills"); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Hidden Skills", .getValue = [] { return count_label( count_event_bits(hiddenSkillEntries), hiddenSkillEntries.size()); }, - }) - .on_focus([&rightPane](Rml::Event&) { - populate_toggle_group(rightPane, event_toggle_entries(hiddenSkillEntries)); + }), + rightPane, [](Pane& pane) { + populate_toggle_group(pane, event_toggle_entries(hiddenSkillEntries)); }); leftPane.add_section("Logs"); - leftPane - .add_select_button({ + leftPane.register_control( + leftPane.add_select_button({ .key = "Postman Letters", .getValue = [] { return count_label(count_letters(), letterSenders.size()); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_letters_picker(rightPane); }); + }), + rightPane, [](Pane& pane) { populate_letters_picker(pane); }); leftPane.add_section("Fishing Log"); for (const auto& fish : fishSpeciesEntries) { - leftPane - .add_select_button({ - .key = fish.name, - .getValue = [fish] { return fish_species_label(fish); }, - }) - .on_focus([&rightPane, fish]( - Rml::Event&) { populate_fish_species_picker(rightPane, fish); }); + leftPane.register_control(leftPane.add_select_button({ + .key = fish.name, + .getValue = [fish] { return fish_species_label(fish); }, + }), + rightPane, [fish](Pane& pane) { populate_fish_species_picker(pane, fish); }); } }); @@ -1841,8 +1831,8 @@ EditorWindow::EditorWindow() { auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Records"); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "STAR Game Time (ms)", .getValue = [] { @@ -1854,10 +1844,10 @@ EditorWindow::EditorWindow() { get_minigame()->setHookGameTime(static_cast(std::max(0, value))); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Snowboard Race Time (ms)", .getValue = [] { @@ -1869,10 +1859,10 @@ EditorWindow::EditorWindow() { get_minigame()->setRaceGameTime(static_cast(std::max(0, value))); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_child(NumberButton::Props{ + }), + rightPane, {}); + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Fruit-Pop-Flight Score", .getValue = [] { @@ -1884,8 +1874,8 @@ EditorWindow::EditorWindow() { get_minigame()->setBalloonScore(static_cast(std::max(0, value))); }, .max = std::numeric_limits::max(), - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); + }), + rightPane, {}); }); add_tab("Config", [this](Rml::Element* content) { @@ -1893,25 +1883,23 @@ EditorWindow::EditorWindow() { auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Options"); - leftPane - .add_child(BoolButton::Props{ + leftPane.register_control( + leftPane.add_child(BoolButton::Props{ .key = "Enable Vibration", .getValue = [] { return get_player_config()->getVibration() != 0; }, .setValue = [](bool value) { get_player_config()->setVibration(value); }, - }) - .on_focus([&rightPane](Rml::Event&) { rightPane.clear(); }); - leftPane - .add_select_button({ - .key = "Target Type", - .getValue = [] { return target_type_label(); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_target_type_picker(rightPane); }); - leftPane - .add_select_button({ - .key = "Sound", - .getValue = [] { return sound_mode_label(); }, - }) - .on_focus([&rightPane](Rml::Event&) { populate_sound_mode_picker(rightPane); }); + }), + rightPane, {}); + leftPane.register_control(leftPane.add_select_button({ + .key = "Target Type", + .getValue = [] { return target_type_label(); }, + }), + rightPane, [](Pane& pane) { populate_target_type_picker(pane); }); + leftPane.register_control(leftPane.add_select_button({ + .key = "Sound", + .getValue = [] { return sound_mode_label(); }, + }), + rightPane, [](Pane& pane) { populate_sound_mode_picker(pane); }); }); } diff --git a/src/dusk/ui/pane.cpp b/src/dusk/ui/pane.cpp index 040342addd..59989ad155 100644 --- a/src/dusk/ui/pane.cpp +++ b/src/dusk/ui/pane.cpp @@ -75,6 +75,12 @@ Pane::Pane(Rml::Element* parent, Type type) : FluentComponent(createRoot(parent) childIndex = i; } } + // If item already selected, deselect + if (childIndex >= 0 && childIndex < mChildren.size() && + mChildren[childIndex]->selected()) + { + childIndex = -1; + } set_selected_item(childIndex); // If the selection was handled locally, don't allow it to bubble up to window if (event.GetParameter("handled", false)) { @@ -98,6 +104,40 @@ void Pane::set_selected_item(int index) { } } +Component& Pane::register_control( + Component& component, Pane& nextPane, std::function callback) { + component.listen(component.root(), Rml::EventId::Mouseover, + [this, &component, &nextPane, callback](Rml::Event&) { + if (component.disabled()) { + return; + } + bool anySelected = false; + for (const auto& child : mChildren) { + if (child->selected()) { + anySelected = true; + break; + } + } + if (!anySelected) { + nextPane.clear(); + if (callback) { + callback(nextPane); + } + } + }); + component.listen(component.root(), Rml::EventId::Focus, + [&component, &nextPane, callback = std::move(callback)](Rml::Event&) { + if (component.disabled()) { + return; + } + nextPane.clear(); + if (callback) { + callback(nextPane); + } + }); + return component; +} + bool Pane::focus() { // Focus the first selected child for (const auto& child : mChildren) { diff --git a/src/dusk/ui/pane.hpp b/src/dusk/ui/pane.hpp index 0b54981c7b..f22d89825d 100644 --- a/src/dusk/ui/pane.hpp +++ b/src/dusk/ui/pane.hpp @@ -19,6 +19,8 @@ public: void update() override; void set_selected_item(int index); + Component& register_control( + Component& component, Pane& nextPane, std::function callback); Rml::Element* add_section(const Rml::String& text); ControlledButton& add_button(ControlledButton::Props props) { diff --git a/src/dusk/ui/select_button.cpp b/src/dusk/ui/select_button.cpp index f53c444011..ad98ed422e 100644 --- a/src/dusk/ui/select_button.cpp +++ b/src/dusk/ui/select_button.cpp @@ -84,7 +84,7 @@ void SelectButton::update_props(Props props) { } bool SelectButton::handle_nav_command(NavCommand cmd) { - if (cmd == NavCommand::Confirm) { + if (cmd == NavCommand::Confirm && mProps.submit) { mRoot->DispatchEvent(Rml::EventId::Submit, {}); return true; } diff --git a/src/dusk/ui/select_button.hpp b/src/dusk/ui/select_button.hpp index 08dd638ff4..001de68294 100644 --- a/src/dusk/ui/select_button.hpp +++ b/src/dusk/ui/select_button.hpp @@ -17,6 +17,7 @@ public: Rml::String value; Rml::String icon; bool modified = false; + bool submit = true; }; SelectButton(Rml::Element* parent, Props props); @@ -54,10 +55,15 @@ public: std::function getValue; std::function isDisabled; std::function isModified; + bool submit = true; }; ControlledSelectButton(Rml::Element* parent, Props props) - : BaseControlledSelectButton(parent, {std::move(props.key)}), + : BaseControlledSelectButton(parent, + { + .key = std::move(props.key), + .submit = props.submit, + }), mGetValue(std::move(props.getValue)), mIsDisabled(std::move(props.isDisabled)), mIsModified(std::move(props.isModified)) {} diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index ca6bd952f0..c7da182bcc 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -60,11 +60,6 @@ const Rml::String kUnlockFramerateHelpText = "Uses inter-frame interpolation to enable higher frame rates.

May introduce minor " "visual artifacts or animation glitches."; -int bloom_multiplier_percent() { - return std::clamp( - static_cast(getSettings().game.bloomMultiplier.getValue() * 100.0f + 0.5f), 0, 100); -} - int float_setting_percent(ConfigVar& var) { return static_cast(var.getValue() * 100.0f + 0.5f); } @@ -83,53 +78,88 @@ struct ConfigBoolProps { SelectButton& config_bool_select( Pane& leftPane, Pane& rightPane, ConfigVar& var, ConfigBoolProps props) { - return leftPane - .add_child(BoolButton::Props{ - .key = std::move(props.key), - .icon = std::move(props.icon), - .getValue = [&var] { return var.getValue(); }, - .setValue = - [&var, callback = std::move(props.onChange)](bool value) { - if (value == var.getValue()) { - return; - } - var.setValue(value); - config::Save(); - if (callback) { - callback(value); - } - }, - .isDisabled = std::move(props.isDisabled), - .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, - }) - .on_focus([&rightPane, helpText = std::move(props.helpText)](Rml::Event&) { - rightPane.clear(); - rightPane.add_rml(helpText); + auto& button = leftPane.add_child(BoolButton::Props{ + .key = std::move(props.key), + .icon = std::move(props.icon), + .getValue = [&var] { return var.getValue(); }, + .setValue = + [&var, callback = std::move(props.onChange)](bool value) { + if (value == var.getValue()) { + return; + } + var.setValue(value); + config::Save(); + if (callback) { + callback(value); + } + }, + .isDisabled = std::move(props.isDisabled), + .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, + }); + leftPane.register_control( + button, rightPane, [helpText = std::move(props.helpText)](Pane& pane) { + pane.clear(); + pane.add_rml(helpText); }); + return button; } SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar& var, Rml::String key, Rml::String helpText, int min, int max, int step = 5, std::function isDisabled = {}) { - return leftPane - .add_child(NumberButton::Props{ - .key = std::move(key), - .getValue = [&var] { return float_setting_percent(var); }, - .setValue = - [&var, min, max](int value) { - var.setValue(std::clamp(value, min, max) / 100.0f); - config::Save(); - }, - .isDisabled = std::move(isDisabled), - .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, - .min = min, - .max = max, - .step = step, - .suffix = "%", - }) - .on_focus([&rightPane, helpText = std::move(helpText)](Rml::Event&) { - rightPane.clear(); - rightPane.add_text(helpText); + auto& button = leftPane.add_child(NumberButton::Props{ + .key = std::move(key), + .getValue = [&var] { return float_setting_percent(var); }, + .setValue = + [&var, min, max](int value) { + var.setValue(std::clamp(value, min, max) / 100.0f); + config::Save(); + }, + .isDisabled = std::move(isDisabled), + .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, + .min = min, + .max = max, + .step = step, + .suffix = "%", + }); + leftPane.register_control(button, rightPane, [helpText = std::move(helpText)](Pane& pane) { + pane.clear(); + pane.add_text(helpText); + }); + return button; +} + +template +void overlay_control( + Window& window, Pane& leftPane, Pane& rightPane, ConfigVar& var, const OverlayProps& props) { + leftPane.register_control( + leftPane + .add_select_button({ + .key = props.title, + .getValue = + [&var, option = props.option] { + if constexpr (std::is_same_v) { + return format_graphics_setting_value( + option, float_setting_percent(var)); + } else { + return format_graphics_setting_value( + option, static_cast(var.getValue())); + } + }, + .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, + .submit = false, + }) + .on_nav_command([&window, props](Rml::Event&, NavCommand cmd) { + if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || + cmd == NavCommand::Right) { + window.push(std::make_unique(props)); + return true; + } + return false; + }), + rightPane, [helpText = props.helpText](Pane& pane) { + pane.clear(); + pane.add_text(helpText); }); } @@ -176,141 +206,43 @@ SettingsWindow::SettingsWindow() { }); leftPane.add_section("Resolution"); - leftPane - .add_select_button({ - .key = "Internal Resolution", - .getValue = - [] { - return format_graphics_setting_value(GraphicsOption::InternalResolution, - getSettings().game.internalResolutionScale.getValue()); - }, - .isModified = - [] { - return getSettings().game.internalResolutionScale.getValue() != - getSettings().game.internalResolutionScale.getDefaultValue(); - }, - }) - .on_nav_command([this](Rml::Event&, NavCommand cmd) { - if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || - cmd == NavCommand::Right) { - push(std::make_unique(OverlayProps{ - .option = GraphicsOption::InternalResolution, - .title = "Internal Resolution", - .helpText = kInternalResolutionHelpText, - .valueMin = 0, - .valueMax = 12, - .defaultValue = 0, - })); - return true; - } - return false; - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text(kInternalResolutionHelpText); + overlay_control(*this, leftPane, rightPane, getSettings().game.internalResolutionScale, + OverlayProps{ + .option = GraphicsOption::InternalResolution, + .title = "Internal Resolution", + .helpText = kInternalResolutionHelpText, + .valueMin = 0, + .valueMax = 12, + .defaultValue = 0, }); - leftPane - .add_select_button({ - .key = "Shadow Resolution", - .getValue = - [] { - return format_graphics_setting_value(GraphicsOption::ShadowResolution, - getSettings().game.shadowResolutionMultiplier.getValue()); - }, - .isModified = - [] { - return getSettings().game.shadowResolutionMultiplier.getValue() != - getSettings().game.shadowResolutionMultiplier.getDefaultValue(); - }, - }) - .on_nav_command([this](Rml::Event&, NavCommand cmd) { - if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || - cmd == NavCommand::Right) { - push(std::make_unique(OverlayProps{ - .option = GraphicsOption::ShadowResolution, - .title = "Shadow Resolution", - .helpText = kShadowResolutionHelpText, - .valueMin = 1, - .valueMax = 8, - .defaultValue = 1, - })); - return true; - } - return false; - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text(kShadowResolutionHelpText); + overlay_control(*this, leftPane, rightPane, getSettings().game.shadowResolutionMultiplier, + OverlayProps{ + .option = GraphicsOption::ShadowResolution, + .title = "Shadow Resolution", + .helpText = kShadowResolutionHelpText, + .valueMin = 1, + .valueMax = 8, + .defaultValue = 1, }); leftPane.add_section("Post-Processing"); - leftPane - .add_select_button({ - .key = "Bloom", - .getValue = - [] { - return format_graphics_setting_value(GraphicsOption::BloomMode, - static_cast(getSettings().game.bloomMode.getValue())); - }, - .isModified = - [] { - return getSettings().game.bloomMode.getValue() != - getSettings().game.bloomMode.getDefaultValue(); - }, - }) - .on_nav_command([this](Rml::Event&, NavCommand cmd) { - if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || - cmd == NavCommand::Right) { - push(std::make_unique(OverlayProps{ - .option = GraphicsOption::BloomMode, - .title = "Bloom", - .helpText = kBloomHelpText, - .valueMin = static_cast(BloomMode::Off), - .valueMax = static_cast(BloomMode::Dusk), - .defaultValue = static_cast(BloomMode::Classic), - })); - return true; - } - return false; - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text(kBloomHelpText); + overlay_control(*this, leftPane, rightPane, getSettings().game.bloomMode, + OverlayProps{ + .option = GraphicsOption::BloomMode, + .title = "Bloom", + .helpText = kBloomHelpText, + .valueMin = static_cast(BloomMode::Off), + .valueMax = static_cast(BloomMode::Dusk), + .defaultValue = static_cast(BloomMode::Classic), }); - leftPane - .add_select_button({ - .key = "Bloom Brightness", - .getValue = - [] { - return format_graphics_setting_value( - GraphicsOption::BloomMultiplier, bloom_multiplier_percent()); - }, - .isDisabled = - [] { return getSettings().game.bloomMode.getValue() == BloomMode::Off; }, - .isModified = - [] { - return getSettings().game.bloomMultiplier.getValue() != - getSettings().game.bloomMultiplier.getDefaultValue(); - }, - }) - .on_nav_command([this](Rml::Event&, NavCommand cmd) { - if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || - cmd == NavCommand::Right) { - push(std::make_unique(OverlayProps{ - .option = GraphicsOption::BloomMultiplier, - .title = "Bloom Brightness", - .helpText = kBloomBrightnessHelpText, - .valueMin = 0, - .valueMax = 100, - .defaultValue = 100, - })); - return true; - } - return false; - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text(kBloomBrightnessHelpText); + overlay_control(*this, leftPane, rightPane, getSettings().game.bloomMultiplier, + OverlayProps{ + .option = GraphicsOption::BloomMultiplier, + .title = "Bloom Brightness", + .helpText = kBloomBrightnessHelpText, + .valueMin = 0, + .valueMax = 100, + .defaultValue = 100, }); leftPane.add_section("Rendering"); @@ -344,11 +276,12 @@ SettingsWindow::SettingsWindow() { }; leftPane.add_section("Controller"); - leftPane.add_button("Configure Controller") - .on_pressed([this] { push(std::make_unique()); }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text("Open controller binding configuration."); + leftPane.register_control(leftPane.add_button("Configure Controller").on_pressed([this] { + push(std::make_unique()); + }), + rightPane, [](Pane& pane) { + pane.clear(); + pane.add_text("Open controller binding configuration."); }); leftPane.add_section("Camera"); @@ -403,8 +336,8 @@ SettingsWindow::SettingsWindow() { // TODO: Individual sliders for Main Music, Sub Music, Sound Effects, and Fanfare. leftPane.add_section("Volume"); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Master Volume", .getValue = [] { return getSettings().audio.masterVolume.getValue(); }, .setValue = @@ -420,10 +353,10 @@ SettingsWindow::SettingsWindow() { }, .max = 100, .suffix = "%", - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text("Adjusts the volume of all sounds in the game."); + }), + rightPane, [](Pane& pane) { + pane.clear(); + pane.add_text("Adjusts the volume of all sounds in the game."); }); leftPane.add_section("Effects"); @@ -493,8 +426,8 @@ SettingsWindow::SettingsWindow() { "Enables rotating Link in the collection menu with the C-Stick."); leftPane.add_section("Difficulty"); - leftPane - .add_child(NumberButton::Props{ + leftPane.register_control( + leftPane.add_child(NumberButton::Props{ .key = "Damage Multiplier", .getValue = [] { return getSettings().game.damageMultiplier.getValue(); }, .setValue = @@ -511,10 +444,10 @@ SettingsWindow::SettingsWindow() { .min = 1, .max = 8, .suffix = "×", - }) - .on_focus([&rightPane](Rml::Event&) { - rightPane.clear(); - rightPane.add_text("Multiplies incoming damage."); + }), + rightPane, [](Pane& pane) { + pane.clear(); + pane.add_text("Multiplies incoming damage."); }); addSpeedrunDisabledOption( "Instant Death", getSettings().game.instantDeath, "Any hit will instantly kill you.");