# -*- coding: utf-8 -*-
"""
A module containing NodeEditor's class for representing Socket and Socket Position Constants.
"""
from collections import OrderedDict
from node_editor.node_serializable import Serializable
from node_editor.node_graphics_socket import QDMGraphicsSocket
LEFT_TOP = 1 #:
LEFT_CENTER =2 #:
LEFT_BOTTOM = 3 #:
RIGHT_TOP = 4 #:
RIGHT_CENTER = 5 #:
RIGHT_BOTTOM = 6 #:
DEBUG = False
DEBUG_REMOVE_WARNINGS = False
[docs]class Socket(Serializable):
Socket_GR_Class = QDMGraphicsSocket
"""Class representing Socket."""
def __init__(self, node: 'Node', index: int=0, position: int=LEFT_TOP, socket_type: int=1, multi_edges: bool=True,
count_on_this_node_side: int=1, is_input: bool=False):
"""
:param node: reference to the :class:`~node_editor.node_node.Node` containing this `Socket`
:type node: :class:`~nodeeditor.node_node.Node`
:param index: Current index of this socket in the position
:type index: ``int``
:param position: Socket position. See :ref:`socket-position-constants`
:param socket_type: Constant defining type(color) of this socket
:param multi_edges: Can this socket have multiple `Edges` connected?
:type multi_edges: ``bool``
:param count_on_this_node_side: number of total sockets on this position
:type count_on_this_node_side: ``int``
:param is_input: Is this an input `Socket`?
:type is_input: ``bool``
:Instance Attributes:
- **node** - reference to the :class:`~node_editor.node_node.Node` containing this `Socket`
- **edges** - list of `Edges` connected to this `Socket`
- **grSocket** - reference to the :class:`~node_editor.node_graphics_socket.QDMGraphicsSocket`
- **position** - Socket position. See :ref:`socket-position-constants`
- **index** - Current index of this socket in the position
- **socket_type** - Constant defining type(color) of this socket
- **count_on_this_node_side** - number of sockets on this position
- **is_multi_edges** - ``True`` if `Socket` can contain multiple `Edges`
- **is_input** - ``True`` if this socket serves for Input
- **is_output** - ``True`` if this socket serves for Output
"""
super().__init__()
self.node = node
self.position = position
self.index = index
self.socket_type = socket_type
self.count_on_this_node_side = count_on_this_node_side
self.is_multi_edges = multi_edges
self.is_input = is_input
self.is_output = not self.is_input
if DEBUG: print("Socket -- creating with", self.index, self.position, "for node_editor", self.node)
self.grSocket = self.__class__.Socket_GR_Class(self)
self.setSocketPosition()
self.edges = []
def __str__(self):
return "<Socket #%d %s %s..%s>" % (
self.index, "ME" if self.is_multi_edges else "SE", hex(id(self))[2:5], hex(id(self))[-3:]
)
[docs] def delete(self):
"""Delete this `Socket` from graphics scene for sure"""
self.grSocket.setParentItem(None)
self.node.scene.grScene.removeItem(self.grSocket)
del self.grSocket
[docs] def changeSocketType(self, new_socket_type: int) -> bool:
"""
Change the Socket Type
:param new_socket_type: new socket type
:type new_socket_type: ``int``
:return: Returns ``True`` if the socket type was actually changed
:rtype: ``bool``
"""
if self.socket_type != new_socket_type:
self.socket_type = new_socket_type
self.grSocket.changeSocketType()
return True
return False
[docs] def setSocketPosition(self):
"""Helper function to set `Graphics Socket` position. Exact socket position is calculated
inside :class:`~node_editor.node_node.Node`."""
self.grSocket.setPos(*self.node.getSocketPosition(self.index, self.position, self.count_on_this_node_side))
[docs] def getSocketPosition(self):
"""
:return: Returns this `Socket` position according to the implementation stored in
:class:`~node_editor.node_node.Node`
:rtype: ``x, y`` position
"""
if DEBUG: print(" GSP: ", self.index, self.position, "node_editor:", self.node)
res = self.node.getSocketPosition(self.index, self.position, self.count_on_this_node_side)
if DEBUG: print(" res", res)
return res
[docs] def hasAnyEdge(self) -> bool:
"""
Returns ``True`` if any :class:`~node_editor.node_edge.Edge` is connected to this socket
:return: ``True`` if any :class:`~node_editor.node_edge.Edge` is connected to this socket
:rtype: ``bool``
"""
return len(self.edges) > 0
[docs] def isConnected(self, edge: 'Edge') -> bool:
"""
Returns ``True`` if :class:`~node_editor.node_edge.Edge` is connected to this `Socket`
:param edge: :class:`~node_editor.node_edge.Edge` to check if it is connected to this `Socket`
:type edge: :class:`~nodeeditor.node_edge.Edge`
:return: ``True`` if `Edge` is connected to this socket
:rtype: ``bool``
"""
return edge in self.edges
[docs] def addEdge(self, edge: 'Edge'):
"""
Append an Edge to the list of connected Edges
:param edge: :class:`~node_editor.node_edge.Edge` to connect to this `Socket`
:type edge: :class:`~nodeeditor.node_edge.Edge`
"""
self.edges.append(edge)
[docs] def removeEdge(self, edge: 'Edge'):
"""
Disconnect passed :class:`~node_editor.node_edge.Edge` from this `Socket`
:param edge: :class:`~node_editor.node_edge.Edge` to disconnect
:type edge: :class:`~nodeeditor.node_edge.Edge`
"""
if edge in self.edges: self.edges.remove(edge)
else:
if DEBUG_REMOVE_WARNINGS:
print("!W:", "Socket::removeEdge", "wanna remove edge", edge,
"from self.edges but it's not in the list!")
[docs] def removeAllEdges(self, silent: bool=False):
"""Disconnect all `Edges` from this `Socket`"""
while self.edges:
edge = self.edges.pop(0)
if silent:
edge.remove(silent_for_socket=self)
else:
edge.remove() # just remove all with notifications
[docs] def determineMultiEdges(self, data: dict) -> bool:
"""
Deserialization helper function. In our tutorials we created a new version of graph data format.
This function is here to help solve the issue of opening older files in the newer format.
If the 'multi_edges' param is missing in the dictionary, we determine if this `Socket`
should support multiple `Edges`.
:param data: `Socket` data in ``dict`` format for deserialization
:type data: ``dict``
:return: ``True`` if this `Socket` should support multi_edges
"""
if 'multi_edges' in data:
return data['multi_edges']
else:
# probably older version of file, make RIGHT socket multiedged by default
return data['position'] in (RIGHT_BOTTOM, RIGHT_TOP)
[docs] def serialize(self) -> OrderedDict:
return OrderedDict([
('id', self.id),
('index', self.index),
('multi_edges', self.is_multi_edges),
('position', self.position),
('socket_type', self.socket_type),
])
[docs] def deserialize(self, data: dict, hashmap: dict={}, restore_id: bool=True) -> bool:
if restore_id: self.id = data['id']
self.is_multi_edges = self.determineMultiEdges(data)
self.changeSocketType(data['socket_type'])
hashmap[data['id']] = self
return True