mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-08 18:13:02 -04:00
UI: Refactor pane control to allow hover for help text
This commit is contained in:
@@ -66,15 +66,6 @@ public:
|
||||
return static_cast<Derived&>(*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<bool(Rml::Event&, NavCommand)> callback) {
|
||||
listen(Rml::EventId::Click, [this, callback](Rml::Event& event) {
|
||||
if (!disabled() && callback(event, NavCommand::Confirm)) {
|
||||
|
||||
@@ -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>(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>(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>(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>(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);
|
||||
|
||||
+295
-307
@@ -1295,73 +1295,71 @@ EditorWindow::EditorWindow() {
|
||||
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
|
||||
|
||||
leftPane.add_section("Player");
|
||||
leftPane
|
||||
.add_child<StringButton>(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>(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>(NumberButton::Props{
|
||||
leftPane.register_control(leftPane.add_child<StringButton>(StringButton::Props{
|
||||
.key = "Player Name",
|
||||
.getValue = get_player_name,
|
||||
.setValue = set_player_name,
|
||||
.maxLength = 16,
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(leftPane.add_child<StringButton>(StringButton::Props{
|
||||
.key = "Horse Name",
|
||||
.getValue = get_horse_name,
|
||||
.setValue = set_horse_name,
|
||||
.maxLength = 16,
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Day",
|
||||
.getValue = [] { return get_player_status_b()->getDate(); },
|
||||
.setValue =
|
||||
[](int value) { get_player_status_b()->setDate(static_cast<u16>(value)); },
|
||||
.max = UINT16_MAX,
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Transform Level",
|
||||
.getValue =
|
||||
[] {
|
||||
@@ -1455,10 +1453,10 @@ EditorWindow::EditorWindow() {
|
||||
static_cast<u8>((1u << value) - 1u);
|
||||
},
|
||||
.max = 3,
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Twilight Clear Level",
|
||||
.getValue =
|
||||
[] {
|
||||
@@ -1471,8 +1469,8 @@ EditorWindow::EditorWindow() {
|
||||
static_cast<u8>((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>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Room",
|
||||
.getValue = [] { return get_player_return_place()->mRoomNo; },
|
||||
.setValue =
|
||||
[](int value) { get_player_return_place()->mRoomNo = static_cast<s8>(value); },
|
||||
.min = std::numeric_limits<s8>::min(),
|
||||
.max = std::numeric_limits<s8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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<u8>(value);
|
||||
},
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
}),
|
||||
rightPane, {});
|
||||
|
||||
leftPane.add_section("Horse Location");
|
||||
leftPane
|
||||
.add_child<StringButton>(StringButton::Props{
|
||||
.key = "Horse Position",
|
||||
.getValue =
|
||||
[] {
|
||||
const auto* horsePlace = get_horse_place();
|
||||
return fmt::format("{}, {}, {}", static_cast<float>(horsePlace->mPos.x),
|
||||
static_cast<float>(horsePlace->mPos.y),
|
||||
static_cast<float>(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>(NumberButton::Props{
|
||||
leftPane.register_control(leftPane.add_child<StringButton>(StringButton::Props{
|
||||
.key = "Horse Position",
|
||||
.getValue =
|
||||
[] {
|
||||
const auto* horsePlace = get_horse_place();
|
||||
return fmt::format("{}, {}, {}",
|
||||
static_cast<float>(horsePlace->mPos.x),
|
||||
static_cast<float>(horsePlace->mPos.y),
|
||||
static_cast<float>(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>(NumberButton::Props{
|
||||
.key = "Horse Angle",
|
||||
.getValue = [] { return get_horse_place()->mAngleY; },
|
||||
.setValue = [](int value) { get_horse_place()->mAngleY = static_cast<s16>(value); },
|
||||
.min = std::numeric_limits<s16>::min(),
|
||||
.max = std::numeric_limits<s16>::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>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Horse Room",
|
||||
.getValue = [] { return get_horse_place()->mRoomNo; },
|
||||
.setValue = [](int value) { get_horse_place()->mRoomNo = static_cast<s8>(value); },
|
||||
.min = std::numeric_limits<s8>::min(),
|
||||
.max = std::numeric_limits<s8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Horse Spawn ID",
|
||||
.getValue = [] { return get_horse_place()->mSpawnId; },
|
||||
.setValue = [](int value) { get_horse_place()->mSpawnId = static_cast<u8>(value); },
|
||||
.max = std::numeric_limits<u8>::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<Pane>(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>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Arrows Amount",
|
||||
.getValue = [] { return get_player_item_record()->mArrowNum; },
|
||||
.setValue =
|
||||
[](int value) { get_player_item_record()->mArrowNum = static_cast<u8>(value); },
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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<u8>(value);
|
||||
},
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
}),
|
||||
rightPane, {});
|
||||
for (int bag = 0; bag < 3; ++bag) {
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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<u8>(value);
|
||||
},
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
}),
|
||||
rightPane, {});
|
||||
}
|
||||
for (int bottle = 0; bottle < 4; ++bottle) {
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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<u8>(value);
|
||||
},
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
}),
|
||||
rightPane, {});
|
||||
}
|
||||
|
||||
leftPane.add_section("Capacities");
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Arrows Max",
|
||||
.getValue = [] { return get_player_item_max()->mItemMax[0]; },
|
||||
.setValue =
|
||||
[](int value) { get_player_item_max()->mItemMax[0] = static_cast<u8>(value); },
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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<u8>(value); },
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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<u8>(value); },
|
||||
.max = std::numeric_limits<u8>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Bomblings Max",
|
||||
.getValue = [] { return get_player_item_max()->mItemMax[3]; },
|
||||
.setValue =
|
||||
[](int value) { get_player_item_max()->mItemMax[3] = static_cast<u8>(value); },
|
||||
.max = std::numeric_limits<u8>::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<Pane>(content, Pane::Type::Controlled);
|
||||
auto& rightPane = add_child<Pane>(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<Pane>(content, Pane::Type::Uncontrolled);
|
||||
|
||||
leftPane.add_section("Records");
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "STAR Game Time (ms)",
|
||||
.getValue =
|
||||
[] {
|
||||
@@ -1854,10 +1844,10 @@ EditorWindow::EditorWindow() {
|
||||
get_minigame()->setHookGameTime(static_cast<u32>(std::max(0, value)));
|
||||
},
|
||||
.max = std::numeric_limits<int>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Snowboard Race Time (ms)",
|
||||
.getValue =
|
||||
[] {
|
||||
@@ -1869,10 +1859,10 @@ EditorWindow::EditorWindow() {
|
||||
get_minigame()->setRaceGameTime(static_cast<u32>(std::max(0, value)));
|
||||
},
|
||||
.max = std::numeric_limits<int>::max(),
|
||||
})
|
||||
.on_focus([&rightPane](Rml::Event&) { rightPane.clear(); });
|
||||
leftPane
|
||||
.add_child<NumberButton>(NumberButton::Props{
|
||||
}),
|
||||
rightPane, {});
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(NumberButton::Props{
|
||||
.key = "Fruit-Pop-Flight Score",
|
||||
.getValue =
|
||||
[] {
|
||||
@@ -1884,8 +1874,8 @@ EditorWindow::EditorWindow() {
|
||||
get_minigame()->setBalloonScore(static_cast<u32>(std::max(0, value)));
|
||||
},
|
||||
.max = std::numeric_limits<int>::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<Pane>(content, Pane::Type::Uncontrolled);
|
||||
|
||||
leftPane.add_section("Options");
|
||||
leftPane
|
||||
.add_child<BoolButton>(BoolButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<BoolButton>(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); });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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<void(Pane&)> 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) {
|
||||
|
||||
@@ -19,6 +19,8 @@ public:
|
||||
void update() override;
|
||||
|
||||
void set_selected_item(int index);
|
||||
Component& register_control(
|
||||
Component& component, Pane& nextPane, std::function<void(Pane&)> callback);
|
||||
|
||||
Rml::Element* add_section(const Rml::String& text);
|
||||
ControlledButton& add_button(ControlledButton::Props props) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<Rml::String()> getValue;
|
||||
std::function<bool()> isDisabled;
|
||||
std::function<bool()> 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)) {}
|
||||
|
||||
|
||||
+126
-193
@@ -60,11 +60,6 @@ const Rml::String kUnlockFramerateHelpText =
|
||||
"Uses inter-frame interpolation to enable higher frame rates.<br/><br/>May introduce minor "
|
||||
"visual artifacts or animation glitches.";
|
||||
|
||||
int bloom_multiplier_percent() {
|
||||
return std::clamp(
|
||||
static_cast<int>(getSettings().game.bloomMultiplier.getValue() * 100.0f + 0.5f), 0, 100);
|
||||
}
|
||||
|
||||
int float_setting_percent(ConfigVar<float>& var) {
|
||||
return static_cast<int>(var.getValue() * 100.0f + 0.5f);
|
||||
}
|
||||
@@ -83,53 +78,88 @@ struct ConfigBoolProps {
|
||||
|
||||
SelectButton& config_bool_select(
|
||||
Pane& leftPane, Pane& rightPane, ConfigVar<bool>& var, ConfigBoolProps props) {
|
||||
return leftPane
|
||||
.add_child<BoolButton>(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>(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<float>& var,
|
||||
Rml::String key, Rml::String helpText, int min, int max, int step = 5,
|
||||
std::function<bool()> isDisabled = {}) {
|
||||
return leftPane
|
||||
.add_child<NumberButton>(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>(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 <typename T>
|
||||
void overlay_control(
|
||||
Window& window, Pane& leftPane, Pane& rightPane, ConfigVar<T>& 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<T, float>) {
|
||||
return format_graphics_setting_value(
|
||||
option, float_setting_percent(var));
|
||||
} else {
|
||||
return format_graphics_setting_value(
|
||||
option, static_cast<int>(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<Overlay>(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<Overlay>(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<Overlay>(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<int>(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<Overlay>(OverlayProps{
|
||||
.option = GraphicsOption::BloomMode,
|
||||
.title = "Bloom",
|
||||
.helpText = kBloomHelpText,
|
||||
.valueMin = static_cast<int>(BloomMode::Off),
|
||||
.valueMax = static_cast<int>(BloomMode::Dusk),
|
||||
.defaultValue = static_cast<int>(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<int>(BloomMode::Off),
|
||||
.valueMax = static_cast<int>(BloomMode::Dusk),
|
||||
.defaultValue = static_cast<int>(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<Overlay>(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<ControllerConfigWindow>()); })
|
||||
.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<ControllerConfigWindow>());
|
||||
}),
|
||||
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>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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>(NumberButton::Props{
|
||||
leftPane.register_control(
|
||||
leftPane.add_child<NumberButton>(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.");
|
||||
|
||||
Reference in New Issue
Block a user