Skip to content

Commit

Permalink
📝 Add docstrings to graphics classes
Browse files Browse the repository at this point in the history
📝 Add docstrings to graphics classes
  • Loading branch information
MathisFederico authored Nov 2, 2021
2 parents 6c4b184 + 1ceaff3 commit fe87147
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 53 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
: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
Expand Down
14 changes: 13 additions & 1 deletion opencodeblocks/core/serializable.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
7 changes: 7 additions & 0 deletions opencodeblocks/graphics/blocks/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# OpenCodeBlock an open-source tool for modular visual programing in python
# Copyright (C) 2021 Mathïs FEDERICO <https://www.gnu.org/licenses/>

""" 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
}
60 changes: 53 additions & 7 deletions opencodeblocks/graphics/blocks/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -125,17 +151,20 @@ 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:
self.sockets_out.append(socket)
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:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -174,25 +206,37 @@ 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)
if scene is not None:
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):
Expand All @@ -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):
Expand All @@ -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):
Expand Down
7 changes: 6 additions & 1 deletion opencodeblocks/graphics/blocks/codeblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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):
Expand Down
34 changes: 32 additions & 2 deletions opencodeblocks/graphics/edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -51,36 +68,48 @@ 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:
socket.remove_edge(self)
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:
self._destination = self.destination_socket.scenePos()

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':
Expand All @@ -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):
Expand Down
Loading

0 comments on commit fe87147

Please sign in to comment.