diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index 4e5707d7..16328e69 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -17,6 +17,7 @@ from NodeGraphQt.base.node import NodeObject from NodeGraphQt.base.port import Port from NodeGraphQt.constants import ( + MIME_TYPE, URI_SCHEME, URN_SCHEME, LayoutDirectionEnum, @@ -341,7 +342,7 @@ def _on_node_selection_changed(self, sel_ids, desel_ids): unsel_nodes = [self.get_node_by_id(nid) for nid in desel_ids] self.node_selection_changed.emit(sel_nodes, unsel_nodes) - def _on_node_data_dropped(self, data, pos): + def _on_node_data_dropped(self, mimedata, pos): """ called when data has been dropped on the viewer. @@ -350,36 +351,52 @@ def _on_node_data_dropped(self, data, pos): URN = ngqt::node:com.nodes.MyNode1;node:com.nodes.MyNode2 Args: - data (QtCore.QMimeData): mime data. + mimedata (QtCore.QMimeData): mime data. pos (QtCore.QPoint): scene position relative to the drop. """ uri_regex = re.compile(r'{}(?:/*)([\w/]+)(\.\w+)'.format(URI_SCHEME)) urn_regex = re.compile(r'{}([\w\.:;]+)'.format(URN_SCHEME)) - if data.hasFormat('text/uri-list'): - for url in data.urls(): + if mimedata.hasFormat(MIME_TYPE): + data = mimedata.data(MIME_TYPE).data().decode() + urn_search = urn_regex.search(data) + if urn_search: + search_str = urn_search.group(1) + node_ids = sorted(re.findall(r'node:([\w\.]+)', search_str)) + x, y = pos.x(), pos.y() + for node_id in node_ids: + self.create_node(node_id, pos=[x, y]) + x += 80 + y += 80 + elif mimedata.hasFormat('text/uri-list'): + not_supported_urls = [] + for url in mimedata.urls(): local_file = url.toLocalFile() if local_file: try: self.import_session(local_file) continue except Exception as e: - pass + not_supported_urls.append(url) url_str = url.toString() - uri_search = uri_regex.search(url_str) - urn_search = urn_regex.search(url_str) - if uri_search: - path = uri_search.group(1) - ext = uri_search.group(2) - self.import_session('{}{}'.format(path, ext)) - elif urn_search: - search_str = urn_search.group(1) - node_ids = sorted(re.findall('node:([\w\\.]+)', search_str)) - x, y = pos.x(), pos.y() - for node_id in node_ids: - self.create_node(node_id, pos=[x, y]) - x += 80 - y += 80 + if url_str: + uri_search = uri_regex.search(url_str) + if uri_search: + path = uri_search.group(1) + ext = uri_search.group(2) + try: + self.import_session('{}{}'.format(path, ext)) + except Exception as e: + not_supported_urls.append(url) + + if not_supported_urls: + print( + 'Can\'t import the following urls: \n{}' + .format('\n'.join(not_supported_urls)) + ) + self.data_dropped.emit(mimedata, pos) + else: + self.data_dropped.emit(mimedata, pos) def _on_nodes_moved(self, node_data): """ @@ -640,7 +657,7 @@ def set_grid_mode(self, mode=None): :linenos: graph = NodeGraph() - graph.set_grid_mode(ViewerEnum.CURVED.value) + graph.set_grid_mode(ViewerEnum.GRID_DISPLAY_DOTS.value) Args: mode (int): background style. diff --git a/NodeGraphQt/constants.py b/NodeGraphQt/constants.py index 986e5cd3..6679d848 100644 --- a/NodeGraphQt/constants.py +++ b/NodeGraphQt/constants.py @@ -14,6 +14,7 @@ # ================================== PRIVATE =================================== +MIME_TYPE = 'nodegraphqt/nodes' URI_SCHEME = 'nodegraphqt://' URN_SCHEME = 'nodegraphqt::' @@ -24,6 +25,7 @@ ICON_NODE_BASE = os.path.join(ICON_PATH, 'node_base.png') # DRAW STACK ORDER +Z_VAL_BACKDROP = -2 Z_VAL_PIPE = -1 Z_VAL_NODE = 1 Z_VAL_PORT = 2 diff --git a/NodeGraphQt/custom_widgets/nodes_palette.py b/NodeGraphQt/custom_widgets/nodes_palette.py index 2ac831d0..26ec3ebc 100644 --- a/NodeGraphQt/custom_widgets/nodes_palette.py +++ b/NodeGraphQt/custom_widgets/nodes_palette.py @@ -4,7 +4,7 @@ from Qt import QtWidgets, QtCore, QtGui -from NodeGraphQt.constants import URN_SCHEME +from NodeGraphQt.constants import MIME_TYPE, URN_SCHEME class _NodesGridDelegate(QtWidgets.QStyledItemDelegate): @@ -122,11 +122,13 @@ def __init__(self, parent=None): super(_NodesGridProxyModel, self).__init__(parent) def mimeData(self, indexes, p_int=None): - node_ids = ['node:{}'.format(i.data(QtCore.Qt.ToolTipRole)) - for i in indexes] + node_ids = [ + 'node:{}'.format(i.data(QtCore.Qt.ToolTipRole)) + for i in indexes + ] node_urn = URN_SCHEME + ';'.join(node_ids) - mime_data = super(_NodesGridProxyModel, self).mimeData(indexes, p_int) - mime_data.setUrls([node_urn]) + mime_data = QtCore.QMimeData() + mime_data.setData(MIME_TYPE, QtCore.QByteArray(node_urn.encode())) return mime_data diff --git a/NodeGraphQt/custom_widgets/nodes_tree.py b/NodeGraphQt/custom_widgets/nodes_tree.py index 192d2692..fe2a87c1 100644 --- a/NodeGraphQt/custom_widgets/nodes_tree.py +++ b/NodeGraphQt/custom_widgets/nodes_tree.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- from Qt import QtWidgets, QtCore, QtGui -from NodeGraphQt.constants import URN_SCHEME +from NodeGraphQt.constants import MIME_TYPE, URN_SCHEME TYPE_NODE = QtWidgets.QTreeWidgetItem.UserType + 1 TYPE_CATEGORY = QtWidgets.QTreeWidgetItem.UserType + 2 @@ -69,8 +69,8 @@ def __repr__(self): def mimeData(self, items): node_ids = ['node:{}'.format(i.toolTip(0)) for i in items] node_urn = URN_SCHEME + ';'.join(node_ids) - mime_data = super(NodesTreeWidget, self).mimeData(items) - mime_data.setUrls([node_urn]) + mime_data = QtCore.QMimeData() + mime_data.setData(MIME_TYPE, QtCore.QByteArray(node_urn.encode())) return mime_data def _build_tree(self): diff --git a/NodeGraphQt/nodes/backdrop_node.py b/NodeGraphQt/nodes/backdrop_node.py index 47e8c914..1aa9d6db 100644 --- a/NodeGraphQt/nodes/backdrop_node.py +++ b/NodeGraphQt/nodes/backdrop_node.py @@ -131,3 +131,11 @@ def size(self): self.model.width = self.view.width self.model.height = self.view.height return self.model.width, self.model.height + + def inputs(self): + # required function but unused for the backdrop node. + return + + def outputs(self): + # required function but unused for the backdrop node. + return diff --git a/NodeGraphQt/pkg_info.py b/NodeGraphQt/pkg_info.py index b8b689de..9600fa89 100644 --- a/NodeGraphQt/pkg_info.py +++ b/NodeGraphQt/pkg_info.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -__version__ = '0.6.29' +__version__ = '0.6.30' __status__ = 'Work in Progress' __license__ = 'MIT' diff --git a/NodeGraphQt/qgraphics/node_backdrop.py b/NodeGraphQt/qgraphics/node_backdrop.py index 628d2186..02990ab6 100644 --- a/NodeGraphQt/qgraphics/node_backdrop.py +++ b/NodeGraphQt/qgraphics/node_backdrop.py @@ -1,7 +1,7 @@ #!/usr/bin/python from Qt import QtGui, QtCore, QtWidgets -from NodeGraphQt.constants import Z_VAL_PIPE, NodeEnum +from NodeGraphQt.constants import Z_VAL_BACKDROP, NodeEnum from NodeGraphQt.qgraphics.node_abstract import AbstractNodeItem from NodeGraphQt.qgraphics.pipe import PipeItem from NodeGraphQt.qgraphics.port import PortItem @@ -113,7 +113,7 @@ class BackdropNodeItem(AbstractNodeItem): def __init__(self, name='backdrop', text='', parent=None): super(BackdropNodeItem, self).__init__(name, parent) - self.setZValue(Z_VAL_PIPE - 1) + self.setZValue(Z_VAL_BACKDROP) self._properties['backdrop_text'] = text self._min_size = 80, 80 self._sizer = BackdropSizer(self, 26.0) diff --git a/NodeGraphQt/qgraphics/node_base.py b/NodeGraphQt/qgraphics/node_base.py index e85474ee..f35ad9da 100644 --- a/NodeGraphQt/qgraphics/node_base.py +++ b/NodeGraphQt/qgraphics/node_base.py @@ -875,6 +875,16 @@ def text_item(self): """ return self._text_item + @property + def icon_item(self): + """ + Get the node icon qgraphics item. + + Returns: + QtWidgets.QGraphicsPixmapItem: node icon object. + """ + return self._icon_item + @property def inputs(self): """ diff --git a/NodeGraphQt/qgraphics/node_circle.py b/NodeGraphQt/qgraphics/node_circle.py index 07bb0c7e..d17fe216 100644 --- a/NodeGraphQt/qgraphics/node_circle.py +++ b/NodeGraphQt/qgraphics/node_circle.py @@ -32,7 +32,7 @@ def _align_ports_horizontal(self, v_offset): port_height = inputs[0].boundingRect().height() count = len(inputs) - if count > 2: + if count >= 2: is_odd = bool(count % 2) middle_idx = int(count / 2) @@ -60,12 +60,10 @@ def _align_ports_horizontal(self, v_offset): port.setPos(port_x, port_y) port_x += (port_width / 2) - (txt_offset / 2) port_y += port_height + spacing - else: port_x = (port_width / 2) * -1 port_y = node_center_y - (port_height / 2) - inputs[0].setPos(port_x, port_y - (port_height / 2) + spacing) - inputs[1].setPos(port_x, port_y + (port_height / 2) + spacing) + inputs[0].setPos(port_x, port_y) # adjust input text position for port, text in self._input_items.items(): @@ -81,7 +79,7 @@ def _align_ports_horizontal(self, v_offset): port_height = outputs[0].boundingRect().height() count = len(outputs) - if count > 2: + if count >= 2: is_odd = bool(count % 2) middle_idx = int(count / 2) @@ -112,8 +110,7 @@ def _align_ports_horizontal(self, v_offset): else: port_x = width - (port_width / 2) port_y = node_center_y - (port_height / 2) - outputs[0].setPos(port_x, port_y - (port_height / 2) + spacing) - outputs[1].setPos(port_x, port_y + (port_height / 2) + spacing) + outputs[0].setPos(port_x, port_y) # adjust output text position for port, text in self._output_items.items(): diff --git a/NodeGraphQt/widgets/viewer.py b/NodeGraphQt/widgets/viewer.py index 40288a2f..5c191927 100644 --- a/NodeGraphQt/widgets/viewer.py +++ b/NodeGraphQt/widgets/viewer.py @@ -673,16 +673,25 @@ def dropEvent(self, event): pos = self.mapToScene(event.pos()) event.setDropAction(QtCore.Qt.CopyAction) self.data_dropped.emit( - event.mimeData(), QtCore.QPoint(pos.x(), pos.y())) + event.mimeData(), QtCore.QPoint(pos.x(), pos.y()) + ) def dragEnterEvent(self, event): - if event.mimeData().hasFormat('text/uri-list'): + is_acceptable = any([ + event.mimeData().hasFormat(i) for i in + ['nodegraphqt/nodes', 'text/plain', 'text/uri-list'] + ]) + if is_acceptable: event.accept() else: event.ignore() def dragMoveEvent(self, event): - if event.mimeData().hasFormat('text/uri-list'): + is_acceptable = any([ + event.mimeData().hasFormat(i) for i in + ['nodegraphqt/nodes', 'text/plain', 'text/uri-list'] + ]) + if is_acceptable: event.accept() else: event.ignore()