Skip to content

Commit aa8c3a6

Browse files
committed
refactor drag n drop logic.
1 parent 986e210 commit aa8c3a6

File tree

5 files changed

+69
-79
lines changed

5 files changed

+69
-79
lines changed

NodeGraphQt/base/graph.py

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from .model import NodeGraphModel
1818
from .node import NodeObject, BaseNode, BackdropNode
1919
from .port import Port
20-
from ..constants import (DRAG_DROP_ID,
20+
from ..constants import (URI_SCHEME, URN_SCHEME,
2121
PIPE_LAYOUT_CURVED,
2222
PIPE_LAYOUT_STRAIGHT,
2323
PIPE_LAYOUT_ANGLE,
@@ -27,41 +27,6 @@
2727
from ..widgets.viewer import NodeViewer
2828

2929

30-
class QWidgetDrops(QtWidgets.QWidget):
31-
32-
def __init__(self):
33-
super(QWidgetDrops, self).__init__()
34-
self.setAcceptDrops(True)
35-
self.setWindowTitle("NodeGraphQt")
36-
self.setStyleSheet('''
37-
QWidget {
38-
background-color: rgb(55,55,55);
39-
color: rgb(200,200,200);
40-
border-width: 0px;
41-
}''')
42-
43-
def dragEnterEvent(self, event):
44-
if event.mimeData().hasUrls:
45-
event.accept()
46-
else:
47-
event.ignore()
48-
49-
def dragMoveEvent(self, event):
50-
if event.mimeData().hasUrls:
51-
event.accept()
52-
else:
53-
event.ignore()
54-
55-
def dropEvent(self, event):
56-
if event.mimeData().hasUrls:
57-
event.setDropAction(QtCore.Qt.CopyAction)
58-
event.accept()
59-
for url in event.mimeData().urls():
60-
self.import_session(url.toLocalFile())
61-
else:
62-
event.ignore()
63-
64-
6530
class NodeGraph(QtCore.QObject):
6631
"""
6732
The ``NodeGraph`` class is the main controller for managing all nodes
@@ -315,23 +280,41 @@ def _on_node_data_dropped(self, data, pos):
315280
"""
316281
called when data has been dropped on the viewer.
317282
283+
Example Identifiers:
284+
URI = ngqt://path/to/node/session.graph
285+
URN = ngqt::node:com.chantasticvfx.MyNode
286+
318287
Args:
319288
data (QtCore.QMimeData): mime data.
320289
pos (QtCore.QPoint): scene position relative to the drop.
321290
"""
322-
323-
# don't emit signal for internal widget drops.
324-
if data.hasFormat('text/plain'):
325-
if data.text().startswith('<${}>:'.format(DRAG_DROP_ID)):
326-
node_ids = data.text()[len('<${}>:'.format(DRAG_DROP_ID)):]
327-
x, y = pos.x(), pos.y()
328-
for node_id in node_ids.split(','):
329-
self.create_node(node_id, pos=[x, y])
330-
x += 20
331-
y += 20
332-
return
333-
334-
self.data_dropped.emit(data, pos)
291+
uri_regex = re.compile('{}(?:/*)([\w/]+)(\\.\w+)'.format(URI_SCHEME))
292+
urn_regex = re.compile('{}([\w\\.:;]+)'.format(URN_SCHEME))
293+
if data.hasFormat('text/uri-list'):
294+
for url in data.urls():
295+
local_file = url.toLocalFile()
296+
if local_file:
297+
try:
298+
self.import_session(local_file)
299+
continue
300+
except Exception as e:
301+
pass
302+
303+
url_str = url.toString()
304+
uri_search = uri_regex.search(url_str)
305+
urn_search = urn_regex.search(url_str)
306+
if uri_search:
307+
path = uri_search.group(1)
308+
ext = uri_search.group(2)
309+
self.import_session('{}{}'.format(path, ext))
310+
elif urn_search:
311+
search_str = urn_search.group(1)
312+
node_ids = sorted(re.findall('node:([\w\\.]+)', search_str))
313+
for node_id in node_ids:
314+
x, y = pos.x(), pos.y()
315+
self.create_node(node_id, pos=[x, y])
316+
x += 20
317+
y += 20
335318

336319
def _on_nodes_moved(self, node_data):
337320
"""
@@ -450,9 +433,7 @@ def widget(self):
450433
PySide2.QtWidgets.QWidget: node graph widget.
451434
"""
452435
if self._widget is None:
453-
self._widget = QWidgetDrops()
454-
self._widget.import_session = self.import_session
455-
436+
self._widget = QtWidgets.QWidget()
456437
layout = QtWidgets.QVBoxLayout(self._widget)
457438
layout.setContentsMargins(0, 0, 0, 0)
458439
layout.setSpacing(0)
@@ -1435,7 +1416,7 @@ def import_session(self, file_path):
14351416

14361417
file_path = file_path.strip()
14371418
if not os.path.isfile(file_path):
1438-
raise IOError('file does not exist.')
1419+
raise IOError('file does not exist: {}'.format(file_path))
14391420

14401421
try:
14411422
with open(file_path) as data_file:

NodeGraphQt/base/node.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -976,28 +976,32 @@ def delete_output(self, port):
976976

977977
def set_ports(self, port_data):
978978
"""
979-
Set node input and output ports.
979+
Set node input and output ports from specified port data.
980+
981+
example port data:
982+
{
983+
'input_ports':
984+
[{
985+
'name': 'input',
986+
'multi_connection': True,
987+
'display_name': 'Input',
988+
'data_type': 'NoneType',
989+
'locked': False
990+
}],
991+
'output_ports':
992+
[{
993+
'name': 'output',
994+
'multi_connection': True,
995+
'display_name': 'Output',
996+
'data_type': 'NoneType',
997+
'locked': False
998+
}]
999+
}
9801000
9811001
Args:
9821002
port_data(dict): port data.
9831003
"""
9841004

985-
# port data eg.
986-
# {
987-
# 'input_ports':
988-
# [{'name': ...,
989-
# 'multi_connection': ...,
990-
# 'display_name': ...,
991-
# 'data_type': ...
992-
# }, ...],
993-
# 'output_ports':
994-
# [{'name': ...,
995-
# 'multi_connection': ...,
996-
# 'display_name': ...,
997-
# 'data_type': ...
998-
# }, ...]
999-
# }
1000-
10011005
for port in self._inputs:
10021006
self._view.delete_input(port.view)
10031007
port.model.node = None

NodeGraphQt/constants.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@
9999
VIEWER_GRID_COLOR = (45, 45, 45)
100100
VIEWER_GRID_SIZE = 50
101101

102-
DRAG_DROP_ID = 'n0deGraphQT'
102+
URI_SCHEME = 'ngqt://'
103+
URN_SCHEME = 'ngqt::'
103104

104105
# === PATHS ===
105106

NodeGraphQt/widgets/node_tree.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# -*- coding: utf-8 -*-
33
from Qt import QtWidgets, QtCore
44

5-
from ..constants import DRAG_DROP_ID
5+
from ..constants import URN_SCHEME
66

77
TYPE_NODE = QtWidgets.QTreeWidgetItem.UserType + 1
88
TYPE_CATEGORY = QtWidgets.QTreeWidgetItem.UserType + 2
@@ -40,9 +40,10 @@ def __repr__(self):
4040
return '<{} object at {}>'.format(self.__class__.__name__, hex(id(self)))
4141

4242
def mimeData(self, items):
43-
node_ids = ','.join(i.toolTip(0) for i in items)
43+
node_ids = ['node:{}'.format(i.toolTip(0)) for i in items]
44+
node_urn = URN_SCHEME + ';'.join(node_ids)
4445
mime_data = super(NodeTreeWidget, self).mimeData(items)
45-
mime_data.setText('<${}>:{}'.format(DRAG_DROP_ID, node_ids))
46+
mime_data.setUrls([node_urn])
4647
return mime_data
4748

4849
def _build_tree(self):

NodeGraphQt/widgets/viewer.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,11 @@ def mouseMoveEvent(self, event):
425425
if isinstance(item, Pipe) and item.isVisible():
426426
if not item.input_port:
427427
continue
428-
if not item.input_port.node is node and \
429-
not item.output_port.node is node:
428+
port_node_check = all([
429+
not item.input_port.node is node,
430+
not item.output_port.node is node
431+
])
432+
if port_node_check:
430433
item.setSelected(True)
431434
self.COLLIDING_state = True
432435
break
@@ -446,18 +449,18 @@ def wheelEvent(self, event):
446449

447450
def dropEvent(self, event):
448451
pos = self.mapToScene(event.pos())
449-
event.setDropAction(QtCore.Qt.MoveAction)
452+
event.setDropAction(QtCore.Qt.CopyAction)
450453
self.data_dropped.emit(
451454
event.mimeData(), QtCore.QPoint(pos.x(), pos.y()))
452455

453456
def dragEnterEvent(self, event):
454-
if event.mimeData().hasFormat('text/plain'):
457+
if event.mimeData().hasFormat('text/uri-list'):
455458
event.accept()
456459
else:
457460
event.ignore()
458461

459462
def dragMoveEvent(self, event):
460-
if event.mimeData().hasFormat('text/plain'):
463+
if event.mimeData().hasFormat('text/uri-list'):
461464
event.accept()
462465
else:
463466
event.ignore()

0 commit comments

Comments
 (0)