mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
385 lines
12 KiB
C++
385 lines
12 KiB
C++
#include <hex/api/content_registry/user_interface.hpp>
|
|
#include <hex/api/theme_manager.hpp>
|
|
#include <hex/helpers/logger.hpp>
|
|
#include <fonts/vscode_icons.hpp>
|
|
#include <fonts/tabler_icons.hpp>
|
|
#include <fmt/format.h>
|
|
#include "lib/core/globals.h"
|
|
#include "lib/config/config.h"
|
|
#include "lib/data/disk.h"
|
|
#include "lib/data/sector.h"
|
|
#include "lib/config/proto.h"
|
|
#include "globals.h"
|
|
#include "configview.h"
|
|
#include "datastore.h"
|
|
#include "utils.h"
|
|
|
|
using namespace hex;
|
|
|
|
static DynamicSettingFactory settings("fluxengine.settings");
|
|
|
|
static constexpr const char* DEFAULT_CUSTOM_SETTINGS = R"R(
|
|
# These settings will override the ones above.
|
|
# Here are some useful ones:
|
|
# decoder.retries=0
|
|
# drive.revolutions=1.2
|
|
)R";
|
|
|
|
ConfigView::ConfigView():
|
|
View::Window("fluxengine.view.config.name", ICON_VS_COMPASS)
|
|
{
|
|
Events::SetSystemConfig::subscribe(
|
|
[](std::string customConfig)
|
|
{
|
|
auto customSetting = settings.get<std::string>("systemProperties");
|
|
customSetting =
|
|
"# These settings were set by a file and\n"
|
|
"# may contradict the ones above (it's a bug).\n" +
|
|
customConfig;
|
|
});
|
|
}
|
|
|
|
static void emitOptions(DynamicSetting<std::string>& setting,
|
|
const ConfigProto* config,
|
|
const std::set<int>& applicableOptions)
|
|
{
|
|
auto options = stringToOptions(setting);
|
|
|
|
for (auto& it : config->option())
|
|
{
|
|
if (!applicableOptions.empty() &&
|
|
std::ranges::none_of(it.applicability(),
|
|
[&](int item)
|
|
{
|
|
return applicableOptions.contains(item);
|
|
}))
|
|
continue;
|
|
|
|
bool selected = options.contains(it.name());
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::TextWrapped(
|
|
"%s", wolv::util::capitalizeString(it.comment()).c_str());
|
|
|
|
ImGui::TableNextColumn();
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
if (ImGui::BeginCombo(fmt::format("##{}", it.comment()).c_str(),
|
|
selected ? "fluxengine.view.config.yes"_lang
|
|
: "fluxengine.view.config.no"_lang,
|
|
ImGuiComboFlags_None))
|
|
{
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndCombo();
|
|
};
|
|
|
|
int value = -1;
|
|
if (ImGui::Selectable("fluxengine.view.config.no"_lang, !selected))
|
|
value = 0;
|
|
if (ImGui::Selectable("fluxengine.view.config.yes"_lang, selected))
|
|
value = 1;
|
|
if (value != -1)
|
|
{
|
|
options.erase(it.name());
|
|
if (value)
|
|
options[it.name()] = "true";
|
|
setting = optionsToString(options);
|
|
Datastore::reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto& it : config->option_group())
|
|
{
|
|
if (!applicableOptions.empty() &&
|
|
std::ranges::none_of(it.applicability(),
|
|
[&](int item)
|
|
{
|
|
return applicableOptions.contains(item);
|
|
}))
|
|
continue;
|
|
|
|
std::string comment = it.comment();
|
|
if (comment == "$formats")
|
|
comment = (std::string) "fluxengine.view.config.variations"_lang;
|
|
|
|
const OptionProto* selectedOption = nullptr;
|
|
if (it.name().empty())
|
|
{
|
|
for (auto& ot : it.option())
|
|
if (options.contains(ot.name()))
|
|
selectedOption = &ot;
|
|
}
|
|
else
|
|
{
|
|
auto value = findOrDefault(options, it.name());
|
|
for (auto& ot : it.option())
|
|
if (ot.name() == value)
|
|
selectedOption = &ot;
|
|
}
|
|
|
|
if (!selectedOption)
|
|
for (auto& ot : it.option())
|
|
if (ot.set_by_default())
|
|
selectedOption = &ot;
|
|
|
|
std::string value;
|
|
if (selectedOption)
|
|
value = wolv::util::capitalizeString(selectedOption->comment());
|
|
else
|
|
value = "***missing default***";
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::TextWrapped("%s", comment.c_str());
|
|
|
|
ImGui::TableNextColumn();
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
if (ImGui::BeginCombo(fmt::format("##{}", it.comment()).c_str(),
|
|
value.c_str(),
|
|
ImGuiComboFlags_None))
|
|
{
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndCombo();
|
|
};
|
|
|
|
for (auto& ot : it.option())
|
|
if (ImGui::Selectable(
|
|
ot.comment().c_str(), &ot == selectedOption))
|
|
{
|
|
if (it.name().empty())
|
|
{
|
|
if (selectedOption)
|
|
options.erase(selectedOption->name());
|
|
options[ot.name()] = "true";
|
|
}
|
|
else
|
|
{
|
|
options.erase(it.name());
|
|
options[it.name()] = ot.name();
|
|
}
|
|
setting = optionsToString(options);
|
|
Datastore::reset();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void formatProperties()
|
|
{
|
|
auto formatSetting = settings.get<std::string>("format.selected", "ibm");
|
|
auto selectedFormat = findOrDefault(formats, (std::string)formatSetting);
|
|
if (!selectedFormat)
|
|
{
|
|
formatSetting = "ibm";
|
|
selectedFormat = formats.at(formatSetting);
|
|
}
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::TextWrapped("Format");
|
|
ImGui::TableNextColumn();
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
if (ImGui::BeginCombo("##formats",
|
|
selectedFormat->shortname().c_str(),
|
|
ImGuiComboFlags_HeightLargest))
|
|
{
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndCombo();
|
|
};
|
|
|
|
for (auto& [name, format] : formats)
|
|
if (!format->is_extension())
|
|
{
|
|
auto label = format->shortname();
|
|
if (label.empty())
|
|
label = name;
|
|
if (ImGui::Selectable(
|
|
fmt::format("{}##{}", label, name).c_str(), false))
|
|
{
|
|
formatSetting = name;
|
|
Datastore::reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
auto formatOptionsSetting = DynamicSetting<std::string>(
|
|
"fluxengine.settings", (std::string)formatSetting);
|
|
emitOptions(formatOptionsSetting, selectedFormat, {});
|
|
}
|
|
|
|
static void deviceProperties()
|
|
{
|
|
/* Device name */
|
|
|
|
std::set<int> applicableOptions = {ANY_SOURCESINK};
|
|
auto deviceNameSetting = settings.get<std::string>("device");
|
|
auto selectedDevice = findOrDefault(Datastore::getDevices(),
|
|
(std::string)deviceNameSetting,
|
|
{.label = "No device configured"});
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::Text("Device");
|
|
|
|
if ((std::string)deviceNameSetting == DEVICE_FLUXFILE)
|
|
applicableOptions.insert(FLUXFILE_SOURCESINK);
|
|
else if ((std::string)deviceNameSetting == DEVICE_MANUAL)
|
|
{
|
|
applicableOptions.insert(MANUAL_SOURCESINK);
|
|
applicableOptions.insert(HARDWARE_SOURCESINK);
|
|
}
|
|
else
|
|
applicableOptions.insert(HARDWARE_SOURCESINK);
|
|
|
|
ImGui::TableNextColumn();
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
if (ImGui::BeginCombo("##devices",
|
|
selectedDevice.label.c_str(),
|
|
ImGuiComboFlags_HeightLargest))
|
|
{
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndCombo();
|
|
};
|
|
|
|
for (auto& [name, device] : Datastore::getDevices())
|
|
if (ImGui::Selectable(device.label.c_str(), false))
|
|
deviceNameSetting = name;
|
|
}
|
|
|
|
/* The rescan button. */
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::TableNextColumn();
|
|
if (ImGui::Button("fluxengine.view.config.rescan"_lang))
|
|
{
|
|
Datastore::probeDevices();
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("fluxengine.view.config.setupFluxFile"_lang))
|
|
{
|
|
fs::openFileBrowser(fs::DialogMode::Open,
|
|
{},
|
|
[](const auto& path)
|
|
{
|
|
settings.get<std::string>("device") = DEVICE_FLUXFILE;
|
|
settings.get<std::fs::path>("fluxfile") = path;
|
|
});
|
|
}
|
|
|
|
/* The file path, if DEVICE_FLUXFILE, and device path, if DEVICE_MANUAL
|
|
*/
|
|
|
|
auto doPathSetting = [=](const std::string& label,
|
|
const std::string& setting,
|
|
const std::string& id)
|
|
{
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::Text(label);
|
|
|
|
auto pathSetting = settings.get<std::string>(setting);
|
|
auto pathString = (std::string)pathSetting;
|
|
ImGui::TableNextColumn();
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
if (ImGui::InputText(id.c_str(),
|
|
pathString,
|
|
ImGuiInputTextFlags_CallbackCompletion |
|
|
ImGuiInputTextFlags_ElideLeft))
|
|
pathSetting = pathString;
|
|
};
|
|
|
|
if ((std::string)deviceNameSetting == DEVICE_FLUXFILE)
|
|
doPathSetting("fluxengine.view.config.fluxFile"_lang,
|
|
"fluxfile",
|
|
"##fluxfilePath");
|
|
if ((std::string)deviceNameSetting == DEVICE_MANUAL)
|
|
doPathSetting("fluxengine.view.config.manualDevicePath"_lang,
|
|
"manualDevicePath",
|
|
"##manualDevicePath");
|
|
|
|
/* Other options */
|
|
|
|
auto globalOptionsSetting =
|
|
DynamicSetting<std::string>("fluxengine.settings", "globalSettings");
|
|
emitOptions(
|
|
globalOptionsSetting, formats.at("_global_options"), applicableOptions);
|
|
}
|
|
|
|
void ConfigView::drawContent()
|
|
{
|
|
ImGui::BeginDisabled(Datastore::isBusy());
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndDisabled();
|
|
};
|
|
|
|
ImGui::SeparatorText("fluxengine.view.config.formatProperties"_lang);
|
|
if (ImGui::BeginTable("propertiesEditor",
|
|
2,
|
|
ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders |
|
|
ImGuiTableFlags_RowBg))
|
|
{
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndTable();
|
|
};
|
|
|
|
formatProperties();
|
|
}
|
|
|
|
ImGui::SeparatorText("fluxengine.view.config.deviceProperties"_lang);
|
|
if (ImGui::BeginTable("propertiesEditor",
|
|
2,
|
|
ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders |
|
|
ImGuiTableFlags_RowBg))
|
|
{
|
|
ON_SCOPE_EXIT
|
|
{
|
|
ImGui::EndTable();
|
|
};
|
|
deviceProperties();
|
|
}
|
|
|
|
ImGui::SeparatorText("fluxengine.view.config.customProperties"_lang);
|
|
|
|
if (ImGui::BeginTabBar("customconfig", ImGuiTabBarFlags_None))
|
|
{
|
|
DEFER(ImGui::EndTabBar());
|
|
if (ImGui::BeginTabItem("User"))
|
|
{
|
|
DEFER(ImGui::EndTabItem());
|
|
|
|
auto setting =
|
|
settings.get<std::string>("custom", DEFAULT_CUSTOM_SETTINGS);
|
|
std::string buffer = setting;
|
|
if (ImGui::InputTextMultiline("##customProperties",
|
|
buffer,
|
|
ImGui::GetContentRegionAvail(),
|
|
ImGuiInputTextFlags_None))
|
|
setting = buffer;
|
|
}
|
|
if (ImGui::BeginTabItem("System"))
|
|
{
|
|
DEFER(ImGui::EndTabItem());
|
|
|
|
auto setting = settings.get<std::string>("systemProperties");
|
|
std::string buffer = setting;
|
|
if (ImGui::InputTextMultiline("##systemProperties",
|
|
buffer,
|
|
ImGui::GetContentRegionAvail(),
|
|
ImGuiInputTextFlags_None))
|
|
setting = buffer;
|
|
}
|
|
}
|
|
}
|