mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Wire up some more control panel buttons. Create an in-memory sector
interface for doing filesystem stuff.
This commit is contained in:
@@ -85,6 +85,22 @@ std::vector<CylinderHead> Layout::computePhysicalLocations()
|
||||
return locations;
|
||||
}
|
||||
|
||||
std::vector<CylinderHead> Layout::computeLogicalLocations()
|
||||
{
|
||||
if (!globalConfig()->tracks().empty())
|
||||
return parseCylinderHeadsString(globalConfig()->tracks());
|
||||
|
||||
std::set<unsigned> tracks = iterate(0, globalConfig()->layout().tracks());
|
||||
std::set<unsigned> heads = iterate(0, globalConfig()->layout().sides());
|
||||
|
||||
std::vector<CylinderHead> locations;
|
||||
for (unsigned logicalCylinder : tracks)
|
||||
for (unsigned logicalHead : heads)
|
||||
locations.push_back(CylinderHead{logicalCylinder, logicalHead});
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
Layout::LayoutBounds Layout::getBounds(
|
||||
const std::vector<CylinderHead>& locations)
|
||||
{
|
||||
@@ -105,7 +121,9 @@ Layout::LayoutBounds Layout::getBounds(
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> Layout::getTrackOrdering(
|
||||
LayoutProto::Order ordering, unsigned guessedCylinders, unsigned guessedHeads)
|
||||
LayoutProto::Order ordering,
|
||||
unsigned guessedCylinders,
|
||||
unsigned guessedHeads)
|
||||
{
|
||||
auto layout = globalConfig()->layout();
|
||||
int tracks = layout.has_tracks() ? layout.tracks() : guessedCylinders;
|
||||
@@ -206,7 +224,8 @@ std::shared_ptr<const TrackInfo> Layout::getLayoutOfTrack(
|
||||
for (const auto& f : globalConfig()->layout().layoutdata())
|
||||
{
|
||||
if (f.has_track() && f.has_up_to_track() &&
|
||||
((logicalCylinder < f.track()) || (logicalCylinder > f.up_to_track())))
|
||||
((logicalCylinder < f.track()) ||
|
||||
(logicalCylinder > f.up_to_track())))
|
||||
continue;
|
||||
if (f.has_track() && !f.has_up_to_track() &&
|
||||
(logicalCylinder != f.track()))
|
||||
@@ -222,7 +241,8 @@ std::shared_ptr<const TrackInfo> Layout::getLayoutOfTrack(
|
||||
trackInfo->sectorSize = layoutdata.sector_size();
|
||||
trackInfo->logicalCylinder = logicalCylinder;
|
||||
trackInfo->logicalHead = logicalHead;
|
||||
trackInfo->physicalCylinder = remapCylinderLogicalToPhysical(logicalCylinder);
|
||||
trackInfo->physicalCylinder =
|
||||
remapCylinderLogicalToPhysical(logicalCylinder);
|
||||
trackInfo->physicalHead =
|
||||
logicalHead ^ globalConfig()->layout().swap_sides();
|
||||
trackInfo->groupSize = getTrackStep();
|
||||
@@ -290,7 +310,8 @@ int Layout::getHeadWidth()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<LogicalLocation> Layout::computeFilesystemLogicalOrdering(){
|
||||
std::vector<LogicalLocation> Layout::computeFilesystemLogicalOrdering()
|
||||
{
|
||||
std::vector<LogicalLocation> result;
|
||||
auto& layout = globalConfig()->layout();
|
||||
if (layout.has_tracks() && layout.has_sides())
|
||||
@@ -309,8 +330,7 @@ std::vector<LogicalLocation> Layout::computeFilesystemLogicalOrdering(){
|
||||
continue;
|
||||
|
||||
for (unsigned sectorId : trackLayout->filesystemSectorOrder)
|
||||
result.push_back(
|
||||
{track, side, sectorId});
|
||||
result.push_back({track, side, sectorId});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -25,9 +25,10 @@ public:
|
||||
static unsigned remapHeadLogicalToPhysical(unsigned logicalHead);
|
||||
|
||||
/* Uses the layout and current track and heads settings to determine
|
||||
* which physical tracks are going to be read from or written to.
|
||||
* which physical/logical tracks are going to be read from or written to.
|
||||
*/
|
||||
static std::vector<CylinderHead> computePhysicalLocations();
|
||||
static std::vector<CylinderHead> computeLogicalLocations();
|
||||
|
||||
/* Uses the current layout to compute the filesystem's block order, in
|
||||
* _logical_ tracks. */
|
||||
|
||||
@@ -37,7 +37,11 @@ struct Sector : public LogicalLocation
|
||||
Bytes data;
|
||||
std::vector<std::shared_ptr<Record>> records;
|
||||
|
||||
Sector(std::shared_ptr<const TrackInfo>& layout, const LogicalLocation& location);
|
||||
Sector(const Sector& other) = default;
|
||||
Sector& operator=(const Sector& other) = default;
|
||||
|
||||
Sector(std::shared_ptr<const TrackInfo>& layout,
|
||||
const LogicalLocation& location);
|
||||
|
||||
std::tuple<int, int, int, Status> key() const
|
||||
{
|
||||
@@ -45,19 +49,9 @@ struct Sector : public LogicalLocation
|
||||
logicalCylinder, logicalHead, logicalSector, status);
|
||||
}
|
||||
|
||||
bool operator==(const Sector& rhs) const
|
||||
std::strong_ordering operator<=>(const Sector& rhs) const
|
||||
{
|
||||
return key() == rhs.key();
|
||||
}
|
||||
|
||||
bool operator!=(const Sector& rhs) const
|
||||
{
|
||||
return key() != rhs.key();
|
||||
}
|
||||
|
||||
bool operator<(const Sector& rhs) const
|
||||
{
|
||||
return key() < rhs.key();
|
||||
return key() <=> rhs.key();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ cxxlibrary(
|
||||
"./imagesectorinterface.cc",
|
||||
"./lif.cc",
|
||||
"./machfs.cc",
|
||||
"./memorysectorinterface.cc",
|
||||
"./microdos.cc",
|
||||
"./philefs.cc",
|
||||
"./prodos.cc",
|
||||
|
||||
71
lib/vfs/memorysectorinterface.cc
Normal file
71
lib/vfs/memorysectorinterface.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/vfs/sectorinterface.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "lib/data/layout.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/core/bytes.h"
|
||||
|
||||
class MemorySectorInterface : public SectorInterface
|
||||
{
|
||||
public:
|
||||
MemorySectorInterface(std::shared_ptr<Image> image): _backupImage(image)
|
||||
{
|
||||
discardChanges();
|
||||
}
|
||||
|
||||
public:
|
||||
std::shared_ptr<const Sector> get(
|
||||
unsigned track, unsigned side, unsigned sectorId) override
|
||||
{
|
||||
return _liveImage->get(track, side, sectorId);
|
||||
}
|
||||
|
||||
std::shared_ptr<Sector> put(
|
||||
unsigned track, unsigned side, unsigned sectorId) override
|
||||
{
|
||||
_changed = true;
|
||||
return _liveImage->put(track, side, sectorId);
|
||||
}
|
||||
|
||||
bool isReadOnly() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool needsFlushing() override
|
||||
{
|
||||
return _changed;
|
||||
}
|
||||
|
||||
void flushChanges() override
|
||||
{
|
||||
// _writer->writeImage(*_image);
|
||||
_changed = false;
|
||||
}
|
||||
|
||||
void discardChanges() override
|
||||
{
|
||||
_liveImage = std::make_unique<Image>();
|
||||
for (auto sector : *_backupImage)
|
||||
{
|
||||
auto s = _liveImage->put(sector->logicalCylinder,
|
||||
sector->logicalHead,
|
||||
sector->logicalSector);
|
||||
*s = *sector;
|
||||
}
|
||||
_changed = false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Image> _backupImage;
|
||||
std::shared_ptr<Image> _liveImage;
|
||||
bool _changed = false;
|
||||
};
|
||||
|
||||
std::unique_ptr<SectorInterface> SectorInterface::createMemorySectorInterface(
|
||||
std::shared_ptr<Image> image)
|
||||
{
|
||||
return std::make_unique<MemorySectorInterface>(image);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef SECTORINTERFACE_H
|
||||
#define SECTORINTERFACE_H
|
||||
|
||||
class Image;
|
||||
class ImageReader;
|
||||
class ImageWriter;
|
||||
class Sector;
|
||||
@@ -35,6 +36,8 @@ public:
|
||||
virtual void discardChanges() {}
|
||||
|
||||
public:
|
||||
static std::unique_ptr<SectorInterface> createMemorySectorInterface(
|
||||
std::shared_ptr<Image> image);
|
||||
static std::unique_ptr<SectorInterface> createImageSectorInterface(
|
||||
std::shared_ptr<ImageReader> reader,
|
||||
std::shared_ptr<ImageWriter> writer);
|
||||
|
||||
@@ -332,16 +332,16 @@ plugin(
|
||||
srcs=[
|
||||
"./abstractsectorview.cc",
|
||||
"./abstractsectorview.h",
|
||||
"./imageview.cc",
|
||||
"./imageview.h",
|
||||
"./physicalview.cc",
|
||||
"./physicalview.h",
|
||||
"./datastore.cc",
|
||||
"./datastore.h",
|
||||
"./diskprovider.cc",
|
||||
"./diskprovider.h",
|
||||
"./fluxengine.cc",
|
||||
"./globals.h",
|
||||
"./imageview.cc",
|
||||
"./imageview.h",
|
||||
"./physicalview.cc",
|
||||
"./physicalview.h",
|
||||
"./summaryview.cc",
|
||||
"./summaryview.h",
|
||||
"./utils.cc",
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
#include "lib/data/flux.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/algorithms/readerwriter.h"
|
||||
#include "lib/usb/usbfinder.h"
|
||||
#include "lib/vfs/vfs.h"
|
||||
#include "arch/arch.h"
|
||||
#include "globals.h"
|
||||
#include "datastore.h"
|
||||
@@ -33,6 +35,7 @@ static std::thread workerThread;
|
||||
static std::atomic<bool> busy;
|
||||
|
||||
static bool configurationValid;
|
||||
static bool formattingSupported;
|
||||
static std::map<std::string, Datastore::Device> devices;
|
||||
static std::map<CylinderHead, std::shared_ptr<const TrackInfo>>
|
||||
physicalCylinderLayouts;
|
||||
@@ -197,6 +200,11 @@ bool Datastore::isConfigurationValid()
|
||||
return isConfigurationValid;
|
||||
}
|
||||
|
||||
bool Datastore::canFormat()
|
||||
{
|
||||
return formattingSupported;
|
||||
}
|
||||
|
||||
const std::map<std::string, Datastore::Device>& Datastore::getDevices()
|
||||
{
|
||||
return devices;
|
||||
@@ -319,7 +327,6 @@ void Datastore::rebuildConfiguration()
|
||||
hex::TaskManager::doLaterOnce(
|
||||
[]
|
||||
{
|
||||
hex::log::debug("FluxEngine configuration stale; rebuilding it");
|
||||
configurationValid = false;
|
||||
|
||||
/* Reset and apply the format configuration. */
|
||||
@@ -398,6 +405,30 @@ void Datastore::rebuildConfiguration()
|
||||
/* Update the UI-thread copy of the bits of configuration we
|
||||
* need. */
|
||||
|
||||
formattingSupported = false;
|
||||
Datastore::runOnWorkerThread(
|
||||
[]
|
||||
{
|
||||
bool formattingSupported;
|
||||
try
|
||||
{
|
||||
auto filesystem = Filesystem::createFilesystem(
|
||||
globalConfig()->filesystem(), nullptr);
|
||||
uint32_t flags = filesystem->capabilities();
|
||||
formattingSupported = flags & Filesystem::OP_CREATE;
|
||||
}
|
||||
catch (const ErrorException&)
|
||||
{
|
||||
formattingSupported = false;
|
||||
}
|
||||
|
||||
hex::TaskManager::doLater(
|
||||
[=]
|
||||
{
|
||||
::formattingSupported = formattingSupported;
|
||||
});
|
||||
});
|
||||
|
||||
Datastore::runOnWorkerThread(
|
||||
[]
|
||||
{
|
||||
@@ -539,3 +570,33 @@ void Datastore::writeImage(const std::fs::path& path)
|
||||
->writeImage(*Datastore::getDiskFlux()->image);
|
||||
});
|
||||
}
|
||||
|
||||
void Datastore::writeFluxFile(const std::fs::path& path)
|
||||
{
|
||||
busy = true;
|
||||
Datastore::runOnWorkerThread(
|
||||
[=]
|
||||
{
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
rebuildConfiguration();
|
||||
};
|
||||
globalConfig().setFluxSink(path);
|
||||
auto fluxSource = FluxSource::createMemoryFluxSource(*diskFlux);
|
||||
auto fluxSink = FluxSink::create(globalConfig());
|
||||
writeRawDiskCommand(*fluxSource, *fluxSink);
|
||||
});
|
||||
}
|
||||
|
||||
void Datastore::createBlankImage()
|
||||
{
|
||||
busy = true;
|
||||
Datastore::runOnWorkerThread(
|
||||
[=]
|
||||
{
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
rebuildConfiguration();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
|
||||
static bool isBusy();
|
||||
static bool isConfigurationValid();
|
||||
static bool canFormat();
|
||||
static void probeDevices();
|
||||
|
||||
static const std::map<std::string, Device>& getDevices();
|
||||
@@ -42,6 +43,8 @@ public:
|
||||
|
||||
static void beginRead();
|
||||
static void writeImage(const std::fs::path& path);
|
||||
static void writeFluxFile(const std::fs::path& path);
|
||||
static void createBlankImage();
|
||||
static void stop();
|
||||
|
||||
static std::shared_ptr<const DiskFlux> getDiskFlux();
|
||||
|
||||
@@ -55,6 +55,11 @@ static void saveSectorImage()
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, Datastore::writeImage);
|
||||
}
|
||||
|
||||
static void saveFluxFile()
|
||||
{
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, Datastore::writeFluxFile);
|
||||
}
|
||||
|
||||
static void showOptions() {}
|
||||
|
||||
static void emitOptions(DynamicSetting<std::string>& setting,
|
||||
@@ -146,7 +151,7 @@ static void emitOptions(DynamicSetting<std::string>& setting,
|
||||
wolv::util::capitalizeString(selectedOption->comment())
|
||||
.c_str());
|
||||
else
|
||||
ImGui::TextWrapped("***bad***");
|
||||
ImGui::TextWrapped("***missing default***");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::BeginCombo(fmt::format("##{}", it.comment()).c_str(),
|
||||
nullptr,
|
||||
@@ -163,7 +168,8 @@ static void emitOptions(DynamicSetting<std::string>& setting,
|
||||
{
|
||||
if (it.name().empty())
|
||||
{
|
||||
options.erase(selectedOption->name());
|
||||
if (selectedOption)
|
||||
options.erase(selectedOption->name());
|
||||
options[ot.name()] = "true";
|
||||
}
|
||||
else
|
||||
@@ -523,7 +529,7 @@ void SummaryView::drawContent()
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (MaybeDisabledButton(
|
||||
if (maybeDisabledButton(
|
||||
fmt::format(
|
||||
"{} {}", ICON_TA_DEVICE_FLOPPY, "Read disk"),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
@@ -531,21 +537,21 @@ void SummaryView::drawContent()
|
||||
Datastore::beginRead();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
MaybeDisabledButton(
|
||||
maybeDisabledButton(
|
||||
fmt::format(
|
||||
"{} {}", ICON_VS_FOLDER_OPENED, "Load sector image"),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
MaybeDisabledButton(
|
||||
maybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_VS_SAVE_AS, "Write disk").c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy || !hasImage);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
MaybeDisabledButton(
|
||||
maybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_TA_REPEAT, "Reread bad tracks")
|
||||
.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
@@ -553,7 +559,7 @@ void SummaryView::drawContent()
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(ICON_VS_ARROW_RIGHT);
|
||||
ImGui::TableNextColumn();
|
||||
if (MaybeDisabledButton(
|
||||
if (maybeDisabledButton(
|
||||
fmt::format(
|
||||
"{} {}", ICON_VS_SAVE_ALL, "Save sector image")
|
||||
.c_str(),
|
||||
@@ -563,27 +569,30 @@ void SummaryView::drawContent()
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text(ICON_VS_ARROW_RIGHT);
|
||||
ImGui::TableNextColumn();
|
||||
MaybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_TA_DOWNLOAD, "Save flux file")
|
||||
.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy || !diskFlux);
|
||||
if (maybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_TA_DOWNLOAD, "Save flux file")
|
||||
.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy || !diskFlux))
|
||||
saveFluxFile();
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (MaybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_TA_UPLOAD, "Load flux file")
|
||||
if (maybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_TA_UPLOAD, "Setup flux file")
|
||||
.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy))
|
||||
loadFluxFile();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
MaybeDisabledButton(
|
||||
fmt::format("{} {}", ICON_VS_NEW_FILE, "Create blank image")
|
||||
.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy);
|
||||
if (maybeDisabledButton(
|
||||
fmt::format(
|
||||
"{} {}", ICON_VS_NEW_FILE, "Create blank image")
|
||||
.c_str(),
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
busy || !Datastore::canFormat()))
|
||||
Datastore::createBlankImage();
|
||||
}
|
||||
|
||||
{
|
||||
@@ -606,7 +615,7 @@ void SummaryView::drawContent()
|
||||
ImGui::PopStyleColor(3);
|
||||
};
|
||||
|
||||
if (MaybeDisabledButton(
|
||||
if (maybeDisabledButton(
|
||||
fmt::format("{} {}",
|
||||
ICON_TA_CANCEL,
|
||||
"fluxengine.summary.controls.stop"_lang),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
int MaybeDisabledButton(
|
||||
int maybeDisabledButton(
|
||||
const std::string& message, const ImVec2& size, bool isDisabled)
|
||||
{
|
||||
ImGui::BeginDisabled(isDisabled);
|
||||
|
||||
@@ -9,7 +9,7 @@ struct ImVec2;
|
||||
|
||||
using OptionsMap = std::map<std::string, std::string>;
|
||||
|
||||
extern int MaybeDisabledButton(
|
||||
extern int maybeDisabledButton(
|
||||
const std::string& message, const ImVec2& size, bool isDisabled);
|
||||
extern std::string shortenString(const std::string& s, size_t len);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user