Insight GUI changes:

- New target pinout widgets
- Made auto-refresh of registers and GPIO pad states optional (via context menu on refresh tool button)
This commit is contained in:
Nav
2025-02-18 00:35:39 +00:00
parent e8f747a152
commit 8a473473db
75 changed files with 2927 additions and 2304 deletions

View File

@@ -54,19 +54,23 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/Dialog/Dialog.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/ConfirmationDialog.cpp
# Target package widgets
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.cpp
# Target pinouts
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinoutContainer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinoutScene.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroup.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroupSet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/HorizontalLabelGroup.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/HorizontalLabelGroupSet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/Label.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PadLabels.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinNumberLabel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PadNameLabel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/GpioDirectionLabel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/GpioStateLabel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/GpioDisabledLabel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/Pin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/Qfp/QfpPinout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/Dip/DipPinout.cpp
# Target register side pane
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp
@@ -149,10 +153,6 @@ qt_add_resources(
"./UserInterfaces/InsightWindow/Widgets/TaskWindow/UiFiles/TaskWindow.ui"
"./UserInterfaces/InsightWindow/Widgets/TaskWindow/Stylesheets/TaskWindow.qss"
# Target package widgets
"./UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss"
"./UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"
# Target registers pane
"./UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/UiFiles/TargetRegistersSidePane.ui"
"./UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/collapse-all.svg"

View File

@@ -7,9 +7,6 @@
#include "UiLoader.hpp"
#include "Widgets/RotatableLabel.hpp"
#include "Widgets/TargetWidgets/DIP/DualInlinePackageWidget.hpp"
#include "Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.hpp"
#include "Widgets/TargetMemoryInspectionPane/ToolButton.hpp"
#include "src/Logger/Logger.hpp"
@@ -28,14 +25,14 @@ using Targets::TargetExecutionState;
using Targets::TargetPinDescriptor;
InsightWindow::InsightWindow(
InsightProjectSettings& insightProjectSettings,
InsightProjectSettings& settings,
const InsightConfig& insightConfig,
const EnvironmentConfig& environmentConfig,
const TargetDescriptor& targetDescriptor,
const TargetState& targetState
)
: QMainWindow(nullptr)
, insightProjectSettings(insightProjectSettings)
, settings(settings)
, insightConfig(insightConfig)
, environmentConfig(environmentConfig)
, targetConfig(environmentConfig.targetConfig)
@@ -48,10 +45,10 @@ InsightWindow::InsightWindow(
constexpr auto defaultWindowSize = QSize{1000, 500};
const auto windowSize = this->insightProjectSettings.mainWindowSize.has_value()
const auto windowSize = this->settings.mainWindowSize.has_value()
? QSize{
std::max(this->insightProjectSettings.mainWindowSize->width(), defaultWindowSize.width()),
std::max(this->insightProjectSettings.mainWindowSize->height(), defaultWindowSize.height())
std::max(this->settings.mainWindowSize->width(), defaultWindowSize.width()),
std::max(this->settings.mainWindowSize->height(), defaultWindowSize.height())
}
: defaultWindowSize;
@@ -95,9 +92,6 @@ InsightWindow::InsightWindow(
this->mainMenuBar = this->windowContainer->findChild<QMenuBar*>("menu-bar");
this->layoutContainer->layout()->setMenuBar(this->mainMenuBar);
this->container = this->layoutContainer->findChild<QWidget*>("container");
this->ioContainerWidget = this->windowContainer->findChild<InsightTargetWidgets::TargetPackageWidgetContainer*>(
"io-container"
);
auto* horizontalContentLayout = this->container->findChild<QHBoxLayout*>("horizontal-content-layout");
auto* verticalContentLayout = this->container->findChild<QVBoxLayout*>("vertical-content-layout");
@@ -110,21 +104,27 @@ InsightWindow::InsightWindow(
auto* openAboutWindowAction = helpMenu->findChild<QAction*>("open-about-dialogue");
this->header = this->windowContainer->findChild<QWidget*>("header");
this->refreshIoInspectionButton = this->header->findChild<SvgToolButton*>("refresh-io-inspection-btn");
this->refreshRegistersOnTargetStopAction = this->refreshIoInspectionButton->findChild<QAction*>("refresh-regs");
this->refreshGpioOnTargetStopAction = this->refreshIoInspectionButton->findChild<QAction*>("refresh-gpio");
this->setRefreshRegistersOnTargetStopped(this->settings.refreshRegistersOnTargetStopped);
this->setRefreshGpioOnTargetStopped(this->settings.refreshGpioOnTargetStopped);
// Create panel states
if (!this->insightProjectSettings.leftPanelState.has_value()) {
this->insightProjectSettings.leftPanelState = PanelState{};
if (!this->settings.leftPanelState.has_value()) {
this->settings.leftPanelState = PanelState{};
}
if (!this->insightProjectSettings.bottomPanelState.has_value()) {
this->insightProjectSettings.bottomPanelState = PanelState{};
if (!this->settings.bottomPanelState.has_value()) {
this->settings.bottomPanelState = PanelState{};
}
this->leftMenuBar = this->container->findChild<QWidget*>("left-side-menu-bar");
this->leftPanel = new PanelWidget{
PanelWidgetType::LEFT,
this->insightProjectSettings.leftPanelState.value(),
this->settings.leftPanelState.value(),
this->container
};
this->leftPanel->setObjectName("left-panel");
@@ -139,11 +139,15 @@ InsightWindow::InsightWindow(
registersBtnLabel->setContentsMargins(4, 4, 10, 2);
targetRegisterButtonLayout->insertWidget(0, registersBtnLabel, 0, Qt::AlignTop);
this->pinoutContainerWidget = new PinoutWidgets::PinoutContainer{this->targetDescriptor, this};
this->pinoutScene = this->pinoutContainerWidget->pinoutScene;
horizontalContentLayout->insertWidget(1, this->pinoutContainerWidget);
this->bottomMenuBar = this->container->findChild<QWidget*>("bottom-menu-bar");
this->bottomMenuBarLayout = this->bottomMenuBar->findChild<QHBoxLayout*>();
this->bottomPanel = new PanelWidget{
PanelWidgetType::BOTTOM,
this->insightProjectSettings.bottomPanelState.value(),
this->settings.bottomPanelState.value(),
this->container
};
this->bottomPanel->setObjectName("bottom-panel");
@@ -228,7 +232,27 @@ InsightWindow::InsightWindow(
this->refreshIoInspectionButton,
&QToolButton::clicked,
this,
&InsightWindow::refresh
[this] () {
this->refresh(true, true);
}
);
QObject::connect(
this->refreshRegistersOnTargetStopAction,
&QAction::triggered,
this,
[this] (bool checked) {
this->setRefreshRegistersOnTargetStopped(checked);
}
);
QObject::connect(
this->refreshGpioOnTargetStopAction,
&QAction::triggered,
this,
[this] (bool checked) {
this->setRefreshGpioOnTargetStopped(checked);
}
);
// Panel connections
@@ -276,7 +300,7 @@ void InsightWindow::resizeEvent(QResizeEvent* event) {
this->adjustPanels();
this->insightProjectSettings.mainWindowSize = windowSize;
this->settings.mainWindowSize = windowSize;
}
void InsightWindow::showEvent(QShowEvent* event) {
@@ -288,46 +312,6 @@ void InsightWindow::closeEvent(QCloseEvent* event) {
return QMainWindow::closeEvent(event);
}
bool InsightWindow::isPinoutSupported(const Targets::TargetPinoutDescriptor& pinoutDescriptor) {
using Targets::TargetPinoutType;
const auto pinCount = pinoutDescriptor.pinDescriptors.size();
if (pinCount > 100) {
return false;
}
if (
pinoutDescriptor.type != TargetPinoutType::DIP
&& pinoutDescriptor.type != TargetPinoutType::SOIC
&& pinoutDescriptor.type != TargetPinoutType::SSOP
&& pinoutDescriptor.type != TargetPinoutType::QFP
&& pinoutDescriptor.type != TargetPinoutType::QFN
) {
return false;
}
if (
(
pinoutDescriptor.type == TargetPinoutType::DIP
|| pinoutDescriptor.type == TargetPinoutType::SOIC
|| pinoutDescriptor.type == TargetPinoutType::SSOP
)
&& pinCount % 2 != 0
) {
return false;
}
if (
(pinoutDescriptor.type == TargetPinoutType::QFP || pinoutDescriptor.type == TargetPinoutType::QFN)
&& (pinCount % 4 != 0 || pinCount <= 4)
) {
return false;
}
return true;
}
void InsightWindow::setUiDisabled(bool disable) {
this->uiDisabled = disable;
@@ -346,7 +330,7 @@ void InsightWindow::populateVariantMenu() {
QString::fromStdString(variantDescriptor.name + " (" + pinoutDescriptor.name + ")")
);
if (InsightWindow::isPinoutSupported(pinoutDescriptor)) {
if (this->pinoutScene->isPinoutSupported(pinoutDescriptor)) {
QObject::connect(
variantAction,
&QAction::triggered,
@@ -384,17 +368,15 @@ void InsightWindow::selectDefaultVariant() {
const auto& descriptor = variantDescriptor->get();
const auto& pinoutDescriptor = this->targetDescriptor.getPinoutDescriptor(descriptor.pinoutKey);
if (InsightWindow::isPinoutSupported(pinoutDescriptor)) {
if (this->pinoutScene->isPinoutSupported(pinoutDescriptor)) {
this->selectVariant(&descriptor);
return;
} else {
Logger::error(
"Unsupported target variant (\"" + descriptor.name
+ "\") provided via 'defaultVariantKey' parameter"
);
}
Logger::error(
"Unsupported target variant (\"" + descriptor.name + "\") provided via 'defaultVariantKey' parameter"
);
} else {
Logger::error(
"Invalid target variant key `" + *(this->insightConfig.defaultVariantKey)
@@ -404,16 +386,16 @@ void InsightWindow::selectDefaultVariant() {
}
// Try the previously selected variant
if (this->insightProjectSettings.selectedVariantKey.has_value()) {
if (this->settings.selectedVariantKey.has_value()) {
const auto variantDescriptor = this->targetDescriptor.tryGetVariantDescriptor(
*(this->insightProjectSettings.selectedVariantKey)
*(this->settings.selectedVariantKey)
);
if (variantDescriptor.has_value()) {
const auto& descriptor = variantDescriptor->get();
const auto& pinoutDescriptor = this->targetDescriptor.getPinoutDescriptor(descriptor.pinoutKey);
if (InsightWindow::isPinoutSupported(pinoutDescriptor)) {
if (this->pinoutScene->isPinoutSupported(pinoutDescriptor)) {
this->selectVariant(&descriptor);
return;
}
@@ -427,7 +409,7 @@ void InsightWindow::selectDefaultVariant() {
for (const auto& [variantKey, variantDescriptor] : this->targetDescriptor.variantDescriptorsByKey) {
const auto& pinoutDescriptor = this->targetDescriptor.getPinoutDescriptor(variantDescriptor.pinoutKey);
if (InsightWindow::isPinoutSupported(pinoutDescriptor)) {
if (this->pinoutScene->isPinoutSupported(pinoutDescriptor)) {
this->selectVariant(&variantDescriptor);
return;
}
@@ -445,65 +427,26 @@ void InsightWindow::selectVariant(const Targets::TargetVariantDescriptor* varian
}
const auto& pinoutDescriptor = this->targetDescriptor.getPinoutDescriptor(variantDescriptor->pinoutKey);
if (!InsightWindow::isPinoutSupported(pinoutDescriptor)) {
Logger::error("Attempted to select unsupported target variant.");
return;
}
assert(this->pinoutScene->isPinoutSupported(pinoutDescriptor));
if (this->targetPackageWidget != nullptr) {
this->targetPackageWidget->hide();
this->targetPackageWidget->deleteLater();
this->targetPackageWidget = nullptr;
this->ioContainerWidget->setPackageWidget(this->targetPackageWidget);
}
this->pinoutScene->setPinout(pinoutDescriptor);
this->selectedVariantDescriptor = variantDescriptor;
this->insightProjectSettings.selectedVariantKey = variantDescriptor->key;
this->settings.selectedVariantKey = variantDescriptor->key;
this->variantMenu->setTitle(QString::fromStdString(variantDescriptor->name + " (" + pinoutDescriptor.name + ")"));
if (
pinoutDescriptor.type == TargetPinoutType::DIP
|| pinoutDescriptor.type == TargetPinoutType::SOIC
|| pinoutDescriptor.type == TargetPinoutType::SSOP
) {
this->targetPackageWidget = new InsightTargetWidgets::Dip::DualInlinePackageWidget{
*variantDescriptor,
pinoutDescriptor,
this->targetDescriptor,
this->targetState,
this->ioContainerWidget
};
} else if (pinoutDescriptor.type == TargetPinoutType::QFP || pinoutDescriptor.type == TargetPinoutType::QFN) {
this->targetPackageWidget = new InsightTargetWidgets::Qfp::QuadFlatPackageWidget{
*variantDescriptor,
pinoutDescriptor,
this->targetDescriptor,
this->targetState,
this->ioContainerWidget
};
}
if (this->targetPackageWidget != nullptr) {
this->ioContainerWidget->setPackageWidget(this->targetPackageWidget);
this->adjustPanels();
this->adjustMinimumSize();
this->targetPackageWidget->show();
}
}
void InsightWindow::createPanes() {
// Target registers pane
if (!this->insightProjectSettings.registersPaneState.has_value()) {
this->insightProjectSettings.registersPaneState = PaneState{false, true, std::nullopt};
if (!this->settings.registersPaneState.has_value()) {
this->settings.registersPaneState = PaneState{false, true, std::nullopt};
}
auto* leftPanelLayout = this->leftPanel->layout();
this->targetRegistersSidePane = new TargetRegistersPaneWidget{
this->targetDescriptor,
this->targetState,
*(this->insightProjectSettings.registersPaneState),
*(this->settings.registersPaneState),
this->leftPanel
};
leftPanelLayout->addWidget(this->targetRegistersSidePane);
@@ -538,11 +481,11 @@ void InsightWindow::createPanes() {
segmentDescriptor,
this->targetDescriptor,
this->targetState,
this->insightProjectSettings.findOrCreateMemoryInspectionPaneSettings(
this->settings.findOrCreateMemoryInspectionPaneSettings(
QString::fromStdString(addressSpaceDescriptor.key),
QString::fromStdString(segmentDescriptor.key)
),
this->insightProjectSettings.findOrCreateMemoryInspectionPaneState(
this->settings.findOrCreateMemoryInspectionPaneState(
QString::fromStdString(addressSpaceDescriptor.key),
QString::fromStdString(segmentDescriptor.key)
),
@@ -598,29 +541,13 @@ void InsightWindow::createPanes() {
}
void InsightWindow::adjustPanels() {
const auto targetPackageWidgetSize = (this->targetPackageWidget != nullptr)
? this->targetPackageWidget->size() : QSize{};
const auto containerSize = this->size();
if (!this->isVisible()) {
return;
}
/*
* The purpose of the -20 is to ensure there is some padding between the panel borders and the
* target package widget. Looks nicer with the padding.
*/
this->leftPanel->setMaximumResize(
std::max(
this->leftPanel->getMinimumResize(),
containerSize.width() - targetPackageWidgetSize.width() - this->leftMenuBar->width() - 20
)
);
/*
* Allow the bottom panel to overlap the target package widget (because the target package widget can
* occupy a lot of space and become an annoyance if the bottom panel is restricted too much).
*/
this->leftPanel->setMaximumResize(std::max(this->leftPanel->getMinimumResize(), containerSize.width() / 2));
this->bottomPanel->setMaximumResize(
std::max(
this->bottomPanel->getMinimumResize(),
@@ -632,26 +559,10 @@ void InsightWindow::adjustPanels() {
}
void InsightWindow::adjustMinimumSize() {
static const auto absoluteMinimum = QSize{900, 400};
/*
* On X11, the QScreen::availableGeometry() function may return the full geometry of the screen, without
* accounting for reserved areas for window managers and other decorations.
*
* Because of this, we always use QScreen::geometry() and account for reserved areas ourselves. It's near
* impossible to do this accurately, so we just subtract 200 from the width and height, and hope that it's
* enough.
*/
const auto screenSize = this->screen()->availableGeometry().size();
const auto absoluteMaximum = QSize{screenSize.width() - 200, screenSize.height() - 200};
static constexpr auto absoluteMinimum = QSize{900, 400};
auto minSize = QSize{};
if (this->targetPackageWidget != nullptr) {
minSize.setWidth(this->targetPackageWidget->width() + 250);
minSize.setHeight(this->targetPackageWidget->height() + 150);
}
if (this->leftPanel->isVisible()) {
minSize.setWidth(minSize.width() + this->leftPanel->getMinimumResize());
}
@@ -661,8 +572,8 @@ void InsightWindow::adjustMinimumSize() {
}
this->setMinimumSize(
std::min(std::max(minSize.width(), absoluteMinimum.width()), absoluteMaximum.width()),
std::min(std::max(minSize.height(), absoluteMinimum.height()), absoluteMaximum.height())
std::max(minSize.width(), absoluteMinimum.width()),
std::max(minSize.height(), absoluteMinimum.height())
);
}
@@ -670,10 +581,15 @@ void InsightWindow::onTargetStateUpdate(TargetState newState, Targets::TargetSta
const auto targetStopped = newState.executionState == TargetExecutionState::STOPPED;
this->setUiDisabled(!targetStopped);
if (this->targetPackageWidget != nullptr) {
this->targetPackageWidget->setDisabled(!targetStopped);
if (targetStopped && (this->settings.refreshRegistersOnTargetStopped || this->settings.refreshGpioOnTargetStopped)) {
this->refresh(
this->settings.refreshRegistersOnTargetStopped,
this->settings.refreshGpioOnTargetStopped
);
}
this->pinoutScene->setDisabled(!targetStopped);
switch (newState.executionState) {
case TargetExecutionState::STOPPED: {
this->targetStatusLabel->setText("Stopped");
@@ -698,8 +614,17 @@ void InsightWindow::onTargetStateUpdate(TargetState newState, Targets::TargetSta
);
}
void InsightWindow::setRefreshRegistersOnTargetStopped(bool enabled) {
this->refreshRegistersOnTargetStopAction->setChecked(enabled);
this->settings.refreshRegistersOnTargetStopped = enabled;
}
void InsightWindow::refresh() {
void InsightWindow::setRefreshGpioOnTargetStopped(bool enabled) {
this->refreshGpioOnTargetStopAction->setChecked(enabled);
this->settings.refreshGpioOnTargetStopped = enabled;
}
void InsightWindow::refresh(bool refreshRegisters, bool refreshGpio) {
if (this->targetState.executionState != TargetExecutionState::STOPPED) {
return;
}
@@ -707,18 +632,18 @@ void InsightWindow::refresh() {
this->refreshIoInspectionButton->startSpin();
this->refreshIoInspectionButton->setDisabled(true);
if (this->targetPackageWidget != nullptr) {
if (refreshGpio) {
this->refreshPadStates();
}
const auto callback = [this] {
this->refreshIoInspectionButton->stopSpin();
this->refreshIoInspectionButton->setDisabled(
this->targetState.executionState != TargetExecutionState::STOPPED
this->targetState.executionState != TargetExecutionState::STOPPED
);
};
if (this->targetRegistersSidePane != nullptr && this->targetRegistersSidePane->state.activated) {
if (refreshRegisters && this->targetRegistersSidePane != nullptr && this->targetRegistersSidePane->state.activated) {
this->targetRegistersSidePane->refreshRegisterValues(std::nullopt, callback);
} else {
@@ -727,11 +652,11 @@ void InsightWindow::refresh() {
}
void InsightWindow::refreshPadStates() {
this->targetPackageWidget->setDisabled(true);
this->pinoutScene->setDisabled(true);
this->targetPackageWidget->refreshPadStates([this] {
this->pinoutScene->refreshPadStates([this] {
if (this->targetState.executionState == TargetExecutionState::STOPPED) {
this->targetPackageWidget->setDisabled(false);
this->pinoutScene->setDisabled(false);
}
});
}

View File

@@ -17,8 +17,8 @@
#include "Widgets/Label.hpp"
#include "Widgets/SvgToolButton.hpp"
#include "Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp"
#include "Widgets/TargetWidgets/TargetPackageWidget.hpp"
#include "Widgets/PinoutWidgets/PinoutContainer.hpp"
#include "Widgets/PinoutWidgets/PinoutScene.hpp"
#include "Widgets/PanelWidget.hpp"
#include "Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp"
#include "Widgets/TargetMemoryInspectionPane/TargetMemoryInspectionPane.hpp"
@@ -33,7 +33,7 @@ class InsightWindow: public QMainWindow
public:
InsightWindow(
InsightProjectSettings& insightProjectSettings,
InsightProjectSettings& settings,
const InsightConfig& insightConfig,
const EnvironmentConfig& environmentConfig,
const Targets::TargetDescriptor& targetDescriptor,
@@ -46,7 +46,7 @@ protected:
void closeEvent(QCloseEvent* event) override;
private:
InsightProjectSettings& insightProjectSettings;
InsightProjectSettings& settings;
InsightConfig insightConfig;
EnvironmentConfig environmentConfig;
@@ -65,15 +65,18 @@ private:
AboutWindow* aboutWindowWidget = nullptr;
QWidget* header = nullptr;
Widgets::SvgToolButton* refreshIoInspectionButton = nullptr;
QAction* refreshRegistersOnTargetStopAction = nullptr;
QAction* refreshGpioOnTargetStopAction = nullptr;
QWidget* leftMenuBar = nullptr;
Widgets::PanelWidget* leftPanel = nullptr;
Widgets::TargetRegistersPaneWidget* targetRegistersSidePane = nullptr;
QToolButton* targetRegistersButton = nullptr;
Widgets::InsightTargetWidgets::TargetPackageWidgetContainer* ioContainerWidget = nullptr;
Widgets::InsightTargetWidgets::TargetPackageWidget* targetPackageWidget = nullptr;
Widgets::PinoutWidgets::PinoutContainer* pinoutContainerWidget = nullptr;
Widgets::PinoutWidgets::PinoutScene* pinoutScene = nullptr;
QWidget* bottomMenuBar = nullptr;
QHBoxLayout* bottomMenuBarLayout = nullptr;
@@ -88,8 +91,6 @@ private:
const Targets::TargetVariantDescriptor* selectedVariantDescriptor = nullptr;
bool uiDisabled = false;
static bool isPinoutSupported(const Targets::TargetPinoutDescriptor& pinoutDescriptor);
void setUiDisabled(bool disable);
void populateVariantMenu();
@@ -101,7 +102,9 @@ private:
void adjustMinimumSize();
void onTargetStateUpdate(Targets::TargetState newState, Targets::TargetState previousState);
void refresh();
void setRefreshRegistersOnTargetStopped(bool enabled);
void setRefreshGpioOnTargetStopped(bool enabled);
void refresh(bool refreshRegisters, bool refreshGpio);
void refreshPadStates();
void openReportIssuesUrl();
void openGettingStartedUrl();

View File

@@ -180,6 +180,10 @@ QToolTip {
border: none;
}
#pinout-widget-container {
background-color: transparent;
}
/* Bottom menu bar & panels */
#bottom-menu-bar {
background-color: transparent;

View File

@@ -87,8 +87,34 @@
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Images/refresh-disabled.svg</string>
</property>
<property name="toolTip">
<string>Refresh Registers And GPIO Pin States</string>
<string>Refresh registers and GPIO pad states (right-click for auto-refresh options)</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="contextMenuEnabled">
<bool>true</bool>
</property>
<widget class="QMenu" name="refresh-menu">
<addaction name="refresh-regs"/>
<addaction name="refresh-gpio"/>
<action name="refresh-regs">
<property name="text">
<string>Refresh registers after target execution stops</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</action>
<action name="refresh-gpio">
<property name="text">
<string>Refresh GPIO pad states after target execution stops</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</action>
</widget>
</widget>
</item>
<item>
@@ -198,27 +224,7 @@
<property name="margin">
<number>0</number>
</property>
<!-- The left panel is inserted here. See InsightWindow::InsightWindow() for more -->
<item>
<widget class="TargetPackageWidgetContainer" name="io-container">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
</property>
<layout class="QHBoxLayout">
<item alignment="Qt::AlignHCenter">
<widget class="Label" name="io-inspection-unavailable">
<property name="visible"><bool>false</bool></property>
<property name="alignment">
<enum>Qt::AlignCenter</enum>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<!-- The left panel, along with the pinout widget container, is inserted here. See InsightWindow::InsightWindow() for more -->
</layout>
</item>
<!-- The bottom panel is inserted here. See InsightWindow::InsightWindow() for more -->

View File

@@ -12,7 +12,6 @@
#include "Widgets/SvgWidget.hpp"
#include "Widgets/SvgToolButton.hpp"
#include "Widgets/ExpandingHeightScrollAreaWidget.hpp"
#include "Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp"
using namespace Widgets;
@@ -101,15 +100,6 @@ UiLoader::UiLoader(QObject* parent)
return widget;
}
},
{
"TargetPackageWidgetContainer",
[this] (QWidget* parent, const QString& name) {
auto* widget = new InsightTargetWidgets::TargetPackageWidgetContainer{parent};
widget->setObjectName(name);
widget->setStyleSheet(parent->styleSheet());
return widget;
}
},
};
}

View File

@@ -0,0 +1,335 @@
#include "DipPinout.hpp"
#include <algorithm>
#include <numeric>
#include "src/Services/StringService.hpp"
namespace Widgets::PinoutWidgets
{
DipPinout::DipPinout(
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const PinoutState& pinoutState
)
: packageBodySize({
(Pin::WIDTH + DipPinout::PIN_MARGIN) * static_cast<int>(pinoutDescriptor.pinDescriptors.size() / 2)
- DipPinout::PIN_MARGIN + (DipPinout::PACKAGE_PADDING * 2),
std::max(
std::min(static_cast<int>(pinoutDescriptor.pinDescriptors.size()) * 8, DipPinout::MAX_PACKAGE_HEIGHT),
DipPinout::MIN_PACKAGE_HEIGHT
)
})
, packageBodyPosition({})
, pinoutDescriptor(pinoutDescriptor)
, pinoutState(pinoutState)
{
assert((pinoutDescriptor.pinDescriptors.size() % 2) == 0);
auto sortedPinDescriptors = std::vector<const Targets::TargetPinDescriptor*>{};
sortedPinDescriptors.reserve(pinoutDescriptor.pinDescriptors.size());
std::transform(
pinoutDescriptor.pinDescriptors.begin(),
pinoutDescriptor.pinDescriptors.end(),
std::back_inserter(sortedPinDescriptors),
[] (const auto& pinDescriptor) {
return &pinDescriptor;
}
);
std::sort(
sortedPinDescriptors.begin(),
sortedPinDescriptors.end(),
[] (const Targets::TargetPinDescriptor* descA, const Targets::TargetPinDescriptor* descB) {
return
Services::StringService::toUint16(descA->position, 10)
< Services::StringService::toUint16(descB->position, 10);
}
);
this->bottomQuadrantLabelGroupSet->setParentItem(this);
this->topQuadrantLabelGroupSet->setParentItem(this);
const auto setSize = sortedPinDescriptors.size() / 2;
for (auto i = std::size_t{0}; i < setSize; i++) {
// Bottom pins
const auto& pinDescriptor = *sortedPinDescriptors[i];
auto* labelGroup = new VerticalLabelGroup{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
this->pinoutState
};
labelGroup->setParentItem(this->bottomQuadrantLabelGroupSet);
this->bottomQuadrantLabelGroupSet->labelGroups.emplace_back(labelGroup);
auto* pin = new Pin{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
Pin::Orientation::VERTICAL,
this->pinoutState
};
pin->setParentItem(this);
this->bottomLabelGroupPinPairs.emplace_back(
VerticalLabelGroupPinPair{.labelGroup = labelGroup, .pin = pin}
);
}
for (auto i = setSize; i < (setSize * 2); i++) {
// Top pins
const auto& pinDescriptor = *sortedPinDescriptors[i];
auto* labelGroup = new VerticalLabelGroup{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
this->pinoutState
};
labelGroup->setParentItem(this->topQuadrantLabelGroupSet);
this->topQuadrantLabelGroupSet->labelGroups.emplace_back(labelGroup);
auto* pin = new Pin{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
Pin::Orientation::VERTICAL,
this->pinoutState
};
pin->setParentItem(this);
this->topLabelGroupPinPairs.emplace_back(
VerticalLabelGroupPinPair{.labelGroup = labelGroup, .pin = pin}
);
}
}
std::vector<Pair<
const Targets::TargetPadDescriptor&,
LabelGroupInterface*
>> DipPinout::padDescriptorLabelGroupPairs() {
auto output = std::vector<Pair<const Targets::TargetPadDescriptor&, LabelGroupInterface*>>{};
for (auto& [labelGroup, pin] : this->bottomLabelGroupPinPairs) {
if (!pin->padDescriptor.has_value()) {
continue;
}
output.emplace_back(pin->padDescriptor->get(), labelGroup);
}
for (auto& [labelGroup, pin] : this->topLabelGroupPinPairs) {
if (!pin->padDescriptor.has_value()) {
continue;
}
output.emplace_back(pin->padDescriptor->get(), labelGroup);
}
return output;
}
void DipPinout::refreshGeometry() {
this->bottomQuadrantLabelGroupSet->refreshGeometry();
this->topQuadrantLabelGroupSet->refreshGeometry();
const auto setSize = this->pinoutDescriptor.pinDescriptors.size() / 2;
const auto maxVerticalPinLineAHeight = static_cast<int>(
DipPinout::MIN_LINE_A_LENGTH + (DipPinout::PIN_LINE_A_SPACING
* std::ceil(static_cast<float>(setSize) / static_cast<float>(2)))
);
this->packageBodyPosition.setX(
std::max(this->bottomQuadrantLabelGroupSet->size.width(), this->topQuadrantLabelGroupSet->size.width()) / 2
- (this->packageBodySize.width() / 2)
);
this->packageBodyPosition.setY(
this->topQuadrantLabelGroupSet->size.height()
+ maxVerticalPinLineAHeight + DipPinout::PIN_LINE_MARGIN + Pin::HEIGHT + DipPinout::PIN_MARGIN
);
this->size.setWidth(
std::max(this->bottomQuadrantLabelGroupSet->size.width(), this->topQuadrantLabelGroupSet->size.width())
);
this->size.setHeight(
this->topQuadrantLabelGroupSet->size.height() + this->packageBodySize.height()
+ ((maxVerticalPinLineAHeight + DipPinout::PIN_LINE_MARGIN + Pin::HEIGHT + DipPinout::PIN_MARGIN) * 2)
+ this->bottomQuadrantLabelGroupSet->size.height()
);
// Position the pins
auto bottomPinXPosition = this->packageBodyPosition.x() + DipPinout::PACKAGE_PADDING;
for (auto& [labelGroup, pin] : this->bottomLabelGroupPinPairs) {
pin->setPos(
bottomPinXPosition,
this->packageBodyPosition.y() + this->packageBodySize.height() + DipPinout::PIN_MARGIN
);
bottomPinXPosition += Pin::WIDTH + DipPinout::PIN_MARGIN;
}
auto topPinXPosition = this->packageBodyPosition.x() + this->packageBodySize.width()
- DipPinout::PACKAGE_PADDING - Pin::WIDTH;
for (auto& [labelGroup, pin] : this->topLabelGroupPinPairs) {
pin->setPos(
topPinXPosition,
this->packageBodyPosition.y() - DipPinout::PIN_MARGIN - Pin::HEIGHT
);
topPinXPosition -= Pin::WIDTH + DipPinout::PIN_MARGIN;
}
this->topQuadrantLabelGroupSet->setPos(
this->packageBodyPosition.x() + (this->packageBodySize.width() / 2)
- (this->topQuadrantLabelGroupSet->size.width() / 2),
0
);
this->bottomQuadrantLabelGroupSet->setPos(
this->packageBodyPosition.x() + (this->packageBodySize.width() / 2)
- (this->bottomQuadrantLabelGroupSet->size.width() / 2),
this->packageBodyPosition.y() + this->packageBodySize.height() + DipPinout::PIN_MARGIN + Pin::HEIGHT
+ DipPinout::PIN_LINE_MARGIN + maxVerticalPinLineAHeight
);
}
QRectF DipPinout::boundingRect() const {
return QRectF{QPointF{0, 0}, this->size};
}
void DipPinout::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static constexpr auto BODY_COLOR = QColor{0x7D, 0x7D, 0x7D};
static constexpr auto DISABLED_BODY_COLOR = QColor{0x7D, 0x7D, 0x7D, 153};
static constexpr auto BG_COLOR = QColor{0x37, 0x38, 0x35};
static constexpr auto LINE_COLOR = QColor{0x5E, 0x5C, 0x59};
static constexpr auto HIGHLIGHTED_LINE_COLOR = QColor{0x7D, 0x7D, 0x7D};
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
painter->setBrush(!this->isEnabled() ? DISABLED_BODY_COLOR : BODY_COLOR);
painter->setPen(Qt::PenStyle::NoPen);
// Package body
painter->drawRect(
this->packageBodyPosition.x(),
this->packageBodyPosition.y(),
this->packageBodySize.width(),
this->packageBodySize.height()
);
painter->setBrush(BG_COLOR);
painter->drawEllipse(
this->packageBodyPosition.x() - (DipPinout::P1_EDGE_INDICATOR_DIAMETER / 2),
this->packageBodyPosition.y() + (this->packageBodySize.height() / 2)
- (DipPinout::P1_EDGE_INDICATOR_DIAMETER / 2),
DipPinout::P1_EDGE_INDICATOR_DIAMETER,
DipPinout::P1_EDGE_INDICATOR_DIAMETER
);
painter->drawEllipse(
this->packageBodyPosition.x() + DipPinout::P1_INDICATOR_MARGIN,
this->packageBodyPosition.y() + this->packageBodySize.height() - DipPinout::P1_INDICATOR_DIAMETER
- DipPinout::P1_INDICATOR_MARGIN,
DipPinout::P1_INDICATOR_DIAMETER,
DipPinout::P1_INDICATOR_DIAMETER
);
painter->setRenderHints(QPainter::RenderHint::Antialiasing, false);
// Pin lines
const auto setSize = this->pinoutDescriptor.pinDescriptors.size() / 2;
{
// Bottom pin lines
auto lineAEndYOffset = int{0};
for (auto pinIndex = std::size_t{0}; pinIndex < this->bottomLabelGroupPinPairs.size(); ++pinIndex) {
const auto* pin = this->bottomLabelGroupPinPairs[pinIndex].pin;
const auto* labelGroup = this->bottomLabelGroupPinPairs[pinIndex].labelGroup;
painter->setPen(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == pin->number
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR
);
const auto lineAStartX = static_cast<int>(pin->pos().x() + (Pin::WIDTH / 2));
const auto lineAStartY = static_cast<int>(pin->pos().y() + Pin::HEIGHT + DipPinout::PIN_LINE_MARGIN);
const auto lineAEndY = static_cast<int>(lineAStartY + DipPinout::MIN_LINE_A_LENGTH + lineAEndYOffset);
painter->drawLine(lineAStartX, lineAStartY, lineAStartX, lineAEndY);
if (setSize % 2 != 0 || pinIndex != (setSize / 2 - 1)) {
lineAEndYOffset = pinIndex <= (setSize / 2 - 1)
? lineAEndYOffset + DipPinout::PIN_LINE_A_SPACING
: lineAEndYOffset - DipPinout::PIN_LINE_A_SPACING;
}
const auto lineBStartX = lineAStartX;
const auto lineBEndX = static_cast<int>(
this->bottomQuadrantLabelGroupSet->pos().x() + labelGroup->pos().x()
+ (labelGroup->size.width() / 2)
);
const auto lineBStartY = lineAEndY;
painter->drawLine(lineBStartX, lineBStartY, lineBEndX, lineBStartY);
const auto lineCStartX = lineBEndX;
const auto lineCStartY = lineBStartY;
const auto lineCEndY = static_cast<int>(
this->bottomQuadrantLabelGroupSet->pos().y() + labelGroup->pos().y() - 5
);
painter->drawLine(lineCStartX, lineCStartY, lineCStartX, lineCEndY);
}
}
{
// Top pin lines
auto lineAEndYOffset = int{0};
for (auto pinIndex = std::size_t{0}; pinIndex < this->topLabelGroupPinPairs.size(); ++pinIndex) {
const auto* pin = this->topLabelGroupPinPairs[pinIndex].pin;
const auto* labelGroup = this->topLabelGroupPinPairs[pinIndex].labelGroup;
painter->setPen(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == pin->number
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR
);
const auto lineAStartX = static_cast<int>(pin->pos().x() + (Pin::WIDTH / 2));
const auto lineAStartY = static_cast<int>(pin->pos().y() - DipPinout::PIN_LINE_MARGIN);
const auto lineAEndY = lineAStartY - (DipPinout::MIN_LINE_A_LENGTH + lineAEndYOffset);
painter->drawLine(lineAStartX, lineAStartY, lineAStartX, lineAEndY);
if (setSize % 2 != 0 || pinIndex != (setSize / 2 - 1)) {
lineAEndYOffset = pinIndex <= (setSize / 2 - 1)
? lineAEndYOffset + DipPinout::PIN_LINE_A_SPACING
: lineAEndYOffset - DipPinout::PIN_LINE_A_SPACING;
}
const auto lineBStartX = lineAStartX;
const auto lineBEndX = static_cast<int>(
this->topQuadrantLabelGroupSet->pos().x() + labelGroup->pos().x()
+ (labelGroup->size.width() / 2)
);
const auto lineBStartY = lineAEndY;
painter->drawLine(lineBStartX, lineBStartY, lineBEndX, lineBStartY);
const auto lineCStartX = lineBEndX;
const auto lineCStartY = lineBStartY;
const auto lineCEndY = static_cast<int>(
this->topQuadrantLabelGroupSet->pos().y() + labelGroup->pos().y() + labelGroup->size.height() + 5
);
painter->drawLine(lineCStartX, lineCStartY, lineCStartX, lineCEndY);
}
}
}
}

View File

@@ -0,0 +1,70 @@
#pragma once
#include <QSize>
#include <QPoint>
#include <QPainter>
#include <vector>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinoutItem.hpp"
#include "src/Targets/TargetPinoutDescriptor.hpp"
#include "src/Targets/TargetDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinoutState.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/Pin.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/LabelGroupInterface.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroup.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroupSet.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroupPinPair.hpp"
#include "src/Helpers/Pair.hpp"
namespace Widgets::PinoutWidgets
{
class DipPinout: public PinoutItem
{
public:
static constexpr int PACKAGE_PADDING = 15;
static constexpr int MAX_PACKAGE_HEIGHT = 88;
static constexpr int MIN_PACKAGE_HEIGHT = 65;
static constexpr int PIN_MARGIN = 2;
static constexpr int PIN_LINE_A_SPACING = 15;
static constexpr int PIN_LINE_MARGIN = 5;
static constexpr int MIN_LINE_A_LENGTH = 10;
static constexpr int P1_INDICATOR_DIAMETER = 12;
static constexpr int P1_INDICATOR_MARGIN = 8;
static constexpr int P1_EDGE_INDICATOR_DIAMETER = 18;
QSize size = {};
QSize packageBodySize;
QPoint packageBodyPosition;
DipPinout(
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const PinoutState& pinoutState
);
std::vector<Pair<const Targets::TargetPadDescriptor&, LabelGroupInterface*>> padDescriptorLabelGroupPairs();
void refreshGeometry() override;
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
const Targets::TargetPinoutDescriptor& pinoutDescriptor;
const PinoutState& pinoutState;
VerticalLabelGroupSet* topQuadrantLabelGroupSet = new VerticalLabelGroupSet{
VerticalLabelGroupSet::Position::TOP
};
VerticalLabelGroupSet* bottomQuadrantLabelGroupSet = new VerticalLabelGroupSet{
VerticalLabelGroupSet::Position::BOTTOM
};
std::vector<VerticalLabelGroupPinPair> topLabelGroupPinPairs = {};
std::vector<VerticalLabelGroupPinPair> bottomLabelGroupPinPairs = {};
};
}

View File

@@ -0,0 +1,17 @@
#include "GpioDirectionLabel.hpp"
namespace Widgets::PinoutWidgets
{
GpioDirectionLabel::GpioDirectionLabel(const Targets::TargetGpioPadState& padeState)
: padeState(padeState)
{}
const QString& GpioDirectionLabel::text() const {
static const auto INPUT_TEXT = QString{"INPUT"};
static const auto OUTPUT_TEXT = QString{"OUTPUT"};
return this->padeState.direction == Targets::TargetGpioPadState::DataDirection::INPUT
? INPUT_TEXT
: OUTPUT_TEXT;
}
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "Label.hpp"
#include "src/Targets/TargetGpioPadState.hpp"
namespace Widgets::PinoutWidgets
{
class GpioDirectionLabel: public Label
{
public:
explicit GpioDirectionLabel(const Targets::TargetGpioPadState& padeState);
[[nodiscard]] const QString& text() const override;
protected:
const Targets::TargetGpioPadState& padeState;
};
}

View File

@@ -0,0 +1,9 @@
#include "GpioDisabledLabel.hpp"
namespace Widgets::PinoutWidgets
{
const QString& GpioDisabledLabel::text() const {
static const auto TEXT = QString{"GPIO PORT DISABLED"};
return TEXT;
}
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include "Label.hpp"
namespace Widgets::PinoutWidgets
{
class GpioDisabledLabel: public Label
{
public:
[[nodiscard]] const QString& text() const override;
};
}

View File

@@ -0,0 +1,22 @@
#include "GpioStateLabel.hpp"
namespace Widgets::PinoutWidgets
{
GpioStateLabel::GpioStateLabel(const Targets::TargetGpioPadState& padeState)
: padeState(padeState)
{}
const QString& GpioStateLabel::text() const {
static const auto HIGH_TEXT = QString{"HIGH"};
static const auto LOW_TEXT = QString{"LOW"};
return this->padeState.value == Targets::TargetGpioPadState::State::HIGH
? HIGH_TEXT
: LOW_TEXT;
}
const QColor& GpioStateLabel::rectColor() const {
static constexpr auto RECT_COLOR = QColor{0x52, 0x46, 0x52};
return RECT_COLOR;
}
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include "Label.hpp"
#include "src/Targets/TargetGpioPadState.hpp"
namespace Widgets::PinoutWidgets
{
class GpioStateLabel: public Label
{
public:
explicit GpioStateLabel(const Targets::TargetGpioPadState& padeState);
[[nodiscard]] const QString& text() const override;
protected:
const Targets::TargetGpioPadState& padeState;
[[nodiscard]] const QColor& rectColor() const override;
};
}

View File

@@ -0,0 +1,108 @@
#include "HorizontalLabelGroup.hpp"
#include "src/Services/StringService.hpp"
namespace Widgets::PinoutWidgets
{
HorizontalLabelGroup::HorizontalLabelGroup(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
Direction direction,
const PinoutState& pinoutState
)
: pinDescriptor(pinDescriptor)
, padDescriptor(padDescriptor)
, pinNumber(Services::StringService::toUint16(this->pinDescriptor.position, 10))
, size({0, 0})
, direction(direction)
, pinoutState(pinoutState)
, pinNumberLabel(PinNumberLabel{this->pinDescriptor})
, padNameLabel(PadNameLabel{this->padDescriptor})
{}
void HorizontalLabelGroup::insertLabel(std::unique_ptr<Label>&& label) {
this->secondaryLabels.emplace_back(std::move(label));
}
void HorizontalLabelGroup::refreshGeometry() {
this->enabledSecondaryLabels.clear();
this->pinNumberLabel.refreshGeometry();
this->padNameLabel.refreshGeometry();
if (this->pinNumberLabel.width < HorizontalLabelGroup::MIN_PIN_NUMBER_LABEL_WIDTH) {
this->pinNumberLabel.width = HorizontalLabelGroup::MIN_PIN_NUMBER_LABEL_WIDTH;
}
if (this->padNameLabel.width < HorizontalLabelGroup::MIN_LABEL_WIDTH) {
this->padNameLabel.width = HorizontalLabelGroup::MIN_LABEL_WIDTH;
}
auto totalWidth = this->pinNumberLabel.width + HorizontalLabelGroup::LABEL_MARGIN + this->padNameLabel.width
+ (!this->secondaryLabels.empty() ? HorizontalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING : 0);
for (const auto& secondaryLabel : this->secondaryLabels) {
if (!secondaryLabel->enabled) {
continue;
}
this->enabledSecondaryLabels.emplace_back(secondaryLabel.get());
secondaryLabel->refreshGeometry();
if (secondaryLabel->width < HorizontalLabelGroup::MIN_LABEL_WIDTH) {
secondaryLabel->width = HorizontalLabelGroup::MIN_LABEL_WIDTH;
}
totalWidth += HorizontalLabelGroup::LABEL_MARGIN + secondaryLabel->width;
}
this->size.setWidth(totalWidth);
this->size.setHeight(Label::HEIGHT);
}
QRectF HorizontalLabelGroup::boundingRect() const {
return QRectF{QPointF{0, 0}, this->size};
}
void HorizontalLabelGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static constexpr auto LINE_COLOR = QColor{0x5E, 0x5C, 0x59};
painter->setOpacity(this->isEnabled() ? 1 : 0.6);
painter->setPen(Qt::PenStyle::NoPen);
auto xPos = int{0};
this->pinNumberLabel.paint(painter, this->transformLabelXPos(xPos, this->pinNumberLabel), 0);
xPos += this->pinNumberLabel.width + HorizontalLabelGroup::LABEL_MARGIN;
this->padNameLabel.paint(painter, this->transformLabelXPos(xPos, this->padNameLabel), 0);
xPos += this->padNameLabel.width + HorizontalLabelGroup::LABEL_MARGIN;
if (!this->enabledSecondaryLabels.empty()) {
painter->setPen(LINE_COLOR);
static constexpr auto centerY = Label::HEIGHT / 2;
const auto separatorLineXStart = this->direction == Direction::LEFT ? this->size.width() - xPos : xPos;
painter->drawLine(
separatorLineXStart,
centerY,
separatorLineXStart + (
this->direction == Direction::LEFT
? (HorizontalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING * -1) + HorizontalLabelGroup::LABEL_MARGIN
: HorizontalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING - HorizontalLabelGroup::LABEL_MARGIN
),
centerY
);
painter->setPen(Qt::PenStyle::NoPen);
xPos += HorizontalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING;
for (const auto& label : this->enabledSecondaryLabels) {
label->paint(painter, this->transformLabelXPos(xPos, *label), 0);
xPos += label->width + HorizontalLabelGroup::LABEL_MARGIN;
}
}
}
int HorizontalLabelGroup::transformLabelXPos(int xPos, const Label& label) const {
return this->direction == Direction::LEFT ? this->size.width() - xPos - label.width : xPos;
}
}

View File

@@ -0,0 +1,69 @@
#pragma once
#include <QGraphicsItem>
#include <QSize>
#include <QRectF>
#include <QPainter>
#include <functional>
#include <vector>
#include <memory>
#include "src/Targets/TargetPinDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "LabelGroupInterface.hpp"
#include "PinoutState.hpp"
#include "Label.hpp"
#include "PinNumberLabel.hpp"
#include "PadNameLabel.hpp"
namespace Widgets::PinoutWidgets
{
class HorizontalLabelGroup
: public LabelGroupInterface
, public QGraphicsItem
{
public:
static constexpr int LABEL_MARGIN = 4;
static constexpr int MIN_PIN_NUMBER_LABEL_WIDTH = 45;
static constexpr int MIN_LABEL_WIDTH = 55;
static constexpr int SECONDARY_LABEL_SEPARATOR_SPACING = 10;
enum Direction: std::uint8_t
{
LEFT,
RIGHT,
};
const Targets::TargetPinDescriptor& pinDescriptor;
const std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor;
std::uint16_t pinNumber;
QSize size = {};
const Direction direction;
HorizontalLabelGroup(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
Direction direction,
const PinoutState& pinoutState
);
void insertLabel(std::unique_ptr<Label>&& label) override;
void refreshGeometry();
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
const PinoutState& pinoutState;
PinNumberLabel pinNumberLabel;
PadNameLabel padNameLabel;
std::vector<std::unique_ptr<Label>> secondaryLabels;
std::vector<Label*> enabledSecondaryLabels;
[[nodiscard]] inline int transformLabelXPos(
int xPos,
const Label& label
) const __attribute__((__always_inline__));
};
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "HorizontalLabelGroup.hpp"
#include "Pin.hpp"
namespace Widgets::PinoutWidgets
{
struct HorizontalLabelGroupPinPair
{
HorizontalLabelGroup* labelGroup;
Pin* pin;
};
}

View File

@@ -0,0 +1,55 @@
#include "HorizontalLabelGroupSet.hpp"
#include <algorithm>
#include <ranges>
#include <QPoint>
namespace Widgets::PinoutWidgets
{
HorizontalLabelGroupSet::HorizontalLabelGroupSet(Position position)
: labelGroups({})
, size({0, 0})
, position(position)
{}
void HorizontalLabelGroupSet::refreshGeometry() {
auto maxWidth = int{0};
for (auto* labelGroup : this->labelGroups) {
labelGroup->refreshGeometry();
maxWidth = std::max(labelGroup->size.width(), maxWidth);
}
auto yPos = int{0};
const auto positionLabelGroup = [&] (HorizontalLabelGroup* labelGroup) {
labelGroup->setPos(
this->position == HorizontalLabelGroupSet::Position::LEFT ? maxWidth - labelGroup->size.width() : 0,
yPos
);
yPos += labelGroup->size.height() + HorizontalLabelGroupSet::GROUP_VERTICAL_MARGIN;
};
if (this->position == Position::RIGHT) {
for (auto groupIt = this->labelGroups.rbegin(); groupIt < this->labelGroups.rend(); ++groupIt) {
positionLabelGroup(*groupIt);
}
} else {
for (auto groupIt = this->labelGroups.begin(); groupIt < this->labelGroups.end(); ++groupIt) {
positionLabelGroup(*groupIt);
}
}
this->size.setWidth(maxWidth);
this->size.setHeight(yPos - HorizontalLabelGroupSet::GROUP_VERTICAL_MARGIN);
}
QRectF HorizontalLabelGroupSet::boundingRect() const {
return QRectF{QPointF{0, 0}, this->size};
}
void HorizontalLabelGroupSet::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
// Nothing to do here...
}
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <QGraphicsItem>
#include <QSize>
#include <QRectF>
#include <QPainter>
#include <vector>
#include "HorizontalLabelGroup.hpp"
namespace Widgets::PinoutWidgets
{
class HorizontalLabelGroupSet: public QGraphicsItem
{
public:
static constexpr int GROUP_VERTICAL_MARGIN = 5;
enum Position: std::uint8_t
{
LEFT,
RIGHT
};
std::vector<HorizontalLabelGroup*> labelGroups;
QSize size;
const Position position;
explicit HorizontalLabelGroupSet(Position position);
void refreshGeometry();
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
};
}

View File

@@ -0,0 +1,45 @@
#include "Label.hpp"
namespace Widgets::PinoutWidgets
{
void Label::refreshGeometry() {
this->minimumWidth = Label::FONT_METRICS.boundingRect(this->text()).width() + (Label::HORIZ_PADDING * 2);
this->width = this->minimumWidth;
}
void Label::paint(QPainter* painter, int startX, int startY) const {
painter->setFont(Label::FONT);
painter->setBrush(this->rectColor());
painter->setPen(Qt::PenStyle::NoPen);
const auto rect = QRect{startX, startY, this->width, Label::HEIGHT};
painter->drawRect(rect);
painter->setPen(this->changed ? this->changedFontColor() : this->fontColor());
painter->drawText(rect, Qt::AlignCenter, this->text());
}
const QColor& Label::rectColor() const {
static constexpr auto RECT_COLOR = QColor{0x42, 0x42, 0x42};
return RECT_COLOR;
}
const QColor& Label::fontColor() const {
static constexpr auto FONT_COLOR = QColor{0xA2, 0xA2, 0xA2};
return FONT_COLOR;
}
const QColor& Label::changedFontColor() const {
/*
* I spent a considerable amount of time attempting to find a good font color for highlighting changes.
* I failed miserably. Have given up, for now.
*
* TODO: Revisit after v2.0.0
*/
return this->fontColor();
// static constexpr auto FONT_COLOR = QColor{0x54, 0x7F, 0xBA};
// return FONT_COLOR;
}
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include <cstddef>
#include <QGraphicsItem>
#include <QString>
#include <QFont>
#include <QFontMetrics>
#include <QPainter>
namespace Widgets::PinoutWidgets
{
class Label
{
public:
static constexpr int HEIGHT = 22;
static constexpr int FONT_SIZE_POINTS = 8;
static constexpr int HORIZ_PADDING = 10;
int minimumWidth = 0;
int width = 0;
/*
* This flag isn't respected for pin number and pad name labels. Not a big deal, as we don't currently disable
* them. Will fix later, if necessary.
*/
bool enabled = true;
bool changed = false;
Label() = default;
virtual ~Label() = default;
[[nodiscard]] virtual const QString& text() const = 0;
void refreshGeometry();
virtual void paint(QPainter* painter, int startX, int startY) const;
protected:
static const inline auto FONT = QFont{"'Ubuntu', sans-serif", Label::FONT_SIZE_POINTS, QFont::Normal};
static const inline auto FONT_METRICS = QFontMetrics{Label::FONT};
[[nodiscard]] virtual const QColor& rectColor() const;
[[nodiscard]] virtual const QColor& fontColor() const;
[[nodiscard]] virtual const QColor& changedFontColor() const;
};
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <memory>
#include "Label.hpp"
namespace Widgets::PinoutWidgets
{
class LabelGroupInterface
{
public:
virtual ~LabelGroupInterface() = default;
virtual void insertLabel(std::unique_ptr<Label>&& label) = 0;
};
}

View File

@@ -0,0 +1,18 @@
#include "PadLabels.hpp"
namespace Widgets::PinoutWidgets
{
void PadLabels::disableGpioLabels() const {
if (this->gpioDirection != nullptr) {
this->gpioDirection->enabled = false;
}
if (this->gpioState != nullptr) {
this->gpioState->enabled = false;
}
if (this->gpioDisabled != nullptr) {
this->gpioDisabled->enabled = false;
}
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "GpioDirectionLabel.hpp"
#include "GpioStateLabel.hpp"
#include "GpioDisabledLabel.hpp"
namespace Widgets::PinoutWidgets
{
struct PadLabels
{
GpioDirectionLabel* gpioDirection = nullptr;
GpioStateLabel* gpioState = nullptr;
GpioDisabledLabel* gpioDisabled = nullptr;
void disableGpioLabels() const;
};
}

View File

@@ -0,0 +1,26 @@
#include "PadNameLabel.hpp"
namespace Widgets::PinoutWidgets
{
PadNameLabel::PadNameLabel(std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor)
: padName(
padDescriptor.has_value()
? QString::fromStdString(padDescriptor->get().name)
: "NOT CONNECTED"
)
{}
const QString& PadNameLabel::text() const {
return this->padName;
}
const QColor& PadNameLabel::rectColor() const {
static constexpr auto RECT_COLOR = QColor{0x38, 0x46, 0x45};
return RECT_COLOR;
}
const QColor& PadNameLabel::fontColor() const {
static constexpr auto FONT_COLOR = QColor{0xA0, 0xA0, 0xA0};
return FONT_COLOR;
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <functional>
#include <optional>
#include "Label.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
namespace Widgets::PinoutWidgets
{
class PadNameLabel: public Label
{
public:
explicit PadNameLabel(std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor);
[[nodiscard]] const QString& text() const override;
protected:
QString padName;
[[nodiscard]] const QColor& rectColor() const override;
[[nodiscard]] const QColor& fontColor() const override;
};
}

View File

@@ -0,0 +1,51 @@
#include "Pin.hpp"
#include "src/Services/StringService.hpp"
namespace Widgets::PinoutWidgets
{
Pin::Pin(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
Orientation orientation,
const PinoutState& pinoutState
)
: pinDescriptor(pinDescriptor)
, padDescriptor(padDescriptor)
, orientation(orientation)
, number(Services::StringService::toUint16(this->pinDescriptor.position, 10))
, pinoutState(pinoutState)
{}
QRectF Pin::boundingRect() const {
return QRectF{
QPointF{0, 0},
this->orientation == Orientation::VERTICAL
? QSize{Pin::WIDTH, Pin::HEIGHT}
: QSize{Pin::HEIGHT, Pin::WIDTH}
};
}
void Pin::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
using Targets::TargetPadType;
static constexpr auto DEFAULT_COLOR = QColor{0x7D, 0x7D, 0x7D};
static constexpr auto HIGHLIGHT_COLOR = QColor{0x53, 0x67, 0x5D};
painter->setBrush(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == this->number
? HIGHLIGHT_COLOR
: DEFAULT_COLOR
);
painter->setPen(Qt::PenStyle::NoPen);
painter->setOpacity(this->isEnabled() ? 1 : 0.6);
if (this->orientation == Orientation::VERTICAL) {
painter->drawRect(0, 0, Pin::WIDTH, Pin::HEIGHT);
} else {
painter->drawRect(0, 0, Pin::HEIGHT, Pin::WIDTH);
}
}
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include <QGraphicsItem>
#include <QSize>
#include <QRectF>
#include <QPainter>
#include <functional>
#include "src/Targets/TargetPinDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "PinoutState.hpp"
namespace Widgets::PinoutWidgets
{
class Pin: public QGraphicsItem
{
public:
static constexpr int WIDTH = 11;
static constexpr int HEIGHT = 17;
enum Orientation: std::uint8_t
{
VERTICAL,
HORIZONTAL
};
const Targets::TargetPinDescriptor& pinDescriptor;
const std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor;
const Orientation orientation;
std::uint16_t number;
Pin(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
Orientation orientation,
const PinoutState& pinoutState
);
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
protected:
const PinoutState& pinoutState;
};
}

View File

@@ -0,0 +1,22 @@
#include "PinNumberLabel.hpp"
namespace Widgets::PinoutWidgets
{
PinNumberLabel::PinNumberLabel(const Targets::TargetPinDescriptor& pinDescriptor)
: pinNumber(QString::fromStdString(pinDescriptor.position))
{}
const QString& PinNumberLabel::text() const {
return this->pinNumber;
}
const QColor& PinNumberLabel::rectColor() const {
static constexpr auto RECT_COLOR = QColor{0x40, 0x53, 0x51};
return RECT_COLOR;
}
const QColor& PinNumberLabel::fontColor() const {
static constexpr auto FONT_COLOR = QColor{0xA8, 0xA8, 0xA8};
return FONT_COLOR;
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "Label.hpp"
#include "src/Targets/TargetPinDescriptor.hpp"
namespace Widgets::PinoutWidgets
{
class PinNumberLabel: public Label
{
public:
explicit PinNumberLabel(const Targets::TargetPinDescriptor& pinDescriptor);
[[nodiscard]] const QString& text() const override;
protected:
QString pinNumber;
[[nodiscard]] const QColor& rectColor() const override;
[[nodiscard]] const QColor& fontColor() const override;
};
}

View File

@@ -0,0 +1,52 @@
#include "PinoutContainer.hpp"
namespace Widgets::PinoutWidgets
{
PinoutContainer::PinoutContainer(const Targets::TargetDescriptor& targetDescriptor, QWidget* parent)
: QGraphicsView(parent)
, pinoutScene(new PinoutScene{targetDescriptor, this})
, targetDescriptor(targetDescriptor)
{
this->setObjectName("pinout-widget-container");
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
this->setViewportUpdateMode(QGraphicsView::ViewportUpdateMode::MinimalViewportUpdate);
this->setFrameShape(QFrame::NoFrame);
this->setDragMode(QGraphicsView::DragMode::NoDrag);
this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
this->setMouseTracking(true);
this->setScene(this->pinoutScene);
}
void PinoutContainer::resizeEvent(QResizeEvent* event) {
QGraphicsView::resizeEvent(event);
}
void PinoutContainer::keyPressEvent(QKeyEvent* event) {
const auto viewSize = this->size();
const auto sceneRect = this->pinoutScene->sceneRect();
const auto key = event->key();
if (key == Qt::Key_Control) {
this->setDragMode(
sceneRect.width() > viewSize.width() || sceneRect.height() > viewSize.height()
? QGraphicsView::DragMode::ScrollHandDrag
: QGraphicsView::DragMode::NoDrag
);
return;
}
QGraphicsView::keyPressEvent(event);
}
void PinoutContainer::keyReleaseEvent(QKeyEvent* event) {
const auto key = event->key();
if (key == Qt::Key_Control) {
this->setDragMode(QGraphicsView::DragMode::NoDrag);
}
QGraphicsView::keyReleaseEvent(event);
}
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <QGraphicsView>
#include <QResizeEvent>
#include <QKeyEvent>
#include "src/Targets/TargetDescriptor.hpp"
#include "PinoutScene.hpp"
namespace Widgets::PinoutWidgets
{
class PinoutContainer: public QGraphicsView
{
Q_OBJECT
public:
PinoutScene* pinoutScene;
PinoutContainer(const Targets::TargetDescriptor& targetDescriptor, QWidget* parent);
void resizeEvent(QResizeEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
protected:
const Targets::TargetDescriptor& targetDescriptor;
};
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <QGraphicsItem>
namespace Widgets::PinoutWidgets
{
class PinoutItem: public QGraphicsItem
{
public:
virtual void refreshGeometry() = 0;
};
}

View File

@@ -0,0 +1,414 @@
#include "PinoutScene.hpp"
#include <cassert>
#include <ranges>
#include <memory>
#include <utility>
#include <QAction>
#include "Qfp/QfpPinout.hpp"
#include "Dip/DipPinout.hpp"
#include "GpioDirectionLabel.hpp"
#include "GpioStateLabel.hpp"
#include "GpioDisabledLabel.hpp"
#include "VerticalLabelGroup.hpp"
#include "HorizontalLabelGroup.hpp"
#include "Pin.hpp"
#include "src/Insight/InsightSignals.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "src/Insight/InsightWorker/Tasks/ReadTargetGpioPadStates.hpp"
#include "src/Insight/InsightWorker/Tasks/SetTargetGpioPadState.hpp"
namespace Widgets::PinoutWidgets
{
using Targets::TargetGpioPadState;
PinoutScene::PinoutScene(const Targets::TargetDescriptor& targetDescriptor, QGraphicsView* parent)
: QGraphicsScene(parent)
, parentView(parent)
, targetDescriptor(targetDescriptor)
{
for (const auto& padDescriptor : std::views::values(this->targetDescriptor.padDescriptorsByKey)) {
if (padDescriptor.type != Targets::TargetPadType::GPIO) {
continue;
}
this->gpioPadDescriptors.emplace_back(&padDescriptor);
this->gpioPadStatesByPadId.emplace(
padDescriptor.id,
TargetGpioPadState{
.disabled = true,
.value = TargetGpioPadState::State::UNKNOWN,
.direction = TargetGpioPadState::DataDirection::UNKNOWN,
}
);
}
}
bool PinoutScene::isPinoutSupported(const Targets::TargetPinoutDescriptor& pinoutDescriptor) {
using Targets::TargetPinoutType;
const auto pinCount = pinoutDescriptor.pinDescriptors.size();
// return pinoutDescriptor.type == TargetPinoutType::QFP || pinoutDescriptor.type == TargetPinoutType::QFN;
if (pinCount > 100) {
return false;
}
if (
pinoutDescriptor.type != TargetPinoutType::DIP
&& pinoutDescriptor.type != TargetPinoutType::SOIC
&& pinoutDescriptor.type != TargetPinoutType::SSOP
&& pinoutDescriptor.type != TargetPinoutType::QFP
&& pinoutDescriptor.type != TargetPinoutType::QFN
) {
return false;
}
if (
(
pinoutDescriptor.type == TargetPinoutType::DIP
|| pinoutDescriptor.type == TargetPinoutType::SOIC
|| pinoutDescriptor.type == TargetPinoutType::SSOP
)
&& pinCount % 2 != 0
) {
return false;
}
if (
(pinoutDescriptor.type == TargetPinoutType::QFP || pinoutDescriptor.type == TargetPinoutType::QFN)
&& (pinCount % 4 != 0 || pinCount <= 4)
) {
return false;
}
return true;
}
void PinoutScene::setPinout(const Targets::TargetPinoutDescriptor& pinoutDescriptor) {
using Targets::TargetPinoutType;
assert(this->isPinoutSupported(pinoutDescriptor));
this->padLabelsByPadId.clear();
if (this->pinoutItem != nullptr) {
this->removeItem(this->pinoutItem);
delete this->pinoutItem;
this->pinoutItem = nullptr;
}
if (pinoutDescriptor.type == TargetPinoutType::QFP || pinoutDescriptor.type == TargetPinoutType::QFN) {
auto* pinoutItem = new QfpPinout{pinoutDescriptor, this->targetDescriptor, this->pinoutState};
this->populatePadLabels(pinoutItem->padDescriptorLabelGroupPairs());
this->pinoutItem = pinoutItem;
}
if (
pinoutDescriptor.type == TargetPinoutType::DIP
|| pinoutDescriptor.type == TargetPinoutType::SOIC
|| pinoutDescriptor.type == TargetPinoutType::SSOP
) {
auto* pinoutItem = new DipPinout{pinoutDescriptor, this->targetDescriptor, this->pinoutState};
this->populatePadLabels(pinoutItem->padDescriptorLabelGroupPairs());
this->pinoutItem = pinoutItem;
}
assert(this->pinoutItem != nullptr);
this->pinoutItem->refreshGeometry();
this->addItem(this->pinoutItem);
this->adjustSize();
this->update();
}
void PinoutScene::setDisabled(bool disabled) {
if (this->pinoutItem == nullptr) {
return;
}
this->pinoutItem->setEnabled(!disabled);
this->update();
}
void PinoutScene::refreshPadStates(const std::optional<std::function<void(void)>>& callback) {
const auto refreshTask = QSharedPointer<ReadTargetGpioPadStates>{
new ReadTargetGpioPadStates{this->gpioPadDescriptors},
&QObject::deleteLater
};
QObject::connect(
refreshTask.get(),
&ReadTargetGpioPadStates::targetGpioPadStatesRead,
this,
&PinoutScene::updatePadStates
);
if (callback.has_value()) {
QObject::connect(
refreshTask.get(),
&InsightWorkerTask::completed,
this,
callback.value()
);
}
InsightWorker::queueTask(refreshTask);
}
void PinoutScene::adjustSize() {
if (this->pinoutItem == nullptr) {
return;
}
this->setSceneRect(this->pinoutItem->boundingRect());
}
void PinoutScene::populatePadLabels(
const std::vector<
Pair<const Targets::TargetPadDescriptor&, LabelGroupInterface*>
>& padDescriptorLabelGroupPairs
) {
for (auto& [padDescriptor, labelGroup] : padDescriptorLabelGroupPairs) {
auto padLabels = PadLabels{};
auto gpioPadStateIt = this->gpioPadStatesByPadId.find(padDescriptor.id);
if (gpioPadStateIt != this->gpioPadStatesByPadId.end()) {
const auto& gpioPadState = gpioPadStateIt->second;
if (padDescriptor.type == Targets::TargetPadType::GPIO) {
auto gpioDirectionLabel = std::make_unique<GpioDirectionLabel>(gpioPadState);
auto gpioStateLabel = std::make_unique<GpioStateLabel>(gpioPadState);
auto gpioDisabledLabel = std::make_unique<GpioDisabledLabel>();
gpioDirectionLabel->enabled = false;
gpioStateLabel->enabled = false;
gpioDisabledLabel->enabled = false;
padLabels.gpioDirection = gpioDirectionLabel.get();
padLabels.gpioState = gpioStateLabel.get();
padLabels.gpioDisabled = gpioDisabledLabel.get();
labelGroup->insertLabel(std::move(gpioDirectionLabel));
labelGroup->insertLabel(std::move(gpioStateLabel));
labelGroup->insertLabel(std::move(gpioDisabledLabel));
}
}
this->padLabelsByPadId.emplace(padDescriptor.id, padLabels);
}
}
void PinoutScene::updatePadStates(const Targets::TargetGpioPadDescriptorAndStatePairs& padStatePairs) {
if (this->pinoutItem == nullptr) {
return;
}
for (const auto& [padDescriptor, padState] : padStatePairs) {
const auto currentPadStateIt = this->gpioPadStatesByPadId.find(padDescriptor.id);
if (currentPadStateIt == this->gpioPadStatesByPadId.end()) {
continue;
}
auto& currentPadState = currentPadStateIt->second;
const auto padLabelsIt = this->padLabelsByPadId.find(padDescriptor.id);
if (padLabelsIt == this->padLabelsByPadId.end()) {
continue;
}
auto& padLabels = padLabelsIt->second;
padLabels.disableGpioLabels();
if (!padState.disabled) {
if (padState.direction != TargetGpioPadState::DataDirection::UNKNOWN) {
padLabels.gpioDirection->enabled = true;
padLabels.gpioDirection->changed = padState.direction != currentPadState.direction;
}
if (padState.value != TargetGpioPadState::State::UNKNOWN) {
padLabels.gpioState->enabled = true;
padLabels.gpioState->changed = padState.value != currentPadState.value;
}
} else {
padLabels.gpioDisabled->enabled = true;
}
currentPadState = padState;
}
this->pinoutItem->refreshGeometry();
this->adjustSize();
this->update();
}
void PinoutScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
if (!this->pinoutItem->isEnabled()) {
return;
}
const auto mousePosition = mouseEvent->scenePos();
const auto hoveredItems = this->items(mousePosition);
if (!hoveredItems.empty()) {
this->update();
const auto* hoveredItem = hoveredItems.first();
const auto* hoveredVerticalLabelGroup = dynamic_cast<const VerticalLabelGroup*>(hoveredItem);
if (hoveredVerticalLabelGroup != nullptr) {
this->pinoutState.hoveredPinNumber = hoveredVerticalLabelGroup->pinNumber;
return;
}
const auto* hoveredHorizontalLabelGroup = dynamic_cast<const HorizontalLabelGroup*>(hoveredItem);
if (hoveredHorizontalLabelGroup != nullptr) {
this->pinoutState.hoveredPinNumber = hoveredHorizontalLabelGroup->pinNumber;
return;
}
const auto* hoveredPin = dynamic_cast<const Pin*>(hoveredItem);
if (hoveredPin != nullptr) {
this->pinoutState.hoveredPinNumber = hoveredPin->number;
return;
}
}
if (this->pinoutState.hoveredPinNumber.has_value()) {
this->pinoutState.hoveredPinNumber = std::nullopt;
this->update();
}
}
void PinoutScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent) {
if (mouseEvent->button() != Qt::MouseButton::LeftButton) {
return QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
const auto mousePosition = mouseEvent->scenePos();
const auto clickedItems = this->items(mousePosition);
if (clickedItems.empty()) {
return;
}
const auto* clickedPinItem = dynamic_cast<const Pin*>(clickedItems.first());
if (clickedPinItem == nullptr || !clickedPinItem->padDescriptor.has_value()) {
return;
}
this->toggleOutputPad(clickedPinItem->padDescriptor->get());
}
void PinoutScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
const auto screenPosition = event->screenPos();
const auto clickedItems = this->items(event->scenePos());
if (clickedItems.empty()) {
return;
}
const auto* clickedPinItem = dynamic_cast<const Pin*>(clickedItems.first());
if (clickedPinItem != nullptr) {
if (!clickedPinItem->padDescriptor.has_value()) {
return;
}
auto* menu = this->contextMenuForPad(clickedPinItem->padDescriptor->get());
menu->exec(screenPosition);
return;
}
const auto* clickedVerticalLabelGroupItem = dynamic_cast<const VerticalLabelGroup*>(clickedItems.first());
if (clickedVerticalLabelGroupItem != nullptr) {
if (!clickedVerticalLabelGroupItem->padDescriptor.has_value()) {
return;
}
auto* menu = this->contextMenuForPad(clickedVerticalLabelGroupItem->padDescriptor->get());
menu->exec(screenPosition);
return;
}
const auto* clickedHorizontalLabelGroupItem = dynamic_cast<const HorizontalLabelGroup*>(clickedItems.first());
if (clickedHorizontalLabelGroupItem != nullptr) {
if (!clickedHorizontalLabelGroupItem->padDescriptor.has_value()) {
return;
}
auto* menu = this->contextMenuForPad(clickedHorizontalLabelGroupItem->padDescriptor->get());
menu->exec(screenPosition);
return;
}
}
QMenu* PinoutScene::contextMenuForPad(const Targets::TargetPadDescriptor& padDescriptor) {
using Targets::TargetGpioPadState;
auto* menu = new QMenu{this->parentView};
menu->setAttribute(Qt::WA_DeleteOnClose);
auto* toggleOutputAction = new QAction{"Toggle output state", menu};
QObject::connect(
toggleOutputAction,
&QAction::triggered,
this,
[this, &padDescriptor] () {
this->toggleOutputPad(padDescriptor);
}
);
const auto currentPadStateIt = this->gpioPadStatesByPadId.find(padDescriptor.id);
if (
currentPadStateIt == this->gpioPadStatesByPadId.end()
|| currentPadStateIt->second.direction != TargetGpioPadState::DataDirection::OUTPUT
) {
toggleOutputAction->setDisabled(true);
}
menu->addAction(toggleOutputAction);
return menu;
}
void PinoutScene::toggleOutputPad(const Targets::TargetPadDescriptor& padDescriptor) {
using Targets::TargetGpioPadState;
const auto currentPadStateIt = this->gpioPadStatesByPadId.find(padDescriptor.id);
if (currentPadStateIt == this->gpioPadStatesByPadId.end()) {
return;
}
const auto& currentPadState = currentPadStateIt->second;
if (currentPadState.disabled || currentPadState.direction != TargetGpioPadState::DataDirection::OUTPUT) {
return;
}
auto newPadState = currentPadState;
newPadState.value = currentPadState.value == TargetGpioPadState::State::HIGH
? TargetGpioPadState::State::LOW
: TargetGpioPadState::State::HIGH;
const auto setPadStateTask = QSharedPointer<SetTargetGpioPadState>{
new SetTargetGpioPadState{padDescriptor, newPadState},
&QObject::deleteLater
};
QObject::connect(
setPadStateTask.get(),
&InsightWorkerTask::completed,
this,
[this, &padDescriptor, newPadState] {
this->updatePadStates(Targets::TargetGpioPadDescriptorAndStatePairs{{padDescriptor, newPadState}});
}
);
QObject::connect(setPadStateTask.get(), &InsightWorkerTask::finished, this, [this] {
this->setDisabled(false);
});
this->setDisabled(true);
InsightWorker::queueTask(setPadStateTask);
}
}

View File

@@ -0,0 +1,62 @@
#pragma once
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <unordered_map>
#include <optional>
#include <functional>
#include <QMenu>
#include "src/Targets/TargetDescriptor.hpp"
#include "src/Targets/TargetPinoutDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "src/Targets/TargetGpioPadState.hpp"
#include "PinoutState.hpp"
#include "PinoutItem.hpp"
#include "PadLabels.hpp"
#include "LabelGroupInterface.hpp"
#include "src/Helpers/Pair.hpp"
namespace Widgets::PinoutWidgets
{
class PinoutScene: public QGraphicsScene
{
Q_OBJECT
public:
explicit PinoutScene(const Targets::TargetDescriptor& targetDescriptor, QGraphicsView* parent);
bool isPinoutSupported(const Targets::TargetPinoutDescriptor& pinoutDescriptor);
void setPinout(const Targets::TargetPinoutDescriptor& pinoutDescriptor);
void setDisabled(bool disabled);
void refreshPadStates(const std::optional<std::function<void(void)>>& callback = std::nullopt);
protected:
QGraphicsView* parentView = nullptr;
const Targets::TargetDescriptor& targetDescriptor;
PinoutState pinoutState = {};
PinoutItem* pinoutItem = nullptr;
std::unordered_map<Targets::TargetPadId, PadLabels> padLabelsByPadId;
Targets::TargetPadDescriptors gpioPadDescriptors;
std::unordered_map<Targets::TargetPadId, Targets::TargetGpioPadState> gpioPadStatesByPadId;
void adjustSize();
void populatePadLabels(
const std::vector<
Pair<const Targets::TargetPadDescriptor&, LabelGroupInterface*>
>& padDescriptorLabelGroupPairs
);
void updatePadStates(const Targets::TargetGpioPadDescriptorAndStatePairs& padStatePairs);
void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override;
QMenu* contextMenuForPad(const Targets::TargetPadDescriptor& padDescriptor);
void toggleOutputPad(const Targets::TargetPadDescriptor& padDescriptor);
};
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
#include <optional>
namespace Widgets::PinoutWidgets
{
struct PinoutState
{
std::optional<std::uint16_t> hoveredPinNumber = std::nullopt;
};
}

View File

@@ -0,0 +1,552 @@
#include "QfpPinout.hpp"
#include <algorithm>
#include <numeric>
#include "src/Services/StringService.hpp"
namespace Widgets::PinoutWidgets
{
QfpPinout::QfpPinout(
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const PinoutState& pinoutState
)
: packageBodySize({
(Pin::WIDTH + QfpPinout::PIN_MARGIN) * static_cast<int>(pinoutDescriptor.pinDescriptors.size() / 4)
- QfpPinout::PIN_MARGIN + (QfpPinout::PACKAGE_PADDING * 2),
(Pin::WIDTH + QfpPinout::PIN_MARGIN) * static_cast<int>(pinoutDescriptor.pinDescriptors.size() / 4)
- QfpPinout::PIN_MARGIN + (QfpPinout::PACKAGE_PADDING * 2)
})
, packageBodyPosition({})
, pinoutDescriptor(pinoutDescriptor)
, pinoutState(pinoutState)
{
assert((pinoutDescriptor.pinDescriptors.size() % 4) == 0);
auto sortedPinDescriptors = std::vector<const Targets::TargetPinDescriptor*>{};
sortedPinDescriptors.reserve(pinoutDescriptor.pinDescriptors.size());
std::transform(
pinoutDescriptor.pinDescriptors.begin(),
pinoutDescriptor.pinDescriptors.end(),
std::back_inserter(sortedPinDescriptors),
[] (const auto& pinDescriptor) {
return &pinDescriptor;
}
);
std::sort(
sortedPinDescriptors.begin(),
sortedPinDescriptors.end(),
[] (const Targets::TargetPinDescriptor* descA, const Targets::TargetPinDescriptor* descB) {
return
Services::StringService::toUint16(descA->position, 10)
< Services::StringService::toUint16(descB->position, 10);
}
);
this->leftQuadrantLabelGroupSet->setParentItem(this);
this->bottomQuadrantLabelGroupSet->setParentItem(this);
this->rightQuadrantLabelGroupSet->setParentItem(this);
this->topQuadrantLabelGroupSet->setParentItem(this);
const auto quadSize = sortedPinDescriptors.size() / 4;
for (auto i = std::size_t{0}; i < quadSize; i++) {
// Left pins
const auto& pinDescriptor = *sortedPinDescriptors[i];
auto* labelGroup = new HorizontalLabelGroup{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
HorizontalLabelGroup::Direction::LEFT,
this->pinoutState
};
labelGroup->setParentItem(this->leftQuadrantLabelGroupSet);
this->leftQuadrantLabelGroupSet->labelGroups.emplace_back(labelGroup);
auto* pin = new Pin{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
Pin::Orientation::HORIZONTAL,
this->pinoutState
};
pin->setParentItem(this);
this->leftLabelGroupPinPairs.emplace_back(
HorizontalLabelGroupPinPair{.labelGroup = labelGroup, .pin = pin}
);
}
for (auto i = quadSize; i < (quadSize * 2); i++) {
// Bottom pins
const auto& pinDescriptor = *sortedPinDescriptors[i];
auto* labelGroup = new VerticalLabelGroup{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
this->pinoutState
};
labelGroup->setParentItem(this->bottomQuadrantLabelGroupSet);
this->bottomQuadrantLabelGroupSet->labelGroups.emplace_back(labelGroup);
auto* pin = new Pin{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
Pin::Orientation::VERTICAL,
this->pinoutState
};
pin->setParentItem(this);
this->bottomLabelGroupPinPairs.emplace_back(
VerticalLabelGroupPinPair{.labelGroup = labelGroup, .pin = pin}
);
}
for (auto i = quadSize * 2; i < (quadSize * 3); i++) {
// Right pins
const auto& pinDescriptor = *sortedPinDescriptors[i];
auto* labelGroup = new HorizontalLabelGroup{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
HorizontalLabelGroup::Direction::RIGHT,
this->pinoutState
};
labelGroup->setParentItem(this->rightQuadrantLabelGroupSet);
this->rightQuadrantLabelGroupSet->labelGroups.emplace_back(labelGroup);
auto* pin = new Pin{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
Pin::Orientation::HORIZONTAL,
this->pinoutState
};
pin->setParentItem(this);
this->rightLabelGroupPinPairs.emplace_back(
HorizontalLabelGroupPinPair{.labelGroup = labelGroup, .pin = pin}
);
}
for (auto i = quadSize * 3; i < (quadSize * 4); i++) {
// Top pins
const auto& pinDescriptor = *sortedPinDescriptors[i];
auto* labelGroup = new VerticalLabelGroup{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
this->pinoutState
};
labelGroup->setParentItem(this->topQuadrantLabelGroupSet);
this->topQuadrantLabelGroupSet->labelGroups.emplace_back(labelGroup);
auto* pin = new Pin{
pinDescriptor,
pinDescriptor.padKey.has_value()
? std::optional{std::cref(targetDescriptor.getPadDescriptor(*(pinDescriptor.padKey)))}
: std::nullopt,
Pin::Orientation::VERTICAL,
this->pinoutState
};
pin->setParentItem(this);
this->topLabelGroupPinPairs.emplace_back(
VerticalLabelGroupPinPair{.labelGroup = labelGroup, .pin = pin}
);
}
}
std::vector<Pair<
const Targets::TargetPadDescriptor&,
LabelGroupInterface*
>> QfpPinout::padDescriptorLabelGroupPairs() {
auto output = std::vector<Pair<const Targets::TargetPadDescriptor&, LabelGroupInterface*>>{};
for (auto& [labelGroup, pin] : this->leftLabelGroupPinPairs) {
if (!pin->padDescriptor.has_value()) {
continue;
}
output.emplace_back(pin->padDescriptor->get(), labelGroup);
}
for (auto& [labelGroup, pin] : this->bottomLabelGroupPinPairs) {
if (!pin->padDescriptor.has_value()) {
continue;
}
output.emplace_back(pin->padDescriptor->get(), labelGroup);
}
for (auto& [labelGroup, pin] : this->rightLabelGroupPinPairs) {
if (!pin->padDescriptor.has_value()) {
continue;
}
output.emplace_back(pin->padDescriptor->get(), labelGroup);
}
for (auto& [labelGroup, pin] : this->topLabelGroupPinPairs) {
if (!pin->padDescriptor.has_value()) {
continue;
}
output.emplace_back(pin->padDescriptor->get(), labelGroup);
}
return output;
}
void QfpPinout::refreshGeometry() {
this->leftQuadrantLabelGroupSet->refreshGeometry();
this->bottomQuadrantLabelGroupSet->refreshGeometry();
this->rightQuadrantLabelGroupSet->refreshGeometry();
this->topQuadrantLabelGroupSet->refreshGeometry();
const auto quadSize = this->pinoutDescriptor.pinDescriptors.size() / 4;
const auto maxHorizontalPinLineAHeight = static_cast<int>(
QfpPinout::MIN_LINE_A_LENGTH + (QfpPinout::PIN_LINE_A_SPACING
* std::ceil(static_cast<float>(quadSize) / static_cast<float>(2)))
);
const auto maxVerticalPinLineAHeight = this->minVerticalLineALength() + static_cast<int>(
QfpPinout::PIN_LINE_A_SPACING * std::ceil(static_cast<float>(quadSize) / static_cast<float>(2))
);
this->packageBodyPosition.setX(
std::max(
this->leftQuadrantLabelGroupSet->size.width() + maxHorizontalPinLineAHeight + QfpPinout::PIN_LINE_MARGIN + Pin::HEIGHT + QfpPinout::PIN_MARGIN,
(std::max(this->bottomQuadrantLabelGroupSet->size.width(), this->topQuadrantLabelGroupSet->size.width()) / 2) - (this->packageBodySize.width() / 2)
)
);
this->packageBodyPosition.setY(
this->topQuadrantLabelGroupSet->size.height()
+ maxVerticalPinLineAHeight + QfpPinout::PIN_LINE_MARGIN + Pin::HEIGHT + QfpPinout::PIN_MARGIN
);
this->size.setWidth(
std::max(
std::max(
this->bottomQuadrantLabelGroupSet->size.width(),
this->topQuadrantLabelGroupSet->size.width()
),
this->leftQuadrantLabelGroupSet->size.width() + this->packageBodySize.width() + (
(maxHorizontalPinLineAHeight + QfpPinout::PIN_LINE_MARGIN + Pin::HEIGHT + QfpPinout::PIN_MARGIN) * 2
) + this->rightQuadrantLabelGroupSet->size.width()
)
);
this->size.setHeight(
this->topQuadrantLabelGroupSet->size.height() + this->packageBodySize.height()
+ ((maxVerticalPinLineAHeight + QfpPinout::PIN_LINE_MARGIN + Pin::HEIGHT + QfpPinout::PIN_MARGIN) * 2)
+ this->bottomQuadrantLabelGroupSet->size.height()
);
// Position the pins
auto leftPinYPosition = this->packageBodyPosition.y() + QfpPinout::PACKAGE_PADDING;
for (auto& [labelGroup, pin] : this->leftLabelGroupPinPairs) {
pin->setPos(
this->packageBodyPosition.x() - Pin::HEIGHT - QfpPinout::PIN_MARGIN,
leftPinYPosition
);
leftPinYPosition += Pin::WIDTH + QfpPinout::PIN_MARGIN;
}
auto bottomPinXPosition = this->packageBodyPosition.x() + QfpPinout::PACKAGE_PADDING;
for (auto& [labelGroup, pin] : this->bottomLabelGroupPinPairs) {
pin->setPos(
bottomPinXPosition,
this->packageBodyPosition.y() + this->packageBodySize.height() + QfpPinout::PIN_MARGIN
);
bottomPinXPosition += Pin::WIDTH + QfpPinout::PIN_MARGIN;
}
auto rightPinYPosition = this->packageBodyPosition.y() + this->packageBodySize.height()
- QfpPinout::PACKAGE_PADDING - Pin::WIDTH;
for (auto& [labelGroup, pin] : this->rightLabelGroupPinPairs) {
pin->setPos(
this->packageBodyPosition.x() + this->packageBodySize.width() + QfpPinout::PIN_MARGIN,
rightPinYPosition
);
rightPinYPosition -= Pin::WIDTH + QfpPinout::PIN_MARGIN;
}
auto topPinXPosition = this->packageBodyPosition.x() + this->packageBodySize.width()
- QfpPinout::PACKAGE_PADDING - Pin::WIDTH;
for (auto& [labelGroup, pin] : this->topLabelGroupPinPairs) {
pin->setPos(
topPinXPosition,
this->packageBodyPosition.y() - QfpPinout::PIN_MARGIN - Pin::HEIGHT
);
topPinXPosition -= Pin::WIDTH + QfpPinout::PIN_MARGIN;
}
this->leftQuadrantLabelGroupSet->setPos(
this->packageBodyPosition.x() - QfpPinout::PIN_MARGIN - Pin::HEIGHT - QfpPinout::PIN_LINE_MARGIN
- maxHorizontalPinLineAHeight - this->leftQuadrantLabelGroupSet->size.width(),
this->packageBodyPosition.y() + (this->packageBodySize.height() / 2) - (this->leftQuadrantLabelGroupSet->size.height() / 2)
);
this->topQuadrantLabelGroupSet->setPos(
this->packageBodyPosition.x() + (this->packageBodySize.width() / 2)
- (this->topQuadrantLabelGroupSet->size.width() / 2),
0
);
this->rightQuadrantLabelGroupSet->setPos(
this->packageBodyPosition.x() + this->packageBodySize.width() + QfpPinout::PIN_MARGIN + Pin::HEIGHT + QfpPinout::PIN_LINE_MARGIN
+ maxHorizontalPinLineAHeight,
this->packageBodyPosition.y() + (this->packageBodySize.height() / 2) - (this->leftQuadrantLabelGroupSet->size.height() / 2)
);
this->bottomQuadrantLabelGroupSet->setPos(
this->packageBodyPosition.x() + (this->packageBodySize.width() / 2)
- (this->bottomQuadrantLabelGroupSet->size.width() / 2),
this->packageBodyPosition.y() + this->packageBodySize.height() + QfpPinout::PIN_MARGIN + Pin::HEIGHT
+ QfpPinout::PIN_LINE_MARGIN + maxVerticalPinLineAHeight
);
}
QRectF QfpPinout::boundingRect() const {
return QRectF{QPointF{0, 0}, this->size};
}
void QfpPinout::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static constexpr auto BODY_COLOR = QColor{0x7D, 0x7D, 0x7D};
static constexpr auto DISABLED_BODY_COLOR = QColor{0x7D, 0x7D, 0x7D, 153};
static constexpr auto BG_COLOR = QColor{0x37, 0x38, 0x35};
static constexpr auto LINE_COLOR = QColor{0x5E, 0x5C, 0x59};
static constexpr auto HIGHLIGHTED_LINE_COLOR = QColor{0x7D, 0x7D, 0x7D};
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
painter->setBrush(!this->isEnabled() ? DISABLED_BODY_COLOR : BODY_COLOR);
painter->setPen(Qt::PenStyle::NoPen);
// Package body
painter->drawRect(
this->packageBodyPosition.x(),
this->packageBodyPosition.y(),
this->packageBodySize.width(),
this->packageBodySize.height()
);
painter->setBrush(BG_COLOR);
painter->drawEllipse(
this->packageBodyPosition.x() + 10,
this->packageBodyPosition.y() + 10,
14,
14
);
painter->setRenderHints(QPainter::RenderHint::Antialiasing, false);
// Pin lines
const auto quadSize = this->pinoutDescriptor.pinDescriptors.size() / 4;
{
// Left pin lines
auto lineAEndXOffset = int{0};
for (auto pinIndex = std::size_t{0}; pinIndex < this->leftLabelGroupPinPairs.size(); ++pinIndex) {
const auto* pin = this->leftLabelGroupPinPairs[pinIndex].pin;
const auto* labelGroup = this->leftLabelGroupPinPairs[pinIndex].labelGroup;
painter->setPen(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == pin->number
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR
);
const auto lineAStartX = static_cast<int>(pin->pos().x() - QfpPinout::PIN_LINE_MARGIN);
const auto lineAStartY = static_cast<int>(pin->pos().y() + (Pin::WIDTH / 2));
const auto lineAEndX = static_cast<int>(lineAStartX - QfpPinout::MIN_LINE_A_LENGTH - lineAEndXOffset);
painter->drawLine(lineAStartX, lineAStartY, lineAEndX, lineAStartY);
if (quadSize % 2 != 0 || pinIndex != (quadSize / 2 - 1)) {
lineAEndXOffset = pinIndex <= (quadSize / 2 - 1)
? lineAEndXOffset + QfpPinout::PIN_LINE_A_SPACING
: lineAEndXOffset - QfpPinout::PIN_LINE_A_SPACING;
}
const auto lineBStartX = lineAEndX;
const auto lineBStartY = lineAStartY;
const auto lineBEndY = static_cast<int>(
this->leftQuadrantLabelGroupSet->pos().y() + labelGroup->pos().y()
+ (labelGroup->size.height() / 2)
);
painter->drawLine(lineBStartX, lineBStartY, lineBStartX, lineBEndY);
const auto lineCStartX = lineBStartX;
const auto lineCStartY = lineBEndY;
const auto lineCEndX = static_cast<int>(
this->leftQuadrantLabelGroupSet->pos().x() + labelGroup->pos().x() + labelGroup->size.width() + QfpPinout::PIN_LINE_MARGIN
);
painter->drawLine(lineCStartX, lineCStartY, lineCEndX, lineCStartY);
}
}
{
// Bottom pin lines
auto lineAEndYOffset = int{0};
for (auto pinIndex = std::size_t{0}; pinIndex < this->bottomLabelGroupPinPairs.size(); ++pinIndex) {
const auto* pin = this->bottomLabelGroupPinPairs[pinIndex].pin;
const auto* labelGroup = this->bottomLabelGroupPinPairs[pinIndex].labelGroup;
painter->setPen(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == pin->number
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR
);
const auto lineAStartX = static_cast<int>(pin->pos().x() + (Pin::WIDTH / 2));
const auto lineAStartY = static_cast<int>(pin->pos().y() + Pin::HEIGHT + QfpPinout::PIN_LINE_MARGIN);
const auto lineAEndY = static_cast<int>(lineAStartY + this->minVerticalLineALength() + lineAEndYOffset);
painter->drawLine(lineAStartX, lineAStartY, lineAStartX, lineAEndY);
if (quadSize % 2 != 0 || pinIndex != (quadSize / 2 - 1)) {
lineAEndYOffset = pinIndex <= (quadSize / 2 - 1)
? lineAEndYOffset + QfpPinout::PIN_LINE_A_SPACING
: lineAEndYOffset - QfpPinout::PIN_LINE_A_SPACING;
}
const auto lineBStartX = lineAStartX;
const auto lineBEndX = static_cast<int>(
this->bottomQuadrantLabelGroupSet->pos().x() + labelGroup->pos().x()
+ (labelGroup->size.width() / 2)
);
const auto lineBStartY = lineAEndY;
painter->drawLine(lineBStartX, lineBStartY, lineBEndX, lineBStartY);
const auto lineCStartX = lineBEndX;
const auto lineCStartY = lineBStartY;
const auto lineCEndY = static_cast<int>(
this->bottomQuadrantLabelGroupSet->pos().y() + labelGroup->pos().y() - 5
);
painter->drawLine(lineCStartX, lineCStartY, lineCStartX, lineCEndY);
}
}
{
// Right pin lines
auto lineAEndXOffset = int{0};
for (auto pinIndex = std::size_t{0}; pinIndex < this->rightLabelGroupPinPairs.size(); ++pinIndex) {
const auto* pin = this->rightLabelGroupPinPairs[pinIndex].pin;
const auto* labelGroup = this->rightLabelGroupPinPairs[pinIndex].labelGroup;
painter->setPen(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == pin->number
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR
);
const auto lineAStartX = static_cast<int>(pin->pos().x() + Pin::HEIGHT + QfpPinout::PIN_LINE_MARGIN);
const auto lineAStartY = static_cast<int>(pin->pos().y() + (Pin::WIDTH / 2));
const auto lineAEndX = static_cast<int>(lineAStartX + QfpPinout::MIN_LINE_A_LENGTH + lineAEndXOffset);
painter->drawLine(lineAStartX, lineAStartY, lineAEndX, lineAStartY);
if (quadSize % 2 != 0 || pinIndex != (quadSize / 2 - 1)) {
lineAEndXOffset = pinIndex <= (quadSize / 2 - 1)
? lineAEndXOffset + QfpPinout::PIN_LINE_A_SPACING
: lineAEndXOffset - QfpPinout::PIN_LINE_A_SPACING;
}
const auto lineBStartX = lineAEndX;
const auto lineBStartY = lineAStartY;
const auto lineBEndY = static_cast<int>(
this->rightQuadrantLabelGroupSet->pos().y() + labelGroup->pos().y()
+ (labelGroup->size.height() / 2)
);
painter->drawLine(lineBStartX, lineBStartY, lineBStartX, lineBEndY);
const auto lineCStartX = lineBStartX;
const auto lineCStartY = lineBEndY;
const auto lineCEndX = static_cast<int>(
this->rightQuadrantLabelGroupSet->pos().x() + labelGroup->pos().x() - QfpPinout::PIN_LINE_MARGIN
);
painter->drawLine(lineCStartX, lineCStartY, lineCEndX, lineCStartY);
}
}
{
// Top pin lines
auto lineAEndYOffset = int{0};
for (auto pinIndex = std::size_t{0}; pinIndex < this->topLabelGroupPinPairs.size(); ++pinIndex) {
const auto* pin = this->topLabelGroupPinPairs[pinIndex].pin;
const auto* labelGroup = this->topLabelGroupPinPairs[pinIndex].labelGroup;
painter->setPen(
this->pinoutState.hoveredPinNumber.has_value() && this->pinoutState.hoveredPinNumber == pin->number
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR
);
const auto lineAStartX = static_cast<int>(pin->pos().x() + (Pin::WIDTH / 2));
const auto lineAStartY = static_cast<int>(pin->pos().y() - QfpPinout::PIN_LINE_MARGIN);
const auto lineAEndY = lineAStartY - (this->minVerticalLineALength() + lineAEndYOffset);
painter->drawLine(lineAStartX, lineAStartY, lineAStartX, lineAEndY);
if (quadSize % 2 != 0 || pinIndex != (quadSize / 2 - 1)) {
lineAEndYOffset = pinIndex <= (quadSize / 2 - 1)
? lineAEndYOffset + QfpPinout::PIN_LINE_A_SPACING
: lineAEndYOffset - QfpPinout::PIN_LINE_A_SPACING;
}
const auto lineBStartX = lineAStartX;
const auto lineBEndX = static_cast<int>(
this->topQuadrantLabelGroupSet->pos().x() + labelGroup->pos().x()
+ (labelGroup->size.width() / 2)
);
const auto lineBStartY = lineAEndY;
painter->drawLine(lineBStartX, lineBStartY, lineBEndX, lineBStartY);
const auto lineCStartX = lineBEndX;
const auto lineCStartY = lineBStartY;
const auto lineCEndY = static_cast<int>(
this->topQuadrantLabelGroupSet->pos().y() + labelGroup->pos().y() + labelGroup->size.height() + 5
);
painter->drawLine(lineCStartX, lineCStartY, lineCStartX, lineCEndY);
}
}
}
int QfpPinout::minVerticalLineALength() const {
return std::max(
(
this->leftQuadrantLabelGroupSet->size.height() - (this->packageBodySize.height()
+ ((QfpPinout::PIN_MARGIN + Pin::HEIGHT + QfpPinout::PIN_LINE_MARGIN) * 2)
) + 10
) / 2,
0
) + QfpPinout::MIN_LINE_A_LENGTH;
}
}

View File

@@ -0,0 +1,81 @@
#pragma once
#include <QSize>
#include <QPoint>
#include <QPainter>
#include <vector>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinoutItem.hpp"
#include "src/Targets/TargetPinoutDescriptor.hpp"
#include "src/Targets/TargetDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/PinoutState.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/Pin.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/LabelGroupInterface.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroup.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroupSet.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/VerticalLabelGroupPinPair.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/HorizontalLabelGroup.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/HorizontalLabelGroupSet.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PinoutWidgets/HorizontalLabelGroupPinPair.hpp"
#include "src/Helpers/Pair.hpp"
namespace Widgets::PinoutWidgets
{
class QfpPinout: public PinoutItem
{
public:
static constexpr int PACKAGE_PADDING = 15;
static constexpr int PIN_MARGIN = 2;
static constexpr int PIN_LINE_A_SPACING = 15;
static constexpr int PIN_LINE_MARGIN = 5;
static constexpr int MIN_LINE_A_LENGTH = 10;
QSize size = {};
QSize packageBodySize;
QPoint packageBodyPosition;
QfpPinout(
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const PinoutState& pinoutState
);
std::vector<Pair<const Targets::TargetPadDescriptor&, LabelGroupInterface*>> padDescriptorLabelGroupPairs();
void refreshGeometry() override;
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
const Targets::TargetPinoutDescriptor& pinoutDescriptor;
const PinoutState& pinoutState;
HorizontalLabelGroupSet* leftQuadrantLabelGroupSet = new HorizontalLabelGroupSet{
HorizontalLabelGroupSet::Position::LEFT
};
HorizontalLabelGroupSet* rightQuadrantLabelGroupSet = new HorizontalLabelGroupSet{
HorizontalLabelGroupSet::Position::RIGHT
};
VerticalLabelGroupSet* topQuadrantLabelGroupSet = new VerticalLabelGroupSet{
VerticalLabelGroupSet::Position::TOP
};
VerticalLabelGroupSet* bottomQuadrantLabelGroupSet = new VerticalLabelGroupSet{
VerticalLabelGroupSet::Position::BOTTOM
};
std::vector<HorizontalLabelGroupPinPair> leftLabelGroupPinPairs = {};
std::vector<HorizontalLabelGroupPinPair> rightLabelGroupPinPairs = {};
std::vector<VerticalLabelGroupPinPair> topLabelGroupPinPairs = {};
std::vector<VerticalLabelGroupPinPair> bottomLabelGroupPinPairs = {};
int minVerticalLineALength() const;
};
}

View File

@@ -0,0 +1,187 @@
#include "VerticalLabelGroup.hpp"
#include <algorithm>
#include <ranges>
#include "src/Services/StringService.hpp"
namespace Widgets::PinoutWidgets
{
VerticalLabelGroup::VerticalLabelGroup(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const PinoutState& pinoutState
)
: pinDescriptor(pinDescriptor)
, padDescriptor(padDescriptor)
, pinNumber(Services::StringService::toUint16(this->pinDescriptor.position, 10))
, pinoutState(pinoutState)
, pinNumberLabel(PinNumberLabel{this->pinDescriptor})
, padNameLabel(PadNameLabel{this->padDescriptor})
{
this->setAcceptedMouseButtons(Qt::MouseButton::NoButton);
}
void VerticalLabelGroup::insertLabel(std::unique_ptr<Label>&& label) {
this->secondaryLabels.emplace_back(std::move(label));
}
void VerticalLabelGroup::refreshGeometry() {
this->secondaryLabelsByRowIndex.clear();
this->pinNumberLabel.refreshGeometry();
this->padNameLabel.refreshGeometry();
const auto primaryRowWidth = this->pinNumberLabel.minimumWidth + VerticalLabelGroup::LABEL_MARGIN
+ this->padNameLabel.minimumWidth;
auto maxLabelWidth = std::max(primaryRowWidth, VerticalLabelGroup::MIN_LABEL_WIDTH);
for (const auto& secondaryLabel : this->secondaryLabels) {
if (!secondaryLabel->enabled) {
continue;
}
secondaryLabel->refreshGeometry();
if (secondaryLabel->width > maxLabelWidth) {
maxLabelWidth = secondaryLabel->width;
}
}
const auto addLabelToRow = [this, maxLabelWidth] (Label& label) -> std::size_t {
for (auto& [rowIndex, rowLabels] : this->secondaryLabelsByRowIndex) {
const auto occupiedRowWidth = std::accumulate(
rowLabels.begin(),
rowLabels.end(),
int{0},
[] (int width, const Label* label) {
return width + label->minimumWidth + VerticalLabelGroup::LABEL_MARGIN;
}
) - VerticalLabelGroup::LABEL_MARGIN;
const auto availableRowWidth = maxLabelWidth - occupiedRowWidth;
if (label.minimumWidth <= availableRowWidth) {
rowLabels.emplace_back(&label);
return rowIndex;
}
}
const auto newRowIndex = this->secondaryLabelsByRowIndex.empty()
? 0
: this->secondaryLabelsByRowIndex.size();
this->secondaryLabelsByRowIndex.emplace(newRowIndex, std::vector{&label});
return newRowIndex;
};
for (auto& secondaryLabel : this->secondaryLabels) {
if (!secondaryLabel->enabled) {
continue;
}
addLabelToRow(*secondaryLabel);
}
// Resize label widths to fill any excess row space
for (const auto& rowLabels : std::views::values(this->secondaryLabelsByRowIndex)) {
const auto occupiedRowWidth = std::accumulate(
rowLabels.begin(),
rowLabels.end(),
int{0},
[] (int width, const Label* label) {
return width + label->minimumWidth + VerticalLabelGroup::LABEL_MARGIN;
}
) - VerticalLabelGroup::LABEL_MARGIN;
const auto excessWidth = maxLabelWidth - occupiedRowWidth;
if (excessWidth == 0) {
continue;
}
for (auto* label : rowLabels) {
label->width += excessWidth / static_cast<int>(rowLabels.size());
}
// Add the remainder to the first label in the row
(*rowLabels.begin())->width += excessWidth % static_cast<int>(rowLabels.size());
}
if (primaryRowWidth < maxLabelWidth) {
this->padNameLabel.width += maxLabelWidth - primaryRowWidth;
}
this->size.setWidth(maxLabelWidth + (VerticalLabelGroup::HORIZ_PADDING * 2));
this->size.setHeight(
(
static_cast<int>(this->secondaryLabelsByRowIndex.size() + 1)
* (Label::HEIGHT + VerticalLabelGroup::LABEL_MARGIN)
) - VerticalLabelGroup::LABEL_MARGIN + (VerticalLabelGroup::VERTICAL_PADDING * 2)
+ (!this->secondaryLabelsByRowIndex.empty() ? VerticalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING : 0)
);
}
QRectF VerticalLabelGroup::boundingRect() const {
return QRectF{QPointF{0, 0}, this->size};
}
void VerticalLabelGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static constexpr auto LINE_COLOR = QColor{0x5E, 0x5C, 0x59};
static constexpr auto HIGHLIGHTED_LINE_COLOR = QColor{0x7D, 0x7D, 0x7D};
painter->setOpacity(this->isEnabled() ? 1 : 0.6);
painter->setPen(Qt::PenStyle::NoPen);
constexpr auto START_X = VerticalLabelGroup::HORIZ_PADDING;
auto yPos = VerticalLabelGroup::VERTICAL_PADDING;
this->pinNumberLabel.paint(painter, START_X, yPos);
this->padNameLabel.paint(
painter,
START_X + this->pinNumberLabel.width + VerticalLabelGroup::LABEL_MARGIN,
yPos
);
yPos += Label::HEIGHT + VerticalLabelGroup::LABEL_MARGIN;
const auto& lineColor = this->pinoutState.hoveredPinNumber.has_value()
&& this->pinoutState.hoveredPinNumber == this->pinNumber
? HIGHLIGHTED_LINE_COLOR
: LINE_COLOR;
if (!this->secondaryLabelsByRowIndex.empty()) {
painter->setPen(lineColor);
const auto centerX = this->size.width() / 2;
painter->drawLine(
centerX,
yPos,
centerX,
yPos + VerticalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING - VerticalLabelGroup::LABEL_MARGIN
);
painter->setPen(Qt::PenStyle::NoPen);
yPos += VerticalLabelGroup::SECONDARY_LABEL_SEPARATOR_SPACING;
for (const auto& rowLabels : std::views::values(this->secondaryLabelsByRowIndex)) {
auto xPos = START_X;
for (const auto* label : rowLabels) {
label->paint(painter, xPos, yPos);
xPos += label->width + VerticalLabelGroup::LABEL_MARGIN;
}
yPos += Label::HEIGHT + VerticalLabelGroup::LABEL_MARGIN;
}
}
static constexpr auto VERTICAL_BORDER_LENGTH = 10;
painter->setPen(lineColor);
painter->drawLine(0, 0, 0, VERTICAL_BORDER_LENGTH);
painter->drawLine(0, 0, this->size.width(), 0);
painter->drawLine(this->size.width(), 0, this->size.width(), VERTICAL_BORDER_LENGTH);
painter->drawLine(0, this->size.height() - 1, 0, this->size.height() - 1 - VERTICAL_BORDER_LENGTH);
painter->drawLine(0, this->size.height() - 1, this->size.width(), this->size.height() - 1);
painter->drawLine(
this->size.width(),
this->size.height() - 1, this->size.width(),
this->size.height() - 1 - VERTICAL_BORDER_LENGTH
);
}
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <QGraphicsItem>
#include <QSize>
#include <QRectF>
#include <functional>
#include <memory>
#include <vector>
#include <map>
#include "src/Targets/TargetPinDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "LabelGroupInterface.hpp"
#include "PinoutState.hpp"
#include "Label.hpp"
#include "PinNumberLabel.hpp"
#include "PadNameLabel.hpp"
namespace Widgets::PinoutWidgets
{
class VerticalLabelGroup
: public LabelGroupInterface
, public QGraphicsItem
{
public:
static constexpr int VERTICAL_PADDING = 6;
static constexpr int HORIZ_PADDING = 6;
static constexpr int LABEL_MARGIN = 4;
static constexpr int MIN_LABEL_WIDTH = 150;
static constexpr int SECONDARY_LABEL_SEPARATOR_SPACING = 10;
const Targets::TargetPinDescriptor& pinDescriptor;
const std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor;
std::uint16_t pinNumber;
QSize size = {};
VerticalLabelGroup(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const PinoutState& pinoutState
);
void insertLabel(std::unique_ptr<Label>&& label) override;
void refreshGeometry();
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
const PinoutState& pinoutState;
PinNumberLabel pinNumberLabel;
PadNameLabel padNameLabel;
std::vector<std::unique_ptr<Label>> secondaryLabels;
std::map<std::size_t, std::vector<Label*>> secondaryLabelsByRowIndex;
};
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "VerticalLabelGroup.hpp"
#include "Pin.hpp"
namespace Widgets::PinoutWidgets
{
struct VerticalLabelGroupPinPair
{
VerticalLabelGroup* labelGroup;
Pin* pin;
};
}

View File

@@ -0,0 +1,120 @@
#include "VerticalLabelGroupSet.hpp"
#include <algorithm>
#include <ranges>
#include <QPoint>
namespace Widgets::PinoutWidgets
{
VerticalLabelGroupSet::VerticalLabelGroupSet(Position position)
: labelGroups({})
, size({0, 0})
, position(position)
{}
void VerticalLabelGroupSet::refreshGeometry() {
for (auto* labelGroup : this->labelGroups) {
labelGroup->refreshGeometry();
}
const auto firstRowHeight = this->getFirstRowHeight();
auto maxHeight = int{0};
auto firstRowXPos = int{0};
auto secondRowXPos = int{0};
const auto positionLabelGroup = [&] (VerticalLabelGroup* labelGroup) {
if (this->isGroupOnFirstRow(labelGroup)) {
auto position = QPoint{
firstRowXPos + VerticalLabelGroupSet::GROUP_HORIZONTAL_MARGIN,
0
};
if (
this->position == Position::TOP
|| (this->labelGroups.size() % 2 != 0 && firstRowXPos == 0 && secondRowXPos > 0)
) {
const auto groupCenterX = position.x() + (labelGroup->size.width() / 2);
const auto secondRowMinX = secondRowXPos + (VerticalLabelGroupSet::GROUP_HORIZONTAL_MARGIN / 2);
if (groupCenterX < secondRowMinX) {
position.setX(position.x() + (secondRowMinX - groupCenterX));
} else {
secondRowXPos = groupCenterX - (VerticalLabelGroupSet::GROUP_HORIZONTAL_MARGIN / 2);
}
}
labelGroup->setPos(position);
firstRowXPos = position.x() + labelGroup->size.width();
} else {
auto position = QPoint{
secondRowXPos + VerticalLabelGroupSet::GROUP_HORIZONTAL_MARGIN,
firstRowHeight + VerticalLabelGroupSet::GROUP_VERTICAL_MARGIN
};
if (
this->position == Position::BOTTOM
|| (this->labelGroups.size() % 2 != 0 && secondRowXPos == 0 && firstRowXPos > 0)
) {
const auto groupCenterX = position.x() + (labelGroup->size.width() / 2);
const auto firstRowMinX = firstRowXPos + (VerticalLabelGroupSet::GROUP_HORIZONTAL_MARGIN / 2);
if (groupCenterX < firstRowMinX) {
position.setX(position.x() + (firstRowMinX - groupCenterX));
} else {
firstRowXPos = groupCenterX - (VerticalLabelGroupSet::GROUP_HORIZONTAL_MARGIN / 2);
}
}
labelGroup->setPos(position);
secondRowXPos = position.x() + labelGroup->size.width();
}
maxHeight = std::max(static_cast<int>(labelGroup->pos().y() + labelGroup->size.height()), maxHeight);
};
if (this->position == Position::TOP) {
for (auto groupIt = this->labelGroups.rbegin(); groupIt < this->labelGroups.rend(); ++groupIt) {
positionLabelGroup(*groupIt);
}
} else {
for (auto groupIt = this->labelGroups.begin(); groupIt < this->labelGroups.end(); ++groupIt) {
positionLabelGroup(*groupIt);
}
}
this->size.setWidth(std::max(firstRowXPos, secondRowXPos));
this->size.setHeight(maxHeight);
}
QRectF VerticalLabelGroupSet::boundingRect() const {
return QRectF{QPointF{0, 0}, this->size};
}
void VerticalLabelGroupSet::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
// Nothing to do here...
}
bool VerticalLabelGroupSet::isGroupOnFirstRow(const VerticalLabelGroup* group) const {
return (group->pinNumber % 2) != 0;
}
int VerticalLabelGroupSet::getFirstRowHeight() const {
auto height = int{0};
for (const auto* labelGroup : this->labelGroups) {
if (!this->isGroupOnFirstRow(labelGroup)) {
continue;
}
height = std::max(labelGroup->size.height(), height);
}
return height;
}
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <QGraphicsItem>
#include <QSize>
#include <QRectF>
#include <QPainter>
#include <vector>
#include "VerticalLabelGroup.hpp"
namespace Widgets::PinoutWidgets
{
class VerticalLabelGroupSet: public QGraphicsItem
{
public:
static constexpr int GROUP_HORIZONTAL_MARGIN = 16;
static constexpr int GROUP_VERTICAL_MARGIN = 10;
enum Position: std::uint8_t
{
TOP,
BOTTOM
};
std::vector<VerticalLabelGroup*> labelGroups;
QSize size;
const Position position;
explicit VerticalLabelGroupSet(Position position);
void refreshGeometry();
[[nodiscard]] QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
bool isGroupOnFirstRow(const VerticalLabelGroup* group) const;
int getFirstRowHeight() const;
};
}

View File

@@ -1,87 +0,0 @@
#include "BodyWidget.hpp"
namespace Widgets::InsightTargetWidgets::Dip
{
BodyWidget::BodyWidget(QWidget* parent, std::size_t pinCount)
: QWidget(parent)
{
this->setObjectName("target-body");
/*
* The DIP package widget looks awkward when the body height is fixed. For this reason, the body height and
* indicator sizes are proportional to the pin count.
*
* The proportionality constants used below were chosen because they look the nicest. No other reason.
*/
this->setFixedHeight(
std::min(
BodyWidget::MAXIMUM_BODY_HEIGHT,
std::max(
BodyWidget::MINIMUM_BODY_HEIGHT,
static_cast<int>(std::ceil(3.6 * static_cast<double>(pinCount)))
)
)
);
this->firstPinIndicatorDiameter = std::min(
BodyWidget::MAXIMUM_FIRST_PIN_INDICATOR_HEIGHT,
std::max(BodyWidget::MINIMUM_FIRST_PIN_INDICATOR_HEIGHT, static_cast<int>(std::floor(pinCount / 2)))
);
this->orientationIndicatorDiameter = this->firstPinIndicatorDiameter % 2 == 0 ?
this->firstPinIndicatorDiameter + 3
: this->firstPinIndicatorDiameter + 2;
}
void BodyWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter{this};
this->drawWidget(painter);
}
void BodyWidget::drawWidget(QPainter& painter) {
painter.setRenderHints(
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
true
);
const auto bodyHeight = this->height();
const auto bodyRect = QRectF(
0,
0,
this->width(),
bodyHeight
);
// The first pin indicator is just a circle positioned close to the first pin
const auto firstPinIndicatorRect = QRectF(
6,
(bodyHeight - this->firstPinIndicatorDiameter - 6),
this->firstPinIndicatorDiameter,
this->firstPinIndicatorDiameter
);
/*
* The orientation indicator is just a half-circle cut-out, positioned on the side of the DIP package
* closest to the first pin.
*/
const auto orientationIndicatorRect = QRectF(
-(this->orientationIndicatorDiameter / 2),
(bodyHeight / 2) - (this->orientationIndicatorDiameter / 2),
this->orientationIndicatorDiameter,
this->orientationIndicatorDiameter
);
static const auto backgroundColor = QColor{0x37, 0x38, 0x35};
auto targetBodyColor = this->getBodyColor();
if (!this->isEnabled()) {
targetBodyColor.setAlpha(this->getDisableAlphaLevel());
}
painter.setPen(Qt::PenStyle::NoPen);
painter.setBrush(targetBodyColor);
painter.drawRect(bodyRect);
painter.setBrush(backgroundColor);
painter.drawEllipse(firstPinIndicatorRect);
painter.drawEllipse(orientationIndicatorRect);
}
}

View File

@@ -1,49 +0,0 @@
#pragma once
#include <QWidget>
#include <QPainter>
namespace Widgets::InsightTargetWidgets::Dip
{
class BodyWidget: public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor DESIGNABLE true)
Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true)
public:
explicit BodyWidget(QWidget* parent, std::size_t pinCount);
[[nodiscard]] QColor getBodyColor() const {
return this->bodyColor;
}
void setBodyColor(const QColor& color) {
this->bodyColor = color;
}
[[nodiscard]] int getDisableAlphaLevel() const {
return this->disableAlphaLevel;
}
void setDisableAlphaLevel(int level) {
this->disableAlphaLevel = level;
}
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
private:
static constexpr int MAXIMUM_BODY_HEIGHT = 156;
static constexpr int MINIMUM_BODY_HEIGHT = 96;
static constexpr int MAXIMUM_FIRST_PIN_INDICATOR_HEIGHT = 16;
static constexpr int MINIMUM_FIRST_PIN_INDICATOR_HEIGHT = 12;
// These properties can be modified via Qt style sheets (see Stylesheets/DualInlinePackage.qss)
QColor bodyColor = {"#8E8B83"};
int disableAlphaLevel = 100;
int firstPinIndicatorDiameter = 14;
int orientationIndicatorDiameter = 16;
};
}

View File

@@ -1,273 +0,0 @@
#include "DualInlinePackageWidget.hpp"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <vector>
#include <QEvent>
#include <QFile>
#include "src/Services/PathService.hpp"
namespace Widgets::InsightTargetWidgets::Dip
{
DualInlinePackageWidget::DualInlinePackageWidget(
const Targets::TargetVariantDescriptor& variantDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const Targets::TargetState& targetState,
QWidget* parent
)
: TargetPackageWidget(
variantDescriptor,
pinoutDescriptor,
targetState,
parent
)
{
auto stylesheetFile = QFile{QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/"
"DualInlinePackage.qss"
)
};
stylesheetFile.open(QFile::ReadOnly);
this->setStyleSheet(stylesheetFile.readAll());
this->pinWidgets.reserve(this->pinoutDescriptor.pinDescriptors.size());
this->layout = new QVBoxLayout{};
this->layout->setSpacing(PinWidget::WIDTH_SPACING);
this->layout->setContentsMargins(0, 0, 0, 0);
this->layout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
this->topPinLayout = new QHBoxLayout{};
this->topPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
this->topPinLayout->setDirection(QBoxLayout::Direction::RightToLeft);
this->topPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
this->bottomPinLayout = new QHBoxLayout{};
this->bottomPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
this->bottomPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
for (const auto& pinDescriptor : this->pinoutDescriptor.pinDescriptors) {
auto* pinWidget = new PinWidget{
pinDescriptor,
pinDescriptor.padKey.has_value()
? targetDescriptor.tryGetPadDescriptor(*(pinDescriptor.padKey))
: std::nullopt,
this->pinoutDescriptor,
this
};
this->pinWidgets.push_back(pinWidget);
TargetPackageWidget::pinWidgetsByPosition.emplace(pinDescriptor.numericPosition, pinWidget);
if (pinWidget->padDescriptor.has_value()) {
const auto& padDescriptor = pinWidget->padDescriptor->get();
TargetPackageWidget::pinWidgetsByPadId.emplace(padDescriptor.id, pinWidget);
TargetPackageWidget::padDescriptors.push_back(&padDescriptor);
}
if (pinDescriptor.numericPosition <= (this->pinoutDescriptor.pinDescriptors.size() / 2)) {
this->bottomPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignHCenter);
} else {
this->topPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignHCenter);
}
}
this->bodyWidget = new BodyWidget{this, this->pinoutDescriptor.pinDescriptors.size()};
this->layout->addLayout(this->topPinLayout);
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignVCenter);
this->layout->addLayout(this->bottomPinLayout);
this->setLayout(this->layout);
const auto bodyWidgetHeight = this->bodyWidget->height();
const auto bodyWidgetWidth = ((PinWidget::MINIMUM_WIDTH + PinWidget::WIDTH_SPACING)
* static_cast<int>(this->pinWidgets.size() / 2)) - PinWidget::WIDTH_SPACING + 46;
this->bodyWidget->setGeometry(
0,
PinWidget::MAXIMUM_HEIGHT + PinWidget::WIDTH_SPACING,
bodyWidgetWidth,
bodyWidgetHeight
);
const auto width = bodyWidgetWidth;
const auto height = (
(
PinWidget::MAXIMUM_HEIGHT + PinWidget::WIDTH_SPACING + PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
+ PinWidget::PIN_DIRECTION_LABEL_LONG_LINE_LENGTH + (
(PinWidget::LABEL_HEIGHT + PinWidget::PIN_LABEL_SPACING) * 2
)
) * 2) + bodyWidgetHeight;
this->topPinLayout->setGeometry(QRect{0, 0, width, PinWidget::MAXIMUM_HEIGHT});
this->bottomPinLayout->setGeometry(
QRect(
0,
(PinWidget::MAXIMUM_HEIGHT + bodyWidgetHeight + (PinWidget::WIDTH_SPACING * 2)),
width,
PinWidget::MAXIMUM_HEIGHT
)
);
this->topPinLayout->setContentsMargins(23, 0, 23, 0);
this->bottomPinLayout->setContentsMargins( 23, 0, 23, 0);
this->setFixedSize(width, height);
this->setGeometry(
(parent->width() / 2) - (width / 2),
(parent->height() / 2) - (height / 2),
width,
height
);
}
void DualInlinePackageWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter{this};
this->drawWidget(painter);
}
void DualInlinePackageWidget::drawWidget(QPainter& painter) {
using Targets::TargetGpioPadState;
static auto pinNameFont = QFont{"'Ubuntu', sans-serif"};
static auto pinDirectionFont = pinNameFont;
pinNameFont.setPixelSize(11);
pinDirectionFont.setPixelSize(10);
static const auto lineColor = QColor{0x4F, 0x4F, 0x4F};
static const auto pinNameFontColor = QColor{0xA6, 0xA7, 0xAA};
static const auto pinDirectionFontColor = QColor{0x8A, 0x8A, 0x8D};
static const auto pinChangedFontColor = QColor{0x4D, 0x7B, 0xBA};
static const auto inDirectionText = QString{"IN"};
static const auto outDirectionText = QString{"OUT"};
for (const auto* pinWidget : this->pinWidgets) {
const auto pinGeoPosition = pinWidget->pos();
painter.setFont(pinNameFont);
if (pinWidget->position == Position::TOP) {
painter.setPen(lineColor);
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
: PinWidget::PIN_NAME_LABEL_SHORT_LINE_LENGTH
);
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_DIRECTION_LABEL_SHORT_LINE_LENGTH
: PinWidget::PIN_DIRECTION_LABEL_LONG_LINE_LENGTH
);
painter.drawLine(QLine(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength,
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y()
));
painter.setPen(pinWidget->padStateChanged ? pinChangedFontColor : pinNameFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT,
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->pinNameLabelText
);
if (pinWidget->padState.has_value()) {
painter.setFont(pinDirectionFont);
painter.setPen(lineColor);
painter.drawLine(QLine(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
- pinDirectionLabelLineLength,
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
));
painter.setPen(pinDirectionFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - pinDirectionLabelLineLength
- (PinWidget::MAXIMUM_LABEL_HEIGHT * 2),
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->padState->direction == TargetGpioPadState::DataDirection::INPUT
? inDirectionText
: outDirectionText
);
}
} else if (pinWidget->position == Position::BOTTOM) {
painter.setPen(lineColor);
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
: PinWidget::PIN_NAME_LABEL_SHORT_LINE_LENGTH
);
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_DIRECTION_LABEL_SHORT_LINE_LENGTH
: PinWidget::PIN_DIRECTION_LABEL_LONG_LINE_LENGTH
);
painter.drawLine(QLine(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT,
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
));
painter.setPen(pinWidget->padStateChanged ? pinChangedFontColor : pinNameFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() + + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength,
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->pinNameLabelText
);
if (pinWidget->padState.has_value()) {
painter.setFont(pinDirectionFont);
painter.setPen(lineColor);
painter.drawLine(QLine(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
+ PinWidget::MAXIMUM_LABEL_HEIGHT,
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength
));
painter.setPen(pinDirectionFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength,
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->padState->direction == TargetGpioPadState::DataDirection::INPUT
? inDirectionText
: outDirectionText
);
}
}
}
}
}

View File

@@ -1,47 +0,0 @@
#pragma once
#include <QWidget>
#include <vector>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPaintEvent>
#include <QPainter>
#include "../TargetPackageWidget.hpp"
#include "PinWidget.hpp"
#include "BodyWidget.hpp"
#include "src/Targets/TargetDescriptor.hpp"
namespace Widgets::InsightTargetWidgets::Dip
{
/**
* The DualInlinePackageWidget implements a custom Qt widget for the Dual-inline package target variants.
*/
class DualInlinePackageWidget: public TargetPackageWidget
{
Q_OBJECT
public:
DualInlinePackageWidget(
const Targets::TargetVariantDescriptor& variantDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const Targets::TargetState& targetState,
QWidget* parent
);
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
private:
QVBoxLayout* layout = nullptr;
QHBoxLayout* topPinLayout = nullptr;
QHBoxLayout* bottomPinLayout = nullptr;
BodyWidget* bodyWidget = nullptr;
std::vector<PinWidget*> pinWidgets;
};
}

View File

@@ -1,49 +0,0 @@
#include "PinBodyWidget.hpp"
#include <QPainter>
namespace Widgets::InsightTargetWidgets::Dip
{
using namespace Targets;
PinBodyWidget::PinBodyWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
QWidget* parent
)
: TargetPinBodyWidget(
pinDescriptor,
padDescriptor,
parent
)
{
this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT);
}
void PinBodyWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter{this};
this->drawWidget(painter);
}
void PinBodyWidget::drawWidget(QPainter& painter) {
painter.setRenderHints(
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
true
);
auto pinWidth = PinBodyWidget::WIDTH;
auto pinHeight = PinBodyWidget::HEIGHT;
this->setFixedSize(pinWidth, pinHeight);
auto pinColor = this->getBodyColor();
painter.setPen(Qt::PenStyle::NoPen);
painter.setBrush(pinColor);
painter.drawRect(
0,
0,
pinWidth,
pinHeight
);
}
}

View File

@@ -1,30 +0,0 @@
#pragma once
#include <QWidget>
#include <QEvent>
#include "../TargetPinBodyWidget.hpp"
#include "src/Targets/TargetPinDescriptor.hpp"
namespace Widgets::InsightTargetWidgets::Dip
{
class PinBodyWidget: public TargetPinBodyWidget
{
Q_OBJECT
public:
static const int WIDTH = 19;
static const int HEIGHT = 28;
PinBodyWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
QWidget* parent
);
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
};
}

View File

@@ -1,58 +0,0 @@
#include "PinWidget.hpp"
namespace Widgets::InsightTargetWidgets::Dip
{
using namespace Targets;
PinWidget::PinWidget(
const TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
QWidget* parent
)
: TargetPinWidget(
pinDescriptor,
padDescriptor,
pinoutDescriptor,
parent
)
{
this->setFixedSize(PinWidget::MINIMUM_WIDTH, PinWidget::MAXIMUM_HEIGHT);
this->layout = new QVBoxLayout{};
this->layout->setContentsMargins(0, 0, 0, 0);
this->layout->setSpacing(0);
this->bodyWidget = new PinBodyWidget{this->pinDescriptor, padDescriptor, this};
this->position = (pinDescriptor.numericPosition > (pinoutDescriptor.pinDescriptors.size() / 2))
? Position::TOP : Position::BOTTOM;
const bool isTopWidget = this->position == Position::TOP;
this->layout->setAlignment(isTopWidget ? (Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignBottom)
: (Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop));
this->pinNameLabelText = QString::fromStdString(
this->padDescriptor.has_value() ? padDescriptor->get().name : "NC"
);
this->pinNameLabelText.truncate(5);
this->pinNumberLabel = new Label{this};
this->pinNumberLabel->setObjectName("target-pin-number");
this->pinNumberLabel->setText(QString::number(pinDescriptor.numericPosition));
this->pinNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
if (isTopWidget) {
this->layout->setDirection(QBoxLayout::Direction::BottomToTop);
}
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignHCenter);
this->layout->insertSpacing(1, PinWidget::PIN_LABEL_SPACING);
this->layout->addWidget(this->pinNumberLabel, 0, Qt::AlignmentFlag::AlignHCenter);
this->pinNumberLabel->setFixedHeight(PinWidget::LABEL_HEIGHT);
this->setLayout(this->layout);
connect(this->bodyWidget, &PinBodyWidget::clicked, this, &TargetPinWidget::onWidgetBodyClicked);
}
}

View File

@@ -1,62 +0,0 @@
#pragma once
#include <QWidget>
#include <cstdint>
#include <QVBoxLayout>
#include <QPainter>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/Label.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.hpp"
#include "PinBodyWidget.hpp"
namespace Widgets::InsightTargetWidgets::Dip
{
enum class Position: std::uint8_t
{
TOP,
BOTTOM
};
class PinWidget: public TargetPinWidget
{
Q_OBJECT
public:
static constexpr int MINIMUM_WIDTH = PinBodyWidget::WIDTH;
static constexpr int WIDTH_SPACING = 4;
static constexpr int PIN_LABEL_SPACING = 2;
static constexpr int PIN_NAME_LABEL_LONG_LINE_LENGTH = 25;
static constexpr int PIN_NAME_LABEL_SHORT_LINE_LENGTH = 5;
static constexpr int PIN_DIRECTION_LABEL_LONG_LINE_LENGTH = 22;
static constexpr int PIN_DIRECTION_LABEL_SHORT_LINE_LENGTH = 21;
static constexpr int LABEL_HEIGHT = 20;
static constexpr int MAXIMUM_LABEL_WIDTH = 42;
static constexpr int MAXIMUM_LABEL_HEIGHT = 20;
static constexpr int MAXIMUM_HEIGHT = PinBodyWidget::HEIGHT + PinWidget::PIN_LABEL_SPACING
+ PinWidget::LABEL_HEIGHT;
Position position = Position::TOP;
QString pinNameLabelText;
PinWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
QWidget* parent
);
void updatePadState(const Targets::TargetGpioPadState& padState) override {
TargetPinWidget::updatePadState(padState);
if (this->bodyWidget != nullptr) {
this->bodyWidget->setPadState(padState);
}
}
private:
QVBoxLayout* layout = nullptr;
Label* pinNumberLabel = nullptr;
PinBodyWidget* bodyWidget = nullptr;
};
}

View File

@@ -1,20 +0,0 @@
#target-pin-number {
font-size: 13px;
}
#target-pin-name {
font-size: 11px;
}
#target-pin-name {
color: #a6a7aa;
}
#target-pin-direction {
color: #8a8a8d;
font-size: 10px;
}
#target-pin-body {
qproperty-disableAlphaLevel: 100;
}

View File

@@ -1,52 +0,0 @@
#include "BodyWidget.hpp"
#include <QPainter>
namespace Widgets::InsightTargetWidgets::Qfp
{
void BodyWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter{this};
this->drawWidget(painter);
}
void BodyWidget::drawWidget(QPainter& painter) {
painter.setRenderHints(
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
true
);
auto targetBodyColor = this->getBodyColor();
auto backgroundColor = QColor{"#373835"};
if (!this->isEnabled()) {
targetBodyColor.setAlpha(this->getDisableAlphaLevel());
}
painter.setPen(Qt::PenStyle::NoPen);
painter.setBrush(targetBodyColor);
const auto containerSize = this->size();
const auto targetBodyWidth = containerSize.width() - 8;
const auto targetBodyHeight = containerSize.height() - 8;
auto targetBodyPoint = QPoint(
(containerSize.width() / 2) - (targetBodyWidth / 2),
(containerSize.height() / 2) - (targetBodyHeight / 2)
);
painter.drawRect(
targetBodyPoint.x(),
targetBodyPoint.y(),
targetBodyWidth,
targetBodyHeight
);
painter.setBrush(backgroundColor);
painter.drawEllipse(QRectF(
targetBodyPoint.x() + 13,
targetBodyPoint.y() + 13,
18,
18
));
}
}

View File

@@ -1,43 +0,0 @@
#pragma once
#include <QWidget>
namespace Widgets::InsightTargetWidgets::Qfp
{
class BodyWidget: public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor DESIGNABLE true)
Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true)
public:
explicit BodyWidget(QWidget* parent): QWidget(parent) {
this->setObjectName("target-body");
}
[[nodiscard]] QColor getBodyColor() const {
return this->bodyColor;
}
void setBodyColor(QColor color) {
this->bodyColor = color;
}
[[nodiscard]] int getDisableAlphaLevel() const {
return this->disableAlphaLevel;
}
void setDisableAlphaLevel(int level) {
this->disableAlphaLevel = level;
}
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
private:
// These properties can be modified via Qt style sheets (see Stylesheets/QuadFlatPackage.qss)
QColor bodyColor = {"#8E8B83"};
int disableAlphaLevel = 100;
};
}

View File

@@ -1,57 +0,0 @@
#include "PinBodyWidget.hpp"
#include <QPainter>
#include <QEvent>
namespace Widgets::InsightTargetWidgets::Qfp
{
using namespace Targets;
PinBodyWidget::PinBodyWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
bool isVertical,
QWidget* parent
)
: TargetPinBodyWidget(
pinDescriptor,
padDescriptor,
parent
)
, isVertical(isVertical)
{
if (isVertical) {
this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT);
} else {
this->setFixedSize(PinBodyWidget::HEIGHT, PinBodyWidget::WIDTH);
}
}
void PinBodyWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter{this};
this->drawWidget(painter);
}
void PinBodyWidget::drawWidget(QPainter& painter) {
painter.setRenderHints(
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
true
);
auto pinWidth = this->isVertical ? PinBodyWidget::WIDTH : PinBodyWidget::HEIGHT;
auto pinHeight = this->isVertical ? PinBodyWidget::HEIGHT : PinBodyWidget::WIDTH;
this->setFixedSize(pinWidth, pinHeight);
auto pinColor = this->getBodyColor();
painter.setPen(Qt::PenStyle::NoPen);
painter.setBrush(pinColor);
painter.drawRect(
0,
0,
pinWidth,
pinHeight
);
}
}

View File

@@ -1,35 +0,0 @@
#pragma once
#include <QWidget>
#include <QMouseEvent>
#include <utility>
#include "../TargetPinBodyWidget.hpp"
#include "src/Targets/TargetPinDescriptor.hpp"
namespace Widgets::InsightTargetWidgets::Qfp
{
class PinBodyWidget: public TargetPinBodyWidget
{
Q_OBJECT
public:
static const int WIDTH = 17;
static const int HEIGHT = 26;
PinBodyWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
bool isVertical,
QWidget* parent
);
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
private:
bool isVertical = false;
};
}

View File

@@ -1,114 +0,0 @@
#include <QWidget>
#include <QPainter>
#include <QLayout>
#include <cmath>
#include <QEvent>
#include "PinWidget.hpp"
#include "PinBodyWidget.hpp"
namespace Widgets::InsightTargetWidgets::Qfp
{
using namespace Targets;
PinWidget::PinWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
QWidget* parent
)
: TargetPinWidget(
pinDescriptor,
padDescriptor,
pinoutDescriptor,
parent
)
{
this->layout = new QBoxLayout{QBoxLayout::TopToBottom};
this->layout->setContentsMargins(0, 0, 0, 0);
this->layout->setSpacing(0);
const auto pinNumber = pinDescriptor.numericPosition;
auto pinCountPerLayout = (pinoutDescriptor.pinDescriptors.size() / 4);
if (pinNumber <= pinCountPerLayout) {
this->position = Position::LEFT;
} else if (pinNumber > pinCountPerLayout && pinNumber <= (pinCountPerLayout * 2)) {
this->position = Position::BOTTOM;
} else if (pinNumber > (pinCountPerLayout * 2) && pinNumber <= (pinCountPerLayout * 3)) {
this->position = Position::RIGHT;
} else if (pinNumber > (pinCountPerLayout * 3) && pinNumber <= (pinCountPerLayout * 4)) {
this->position = Position::TOP;
}
this->bodyWidget = new PinBodyWidget{
this->pinDescriptor,
padDescriptor,
(this->position == Position::TOP || this->position == Position::BOTTOM),
this
};
this->pinNameLabelText = QString::fromStdString(
this->padDescriptor.has_value() ? padDescriptor->get().name : "NC"
);
this->pinNameLabelText.truncate(5);
this->pinNumberLabel = new Label{this};
this->pinNumberLabel->setObjectName("target-pin-number");
auto pinNumberText = QString::number(pinNumber);
pinNumberText.truncate(5);
this->pinNumberLabel->setText(QString::number(pinNumber));
this->pinNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
if (this->position == Position::LEFT) {
this->layout->setAlignment((Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignRight));
this->layout->setDirection(QBoxLayout::Direction::RightToLeft);
this->setFixedSize(PinWidget::MAXIMUM_HORIZONTAL_WIDTH, PinWidget::MAXIMUM_HORIZONTAL_HEIGHT);
} else if (this->position == Position::BOTTOM) {
this->layout->setAlignment(Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop);
this->layout->setDirection(QBoxLayout::Direction::TopToBottom);
this->setFixedSize(PinWidget::MAXIMUM_VERTICAL_WIDTH, PinWidget::MAXIMUM_VERTICAL_HEIGHT);
} else if (this->position == Position::RIGHT) {
this->layout->setAlignment((Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft));
this->layout->setDirection(QBoxLayout::Direction::LeftToRight);
this->setFixedSize(PinWidget::MAXIMUM_HORIZONTAL_WIDTH, PinWidget::MAXIMUM_HORIZONTAL_HEIGHT);
} else if (this->position == Position::TOP) {
this->layout->setAlignment((Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignBottom));
this->layout->setDirection(QBoxLayout::Direction::BottomToTop);
this->setFixedSize(PinWidget::MAXIMUM_VERTICAL_WIDTH, PinWidget::MAXIMUM_VERTICAL_HEIGHT);
}
this->layout->addWidget(this->bodyWidget);
this->layout->addSpacing(3);
this->layout->addWidget(this->pinNumberLabel);
if (this->position == Position::LEFT || this->position == Position::RIGHT) {
this->pinNumberLabel->setFixedSize(
PinWidget::MAXIMUM_PIN_NUMBER_LABEL_WIDTH,
PinWidget::MAXIMUM_HORIZONTAL_HEIGHT
);
} else if (this->position == Position::TOP || this->position == Position::BOTTOM) {
this->pinNumberLabel->setFixedSize(PinBodyWidget::WIDTH, PinWidget::LABEL_HEIGHT - 2);
}
this->layout->addStretch(1);
this->setLayout(this->layout);
connect(this->bodyWidget, &PinBodyWidget::clicked, this, &TargetPinWidget::onWidgetBodyClicked);
}
void PinWidget::updatePadState(const Targets::TargetGpioPadState& padState) {
TargetPinWidget::updatePadState(padState);
if (this->bodyWidget != nullptr) {
this->bodyWidget->setPadState(padState);
}
}
}

View File

@@ -1,63 +0,0 @@
#pragma once
#include <QWidget>
#include <cstdint>
#include <QBoxLayout>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/Label.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.hpp"
#include "PinBodyWidget.hpp"
namespace Widgets::InsightTargetWidgets::Qfp
{
enum class Position: std::uint8_t
{
TOP,
BOTTOM,
LEFT,
RIGHT,
};
class PinWidget: public TargetPinWidget
{
Q_OBJECT
public:
static constexpr int PIN_WIDGET_LAYOUT_PADDING = 46;
static constexpr int WIDTH_SPACING = 4;
static constexpr int PIN_NAME_LABEL_LONG_LINE_LENGTH = 25;
static constexpr int PIN_NAME_LABEL_SHORT_LINE_LENGTH = 5;
static constexpr int PIN_DIRECTION_LABEL_LONG_LINE_LENGTH = 22;
static constexpr int PIN_DIRECTION_LABEL_SHORT_LINE_LENGTH = 21;
static constexpr int PIN_LABEL_SPACING = 2;
static constexpr int LABEL_HEIGHT = 20;
static constexpr int MAXIMUM_PIN_NUMBER_LABEL_WIDTH = 26;
static constexpr int MAXIMUM_PIN_DIRECTION_LABEL_WIDTH = 24;
static constexpr int MAXIMUM_LABEL_WIDTH = 42;
static constexpr int MAXIMUM_LABEL_HEIGHT = 20;
static constexpr int MAXIMUM_HORIZONTAL_WIDTH = PinBodyWidget::HEIGHT + PinWidget::MAXIMUM_PIN_NUMBER_LABEL_WIDTH + 3;
static constexpr int MAXIMUM_HORIZONTAL_HEIGHT = PinBodyWidget::WIDTH;
static constexpr int MAXIMUM_VERTICAL_HEIGHT = PinBodyWidget::HEIGHT + PinWidget::LABEL_HEIGHT + 3;
static constexpr int MAXIMUM_VERTICAL_WIDTH = PinBodyWidget::WIDTH;
Position position;
QString pinNameLabelText;
PinWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
QWidget* parent
);
void updatePadState(const Targets::TargetGpioPadState& padState) override;
private:
QBoxLayout* layout = nullptr;
Label* pinNumberLabel = nullptr;
Label* pinNameLabel = nullptr;
Label* pinDirectionLabel = nullptr;
PinBodyWidget* bodyWidget = nullptr;
};
}

View File

@@ -1,448 +0,0 @@
#include "QuadFlatPackageWidget.hpp"
#include <QPainter>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <vector>
#include <QFile>
#include <QLine>
#include "src/Services/PathService.hpp"
#include "PinWidget.hpp"
#include "BodyWidget.hpp"
namespace Widgets::InsightTargetWidgets::Qfp
{
using namespace Targets;
QuadFlatPackageWidget::QuadFlatPackageWidget(
const Targets::TargetVariantDescriptor& variantDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const Targets::TargetState& targetState,
QWidget* parent
)
: TargetPackageWidget(
variantDescriptor,
pinoutDescriptor,
targetState,
parent
)
{
assert((this->pinoutDescriptor.pinDescriptors.size() % 4) == 0);
auto stylesheetFile = QFile{QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"
)
};
stylesheetFile.open(QFile::ReadOnly);
this->setStyleSheet(stylesheetFile.readAll());
this->pinWidgets.reserve(this->pinoutDescriptor.pinDescriptors.size());
this->layout = new QVBoxLayout{};
this->layout->setSpacing(0);
this->layout->setContentsMargins(0, 0, 0, 0);
this->horizontalLayout = new QHBoxLayout{};
this->horizontalLayout->setSpacing(0);
this->horizontalLayout->setDirection(QBoxLayout::Direction::LeftToRight);
this->horizontalLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
this->topPinLayout = new QHBoxLayout{};
this->topPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
this->topPinLayout->setDirection(QBoxLayout::Direction::RightToLeft);
this->topPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
this->rightPinLayout = new QVBoxLayout();
this->rightPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
this->rightPinLayout->setDirection(QBoxLayout::Direction::BottomToTop);
this->rightPinLayout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
this->bottomPinLayout = new QHBoxLayout{};
this->bottomPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
this->bottomPinLayout->setDirection(QBoxLayout::Direction::LeftToRight);
this->bottomPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
this->leftPinLayout = new QVBoxLayout{};
this->leftPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
this->leftPinLayout->setDirection(QBoxLayout::Direction::TopToBottom);
this->leftPinLayout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
const auto pinCountPerLayout = static_cast<int>(this->pinoutDescriptor.pinDescriptors.size() / 4);
for (const auto& pinDescriptor: this->pinoutDescriptor.pinDescriptors) {
auto* pinWidget = new PinWidget{
pinDescriptor,
pinDescriptor.padKey.has_value()
? targetDescriptor.tryGetPadDescriptor(*(pinDescriptor.padKey))
: std::nullopt,
this->pinoutDescriptor,
this
};
this->pinWidgets.push_back(pinWidget);
TargetPackageWidget::pinWidgetsByPosition.emplace(pinDescriptor.numericPosition, pinWidget);
if (pinWidget->padDescriptor.has_value()) {
const auto& padDescriptor = pinWidget->padDescriptor->get();
TargetPackageWidget::pinWidgetsByPadId.emplace(padDescriptor.id, pinWidget);
TargetPackageWidget::padDescriptors.push_back(&padDescriptor);
}
if (pinWidget->position == Position::LEFT) {
this->leftPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignRight);
} else if (pinWidget->position == Position::BOTTOM) {
this->bottomPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignTop);
} else if (pinWidget->position == Position::RIGHT) {
this->rightPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignLeft);
} else if (pinWidget->position == Position::TOP) {
this->topPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignBottom);
}
}
this->bodyWidget = new BodyWidget{this};
this->layout->addLayout(this->topPinLayout);
this->horizontalLayout->addLayout(this->leftPinLayout);
this->horizontalLayout->addWidget(this->bodyWidget);
this->horizontalLayout->addLayout(this->rightPinLayout);
this->layout->addLayout(this->horizontalLayout);
this->layout->addLayout(this->bottomPinLayout);
this->setLayout(this->layout);
// Layout sizing, positioning and padding
const auto verticalPinWidgetHeight = PinWidget::MAXIMUM_VERTICAL_HEIGHT;
const auto verticalPinWidgetWidth = PinWidget::MAXIMUM_VERTICAL_WIDTH;
const auto horizontalPinWidgetHeight = PinWidget::MAXIMUM_HORIZONTAL_HEIGHT;
const auto horizontalPinWidgetWidth = PinWidget::MAXIMUM_HORIZONTAL_WIDTH;
/*
* Horizontal layouts are the right and left pin layouts - the ones that hold horizontal pin widgets.
* The bottom and top layouts are vertical layouts, as they hold the vertical pin widgets.
*/
const auto horizontalLayoutHeight = ((horizontalPinWidgetHeight + PinWidget::WIDTH_SPACING) * pinCountPerLayout
+ PinWidget::PIN_WIDGET_LAYOUT_PADDING - PinWidget::WIDTH_SPACING);
const auto verticalLayoutWidth = ((verticalPinWidgetWidth + PinWidget::WIDTH_SPACING) * pinCountPerLayout
+ PinWidget::PIN_WIDGET_LAYOUT_PADDING - PinWidget::WIDTH_SPACING);
const auto height = horizontalLayoutHeight + (verticalPinWidgetHeight * 2) + (
(
PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
+ PinWidget::PIN_DIRECTION_LABEL_LONG_LINE_LENGTH
+ (PinWidget::MAXIMUM_LABEL_HEIGHT * 2)
+ (PinWidget::PIN_LABEL_SPACING * 3)
) * 2
);
const auto width = verticalLayoutWidth + (horizontalPinWidgetWidth * 2) + (
(
PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
+ PinWidget::MAXIMUM_LABEL_WIDTH
+ PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH
+ (PinWidget::PIN_LABEL_SPACING * 2)
) * 2
);
this->topPinLayout->insertSpacing(0, horizontalPinWidgetWidth);
this->topPinLayout->addSpacing(horizontalPinWidgetWidth);
this->bottomPinLayout->insertSpacing(0, horizontalPinWidgetWidth);
this->bottomPinLayout->addSpacing(horizontalPinWidgetWidth);
this->leftPinLayout->setGeometry(QRect(
0,
verticalPinWidgetHeight,
horizontalPinWidgetWidth,
horizontalLayoutHeight
));
this->bodyWidget->setFixedSize(verticalLayoutWidth, horizontalLayoutHeight);
this->rightPinLayout->setGeometry(QRect(
horizontalLayoutHeight + horizontalPinWidgetWidth,
verticalPinWidgetHeight,
horizontalPinWidgetWidth,
horizontalLayoutHeight
));
const auto pinWidgetLayoutMargin = PinWidget::PIN_WIDGET_LAYOUT_PADDING / 2;
this->topPinLayout->setContentsMargins(
pinWidgetLayoutMargin,
0,
pinWidgetLayoutMargin,
0
);
this->bottomPinLayout->setContentsMargins(
pinWidgetLayoutMargin,
0,
pinWidgetLayoutMargin,
0
);
this->leftPinLayout->setContentsMargins(
0,
pinWidgetLayoutMargin,
0,
pinWidgetLayoutMargin
);
this->rightPinLayout->setContentsMargins(
0,
pinWidgetLayoutMargin,
0,
pinWidgetLayoutMargin
);
this->setFixedSize(width, height);
// Set the fixed size and center the widget
this->setGeometry(
(parent->width() / 2) - (width / 2),
(parent->height() / 2) - (height / 2),
width,
height
);
}
void QuadFlatPackageWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter{this};
this->drawWidget(painter);
}
void QuadFlatPackageWidget::drawWidget(QPainter& painter) {
static auto pinNameFont = QFont{"'Ubuntu', sans-serif"};
static auto pinDirectionFont = pinNameFont;
pinNameFont.setPixelSize(11);
pinDirectionFont.setPixelSize(10);
static const auto lineColor = QColor{0x4F, 0x4F, 0x4F};
static const auto pinNameFontColor = QColor{0xA6, 0xA7, 0xAA};
static const auto pinDirectionFontColor = QColor{0x8A, 0x8A, 0x8D};
static const auto pinChangedFontColor = QColor{0x4D, 0x7B, 0xBA};
static const auto inDirectionText = QString{"IN"};
static const auto outDirectionText = QString{"OUT"};
for (const auto* pinWidget : this->pinWidgets) {
const auto pinGeoPosition = pinWidget->pos();
const auto& padState = pinWidget->getPadState();
const auto padStateChanged = pinWidget->hasPadStateChanged();
painter.setFont(pinNameFont);
if (pinWidget->position == Position::LEFT) {
painter.setPen(lineColor);
painter.drawLine(QLine{
pinGeoPosition.x() - PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH,
pinGeoPosition.y() + (PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2),
pinGeoPosition.x(),
pinGeoPosition.y() + (PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2)
});
painter.setPen(padStateChanged ? pinChangedFontColor : pinNameFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() - PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
- PinWidget::MAXIMUM_LABEL_WIDTH - (PinWidget::PIN_LABEL_SPACING * 2),
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->pinNameLabelText
);
if (padState.has_value()) {
painter.setFont(pinDirectionFont);
painter.setPen(pinDirectionFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() - PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
- PinWidget::MAXIMUM_LABEL_WIDTH - (PinWidget::PIN_LABEL_SPACING * 3)
- PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
padState->direction == TargetGpioPadState::DataDirection::INPUT
? inDirectionText
: outDirectionText
);
}
} else if (pinWidget->position == Position::RIGHT) {
painter.setPen(lineColor);
painter.drawLine(QLine{
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH,
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH
+ PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH,
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
});
painter.setPen(padStateChanged ? pinChangedFontColor : pinNameFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH
+ PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH + 8,
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->pinNameLabelText
);
if (padState.has_value()) {
painter.setFont(pinDirectionFont);
painter.setPen(pinDirectionFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH
+ PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH + PinWidget::MAXIMUM_LABEL_WIDTH
+ (PinWidget::PIN_LABEL_SPACING * 3),
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
padState->direction == TargetGpioPadState::DataDirection::INPUT
? inDirectionText
: outDirectionText
);
}
} else if (pinWidget->position == Position::TOP) {
painter.setPen(lineColor);
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
: PinWidget::PIN_NAME_LABEL_SHORT_LINE_LENGTH
);
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_DIRECTION_LABEL_SHORT_LINE_LENGTH
: PinWidget::PIN_DIRECTION_LABEL_LONG_LINE_LENGTH
);
painter.drawLine(QLine{
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength,
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y()
});
painter.setPen(padStateChanged ? pinChangedFontColor : pinNameFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT,
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->pinNameLabelText
);
if (padState.has_value()) {
painter.setFont(pinDirectionFont);
painter.setPen(lineColor);
painter.drawLine(QLine{
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
- pinDirectionLabelLineLength,
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
});
painter.setPen(pinDirectionFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() - pinNameLabelLineLength - pinDirectionLabelLineLength
- (PinWidget::MAXIMUM_LABEL_HEIGHT * 2),
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
padState->direction == TargetGpioPadState::DataDirection::INPUT
? inDirectionText
: outDirectionText
);
}
} else if (pinWidget->position == Position::BOTTOM) {
painter.setPen(lineColor);
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_NAME_LABEL_LONG_LINE_LENGTH
: PinWidget::PIN_NAME_LABEL_SHORT_LINE_LENGTH
);
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0
? PinWidget::PIN_DIRECTION_LABEL_SHORT_LINE_LENGTH
: PinWidget::PIN_DIRECTION_LABEL_LONG_LINE_LENGTH
);
painter.drawLine(QLine{
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT,
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
});
painter.setPen(padStateChanged ? pinChangedFontColor : pinNameFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() + + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength,
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
pinWidget->pinNameLabelText
);
if (padState.has_value()) {
painter.setFont(pinDirectionFont);
painter.setPen(lineColor);
painter.drawLine(QLine{
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
+ PinWidget::MAXIMUM_LABEL_HEIGHT,
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength
});
painter.setPen(pinDirectionFontColor);
painter.drawText(
QRect(
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength,
PinWidget::MAXIMUM_LABEL_WIDTH,
PinWidget::MAXIMUM_LABEL_HEIGHT
),
Qt::AlignCenter,
padState->direction == TargetGpioPadState::DataDirection::INPUT
? inDirectionText
: outDirectionText
);
}
}
}
}
}

View File

@@ -1,48 +0,0 @@
#pragma once
#include <QWidget>
#include <vector>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "../TargetPackageWidget.hpp"
#include "PinWidget.hpp"
#include "BodyWidget.hpp"
#include "src/Targets/TargetDescriptor.hpp"
namespace Widgets::InsightTargetWidgets::Qfp
{
/**
* QuadFlatPackageWidget implements a custom Qt widget for Quad-flat package variants.
*/
class QuadFlatPackageWidget: public TargetPackageWidget
{
Q_OBJECT
public:
QuadFlatPackageWidget(
const Targets::TargetVariantDescriptor& variantDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetDescriptor& targetDescriptor,
const Targets::TargetState& targetState,
QWidget* parent
);
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
private:
QVBoxLayout* layout = nullptr;
QHBoxLayout* horizontalLayout = nullptr;
QHBoxLayout* topPinLayout = nullptr;
QVBoxLayout* rightPinLayout = nullptr;
QHBoxLayout* bottomPinLayout = nullptr;
QVBoxLayout* leftPinLayout = nullptr;
BodyWidget* bodyWidget = nullptr;
std::vector<PinWidget*> pinWidgets;
};
}

View File

@@ -1,7 +0,0 @@
#target-pin-number {
font-size: 13px;
}
#target-pin-body {
qproperty-disableAlphaLevel: 100;
}

View File

@@ -1,93 +0,0 @@
#include "TargetPackageWidget.hpp"
#include <QEvent>
#include "src/Insight/InsightSignals.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "src/Insight/InsightWorker/Tasks/ReadTargetGpioPadStates.hpp"
namespace Widgets::InsightTargetWidgets
{
using Targets::TargetState;
using Targets::TargetExecutionState;
TargetPackageWidget::TargetPackageWidget(
const Targets::TargetVariantDescriptor& variantDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetState& targetState,
QWidget* parent
)
: QWidget(parent)
, variantDescriptor(variantDescriptor)
, pinoutDescriptor(pinoutDescriptor)
, targetState(targetState)
{
auto* insightSignals = InsightSignals::instance();
QObject::connect(
insightSignals,
&InsightSignals::programmingModeEnabled,
this,
&TargetPackageWidget::onProgrammingModeEnabled
);
QObject::connect(
insightSignals,
&InsightSignals::programmingModeDisabled,
this,
&TargetPackageWidget::onProgrammingModeDisabled
);
this->setDisabled(true);
}
void TargetPackageWidget::refreshPadStates(std::optional<std::function<void(void)>> callback) {
const auto refreshTask = QSharedPointer<ReadTargetGpioPadStates>{
new ReadTargetGpioPadStates{this->padDescriptors},
&QObject::deleteLater
};
QObject::connect(
refreshTask.get(),
&ReadTargetGpioPadStates::targetGpioPadStatesRead,
this,
&TargetPackageWidget::updatePadStates
);
if (callback.has_value()) {
QObject::connect(
refreshTask.get(),
&InsightWorkerTask::completed,
this,
callback.value()
);
}
InsightWorker::queueTask(refreshTask);
}
void TargetPackageWidget::updatePadStates(const Targets::TargetGpioPadDescriptorAndStatePairs& padStatePairs) {
for (const auto& [padDescriptor, padState] : padStatePairs) {
const auto widgetIt = this->pinWidgetsByPadId.find(padDescriptor.id);
if (widgetIt == this->pinWidgetsByPadId.end()) {
continue;
}
widgetIt->second->updatePadState(padState);
}
this->update();
}
void TargetPackageWidget::onProgrammingModeEnabled() {
if (this->targetState.executionState == TargetExecutionState::STOPPED) {
this->setDisabled(true);
}
}
void TargetPackageWidget::onProgrammingModeDisabled() {
if (this->targetState.executionState == TargetExecutionState::STOPPED) {
this->setDisabled(false);
}
}
}

View File

@@ -1,55 +0,0 @@
#pragma once
#include <QWidget>
#include <utility>
#include <unordered_map>
#include <optional>
#include "src/Targets/TargetVariantDescriptor.hpp"
#include "src/Targets/TargetPinoutDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "src/Targets/TargetGpioPadState.hpp"
#include "src/Targets/TargetState.hpp"
#include "TargetPinWidget.hpp"
namespace Widgets::InsightTargetWidgets
{
/**
* Each custom target package widget should be derived from this class.
*/
class TargetPackageWidget: public QWidget
{
Q_OBJECT
public:
TargetPackageWidget(
const Targets::TargetVariantDescriptor& variantDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
const Targets::TargetState& targetState,
QWidget* parent
);
virtual void refreshPadStates(std::optional<std::function<void(void)>> callback = std::nullopt);
QSize sizeHint() const override {
return this->minimumSize();
}
QSize minimumSizeHint() const override {
return this->sizeHint();
}
protected:
const Targets::TargetVariantDescriptor& variantDescriptor;
const Targets::TargetPinoutDescriptor& pinoutDescriptor;
const Targets::TargetState& targetState;
std::unordered_map<std::uint16_t, TargetPinWidget*> pinWidgetsByPosition;
std::unordered_map<Targets::TargetPadId, TargetPinWidget*> pinWidgetsByPadId;
Targets::TargetPadDescriptors padDescriptors;
virtual void updatePadStates(const Targets::TargetGpioPadDescriptorAndStatePairs& padStatePairs);
void onProgrammingModeEnabled();
void onProgrammingModeDisabled();
};
}

View File

@@ -1,30 +0,0 @@
#include "TargetPackageWidgetContainer.hpp"
#include <QLayout>
namespace Widgets::InsightTargetWidgets
{
TargetPackageWidgetContainer::TargetPackageWidgetContainer(QWidget* parent): QWidget(parent) {}
void TargetPackageWidgetContainer::setPackageWidget(TargetPackageWidget* packageWidget) {
this->packageWidget = packageWidget;
if (packageWidget != nullptr) {
this->layout()->addWidget(packageWidget);
}
}
void TargetPackageWidgetContainer::resizeEvent(QResizeEvent* event) {
if (this->packageWidget == nullptr) {
return;
}
const auto packageSize = this->packageWidget->size();
this->packageWidget->setGeometry(
(this->width() / 2) - (packageSize.width() / 2),
(this->height() / 2) - (packageSize.height() / 2),
packageSize.width(),
packageSize.height()
);
}
}

View File

@@ -1,25 +0,0 @@
#pragma once
#include <QWidget>
#include <QResizeEvent>
#include "TargetPackageWidget.hpp"
namespace Widgets::InsightTargetWidgets
{
class TargetPackageWidgetContainer: public QWidget
{
Q_OBJECT
public:
TargetPackageWidgetContainer(QWidget* parent);
void setPackageWidget(TargetPackageWidget* packageWidget);
protected:
void resizeEvent(QResizeEvent* event) override;
private:
TargetPackageWidget* packageWidget = nullptr;
};
}

View File

@@ -1,92 +0,0 @@
#include <QEvent>
#include "TargetPinBodyWidget.hpp"
namespace Widgets::InsightTargetWidgets
{
using namespace Targets;
TargetPinBodyWidget::TargetPinBodyWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
QWidget* parent
)
: QWidget(parent)
, pinDescriptor(pinDescriptor)
, padDescriptor(padDescriptor)
{
this->setObjectName("target-pin-body");
this->setToolTip(
this->padDescriptor.has_value()
? QString::fromStdString(this->padDescriptor->get().name).toUpper()
: "Not connected"
);
}
QColor TargetPinBodyWidget::getBodyColor() {
using Targets::TargetGpioPadState;
auto pinColor = this->defaultBodyColor;
if (this->padDescriptor.has_value()) {
const auto& padDescriptor = this->padDescriptor->get();
if (padDescriptor.type == TargetPadType::VCC) {
pinColor = this->vccBodyColor;
} else if (padDescriptor.type == TargetPadType::GND) {
pinColor = this->gndBodyColor;
} else if (padDescriptor.type == TargetPadType::GPIO) {
if (this->padState.has_value()) {
if (this->padState->value == TargetGpioPadState::State::HIGH) {
pinColor = this->padState->direction == TargetGpioPadState::DataDirection::OUTPUT
? this->outputHighBodyColor
: this->inputHighBodyColor;
}
if (
(
this->padState->direction == TargetGpioPadState::DataDirection::OUTPUT
|| (
this->padState->direction == TargetGpioPadState::DataDirection::INPUT
&& this->padState->value == TargetGpioPadState::State::LOW
)
)
&& !this->hoverActive
) {
pinColor.setAlpha(220);
}
}
}
}
if (!this->isEnabled()) {
pinColor.setAlpha(this->disableAlphaLevel);
}
return pinColor;
}
bool TargetPinBodyWidget::event(QEvent* event) {
if (this->padState.has_value() && this->padState->direction == TargetGpioPadState::DataDirection::OUTPUT) {
switch (event->type()) {
case QEvent::Enter: {
this->hoverActive = true;
this->repaint();
break;
}
case QEvent::Leave: {
this->hoverActive = false;
this->repaint();
break;
}
default: {
break;
}
}
}
return QWidget::event(event);
}
}

View File

@@ -1,118 +0,0 @@
#pragma once
#include <QWidget>
#include <QEvent>
#include <QMouseEvent>
#include <optional>
#include <functional>
#include "src/Targets/TargetPinDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "src/Targets/TargetGpioPadState.hpp"
namespace Widgets::InsightTargetWidgets
{
class TargetPinBodyWidget: public QWidget
{
Q_OBJECT
/*
* Pin body colors can be set in QSS files.
*/
Q_PROPERTY(QColor defaultBodyColor READ getDefaultBodyColor WRITE setDefaultBodyColor DESIGNABLE true)
Q_PROPERTY(QColor vccBodyColor READ getVccBodyColor WRITE setVccBodyColor DESIGNABLE true)
Q_PROPERTY(QColor gndBodyColor READ getGndBodyColor WRITE setGndBodyColor DESIGNABLE true)
Q_PROPERTY(QColor outputHighBodyColor READ getOutputHighBodyColor WRITE setOutputHighBodyColor DESIGNABLE true)
Q_PROPERTY(QColor inputHighBodyColor READ getInputHighBodyColor WRITE setInputHighBodyColor DESIGNABLE true)
Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true)
public:
TargetPinBodyWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
QWidget* parent
);
void setPadState(const Targets::TargetGpioPadState& padState) {
this->padState = padState;
}
const QColor& getDefaultBodyColor() const {
return this->defaultBodyColor;
}
void setDefaultBodyColor(const QColor& color) {
this->defaultBodyColor = color;
}
const QColor& getVccBodyColor() const {
return this->vccBodyColor;
}
void setVccBodyColor(const QColor& vccBodyColor) {
this->vccBodyColor = vccBodyColor;
}
const QColor& getGndBodyColor() const {
return this->gndBodyColor;
}
void setGndBodyColor(const QColor& gndBodyColor) {
this->gndBodyColor = gndBodyColor;
}
const QColor& getOutputHighBodyColor() const {
return this->outputHighBodyColor;
}
void setOutputHighBodyColor(const QColor& outputHighBodyColor) {
this->outputHighBodyColor = outputHighBodyColor;
}
const QColor& getInputHighBodyColor() const {
return this->inputHighBodyColor;
}
void setInputHighBodyColor(const QColor& inputHighBodyColor) {
this->inputHighBodyColor = inputHighBodyColor;
}
int getDisableAlphaLevel() const {
return this->disableAlphaLevel;
}
void setDisableAlphaLevel(int level) {
this->disableAlphaLevel = level;
}
signals:
void clicked();
protected:
const Targets::TargetPinDescriptor& pinDescriptor;
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor;
std::optional<Targets::TargetGpioPadState> padState;
bool hoverActive = false;
QColor defaultBodyColor = {"#908D85"};
QColor vccBodyColor = {"#70383A"};
QColor gndBodyColor = {"#484A4B"};
QColor outputHighBodyColor = {"#3C5E62"};
QColor inputHighBodyColor = {"#7B5E38"};
int disableAlphaLevel = 100;
QColor getBodyColor();
bool event(QEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override {
if (event->button() == Qt::MouseButton::LeftButton) {
emit this->clicked();
}
QWidget::mouseReleaseEvent(event);
}
};
}

View File

@@ -1,56 +0,0 @@
#include "TargetPinWidget.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "src/Insight/InsightWorker/Tasks/SetTargetGpioPadState.hpp"
namespace Widgets::InsightTargetWidgets
{
TargetPinWidget::TargetPinWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
QWidget* parent
)
: QWidget(parent)
, pinDescriptor(pinDescriptor)
, padDescriptor(padDescriptor)
, pinoutDescriptor(pinoutDescriptor)
{
if (!this->padDescriptor.has_value() || this->padDescriptor->get().type == Targets::TargetPadType::OTHER) {
this->setDisabled(true);
}
}
void TargetPinWidget::onWidgetBodyClicked() {
using Targets::TargetGpioPadState;
if (
this->padDescriptor.has_value()
&& this->padState.has_value()
&& this->padState->direction == TargetGpioPadState::DataDirection::OUTPUT
) {
this->setDisabled(true);
auto newPadState = *this->padState;
newPadState.value = this->padState->value == TargetGpioPadState::State::HIGH
? TargetGpioPadState::State::LOW
: TargetGpioPadState::State::HIGH;
const auto setPadStateTask = QSharedPointer<SetTargetGpioPadState>{
new SetTargetGpioPadState{this->padDescriptor->get(), newPadState},
&QObject::deleteLater
};
QObject::connect(setPadStateTask.get(), &InsightWorkerTask::completed, this, [this, newPadState] {
this->updatePadState(newPadState);
this->setDisabled(false);
});
QObject::connect(setPadStateTask.get(), &InsightWorkerTask::failed, this, [this] {
this->setDisabled(false);
});
InsightWorker::queueTask(setPadStateTask);
}
}
}

View File

@@ -1,55 +0,0 @@
#pragma once
#include <QWidget>
#include <utility>
#include <optional>
#include <functional>
#include "src/Targets/TargetPinDescriptor.hpp"
#include "src/Targets/TargetPadDescriptor.hpp"
#include "src/Targets/TargetPinoutDescriptor.hpp"
#include "src/Targets/TargetGpioPadState.hpp"
#include "src/Services/StringService.hpp"
namespace Widgets::InsightTargetWidgets
{
class TargetPinWidget: public QWidget
{
Q_OBJECT
public:
const Targets::TargetPinDescriptor& pinDescriptor;
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor;
const Targets::TargetPinoutDescriptor& pinoutDescriptor;
std::optional<Targets::TargetGpioPadState> padState;
bool padStateChanged = false;
TargetPinWidget(
const Targets::TargetPinDescriptor& pinDescriptor,
std::optional<std::reference_wrapper<const Targets::TargetPadDescriptor>> padDescriptor,
const Targets::TargetPinoutDescriptor& pinoutDescriptor,
QWidget* parent
);
int getPinNumber() const {
return Services::StringService::toUint8(this->pinDescriptor.position, 10);
}
const std::optional<Targets::TargetGpioPadState>& getPadState() const {
return this->padState;
}
virtual void updatePadState(const Targets::TargetGpioPadState& padState) {
this->padStateChanged = !this->padState.has_value() || this->padState != padState;
this->padState = padState;
}
bool hasPadStateChanged() const {
return this->padStateChanged;
}
public slots:
virtual void onWidgetBodyClicked();
};
}

View File

@@ -50,6 +50,14 @@ InsightProjectSettings::InsightProjectSettings(const QJsonObject& jsonObject) {
this->registersPaneState = this->paneStateFromJson(jsonObject.find("registersPaneState")->toObject());
}
if (jsonObject.contains("refreshRegistersOnTargetStopped")) {
this->refreshRegistersOnTargetStopped = jsonObject.value("refreshRegistersOnTargetStopped").toBool();
}
if (jsonObject.contains("refreshGpioOnTargetStopped")) {
this->refreshGpioOnTargetStopped = jsonObject.value("refreshGpioOnTargetStopped").toBool();
}
if (jsonObject.contains("selectedVariantKey")) {
this->selectedVariantKey = jsonObject.find("selectedVariantKey")->toString().toStdString();
}
@@ -99,6 +107,9 @@ QJsonObject InsightProjectSettings::toJson() const {
insightObj.insert("registersPaneState", this->paneStateToJson(this->registersPaneState.value()));
}
insightObj.insert("refreshRegistersOnTargetStopped", this->refreshRegistersOnTargetStopped);
insightObj.insert("refreshGpioOnTargetStopped", this->refreshGpioOnTargetStopped);
if (this->selectedVariantKey.has_value()) {
insightObj.insert("selectedVariantKey", QString::fromStdString(this->selectedVariantKey.value()));
}

View File

@@ -27,6 +27,9 @@ public:
std::optional<Widgets::PanelState> bottomPanelState;
std::optional<Widgets::PaneState> registersPaneState;
bool refreshRegistersOnTargetStopped = false;
bool refreshGpioOnTargetStopped = false;
/**
* The key of the previously selected variant
*/

View File

@@ -602,10 +602,10 @@ namespace Targets::Microchip::Avr8
output.emplace_back(
*padDescriptor,
TargetGpioPadState{
(readGpioReg(stateRegisterDescriptor) & gpioPadDescriptor.registerMask) != 0
.value = (readGpioReg(stateRegisterDescriptor) & gpioPadDescriptor.registerMask) != 0
? TargetGpioPadState::State::HIGH
: TargetGpioPadState::State::LOW,
ddrValue
.direction = ddrValue
}
);
}

View File

@@ -443,6 +443,14 @@ namespace Targets::RiscV::Wch
const auto& portClockEnableRegisterValue = readGpioReg(this->portPeripheralClockEnableRegisterDescriptor);
if (!portClockEnableRegisterValue.bitFieldAs<bool>(gpioPadDescriptor.peripheralClockEnableBitFieldDescriptor)) {
// The port peripheral is currently disabled. We cannot obtain any meaningful state for this pad
output.emplace_back(
*padDescriptor,
TargetGpioPadState{
.disabled = true,
.value = TargetGpioPadState::State::UNKNOWN,
.direction = TargetGpioPadState::DataDirection::UNKNOWN
}
);
continue;
}
@@ -453,10 +461,10 @@ namespace Targets::RiscV::Wch
output.emplace_back(
*padDescriptor,
TargetGpioPadState{
readGpioReg(gpioPadDescriptor.inputDataRegisterDescriptor).bitFieldAs<bool>(
.value = readGpioReg(gpioPadDescriptor.inputDataRegisterDescriptor).bitFieldAs<bool>(
gpioPadDescriptor.inputDataBitFieldDescriptor
) ? TargetGpioPadState::State::HIGH : TargetGpioPadState::State::LOW,
TargetGpioPadState::DataDirection::INPUT
.direction = TargetGpioPadState::DataDirection::INPUT
}
);
@@ -466,10 +474,10 @@ namespace Targets::RiscV::Wch
output.emplace_back(
*padDescriptor,
TargetGpioPadState{
readGpioReg(gpioPadDescriptor.outputDataRegisterDescriptor).bitFieldAs<bool>(
.value = readGpioReg(gpioPadDescriptor.outputDataRegisterDescriptor).bitFieldAs<bool>(
gpioPadDescriptor.outputDataBitFieldDescriptor
) ? TargetGpioPadState::State::HIGH : TargetGpioPadState::State::LOW,
TargetGpioPadState::DataDirection::OUTPUT
.direction = TargetGpioPadState::DataDirection::OUTPUT
}
);
}

View File

@@ -1186,7 +1186,7 @@ namespace Targets::TargetDescription
return TargetPadType::VCC;
}
if (padNameLower.find("gnd") == 0 || padNameLower.find("agnd") == 0) {
if (padNameLower.find("gnd") == 0 || padNameLower.find("agnd") == 0 || padNameLower.find("vss") == 0) {
return TargetPadType::GND;
}

View File

@@ -15,24 +15,19 @@ namespace Targets
{
HIGH,
LOW,
UNKNOWN,
};
enum class DataDirection: std::uint8_t
{
INPUT,
OUTPUT,
UNKNOWN,
};
State value;
DataDirection direction;
TargetGpioPadState(
State value,
DataDirection direction
)
: value(value)
, direction(direction)
{}
bool disabled = false;
State value = State::UNKNOWN;
DataDirection direction = DataDirection::UNKNOWN;
bool operator == (const TargetGpioPadState& other) const {
return this->value == other.value && this->direction == other.direction;