Make two variations on the sector map; one for the physical view and one

for the logical view.
This commit is contained in:
David Given
2025-09-13 22:54:48 +02:00
parent 85afadacf0
commit 98f7febef7
14 changed files with 1144 additions and 262 deletions

View File

@@ -0,0 +1,193 @@
#include <hex/api/content_registry/user_interface.hpp>
#include <hex/helpers/logger.hpp>
#include <fonts/vscode_icons.hpp>
#include "lib/core/globals.h"
#include "lib/data/image.h"
#include "lib/data/sector.h"
#include "globals.h"
#include "physicalview.h"
#include "datastore.h"
using namespace hex;
AbstractSectorView::AbstractSectorView(const std::string& name):
View::Window(name, ICON_VS_MAP)
{
}
void AbstractSectorView::drawContent()
{
if (!Datastore::isConfigurationValid())
return;
auto diskFlux = Datastore::getDiskFlux();
if (!diskFlux)
return;
auto& image = diskFlux->image;
if (!image)
return;
auto [minCylinder, maxCylinder, minHead, maxHead] = getBounds();
unsigned minSector = UINT_MAX;
unsigned maxSector = 0;
for (int i = 0; i < image->getBlockCount(); i++)
{
auto [logicalCylinder, logicalHead, logicalSector] =
image->findBlock(i);
minSector = std::min(minSector, logicalSector);
maxSector = std::max(maxSector, logicalSector);
}
unsigned sectorCount = maxSector - minSector + 1;
auto backgroundColour = ImGui::GetColorU32(ImGuiCol_WindowBg);
ImGui::PushStyleColor(ImGuiCol_TableBorderLight, backgroundColour);
ON_SCOPE_EXIT
{
ImGui::PopStyleColor();
};
ImGui::PushStyleColor(ImGuiCol_TableBorderStrong, backgroundColour);
ON_SCOPE_EXIT
{
ImGui::PopStyleColor();
};
if (ImGui::BeginTable("diskSummary",
sectorCount + 2,
ImGuiTableFlags_NoSavedSettings |
ImGuiTableFlags_HighlightHoveredColumn |
ImGuiTableFlags_NoClip | ImGuiTableFlags_NoPadInnerX |
ImGuiTableFlags_NoPadOuterX | ImGuiTableFlags_Borders))
{
ON_SCOPE_EXIT
{
ImGui::EndTable();
};
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, {1, 1});
ON_SCOPE_EXIT
{
ImGui::PopStyleVar();
};
auto originalFontSize = ImGui::GetFontSize();
ImGui::PushFont(NULL, originalFontSize * 0.6);
ON_SCOPE_EXIT
{
ImGui::PopFont();
};
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0, 0});
ON_SCOPE_EXIT
{
ImGui::PopStyleVar();
};
ImGui::PushStyleVar(
ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
ON_SCOPE_EXIT
{
ImGui::PopStyleVar();
};
float rowHeight = originalFontSize * 0.6 * 1.3;
ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed, originalFontSize * 2.0);
ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight);
ImGui::TableNextColumn();
for (int sector = minSector; sector <= maxSector; sector++)
{
ImGui::TableNextColumn();
auto text = fmt::format("s{}", sector);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
ImGui::GetColumnWidth() / 2 -
ImGui::CalcTextSize(text.c_str()).x / 2);
ImGui::Text("%s", text.c_str());
}
for (unsigned cylinder = minCylinder; cylinder <= maxCylinder;
cylinder++)
for (unsigned head = minHead; head <= maxHead; head++)
{
ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight);
ImGui::TableNextColumn();
{
auto text = fmt::format("c{}h{}", cylinder, head);
auto textSize = ImGui::CalcTextSize(text.c_str());
ImGui::SetCursorPos(
{ImGui::GetCursorPosX() + ImGui::GetColumnWidth() / 2 -
textSize.x / 2,
ImGui::GetCursorPosY() + rowHeight / 2 -
textSize.y / 2});
ImGui::Text("%s", text.c_str());
}
for (unsigned sectorId = minSector; sectorId <= maxSector;
sectorId++)
{
ImGui::TableNextColumn();
auto sector = getSector(cylinder, head, sectorId);
if (sector)
{
auto colour = ImGuiExt::GetCustomColorU32(
(sector->status == Sector::OK)
? ImGuiCustomCol_LoggerInfo
: ImGuiCustomCol_LoggerError);
ImGui::PushStyleColor(ImGuiCol_Header, colour);
ON_SCOPE_EXIT
{
ImGui::PopStyleColor();
};
auto block = Datastore::findBlockByLogicalLocation(
{sector->logicalCylinder,
sector->logicalHead,
sector->logicalSector});
auto id = block.has_value() ? fmt::format("#{}", *block)
: "???";
if (ImGui::Selectable(fmt::format("{}##image_c{}h{}s{}",
id,
cylinder,
head,
sectorId)
.c_str(),
true,
ImGuiSelectableFlags_None,
{0,
rowHeight -
ImGui::GetStyle().CellPadding.y * 2}))
Events::SeekToSectorViaPhysicalLocation::post(
CylinderHeadSector{sector->physicalCylinder,
sector->physicalHead,
sectorId});
ImGui::PushFont(NULL, originalFontSize);
ON_SCOPE_EXIT
{
ImGui::PopFont();
};
ImGui::SetItemTooltip(
fmt::format("Physical: c{}h{}s{}\n"
"Logical: c{}h{}s{}\n"
"Size: {} bytes\n"
"Status: {}",
sector->physicalCylinder,
sector->physicalHead,
sectorId,
sector->logicalCylinder,
sector->logicalHead,
sectorId,
sector->data.size(),
Sector::statusToString(sector->status))
.c_str());
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <hex/ui/view.hpp>
#include "lib/core/globals.h"
#include "lib/data/layout.h"
class Sector;
class AbstractSectorView : public hex::View::Window
{
public:
AbstractSectorView(const std::string& name);
void drawContent() override;
[[nodiscard]] bool shouldDraw() const override
{
return true;
}
[[nodiscard]] bool hasViewMenuItemEntry() const override
{
return true;
}
protected:
virtual std::shared_ptr<const Sector> getSector(
unsigned cylinder, unsigned head, unsigned sectorId) = 0;
virtual Layout::LayoutBounds getBounds() = 0;
};

View File

@@ -330,8 +330,12 @@ plugin(
name="fluxengine-plugin",
id="fluxengine",
srcs=[
"./abstractsectorview.cc",
"./abstractsectorview.h",
"./imageview.cc",
"./imageview.h",
"./physicalview.cc",
"./physicalview.h",
"./datastore.cc",
"./datastore.h",
"./diskprovider.cc",

View File

@@ -38,8 +38,11 @@ static std::map<CylinderHead, std::shared_ptr<const TrackInfo>>
physicalCylinderLayouts;
static std::map<CylinderHeadSector, std::shared_ptr<const Sector>>
sectorByPhysicalLocation;
static std::map<LogicalLocation, std::shared_ptr<const Sector>>
sectorByLogicalLocation;
static std::map<LogicalLocation, unsigned> blockByLogicalLocation;
static Layout::LayoutBounds diskPhysicalBounds;
static Layout::LayoutBounds diskLogicalBounds;
static void workerThread_cb()
{
@@ -210,6 +213,11 @@ const Layout::LayoutBounds& Datastore::getDiskPhysicalBounds()
return diskPhysicalBounds;
}
const Layout::LayoutBounds& Datastore::getDiskLogicalBounds()
{
return diskLogicalBounds;
}
std::shared_ptr<const DiskFlux> Datastore::getDiskFlux()
{
return diskFlux;
@@ -224,6 +232,15 @@ std::shared_ptr<const Sector> Datastore::findSectorByPhysicalLocation(
return it->second;
}
std::shared_ptr<const Sector> Datastore::findSectorByLogicalLocation(
const LogicalLocation& location)
{
const auto& it = sectorByLogicalLocation.find(location);
if (it == sectorByLogicalLocation.end())
return nullptr;
return it->second;
}
std::optional<unsigned> Datastore::findBlockByLogicalLocation(
const LogicalLocation& location)
{
@@ -248,14 +265,20 @@ static void badConfiguration()
static void rebuildDiskFluxIndices()
{
sectorByPhysicalLocation.clear();
sectorByLogicalLocation.clear();
blockByLogicalLocation.clear();
if (diskFlux)
{
for (const auto& track : diskFlux->tracks)
for (const auto& sector : track->sectors)
{
sectorByPhysicalLocation[{sector->physicalCylinder,
sector->physicalHead,
sector->logicalSector}] = sector;
sectorByLogicalLocation[{sector->logicalCylinder,
sector->logicalHead,
sector->logicalSector}] = sector;
}
if (diskFlux->image)
for (unsigned block = 0; block < diskFlux->image->getBlockCount();
@@ -380,6 +403,8 @@ void Datastore::rebuildConfiguration()
{
auto locations = Layout::computePhysicalLocations();
auto diskPhysicalBounds = Layout::getBounds(locations);
auto diskLogicalBounds =
Layout::getBounds(Layout::computeLogicalLocations());
decltype(::physicalCylinderLayouts) physicalCylinderLayouts;
for (auto& it : locations)
@@ -390,6 +415,7 @@ void Datastore::rebuildConfiguration()
[=]
{
::diskPhysicalBounds = diskPhysicalBounds;
::diskLogicalBounds = diskLogicalBounds;
::physicalCylinderLayouts = physicalCylinderLayouts;
rebuildDiskFluxIndices();
configurationValid = true;

View File

@@ -31,10 +31,12 @@ public:
getphysicalCylinderLayouts();
static std::shared_ptr<const Sector> findSectorByPhysicalLocation(
const CylinderHeadSector& location);
static std::shared_ptr<const Sector> findSectorByLogicalLocation(
const LogicalLocation& location);
static std::optional<unsigned> findBlockByLogicalLocation(
const LogicalLocation& location);
static const Layout::LayoutBounds& getDiskPhysicalBounds();
static const Layout::LayoutBounds& getImageLogicalBounds();
static const Layout::LayoutBounds& getDiskLogicalBounds();
static void rebuildConfiguration();
static void onLogMessage(const AnyLogMessage& message);

View File

@@ -67,8 +67,8 @@ void DiskProvider::readRaw(u64 offset, void* buffer, size_t size)
auto [block, blockOffset] =
diskFlux->image->findBlockByOffset(offset);
auto sector = diskFlux->image->getBlock(block);
unsigned bytesRemaining =
std::min((unsigned)size, sector->trackLayout->sectorSize - blockOffset);
unsigned bytesRemaining = std::min(
(unsigned)size, sector->trackLayout->sectorSize - blockOffset);
auto bytes = sector->data.slice(blockOffset, bytesRemaining);
memcpy(buffer, bytes.cbegin(), bytes.size());

View File

@@ -5,6 +5,7 @@
#include <romfs/romfs.hpp>
#include "globals.h"
#include "imageview.h"
#include "physicalview.h"
#include "summaryview.h"
#include "diskprovider.h"
#include "datastore.h"
@@ -22,6 +23,7 @@ IMHEX_PLUGIN_SETUP("FluxEngine", "David Given", "FluxEngine integration")
hex::ContentRegistry::Provider::add<DiskProvider>();
hex::ContentRegistry::Views::add<ImageView>();
hex::ContentRegistry::Views::add<PhysicalView>();
hex::ContentRegistry::Views::add<SummaryView>();
Datastore::init();

View File

@@ -10,188 +10,15 @@
using namespace hex;
ImageView::ImageView():
View::Window("fluxengine.view.image.name", ICON_VS_DEBUG_LINE_BY_LINE)
ImageView::ImageView(): AbstractSectorView("fluxengine.view.image.name") {}
Layout::LayoutBounds ImageView::getBounds()
{
return Datastore::getDiskLogicalBounds();
}
void ImageView::drawContent()
std::shared_ptr<const Sector> ImageView::getSector(
unsigned cylinder, unsigned head, unsigned sectorId)
{
if (!Datastore::isConfigurationValid())
return;
auto diskFlux = Datastore::getDiskFlux();
if (!diskFlux)
return;
auto& image = diskFlux->image;
if (!image)
return;
auto [minCylinder, maxCylinder, minHead, maxHead] =
Datastore::getDiskPhysicalBounds();
unsigned minSector = UINT_MAX;
unsigned maxSector = 0;
for (int i = 0; i < image->getBlockCount(); i++)
{
auto [logicalCylinder, logicalHead, logicalSector] =
image->findBlock(i);
minSector = std::min(minSector, logicalSector);
maxSector = std::max(maxSector, logicalSector);
}
unsigned sectorCount = maxSector - minSector + 1;
auto backgroundColour = ImGui::GetColorU32(ImGuiCol_WindowBg);
ImGui::PushStyleColor(ImGuiCol_TableBorderLight, backgroundColour);
ON_SCOPE_EXIT
{
ImGui::PopStyleColor();
};
ImGui::PushStyleColor(ImGuiCol_TableBorderStrong, backgroundColour);
ON_SCOPE_EXIT
{
ImGui::PopStyleColor();
};
if (ImGui::BeginTable("diskSummary",
sectorCount + 2,
ImGuiTableFlags_NoSavedSettings |
ImGuiTableFlags_HighlightHoveredColumn |
ImGuiTableFlags_NoClip | ImGuiTableFlags_NoPadInnerX |
ImGuiTableFlags_NoPadOuterX | ImGuiTableFlags_Borders))
{
ON_SCOPE_EXIT
{
ImGui::EndTable();
};
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, {1, 1});
ON_SCOPE_EXIT
{
ImGui::PopStyleVar();
};
auto originalFontSize = ImGui::GetFontSize();
ImGui::PushFont(NULL, originalFontSize * 0.6);
ON_SCOPE_EXIT
{
ImGui::PopFont();
};
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0, 0});
ON_SCOPE_EXIT
{
ImGui::PopStyleVar();
};
ImGui::PushStyleVar(
ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
ON_SCOPE_EXIT
{
ImGui::PopStyleVar();
};
float rowHeight = originalFontSize * 0.6 * 1.3;
ImGui::TableSetupColumn(
"", ImGuiTableColumnFlags_WidthFixed, originalFontSize * 2.0);
ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight);
ImGui::TableNextColumn();
for (int sector = minSector; sector <= maxSector; sector++)
{
ImGui::TableNextColumn();
auto text = fmt::format("s{}", sector);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
ImGui::GetColumnWidth() / 2 -
ImGui::CalcTextSize(text.c_str()).x / 2);
ImGui::Text("%s", text.c_str());
}
for (unsigned physicalCylinder = minCylinder;
physicalCylinder <= maxCylinder;
physicalCylinder++)
for (unsigned physicalHead = minHead; physicalHead <= maxHead;
physicalHead++)
{
ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight);
ImGui::TableNextColumn();
{
auto text =
fmt::format("c{}h{}", physicalCylinder, physicalHead);
auto textSize = ImGui::CalcTextSize(text.c_str());
ImGui::SetCursorPos(
{ImGui::GetCursorPosX() + ImGui::GetColumnWidth() / 2 -
textSize.x / 2,
ImGui::GetCursorPosY() + rowHeight / 2 -
textSize.y / 2});
ImGui::Text("%s", text.c_str());
}
for (unsigned sectorId = minSector; sectorId <= maxSector;
sectorId++)
{
ImGui::TableNextColumn();
auto sector = Datastore::findSectorByPhysicalLocation(
{physicalCylinder, physicalHead, sectorId});
if (sector)
{
auto colour = ImGuiExt::GetCustomColorU32(
(sector->status == Sector::OK)
? ImGuiCustomCol_LoggerInfo
: ImGuiCustomCol_LoggerError);
ImGui::PushStyleColor(ImGuiCol_Header, colour);
ON_SCOPE_EXIT
{
ImGui::PopStyleColor();
};
auto block = Datastore::findBlockByLogicalLocation(
{sector->logicalCylinder,
sector->logicalHead,
sector->logicalSector});
auto id = block.has_value() ? fmt::format("#{}", *block)
: "???";
if (ImGui::Selectable(fmt::format("{}##image_c{}h{}s{}",
id,
physicalCylinder,
physicalHead,
sectorId)
.c_str(),
true,
ImGuiSelectableFlags_None,
{0,
rowHeight -
ImGui::GetStyle().CellPadding.y * 2}))
Events::SeekToSectorViaPhysicalLocation::post(
CylinderHeadSector{
physicalCylinder, physicalHead, sectorId});
ImGui::PushFont(NULL, originalFontSize);
ON_SCOPE_EXIT
{
ImGui::PopFont();
};
ImGui::SetItemTooltip(
fmt::format("Physical: c{}h{}s{}\n"
"Logical: c{}h{}s{}\n"
"Size: {} bytes\n"
"Status: {}",
physicalCylinder,
physicalHead,
sectorId,
sector->logicalCylinder,
sector->logicalHead,
sectorId,
sector->data.size(),
Sector::statusToString(sector->status))
.c_str());
}
}
}
}
return Datastore::findSectorByLogicalLocation({cylinder, head, sectorId});
}

View File

@@ -1,21 +1,14 @@
#pragma once
#include <hex/ui/view.hpp>
#include "abstractsectorview.h"
class ImageView : public hex::View::Window
class ImageView : public AbstractSectorView
{
public:
ImageView();
~ImageView() override = default;
void drawContent() override;
[[nodiscard]] bool shouldDraw() const override
{
return true;
}
[[nodiscard]] bool hasViewMenuItemEntry() const override
{
return true;
}
std::shared_ptr<const Sector> getSector(
unsigned cylinder, unsigned head, unsigned sectorId) override;
Layout::LayoutBounds getBounds() override;
};

29
src/gui2/physicalview.cc Normal file
View File

@@ -0,0 +1,29 @@
#include <hex/api/content_registry/user_interface.hpp>
#include <hex/helpers/logger.hpp>
#include <fonts/vscode_icons.hpp>
#include "lib/core/globals.h"
#include "lib/data/image.h"
#include "lib/data/sector.h"
#include "globals.h"
#include "physicalview.h"
#include "datastore.h"
using namespace hex;
PhysicalView::PhysicalView():
AbstractSectorView("fluxengine.view.physical.name")
{
}
PhysicalView::~PhysicalView() {}
Layout::LayoutBounds PhysicalView::getBounds()
{
return Datastore::getDiskPhysicalBounds();
}
std::shared_ptr<const Sector> PhysicalView::getSector(
unsigned cylinder, unsigned head, unsigned sectorId)
{
return Datastore::findSectorByPhysicalLocation({cylinder, head, sectorId});
}

15
src/gui2/physicalview.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include <hex/ui/view.hpp>
#include "abstractsectorview.h"
class PhysicalView : public AbstractSectorView
{
public:
PhysicalView();
~PhysicalView();
std::shared_ptr<const Sector> getSector(
unsigned cylinder, unsigned head, unsigned sectorId) override;
Layout::LayoutBounds getBounds() override;
};

View File

@@ -25,5 +25,7 @@
"fluxengine.view.summary.manualDevicePath": "Device path",
"fluxengine.view.summary.fluxFile": "Flux file",
"fluxengine.view.image.name": "FluxEngine sector map"
"fluxengine.view.image.name": "FluxEngine logical sector map",
"fluxengine.view.physical.name": "FluxEngine physical sector map"
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ using namespace hex;
static DynamicSettingFactory settings("fluxengine.settings");
SummaryView::SummaryView():
View::Window("fluxengine.view.summary.name", ICON_VS_DEBUG_LINE_BY_LINE)
View::Window("fluxengine.view.summary.name", ICON_VS_COMPASS)
{
}