diff --git a/agui2/CMakeLists.txt b/agui2/CMakeLists.txt index b17c68bdb5a0c735508e9042021cdc3d9141e201..f2376bf419801a035fea3b633f6dfeedc7117daf 100644 --- a/agui2/CMakeLists.txt +++ b/agui2/CMakeLists.txt @@ -38,6 +38,10 @@ add_executable(${PROJECT_NAME} Graphics/Dialogs/OutputDialog.h Graphics/Dialogs/ResultDialog.cpp Graphics/Dialogs/ResultDialog.h + Graphics/Connection.cpp + Graphics/Connection.h + Graphics/ConnectionBox.cpp + Graphics/ConnectionBox.h Graphics/DoubleGraphicsBox.cpp Graphics/DoubleGraphicsBox.h Graphics/GraphicsBox.cpp @@ -76,7 +80,8 @@ add_executable(${PROJECT_NAME} WrapperBox.cpp WrapperBox.h WrapperFactory.cpp - WrapperFactory.h) + WrapperFactory.h + ) target_link_libraries( ${PROJECT_NAME} diff --git a/agui2/Graphics/Connection.cpp b/agui2/Graphics/Connection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81b049c06643249bb5060bd0b9780ad637d3729b --- /dev/null +++ b/agui2/Graphics/Connection.cpp @@ -0,0 +1,47 @@ +#include <Graphics/Connection.h> + +#include <QGraphicsScene> +#include <QPainter> + +#include <Graphics/ConnectionBox.h> +#include <Utils.h> + +Connection::Connection(ConnectionBox* origin, ConnectionBox* target) + : originConnectionBox(origin) + , targetConnectionBox(target) +{ + this->setZValue(2); + this->boundRect = Utils::pointsToRect(origin->pos(), target->pos()); + this->boundRect.adjust(-1, -1, 1, 1); + origin->scene()->addItem(this); + origin->scene()->update(); +} + +QRectF Connection::boundingRect() const { + return this->boundRect; +} + +void Connection::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { + painter->setPen(QPen(Qt::black,1)); + + QPointF originPoint = this->originConnectionBox->scenePos(); + QPointF targetPoint = this->targetConnectionBox->scenePos(); + + QRectF rect = Utils::pointsToRect(originPoint, targetPoint); + + qreal midWidth = rect.left() + rect.width() / 2.0; + + painter->drawLine(originPoint, + { midWidth, originPoint.y() }); + painter->drawLine(QPointF { midWidth, originPoint.y() }, + { midWidth, targetPoint.y() }); + painter->drawLine(QPointF { midWidth, targetPoint.y() }, + { targetPoint.x(), targetPoint.y() }); + this->recalculateBoundingRect(originPoint, targetPoint); +} + +void Connection::recalculateBoundingRect(const QPointF& a, const QPointF& b) { + this->prepareGeometryChange(); + this->boundRect = Utils::pointsToRect(a, b); + this->boundRect.adjust(-1, -1, 1, 1); +} diff --git a/agui2/Graphics/Connection.h b/agui2/Graphics/Connection.h new file mode 100644 index 0000000000000000000000000000000000000000..8628f4239482cc7c54a65ab89b82563ef0e34c62 --- /dev/null +++ b/agui2/Graphics/Connection.h @@ -0,0 +1,24 @@ +#pragma once + +#include <QtWidgets/QGraphicsItem> + +class ConnectionBox; + +class Connection : public QGraphicsItem { +public: + Connection(ConnectionBox* origin, ConnectionBox* target); + + QRectF boundingRect() const override; + + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; + +private: + void recalculateBoundingRect(const QPointF& topLeft, const QPointF& bottomRight); + + QRectF boundRect; + + ConnectionBox* originConnectionBox; + ConnectionBox* targetConnectionBox; +}; + + diff --git a/agui2/Graphics/ConnectionBox.cpp b/agui2/Graphics/ConnectionBox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a880a5649577612f38a3dea22b53099d3541a0e --- /dev/null +++ b/agui2/Graphics/ConnectionBox.cpp @@ -0,0 +1,84 @@ +#include <Graphics/ConnectionBox.h> + +#include <utility> + +#include <QtGui/QDrag> +#include <QtWidgets/QApplication> + +#include <Graphics/GraphicsBox.h> +#include <Graphics/GraphicsScene.h> + +const QColor ConnectionBox::defaultColor = Qt::white; + +ConnectionBox::ConnectionBox(GraphicsBox* parent, bool isInput) + : QGraphicsRectItem(-8, -8, 16, 16, parent) + , isInput(isInput) + +{ + this->setBrush(ConnectionBox::defaultColor); + this->setAcceptedMouseButtons(Qt::LeftButton); +} + +GraphicsBox* ConnectionBox::getParent() const { + return dynamic_cast<GraphicsBox*>(this->parentObject()); +} + +void ConnectionBox::mousePressEvent(QGraphicsSceneMouseEvent* event) { + this->setCursor(Qt::UpArrowCursor); + + Q_ASSERT(!this->tempLine); + this->tempLine = this->scene()->addLine({this->scenePos(), this->scenePos()}); + this->tempLine->setZValue(2); +} + +void ConnectionBox::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { + Q_ASSERT(this->tempLine); + QLineF line = this->tempLine->line(); + line.setP2(event->scenePos()); + this->tempLine->setLine(line); + + static ConnectionBox* other = nullptr; + if (other) + { + other->setBrush(ConnectionBox::defaultColor); + } + + other = nullptr; + for (auto* item: this->scene()->items(event->scenePos())) + { + if (auto* cb = dynamic_cast<ConnectionBox*>(item)) + { + other = cb; + break; + } + } + + if (other && other->isInput == !this->isInput) + { + other->setBrush(Qt::yellow); + } +} + +void ConnectionBox::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { + this->setCursor(Qt::ArrowCursor); + + Q_ASSERT(this->tempLine); + delete this->tempLine; + this->tempLine = nullptr; + + auto* other = dynamic_cast<ConnectionBox*>(this->scene()->itemAt(event->scenePos(), {})); + if (other && other->isInput == !this->isInput) + { + ConnectionBox::connect(this, other); + } +} + +void ConnectionBox::connect(ConnectionBox* a, ConnectionBox* b) { + Q_ASSERT(a->isInput != b->isInput); + auto* origin = a; + auto* target = b; + if (!origin->isInput) + std::swap(origin, target); + + origin->connection = target->connection = std::make_shared<Connection>(origin, target); +} diff --git a/agui2/Graphics/ConnectionBox.h b/agui2/Graphics/ConnectionBox.h new file mode 100644 index 0000000000000000000000000000000000000000..7c5e3298c38d3842a20bb8a2c8dbd6373f25e987 --- /dev/null +++ b/agui2/Graphics/ConnectionBox.h @@ -0,0 +1,31 @@ +#pragma once +#include <memory> + +#include <QtWidgets/QGraphicsRectItem> + +#include <Graphics/Connection.h> + +class GraphicsBox; + +class ConnectionBox : public QGraphicsRectItem { +public: + ConnectionBox(GraphicsBox* parent, bool isInput); + + static const QColor defaultColor; + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override; + + static void connect(ConnectionBox* a, ConnectionBox* b); + +private: + GraphicsBox* getParent() const; + + std::shared_ptr<Connection> connection; + QGraphicsLineItem* tempLine = nullptr; + bool isInput; +}; + + diff --git a/agui2/Graphics/GraphicsBox.cpp b/agui2/Graphics/GraphicsBox.cpp index ea7db09bb83874eb96adbbaf887e1c17b0068fdf..da59c5c9b4a5cb264d632116424beac4b40e7ecd 100644 --- a/agui2/Graphics/GraphicsBox.cpp +++ b/agui2/Graphics/GraphicsBox.cpp @@ -7,6 +7,7 @@ #include <QGraphicsSceneContextMenuEvent> #include <ConnectionHelper.h> +#include <Graphics/ConnectionBox.h> #include <Graphics/Dialogs/InputDialog.h> #include <Graphics/GraphicsConnection.h> #include <Graphics/GraphicsScene.h> @@ -23,6 +24,22 @@ GraphicsBox::GraphicsBox(QString text, qreal x, qreal y, uint8_t inputs, uint8_t setZValue(1); setBoundingRectangle(); + + this->inputConnections.reserve(inputs); + for (uint8_t i = 0; i < inputs; ++i) + { + auto* box = new ConnectionBox(this, true); + box->setPos(this->m_boundRect.left(), this->m_boundRect.top() + ((i + 1) * this->m_boundRect.height()) / float(inputs + 1)); + this->inputConnections.push_back(box); + } + + this->outputConnections.reserve(outputs); + for (uint8_t i = 0; i < outputs; ++i) + { + auto* box = new ConnectionBox(this, false); + box->setPos(this->m_boundRect.right(), this->m_boundRect.top() + ((i + 1) * this->m_boundRect.height()) / float(outputs + 1)); + this->outputConnections.push_back(box); + } } GraphicsBox::~GraphicsBox() diff --git a/agui2/Graphics/GraphicsBox.h b/agui2/Graphics/GraphicsBox.h index 4a31ad16f605a4753f63de886780cecfa2fb86c6..10870b613dabcae75c1a43f6ffae75319faf4554 100644 --- a/agui2/Graphics/GraphicsBox.h +++ b/agui2/Graphics/GraphicsBox.h @@ -11,6 +11,7 @@ #define BOX_MARGIN 20 +class ConnectionBox; class GraphicsConnection; class WrapperBox; @@ -38,6 +39,8 @@ protected: GraphicsConnection* m_OutConnection = nullptr; GraphicsConnection* m_InConnection = nullptr; WrapperBox* m_wrapper; + std::vector<ConnectionBox*> inputConnections; + std::vector<ConnectionBox*> outputConnections; void finishMenu( QMenu * menu ); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override ; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;