add functionality for saving and loading presets

This commit is contained in:
gymnast86
2026-06-19 03:08:12 -07:00
parent f20cf3c24e
commit 08e0645ef8
6 changed files with 199 additions and 6 deletions
+1
View File
@@ -490,6 +490,7 @@ window.modal.danger .modal-header icon {
font-size: 20dp;
color: #FFFFFF;
font-weight: normal;
word-break: break-word;
}
.modal-body span.tip {
@@ -86,6 +86,9 @@ namespace randomizer::seedgen::config
}
auto& settings = this->_settingsList.front();
settings.GetModifiableExcludedLocations().clear();
settings.GetModifiableMixedEntrancePools().clear();
settings.GetModifiableStartingInventory().clear();
// Load settings info
auto settingInfoMap = settings::GetAllSettingsInfo();
+33
View File
@@ -1,5 +1,7 @@
#include "modal.hpp"
#include "string_button.hpp"
namespace dusk::ui {
Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::move(props)) {
@@ -100,4 +102,35 @@ bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
return false;
}
TextInputModal::TextInputModal(Props props) : Modal(props) {
auto modalBody = mDialog->QuerySelector(".modal-body");
mInput = std::make_unique<StringButton>(modalBody, StringButton::Props{
.getValue = [this]{return mInputText;},
.setValue = [this](Rml::String value) { mInputText = value; },
});
mInput->start_editing();
}
bool TextInputModal::handle_nav_command(Rml::Event& event, NavCommand cmd) {
auto retVal = Modal::handle_nav_command(event, cmd);
if (!retVal) {
if (mInput->root()->IsPseudoClassSet("focus") && cmd == NavCommand::Down) {
mButtons[0]->focus();
retVal = true;
} else if (!mInput->root()->IsPseudoClassSet("focus") && cmd == NavCommand::Up) {
mInput->focus();
retVal = true;
}
}
return retVal;
}
void TextInputModal::update() {
mInput->update();
Document::update();
}
} // namespace dusk::ui
+16 -2
View File
@@ -31,12 +31,26 @@ public:
protected:
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
private:
void dismiss();
Props mProps;
std::vector<std::unique_ptr<Button> > mButtons;
};
class StringButton;
class TextInputModal : public Modal {
public:
explicit TextInputModal(Props props);
Rml::String get_input_text() {return mInputText;}
void update() override;
protected:
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
private:
std::unique_ptr<StringButton> mInput{};
Rml::String mInputText{};
};
} // namespace dusk::ui
+143 -4
View File
@@ -652,14 +652,11 @@ void RandomizerWindow::rando_excluded_locations_update_left_pane(Pane& innerLeft
// Focus the closest child in the next Pane. Returns true if a child was found to focus
bool focus_closest_child_on_next_pane(Pane& currentPane, Pane& nextPane) {
auto childToFocusY = currentPane.get_focused_child_y();
return nextPane.focus_closest_child(childToFocusY);
}
void delete_seed_callback(Pane& pane) {
// Get the Y position to focus the child nearest to after we rebuild this pane
auto childToFocusY = pane.get_focused_child_y();
@@ -688,7 +685,6 @@ void delete_seed_callback(Pane& pane) {
}
}
// TODO: our ui lib doesnt have an easy way to either refresh or remove values from the right pane
pane.add_button(
{
.text = hash,
@@ -713,6 +709,9 @@ RandomizerWindow::RandomizerWindow(dFile_select_c* fileSelect /*= nullptr*/) : m
if (!std::filesystem::exists(GetRandomizerSeedsPath())) {
std::filesystem::create_directories(GetRandomizerSeedsPath());
}
if (!std::filesystem::exists(GetRandomizerPresetsPath())) {
std::filesystem::create_directories(GetRandomizerPresetsPath());
}
// If we're bringing this menu up during file selection
if (mFileSelectMenu) {
@@ -823,6 +822,58 @@ RandomizerWindow::RandomizerWindow(dFile_select_c* fileSelect /*= nullptr*/) : m
leftPane.add_button("Delete Seeds"),
rightPane, delete_seed_callback
);
leftPane.add_section("Presets");
leftPane.register_control(
leftPane.add_button("Save Current Settings as Preset")
.on_pressed([] {
push_document(std::make_unique<TextInputModal>(Modal::Props{
.title = "Preset Name",
.bodyRml = "",
.actions = {
ModalAction{
.label = "Save",
.onPressed = [](Modal& modal) {
auto textModal = dynamic_cast<TextInputModal*>(&modal);
if (!textModal->get_input_text().empty()) {
modal.pop();
SaveNewRandomizerPreset(textModal->get_input_text());
}
},
},
ModalAction{
.label = "Cancel",
.onPressed = [](Modal& modal) {
modal.pop();
},
},
},
.icon = "information"
}));
}),
rightPane, [](Pane& pane) {
pane.clear();
pane.add_text("Save the current settings to your list of presets.");
});
leftPane.register_control(
leftPane.add_button("Load Preset"),
rightPane, [](Pane& pane) {
pane.clear();
pane.add_text("Choose an existing preset to load from.");
for (const auto& file : std::filesystem::directory_iterator{GetRandomizerPresetsPath()}) {
const auto& filepath = file.path();
auto presetName = file.path().stem().generic_string();
pane.add_button(ControlledButton::Props{
.text = presetName,
})
.on_pressed([filepath] {
ApplyExistingRandomizerPreset(filepath);
});
}
});
});
add_tab("Seed Options", [this](Rml::Element* content) {
@@ -1168,6 +1219,90 @@ bool FileSelectRandomizerWindow::consume_close_request() {
return true;
}
void SaveNewRandomizerPreset(const std::string& presetName, bool overwriteExisting /*= false*/) {
auto presetFilepath = GetRandomizerPresetsPath() / (presetName + ".yaml");
// If the preset exists, ask the user if they want to overwrite it. If so, call this function
// again but force overwrite the existing preset
if (std::filesystem::exists(presetFilepath) && !overwriteExisting) {
push_document(std::make_unique<Modal>(Modal::Props{
.title = "Overwrite Existing Preset",
.bodyRml = "A preset with the name " + presetName + " already exists. Do you wish to overwrite it?",
.actions = {
ModalAction{
.label = "Yes",
.onPressed = [presetName](Modal& modal) {
modal.pop();
SaveNewRandomizerPreset(presetName, true);
}
},
ModalAction{
.label = "No",
.onPressed = [](Modal& modal) {
modal.pop();
}
}
}
}));
}
// If there was an error trying to save, let the user know
try {
GetRandomizerConfig().WriteSettingsToFile(presetFilepath);
} catch (std::exception& e) {
auto modal = dynamic_cast<Modal*>(&push_document(std::make_unique<Modal>(Modal::Props{
.title = "Error Saving Preset",
.bodyRml = fmt::format("Error: {}", e.what()),
.actions = {
ModalAction{
.label = "Okay",
.onPressed = [](Modal& modal) {
modal.pop();
}
}
},
.icon = "error"
})));
return;
}
push_toast(Toast{
.title = "",
.content = fmt::format("Saved preset {}", presetName),
.duration = std::chrono::seconds(3)
});
}
void ApplyExistingRandomizerPreset(const std::filesystem::path& presetFilePath) {
// Don't overwrite the seed with the one from the preset
auto seed = GetRandomizerConfig().GetSeed();
try {
GetRandomizerConfig().LoadFromFile(presetFilePath, GetRandomizerPreferencesPath(), false, false);
GetRandomizerConfig().SetSeed(seed);
} catch (std::exception& e) {
auto modal = dynamic_cast<Modal*>(&push_document(std::make_unique<Modal>(Modal::Props{
.title = "Error Loading Preset",
.bodyRml = fmt::format("Error: {}", e.what()),
.actions = {
ModalAction{
.label = "Okay",
.onPressed = [](Modal& modal) {
modal.pop();
}
}
},
.icon = "error"
})));
return;
}
push_toast(Toast{
.title = "",
.content = fmt::format("Loaded preset {}", presetFilePath.stem().generic_string()),
.duration = std::chrono::seconds(3)
});
}
std::filesystem::path GetRandomizerPath() {
return data::configured_data_path() / "randomizer";
}
@@ -1180,6 +1315,10 @@ std::filesystem::path GetRandomizerPreferencesPath() {
return GetRandomizerPath() / "preferences.yaml";
}
std::filesystem::path GetRandomizerPresetsPath() {
return GetRandomizerPath() / "presets";
}
std::filesystem::path GetRandomizerSeedsPath() {
return GetRandomizerPath() / "seeds";
}
+3
View File
@@ -10,10 +10,13 @@ class dFile_select_c;
namespace dusk::ui {
class Pane;
void SaveNewRandomizerPreset(const std::string& presetName, bool overwriteExisting = false);
void ApplyExistingRandomizerPreset(const std::filesystem::path& presetFilePath);
std::filesystem::path GetRandomizerPath();
std::filesystem::path GetRandomizerSettingsPath();
std::filesystem::path GetRandomizerPreferencesPath();
std::filesystem::path GetRandomizerSeedsPath();
std::filesystem::path GetRandomizerPresetsPath();
randomizer::seedgen::config::Config& GetRandomizerConfig();