From fd95e0d5b2b7e016728fc1189443857af3f1f1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 16:28:35 +0100 Subject: [PATCH 01/13] :tada: :wrench: Starts work on the widgetification of the interface. Removes the size code which is now handled by a QSizeGrip and a QSplitter --- .gitignore | 3 + opencodeblocks/graphics/blocks/block.py | 189 ++++++++++---------- opencodeblocks/graphics/blocks/codeblock.py | 125 +------------ opencodeblocks/graphics/pyeditor.py | 2 +- opencodeblocks/graphics/scene/scene.py | 2 + 5 files changed, 107 insertions(+), 214 deletions(-) diff --git a/.gitignore b/.gitignore index 3f51e187..21565abd 100644 --- a/.gitignore +++ b/.gitignore @@ -126,3 +126,6 @@ dmypy.json # Sublime text *.sublime-workspace + +# Pyright config +pyrightconfig.json diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 5475a3b9..6613575c 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -6,8 +6,8 @@ from typing import TYPE_CHECKING, Optional, OrderedDict, Tuple from PyQt5.QtCore import QPointF, QRectF, Qt -from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPainter, QPainterPath -from PyQt5.QtWidgets import QGraphicsItem, QGraphicsSceneMouseEvent, QGraphicsTextItem, \ +from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPainter, QPainterPath, QResizeEvent +from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, QGraphicsSceneMouseEvent, QGraphicsTextItem, QLabel, QSizeGrip, QSplitter, \ QStyleOptionGraphicsItem, QWidget, QApplication, QGraphicsSceneHoverEvent from opencodeblocks.core.serializable import Serializable @@ -16,6 +16,15 @@ if TYPE_CHECKING: from opencodeblocks.graphics.scene.scene import OCBScene +class RootWidget(QWidget): + def __init__(self, parent: QWidget = None): + super().__init__(parent) + def resizeEvent(self, evt: QResizeEvent): + # super().resizeEvent(evt) + print("r evt") + print(evt.size().width(),evt.size().height()) + print(evt.oldSize().width(),evt.oldSize().height()) + class OCBBlock(QGraphicsItem, Serializable): @@ -58,9 +67,9 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.height = height self.edge_size = edge_size + # self.title_graphics = QGraphicsTextItem(self) + # self.setTitleGraphics(title_color, title_font, title_size, title_padding) self.title_height = 3 * title_size - self.title_graphics = QGraphicsTextItem(self) - self.setTitleGraphics(title_color, title_font, title_size, title_padding) self.title = title self._pen_outline = QPen(QColor("#7F000000")) @@ -74,6 +83,28 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.setAcceptHoverEvents(True) + self.holder = QGraphicsProxyWidget(self) + self.root = RootWidget() + self.root.setAttribute(Qt.WA_TranslucentBackground) + self.root.setGeometry( + 0,0, + int(self.width), + int(self.height) + ) + + + self.title_widget = QLabel(self.title,self.root) + self.title_widget.setAttribute(Qt.WA_TransparentForMouseEvents) + self.title_widget.setAttribute(Qt.WA_TranslucentBackground) + self.setTitleGraphics(title_color,title_font,title_size,title_padding) + + self.splitter = QSplitter(Qt.Vertical,self.root) + + self.size_grip = QSizeGrip(self.root) + + self.holder.setWidget(self.root) + # self.holder.setZValue(-1) + self.resizing = False self.resizing_hover = False # Is the mouse hovering over the resizing area ? self.moved = False @@ -94,34 +125,33 @@ def boundingRect(self) -> QRectF: """ Get the the block bounding box. """ return QRectF(0, 0, self.width, self.height).normalized() + 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_widget.setMargin(int(padding)) + self.title_widget.setStyleSheet("QLabel { color : %s; }" % color); + self.title_widget.setFont(QFont(font, size)) + 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) - path_title.addRoundedRect(0, 0, self.width, self.title_height, - self.edge_size, self.edge_size) - path_title.addRect(0, self.title_height - self.edge_size, - self.edge_size, self.edge_size) - path_title.addRect(self.width - self.edge_size, self.title_height - self.edge_size, - self.edge_size, self.edge_size) - painter.setPen(Qt.PenStyle.NoPen) - painter.setBrush(self._brush_title) - painter.drawPath(path_title.simplified()) - + # content - path_title = QPainterPath() - path_title.setFillRule(Qt.FillRule.WindingFill) - path_title.addRoundedRect(0, self.title_height, self.width, self.height - self.title_height, - self.edge_size, self.edge_size) - path_title.addRect(0, self.title_height, self.edge_size, self.edge_size) - path_title.addRect(self.width - self.edge_size, self.title_height, + path_content = QPainterPath() + path_content.setFillRule(Qt.FillRule.WindingFill) + path_content.addRoundedRect(0, 0, self.width, self.height, self.edge_size, self.edge_size) painter.setPen(Qt.PenStyle.NoPen) painter.setBrush(self._brush_background) - painter.drawPath(path_title.simplified()) + painter.drawPath(path_content.simplified()) # outline path_outline = QPainterPath() @@ -133,8 +163,8 @@ def paint(self, painter: QPainter, def _is_in_resize_area(self, pos:QPointF): """ Return True if the given position is in the block resize_area. """ - return self.width - self.edge_size*2 < pos.x() \ - and self.height - self.edge_size*2 < pos.y() + return self.width - self.edge_size < pos.x() \ + and self.height - self.edge_size < pos.y() def get_socket_pos(self, socket:OCBSocket) -> Tuple[float]: """ Get a socket position to place them on the block sides. """ @@ -175,51 +205,8 @@ def remove_socket(self, socket:OCBSocket): socket.remove() self.update_sockets() - def hoverMoveEvent(self, event:QGraphicsSceneHoverEvent): - """ Triggered when hovering over a block """ - pos = event.pos() - if self._is_in_resize_area(pos): - if not self.resizing_hover: - self._start_hovering() - elif self.resizing_hover: - self._stop_hovering() - return super().hoverMoveEvent(event) - - def _start_hovering(self): - self.resizing_hover = True - QApplication.setOverrideCursor(Qt.CursorShape.SizeFDiagCursor) - - def _stop_hovering(self): - self.resizing_hover = False - QApplication.restoreOverrideCursor() - - def _start_resize(self,pos:QPointF): - self.resizing = True - self.resize_start = pos - QApplication.setOverrideCursor(Qt.CursorShape.SizeFDiagCursor) - - def _stop_resize(self): - self.resizing = False - QApplication.setOverrideCursor(Qt.CursorShape.SizeFDiagCursor) - - def hoverLeaveEvent(self, event:QGraphicsSceneHoverEvent): - """ Triggered when the mouse stops hovering over a block """ - if self.resizing_hover: - self._stop_hovering() - return super().hoverLeaveEvent(event) - - def mousePressEvent(self, event:QGraphicsSceneMouseEvent): - """ OCBBlock reaction to a mousePressEvent. """ - pos = event.pos() - if self.resizing_hover and event.buttons() == Qt.MouseButton.LeftButton: - self._start_resize(pos) - 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._stop_resize() if self.moved: self.moved = False self.scene().history.checkpoint("Moved block", set_modified=True) @@ -227,31 +214,9 @@ def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent): 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) - self.height = max(self.height + delta.y(), self._min_height) - self.resize_start = event.pos() - self.title_graphics.setTextWidth(self.width - 2 * self.edge_size) - self.update() - else: - super().mouseMoveEvent(event) - 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. + super().mouseMoveEvent(event) + self.moved = True - """ - 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. """ @@ -264,8 +229,30 @@ def remove(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) + if hasattr(self, 'splitter'): + self.splitter.setGeometry( + int(self.edge_size), + int(self.edge_size + self.title_height), + int(self.width - self.edge_size*2), + int(self.height - self.edge_size*2 - self.title_height) + ) + self.title_widget.setGeometry( + int(self.edge_size), + int(0), + int(self.width - 2 * self.edge_size), + int(self.title_height) + ) + self.size_grip.setGeometry( + int(self.width - self.edge_size*2), + int(self.height - self.edge_size*2), + int(self.edge_size*1.7), + int(self.edge_size*1.7) + ) + # self.root.setGeometry( + # 0,0, + # int(self.width), + # int(self.height) + # ) @property def title(self): @@ -274,8 +261,8 @@ def title(self): @title.setter def title(self, value:str): self._title = value - if hasattr(self, 'title_graphics'): - self.title_graphics.setPlainText(self._title) + # if hasattr(self, 'title_graphics'): + # self.title_graphics.setPlainText(self._title) @property def width(self): @@ -314,6 +301,14 @@ def deserialize(self, data: dict, hashmap:dict=None, restore_id=True) -> None: self.id = data['id'] for dataname in ('title', 'block_type', 'source', 'width', 'height'): setattr(self, dataname, data[dataname]) + self.root.setGeometry( + 0,0, + int(self.width), + int(self.height) + ) + self.root.setMaximumWidth(int(self.width*2)); + self.root.setMaximumHeight(int(self.height*2)); + self.setPos(QPointF(*data['position'])) self.metadata = dict(data['metadata']) self.setTitleGraphics(**self.metadata['title_metadata']) diff --git a/opencodeblocks/graphics/blocks/codeblock.py b/opencodeblocks/graphics/blocks/codeblock.py index ef088285..83d2007f 100644 --- a/opencodeblocks/graphics/blocks/codeblock.py +++ b/opencodeblocks/graphics/blocks/codeblock.py @@ -7,7 +7,7 @@ from PyQt5.QtCore import Qt, QByteArray, QPointF from PyQt5.QtGui import QPainter, QPainterPath, QPixmap -from PyQt5.QtWidgets import QStyleOptionGraphicsItem, QWidget, QGraphicsProxyWidget, QLabel, \ +from PyQt5.QtWidgets import QStyleOptionGraphicsItem, QWidget, QLabel, \ QGraphicsSceneMouseEvent, QApplication from opencodeblocks.graphics.blocks.block import OCBBlock @@ -37,45 +37,13 @@ def __init__(self, **kwargs): self.stdout = "" self.image = "" - self.resizing_source_code = False - self.update_all() # Set the geometry of display and source_editor def init_source_editor(self): """ Initialize the python source code editor. """ - source_editor_graphics = QGraphicsProxyWidget(self) source_editor = PythonEditor(self) - source_editor_graphics.setWidget(source_editor) - source_editor_graphics.setZValue(-1) - return source_editor_graphics - - @property - def _editor_widget_height(self): - return self.height - self.title_height - 2*self.edge_size \ - - self.output_panel_height - - @_editor_widget_height.setter - def _editor_widget_height(self, value: int): - self.output_panel_height = self.height - value - self.title_height - 2*self.edge_size - - def update_all(self): - """ Update the code block parts. """ - if hasattr(self, 'source_editor'): - editor_widget = self.source_editor.widget() - editor_widget.setGeometry( - int(self.edge_size), - int(self.edge_size + self.title_height), - int(self._width - 2*self.edge_size), - int(self._editor_widget_height) - ) - display_widget = self.display.widget() - display_widget.setGeometry( - int(self.edge_size), - int(self.height - self.output_panel_height - self.edge_size), - int(self.width - 2*self.edge_size), - int(self.output_panel_height) - ) - super().update_all() + self.splitter.addWidget(source_editor) + return source_editor @property def source(self) -> str: @@ -86,8 +54,7 @@ def source(self) -> str: def source(self, value:str): self._source = value if hasattr(self, 'source_editor'): - editor_widget = self.source_editor.widget() - editor_widget.setText(self._source) + self.source_editor.setText(self._source) @property def stdout(self) -> str: @@ -99,8 +66,7 @@ def stdout(self, value:str): if hasattr(self, 'source_editor'): # If there is a text output, erase the image output and display the text output self.image = "" - editor_widget = self.display.widget() - editor_widget.setText(self._stdout) + self.display.setText(self._stdout) @property def image(self) -> str: @@ -112,7 +78,7 @@ def image(self, value:str): self._image = value if hasattr(self, 'source_editor') and self.image != "": # If there is an image output, erase the text output and display the image output - editor_widget = self.display.widget() + editor_widget = self.display editor_widget.setText("") qlabel = editor_widget ba = QByteArray.fromBase64(str.encode(self.image)) @@ -124,85 +90,12 @@ def image(self, value:str): def source(self, value:str): self._source = value if hasattr(self, 'source_editor'): - editor_widget = self.source_editor.widget() + editor_widget = self.source_editor editor_widget.setText(self._source) - def paint(self, painter: QPainter, - option: QStyleOptionGraphicsItem, #pylint:disable=unused-argument - widget: Optional[QWidget]=None): #pylint:disable=unused-argument - """ Paint the code output panel """ - super().paint(painter, option, widget) - path_title = QPainterPath() - path_title.setFillRule(Qt.FillRule.WindingFill) - path_title.addRoundedRect(0, 0, self.width, self.height, - self.edge_size, self.edge_size) - painter.setPen(Qt.PenStyle.NoPen) - painter.setBrush(self._brush_background) - painter.drawPath(path_title.simplified()) - - def _is_in_resize_source_code_area(self, pos:QPointF): - """ - Return True if the given position is in the area - used to resize the source code widget - """ - source_editor_start = self.height - self.output_panel_height - self.edge_size - - return self.width - self.edge_size/2 < pos.x() and \ - source_editor_start - self.edge_size < pos.y() < source_editor_start + self.edge_size - - - def _is_in_resize_area(self, pos:QPointF): - """ Return True if the given position is in the block resize_area. """ - - # This block features 2 resizing areas with 2 different behaviors - is_in_bottom_left = super()._is_in_resize_area(pos) - return is_in_bottom_left or self._is_in_resize_source_code_area(pos) - - def _start_resize(self,pos:QPointF): - self.resizing = True - self.resize_start = pos - if self._is_in_resize_source_code_area(pos): - self.resizing_source_code = True - QApplication.setOverrideCursor(Qt.CursorShape.SizeFDiagCursor) - - def _stop_resize(self): - self.resizing = False - self.resizing_source_code = False - QApplication.restoreOverrideCursor() - - def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent): - """ - We override the default resizing behavior as the code part and the display part of the block - block can be resized independently. - """ - if self.resizing: - delta = event.pos() - self.resize_start - self.width = max(self.width + delta.x(), self._min_width) - - height_delta = max(delta.y(), - # List of all the quantities that must remain negative. - # Mainly: min_height - height must be negative for all elements - self._min_output_panel_height - self.output_panel_height, - self._min_height - self.height, - self._min_source_editor_height - self._editor_widget_height - ) - - self.height += height_delta - if not self.resizing_source_code: - self.output_panel_height += height_delta - - self.resize_start = event.pos() - self.title_graphics.setTextWidth(self.width - 2 * self.edge_size) - self.update() - - self.moved = True - super().mouseMoveEvent(event) - def init_display(self): """ Initialize the output display widget: QLabel """ - display_graphics = QGraphicsProxyWidget(self) display = QLabel() display.setText("") - display_graphics.setWidget(display) - display_graphics.setZValue(-1) - return display_graphics + self.splitter.addWidget(display) + return display \ No newline at end of file diff --git a/opencodeblocks/graphics/pyeditor.py b/opencodeblocks/graphics/pyeditor.py index cddafa16..eb638e16 100644 --- a/opencodeblocks/graphics/pyeditor.py +++ b/opencodeblocks/graphics/pyeditor.py @@ -85,7 +85,7 @@ def update_theme(self): def views(self) -> List['OCBView']: """ Get the views in which the python_editor is present. """ - return self.graphicsProxyWidget().scene().views() + return self.parent().parent().graphicsProxyWidget().scene().views() def set_views_mode(self, mode:str): """ Set the views in which the python_editor is present to editing mode. """ diff --git a/opencodeblocks/graphics/scene/scene.py b/opencodeblocks/graphics/scene/scene.py index 6708e1ea..709bad21 100644 --- a/opencodeblocks/graphics/scene/scene.py +++ b/opencodeblocks/graphics/scene/scene.py @@ -38,6 +38,8 @@ def __init__(self, parent=None, self.grid_size = grid_size self.grid_squares = grid_squares + self.children = [] # List of widgets + self.width, self.height = width, height self.setSceneRect(-self.width//2, -self.height//2, self.width, self.height) self.setBackgroundBrush(self._background_color) From a28e03175e3f1330b89eca27d5d3f7c004263045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 17:16:28 +0100 Subject: [PATCH 02/13] :tada: Resizing now works properly ! (If you ignore the shaking) --- opencodeblocks/graphics/blocks/block.py | 75 +++++++++++++++---------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 6613575c..65f4332b 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -6,9 +6,9 @@ from typing import TYPE_CHECKING, Optional, OrderedDict, Tuple from PyQt5.QtCore import QPointF, QRectF, Qt -from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPainter, QPainterPath, QResizeEvent -from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, QGraphicsSceneMouseEvent, QGraphicsTextItem, QLabel, QSizeGrip, QSplitter, \ - QStyleOptionGraphicsItem, QWidget, QApplication, QGraphicsSceneHoverEvent +from PyQt5.QtGui import QBrush, QMouseEvent, QPen, QColor, QFont, QPainter, QPainterPath +from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, QGraphicsSceneMouseEvent, QLabel, QSizeGrip, QSplitter, \ + QStyleOptionGraphicsItem, QWidget from opencodeblocks.core.serializable import Serializable from opencodeblocks.graphics.socket import OCBSocket @@ -16,15 +16,35 @@ if TYPE_CHECKING: from opencodeblocks.graphics.scene.scene import OCBScene -class RootWidget(QWidget): - def __init__(self, parent: QWidget = None): +class RootSizeGrip(QSizeGrip): + def __init__(self, container: QGraphicsItem, parent: QWidget = None): super().__init__(parent) - def resizeEvent(self, evt: QResizeEvent): - # super().resizeEvent(evt) - print("r evt") - print(evt.size().width(),evt.size().height()) - print(evt.oldSize().width(),evt.oldSize().height()) + self.mouseX = 0 + self.mouseY = 0 + self.container = container + self.resizing = False + def mousePressEvent(self, mouseEvent: QMouseEvent): + self.mouseX = mouseEvent.x() + self.mouseY = mouseEvent.y() + self.resizing = True + def mouseReleaseEvent(self, mouseEvent: QMouseEvent): + self.resizing = False + def mouseMoveEvent(self, mouseEvent: QMouseEvent): + # Perform resizing of the root widget + rootWidget = self.parent() + deltaX = mouseEvent.x() - self.mouseX + deltaY = mouseEvent.y() - self.mouseY + rootWidget.setGeometry( + 0, + 0, + rootWidget.width() + deltaX, + rootWidget.height() + deltaY + ) + # Update the underlying OCBBlock + self.container.update_all() + self.mouseX = mouseEvent.x() + self.mouseY = mouseEvent.y() class OCBBlock(QGraphicsItem, Serializable): @@ -67,8 +87,6 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.height = height self.edge_size = edge_size - # self.title_graphics = QGraphicsTextItem(self) - # self.setTitleGraphics(title_color, title_font, title_size, title_padding) self.title_height = 3 * title_size self.title = title @@ -84,12 +102,12 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.setAcceptHoverEvents(True) self.holder = QGraphicsProxyWidget(self) - self.root = RootWidget() + self.root = QWidget() self.root.setAttribute(Qt.WA_TranslucentBackground) self.root.setGeometry( 0,0, - int(self.width), - int(self.height) + int(width), + int(height) ) @@ -100,7 +118,7 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.splitter = QSplitter(Qt.Vertical,self.root) - self.size_grip = QSizeGrip(self.root) + self.size_grip = RootSizeGrip(self,self.root) self.holder.setWidget(self.root) # self.holder.setZValue(-1) @@ -248,11 +266,6 @@ def update_all(self): int(self.edge_size*1.7), int(self.edge_size*1.7) ) - # self.root.setGeometry( - # 0,0, - # int(self.width), - # int(self.height) - # ) @property def title(self): @@ -261,26 +274,28 @@ def title(self): @title.setter def title(self, value:str): self._title = value - # if hasattr(self, 'title_graphics'): - # self.title_graphics.setPlainText(self._title) + if hasattr(self, 'title_widget'): + self.title_widget.setText(self._title) @property def width(self): """ Block width. """ - return self._width + return self.root.width() @width.setter def width(self, value:float): - self._width = value - self.update_all() + pass + # self._width = value + # self.update_all() @property def height(self): """ Block height. """ - return self._height + return self.root.height() @height.setter def height(self, value:float): - self._height = value - self.update_all() + pass + # self._height = value + # self.update_all() def serialize(self) -> OrderedDict: metadata = OrderedDict(sorted(self.metadata.items())) @@ -306,8 +321,6 @@ def deserialize(self, data: dict, hashmap:dict=None, restore_id=True) -> None: int(self.width), int(self.height) ) - self.root.setMaximumWidth(int(self.width*2)); - self.root.setMaximumHeight(int(self.height*2)); self.setPos(QPointF(*data['position'])) self.metadata = dict(data['metadata']) From 7b2289f211864b782d9acee79e8affdbc157c2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 17:37:28 +0100 Subject: [PATCH 03/13] :beetle: Fixes issues where the starting size of a block was incorrect. Fixes issues where a block was shaking when resizing --- opencodeblocks/graphics/blocks/block.py | 70 ++++++++++++++----------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 65f4332b..7a98aa5f 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -24,27 +24,43 @@ def __init__(self, container: QGraphicsItem, parent: QWidget = None): self.container = container self.resizing = False def mousePressEvent(self, mouseEvent: QMouseEvent): - self.mouseX = mouseEvent.x() - self.mouseY = mouseEvent.y() + self.mouseX = mouseEvent.globalX() + self.mouseY = mouseEvent.globalY() self.resizing = True def mouseReleaseEvent(self, mouseEvent: QMouseEvent): self.resizing = False def mouseMoveEvent(self, mouseEvent: QMouseEvent): - # Perform resizing of the root widget - rootWidget = self.parent() - deltaX = mouseEvent.x() - self.mouseX - deltaY = mouseEvent.y() - self.mouseY - rootWidget.setGeometry( + """ Performs resizing of the root widget """ + """ + Here, we use globalx and globaly instead of x() and y(). + This is because when using x() and y(), the mouse position is taken + relative to the grip, so if the grip moves, the deltaX and deltaY changes. + + This creates a shaking effect when resizing. We use global to not have this effect. + """ + deltaX = mouseEvent.globalX() - self.mouseX + deltaY = mouseEvent.globalY() - self.mouseY + + new_width = max( + self.container.width + deltaX, + self.container._min_width + ) + new_height = max( + self.container.height + deltaY, + self.container._min_height + ) + + self.parent().setGeometry( 0, 0, - rootWidget.width() + deltaX, - rootWidget.height() + deltaY + new_width, + new_height ) # Update the underlying OCBBlock self.container.update_all() - self.mouseX = mouseEvent.x() - self.mouseY = mouseEvent.y() + self.mouseX = mouseEvent.globalX() + self.mouseY = mouseEvent.globalY() class OCBBlock(QGraphicsItem, Serializable): @@ -80,13 +96,6 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.sockets_in = [] self.sockets_out = [] - self._min_width = 300 - self._min_height = 100 - - self.width = width - self.height = height - self.edge_size = edge_size - self.title_height = 3 * title_size self.title = title @@ -110,7 +119,6 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), int(height) ) - self.title_widget = QLabel(self.title,self.root) self.title_widget.setAttribute(Qt.WA_TransparentForMouseEvents) self.title_widget.setAttribute(Qt.WA_TranslucentBackground) @@ -123,8 +131,12 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.holder.setWidget(self.root) # self.holder.setZValue(-1) - self.resizing = False - self.resizing_hover = False # Is the mouse hovering over the resizing area ? + self.edge_size = edge_size + self._min_width = 300 + self._min_height = 100 + self.width = width + self.height = height + self.moved = False self.metadata = { 'title_metadata': { @@ -266,6 +278,7 @@ def update_all(self): int(self.edge_size*1.7), int(self.edge_size*1.7) ) + print("Updated with: ",self.width) @property def title(self): @@ -283,9 +296,8 @@ def width(self): return self.root.width() @width.setter def width(self, value:float): - pass - # self._width = value - # self.update_all() + self.root.setGeometry(0,0,int(value),self.root.height()) + self.update_all() @property def height(self): @@ -293,9 +305,8 @@ def height(self): return self.root.height() @height.setter def height(self, value:float): - pass - # self._height = value - # self.update_all() + self.root.setGeometry(0,0,self.root.width(),int(value)) + self.update_all() def serialize(self) -> OrderedDict: metadata = OrderedDict(sorted(self.metadata.items())) @@ -316,11 +327,6 @@ def deserialize(self, data: dict, hashmap:dict=None, restore_id=True) -> None: self.id = data['id'] for dataname in ('title', 'block_type', 'source', 'width', 'height'): setattr(self, dataname, data[dataname]) - self.root.setGeometry( - 0,0, - int(self.width), - int(self.height) - ) self.setPos(QPointF(*data['position'])) self.metadata = dict(data['metadata']) From d9b63ff8b0c24972f75f0ff0240b564373f6033d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 17:55:19 +0100 Subject: [PATCH 04/13] :sparkles: Pylint back to starting value ! --- opencodeblocks/graphics/blocks/block.py | 143 +++++++----------- .../graphics/blocks/blocksizegrip.py | 60 ++++++++ opencodeblocks/graphics/blocks/codeblock.py | 29 ++-- opencodeblocks/graphics/theme_manager.py | 6 +- 4 files changed, 133 insertions(+), 105 deletions(-) create mode 100644 opencodeblocks/graphics/blocks/blocksizegrip.py diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 7a98aa5f..67494610 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -6,70 +6,26 @@ from typing import TYPE_CHECKING, Optional, OrderedDict, Tuple from PyQt5.QtCore import QPointF, QRectF, Qt -from PyQt5.QtGui import QBrush, QMouseEvent, QPen, QColor, QFont, QPainter, QPainterPath -from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, QGraphicsSceneMouseEvent, QLabel, QSizeGrip, QSplitter, \ +from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPainter, QPainterPath +from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, QGraphicsSceneMouseEvent, QLabel, QSplitter, \ QStyleOptionGraphicsItem, QWidget from opencodeblocks.core.serializable import Serializable from opencodeblocks.graphics.socket import OCBSocket +from opencodeblocks.graphics.blocks.blocksizegrip import BlockSizeGrip if TYPE_CHECKING: from opencodeblocks.graphics.scene.scene import OCBScene -class RootSizeGrip(QSizeGrip): - def __init__(self, container: QGraphicsItem, parent: QWidget = None): - super().__init__(parent) - self.mouseX = 0 - self.mouseY = 0 - self.container = container - self.resizing = False - def mousePressEvent(self, mouseEvent: QMouseEvent): - self.mouseX = mouseEvent.globalX() - self.mouseY = mouseEvent.globalY() - self.resizing = True - def mouseReleaseEvent(self, mouseEvent: QMouseEvent): - self.resizing = False - def mouseMoveEvent(self, mouseEvent: QMouseEvent): - """ Performs resizing of the root widget """ - """ - Here, we use globalx and globaly instead of x() and y(). - This is because when using x() and y(), the mouse position is taken - relative to the grip, so if the grip moves, the deltaX and deltaY changes. - - This creates a shaking effect when resizing. We use global to not have this effect. - """ - deltaX = mouseEvent.globalX() - self.mouseX - deltaY = mouseEvent.globalY() - self.mouseY - - new_width = max( - self.container.width + deltaX, - self.container._min_width - ) - new_height = max( - self.container.height + deltaY, - self.container._min_height - ) - - self.parent().setGeometry( - 0, - 0, - new_width, - new_height - ) - # Update the underlying OCBBlock - self.container.update_all() - - self.mouseX = mouseEvent.globalX() - self.mouseY = mouseEvent.globalY() class OCBBlock(QGraphicsItem, Serializable): """ 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): + 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: @@ -114,22 +70,25 @@ def __init__(self, block_type:str='base', source:str='', position:tuple=(0, 0), self.root = QWidget() self.root.setAttribute(Qt.WA_TranslucentBackground) self.root.setGeometry( - 0,0, + 0, 0, int(width), int(height) ) - self.title_widget = QLabel(self.title,self.root) + self.title_widget = QLabel(self.title, self.root) self.title_widget.setAttribute(Qt.WA_TransparentForMouseEvents) self.title_widget.setAttribute(Qt.WA_TranslucentBackground) - self.setTitleGraphics(title_color,title_font,title_size,title_padding) + self.setTitleGraphics( + title_color, + title_font, + title_size, + title_padding) - self.splitter = QSplitter(Qt.Vertical,self.root) + self.splitter = QSplitter(Qt.Vertical, self.root) - self.size_grip = RootSizeGrip(self,self.root) + self.size_grip = BlockSizeGrip(self, self.root) self.holder.setWidget(self.root) - # self.holder.setZValue(-1) self.edge_size = edge_size self._min_width = 300 @@ -155,7 +114,8 @@ def boundingRect(self) -> QRectF: """ Get the the block bounding box. """ return QRectF(0, 0, self.width, self.height).normalized() - def setTitleGraphics(self, color:str, font:str, size:int, padding:float): + def setTitleGraphics(self, color: str, font: str, + size: int, padding: float): """ Set the title graphics. Args: @@ -166,19 +126,19 @@ def setTitleGraphics(self, color:str, font:str, size:int, padding:float): """ self.title_widget.setMargin(int(padding)) - self.title_widget.setStyleSheet("QLabel { color : %s; }" % color); + self.title_widget.setStyleSheet("QLabel { color : %s; }" % color) self.title_widget.setFont(QFont(font, size)) def paint(self, painter: QPainter, - option: QStyleOptionGraphicsItem, #pylint:disable=unused-argument - widget: Optional[QWidget]=None): #pylint:disable=unused-argument + option: QStyleOptionGraphicsItem, # pylint:disable=unused-argument + widget: Optional[QWidget] = None): # pylint:disable=unused-argument """ Paint the block. """ - + # content path_content = QPainterPath() path_content.setFillRule(Qt.FillRule.WindingFill) path_content.addRoundedRect(0, 0, self.width, self.height, - self.edge_size, self.edge_size) + self.edge_size, self.edge_size) painter.setPen(Qt.PenStyle.NoPen) painter.setBrush(self._brush_background) painter.drawPath(path_content.simplified()) @@ -186,17 +146,18 @@ def paint(self, painter: QPainter, # outline path_outline = QPainterPath() path_outline.addRoundedRect(0, 0, self.width, self.height, - self.edge_size, self.edge_size) - painter.setPen(self._pen_outline_selected if self.isSelected() else self._pen_outline) + self.edge_size, self.edge_size) + painter.setPen( + self._pen_outline_selected if self.isSelected() else self._pen_outline) painter.setBrush(Qt.BrushStyle.NoBrush) painter.drawPath(path_outline.simplified()) - def _is_in_resize_area(self, pos:QPointF): + def _is_in_resize_area(self, pos: QPointF): """ Return True if the given position is in the block resize_area. """ return self.width - self.edge_size < pos.x() \ - and self.height - self.edge_size < pos.y() + and self.height - self.edge_size < pos.y() - def get_socket_pos(self, socket:OCBSocket) -> Tuple[float]: + 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 @@ -210,7 +171,8 @@ def get_socket_pos(self, socket:OCBSocket) -> Tuple[float]: y = y_offset else: side_lenght = self.height - y_offset - 2 * socket.radius - self.edge_size - y = y_offset + side_lenght * sockets.index(socket) / (len(sockets) - 1) + y = y_offset + side_lenght * \ + sockets.index(socket) / (len(sockets) - 1) return x, y def update_sockets(self): @@ -218,7 +180,7 @@ def update_sockets(self): for socket in self.sockets_in + self.sockets_out: socket.setPos(*self.get_socket_pos(socket)) - def add_socket(self, socket:OCBSocket): + def add_socket(self, socket: OCBSocket): """ Add a socket to the block. """ if socket.socket_type == 'input': self.sockets_in.append(socket) @@ -226,7 +188,7 @@ def add_socket(self, socket:OCBSocket): self.sockets_out.append(socket) self.update_sockets() - def remove_socket(self, socket:OCBSocket): + def remove_socket(self, socket: OCBSocket): """ Remove a socket from the block. """ if socket.socket_type == 'input': self.sockets_in.remove(socket) @@ -235,19 +197,18 @@ def remove_socket(self, socket:OCBSocket): socket.remove() self.update_sockets() - def mouseReleaseEvent(self, event:QGraphicsSceneMouseEvent): + def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent): """ OCBBlock reaction to a mouseReleaseEvent. """ if self.moved: self.moved = False self.scene().history.checkpoint("Moved block", set_modified=True) super().mouseReleaseEvent(event) - def mouseMoveEvent(self, event:QGraphicsSceneMouseEvent): + def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent): """ OCBBlock reaction to a mouseMoveEvent. """ super().mouseMoveEvent(event) self.moved = True - def remove(self): """ Remove the block from the scene containing it. """ scene = self.scene() @@ -259,12 +220,12 @@ def remove(self): def update_all(self): """ Update sockets and title. """ self.update_sockets() - if hasattr(self, 'splitter'): + if hasattr(self, 'title_widget'): self.splitter.setGeometry( int(self.edge_size), int(self.edge_size + self.title_height), - int(self.width - self.edge_size*2), - int(self.height - self.edge_size*2 - self.title_height) + int(self.width - self.edge_size * 2), + int(self.height - self.edge_size * 2 - self.title_height) ) self.title_widget.setGeometry( int(self.edge_size), @@ -273,19 +234,19 @@ def update_all(self): int(self.title_height) ) self.size_grip.setGeometry( - int(self.width - self.edge_size*2), - int(self.height - self.edge_size*2), - int(self.edge_size*1.7), - int(self.edge_size*1.7) + int(self.width - self.edge_size * 2), + int(self.height - self.edge_size * 2), + int(self.edge_size * 1.7), + int(self.edge_size * 1.7) ) - print("Updated with: ",self.width) @property def title(self): """ Block title. """ return self._title + @title.setter - def title(self, value:str): + def title(self, value: str): self._title = value if hasattr(self, 'title_widget'): self.title_widget.setText(self._title) @@ -294,18 +255,20 @@ def title(self, value:str): def width(self): """ Block width. """ return self.root.width() + @width.setter - def width(self, value:float): - self.root.setGeometry(0,0,int(value),self.root.height()) + def width(self, value: float): + self.root.setGeometry(0, 0, int(value), self.root.height()) self.update_all() @property def height(self): """ Block height. """ return self.root.height() + @height.setter - def height(self, value:float): - self.root.setGeometry(0,0,self.root.width(),int(value)) + def height(self, value: float): + self.root.setGeometry(0, 0, self.root.width(), int(value)) self.update_all() def serialize(self) -> OrderedDict: @@ -319,10 +282,12 @@ def serialize(self) -> OrderedDict: ('width', self.width), ('height', self.height), ('metadata', metadata), - ('sockets', [socket.serialize() for socket in self.sockets_in + self.sockets_out]), + ('sockets', [socket.serialize() + for socket in self.sockets_in + self.sockets_out]), ]) - def deserialize(self, data: dict, hashmap:dict=None, restore_id=True) -> None: + def deserialize(self, data: dict, hashmap: dict = None, + restore_id=True) -> None: if restore_id: self.id = data['id'] for dataname in ('title', 'block_type', 'source', 'width', 'height'): diff --git a/opencodeblocks/graphics/blocks/blocksizegrip.py b/opencodeblocks/graphics/blocks/blocksizegrip.py new file mode 100644 index 00000000..635c04cb --- /dev/null +++ b/opencodeblocks/graphics/blocks/blocksizegrip.py @@ -0,0 +1,60 @@ + +""" +Implements the SizeGrip Widget for the Blocks. + +The size grip is the little icon at the bottom right of a block that is used to +resize a block. +""" + +from PyQt5.QtWidgets import QGraphicsItem, QSizeGrip, QWidget +from PyQt5.QtGui import QMouseEvent + + +class BlockSizeGrip(QSizeGrip): + def __init__(self, container: QGraphicsItem, parent: QWidget = None): + """ + Constructor for BlockSizeGrip + + container is the QGraphicsItem holding the QSizeGrip. + We should have: parent.graphicsProxyWidget().parent() == container + """ + super().__init__(parent) + self.mouseX = 0 + self.mouseY = 0 + self.container = container + self.resizing = False + + def mousePressEvent(self, mouseEvent: QMouseEvent): + """ Start the resizing """ + self.mouseX = mouseEvent.globalX() + self.mouseY = mouseEvent.globalY() + self.resizing = True + + def mouseReleaseEvent(self, mouseEvent: QMouseEvent): + """ Stop the resizing """ + self.resizing = False + + def mouseMoveEvent(self, mouseEvent: QMouseEvent): + """ Performs resizing of the root widget """ + + deltaX = mouseEvent.globalX() - self.mouseX + deltaY = mouseEvent.globalY() - self.mouseY + # Here, we use globalx and globaly instead of x() and y(). + # This is because when using x() and y(), the mouse position is taken + # relative to the grip, so if the grip moves, the deltaX and deltaY changes. + # This creates a shaking effect when resizing. We use global to not + # have this effect. + new_width = max( + self.container.width + deltaX, + self.container._min_width + ) + new_height = max( + self.container.height + deltaY, + self.container._min_height + ) + + self.parent().setGeometry(0, 0, new_width, new_height) + self.container.update_all() + + self.mouseX = mouseEvent.globalX() + self.mouseY = mouseEvent.globalY() diff --git a/opencodeblocks/graphics/blocks/codeblock.py b/opencodeblocks/graphics/blocks/codeblock.py index 83d2007f..6756d794 100644 --- a/opencodeblocks/graphics/blocks/codeblock.py +++ b/opencodeblocks/graphics/blocks/codeblock.py @@ -3,16 +3,14 @@ """ Module for the base OCB Code Block. """ -from typing import Optional - -from PyQt5.QtCore import Qt, QByteArray, QPointF -from PyQt5.QtGui import QPainter, QPainterPath, QPixmap -from PyQt5.QtWidgets import QStyleOptionGraphicsItem, QWidget, QLabel, \ - QGraphicsSceneMouseEvent, QApplication +from PyQt5.QtCore import QByteArray +from PyQt5.QtGui import QPixmap +from PyQt5.QtWidgets import QLabel from opencodeblocks.graphics.blocks.block import OCBBlock from opencodeblocks.graphics.pyeditor import PythonEditor + class OCBCodeBlock(OCBBlock): """ @@ -37,7 +35,7 @@ def __init__(self, **kwargs): self.stdout = "" self.image = "" - self.update_all() # Set the geometry of display and source_editor + self.update_all() # Set the geometry of display and source_editor def init_source_editor(self): """ Initialize the python source code editor. """ @@ -51,7 +49,7 @@ def source(self) -> str: return self._source @source.setter - def source(self, value:str): + def source(self, value: str): self._source = value if hasattr(self, 'source_editor'): self.source_editor.setText(self._source) @@ -60,11 +58,13 @@ def source(self, value:str): def stdout(self) -> str: """ Code output. Be careful, this also includes stderr """ return self._stdout + @stdout.setter - def stdout(self, value:str): + def stdout(self, value: str): self._stdout = value if hasattr(self, 'source_editor'): - # If there is a text output, erase the image output and display the text output + # If there is a text output, erase the image output and display the + # text output self.image = "" self.display.setText(self._stdout) @@ -74,10 +74,11 @@ def image(self) -> str: return self._image @image.setter - def image(self, value:str): + def image(self, value: str): self._image = value if hasattr(self, 'source_editor') and self.image != "": - # If there is an image output, erase the text output and display the image output + # If there is an image output, erase the text output and display + # the image output editor_widget = self.display editor_widget.setText("") qlabel = editor_widget @@ -87,7 +88,7 @@ def image(self, value:str): qlabel.setPixmap(pixmap) @source.setter - def source(self, value:str): + def source(self, value: str): self._source = value if hasattr(self, 'source_editor'): editor_widget = self.source_editor @@ -98,4 +99,4 @@ def init_display(self): display = QLabel() display.setText("") self.splitter.addWidget(display) - return display \ No newline at end of file + return display diff --git a/opencodeblocks/graphics/theme_manager.py b/opencodeblocks/graphics/theme_manager.py index f366f52d..0f084dea 100644 --- a/opencodeblocks/graphics/theme_manager.py +++ b/opencodeblocks/graphics/theme_manager.py @@ -12,12 +12,13 @@ from opencodeblocks.graphics.theme import Theme + class ThemeManager(QObject): """ Class loading theme files and providing the options set in those files """ themeChanged = pyqtSignal() - def __init__(self, parent = None): + def __init__(self, parent=None): """ Load the default themes and the fonts available to construct the ThemeManager """ super().__init__(parent) self._preferred_fonts = ["Inconsolata", "Roboto Mono", "Courier"] @@ -28,7 +29,7 @@ def __init__(self, parent = None): if font in available_fonts: self.recommended_font_family = font break - + self._themes = [] self._selected_theme_index = 0 theme_path = "./themes" @@ -40,6 +41,7 @@ def __init__(self, parent = None): with open(full_path, 'r', encoding="utf-8") as f: theme = Theme(name, f.read()) self._themes.append(theme) + @property def selected_theme_index(self): return self._selected_theme_index From d934629a31f062afcca809af77e37f329fec8d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 18:44:01 +0100 Subject: [PATCH 05/13] Update opencodeblocks/graphics/blocks/block.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mathïs Fédérico <60117466+MathisFederico@users.noreply.github.com> --- opencodeblocks/graphics/blocks/block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 67494610..6b064dfb 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -126,7 +126,7 @@ def setTitleGraphics(self, color: str, font: str, """ self.title_widget.setMargin(int(padding)) - self.title_widget.setStyleSheet("QLabel { color : %s; }" % color) + self.title_widget.setStyleSheet(f"QLabel \{ color : {color}\}") self.title_widget.setFont(QFont(font, size)) def paint(self, painter: QPainter, From 2d35453b83e43a80f4012043726ac351bae9d258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 19:24:58 +0100 Subject: [PATCH 06/13] :beetle: Fixes the interaction between the 2 resizing handles. --- opencodeblocks/graphics/blocks/block.py | 12 ++++++++- .../graphics/blocks/blocksizegrip.py | 27 +++++++++++-------- opencodeblocks/graphics/pyeditor.py | 2 +- opencodeblocks/graphics/scene/scene.py | 2 -- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 67494610..6c8675b5 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -7,7 +7,8 @@ from PyQt5.QtCore import QPointF, QRectF, Qt from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPainter, QPainterPath -from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, QGraphicsSceneMouseEvent, QLabel, QSplitter, \ +from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, \ + QGraphicsSceneMouseEvent, QLabel, QSplitter, \ QStyleOptionGraphicsItem, QWidget from opencodeblocks.core.serializable import Serializable @@ -221,12 +222,21 @@ def update_all(self): """ Update sockets and title. """ self.update_sockets() if hasattr(self, 'title_widget'): + # We make the resizing of splitter only affect + # the last element of the split view + sizes = self.splitter.sizes() + old_height = self.splitter.height() self.splitter.setGeometry( int(self.edge_size), int(self.edge_size + self.title_height), int(self.width - self.edge_size * 2), int(self.height - self.edge_size * 2 - self.title_height) ) + if len(sizes) > 1: + height_delta = self.splitter.height() - old_height + sizes[-1] += height_delta + self.splitter.setSizes(sizes) + self.title_widget.setGeometry( int(self.edge_size), int(0), diff --git a/opencodeblocks/graphics/blocks/blocksizegrip.py b/opencodeblocks/graphics/blocks/blocksizegrip.py index 635c04cb..2994a118 100644 --- a/opencodeblocks/graphics/blocks/blocksizegrip.py +++ b/opencodeblocks/graphics/blocks/blocksizegrip.py @@ -6,22 +6,23 @@ resize a block. """ +from PyQt5.QtCore import QPoint from PyQt5.QtWidgets import QGraphicsItem, QSizeGrip, QWidget from PyQt5.QtGui import QMouseEvent class BlockSizeGrip(QSizeGrip): - def __init__(self, container: QGraphicsItem, parent: QWidget = None): + def __init__(self, block: QGraphicsItem, parent: QWidget = None): """ Constructor for BlockSizeGrip - container is the QGraphicsItem holding the QSizeGrip. - We should have: parent.graphicsProxyWidget().parent() == container + block is the QGraphicsItem holding the QSizeGrip. + It's usually an OCBBlock """ super().__init__(parent) self.mouseX = 0 self.mouseY = 0 - self.container = container + self.block = block self.resizing = False def mousePressEvent(self, mouseEvent: QMouseEvent): @@ -36,25 +37,29 @@ def mouseReleaseEvent(self, mouseEvent: QMouseEvent): def mouseMoveEvent(self, mouseEvent: QMouseEvent): """ Performs resizing of the root widget """ + transformed_pt1 = self.block.mapFromScene(QPoint(0,0)) + transformed_pt2 = self.block.mapFromScene(QPoint(1,1)) - deltaX = mouseEvent.globalX() - self.mouseX - deltaY = mouseEvent.globalY() - self.mouseY + pt = transformed_pt2 - transformed_pt1 + + delta_x = (mouseEvent.globalX() - self.mouseX) * pt.x() + delta_y = (mouseEvent.globalY() - self.mouseY) * pt.y() # Here, we use globalx and globaly instead of x() and y(). # This is because when using x() and y(), the mouse position is taken # relative to the grip, so if the grip moves, the deltaX and deltaY changes. # This creates a shaking effect when resizing. We use global to not # have this effect. new_width = max( - self.container.width + deltaX, - self.container._min_width + self.block.width + int(delta_x), + self.block._min_width ) new_height = max( - self.container.height + deltaY, - self.container._min_height + self.block.height + int(delta_y), + self.block._min_height ) self.parent().setGeometry(0, 0, new_width, new_height) - self.container.update_all() + self.block.update_all() self.mouseX = mouseEvent.globalX() self.mouseY = mouseEvent.globalY() diff --git a/opencodeblocks/graphics/pyeditor.py b/opencodeblocks/graphics/pyeditor.py index eb638e16..39fbd723 100644 --- a/opencodeblocks/graphics/pyeditor.py +++ b/opencodeblocks/graphics/pyeditor.py @@ -85,7 +85,7 @@ def update_theme(self): def views(self) -> List['OCBView']: """ Get the views in which the python_editor is present. """ - return self.parent().parent().graphicsProxyWidget().scene().views() + return self.block.scene().views() def set_views_mode(self, mode:str): """ Set the views in which the python_editor is present to editing mode. """ diff --git a/opencodeblocks/graphics/scene/scene.py b/opencodeblocks/graphics/scene/scene.py index 709bad21..6708e1ea 100644 --- a/opencodeblocks/graphics/scene/scene.py +++ b/opencodeblocks/graphics/scene/scene.py @@ -38,8 +38,6 @@ def __init__(self, parent=None, self.grid_size = grid_size self.grid_squares = grid_squares - self.children = [] # List of widgets - self.width, self.height = width, height self.setSceneRect(-self.width//2, -self.height//2, self.width, self.height) self.setBackgroundBrush(self._background_color) From 191f15afe5478aed6441ade765091ca5ef497791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 19:34:04 +0100 Subject: [PATCH 07/13] :beetle: Fixes the alignement issue between mouse and block when resizing --- opencodeblocks/graphics/blocks/block.py | 2 +- opencodeblocks/graphics/blocks/blocksizegrip.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 9acb8606..6cfc5e96 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -127,7 +127,7 @@ def setTitleGraphics(self, color: str, font: str, """ self.title_widget.setMargin(int(padding)) - self.title_widget.setStyleSheet(f"QLabel \{ color : {color}\}") + self.title_widget.setStyleSheet(f"QLabel {{ color : {color} }}") self.title_widget.setFont(QFont(font, size)) def paint(self, painter: QPainter, diff --git a/opencodeblocks/graphics/blocks/blocksizegrip.py b/opencodeblocks/graphics/blocks/blocksizegrip.py index 2994a118..2f519f63 100644 --- a/opencodeblocks/graphics/blocks/blocksizegrip.py +++ b/opencodeblocks/graphics/blocks/blocksizegrip.py @@ -41,6 +41,7 @@ def mouseMoveEvent(self, mouseEvent: QMouseEvent): transformed_pt2 = self.block.mapFromScene(QPoint(1,1)) pt = transformed_pt2 - transformed_pt1 + pt /= self.block.scene().views()[0].zoom delta_x = (mouseEvent.globalX() - self.mouseX) * pt.x() delta_y = (mouseEvent.globalY() - self.mouseY) * pt.y() From e8ed726c12a6f2e548f96e78aafb1c49180764eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 21:40:12 +0100 Subject: [PATCH 08/13] :tada: Made Run Button work with the new widget system ! Removed a windows specific warning with asyncio. --- main.py | 6 ++++-- opencodeblocks/graphics/blocks/block.py | 8 ++++++-- opencodeblocks/graphics/blocks/blocksizegrip.py | 1 + opencodeblocks/graphics/blocks/codeblock.py | 7 +++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 4915304b..d7ee6c7a 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,10 @@ # OpenCodeBlock an open-source tool for modular visual programing in python # Copyright (C) 2021 Mathïs FEDERICO -import os -import sys +import os,sys,asyncio + +if os.name == "nt": # If on windows + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) from qtpy.QtWidgets import QApplication from opencodeblocks.graphics.window import OCBWindow diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 6cfc5e96..3fed6a37 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -83,13 +83,17 @@ def __init__(self, block_type: str = 'base', source: str = '', position: tuple = title_color, title_font, title_size, - title_padding) + title_padding + ) self.splitter = QSplitter(Qt.Vertical, self.root) self.size_grip = BlockSizeGrip(self, self.root) - self.holder.setWidget(self.root) + if type(self) == OCBBlock: + # This has to be done at the end of the constructor of + # every class inheriting this. + self.holder.setWidget(self.root) self.edge_size = edge_size self._min_width = 300 diff --git a/opencodeblocks/graphics/blocks/blocksizegrip.py b/opencodeblocks/graphics/blocks/blocksizegrip.py index 2f519f63..06c5d077 100644 --- a/opencodeblocks/graphics/blocks/blocksizegrip.py +++ b/opencodeblocks/graphics/blocks/blocksizegrip.py @@ -12,6 +12,7 @@ class BlockSizeGrip(QSizeGrip): + """ A grip to resize a block """ def __init__(self, block: QGraphicsItem, parent: QWidget = None): """ Constructor for BlockSizeGrip diff --git a/opencodeblocks/graphics/blocks/codeblock.py b/opencodeblocks/graphics/blocks/codeblock.py index 157a9a7c..218bad81 100644 --- a/opencodeblocks/graphics/blocks/codeblock.py +++ b/opencodeblocks/graphics/blocks/codeblock.py @@ -42,6 +42,8 @@ def __init__(self, **kwargs): self.stdout = "" self.image = "" + self.holder.setWidget(self.root) + self.update_all() # Set the geometry of display and source_editor def init_source_editor(self): @@ -143,13 +145,14 @@ def init_run_button(self): run_button = QPushButton(">",self.root) run_button.setMinimumWidth(int(self.edge_size)) run_button.clicked.connect(self.run_code) + run_button.raise_() return run_button def run_code(self): """Run the code in the block""" - code = self.source_editor.widget().text() - kernel = self.source_editor.widget().kernel + code = self.source_editor.text() + kernel = self.source_editor.kernel self.source = code # Execute the code kernel.client.execute(code) From 458e912949cb001a9c0720cda6ac6ef9f8bf3a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 22:04:31 +0100 Subject: [PATCH 09/13] :wrench: Refactors, removed dead code --- opencodeblocks/graphics/blocks/codeblock.py | 32 ++++++--------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/opencodeblocks/graphics/blocks/codeblock.py b/opencodeblocks/graphics/blocks/codeblock.py index 218bad81..67ac1827 100644 --- a/opencodeblocks/graphics/blocks/codeblock.py +++ b/opencodeblocks/graphics/blocks/codeblock.py @@ -37,7 +37,7 @@ def __init__(self, **kwargs): self._min_source_editor_height = 20 self.source_editor = self.init_source_editor() - self.display = self.init_display() + self.output_panel = self.init_output_panel() self.run_button = self.init_run_button() self.stdout = "" self.image = "" @@ -52,17 +52,6 @@ def init_source_editor(self): self.splitter.addWidget(source_editor) return source_editor - - @property - def _editor_widget_height(self): - return self.height - self.title_height - 2*self.edge_size \ - - self.output_panel_height - - @_editor_widget_height.setter - def _editor_widget_height(self, value: int): - self.output_panel_height = self.height - \ - value - self.title_height - 2*self.edge_size - def update_all(self): """ Update the code block parts. """ super().update_all() @@ -98,12 +87,11 @@ def stdout(self, value: str): # text output self.image = "" - editor_widget = self.display # Remove ANSI color codes text = ansi_escape.sub('', value) # Remove backspaces (tf loading bars) text = text.replace('\x08', '') - editor_widget.setText(text) + self.output_panel.setText(text) @property def image(self) -> str: @@ -116,13 +104,11 @@ def image(self, value: str): if hasattr(self, 'source_editor') and self.image != "": # If there is an image output, erase the text output and display # the image output - editor_widget = self.display - editor_widget.setText("") - qlabel = editor_widget + self.output_panel.setText("") ba = QByteArray.fromBase64(str.encode(self.image)) pixmap = QPixmap() pixmap.loadFromData(ba) - qlabel.setPixmap(pixmap) + self.output_panel.setPixmap(pixmap) @source.setter def source(self, value: str): @@ -132,13 +118,13 @@ def source(self, value: str): editor_widget.setText(self._source) - def init_display(self): + def init_output_panel(self): """ Initialize the output display widget: QLabel """ - display = QLabel() - display.setText("") + output_panel = QLabel() + output_panel.setText("") - self.splitter.addWidget(display) - return display + self.splitter.addWidget(output_panel) + return output_panel def init_run_button(self): """ Initialize the run button """ From 9d70f3004f379454f531a51b5e7186dcc76cd60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Thu, 18 Nov 2021 22:08:21 +0100 Subject: [PATCH 10/13] :wrench: Moves the zoom thing into it's own function --- opencodeblocks/graphics/blocks/blocksizegrip.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/blocks/blocksizegrip.py b/opencodeblocks/graphics/blocks/blocksizegrip.py index 06c5d077..b6072d9b 100644 --- a/opencodeblocks/graphics/blocks/blocksizegrip.py +++ b/opencodeblocks/graphics/blocks/blocksizegrip.py @@ -36,13 +36,18 @@ def mouseReleaseEvent(self, mouseEvent: QMouseEvent): """ Stop the resizing """ self.resizing = False + @property + def _zoom(self) -> float: + """ Returns how much the scene is """ + return self.block.scene().views()[0].zoom + def mouseMoveEvent(self, mouseEvent: QMouseEvent): """ Performs resizing of the root widget """ transformed_pt1 = self.block.mapFromScene(QPoint(0,0)) transformed_pt2 = self.block.mapFromScene(QPoint(1,1)) pt = transformed_pt2 - transformed_pt1 - pt /= self.block.scene().views()[0].zoom + pt /= self._zoom delta_x = (mouseEvent.globalX() - self.mouseX) * pt.x() delta_y = (mouseEvent.globalY() - self.mouseY) * pt.y() From 14291801c67802c4e50af68d788f8a72a4d5ed34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Fri, 19 Nov 2021 00:04:15 +0100 Subject: [PATCH 11/13] :tada: History related changes - Moves the position of the "Run" button to title bar. - Saves the position of the splitter to a file - Resize events can now be undone - Increases the size of the undo stack to 50 Note that a test is changed because you cannot drag a block from the button. --- opencodeblocks/graphics/blocks/block.py | 48 +++++++++++++++---- .../graphics/blocks/blocksizegrip.py | 10 ++-- opencodeblocks/graphics/blocks/codeblock.py | 10 ++-- opencodeblocks/graphics/scene/history.py | 2 +- tests/integration/test_blocks.py | 4 +- 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 3fed6a37..bb4244bd 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -5,10 +5,10 @@ from typing import TYPE_CHECKING, Optional, OrderedDict, Tuple -from PyQt5.QtCore import QPointF, QRectF, Qt -from PyQt5.QtGui import QBrush, QPen, QColor, QFont, QPainter, QPainterPath +from PyQt5.QtCore import QEvent, QPointF, QRectF, Qt +from PyQt5.QtGui import QBrush, QMouseEvent, QPen, QColor, QFont, QPainter, QPainterPath, QResizeEvent from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, \ - QGraphicsSceneMouseEvent, QLabel, QSplitter, \ + QGraphicsSceneMouseEvent, QLabel, QSplitter, QSplitterHandle, \ QStyleOptionGraphicsItem, QWidget from opencodeblocks.core.serializable import Serializable @@ -55,6 +55,7 @@ def __init__(self, block_type: str = 'base', source: str = '', position: tuple = self.title_height = 3 * title_size self.title = title + self.title_left_offset = 0 self._pen_outline = QPen(QColor("#7F000000")) self._pen_outline_selected = QPen(QColor("#FFFFA637")) @@ -86,18 +87,18 @@ def __init__(self, block_type: str = 'base', source: str = '', position: tuple = title_padding ) - self.splitter = QSplitter(Qt.Vertical, self.root) + self.splitter = OCBSplitter(self, Qt.Vertical, self.root) self.size_grip = BlockSizeGrip(self, self.root) - if type(self) == OCBBlock: - # This has to be done at the end of the constructor of + if isinstance(self, OCBBlock): + # This has to be called at the end of the constructor of # every class inheriting this. self.holder.setWidget(self.root) self.edge_size = edge_size - self._min_width = 300 - self._min_height = 100 + self.min_width = 300 + self.min_height = 100 self.width = width self.height = height @@ -242,8 +243,8 @@ def update_all(self): self.splitter.setSizes(sizes) self.title_widget.setGeometry( - int(self.edge_size), - int(0), + int(self.edge_size + self.title_left_offset), + int(self.edge_size / 2), int(self.width - 2 * self.edge_size), int(self.title_height) ) @@ -292,6 +293,7 @@ def serialize(self) -> OrderedDict: ('title', self.title), ('block_type', self.block_type), ('source', self.source), + ('splitter_pos', self.splitter.sizes()), ('position', [self.pos().x(), self.pos().y()]), ('width', self.width), ('height', self.height), @@ -311,8 +313,34 @@ def deserialize(self, data: dict, hashmap: dict = None, self.metadata = dict(data['metadata']) self.setTitleGraphics(**self.metadata['title_metadata']) + if 'splitter_pos' in data: + self.splitter.setSizes(data['splitter_pos']) + for socket_data in data['sockets']: socket = OCBSocket(block=self) socket.deserialize(socket_data, hashmap, restore_id) self.add_socket(socket) hashmap.update({socket_data['id']: socket}) + + +class OCBSplitterHandle(QSplitterHandle): + """ A handle for splitters with undoable events """ + + def mouseReleaseEvent(self, evt: QMouseEvent): + """ When releasing the handle, save the state to history """ + scene = self.parent().block.scene() + if scene is not None: + scene.history.checkpoint("Resize block", set_modified=True) + return super().mouseReleaseEvent(evt) + + +class OCBSplitter(QSplitter): + """ A spliter with undoable events """ + + def __init__(self, block: OCBBlock, orientation: int, parent: QWidget): + """ Create a new OCBSplitter """ + super().__init__(orientation, parent) + self.block = block + + def createHandle(self): + return OCBSplitterHandle(self.orientation(), self) diff --git a/opencodeblocks/graphics/blocks/blocksizegrip.py b/opencodeblocks/graphics/blocks/blocksizegrip.py index b6072d9b..c86c5c32 100644 --- a/opencodeblocks/graphics/blocks/blocksizegrip.py +++ b/opencodeblocks/graphics/blocks/blocksizegrip.py @@ -13,6 +13,7 @@ class BlockSizeGrip(QSizeGrip): """ A grip to resize a block """ + def __init__(self, block: QGraphicsItem, parent: QWidget = None): """ Constructor for BlockSizeGrip @@ -35,6 +36,7 @@ def mousePressEvent(self, mouseEvent: QMouseEvent): def mouseReleaseEvent(self, mouseEvent: QMouseEvent): """ Stop the resizing """ self.resizing = False + self.block.scene().history.checkpoint("Resized block", set_modified=True) @property def _zoom(self) -> float: @@ -43,8 +45,8 @@ def _zoom(self) -> float: def mouseMoveEvent(self, mouseEvent: QMouseEvent): """ Performs resizing of the root widget """ - transformed_pt1 = self.block.mapFromScene(QPoint(0,0)) - transformed_pt2 = self.block.mapFromScene(QPoint(1,1)) + transformed_pt1 = self.block.mapFromScene(QPoint(0, 0)) + transformed_pt2 = self.block.mapFromScene(QPoint(1, 1)) pt = transformed_pt2 - transformed_pt1 pt /= self._zoom @@ -58,11 +60,11 @@ def mouseMoveEvent(self, mouseEvent: QMouseEvent): # have this effect. new_width = max( self.block.width + int(delta_x), - self.block._min_width + self.block.min_width ) new_height = max( self.block.height + int(delta_y), - self.block._min_height + self.block.min_height ) self.parent().setGeometry(0, 0, new_width, new_height) diff --git a/opencodeblocks/graphics/blocks/codeblock.py b/opencodeblocks/graphics/blocks/codeblock.py index 67ac1827..7879cb4d 100644 --- a/opencodeblocks/graphics/blocks/codeblock.py +++ b/opencodeblocks/graphics/blocks/codeblock.py @@ -41,6 +41,7 @@ def __init__(self, **kwargs): self.run_button = self.init_run_button() self.stdout = "" self.image = "" + self.title_left_offset = 3 * self.edge_size self.holder.setWidget(self.root) @@ -58,9 +59,9 @@ def update_all(self): if hasattr(self, 'run_button'): self.run_button.setGeometry( int(self.edge_size), - int(self.edge_size + self.title_height), - int(2.5*self.edge_size), - int(2.5*self.edge_size) + int(self.edge_size / 2), + int(2.5 * self.edge_size), + int(2.5 * self.edge_size) ) @property @@ -117,7 +118,6 @@ def source(self, value: str): editor_widget = self.source_editor editor_widget.setText(self._source) - def init_output_panel(self): """ Initialize the output display widget: QLabel """ output_panel = QLabel() @@ -128,7 +128,7 @@ def init_output_panel(self): def init_run_button(self): """ Initialize the run button """ - run_button = QPushButton(">",self.root) + run_button = QPushButton(">", self.root) run_button.setMinimumWidth(int(self.edge_size)) run_button.clicked.connect(self.run_code) run_button.raise_() diff --git a/opencodeblocks/graphics/scene/history.py b/opencodeblocks/graphics/scene/history.py index 3f93ef7e..a6baabe0 100644 --- a/opencodeblocks/graphics/scene/history.py +++ b/opencodeblocks/graphics/scene/history.py @@ -18,7 +18,7 @@ class SceneHistory(): """ - def __init__(self, scene:'OCBScene', max_stack:int=20): + def __init__(self, scene:'OCBScene', max_stack:int = 50): self.scene = scene self.history_stack = [] self.current = -1 diff --git a/tests/integration/test_blocks.py b/tests/integration/test_blocks.py index 0cff9521..449f7763 100644 --- a/tests/integration/test_blocks.py +++ b/tests/integration/test_blocks.py @@ -54,7 +54,9 @@ def test_move_blocks(self, qtbot): def testing_drag(msgQueue): pos_block = QPointF(self.block1.pos().x(), self.block1.pos().y()) - pos_block.setX(pos_block.x() + self.block1.title_height/2) + pos_block.setX( + pos_block.x() + self.block1.title_height + self.block1.edge_size + ) pos_block.setY(pos_block.y() + self.block1.title_height/2) pos_block = self.ocb_widget.view.mapFromScene(pos_block) From 1b54a202d1ebb8e6dfa72fa98d1a47655d18dd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Fri, 19 Nov 2021 00:06:38 +0100 Subject: [PATCH 12/13] :beetle: This code path should not be reached when a child of the class is constructed. --- opencodeblocks/graphics/blocks/block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index bb4244bd..3c060064 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -91,7 +91,7 @@ def __init__(self, block_type: str = 'base', source: str = '', position: tuple = self.size_grip = BlockSizeGrip(self, self.root) - if isinstance(self, OCBBlock): + if type(self) == OCBBlock: # This has to be called at the end of the constructor of # every class inheriting this. self.holder.setWidget(self.root) From ecfe72b88da8861d8b8c0b0f6c189517106ab98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Del=C3=A8gue?= Date: Fri, 19 Nov 2021 00:12:14 +0100 Subject: [PATCH 13/13] :sparkles: Styling issues related to codacy. Adds a comment to prevent future people from introducing bugs by blindingly following linter advice; --- main.py | 4 +++- opencodeblocks/graphics/blocks/block.py | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index d7ee6c7a..2df8be1e 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,9 @@ # OpenCodeBlock an open-source tool for modular visual programing in python # Copyright (C) 2021 Mathïs FEDERICO -import os,sys,asyncio +import os +import sys +import asyncio if os.name == "nt": # If on windows asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) diff --git a/opencodeblocks/graphics/blocks/block.py b/opencodeblocks/graphics/blocks/block.py index 3c060064..c7e05840 100644 --- a/opencodeblocks/graphics/blocks/block.py +++ b/opencodeblocks/graphics/blocks/block.py @@ -5,8 +5,8 @@ from typing import TYPE_CHECKING, Optional, OrderedDict, Tuple -from PyQt5.QtCore import QEvent, QPointF, QRectF, Qt -from PyQt5.QtGui import QBrush, QMouseEvent, QPen, QColor, QFont, QPainter, QPainterPath, QResizeEvent +from PyQt5.QtCore import QPointF, QRectF, Qt +from PyQt5.QtGui import QBrush, QMouseEvent, QPen, QColor, QFont, QPainter, QPainterPath from PyQt5.QtWidgets import QGraphicsItem, QGraphicsProxyWidget, \ QGraphicsSceneMouseEvent, QLabel, QSplitter, QSplitterHandle, \ QStyleOptionGraphicsItem, QWidget @@ -91,7 +91,7 @@ def __init__(self, block_type: str = 'base', source: str = '', position: tuple = self.size_grip = BlockSizeGrip(self, self.root) - if type(self) == OCBBlock: + if type(self) == OCBBlock: # DO NOT TRUST codacy !!! isinstance != type # This has to be called at the end of the constructor of # every class inheriting this. self.holder.setWidget(self.root) @@ -343,4 +343,5 @@ def __init__(self, block: OCBBlock, orientation: int, parent: QWidget): self.block = block def createHandle(self): + """ Return the middle handle of the splitter """ return OCBSplitterHandle(self.orientation(), self)