wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
SceneDropHandler.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <memory>
7
8#include <QGraphicsSceneDragDropEvent>
9#include <QMimeData>
10#include <QtGlobal>
11
12#include "App/Core/Common.h"
14#include "App/Core/Enums.h"
15#include "App/Core/MimeTypes.h"
18#include "App/Element/IC.h"
21#include "App/Scene/Commands.h"
23#include "App/Scene/Scene.h"
24
26 : m_scene(scene)
27{
28}
29
30bool SceneDropHandler::isSupportedDropFormat(const QMimeData *mimeData)
31{
32 const auto &formats = mimeData->formats();
33 return formats.contains(MimeType::DragDropLegacy)
34 || formats.contains(MimeType::CloneDragLegacy)
35 || formats.contains(MimeType::DragDrop)
36 || formats.contains(MimeType::CloneDrag);
37}
38
39void SceneDropHandler::handleNewElementDrop(QGraphicsSceneDragDropEvent *event)
40{
41 // Both MIME types carry the same payload; the newer format has a namespaced key
42 QByteArray itemData;
43
44 if (event->mimeData()->hasFormat(MimeType::DragDropLegacy)) {
45 itemData = event->mimeData()->data(MimeType::DragDropLegacy);
46 }
47
48 if (event->mimeData()->hasFormat(MimeType::DragDrop)) {
49 itemData = event->mimeData()->data(MimeType::DragDrop);
50 }
51
52 QDataStream stream(&itemData, QIODevice::ReadOnly);
54
55 const auto payload = readDragDropPayload(stream);
56
57 // Subtract the drag offset so the element lands under the original grab point
58 QPointF pos = event->scenePos() - payload.offset;
59 qCDebug(zero) << payload.type << " at position: " << pos.x() << ", " << pos.y() << ", label: " << payload.icFileName;
60
61 std::unique_ptr<GraphicElement> element(ElementFactory::buildElement(payload.type));
62 qCDebug(zero) << "Valid element.";
63
64 if (payload.isEmbedded && payload.type == ElementType::IC) {
65 if (!m_scene->icRegistry()->initEmbeddedIC(static_cast<IC *>(element.get()), payload.blobName)) {
66 return;
67 }
68 } else {
69 // loadFromDrop can throw on malformed files; unique_ptr keeps the
70 // freshly-allocated element from leaking when it does.
71 element->loadFromDrop(payload.icFileName, m_scene->contextDir());
72 }
73
74 qCDebug(zero) << "Adding the element to the scene.";
75 auto *raw = element.release();
76 m_scene->receiveCommand(new AddItemsCommand({raw}, m_scene));
77
78 qCDebug(zero) << "Cleaning the selection.";
79 m_scene->clearSelection();
80
81 qCDebug(zero) << "Setting created element as selected.";
82 raw->setSelected(true);
83
84 qCDebug(zero) << "Adjusting the position of the element.";
85 raw->setPos(pos);
86}
87
88void SceneDropHandler::handleCloneDrag(QGraphicsSceneDragDropEvent *event)
89{
90 QByteArray itemData;
91
92 if (event->mimeData()->hasFormat(MimeType::CloneDragLegacy)) {
93 itemData = event->mimeData()->data(MimeType::CloneDragLegacy);
94 }
95
96 if (event->mimeData()->hasFormat(MimeType::CloneDrag)) {
97 itemData = event->mimeData()->data(MimeType::CloneDrag);
98 }
99
100 QDataStream stream(&itemData, QIODevice::ReadOnly);
101 QVersionNumber version = Serialization::readPandaHeader(stream);
102
103 // offset = mouse position at drag-start; recompute drop offset from current position
104 QPointF offset; stream >> offset;
105 QPointF ctr; stream >> ctr;
106 offset = event->scenePos() - offset;
107
108 QHash<quint64, Port *> portMap;
109 auto context = m_scene->deserializationContext(portMap, version, SerializationPurpose::InMemorySnapshot);
110 const auto itemList = Serialization::deserialize(stream, context);
111
112 m_scene->receiveCommand(new AddItemsCommand(itemList, m_scene));
113 m_scene->clearSelection();
114
115 for (auto *item : itemList) {
116 if (item->type() == GraphicElement::Type) {
117 item->setPos((item->pos() + offset));
118 item->setSelected(true);
119 }
120 }
121
122 m_scene->resizeScene();
123}
124
125void SceneDropHandler::addFromMimeData(QMimeData *mimeData, std::optional<QPointF> scenePos)
126{
127 QByteArray itemData = mimeData->hasFormat(MimeType::DragDrop)
128 ? mimeData->data(MimeType::DragDrop)
129 : mimeData->data(MimeType::DragDropLegacy);
130 QDataStream stream(&itemData, QIODevice::ReadOnly);
132
133 const auto payload = readDragDropPayload(stream);
134
135 std::unique_ptr<GraphicElement> element(ElementFactory::buildElement(payload.type));
136 qCDebug(zero) << "Valid element.";
137
138 // RAII for mimeData too — the original deleteLater at the bottom is
139 // unreachable if loadFromDrop throws, so the QMimeData would leak alongside
140 // the half-built element.
141 auto mimeGuard = qScopeGuard([mimeData]() { mimeData->deleteLater(); });
142
143 if (payload.isEmbedded && payload.type == ElementType::IC) {
144 if (!m_scene->icRegistry()->initEmbeddedIC(static_cast<IC *>(element.get()), payload.blobName)) {
145 return;
146 }
147 } else {
148 element->loadFromDrop(payload.icFileName, m_scene->contextDir());
149 }
150
151 qCDebug(zero) << "Adding the element to the scene.";
152 auto *raw = element.release();
153 m_scene->receiveCommand(new AddItemsCommand({raw}, m_scene));
154
155 qCDebug(zero) << "Cleaning the selection.";
156 m_scene->clearSelection();
157
158 qCDebug(zero) << "Setting created element as selected.";
159 raw->setSelected(true);
160
161 // Add-without-drag (double-click / search): drop it where the caller asked (the view
162 // centre) so it lands in sight instead of at the scene origin. The grid snap in
163 // GraphicElement::itemChange rounds the final position.
164 if (scenePos) {
165 raw->setPos(*scenePos);
166 }
167}
All QUndoCommand subclasses and the CommandUtils helper namespace.
Common logging utilities, the Pandaception error type, and helper macros.
#define qCDebug(category)
Definition Common.h:29
DragDropPayload readDragDropPayload(QDataStream &stream)
Reads a drag-and-drop payload from stream.
Shared reader for wiRedPanda's drag-and-drop MIME payload format.
Singleton factory for all circuit element types.
Central enumeration types for element types, groups, and signal status.
Abstract base class for all graphical circuit elements.
IC definition registry with file watching and embedded blob storage.
Integrated Circuit (IC) graphic element that encapsulates a sub-circuit file.
MIME type string constants for drag-and-drop operations.
SceneDropHandler: decodes drag-and-drop payloads into scene elements.
Main circuit editing scene with undo/redo and user interaction.
Deserialization/serialization context structs passed through load()/save() call chains.
Circuit and waveform file serialization/deserialization utilities.
Undo command that adds a list of graphic elements to the scene.
Definition Commands.h:67
static GraphicElement * buildElement(const ElementType type)
Constructs and returns a new graphic element of the given type.
Graphic element representing an Integrated Circuit (sub-circuit) box.
Definition IC.h:31
const QString & blobName() const override
Returns the blob name for embedded ICs, empty if file-backed.
Definition IC.h:79
SceneDropHandler(Scene *scene)
static bool isSupportedDropFormat(const QMimeData *mimeData)
Returns true if mimeData carries any recognised wiRedPanda drop format.
void handleCloneDrag(QGraphicsSceneDragDropEvent *event)
Re-instantiates a clone-dragged selection at the drop position.
void handleNewElementDrop(QGraphicsSceneDragDropEvent *event)
Builds a new element from a palette drag payload and adds it under the cursor.
void addFromMimeData(QMimeData *mimeData, std::optional< QPointF > scenePos=std::nullopt)
Main circuit editing scene.
Definition Scene.h:56
static QList< QGraphicsItem * > deserialize(QDataStream &stream, SerializationContext &context)
Deserializes items from stream until the stream is exhausted.
static QVersionNumber readPandaHeader(QDataStream &stream)
Reads and validates the .panda circuit file header; returns the stored version number.
constexpr const char * CloneDragLegacy
Legacy clone-drag MIME type retained for backward compatibility.
Definition MimeTypes.h:20
constexpr const char * CloneDrag
Current MIME type for clone-drag (Ctrl+drag within the scene).
Definition MimeTypes.h:18
constexpr const char * DragDropLegacy
Legacy drag-and-drop MIME type retained for backward compatibility.
Definition MimeTypes.h:15
constexpr const char * DragDrop
Current drag-and-drop MIME type for element palette → scene drops.
Definition MimeTypes.h:13