2026-02-23 00:21:10 +03:00
|
|
|
#pragma once
|
|
|
|
|
#include <QGraphicsScene>
|
|
|
|
|
#include <QPointer>
|
2026-02-25 18:25:51 +03:00
|
|
|
#include <optional>
|
|
|
|
|
#include <QVariantMap>
|
2026-02-23 00:21:10 +03:00
|
|
|
|
|
|
|
|
#include "BlockItem.h"
|
|
|
|
|
class ArrowItem;
|
|
|
|
|
class JunctionItem;
|
2026-02-25 18:25:51 +03:00
|
|
|
class HeaderFooterItem;
|
2026-02-23 00:21:10 +03:00
|
|
|
|
|
|
|
|
class DiagramScene final : public QGraphicsScene {
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
public:
|
|
|
|
|
explicit DiagramScene(QObject* parent = nullptr);
|
|
|
|
|
|
|
|
|
|
BlockItem* createBlockAt(const QPointF& scenePos);
|
|
|
|
|
BlockItem* createBlockWithId(const QPointF& scenePos, int id, const QString& title);
|
|
|
|
|
void requestSnapshot();
|
2026-02-25 18:25:51 +03:00
|
|
|
void applyMeta(const QVariantMap& meta);
|
|
|
|
|
void updateMeta(const QVariantMap& patch);
|
|
|
|
|
QVariantMap meta() const { return m_meta; }
|
|
|
|
|
QRectF contentRect() const { return m_contentRect; }
|
|
|
|
|
QString currentNodeLabel() const;
|
|
|
|
|
QString currentDiagramTitle() const;
|
2026-02-25 23:25:45 +03:00
|
|
|
int currentBlockId() const { return m_currentBlockId; }
|
2026-02-23 00:23:03 +03:00
|
|
|
bool goDownIntoSelected();
|
|
|
|
|
bool goDownIntoBlock(BlockItem* b);
|
|
|
|
|
bool goUp();
|
2026-02-25 18:25:51 +03:00
|
|
|
void propagateLabelFrom(ArrowItem* root);
|
|
|
|
|
QVariantMap exportToVariant();
|
|
|
|
|
bool importFromVariant(const QVariantMap& map);
|
2026-02-25 23:25:45 +03:00
|
|
|
bool startCallMechanism(BlockItem* origin, BlockItem* refBlock, const QString& label);
|
|
|
|
|
bool hasCallMechanism(const BlockItem* origin) const;
|
|
|
|
|
void updateCallMechanismLabels();
|
2026-02-25 18:25:51 +03:00
|
|
|
signals:
|
|
|
|
|
void changed();
|
|
|
|
|
void metaChanged(const QVariantMap& meta);
|
2026-02-23 00:21:10 +03:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void mousePressEvent(QGraphicsSceneMouseEvent* e) override;
|
|
|
|
|
void mouseMoveEvent(QGraphicsSceneMouseEvent* e) override;
|
|
|
|
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent* e) override;
|
|
|
|
|
void keyPressEvent(QKeyEvent* e) override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct Snapshot {
|
|
|
|
|
struct Endpoint {
|
|
|
|
|
enum class Kind { None, Block, Junction, Scene } kind = Kind::None;
|
|
|
|
|
int id = -1;
|
|
|
|
|
BlockItem::Port port = BlockItem::Port::Input;
|
2026-02-25 18:25:51 +03:00
|
|
|
std::optional<QPointF> localPos;
|
|
|
|
|
std::optional<QPointF> scenePos;
|
2026-02-23 00:21:10 +03:00
|
|
|
};
|
2026-02-25 23:25:45 +03:00
|
|
|
struct Block { int id; QString title; QPointF pos; bool hasDecomp = false; QString number; std::optional<qreal> price; std::optional<QString> color; };
|
2026-02-23 00:21:10 +03:00
|
|
|
struct Junction { int id; QPointF pos; };
|
|
|
|
|
struct Arrow {
|
|
|
|
|
Endpoint from;
|
|
|
|
|
Endpoint to;
|
|
|
|
|
qreal bend = 0.0;
|
|
|
|
|
qreal top = 0.0;
|
|
|
|
|
qreal bottom = 0.0;
|
|
|
|
|
QString label;
|
|
|
|
|
QPointF labelOffset;
|
2026-02-25 18:25:51 +03:00
|
|
|
bool labelHidden = false;
|
|
|
|
|
bool labelInherited = false;
|
|
|
|
|
bool isInterface = false;
|
|
|
|
|
bool isInterfaceStub = false;
|
|
|
|
|
bool labelLocked = false;
|
|
|
|
|
Endpoint interfaceEdge;
|
2026-02-25 23:25:45 +03:00
|
|
|
std::optional<QString> color;
|
|
|
|
|
bool callMechanism = false;
|
|
|
|
|
int callRefId = -1;
|
2026-02-23 00:21:10 +03:00
|
|
|
};
|
|
|
|
|
QVector<Block> blocks;
|
|
|
|
|
QVector<Junction> junctions;
|
|
|
|
|
QVector<Arrow> arrows;
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-25 18:25:51 +03:00
|
|
|
struct HierNode { int blockId; Snapshot snapshot; QString prefix; };
|
2026-02-23 00:23:03 +03:00
|
|
|
|
|
|
|
|
ArrowItem* m_dragArrow = nullptr;
|
|
|
|
|
QPointer<BlockItem> m_dragFromBlock;
|
|
|
|
|
QPointer<JunctionItem> m_dragFromJunction;
|
|
|
|
|
BlockItem::Port m_dragFromPort = BlockItem::Port::Output;
|
|
|
|
|
int m_nextBlockId = 1;
|
|
|
|
|
int m_nextJunctionId = 1;
|
2026-02-25 18:25:51 +03:00
|
|
|
QString m_currentPrefix = QStringLiteral("A");
|
2026-02-23 00:23:03 +03:00
|
|
|
bool m_snapshotScheduled = false;
|
|
|
|
|
bool m_restoringSnapshot = false;
|
|
|
|
|
bool m_itemDragActive = false;
|
|
|
|
|
QHash<QGraphicsItem*, QPointF> m_pressPositions;
|
|
|
|
|
int m_currentBlockId = -1;
|
|
|
|
|
QVector<HierNode> m_hierarchy;
|
2026-02-25 18:25:51 +03:00
|
|
|
QHash<QString, Snapshot> m_children; // hierarchical key ("1/2/3") -> saved child diagram
|
|
|
|
|
ArrowItem* m_dragInterfaceStub = nullptr;
|
|
|
|
|
QVariantMap m_meta;
|
|
|
|
|
HeaderFooterItem* m_headerFooter = nullptr;
|
|
|
|
|
QRectF m_contentRect;
|
2026-02-23 00:23:03 +03:00
|
|
|
|
2026-02-25 18:25:51 +03:00
|
|
|
bool tryStartArrowDrag(const QPointF& scenePos, Qt::KeyboardModifiers mods);
|
2026-02-23 00:23:03 +03:00
|
|
|
bool tryFinishArrowDrag(const QPointF& scenePos);
|
|
|
|
|
bool tryBranchAtArrow(const QPointF& scenePos);
|
|
|
|
|
void cancelCurrentDrag();
|
|
|
|
|
void deleteSelection();
|
|
|
|
|
|
2026-02-23 00:21:10 +03:00
|
|
|
QVector<Snapshot> m_history;
|
|
|
|
|
int m_historyIndex = -1;
|
|
|
|
|
|
|
|
|
|
Snapshot captureSnapshot() const;
|
2026-02-25 18:25:51 +03:00
|
|
|
void restoreSnapshot(const Snapshot& snap, bool resetHistoryState = true);
|
2026-02-23 00:21:10 +03:00
|
|
|
void pushSnapshot();
|
|
|
|
|
void scheduleSnapshot();
|
|
|
|
|
void undo();
|
|
|
|
|
void maybeSnapshotMovedItems();
|
2026-02-23 00:23:03 +03:00
|
|
|
void resetHistory(const Snapshot& base);
|
|
|
|
|
void ensureFrame();
|
2026-02-25 18:25:51 +03:00
|
|
|
void ensureHeaderFooter();
|
|
|
|
|
bool childHasContent(int blockId) const;
|
|
|
|
|
QString currentPathKey() const;
|
|
|
|
|
QString childKeyFor(int blockId) const;
|
|
|
|
|
QString assignNumber(BlockItem* b);
|
2026-02-25 23:25:45 +03:00
|
|
|
void connectBlockSignals(BlockItem* b);
|
|
|
|
|
void purgeBrokenCallMechanisms();
|
2026-02-23 00:21:10 +03:00
|
|
|
|
|
|
|
|
enum class Edge { None, Left, Right, Top, Bottom };
|
|
|
|
|
Edge hitTestEdge(const QPointF& scenePos, QPointF* outScenePoint = nullptr) const;
|
2026-02-25 18:25:51 +03:00
|
|
|
|
|
|
|
|
friend QJsonObject endpointToJson(const Snapshot::Endpoint& ep);
|
|
|
|
|
friend Snapshot::Endpoint endpointFromJson(const QJsonObject& o);
|
2026-02-23 00:21:10 +03:00
|
|
|
};
|