/
pi_coder
/
ByteMachine
Обзор
Документация
Войти
/
pi_coder
/
ByteMachine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/nodes/take_node.cpp
550 строк
17 KB
pimenov-and
Перенос функциональности из старого проекта, в основном это описания узлов
19 июл 2026, 20:13
19 июл 2026, 20:13
cb3c51b
Код
Авторство
О чём код?
//////////////////////////////////////////////////////////////// // ByteMachine // Узел для получения определенного количества байтов //////////////////////////////////////////////////////////////// #include "take_node.h" #include "node_name_manager.h" #include "undo/undo_change_object_prop_value.h" #include "qt_helper.h" #include "xml_helper.h" #include "colors.h" #include <QPainter> #include <QDomDocument> #include <QUndoStack> //============================================================== using std::size_t; //============================================================== // Конструктор с параметрами //============================================================== TakeNode::TakeNode(QUndoStack *undoStack, QObject *parent) : BaseNode{undoStack, parent} { name_ = nodeNameManager()->addName("take"); Q_ASSERT(!name_.isEmpty()); createInputPin(); createOutputPin(); TakeNode::updateStateInfo(); } //============================================================== // Чтение из XML //============================================================== void TakeNode::readFromXml(const QDomElement &elem) { Q_ASSERT(!elem.isNull()); const QString name = readNameFromXml(elem); const qint32 left = readLeftFromXml(elem); const qint32 top = readTopFromXml(elem); const qint32 countByte = readByteCountFromXml(elem); const DirectionTypes direction = readDirectionFromXml(elem); const bool bypass = readBypassFromXml(elem); const QString comment = readCommentFromXml(elem); Q_UNUSED(name) Q_UNUSED(left) Q_UNUSED(top) Q_UNUSED(countByte) Q_UNUSED(direction) Q_UNUSED(bypass) Q_UNUSED(comment) } //============================================================== // Запись в XML //============================================================== void TakeNode::writeToXml(QDomDocument &doc, QDomElement &elem) const { Q_ASSERT(!doc.isNull()); Q_ASSERT(!elem.isNull()); writeNameToXml(doc, elem); writeLeftToXml(doc, elem); writeTopToXml(doc, elem); writeByteCountToXml(doc, elem); writeDirectionToXml(doc, elem); writeBypassToXml(doc, elem); writeCommentToXml(doc, elem); } //============================================================== // Получение размера данных //============================================================== size_t TakeNode::dataSize() const { if (stateInfo_.isError()) { return 0; } return !isBypass() ? byteCount_ : inputDataSize(); } //============================================================== // Получение байта данных //============================================================== quint8 TakeNode::dataByte(size_t index) const { Q_ASSERT_X(index < dataSize(), "Check index", qPrintable(QString("index: %1, dataSize: %2").arg(index).arg(dataSize()))); if (!isBypass()) { switch (direction_) { case DirectionTypes::Begin: { return inputPin_->dataByte(index); } case DirectionTypes::End: { return inputPin_->dataByte(dataSize() - byteCount_ + index); } default: { return 0; } } } else { return inputPin_->dataByte(index); } } //============================================================== // Получение блока данных //============================================================== ByteList TakeNode::dataBlock(size_t index, size_t count) const { Q_ASSERT_X(index + count <= dataSize(), "Check index and count", qPrintable(QString("index: %1, count: %2, dataSize: %3"). arg(index).arg(count).arg(dataSize()))); if (!isBypass()) { switch (direction_) { case DirectionTypes::Begin: { return inputPin_->dataBlock(index, count); } case DirectionTypes::End: { return inputPin_->dataBlock(inputDataSize() - byteCount_ + index, count); } default: { return ByteList{}; } } } else { return inputPin_->dataBlock(index, count); } } //============================================================== // Функция вызывается при изменении данных //============================================================== void TakeNode::dataChanged() { startHighlightTimer(); updateStateInfo(); outputPin_->dataChanged(); } //============================================================== // Получение входных пинов //============================================================== QVector<ShPtrInputPin> TakeNode::inputPins() { return QVector<ShPtrInputPin>{inputPin_}; } //============================================================== // Получение входных пинов (2 вариант) //============================================================== QVector<ShPtrConstInputPin> TakeNode::inputPins() const { return QVector<ShPtrConstInputPin>{inputPin_}; } //============================================================== // Получение выходных пинов //============================================================== QVector<ShPtrOutputPin> TakeNode::outputPins() { return QVector<ShPtrOutputPin>{outputPin_}; } //============================================================== // Получение выходных пинов (константный вариант) //============================================================== QVector<ShPtrConstOutputPin> TakeNode::outputPins() const { return QVector<ShPtrConstOutputPin>{outputPin_}; } //============================================================== // Задание количества байтов //============================================================== void TakeNode::setByteCount(qint32 count) { if (byteCount_ != count) { const qint32 oldCount = byteCount_; byteCount_ = count; const PropValue value{"byteCount", byteCount_}; emit sigChangedProp(value); if (!isUndo_) { Q_ASSERT(undoStack_ != nullptr); const auto undoCmd = new UndoChangeObjectPropValue{this, "byteCount", byteCount_, oldCount}; undoStack_->push(undoCmd); } dataChanged(); } } //============================================================== // Сброс количества байтов //============================================================== void TakeNode::resetByteCount() { setByteCount(0); } //============================================================== // Задание направления //============================================================== void TakeNode::setDirection(DirectionTypes direction) { if (direction_ != direction) { const DirectionTypes oldDirection = direction_; direction_ = direction; const PropValue value{"direction", QVariant::fromValue(direction_)}; emit sigChangedProp(value); if (!isUndo_) { Q_ASSERT(undoStack_ != nullptr); const auto undoCmd = new UndoChangeObjectPropValue{this, "direction", QVariant::fromValue(direction_), QVariant::fromValue(oldDirection)}; undoStack_->push(undoCmd); } dataChanged(); } } //============================================================== // Сброс направления //============================================================== void TakeNode::resetDirection() { setDirection(DirectionTypes::Begin); } //============================================================== // Задание признака пропуска //============================================================== void TakeNode::setBypass(bool bypass) { if (isBypass_ != bypass) { const bool oldBypass = isBypass_; isBypass_ = bypass; const PropValue value{"bypass", isBypass_}; emit sigChangedProp(value); if (!isUndo_) { Q_ASSERT(undoStack_ != nullptr); const auto undoCmd = new UndoChangeObjectPropValue{this, "bypass", isBypass_, oldBypass}; undoStack_->push(undoCmd); } dataChanged(); } } //============================================================== // Сброс признака пропуска //============================================================== void TakeNode::resetBypass() { setBypass(false); } //============================================================== // Функция вызывается при подключении выходного пина //============================================================== void TakeNode::slotOutputPinConnectChanged(ConnectStates state, InputPin *pin) { Q_ASSERT(!isUnknown(state)); Q_ASSERT(pin != nullptr); dataChanged(); const int conNodeId = pin->parentNode()->id(); const int conPinIndex = pin->parentNode()->indexOfInputPin(pin); const bool isCon = ::isConnect(state); emit sigChangedConnect(0, conNodeId, conPinIndex, isCon); } //============================================================== // Чтение количества взятых байтов из XML //============================================================== qint32 TakeNode::readByteCountFromXml(const QDomElement &elem) const { Q_ASSERT(!elem.isNull()); const QString propName = "byteCount"; Q_UNUSED(propName) return 0; } //============================================================== // Чтение направления из XML //============================================================== DirectionTypes TakeNode::readDirectionFromXml(const QDomElement &elem) const { Q_ASSERT(!elem.isNull()); const QString propName = "direction"; Q_UNUSED(propName) return DirectionTypes::Begin; } //============================================================== // Запись количества взятых байтов в XML //============================================================== void TakeNode::writeByteCountToXml(QDomDocument &doc, QDomElement &elem) const { Q_ASSERT(!doc.isNull()); Q_ASSERT(!elem.isNull()); QDomElement elemByteCount = doc.createElement("byteCount"); const QString strByteCount = QString::number(byteCount()); writeValueToXml(doc, elemByteCount, strByteCount); elem.appendChild(elemByteCount); } //============================================================== // Запись направления из XML //============================================================== void TakeNode::writeDirectionToXml(QDomDocument &doc, QDomElement &elem) const { Q_ASSERT(!doc.isNull()); Q_ASSERT(!elem.isNull()); } //============================================================== // Создание входного пина //============================================================== void TakeNode::createInputPin() { inputPin_ = ShPtrInputPin::create(this, 0); } //============================================================== // Создание выходного пина //============================================================== void TakeNode::createOutputPin() { outputPin_ = ShPtrOutputPin::create(this, 0); connect(outputPin_.get(), &OutputPin::sigConnectChanged, this, &TakeNode::slotOutputPinConnectChanged); } //============================================================== // Получение признака подключения входного пина //============================================================== bool TakeNode::isConnectedInputPin() const { return inputPin_->isConnected(); } //============================================================== // Получение размера входных данных //============================================================== int TakeNode::inputDataSize() const { return isConnectedInputPin() ? inputPin_->dataSize() : 0; } //============================================================== // Вывод комментариев //============================================================== void TakeNode::drawComments(QPainter *painter, ColorThemes theme) const { Q_ASSERT(painter != nullptr); Q_ASSERT(!isUnknown(theme)); if (isCommentsVisible()) { QString comments{}; comments += QString{" <<< %1: \"%2\"\n"}.arg(tr("Name"), name()); comments += QString{" %1: %2\n"}.arg(tr("Count (B)")).arg(byteCount()); comments += QString{" %1: %2\n"}.arg(tr("Direction"), directionTypeToStrTr(direction())); comments += QString{" %1: %2\n"}.arg(tr("Bypass"), boolToStrTr(isBypass())); comments += QString{" %1: \"%2\"\n"}.arg(tr("Comment"), comment()); #ifdef QT_DEBUG comments += " -\n"; comments += QString{" %1: %2\n"}.arg("Id").arg(id()); #endif // QT_DEBUG const int commentsLeft = right(); const int commentsTop = top() + (headerHeight() - charHeight()) / 2; const int commentsFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip; const QRect commentsRect{commentsLeft, commentsTop, 0, 0}; painter->setPen(Colors::nodeText(theme)); painter->drawText(commentsRect, commentsFlags, comments); } } //============================================================== // Обновление состояния узла //============================================================== void TakeNode::updateStateInfo() { const NodeStateInfo oldStateInfo = stateInfo_; if (!isConnectedInputPin()) { const QString msg = tr("Input pin is not connected"); stateInfo_ = NodeStateInfo{NodeStates::Error, msg}; } else if (isErrorInParent(this)) { const QString msg = tr("Parent error"); stateInfo_ = NodeStateInfo{NodeStates::Error, msg}; } else if (byteCount_ > inputDataSize()) { const QString msg = tr("Too many count of bytes"); stateInfo_ = NodeStateInfo{NodeStates::Error, msg}; } else if (inputDataSize() == 0) { const QString msg = tr("No data"); stateInfo_ = NodeStateInfo{NodeStates::Warning, msg}; } else if (byteCount_ == 0) { const QString msg = tr("Take count is 0"); stateInfo_ = NodeStateInfo{NodeStates::Warning, msg}; } else { stateInfo_ = NodeStateInfo{NodeStates::Success, QString{}}; } if (stateInfo_ != oldStateInfo) { emit sigChangedState(stateInfo_); } } //============================================================== // Рисование узла //============================================================== void TakeNode::draw(QPainter *painter, ColorThemes theme) const { Q_ASSERT(painter != nullptr); Q_ASSERT(!isUnknown(theme)); drawHighlight(painter, theme); drawSimpleBody(painter, theme); drawPins(painter, theme); drawStateArea(painter, theme); drawComments(painter, theme); } //============================================================== // Получение копии узла //============================================================== ShPtrBaseNode TakeNode::clone() const { const auto cloneNode = ShPtrTakeNode::create(undoStack_, parent()); cloneNode->setUndo(true); cloneNode->setLeft(left()); cloneNode->setTop(top()); cloneNode->setByteCount(byteCount()); cloneNode->setDirection(direction()); cloneNode->setBypass(isBypass()); cloneNode->setComment(comment()); /* if (inputPin_->isConnected()) { ShPtrOutputPin &outPin = inputPin_->outputPin(); ShPtrInputPin inPin = cloneNode->inputPin(0); connectPins(outPin, inPin, false); } */ cloneNode->setUndo(false); return cloneNode; } //============================================================== // Получение подсказки //============================================================== QString TakeNode::tooltipText() const { QString text{}; text += QString{"%1: \"%2\"\n"}.arg(tr("Name"), name()); text += QString{"%1: %2\n"}.arg(tr("Count (B)")).arg(byteCount()); text += QString{"%1: %2\n"}.arg(tr("Direction"), directionTypeToStrTr(direction_)); text += QString{"%1: %2\n"}.arg(tr("Bypass"), boolToStrTr(isBypass())); text += QString{"%1: \"%2\""}.arg(tr("Comment"), comment()); return text; } //============================================================== // Функция получения имени свойства для графического // интерфейса по его системному имени //============================================================== QString TakeNode::getUiPropertyName(const QString &systemName) { const QMap<QString, QString> map { {"name", tr("Name")}, {"left", tr("Left")}, {"top", tr("Top")}, {"width", tr("Width")}, {"height", tr("Height")}, {"topLeft", tr("Top and left")}, {"size", tr("Size")}, {"comment", tr("Comment")}, {"byteCount", tr("Byte count")}, {"direction", tr("Direction")}, {"bypass", tr("Bypass")} }; return map.value(systemName, tr("Unknown")); } //============================================================== // Функция перевода //============================================================== void TakeNode::retranslate() { updateStateInfo(); }