#include #include #include #include #include #include #include namespace hex::plugin::visualizers { void drawDigitalSignalVisualizer(pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &iterable, bool shouldReset, std::span) { auto *bitfield = dynamic_cast(&pattern); if (bitfield == nullptr) throw std::logic_error("Digital signal visualizer only works with bitfields."); struct DataPoint { std::array points; std::string label; std::string value; ImColor color; }; static std::vector dataPoints; static ImVec2 lastPoint; if (shouldReset) { dataPoints.clear(); lastPoint = { 0, 0 }; iterable.forEachEntry(0, iterable.getEntryCount(), [&](u64, pl::ptrn::Pattern *entry) { size_t bitSize = 0; if (auto bitfieldField = dynamic_cast(entry); bitfieldField != nullptr) bitSize = bitfieldField->getBitSize(); else bitSize = entry->getSize() * 8; auto value = entry->getValue(); bool high = value.toUnsigned() > 0; dataPoints.emplace_back( std::array { lastPoint, { lastPoint.x, high ? 1.0F : 0.0F } }, entry->getDisplayName(), entry->getFormattedValue(), entry->getColor() ); lastPoint = dataPoints.back().points[1]; lastPoint.x += bitSize; }); dataPoints.push_back({ .points = { lastPoint, { lastPoint.x, 0 } }, .label = "", .value = "", .color = ImColor(0x00) }); } if (ImPlot::BeginPlot("##Signal", ImVec2(600_scaled, 200_scaled), ImPlotFlags_NoLegend | ImPlotFlags_NoFrame | ImPlotFlags_NoMenus | ImPlotFlags_NoMouseText)) { ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, lastPoint.x); ImPlot::SetupAxis(ImAxis_Y1, "", ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax); ImPlot::SetupAxisFormat(ImAxis_Y1, ""); ImPlot::SetupAxisLimits(ImAxis_Y1, -0.1F, 1.1F); for (size_t i = 0; i < dataPoints.size() - 1; i += 1) { const auto &left = dataPoints[i]; const auto &right = dataPoints[i + 1]; { auto x = left.points[1].x + (right.points[0].x - left.points[1].x) / 2; ImPlot::Annotation(x, 0.55F, left.color, {}, false, "%s", left.label.c_str()); ImPlot::Annotation(x, 0.40F, left.color, {}, false, "%s", left.value.c_str()); } { ImVec2 min = ImPlot::PlotToPixels(ImPlotPoint(left.points[0].x, 0)); ImVec2 max = ImPlot::PlotToPixels(ImPlotPoint(right.points[1].x, 1)); ImPlot::PushPlotClipRect(); auto transparentColor = left.color; transparentColor.Value.w = 0.2F; ImPlot::GetPlotDrawList()->AddRectFilled(min, max, transparentColor); ImPlot::PopPlotClipRect(); } } ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2_scaled); ImPlot::PlotLineG("Signal", [](int idx, void*) -> ImPlotPoint { return dataPoints[idx / 2].points[idx % 2]; }, nullptr, dataPoints.size() * 2); ImPlot::PopStyleVar(); ImPlot::EndPlot(); } } }