mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
Compare commits
7 Commits
5b7f9d84f9
...
dcae381973
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcae381973 | ||
|
|
2142bc7cce | ||
|
|
ae3f82264a | ||
|
|
710e83c098 | ||
|
|
4f46fff3be | ||
|
|
58ea21a9a2 | ||
|
|
0fd1aa82a6 |
@@ -451,6 +451,29 @@ bool Config::applyOption(const std::string& name, const std::string value)
|
|||||||
return optionInfo.usesValue;
|
return optionInfo.usesValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::applyOptionsFile(const std::string& data)
|
||||||
|
{
|
||||||
|
if (!data.empty())
|
||||||
|
{
|
||||||
|
for (auto setting : split(data, '\n'))
|
||||||
|
{
|
||||||
|
setting = trimWhitespace(setting);
|
||||||
|
if (setting.size() == 0)
|
||||||
|
continue;
|
||||||
|
if (setting[0] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto equals = setting.find('=');
|
||||||
|
if (equals == std::string::npos)
|
||||||
|
error("Malformed setting line '{}'", setting);
|
||||||
|
|
||||||
|
auto key = setting.substr(0, equals);
|
||||||
|
auto value = setting.substr(equals + 1);
|
||||||
|
globalConfig().set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Config::applyDefaultOptions()
|
void Config::applyDefaultOptions()
|
||||||
{
|
{
|
||||||
std::set<const OptionGroupProto*> appliedOptionGroups;
|
std::set<const OptionGroupProto*> appliedOptionGroups;
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ public:
|
|||||||
bool isOptionValid(const OptionProto& option);
|
bool isOptionValid(const OptionProto& option);
|
||||||
void applyOption(const OptionInfo& optionInfo);
|
void applyOption(const OptionInfo& optionInfo);
|
||||||
bool applyOption(const std::string& name, const std::string value = "");
|
bool applyOption(const std::string& name, const std::string value = "");
|
||||||
|
void applyOptionsFile(const std::string& data);
|
||||||
void applyDefaultOptions();
|
void applyDefaultOptions();
|
||||||
void clearOptions();
|
void clearOptions();
|
||||||
|
|
||||||
|
|||||||
@@ -540,12 +540,13 @@ findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor)
|
|||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProtoField> findAllProtoFields(google::protobuf::Message* message)
|
std::vector<ProtoField> findAllProtoFields(
|
||||||
|
const google::protobuf::Message* message)
|
||||||
{
|
{
|
||||||
std::vector<ProtoField> allFields;
|
std::vector<ProtoField> allFields;
|
||||||
|
|
||||||
std::function<void(google::protobuf::Message*, const std::string&)>
|
std::function<void(const google::protobuf::Message*, const std::string&)>
|
||||||
recurse = [&](auto* message, const auto& name)
|
recurse = [&](const auto* message, const auto& name)
|
||||||
{
|
{
|
||||||
const auto* reflection = message->GetReflection();
|
const auto* reflection = message->GetReflection();
|
||||||
std::vector<const google::protobuf::FieldDescriptor*> fields;
|
std::vector<const google::protobuf::FieldDescriptor*> fields;
|
||||||
@@ -565,18 +566,19 @@ std::vector<ProtoField> findAllProtoFields(google::protobuf::Message* message)
|
|||||||
const auto n = fmt::format("{}[{}]", basename, i);
|
const auto n = fmt::format("{}[{}]", basename, i);
|
||||||
if (shouldRecurse(f))
|
if (shouldRecurse(f))
|
||||||
recurse(
|
recurse(
|
||||||
reflection->MutableRepeatedMessage(message, f, i),
|
&reflection->GetRepeatedMessage(*message, f, i), n);
|
||||||
n);
|
|
||||||
else
|
else
|
||||||
allFields.push_back(ProtoField(n, message, f, i));
|
allFields.push_back(ProtoField(
|
||||||
|
n, (google::protobuf::Message*)message, f, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (shouldRecurse(f))
|
if (shouldRecurse(f))
|
||||||
recurse(reflection->MutableMessage(message, f), basename);
|
recurse(&reflection->GetMessage(*message, f), basename);
|
||||||
else
|
else
|
||||||
allFields.push_back(ProtoField(basename, message, f));
|
allFields.push_back(ProtoField(
|
||||||
|
basename, (google::protobuf::Message*)message, f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -584,3 +586,12 @@ std::vector<ProtoField> findAllProtoFields(google::protobuf::Message* message)
|
|||||||
recurse(message, "");
|
recurse(message, "");
|
||||||
return allFields;
|
return allFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string renderProtoAsConfig(const google::protobuf::Message* message)
|
||||||
|
{
|
||||||
|
auto allFields = findAllProtoFields(message);
|
||||||
|
std::stringstream ss;
|
||||||
|
for (const auto& field : allFields)
|
||||||
|
ss << field.path() << "=" << field.get() << "\n";
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ extern std::map<std::string, const google::protobuf::FieldDescriptor*>
|
|||||||
findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor);
|
findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor);
|
||||||
|
|
||||||
extern std::vector<ProtoField> findAllProtoFields(
|
extern std::vector<ProtoField> findAllProtoFields(
|
||||||
google::protobuf::Message* message);
|
const google::protobuf::Message* message);
|
||||||
|
extern std::string renderProtoAsConfig(
|
||||||
|
const google::protobuf::Message* message);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static inline const T parseProtoBytes(const std::string_view& bytes)
|
static inline const T parseProtoBytes(const std::string_view& bytes)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "lib/core/bytes.h"
|
#include "lib/core/bytes.h"
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
class RawBits;
|
class RawBits;
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ std::unique_ptr<FluxSource> FluxSource::create(Config& config)
|
|||||||
{
|
{
|
||||||
if (!config.hasFluxSource())
|
if (!config.hasFluxSource())
|
||||||
error("no flux source configured");
|
error("no flux source configured");
|
||||||
auto fluxSource = create(config->flux_source());
|
return create(config->flux_source());
|
||||||
globalConfig().base()->MergeFrom(fluxSource->getExtraConfig());
|
|
||||||
return fluxSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)
|
std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_extraConfig.mutable_layout()->add_layoutdata()->set_sector_size(524);
|
||||||
|
|
||||||
image->setGeometry({.numCylinders = numCylinders,
|
image->setGeometry({.numCylinders = numCylinders,
|
||||||
.numHeads = numHeads,
|
.numHeads = numHeads,
|
||||||
.numSectors = 12,
|
.numSectors = 12,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ int mainWrite(int argc, const char* argv[])
|
|||||||
|
|
||||||
auto reader = ImageReader::create(globalConfig());
|
auto reader = ImageReader::create(globalConfig());
|
||||||
std::shared_ptr<Image> image = reader->readImage();
|
std::shared_ptr<Image> image = reader->readImage();
|
||||||
|
globalConfig().overrides()->MergeFrom(reader->getExtraConfig());
|
||||||
|
|
||||||
auto diskLayout = createDiskLayout();
|
auto diskLayout = createDiskLayout();
|
||||||
auto encoder = Arch::createEncoder(globalConfig());
|
auto encoder = Arch::createEncoder(globalConfig());
|
||||||
|
|||||||
@@ -416,16 +416,17 @@ plugin(
|
|||||||
srcs=sources_from(
|
srcs=sources_from(
|
||||||
"dep/imhex/plugins/builtin/source",
|
"dep/imhex/plugins/builtin/source",
|
||||||
except_for=[
|
except_for=[
|
||||||
"dep/imhex/plugins/builtin/source/content/views/view_achievements.cpp",
|
|
||||||
"dep/imhex/plugins/builtin/source/content/achievements.cpp",
|
"dep/imhex/plugins/builtin/source/content/achievements.cpp",
|
||||||
|
"dep/imhex/plugins/builtin/source/content/data_processor_nodes.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/main_menu_items.cpp",
|
"dep/imhex/plugins/builtin/source/content/main_menu_items.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/welcome_screen.cpp",
|
|
||||||
"dep/imhex/plugins/builtin/source/content/out_of_box_experience.cpp",
|
"dep/imhex/plugins/builtin/source/content/out_of_box_experience.cpp",
|
||||||
|
"dep/imhex/plugins/builtin/source/content/providers.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/ui_items.cpp",
|
"dep/imhex/plugins/builtin/source/content/ui_items.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/views.cpp",
|
"dep/imhex/plugins/builtin/source/content/views.cpp",
|
||||||
|
"dep/imhex/plugins/builtin/source/content/views/view_achievements.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/views/view_data_processor.cpp",
|
"dep/imhex/plugins/builtin/source/content/views/view_data_processor.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/views/view_tutorials.cpp",
|
"dep/imhex/plugins/builtin/source/content/views/view_tutorials.cpp",
|
||||||
"dep/imhex/plugins/builtin/source/content/data_processor_nodes.cpp",
|
"dep/imhex/plugins/builtin/source/content/welcome_screen.cpp",
|
||||||
]
|
]
|
||||||
+ glob(
|
+ glob(
|
||||||
"dep/imhex/plugins/builtin/source/content/data_processor_nodes/*"
|
"dep/imhex/plugins/builtin/source/content/data_processor_nodes/*"
|
||||||
@@ -433,11 +434,12 @@ plugin(
|
|||||||
+ glob("dep/imhex/plugins/builtin/source/content/tutorials/*"),
|
+ glob("dep/imhex/plugins/builtin/source/content/tutorials/*"),
|
||||||
)
|
)
|
||||||
+ [
|
+ [
|
||||||
"./imhex_overrides/welcome.cc",
|
"./imhex_overrides/main_menu_items.cpp",
|
||||||
|
"./imhex_overrides/providers.cpp",
|
||||||
"./imhex_overrides/stubs.cc",
|
"./imhex_overrides/stubs.cc",
|
||||||
"./imhex_overrides/ui_items.cc",
|
"./imhex_overrides/ui_items.cc",
|
||||||
"./imhex_overrides/views.cpp",
|
"./imhex_overrides/views.cpp",
|
||||||
"./imhex_overrides/main_menu_items.cpp",
|
"./imhex_overrides/welcome.cc",
|
||||||
],
|
],
|
||||||
hdrs=headers_from("dep/imhex/plugins/builtin/include"),
|
hdrs=headers_from("dep/imhex/plugins/builtin/include"),
|
||||||
romfsdir="dep/imhex/plugins/builtin/romfs",
|
romfsdir="dep/imhex/plugins/builtin/romfs",
|
||||||
@@ -508,6 +510,8 @@ plugin(
|
|||||||
"./controlpanelview.h",
|
"./controlpanelview.h",
|
||||||
"./datastore.cc",
|
"./datastore.cc",
|
||||||
"./datastore.h",
|
"./datastore.h",
|
||||||
|
"./exerciserview.cc",
|
||||||
|
"./exerciserview.h",
|
||||||
"./diskprovider.cc",
|
"./diskprovider.cc",
|
||||||
"./diskprovider.h",
|
"./diskprovider.h",
|
||||||
"./fluxengine.cc",
|
"./fluxengine.cc",
|
||||||
|
|||||||
@@ -18,9 +18,25 @@ using namespace hex;
|
|||||||
|
|
||||||
static DynamicSettingFactory settings("fluxengine.settings");
|
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():
|
ConfigView::ConfigView():
|
||||||
View::Window("fluxengine.view.config.name", ICON_VS_COMPASS)
|
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,
|
static void emitOptions(DynamicSetting<std::string>& setting,
|
||||||
@@ -336,11 +352,33 @@ void ConfigView::drawContent()
|
|||||||
|
|
||||||
ImGui::SeparatorText("fluxengine.view.config.customProperties"_lang);
|
ImGui::SeparatorText("fluxengine.view.config.customProperties"_lang);
|
||||||
|
|
||||||
auto customSetting = settings.get<std::string>("custom");
|
if (ImGui::BeginTabBar("customconfig", ImGuiTabBarFlags_None))
|
||||||
std::string buffer = customSetting;
|
{
|
||||||
if (ImGui::InputTextMultiline("##customProperties",
|
DEFER(ImGui::EndTabBar());
|
||||||
buffer,
|
if (ImGui::BeginTabItem("User"))
|
||||||
ImGui::GetContentRegionAvail(),
|
{
|
||||||
ImGuiInputTextFlags_None))
|
DEFER(ImGui::EndTabItem());
|
||||||
customSetting = buffer;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/core/utils.h"
|
#include "lib/core/utils.h"
|
||||||
#include "lib/config/config.h"
|
#include "lib/config/config.h"
|
||||||
|
#include "lib/config/proto.h"
|
||||||
#include "lib/data/disk.h"
|
#include "lib/data/disk.h"
|
||||||
#include "lib/data/image.h"
|
#include "lib/data/image.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
|
|
||||||
using hex::operator""_lang;
|
using hex::operator""_lang;
|
||||||
|
|
||||||
static std::shared_ptr<const Disk> disk;
|
static std::shared_ptr<const Disk> disk = std::make_shared<Disk>();
|
||||||
static std::shared_ptr<Image> wtImage;
|
static std::shared_ptr<Image> wtImage;
|
||||||
|
|
||||||
static std::deque<std::function<void()>> pendingTasks;
|
static std::deque<std::function<void()>> pendingTasks;
|
||||||
@@ -50,7 +51,7 @@ static bool formattingSupported;
|
|||||||
static std::map<std::string, Datastore::Device> devices;
|
static std::map<std::string, Datastore::Device> devices;
|
||||||
static std::shared_ptr<const DiskLayout> diskLayout;
|
static std::shared_ptr<const DiskLayout> diskLayout;
|
||||||
|
|
||||||
static void wtRebuildConfiguration();
|
static void wtRebuildConfiguration(bool useCustom);
|
||||||
|
|
||||||
static void workerThread_cb()
|
static void workerThread_cb()
|
||||||
{
|
{
|
||||||
@@ -271,7 +272,11 @@ void Datastore::init()
|
|||||||
hex::Region{startOffset, endOffset - startOffset});
|
hex::Region{startOffset, endOffset - startOffset});
|
||||||
});
|
});
|
||||||
|
|
||||||
runOnWorkerThread(wtRebuildConfiguration);
|
runOnWorkerThread(
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
wtRebuildConfiguration(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Datastore::isBusy()
|
bool Datastore::isBusy()
|
||||||
@@ -338,7 +343,7 @@ static void wtClearDiskData()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void wtRebuildConfiguration()
|
void wtRebuildConfiguration(bool withCustom = false)
|
||||||
{
|
{
|
||||||
/* Reset and apply the format configuration. */
|
/* Reset and apply the format configuration. */
|
||||||
|
|
||||||
@@ -392,26 +397,10 @@ void wtRebuildConfiguration()
|
|||||||
|
|
||||||
/* Custom settings. */
|
/* Custom settings. */
|
||||||
|
|
||||||
auto customSettings = readSettingFromUiThread<std::string>("custom", "");
|
globalConfig().applyOptionsFile(
|
||||||
if (!customSettings.empty())
|
readSettingFromUiThread<std::string>("systemProperties", ""));
|
||||||
{
|
globalConfig().applyOptionsFile(
|
||||||
for (auto setting : split(customSettings, '\n'))
|
readSettingFromUiThread<std::string>("custom", ""));
|
||||||
{
|
|
||||||
setting = trimWhitespace(setting);
|
|
||||||
if (setting.size() == 0)
|
|
||||||
continue;
|
|
||||||
if (setting[0] == '#')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto equals = setting.find('=');
|
|
||||||
if (equals == std::string::npos)
|
|
||||||
error("Malformed setting line '{}'", setting);
|
|
||||||
|
|
||||||
auto key = setting.substr(0, equals);
|
|
||||||
auto value = setting.substr(equals + 1);
|
|
||||||
globalConfig().set(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finalise the options. */
|
/* Finalise the options. */
|
||||||
|
|
||||||
@@ -540,7 +529,7 @@ void Datastore::beginRead(bool rereadBadSectors)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(true);
|
||||||
if (!rereadBadSectors)
|
if (!rereadBadSectors)
|
||||||
wtClearDiskData();
|
wtClearDiskData();
|
||||||
|
|
||||||
@@ -576,7 +565,7 @@ void Datastore::beginWrite()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(true);
|
||||||
wtWaitForUiThreadToCatchUp();
|
wtWaitForUiThreadToCatchUp();
|
||||||
|
|
||||||
auto fluxSinkFactory = FluxSinkFactory::create(globalConfig());
|
auto fluxSinkFactory = FluxSinkFactory::create(globalConfig());
|
||||||
@@ -642,7 +631,7 @@ void Datastore::reset()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(false);
|
||||||
wtClearDiskData();
|
wtClearDiskData();
|
||||||
wtWaitForUiThreadToCatchUp();
|
wtWaitForUiThreadToCatchUp();
|
||||||
}
|
}
|
||||||
@@ -682,7 +671,7 @@ void Datastore::writeImage(const std::fs::path& path)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(true);
|
||||||
wtWaitForUiThreadToCatchUp();
|
wtWaitForUiThreadToCatchUp();
|
||||||
globalConfig().setImageWriter(path.string());
|
globalConfig().setImageWriter(path.string());
|
||||||
ImageWriter::create(globalConfig())
|
ImageWriter::create(globalConfig())
|
||||||
@@ -708,11 +697,23 @@ void Datastore::readImage(const std::fs::path& path)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(true);
|
||||||
wtWaitForUiThreadToCatchUp();
|
wtWaitForUiThreadToCatchUp();
|
||||||
globalConfig().setImageReader(path.string());
|
globalConfig().setImageReader(path.string());
|
||||||
std::shared_ptr<Image> image =
|
auto imageReader = ImageReader::create(globalConfig());
|
||||||
ImageReader::create(globalConfig())->readImage();
|
std::shared_ptr<Image> image = imageReader->readImage();
|
||||||
|
|
||||||
|
const auto& extraConfig = imageReader->getExtraConfig();
|
||||||
|
auto customConfig = renderProtoAsConfig(&extraConfig);
|
||||||
|
|
||||||
|
/* Update the setting, and then rebuild the config again as it
|
||||||
|
* will have changed. */
|
||||||
|
|
||||||
|
wtRunSynchronouslyOnUiThread((std::function<void()>)[=] {
|
||||||
|
Events::SetSystemConfig::post(customConfig);
|
||||||
|
});
|
||||||
|
wtRebuildConfiguration(true);
|
||||||
|
wtWaitForUiThreadToCatchUp();
|
||||||
|
|
||||||
auto disk = wtMakeDiskDataFromImage(image);
|
auto disk = wtMakeDiskDataFromImage(image);
|
||||||
hex::TaskManager::doLater(
|
hex::TaskManager::doLater(
|
||||||
@@ -741,7 +742,7 @@ void Datastore::writeFluxFile(const std::fs::path& path)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(true);
|
||||||
wtWaitForUiThreadToCatchUp();
|
wtWaitForUiThreadToCatchUp();
|
||||||
|
|
||||||
if (!disk || !disk->image)
|
if (!disk || !disk->image)
|
||||||
@@ -777,7 +778,7 @@ void Datastore::createBlankImage()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wtRebuildConfiguration();
|
wtRebuildConfiguration(false);
|
||||||
wtClearDiskData();
|
wtClearDiskData();
|
||||||
wtWaitForUiThreadToCatchUp();
|
wtWaitForUiThreadToCatchUp();
|
||||||
|
|
||||||
@@ -794,6 +795,7 @@ void Datastore::createBlankImage()
|
|||||||
hex::TaskManager::doLater(
|
hex::TaskManager::doLater(
|
||||||
[=]
|
[=]
|
||||||
{
|
{
|
||||||
|
Events::SetSystemConfig::post("");
|
||||||
::disk = disk;
|
::disk = disk;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/gui2/exerciserview.cc
Normal file
70
src/gui2/exerciserview.cc
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#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 "exerciserview.h"
|
||||||
|
#include "datastore.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <implot.h>
|
||||||
|
#include <implot_internal.h>
|
||||||
|
|
||||||
|
using namespace hex;
|
||||||
|
|
||||||
|
ExerciserView::ExerciserView():
|
||||||
|
View::Modal("fluxengine.view.exerciser.name", ICON_VS_DEBUG)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExerciserView::drawContent()
|
||||||
|
{
|
||||||
|
static int selectedDrive = 0;
|
||||||
|
static int selectedTrack = 0;
|
||||||
|
|
||||||
|
const float label_width = ImGui::GetFontSize() * 6;
|
||||||
|
ImGui::PushItemWidth(-label_width);
|
||||||
|
DEFER(ImGui::PopItemWidth());
|
||||||
|
|
||||||
|
ImGui::SliderInt("fluxengine.view.exerciser.drive"_lang,
|
||||||
|
&selectedDrive,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
"%d",
|
||||||
|
ImGuiSliderFlags_None);
|
||||||
|
ImGui::SliderInt("fluxengine.view.exerciser.cylinder"_lang,
|
||||||
|
&selectedTrack,
|
||||||
|
0,
|
||||||
|
82,
|
||||||
|
"%d",
|
||||||
|
ImGuiSliderFlags_None);
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("nudgeTable",
|
||||||
|
3,
|
||||||
|
ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_SizingStretchProp,
|
||||||
|
{ImGui::GetContentRegionAvail().x - label_width, 0}))
|
||||||
|
{
|
||||||
|
DEFER(ImGui::EndTable());
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::Button("fluxengine.view.exerciser.nudgeDown"_lang,
|
||||||
|
{ImGui::GetContentRegionAvail().x, 0}))
|
||||||
|
selectedTrack--;
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::Button("fluxengine.view.exerciser.reset"_lang,
|
||||||
|
{ImGui::GetContentRegionAvail().x, 0}))
|
||||||
|
selectedTrack = 0;
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::Button("fluxengine.view.exerciser.nudgeUp"_lang,
|
||||||
|
{ImGui::GetContentRegionAvail().x, 0}))
|
||||||
|
selectedTrack++;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTrack = std::clamp(selectedTrack, 0, 82);
|
||||||
|
}
|
||||||
22
src/gui2/exerciserview.h
Normal file
22
src/gui2/exerciserview.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
|
class ExerciserView : public hex::View::Modal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExerciserView();
|
||||||
|
~ExerciserView() override = default;
|
||||||
|
|
||||||
|
void drawContent() override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool shouldDraw() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool hasViewMenuItemEntry() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
#include <hex/plugin.hpp>
|
#include <hex/plugin.hpp>
|
||||||
#include <hex/api/content_registry/views.hpp>
|
#include <hex/api/content_registry/views.hpp>
|
||||||
|
#include <hex/api/content_registry/user_interface.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/api/content_registry/provider.hpp>
|
#include <hex/api/content_registry/provider.hpp>
|
||||||
|
#include <hex/api/workspace_manager.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <fonts/vscode_icons.hpp>
|
||||||
|
#include <fonts/tabler_icons.hpp>
|
||||||
#include <romfs/romfs.hpp>
|
#include <romfs/romfs.hpp>
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "imageview.h"
|
#include "imageview.h"
|
||||||
@@ -11,6 +17,7 @@
|
|||||||
#include "controlpanelview.h"
|
#include "controlpanelview.h"
|
||||||
#include "logview.h"
|
#include "logview.h"
|
||||||
#include "visualiserview.h"
|
#include "visualiserview.h"
|
||||||
|
#include "exerciserview.h"
|
||||||
#include "diskprovider.h"
|
#include "diskprovider.h"
|
||||||
#include "datastore.h"
|
#include "datastore.h"
|
||||||
|
|
||||||
@@ -24,6 +31,150 @@ IMHEX_PLUGIN_SETUP("FluxEngine", "David Given", "FluxEngine integration")
|
|||||||
return romfs::get(path).string();
|
return romfs::get(path).string();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"hex.builtin.menu.workspace", "fluxengine.menu.workspace.reset"},
|
||||||
|
ICON_TA_CANCEL,
|
||||||
|
10000,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
static const std::string extractFolder = "auto_extract/workspaces";
|
||||||
|
for (const auto& romfsPath : romfs::list(extractFolder))
|
||||||
|
{
|
||||||
|
for (const auto& imhexPath : hex::paths::getDataPaths(false))
|
||||||
|
{
|
||||||
|
const auto path =
|
||||||
|
imhexPath / std::fs::relative(romfsPath, extractFolder);
|
||||||
|
hex::log::info("Extracting {} to {}",
|
||||||
|
romfsPath.string(),
|
||||||
|
path.string());
|
||||||
|
|
||||||
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
|
if (!file.isValid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto data = romfs::get(romfsPath).span<u8>();
|
||||||
|
file.writeBuffer(data.data(), data.size());
|
||||||
|
|
||||||
|
if (file.getSize() == data.size())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto currentWorkspaceName =
|
||||||
|
hex::WorkspaceManager::getCurrentWorkspace()->first;
|
||||||
|
hex::WorkspaceManager::reload();
|
||||||
|
hex::WorkspaceManager::switchWorkspace(currentWorkspaceName);
|
||||||
|
});
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::registerMainMenuItem(
|
||||||
|
"fluxengine.menu.name", 4999);
|
||||||
|
|
||||||
|
auto isReady = []
|
||||||
|
{
|
||||||
|
return !Datastore::isBusy();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto isReadyAndHasImage = []
|
||||||
|
{
|
||||||
|
return !Datastore::isBusy() && Datastore::getDisk()->image;
|
||||||
|
};
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.readDevice"},
|
||||||
|
ICON_TA_DEVICE_FLOPPY,
|
||||||
|
1000,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
Datastore::beginRead(false);
|
||||||
|
},
|
||||||
|
isReady);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.rereadBad"},
|
||||||
|
ICON_TA_REPEAT,
|
||||||
|
1100,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
Datastore::beginRead(true);
|
||||||
|
},
|
||||||
|
isReadyAndHasImage);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.readImage"},
|
||||||
|
ICON_VS_FOLDER_OPENED,
|
||||||
|
1200,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
hex::fs::openFileBrowser(
|
||||||
|
hex::fs::DialogMode::Open, {}, Datastore::readImage);
|
||||||
|
},
|
||||||
|
isReady);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.createBlank"},
|
||||||
|
ICON_VS_FOLDER_OPENED,
|
||||||
|
1250,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
Datastore::createBlankImage,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
return !Datastore::isBusy() && Datastore::canFormat();
|
||||||
|
});
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItemSeparator(
|
||||||
|
{"fluxengine.menu.name"}, 1300);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.writeDevice"},
|
||||||
|
ICON_TA_DEVICE_FLOPPY,
|
||||||
|
1400,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
Datastore::beginWrite,
|
||||||
|
isReadyAndHasImage);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.writeFlux"},
|
||||||
|
ICON_TA_DOWNLOAD,
|
||||||
|
1500,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
hex::fs::openFileBrowser(
|
||||||
|
hex::fs::DialogMode::Save, {}, Datastore::writeFluxFile);
|
||||||
|
},
|
||||||
|
isReady);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.view.controlpanel.writeImage"},
|
||||||
|
ICON_VS_SAVE_ALL,
|
||||||
|
1600,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
hex::fs::openFileBrowser(
|
||||||
|
hex::fs::DialogMode::Save, {}, Datastore::writeImage);
|
||||||
|
},
|
||||||
|
isReadyAndHasImage);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItemSeparator(
|
||||||
|
{"fluxengine.menu.name"}, 9999);
|
||||||
|
|
||||||
|
hex::ContentRegistry::UserInterface::addMenuItem(
|
||||||
|
{"fluxengine.menu.name", "fluxengine.menu.disk.exerciser"},
|
||||||
|
ICON_TA_TOOLS,
|
||||||
|
10000,
|
||||||
|
hex::Shortcut::None,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
hex::ContentRegistry::Views::getViewByName(
|
||||||
|
"fluxengine.view.exerciser.name")
|
||||||
|
->getWindowOpenState() = true;
|
||||||
|
});
|
||||||
|
|
||||||
hex::ContentRegistry::Provider::add<DiskProvider>();
|
hex::ContentRegistry::Provider::add<DiskProvider>();
|
||||||
|
|
||||||
hex::ContentRegistry::Views::add<ConfigView>();
|
hex::ContentRegistry::Views::add<ConfigView>();
|
||||||
@@ -33,6 +184,7 @@ IMHEX_PLUGIN_SETUP("FluxEngine", "David Given", "FluxEngine integration")
|
|||||||
hex::ContentRegistry::Views::add<PhysicalView>();
|
hex::ContentRegistry::Views::add<PhysicalView>();
|
||||||
hex::ContentRegistry::Views::add<SummaryView>();
|
hex::ContentRegistry::Views::add<SummaryView>();
|
||||||
hex::ContentRegistry::Views::add<VisualiserView>();
|
hex::ContentRegistry::Views::add<VisualiserView>();
|
||||||
|
hex::ContentRegistry::Views::add<ExerciserView>();
|
||||||
|
|
||||||
Datastore::init();
|
Datastore::init();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace Events
|
|||||||
EVENT_DEF(DiskActivityNotification, DiskActivityType, unsigned, unsigned);
|
EVENT_DEF(DiskActivityNotification, DiskActivityType, unsigned, unsigned);
|
||||||
EVENT_DEF(OperationStart, std::string);
|
EVENT_DEF(OperationStart, std::string);
|
||||||
EVENT_DEF(OperationStop, OperationState);
|
EVENT_DEF(OperationStop, OperationState);
|
||||||
|
EVENT_DEF(SetSystemConfig, std::string);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFER(_stmt) \
|
#define DEFER(_stmt) \
|
||||||
|
|||||||
136
src/gui2/imhex_overrides/providers.cpp
Normal file
136
src/gui2/imhex_overrides/providers.cpp
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#include <hex/api/content_registry/provider.hpp>
|
||||||
|
|
||||||
|
#include "content/providers/gdb_provider.hpp"
|
||||||
|
#include "content/providers/file_provider.hpp"
|
||||||
|
#include "content/providers/null_provider.hpp"
|
||||||
|
#include "content/providers/disk_provider.hpp"
|
||||||
|
#include "content/providers/intel_hex_provider.hpp"
|
||||||
|
#include "content/providers/motorola_srec_provider.hpp"
|
||||||
|
#include "content/providers/memory_file_provider.hpp"
|
||||||
|
#include "content/providers/view_provider.hpp"
|
||||||
|
#include <content/providers/process_memory_provider.hpp>
|
||||||
|
#include <content/providers/base64_provider.hpp>
|
||||||
|
#include <content/providers/udp_provider.hpp>
|
||||||
|
#include <popups/popup_notification.hpp>
|
||||||
|
|
||||||
|
#include <hex/api/project_file_manager.hpp>
|
||||||
|
#include <hex/api/task_manager.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <toasts/toast_notification.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
|
void registerProviders() {
|
||||||
|
|
||||||
|
ContentRegistry::Provider::add<FileProvider>(false);
|
||||||
|
ContentRegistry::Provider::add<NullProvider>(false);
|
||||||
|
ContentRegistry::Provider::add<MemoryFileProvider>(false);
|
||||||
|
ContentRegistry::Provider::add<ViewProvider>(false);
|
||||||
|
|
||||||
|
ProjectFile::registerHandler({
|
||||||
|
.basePath = "providers",
|
||||||
|
.required = true,
|
||||||
|
.load = [](const std::fs::path &basePath, const Tar &tar) {
|
||||||
|
auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json"));
|
||||||
|
auto providerIds = json.at("providers").get<std::vector<int>>();
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
std::map<hex::prv::Provider*, std::string> providerWarnings;
|
||||||
|
for (const auto &id : providerIds) {
|
||||||
|
auto providerSettings = nlohmann::json::parse(tar.readString(basePath / fmt::format("{}.json", id)));
|
||||||
|
|
||||||
|
auto providerType = providerSettings.at("type").get<std::string>();
|
||||||
|
auto newProvider = ImHexApi::Provider::createProvider(providerType, true, false);
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
if (!success) {
|
||||||
|
for (auto &task : TaskManager::getRunningTasks())
|
||||||
|
task->interrupt();
|
||||||
|
|
||||||
|
TaskManager::runWhenTasksFinished([]{
|
||||||
|
for (const auto &provider : ImHexApi::Provider::getProviders())
|
||||||
|
ImHexApi::Provider::remove(provider, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (newProvider == nullptr) {
|
||||||
|
// If a provider is not created, it will be overwritten when saving the project,
|
||||||
|
// so we should prevent the project from loading at all
|
||||||
|
ui::ToastError::open(
|
||||||
|
fmt::format("hex.builtin.popup.error.project.load"_lang,
|
||||||
|
fmt::format("hex.builtin.popup.error.project.load.create_provider"_lang, providerType)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
newProvider->setID(id);
|
||||||
|
bool loaded = false;
|
||||||
|
try {
|
||||||
|
newProvider->loadSettings(providerSettings.at("settings"));
|
||||||
|
loaded = true;
|
||||||
|
} catch (const std::exception &e){
|
||||||
|
providerWarnings[newProvider] = e.what();
|
||||||
|
}
|
||||||
|
if (loaded) {
|
||||||
|
if (!newProvider->open() || !newProvider->isAvailable() || !newProvider->isReadable()) {
|
||||||
|
providerWarnings[newProvider] = newProvider->getErrorMessage();
|
||||||
|
} else {
|
||||||
|
EventProviderOpened::post(newProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string warningMessage;
|
||||||
|
for (const auto &warning : providerWarnings){
|
||||||
|
ImHexApi::Provider::remove(warning.first);
|
||||||
|
warningMessage.append(
|
||||||
|
fmt::format("\n - {} : {}", warning.first->getName(), warning.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no providers were opened, display an error with
|
||||||
|
// the warnings that happened when opening them
|
||||||
|
if (ImHexApi::Provider::getProviders().empty()) {
|
||||||
|
ui::ToastError::open(fmt::format("{}{}", "hex.builtin.popup.error.project.load"_lang, "hex.builtin.popup.error.project.load.no_providers"_lang, warningMessage));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Else, if there are warnings, still display them
|
||||||
|
if (warningMessage.empty()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
ui::ToastWarning::open(fmt::format("hex.builtin.popup.error.project.load.some_providers_failed"_lang, warningMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.store = [](const std::fs::path &basePath, const Tar &tar) {
|
||||||
|
std::vector<int> providerIds;
|
||||||
|
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||||
|
auto id = provider->getID();
|
||||||
|
providerIds.push_back(id);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
json["type"] = provider->getTypeName();
|
||||||
|
json["settings"] = provider->storeSettings({});
|
||||||
|
|
||||||
|
tar.writeString(basePath / fmt::format("{}.json", id), json.dump(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
tar.writeString(basePath / "providers.json",
|
||||||
|
nlohmann::json({ { "providers", providerIds } }).dump(4)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -33,13 +33,13 @@
|
|||||||
"fluxengine.view.physical.name": "FluxEngine physical sector map",
|
"fluxengine.view.physical.name": "FluxEngine physical sector map",
|
||||||
|
|
||||||
"fluxengine.view.controlpanel.name": "FluxEngine controls",
|
"fluxengine.view.controlpanel.name": "FluxEngine controls",
|
||||||
"fluxengine.view.controlpanel.readDevice": "Read",
|
"fluxengine.view.controlpanel.readDevice": "Read from device",
|
||||||
"fluxengine.view.controlpanel.writeDevice": "Write",
|
"fluxengine.view.controlpanel.writeDevice": "Write to device",
|
||||||
"fluxengine.view.controlpanel.writeFlux": "Write flux file",
|
"fluxengine.view.controlpanel.writeFlux": "Write flux file",
|
||||||
"fluxengine.view.controlpanel.readImage": "Load disk image",
|
"fluxengine.view.controlpanel.readImage": "Load disk image",
|
||||||
"fluxengine.view.controlpanel.writeImage": "Save disk image",
|
"fluxengine.view.controlpanel.writeImage": "Save disk image",
|
||||||
"fluxengine.view.controlpanel.rereadBad": "Re-read bad tracks",
|
"fluxengine.view.controlpanel.rereadBad": "Re-read bad tracks",
|
||||||
"fluxengine.view.controlpanel.createBlank": "Empty filesystem",
|
"fluxengine.view.controlpanel.createBlank": "Make empty image",
|
||||||
"fluxengine.view.controlpanel.stop": "Stop",
|
"fluxengine.view.controlpanel.stop": "Stop",
|
||||||
|
|
||||||
"fluxengine.view.log.name": "FluxEngine log viewer",
|
"fluxengine.view.log.name": "FluxEngine log viewer",
|
||||||
@@ -47,6 +47,13 @@
|
|||||||
"fluxengine.view.visualiser.name": "FluxEngine disk visualiser",
|
"fluxengine.view.visualiser.name": "FluxEngine disk visualiser",
|
||||||
"fluxengine.view.visualiser.missingData": "Partial visualisation",
|
"fluxengine.view.visualiser.missingData": "Partial visualisation",
|
||||||
|
|
||||||
|
"fluxengine.view.exerciser.name": "FluxEngine disk exerciser",
|
||||||
|
"fluxengine.view.exerciser.drive": "Drive",
|
||||||
|
"fluxengine.view.exerciser.cylinder": "Cylinder",
|
||||||
|
"fluxengine.view.exerciser.nudgeDown": "Nudge down",
|
||||||
|
"fluxengine.view.exerciser.reset": "Reset",
|
||||||
|
"fluxengine.view.exerciser.nudgeUp": "Nudge up",
|
||||||
|
|
||||||
"fluxengine.view.status.runningSuffix": "...",
|
"fluxengine.view.status.runningSuffix": "...",
|
||||||
"fluxengine.view.status.succeededSuffix": "... done",
|
"fluxengine.view.status.succeededSuffix": "... done",
|
||||||
"fluxengine.view.status.failedSuffix": "... failed",
|
"fluxengine.view.status.failedSuffix": "... failed",
|
||||||
@@ -57,5 +64,9 @@
|
|||||||
"fluxengine.view.status.writeImage": "Writing image file to disk",
|
"fluxengine.view.status.writeImage": "Writing image file to disk",
|
||||||
"fluxengine.view.status.blankFilesystem": "Creating blank filesystem",
|
"fluxengine.view.status.blankFilesystem": "Creating blank filesystem",
|
||||||
|
|
||||||
"fluxengine.messages.writingFluxToFile": "The current configuration is to write to a flux file rather than to hardware. Is this what you intended?"
|
"fluxengine.messages.writingFluxToFile": "The current configuration is to write to a flux file rather than to hardware. Is this what you intended?",
|
||||||
|
|
||||||
|
"fluxengine.menu.name": "Disk",
|
||||||
|
"fluxengine.menu.disk.exerciser": "Disk exerciser",
|
||||||
|
"fluxengine.menu.workspace.reset": "Reset workspace"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,6 +226,49 @@ static void test_findallfields(void)
|
|||||||
"u64"}));
|
"u64"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_rendering(void)
|
||||||
|
{
|
||||||
|
std::string s = R"M(
|
||||||
|
i64: -1
|
||||||
|
i32: -2
|
||||||
|
u64: 3
|
||||||
|
u32: 4
|
||||||
|
d: 5.5
|
||||||
|
f: 6.7
|
||||||
|
m {
|
||||||
|
s: "string"
|
||||||
|
}
|
||||||
|
r {
|
||||||
|
s: "val2"
|
||||||
|
}
|
||||||
|
r {
|
||||||
|
s: "val3"
|
||||||
|
}
|
||||||
|
secondoption {
|
||||||
|
s: "2"
|
||||||
|
}
|
||||||
|
)M";
|
||||||
|
|
||||||
|
TestProto proto;
|
||||||
|
if (!google::protobuf::TextFormat::MergeFromString(cleanup(s), &proto))
|
||||||
|
error("couldn't load test proto");
|
||||||
|
|
||||||
|
auto config = renderProtoAsConfig(&proto);
|
||||||
|
|
||||||
|
AssertThat(cleanup(config), Equals(cleanup(R"M(
|
||||||
|
i64=-1
|
||||||
|
i32=-2
|
||||||
|
u64=3
|
||||||
|
u32=4
|
||||||
|
d=5.5
|
||||||
|
m.s=string
|
||||||
|
r[0].s=val2
|
||||||
|
r[1].s=val3
|
||||||
|
secondoption.s=2
|
||||||
|
f=6.7
|
||||||
|
)M")));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[])
|
int main(int argc, const char* argv[])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -237,6 +280,7 @@ int main(int argc, const char* argv[])
|
|||||||
test_fields();
|
test_fields();
|
||||||
test_options();
|
test_options();
|
||||||
test_findallfields();
|
test_findallfields();
|
||||||
|
test_rendering();
|
||||||
}
|
}
|
||||||
catch (const ErrorException& e)
|
catch (const ErrorException& e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user