From 8bf37aeb92752a5d0ecabc4cec0676d154cf13ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 14:42:30 +0100 Subject: [PATCH 01/12] :memo: Add docstrings in serializable.py --- opencodeblocks/core/serializable.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/opencodeblocks/core/serializable.py b/opencodeblocks/core/serializable.py index 4d3a1fe6..ce1fb827 100644 --- a/opencodeblocks/core/serializable.py +++ b/opencodeblocks/core/serializable.py @@ -8,11 +8,23 @@ class Serializable(): - def __init__(self) -> None: + """ Serializable base for serializable objects. """ + + def __init__(self): self.id = id(self) def serialize(self) -> OrderedDict: + """ Serialize the object as an ordered dictionary. """ raise NotImplementedError() def deserialize(self, data:OrderedDict, hashmap:dict=None, restore_id=True) -> None: + """ Deserialize the object from an ordered dictionary. + + Args: + data: Dictionnary containing data do deserialize from. + hashmap: Dictionnary mapping a hash code into knowed objects. + restore_id: If True, the id will be restored using the given data. + If False, a new id will be generated. + + """ raise NotImplementedError() From abc4ed5b7bd9a7915084491379cfec117fad83f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 15:03:45 +0100 Subject: [PATCH 02/12] :memo: Add docstrings to edge.py --- opencodeblocks/graphics/edge.py | 34 +++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/opencodeblocks/graphics/edge.py b/opencodeblocks/graphics/edge.py index 8a3df5b8..0666bd6b 100644 --- a/opencodeblocks/graphics/edge.py +++ b/opencodeblocks/graphics/edge.py @@ -16,11 +16,28 @@ class OCBEdge(QGraphicsPathItem, Serializable): - def __init__(self, path_type='bezier', edge_color="#001000", edge_selected_color="#00ff00", - edge_width:float=4.0, + + """ Base class for directed edges in OpenCodeBlocks. """ + + def __init__(self, edge_width:float=4.0, path_type='bezier', + edge_color="#001000", edge_selected_color="#00ff00", source:QPointF=QPointF(0, 0), destination:QPointF=QPointF(0, 0), source_socket:OCBSocket=None, destination_socket:OCBSocket=None ): + """ Base class for edges in OpenCodeBlocks. + + Args: + edge_width: Width of the edge. + path_type: Type of path, one of ('direct', 'bezier'). + edge_color: Color of the edge. + edge_selected_color: Color of the edge when it is selected. + source: Source point of the directed edge. + destination: Destination point of the directed edge. + source_socket: Source socket of the directed edge, overrides source. + destination_socket: Destination socket of the directed edge, overrides destination. + + """ + Serializable.__init__(self) QGraphicsPathItem.__init__(self, parent=None) self._pen = QPen(QColor(edge_color)) @@ -51,6 +68,12 @@ def __init__(self, path_type='bezier', edge_color="#001000", edge_selected_color self.updateSocketsPosition() def remove_from_socket(self, socket_type='source'): + """ Remove the edge from the sockets it is snaped to on the given socket_type. + + Args: + socket_type: One of ('source', 'destination'). + + """ socket_name = f'{socket_type}_socket' socket = getattr(self, socket_name, OCBSocket) if socket is not None: @@ -58,15 +81,18 @@ def remove_from_socket(self, socket_type='source'): setattr(self, socket_name, None) def remove_from_sockets(self): + """ Remove the edge from all sockets it is snaped to. """ self.remove_from_socket('source') self.remove_from_socket('destination') def remove(self): + """ Remove the edge from the scene in which it is drawn. """ scene = self.scene() if scene is not None: scene.removeItem(self) def updateSocketsPosition(self): + """ Update source and destination based on the sockets the edge is snaped to. """ if self.source_socket is not None: self.source = self.source_socket.scenePos() if self.destination_socket is not None: @@ -74,13 +100,16 @@ def updateSocketsPosition(self): def paint(self, painter:QPainter, option: QStyleOptionGraphicsItem, widget: Optional[QWidget]=None): + """ Paint the edge. """ self.update_path() pen = self._pen_dragging if self.destination_socket is None else self._pen painter.setPen(self._pen_selected if self.isSelected() else pen) painter.setBrush(Qt.BrushStyle.NoBrush) painter.drawPath(self.path()) + super().paint(painter, option, widget) def update_path(self): + """ Update the edge path depending on the path_type. """ self.updateSocketsPosition() path = QPainterPath(self.source) if self.path_type == 'direct': @@ -96,6 +125,7 @@ def update_path(self): @property def destination(self): + """ Destination point of the directed edge. """ return self._destination @destination.setter def destination(self, value): From c0b5433ae5e15096d8facf046dfc4bd6414be4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 15:12:01 +0100 Subject: [PATCH 03/12] :memo: Add docstrings to pyeditor.py --- opencodeblocks/graphics/pyeditor.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/opencodeblocks/graphics/pyeditor.py b/opencodeblocks/graphics/pyeditor.py index 9a2ab71f..88e6c1d3 100644 --- a/opencodeblocks/graphics/pyeditor.py +++ b/opencodeblocks/graphics/pyeditor.py @@ -3,17 +3,28 @@ """ Module for OCB in block python editor. """ +from typing import TYPE_CHECKING, List from PyQt5.QtCore import Qt from PyQt5.QtGui import QFocusEvent, QFont, QFontMetrics, QColor from PyQt5.Qsci import QsciScintilla, QsciLexerPython from opencodeblocks.graphics.blocks.block import OCBBlock +if TYPE_CHECKING: + from opencodeblocks.graphics.view import OCBView class PythonEditor(QsciScintilla): - def __init__(self, block:OCBBlock, parent=None): - super().__init__(parent) + """ In-block python editor for OpenCodeBlocks. """ + + def __init__(self, block:OCBBlock): + """ In-block python editor for OpenCodeBlocks. + + Args: + block: Block in which to add the python editor widget. + + """ + super().__init__(None) self.block = block self.setText(self.block.source) @@ -86,16 +97,23 @@ def __init__(self, block:OCBBlock, parent=None): self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.setWindowFlags(Qt.WindowType.FramelessWindowHint) + def views(self) -> List['OCBView']: + """ Get the views in which the python_editor is present. """ + return self.graphicsProxyWidget().scene().views() + def set_views_mode(self, mode:str): - for view in self.graphicsProxyWidget().scene().views(): + """ Set the views in which the python_editor is present to editing mode. """ + for view in self.views(): if mode == "MODE_EDITING" or view.is_mode("MODE_EDITING"): view.set_mode(mode) def focusInEvent(self, event: QFocusEvent): + """ PythonEditor reaction to PyQt focusIn events. """ self.set_views_mode("MODE_EDITING") return super().focusInEvent(event) def focusOutEvent(self, event: QFocusEvent): + """ PythonEditor reaction to PyQt focusOut events. """ self.set_views_mode("MODE_NOOP") if self.isModified(): self.block.source = self.text() From 9b7886f29ea577d1fcd210a1d469a07352992f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 15:27:45 +0100 Subject: [PATCH 04/12] :memo: Add docstring to socket.py --- opencodeblocks/graphics/socket.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/socket.py b/opencodeblocks/graphics/socket.py index 256f7fee..749dcc16 100644 --- a/opencodeblocks/graphics/socket.py +++ b/opencodeblocks/graphics/socket.py @@ -19,8 +19,21 @@ class OCBSocket(QGraphicsItem, Serializable): + """ Socket base class for OpenCodeBlocks. """ + def __init__(self, block:'OCBBlock', socket_type:str='undefined', radius:float=6.0, color:str='#FF55FFF0', linewidth:float=1.0, linecolor:str='#FF000000'): + """ Socket base class for OpenCodeBlocks. + + Args: + block: Block containing the socket. + socket_type: Type of the socket. + radius: Radius of the socket graphics. + color: Color of the socket graphics. + linewidth: Linewidth of the socket graphics. + linecolor: Linecolor of the socket graphics. + + """ Serializable.__init__(self) self.block = block QGraphicsItem.__init__(self, parent=self.block) @@ -41,26 +54,33 @@ def __init__(self, block:'OCBBlock', socket_type:str='undefined', radius:float=6 } def add_edge(self, edge:'OCBEdge'): + """ Add a given edge to the socket edges. """ self.edges.append(edge) def remove_edge(self, edge:'OCBEdge'): + """ Remove a given edge from the socket edges. """ self.edges.remove(edge) def remove(self): + """ Remove the socket and all its edges from the scene it is in. """ for edge in self.edges: edge.remove() scene = self.scene() if scene is not None: scene.removeItem(self) - def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, + def paint(self, painter: QPainter, + option: QStyleOptionGraphicsItem, widget: Optional[QWidget]=None): + """ Paint the socket. """ painter.setBrush(self._brush) painter.setPen(self._pen) r = self.radius painter.drawEllipse(int(-r),int(-r),int(2*r),int(2*r)) + super().paint(painter, option, widget) def boundingRect(self) -> QRectF: + """ Get the socket bounding box. """ r = self.radius return QRectF(-r, -r, 2*r, 2*r) From e09bf57c4207419b88f146f6d7074bf87fd8183a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 16:06:00 +0100 Subject: [PATCH 05/12] :beetle: Bugfix reccursion loop in OCBSocket.paint --- opencodeblocks/graphics/socket.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/opencodeblocks/graphics/socket.py b/opencodeblocks/graphics/socket.py index 749dcc16..53cd0b81 100644 --- a/opencodeblocks/graphics/socket.py +++ b/opencodeblocks/graphics/socket.py @@ -70,14 +70,13 @@ def remove(self): scene.removeItem(self) def paint(self, painter: QPainter, - option: QStyleOptionGraphicsItem, - widget: Optional[QWidget]=None): + option: QStyleOptionGraphicsItem, #pylint:disable=unused-argument + widget: Optional[QWidget]=None): #pylint:disable=unused-argument """ Paint the socket. """ painter.setBrush(self._brush) painter.setPen(self._pen) r = self.radius painter.drawEllipse(int(-r),int(-r),int(2*r),int(2*r)) - super().paint(painter, option, widget) def boundingRect(self) -> QRectF: """ Get the socket bounding box. """ From a467cd02e0a1aecf2b9c9418071ac27d0094a75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 16:25:31 +0100 Subject: [PATCH 06/12] :memo: Add docstrings to view.py --- opencodeblocks/graphics/view.py | 78 +++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/opencodeblocks/graphics/view.py b/opencodeblocks/graphics/view.py index 880447f9..f5057eff 100644 --- a/opencodeblocks/graphics/view.py +++ b/opencodeblocks/graphics/view.py @@ -6,7 +6,7 @@ from PyQt5.QtCore import QEvent, QPointF, Qt from PyQt5.QtGui import QMouseEvent, QPainter, QWheelEvent from PyQt5.QtWidgets import QGraphicsView -from sip import isdeleted +from PyQt5.sip import isdeleted from opencodeblocks.graphics.scene import OCBScene from opencodeblocks.graphics.socket import OCBSocket @@ -64,10 +64,11 @@ def init_ui(self): self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) def scene(self) -> OCBScene: + """ Get current OCBScene. """ return super().scene() def mousePressEvent(self, event: QMouseEvent): - """Dispatch Qt's mousePress events to corresponding functions below""" + """ Dispatch Qt's mousePress events to corresponding functions below. """ if event.button() == Qt.MouseButton.MiddleButton: self.middleMouseButtonPress(event) elif event.button() == Qt.MouseButton.LeftButton: @@ -77,12 +78,6 @@ def mousePressEvent(self, event: QMouseEvent): else: super().mousePressEvent(event) - def mouseMoveEvent(self, event: QMouseEvent) -> None: - self.lastMousePos = self.mapToScene(event.pos()) - self.drag_edge(event, 'move') - if event is not None: - super().mouseMoveEvent(event) - def mouseReleaseEvent(self, event: QMouseEvent): """Dispatch Qt's mouseRelease events to corresponding functions below""" if event.button() == Qt.MouseButton.MiddleButton: @@ -94,34 +89,58 @@ def mouseReleaseEvent(self, event: QMouseEvent): else: super().mouseReleaseEvent(event) + def mouseMoveEvent(self, event: QMouseEvent) -> None: + """ OCBView reaction to mouseMoveEvent. """ + self.lastMousePos = self.mapToScene(event.pos()) + self.drag_edge(event, 'move') + if event is not None: + super().mouseMoveEvent(event) + def middleMouseButtonPress(self, event: QMouseEvent): + """ OCBView reaction to middleMouseButtonPress event. """ super().mousePressEvent(event) def middleMouseButtonRelease(self, event: QMouseEvent): + """ OCBView reaction to middleMouseButtonRelease event. """ super().mouseReleaseEvent(event) def leftMouseButtonPress(self, event: QMouseEvent): - event = self.bring_forward(event) + """ OCBView reaction to leftMouseButtonPress event. """ + # If clicked on a block, bring it forward. + item_at_click = self.itemAt(event.pos()) + if item_at_click is not None: + while item_at_click.parentItem() is not None: + if isinstance(item_at_click,OCBBlock): + break + item_at_click = item_at_click.parentItem() + + if isinstance(item_at_click, OCBBlock): + self.bring_block_forward(item_at_click) + + # If clicked on a socket, start dragging an edge. event = self.drag_edge(event, 'press') if event is not None: super().mousePressEvent(event) def leftMouseButtonRelease(self, event: QMouseEvent): + """ OCBView reaction to leftMouseButtonRelease event. """ event = self.drag_edge(event, 'release') if event is not None: super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event: QMouseEvent): + """ OCBView reaction to rightMouseButtonPress event. """ event = self.drag_scene(event, "press") super().mousePressEvent(event) def rightMouseButtonRelease(self, event: QMouseEvent): + """ OCBView reaction to rightMouseButtonRelease event. """ event = self.drag_scene(event, "release") super().mouseReleaseEvent(event) self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) def wheelEvent(self, event: QWheelEvent): - """ Handles zooming with mouse wheel """ + """ Handles zooming with mouse wheel events. """ if Qt.Modifier.CTRL == int(event.modifiers()): # calculate zoom if event.angleDelta().y() > 0: @@ -136,30 +155,23 @@ def wheelEvent(self, event: QWheelEvent): super().wheelEvent(event) def deleteSelected(self): + """ Delete selected items from the current scene. """ scene = self.scene() for selected_item in scene.selectedItems(): selected_item.remove() scene.history.checkpoint("Delete selected elements", set_modified=True) - def bring_forward(self, event: QMouseEvent): - """ When a codeblock is selected, it will be drawn in front of other blocks """ - item_at_click = self.itemAt(event.pos()) - if item_at_click is None: - return event - - while item_at_click.parentItem() is not None: - if isinstance(item_at_click,OCBBlock): - break - item_at_click = item_at_click.parentItem() + def bring_block_forward(self, block: OCBBlock): + """ Move the selected block in front of other blocks. - if isinstance(item_at_click, OCBBlock): - if self.currentSelectedBlock is not None and not isdeleted(self.currentSelectedBlock): - self.currentSelectedBlock.setZValue(0) - item_at_click.setZValue(1) - self.currentSelectedBlock = item_at_click - - return event # This is never considered as a handling of the event. + Args: + block: Block to bring forward. + """ + if self.currentSelectedBlock is not None and not isdeleted(self.currentSelectedBlock): + self.currentSelectedBlock.setZValue(0) + block.setZValue(1) + self.currentSelectedBlock = block def drag_scene(self, event: QMouseEvent, action="press"): """ Drag the scene around. """ @@ -209,7 +221,19 @@ def drag_edge(self, event: QMouseEvent, action="press"): return event def set_mode(self, mode:str): + """ Change the view mode. + + Args: + mode: Mode key to change to, must in present in knowed MODES. + + """ self.mode = MODES[mode] def is_mode(self, mode:str): + """ Return True if the view is in the given mode. + + Args: + mode: Mode key to compare to, must in present in knowed MODES. + + """ return self.mode == MODES[mode] From 43d1f0b8f8a068ad3d2c0cceef6fe19c3706c4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 16:27:16 +0100 Subject: [PATCH 07/12] :memo: Add docstring to window.py --- opencodeblocks/graphics/window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opencodeblocks/graphics/window.py b/opencodeblocks/graphics/window.py index 6e959a8b..c960e362 100644 --- a/opencodeblocks/graphics/window.py +++ b/opencodeblocks/graphics/window.py @@ -194,6 +194,7 @@ def closeEvent(self, event:QEvent): event.ignore() def isModified(self) -> bool: + """ Return True if the scene has been modified, False otherwise. """ return self.centralWidget().scene.has_been_modified def maybeSave(self) -> bool: From c7d30cb522521fb3f4e6d6352974f34b4c258f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 16:43:57 +0100 Subject: [PATCH 08/12] :memo: Add docstrings to block.py --- opencodeblocks/graphics/blocks/block.py | 60 ++++++++++++++++++++++--- opencodeblocks/graphics/socket.py | 4 +- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 8f66a6a5..90630bf6 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -19,9 +19,29 @@ class OCBBlock(QGraphicsItem, Serializable): - def __init__(self, title:str='New block', block_type:str='base', source:str='', - position:tuple=(0, 0), title_color:str='white', title_font:str="Ubuntu", + """ Base class for blocks in OpenCodeBlocks. """ + + def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), + width:int=300, height:int=200, edge_size:float=10.0, + title:str='New block', title_color:str='white', title_font:str="Ubuntu", title_size:int=10, title_padding=4.0, parent: Optional['QGraphicsItem']=None): + """ Base class for blocks in OpenCodeBlocks. + + Args: + block_type: Block type. + source: Block source text. + position: Block position in the scene. + width: Block width. + height: Block height. + edge_size: Block edges size. + title: Block title. + title_color: Color of the block title. + title_font: Font of the block title. + title_size: Size of the block title. + title_padding: Padding of the block title. + parent: Parent of the block. + + """ QGraphicsItem.__init__(self, parent=parent) Serializable.__init__(self) @@ -34,9 +54,9 @@ def __init__(self, title:str='New block', block_type:str='base', source:str='', self._min_width = 300 self._min_height = 100 - self.width = 300 - self.height = 200 - self.edge_size = 10.0 + self.width = width + self.height = height + self.edge_size = edge_size self.title_height = 3 * title_size self.title_graphics = QGraphicsTextItem(self) @@ -64,13 +84,17 @@ def __init__(self, title:str='New block', block_type:str='base', source:str='', } def scene(self) -> 'OCBScene': + """ Get the current OCBScene containing the block. """ return super().scene() def boundingRect(self) -> QRectF: + """ Get the the block bounding box. """ return QRectF(0, 0, self.width, self.height).normalized() - def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, - widget: Optional[QWidget]=None) -> None: + def paint(self, painter: QPainter, + option: QStyleOptionGraphicsItem, #pylint:disable=unused-argument + widget: Optional[QWidget]=None): #pylint:disable=unused-argument + """ Paint the block. """ # title path_title = QPainterPath() path_title.setFillRule(Qt.FillRule.WindingFill) @@ -105,10 +129,12 @@ def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, painter.drawPath(path_outline.simplified()) def _is_in_resize_area(self, pos:QPointF): + """ Return True if the given position is in the block resize_area. """ return self.width - pos.x() < 2 * self.edge_size \ and self.height - pos.y() < 2 * self.edge_size def get_socket_pos(self, socket:OCBSocket) -> Tuple[float]: + """ Get a socket position to place them on the block sides. """ if socket.socket_type == 'input': x = 0 sockets = self.sockets_in @@ -125,10 +151,12 @@ def get_socket_pos(self, socket:OCBSocket) -> Tuple[float]: return x, y def update_sockets(self): + """ Update the sockets positions. """ for socket in self.sockets_in + self.sockets_out: socket.setPos(*self.get_socket_pos(socket)) def add_socket(self, socket:OCBSocket): + """ Add a socket to the block. """ if socket.socket_type == 'input': self.sockets_in.append(socket) else: @@ -136,6 +164,7 @@ def add_socket(self, socket:OCBSocket): self.update_sockets() def remove_socket(self, socket:OCBSocket): + """ Remove a socket from the block. """ if socket.socket_type == 'input': self.sockets_in.remove(socket) else: @@ -144,6 +173,7 @@ def remove_socket(self, socket:OCBSocket): self.update_sockets() def mousePressEvent(self, event:QGraphicsSceneMouseEvent): + """ OCBBlock reaction to a mousePressEvent. """ pos = event.pos() if self._is_in_resize_area(pos) and event.buttons() == Qt.MouseButton.LeftButton: self.resize_start = pos @@ -152,6 +182,7 @@ def mousePressEvent(self, event:QGraphicsSceneMouseEvent): super().mousePressEvent(event) def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent): + """ OCBBlock reaction to a mouseReleaseEvent. """ if self.resizing: self.scene().history.checkpoint("Resized block", set_modified=True) self.resizing = False @@ -162,6 +193,7 @@ def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent): + """ OCBBlock reaction to a mouseMoveEvent. """ if self.resizing: delta = event.pos() - self.resize_start self.width = max(self.width + delta.x(), self._min_width) @@ -174,12 +206,22 @@ def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent): self.moved = True def setTitleGraphics(self, color:str, font:str, size:int, padding:float): + """ Set the title graphics. + + Args: + color: title color. + font: title font. + size: title size. + padding: title padding. + + """ self.title_graphics.setDefaultTextColor(QColor(color)) self.title_graphics.setFont(QFont(font, size)) self.title_graphics.setPos(padding, 0) self.title_graphics.setTextWidth(self.width - 2 * self.edge_size) def remove(self): + """ Remove the block from the scene containing it. """ scene = self.scene() for socket in self.sockets_in + self.sockets_out: self.remove_socket(socket) @@ -187,12 +229,14 @@ def remove(self): scene.removeItem(self) def update_all(self): + """ Update sockets and title. """ self.update_sockets() if hasattr(self, 'title_graphics'): self.title_graphics.setTextWidth(self.width - 2 * self.edge_size) @property def title(self): + """ Block title. """ return self._title @title.setter def title(self, value:str): @@ -202,6 +246,7 @@ def title(self, value:str): @property def width(self): + """ Block width. """ return self._width @width.setter def width(self, value:float): @@ -210,6 +255,7 @@ def width(self, value:float): @property def height(self): + """ Block height. """ return self._height @height.setter def height(self, value:float): diff --git a/opencodeblocks/graphics/socket.py b/opencodeblocks/graphics/socket.py index 53cd0b81..e7bc2dad 100644 --- a/opencodeblocks/graphics/socket.py +++ b/opencodeblocks/graphics/socket.py @@ -19,11 +19,11 @@ class OCBSocket(QGraphicsItem, Serializable): - """ Socket base class for OpenCodeBlocks. """ + """ Base class for sockets in OpenCodeBlocks. """ def __init__(self, block:'OCBBlock', socket_type:str='undefined', radius:float=6.0, color:str='#FF55FFF0', linewidth:float=1.0, linecolor:str='#FF000000'): - """ Socket base class for OpenCodeBlocks. + """ Base class for sockets in OpenCodeBlocks. Args: block: Block containing the socket. From 293b660988c4643f8c636c1c2425fad6fa07526a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 17:30:58 +0100 Subject: [PATCH 09/12] :memo: Add docstrings to codeblock.py --- opencodeblocks/graphics/blocks/__init__.py | 7 +++++++ opencodeblocks/graphics/blocks/codeblock.py | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/blocks/__init__.py b/opencodeblocks/graphics/blocks/__init__.py index 57ca1243..893604f8 100644 --- a/opencodeblocks/graphics/blocks/__init__.py +++ b/opencodeblocks/graphics/blocks/__init__.py @@ -1,5 +1,12 @@ # OpenCodeBlock an open-source tool for modular visual programing in python # Copyright (C) 2021 Mathïs FEDERICO +""" Module for the OCB Blocks of different types. """ + from opencodeblocks.graphics.blocks.block import OCBBlock from opencodeblocks.graphics.blocks.codeblock import OCBCodeBlock + +BLOCKS = { + 'base': OCBBlock, + 'code': OCBCodeBlock +} diff --git a/opencodeblocks/graphics/blocks/codeblock.py b/opencodeblocks/graphics/blocks/codeblock.py index 67219e14..306a2e96 100644 --- a/opencodeblocks/graphics/blocks/codeblock.py +++ b/opencodeblocks/graphics/blocks/codeblock.py @@ -10,11 +10,14 @@ class OCBCodeBlock(OCBBlock): + """ Code Block. """ + def __init__(self, **kwargs): super().__init__(block_type='code', **kwargs) self.source_editor = self.init_source_editor() def init_source_editor(self): + """ Initialize the python source code editor. """ source_editor_graphics = QGraphicsProxyWidget(self) source_editor = PythonEditor(self) source_editor.setGeometry( @@ -28,6 +31,7 @@ def init_source_editor(self): return source_editor_graphics def update_all(self): + """ Update the code block parts. """ if hasattr(self, 'source_editor'): editor_widget = self.source_editor.widget() editor_widget.setGeometry( @@ -39,7 +43,8 @@ def update_all(self): super().update_all() @property - def source(self): + def source(self) -> str: + """ Source code. """ return self._source @source.setter def source(self, value:str): From 907f5fb137d6e1f57c3a77bb31822e0242abe100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 17:41:24 +0100 Subject: [PATCH 10/12] :memo: Add docstrings to scene module --- opencodeblocks/graphics/scene/__init__.py | 2 ++ opencodeblocks/graphics/scene/clipboard.py | 18 ++++++++++-------- opencodeblocks/graphics/scene/scene.py | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/opencodeblocks/graphics/scene/__init__.py b/opencodeblocks/graphics/scene/__init__.py index 430e5673..efb3c80c 100644 --- a/opencodeblocks/graphics/scene/__init__.py +++ b/opencodeblocks/graphics/scene/__init__.py @@ -1,4 +1,6 @@ # OpenCodeBlock an open-source tool for modular visual programing in python # Copyright (C) 2021 Mathïs FEDERICO +""" Module for the OCBScene creation and manipulations. """ + from opencodeblocks.graphics.scene.scene import OCBScene diff --git a/opencodeblocks/graphics/scene/clipboard.py b/opencodeblocks/graphics/scene/clipboard.py index 34f375c1..b377359e 100644 --- a/opencodeblocks/graphics/scene/clipboard.py +++ b/opencodeblocks/graphics/scene/clipboard.py @@ -18,26 +18,28 @@ class SceneClipboard(): - """ Helper object to handle clipboard operations on an OCBScene. - Args: - scene: Scene reference. - - """ + """ Helper object to handle clipboard operations on an OCBScene. """ def __init__(self, scene:'OCBScene'): - self.scene = scene + """ Helper object to handle clipboard operations on an OCBScene. - def views(self) -> 'OCBView': - return super().views() + Args: + scene: Scene reference. + + """ + self.scene = scene def cut(self): + """ Cut the selected items and put them into clipboard. """ self._store(self._serializeSelected(delete=True)) def copy(self): + """ Copy the selected items into clipboard. """ self._store(self._serializeSelected(delete=False)) def paste(self): + """ Paste the items in clipboard into the current scene. """ self._deserializeData(self._gatherData()) def _serializeSelected(self, delete=False) -> OrderedDict: diff --git a/opencodeblocks/graphics/scene/scene.py b/opencodeblocks/graphics/scene/scene.py index 9e83137b..c7b6c68b 100644 --- a/opencodeblocks/graphics/scene/scene.py +++ b/opencodeblocks/graphics/scene/scene.py @@ -50,6 +50,7 @@ def __init__(self, parent=None, @property def has_been_modified(self): + """ True if the scene has been modified, False otherwise. """ return self._has_been_modified @has_been_modified.setter def has_been_modified(self, value:bool): @@ -63,9 +64,11 @@ def has_been_modified(self, value:bool): self._has_been_modified = value def addHasBeenModifiedListener(self, callback:FunctionType): + """ Add a callback that will trigger when the scene has been modified. """ self._has_been_modified_listeners.append(callback) def sortedSelectedItems(self) -> List[Union[OCBBlock, OCBEdge]]: + """ Returns the selected blocks and selected edges in two separate lists. """ selected_blocks, selected_edges = [], [] for item in self.selectedItems(): if isinstance(item, OCBBlock): @@ -115,10 +118,12 @@ def drawGrid(self, painter: QPainter, rect: QRectF): painter.drawLines(*lines_light) def save(self, filepath:str): + """ Save the scene into filepath. """ self.save_to_ipyg(filepath) self.has_been_modified = False def save_to_ipyg(self, filepath:str): + """ Save the scene into filepath as interactive python graph (.ipyg). """ if '.' not in filepath: filepath += '.ipyg' @@ -130,6 +135,12 @@ def save_to_ipyg(self, filepath:str): file.write(json.dumps(self.serialize(), indent=4)) def load(self, filepath:str): + """ Load a saved scene. + + Args: + filepath: Path to the file to load. + + """ if filepath.endswith('.ipyg'): data = self.load_from_ipyg(filepath) else: @@ -140,11 +151,18 @@ def load(self, filepath:str): self.has_been_modified = False def load_from_ipyg(self, filepath:str): + """ Load an interactive python graph (.ipyg) into the scene. + + Args: + filepath: Path to the .ipyg file to load. + + """ with open(filepath, 'r', encoding='utf-8') as file: data = json.loads(file.read()) return data def clear(self): + """ Clear the scene from all items. """ self.has_been_modified = False return super().clear() From 86070ebd84f6a81493e5b9fac0fc41e3d56ce6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 17:46:43 +0100 Subject: [PATCH 11/12] :memo: Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 827d9249..b279725e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ You should also start your commit message with one or two applicable emoji. This Emoji | Description -----------------|------------- :tada: `:tada:` | When you add a cool new feature -:bug: `:bug:` | When you fixed a bug +:bug: `:beetle:` | When you fixed a bug :fire: `:fire:` | When you removed something :truck: `:truck:`| When you moved/renamed something :wrench: `:wrench:` | When you improved/refactored a small piece of code From 1ceaff3071f9b9ce0705875c8bf4e36171d6d254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Tue, 2 Nov 2021 17:48:30 +0100 Subject: [PATCH 12/12] :memo: Updated CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b279725e..f52c6233 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ [![Pytest badge](https://github.com/MathisFederico/OpenCodeBlocks/actions/workflows/python-tests.yml/badge.svg?branch=master)](https://github.com/MathisFederico/OpenCodeBlocks/actions/workflows/python-tests.yml) [![Pylint badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FMathisFederico%2F00ce73155619a4544884ca6d251954b3%2Fraw%2Fopencodeblocks_pylint_badge.json)](https://github.com/MathisFederico/OpenCodeBlocks/actions/workflows/python-pylint.yml) [![Unit coverage badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FMathisFederico%2F00ce73155619a4544884ca6d251954b3%2Fraw%2Fopencodeblocks_unit_coverage_badge.json)](https://github.com/MathisFederico/OpenCodeBlocks/actions/workflows/python-coverage.yml) [![Integration coverage badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FMathisFederico%2F00ce73155619a4544884ca6d251954b3%2Fraw%2Fopencodeblocks_integration_coverage_badge.json)](https://github.com/MathisFederico/OpenCodeBlocks/actions/workflows/python-coverage.yml) -Whenever you encounter a :bug: **bug** or have :tada: **feature request**, +Whenever you encounter a :beetle: **bug** or have :tada: **feature request**, report this via [GitHub issues](https://github.com/MathisFederico/OpenCodeBlocks/issues). We are happy to receive contributions in the form of **pull requests** via GitHub. @@ -39,7 +39,7 @@ You should also start your commit message with one or two applicable emoji. This Emoji | Description -----------------|------------- :tada: `:tada:` | When you add a cool new feature -:bug: `:beetle:` | When you fixed a bug +:beetle: `:beetle:` | When you fixed a bug :fire: `:fire:` | When you removed something :truck: `:truck:`| When you moved/renamed something :wrench: `:wrench:` | When you improved/refactored a small piece of code