From 72846475ce0c9b55b6db640bf67750c3fc5a1c48 Mon Sep 17 00:00:00 2001 From: Fabien Roger Date: Thu, 2 Dec 2021 19:47:06 +0100 Subject: [PATCH 1/5] Add move to global view --- opencodeblocks/graphics/view.py | 57 +++++++++++++++++++++++++++++-- opencodeblocks/graphics/widget.py | 4 +++ opencodeblocks/graphics/window.py | 11 ++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/opencodeblocks/graphics/view.py b/opencodeblocks/graphics/view.py index be48822d..3c10b878 100644 --- a/opencodeblocks/graphics/view.py +++ b/opencodeblocks/graphics/view.py @@ -18,6 +18,7 @@ from opencodeblocks.graphics.edge import OCBEdge from opencodeblocks.blocks import OCBBlock +EPS: float = 1e-10 # To check if blocks are of size 0 class OCBView(QGraphicsView): @@ -142,6 +143,48 @@ def centerView(self, x: float, y: float): hsb.setValue(x * self.zoom - self.width() / 2) vsb.setValue(y * self.zoom - self.height() / 2) + def moveToGlobalView(self) -> bool: + """ + OCBView reaction to the space bar being pressed. + Returns True if the event was handled. + """ + + # The focusItem has priority for this event + if self.scene().focusItem() is not None: + return False + if len(self.scene().selectedItems()) > 0: + return False + + items = self.scene().items() + code_blocks:List[OCBBlock] = [i for i in items if isinstance(i, OCBBlock)] + + if len(code_blocks) == 0: + return False + + # Get the blocks with min and max x and y coordinates + + min_x:float = min(block.x() for block in code_blocks) + min_y:float = min(block.y() for block in code_blocks) + max_x:float = max(block.x() + block.width for block in code_blocks) + max_y:float = max(block.y() + block.height for block in code_blocks) + + center_x:float = (min_x + max_x) / 2 + center_y:float = (min_y + max_y) / 2 + + # Determines the required zoom level + + if max_x - min_x < EPS or max_y - min_y < EPS: + # Handle the cas where the zoom level hasn't been computed because of blocks of size <= 0 + return False + + required_zoom_x:float = self.width() / (max_x - min_x) + required_zoom_y:float = self.height() / (max_y - min_y) + + # Operate the zoom and the translation + self.setZoom(min(required_zoom_x, required_zoom_y)) + self.centerView(center_x, center_y) + return True + def getDistanceToCenter(self, x: float, y: float) -> Tuple[float]: """ Return the vector from the (x,y) position given to the center of the view """ ypos = self.verticalScrollBar().value() @@ -212,6 +255,11 @@ def keyPressEvent(self, event: QKeyEvent): Qt.Key.Key_Left, Qt.Key.Key_Right]: if self.moveViewOnArrow(event): return + + if key_id == Qt.Key.Key_Space: + if self.globalView(): + return + super().keyPressEvent(event) def retreiveBlockTypes(self) -> List[Tuple[str]]: @@ -254,11 +302,16 @@ def wheelEvent(self, event: QWheelEvent): zoom_factor = 1 / self.zoom_step if self.zoom_min < self.zoom * zoom_factor < self.zoom_max: - self.zoom *= zoom_factor - self.scale(zoom_factor, zoom_factor) + self.setZoom(self.zoom * zoom_factor) else: super().wheelEvent(event) + def setZoom(self, new_zoom: float): + """ Set the zoom to the appropriate level """ + zoom_factor = new_zoom / self.zoom + self.scale(zoom_factor, zoom_factor) + self.zoom = new_zoom + def deleteSelected(self): """ Delete selected items from the current scene. """ scene = self.scene() diff --git a/opencodeblocks/graphics/widget.py b/opencodeblocks/graphics/widget.py index 0a847e04..a1815d9b 100644 --- a/opencodeblocks/graphics/widget.py +++ b/opencodeblocks/graphics/widget.py @@ -64,3 +64,7 @@ def save(self): def load(self, filepath: str): self.scene.load(filepath) self.savepath = filepath + + def moveToGlobalView(self): + """ Center the view to see the hole graph """ + self.view.moveToGlobalView() diff --git a/opencodeblocks/graphics/window.py b/opencodeblocks/graphics/window.py index e344ea70..c6a05b48 100644 --- a/opencodeblocks/graphics/window.py +++ b/opencodeblocks/graphics/window.py @@ -117,6 +117,10 @@ def createActions(self): self.actDel = QAction('&Del', statusTip='Delete selected items', shortcut='Del', triggered=self.onEditDelete) + # View + self.actGlobal = QAction('Global View', statusTip='View the hole graph', + shortcut=' ', triggered=self.onViewGlobal) + # Window self.actClose = QAction("Cl&ose", self, statusTip="Close the active window", @@ -164,6 +168,7 @@ def createMenus(self): self.viewmenu = self.menuBar().addMenu('&View') self.thememenu = self.viewmenu.addMenu('Theme') self.thememenu.aboutToShow.connect(self.updateThemeMenu) + self.viewmenu.addAction(self.actGlobal) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() @@ -374,5 +379,11 @@ def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window) + def onViewGlobal(self): + """ Center the view to see the hole graph """ + current_window = self.activeMdiChild() + if current_window is not None and isinstance(current_window, OCBWidget): + current_window.moveToGlobalView() + def setTheme(self, theme_index): theme_manager().selected_theme_index = theme_index From 07d0357320d678f1e8e69cd6a0f32c479fa70612 Mon Sep 17 00:00:00 2001 From: Fabien Roger Date: Thu, 2 Dec 2021 22:39:11 +0100 Subject: [PATCH 2/5] Fix typo --- opencodeblocks/graphics/view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencodeblocks/graphics/view.py b/opencodeblocks/graphics/view.py index 3c10b878..8a63c04a 100644 --- a/opencodeblocks/graphics/view.py +++ b/opencodeblocks/graphics/view.py @@ -257,7 +257,7 @@ def keyPressEvent(self, event: QKeyEvent): return if key_id == Qt.Key.Key_Space: - if self.globalView(): + if self.moveToGlobalView(): return super().keyPressEvent(event) From f2c8acce0063ee2eb2dcca44705143768611ea7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Fri, 3 Dec 2021 13:04:05 +0100 Subject: [PATCH 3/5] :sparkles: Applied black codestyle --- opencodeblocks/graphics/view.py | 211 ++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 93 deletions(-) diff --git a/opencodeblocks/graphics/view.py b/opencodeblocks/graphics/view.py index 8a63c04a..da927453 100644 --- a/opencodeblocks/graphics/view.py +++ b/opencodeblocks/graphics/view.py @@ -18,24 +18,31 @@ from opencodeblocks.graphics.edge import OCBEdge from opencodeblocks.blocks import OCBBlock -EPS: float = 1e-10 # To check if blocks are of size 0 +EPS: float = 1e-10 # To check if blocks are of size 0 + class OCBView(QGraphicsView): - """ View for the OCB Window. """ + """View for the OCB Window.""" MODE_NOOP = 0 MODE_EDGE_DRAG = 1 MODE_EDITING = 2 MODES = { - 'NOOP': MODE_NOOP, - 'EDGE_DRAG': MODE_EDGE_DRAG, - 'EDITING': MODE_EDITING, + "NOOP": MODE_NOOP, + "EDGE_DRAG": MODE_EDGE_DRAG, + "EDITING": MODE_EDITING, } - def __init__(self, scene: OCBScene, parent=None, - zoom_step: float = 1.25, zoom_min: float = 0.2, zoom_max: float = 5): + def __init__( + self, + scene: OCBScene, + parent=None, + zoom_step: float = 1.25, + zoom_min: float = 0.2, + zoom_max: float = 5, + ): super().__init__(parent=parent) self.mode = self.MODE_NOOP self.zoom = 1 @@ -49,34 +56,30 @@ def __init__(self, scene: OCBScene, parent=None, self.setScene(scene) def init_ui(self): - """ Initialize the custom OCB View UI. """ + """Initialize the custom OCB View UI.""" # Antialiasing self.setRenderHints( - QPainter.RenderHint.Antialiasing | - QPainter.RenderHint.HighQualityAntialiasing | - QPainter.RenderHint.TextAntialiasing | - QPainter.RenderHint.SmoothPixmapTransform + QPainter.RenderHint.Antialiasing + | QPainter.RenderHint.HighQualityAntialiasing + | QPainter.RenderHint.TextAntialiasing + | QPainter.RenderHint.SmoothPixmapTransform ) # Better Update - self.setViewportUpdateMode( - QGraphicsView.ViewportUpdateMode.FullViewportUpdate - ) + self.setViewportUpdateMode(QGraphicsView.ViewportUpdateMode.FullViewportUpdate) # Remove scroll bars - self.setHorizontalScrollBarPolicy( - Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) # Zoom on cursor - self.setTransformationAnchor( - QGraphicsView.ViewportAnchor.AnchorUnderMouse) + self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse) # Selection box self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) def scene(self) -> OCBScene: - """ Get current 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: @@ -94,14 +97,14 @@ def mouseReleaseEvent(self, event: QMouseEvent): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event: QMouseEvent) -> None: - """ OCBView reaction to mouseMoveEvent. """ + """OCBView reaction to mouseMoveEvent.""" self.lastMousePos = self.mapToScene(event.pos()) - self.drag_edge(event, 'move') + self.drag_edge(event, "move") if event is not None: super().mouseMoveEvent(event) def leftMouseButtonPress(self, event: QMouseEvent): - """ OCBView reaction to leftMouseButtonPress 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: @@ -114,30 +117,30 @@ def leftMouseButtonPress(self, event: QMouseEvent): self.bring_block_forward(item_at_click) # If clicked on a socket, start dragging an edge. - event = self.drag_edge(event, 'press') + 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') + """OCBView reaction to leftMouseButtonRelease event.""" + event = self.drag_edge(event, "release") if event is not None: super().mouseReleaseEvent(event) def middleMouseButtonPress(self, event: QMouseEvent): - """ OCBView reaction to middleMouseButtonPress event. """ + """OCBView reaction to middleMouseButtonPress event.""" if self.itemAt(event.pos()) is None: event = self.drag_scene(event, "press") super().mousePressEvent(event) def middleMouseButtonRelease(self, event: QMouseEvent): - """ OCBView reaction to middleMouseButtonRelease event. """ + """OCBView reaction to middleMouseButtonRelease event.""" event = self.drag_scene(event, "release") super().mouseReleaseEvent(event) self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) def centerView(self, x: float, y: float): - """ Move the view so that the position (x,y) is centered. """ + """Move the view so that the position (x,y) is centered.""" hsb = self.horizontalScrollBar() vsb = self.verticalScrollBar() hsb.setValue(x * self.zoom - self.width() / 2) @@ -145,8 +148,8 @@ def centerView(self, x: float, y: float): def moveToGlobalView(self) -> bool: """ - OCBView reaction to the space bar being pressed. - Returns True if the event was handled. + OCBView reaction to the space bar being pressed. + Returns True if the event was handled. """ # The focusItem has priority for this event @@ -154,22 +157,22 @@ def moveToGlobalView(self) -> bool: return False if len(self.scene().selectedItems()) > 0: return False - + items = self.scene().items() - code_blocks:List[OCBBlock] = [i for i in items if isinstance(i, OCBBlock)] + code_blocks: List[OCBBlock] = [i for i in items if isinstance(i, OCBBlock)] if len(code_blocks) == 0: return False # Get the blocks with min and max x and y coordinates - min_x:float = min(block.x() for block in code_blocks) - min_y:float = min(block.y() for block in code_blocks) - max_x:float = max(block.x() + block.width for block in code_blocks) - max_y:float = max(block.y() + block.height for block in code_blocks) + min_x: float = min(block.x() for block in code_blocks) + min_y: float = min(block.y() for block in code_blocks) + max_x: float = max(block.x() + block.width for block in code_blocks) + max_y: float = max(block.y() + block.height for block in code_blocks) - center_x:float = (min_x + max_x) / 2 - center_y:float = (min_y + max_y) / 2 + center_x: float = (min_x + max_x) / 2 + center_y: float = (min_y + max_y) / 2 # Determines the required zoom level @@ -177,27 +180,27 @@ def moveToGlobalView(self) -> bool: # Handle the cas where the zoom level hasn't been computed because of blocks of size <= 0 return False - required_zoom_x:float = self.width() / (max_x - min_x) - required_zoom_y:float = self.height() / (max_y - min_y) - + required_zoom_x: float = self.width() / (max_x - min_x) + required_zoom_y: float = self.height() / (max_y - min_y) + # Operate the zoom and the translation self.setZoom(min(required_zoom_x, required_zoom_y)) self.centerView(center_x, center_y) return True def getDistanceToCenter(self, x: float, y: float) -> Tuple[float]: - """ Return the vector from the (x,y) position given to the center of the view """ + """Return the vector from the (x,y) position given to the center of the view""" ypos = self.verticalScrollBar().value() xpos = self.horizontalScrollBar().value() return ( xpos - x * self.zoom + self.width() / 2, - ypos - y * self.zoom + self.height() / 2 + ypos - y * self.zoom + self.height() / 2, ) def moveViewOnArrow(self, event: QKeyEvent) -> bool: """ - OCBView reaction to an arrow key being pressed. - Returns True if the event was handled. + OCBView reaction to an arrow key being pressed. + Returns True if the event was handled. """ # The focusItem has priority for this event if self.scene().focusItem() is not None: @@ -218,16 +221,16 @@ def moveViewOnArrow(self, event: QKeyEvent) -> bool: for block in code_blocks: block_center_x = block.x() + block.width / 2 block_center_y = block.y() + block.height / 2 - xdist, ydist = self.getDistanceToCenter( - block_center_x, block_center_y) - dist_array.append(( - block_center_x, - block_center_y, - xdist, - ydist, - max(abs(xdist), abs(ydist)) - - )) + xdist, ydist = self.getDistanceToCenter(block_center_x, block_center_y) + dist_array.append( + ( + block_center_x, + block_center_y, + xdist, + ydist, + max(abs(xdist), abs(ydist)), + ) + ) if key_id == Qt.Key.Key_Up: dist_array = filter(lambda pos: pos[3] > 1, dist_array) @@ -249,13 +252,17 @@ def moveViewOnArrow(self, event: QKeyEvent) -> bool: return True def keyPressEvent(self, event: QKeyEvent): - """ OCBView reaction to a key being pressed """ + """OCBView reaction to a key being pressed""" key_id = event.key() - if key_id in [Qt.Key.Key_Up, Qt.Key.Key_Down, - Qt.Key.Key_Left, Qt.Key.Key_Right]: + if key_id in [ + Qt.Key.Key_Up, + Qt.Key.Key_Down, + Qt.Key.Key_Left, + Qt.Key.Key_Right, + ]: if self.moveViewOnArrow(event): return - + if key_id == Qt.Key.Key_Space: if self.moveToGlobalView(): return @@ -263,7 +270,7 @@ def keyPressEvent(self, event: QKeyEvent): super().keyPressEvent(event) def retreiveBlockTypes(self) -> List[Tuple[str]]: - """ Retreive the list of stored blocks. """ + """Retreive the list of stored blocks.""" block_type_files = os.listdir("blocks") block_types = [] for b in block_type_files: @@ -273,14 +280,14 @@ def retreiveBlockTypes(self) -> List[Tuple[str]]: title = "New Block" if "title" in data: title = f"New {data['title']} Block" - if data['title'] == "Empty": + if data["title"] == "Empty": block_types[:0] = [(filepath, title)] else: block_types.append((filepath, title)) return block_types def contextMenuEvent(self, event: QContextMenuEvent): - """ Displays the context menu when inside a view """ + """Displays the context menu when inside a view""" menu = QMenu(self) actionPool = [] for filepath, block_name in self.retreiveBlockTypes(): @@ -293,7 +300,7 @@ def contextMenuEvent(self, event: QContextMenuEvent): self.scene().create_block_from_file(filepath, p.x(), p.y()) def wheelEvent(self, event: QWheelEvent): - """ Handles zooming with mouse wheel events. """ + """Handles zooming with mouse wheel events.""" if Qt.Modifier.CTRL == int(event.modifiers()): # calculate zoom if event.angleDelta().y() > 0: @@ -307,72 +314,90 @@ def wheelEvent(self, event: QWheelEvent): super().wheelEvent(event) def setZoom(self, new_zoom: float): - """ Set the zoom to the appropriate level """ + """Set the zoom to the appropriate level""" zoom_factor = new_zoom / self.zoom self.scale(zoom_factor, zoom_factor) self.zoom = new_zoom def deleteSelected(self): - """ Delete selected items from the current scene. """ + """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_block_forward(self, block: OCBBlock): - """ Move the selected block in front of other blocks. + """Move the selected block in front of other blocks. Args: block: Block to bring forward. """ if self.currentSelectedBlock is not None and not isdeleted( - self.currentSelectedBlock): + self.currentSelectedBlock + ): self.currentSelectedBlock.setZValue(0) block.setZValue(1) self.currentSelectedBlock = block def drag_scene(self, event: QMouseEvent, action="press"): - """ Drag the scene around. """ + """Drag the scene around.""" if action == "press": - releaseEvent = QMouseEvent(QEvent.Type.MouseButtonRelease, - event.localPos(), event.screenPos(), - Qt.MouseButton.LeftButton, Qt.MouseButton.NoButton, - event.modifiers()) + releaseEvent = QMouseEvent( + QEvent.Type.MouseButtonRelease, + event.localPos(), + event.screenPos(), + Qt.MouseButton.LeftButton, + Qt.MouseButton.NoButton, + event.modifiers(), + ) super().mouseReleaseEvent(releaseEvent) self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag) - return QMouseEvent(event.type(), event.localPos(), event.screenPos(), - Qt.MouseButton.LeftButton, - event.buttons() | Qt.MouseButton.LeftButton, - event.modifiers()) - return QMouseEvent(event.type(), event.localPos(), event.screenPos(), - Qt.MouseButton.LeftButton, - event.buttons() & ~Qt.MouseButton.LeftButton, - event.modifiers()) + return QMouseEvent( + event.type(), + event.localPos(), + event.screenPos(), + Qt.MouseButton.LeftButton, + event.buttons() | Qt.MouseButton.LeftButton, + event.modifiers(), + ) + return QMouseEvent( + event.type(), + event.localPos(), + event.screenPos(), + Qt.MouseButton.LeftButton, + event.buttons() & ~Qt.MouseButton.LeftButton, + event.modifiers(), + ) def drag_edge(self, event: QMouseEvent, action="press"): - """ Create an edge by drag and drop. """ + """Create an edge by drag and drop.""" item_at_click = self.itemAt(event.pos()) scene = self.scene() if action == "press": - if isinstance(item_at_click, OCBSocket) \ - and self.mode != self.MODE_EDGE_DRAG\ - and item_at_click.socket_type != 'input': + if ( + isinstance(item_at_click, OCBSocket) + and self.mode != self.MODE_EDGE_DRAG + and item_at_click.socket_type != "input" + ): self.mode = self.MODE_EDGE_DRAG self.edge_drag = OCBEdge( source_socket=item_at_click, - destination=self.mapToScene(event.pos()) + destination=self.mapToScene(event.pos()), ) scene.addItem(self.edge_drag) return elif action == "release": if self.mode == self.MODE_EDGE_DRAG: - if isinstance(item_at_click, OCBSocket) \ - and item_at_click is not self.edge_drag.source_socket \ - and item_at_click.socket_type != 'output': + if ( + isinstance(item_at_click, OCBSocket) + and item_at_click is not self.edge_drag.source_socket + and item_at_click.socket_type != "output" + ): self.edge_drag.destination_socket = item_at_click scene.history.checkpoint( - "Created edge by dragging", set_modified=True) + "Created edge by dragging", set_modified=True + ) else: self.edge_drag.remove() self.edge_drag = None @@ -383,7 +408,7 @@ def drag_edge(self, event: QMouseEvent, action="press"): return event def set_mode(self, mode: str): - """ Change the view mode. + """Change the view mode. Args: mode: Mode key to change to, must in present in MODES. @@ -392,7 +417,7 @@ def set_mode(self, mode: str): self.mode = self.MODES[mode] def is_mode(self, mode: str): - """ Return True if the view is in the given mode. + """Return True if the view is in the given mode. Args: mode: Mode key to compare to, must in present in MODES. From ad59a7d11c094b39ba2d708b4b1345e80f4af087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Fri, 3 Dec 2021 13:11:11 +0100 Subject: [PATCH 4/5] :wrench: Refactored wheelEvent --- opencodeblocks/graphics/view.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/opencodeblocks/graphics/view.py b/opencodeblocks/graphics/view.py index da927453..ea8801f9 100644 --- a/opencodeblocks/graphics/view.py +++ b/opencodeblocks/graphics/view.py @@ -177,7 +177,7 @@ def moveToGlobalView(self) -> bool: # Determines the required zoom level if max_x - min_x < EPS or max_y - min_y < EPS: - # Handle the cas where the zoom level hasn't been computed because of blocks of size <= 0 + # Handle the case where there is no block return False required_zoom_x: float = self.width() / (max_x - min_x) @@ -308,8 +308,9 @@ def wheelEvent(self, event: QWheelEvent): else: zoom_factor = 1 / self.zoom_step - if self.zoom_min < self.zoom * zoom_factor < self.zoom_max: - self.setZoom(self.zoom * zoom_factor) + new_zoom = self.zoom * zoom_factor + if self.zoom_min < new_zoom < self.zoom_max: + self.setZoom(new_zoom) else: super().wheelEvent(event) From c823ed21bbacd193cd78de8248cb92007414c38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Math=C3=AFs=20F=C3=A9d=C3=A9rico?= Date: Fri, 3 Dec 2021 13:17:47 +0100 Subject: [PATCH 5/5] :sparkles: Fix pylint issues --- .pylintrc | 4 +- opencodeblocks/__main__.py | 10 +-- opencodeblocks/blocks/codeblock.py | 8 +- .../blocks/widgets/blocksplitter.py | 12 +-- opencodeblocks/graphics/widget.py | 14 ++-- opencodeblocks/graphics/window.py | 81 ++++++++++--------- 6 files changed, 64 insertions(+), 65 deletions(-) diff --git a/.pylintrc b/.pylintrc index c58e25a3..a01545e3 100644 --- a/.pylintrc +++ b/.pylintrc @@ -527,7 +527,7 @@ valid-metaclass-classmethod-first-arg=cls max-args=10 # Maximum number of attributes for a class (see R0902). -max-attributes=20 +max-attributes=30 # Maximum number of boolean expressions in an if statement (see R0916). max-bool-expr=5 @@ -542,7 +542,7 @@ max-locals=20 max-parents=7 # Maximum number of public methods for a class (see R0904). -max-public-methods=20 +max-public-methods=30 # Maximum number of return / yield for function / method body. max-returns=6 diff --git a/opencodeblocks/__main__.py b/opencodeblocks/__main__.py index 3845a866..d763abba 100644 --- a/opencodeblocks/__main__.py +++ b/opencodeblocks/__main__.py @@ -5,17 +5,17 @@ import sys import 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 +if os.name == "nt": # If on windows + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) -if __name__ == '__main__': +if __name__ == "__main__": app = QApplication(sys.argv) - app.setStyle('Fusion') + app.setStyle("Fusion") wnd = OCBWindow() if len(sys.argv) > 1: wnd.createNewMdiChild(sys.argv[1]) diff --git a/opencodeblocks/blocks/codeblock.py b/opencodeblocks/blocks/codeblock.py index d77a8ce1..a6f3733f 100644 --- a/opencodeblocks/blocks/codeblock.py +++ b/opencodeblocks/blocks/codeblock.py @@ -3,8 +3,6 @@ """ Module for the base OCB Code Block. """ -from PyQt5.QtCore import QByteArray -from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QPushButton, QTextEdit from ansi2html import Ansi2HTMLConverter @@ -29,9 +27,9 @@ class OCBCodeBlock(OCBBlock): """ def __init__(self, **kwargs): - """ - Create a new OCBCodeBlock. - Initialize all the child widgets specific to this block type + """ + Create a new OCBCodeBlock. + Initialize all the child widgets specific to this block type """ self.source_editor = PythonEditor(self) diff --git a/opencodeblocks/blocks/widgets/blocksplitter.py b/opencodeblocks/blocks/widgets/blocksplitter.py index 31137fb0..a7eee746 100644 --- a/opencodeblocks/blocks/widgets/blocksplitter.py +++ b/opencodeblocks/blocks/widgets/blocksplitter.py @@ -8,10 +8,10 @@ class OCBSplitterHandle(QSplitterHandle): - """ A handle for splitters with undoable events """ + """A handle for splitters with undoable events""" def mouseReleaseEvent(self, evt: QMouseEvent): - """ When releasing the handle, save the state to history """ + """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) @@ -19,13 +19,13 @@ def mouseReleaseEvent(self, evt: QMouseEvent): class OCBSplitter(QSplitter): - """ A spliter with undoable events """ + """A spliter with undoable events""" def __init__(self, block: QWidget, orientation: int, parent: QWidget): - """ Create a new OCBSplitter """ + """Create a new OCBSplitter""" super().__init__(orientation, parent) self.block = block def createHandle(self): - """ Return the middle handle of the splitter """ - return OCBSplitterHandle(self.orientation(), self) \ No newline at end of file + """Return the middle handle of the splitter""" + return OCBSplitterHandle(self.orientation(), self) diff --git a/opencodeblocks/graphics/widget.py b/opencodeblocks/graphics/widget.py index a1815d9b..8d79f871 100644 --- a/opencodeblocks/graphics/widget.py +++ b/opencodeblocks/graphics/widget.py @@ -14,7 +14,7 @@ class OCBWidget(QWidget): - """ Window for the OCB application. """ + """Window for the OCB application.""" def __init__(self, parent=None): super().__init__(parent) @@ -35,9 +35,9 @@ def __init__(self, parent=None): self.savepath = None def updateTitle(self): - """ Update the window title. """ + """Update the window title.""" if self.savepath is None: - title = 'New Graph' + title = "New Graph" else: title = os.path.basename(self.savepath) if self.isModified(): @@ -45,12 +45,12 @@ def updateTitle(self): self.setWindowTitle(title) def isModified(self) -> bool: - """ Return True if the scene has been modified, False otherwise. """ + """Return True if the scene has been modified, False otherwise.""" return self.scene.has_been_modified @property def savepath(self): - """ Current cached file save path. Update window title when set.""" + """Current cached file save path. Update window title when set.""" return self._savepath @savepath.setter @@ -64,7 +64,7 @@ def save(self): def load(self, filepath: str): self.scene.load(filepath) self.savepath = filepath - + def moveToGlobalView(self): - """ Center the view to see the hole graph """ + """Center the view to see the hole graph""" self.view.moveToGlobalView() diff --git a/opencodeblocks/graphics/window.py b/opencodeblocks/graphics/window.py index c6a05b48..6823f3fa 100644 --- a/opencodeblocks/graphics/window.py +++ b/opencodeblocks/graphics/window.py @@ -1,5 +1,6 @@ # OpenCodeBlock an open-source tool for modular visual programing in python # Copyright (C) 2021 Mathïs FEDERICO +# pylint:disable=too-many-instance-attributes """ Module for the OCB Window """ @@ -92,83 +93,83 @@ def updateMenus(self): def createActions(self): """ Create all menu actions. """ # File - self.actNew = QAction('&New', statusTip='Create new ipygraph', + self._actNew = QAction('&New', statusTip='Create new ipygraph', shortcut='Ctrl+N', triggered=self.onFileNew) - self.actOpen = QAction('&Open', statusTip='Open an ipygraph', + self._actOpen = QAction('&Open', statusTip='Open an ipygraph', shortcut='Ctrl+O', triggered=self.onFileOpen) - self.actSave = QAction('&Save', statusTip='Save the ipygraph', + self._actSave = QAction('&Save', statusTip='Save the ipygraph', shortcut='Ctrl+S', triggered=self.onFileSave) - self.actSaveAs = QAction('Save &As...', statusTip='Save the ipygraph as...', + self._actSaveAs = QAction('Save &As...', statusTip='Save the ipygraph as...', shortcut='Ctrl+Shift+S', triggered=self.onFileSaveAs) - self.actQuit = QAction('&Quit', statusTip='Save and Quit the application', + self._actQuit = QAction('&Quit', statusTip='Save and Quit the application', shortcut='Ctrl+Q', triggered=self.close) # Edit - self.actUndo = QAction('&Undo', statusTip='Undo last operation', + self._actUndo = QAction('&Undo', statusTip='Undo last operation', shortcut='Ctrl+Z', triggered=self.onEditUndo) - self.actRedo = QAction('&Redo', statusTip='Redo last operation', + self._actRedo = QAction('&Redo', statusTip='Redo last operation', shortcut='Ctrl+Y', triggered=self.onEditRedo) - self.actCut = QAction('Cu&t', statusTip='Cut to clipboard', + self._actCut = QAction('Cu&t', statusTip='Cut to clipboard', shortcut='Ctrl+X', triggered=self.onEditCut) - self.actCopy = QAction('&Copy', statusTip='Copy to clipboard', + self._actCopy = QAction('&Copy', statusTip='Copy to clipboard', shortcut='Ctrl+C', triggered=self.onEditCopy) - self.actPaste = QAction('&Paste', statusTip='Paste from clipboard', + self._actPaste = QAction('&Paste', statusTip='Paste from clipboard', shortcut='Ctrl+V', triggered=self.onEditPaste) - self.actDel = QAction('&Del', statusTip='Delete selected items', + self._actDel = QAction('&Del', statusTip='Delete selected items', shortcut='Del', triggered=self.onEditDelete) # View - self.actGlobal = QAction('Global View', statusTip='View the hole graph', + self._actGlobal = QAction('Global View', statusTip='View the hole graph', shortcut=' ', triggered=self.onViewGlobal) # Window - self.actClose = QAction("Cl&ose", self, + self._actClose = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) - self.actCloseAll = QAction("Close &All", self, + self._actCloseAll = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) - self.actTile = QAction("&Tile", self, statusTip="Tile the windows", + self._actTile = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) - self.actCascade = QAction("&Cascade", self, + self._actCascade = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) - self.actNext = QAction("Ne&xt", self, + self._actNext = QAction("Ne&xt", self, shortcut=QKeySequence.StandardKey.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) - self.actPrevious = QAction("Pre&vious", self, + self._actPrevious = QAction("Pre&vious", self, shortcut=QKeySequence.StandardKey.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) - self.actSeparator = QAction(self) - self.actSeparator.setSeparator(True) + self._actSeparator = QAction(self) + self._actSeparator.setSeparator(True) def createMenus(self): """ Create the File menu with linked shortcuts. """ self.filemenu = self.menuBar().addMenu('&File') - self.filemenu.addAction(self.actNew) - self.filemenu.addAction(self.actOpen) + self.filemenu.addAction(self._actNew) + self.filemenu.addAction(self._actOpen) self.filemenu.addSeparator() - self.filemenu.addAction(self.actSave) - self.filemenu.addAction(self.actSaveAs) + self.filemenu.addAction(self._actSave) + self.filemenu.addAction(self._actSaveAs) self.filemenu.addSeparator() - self.filemenu.addAction(self.actQuit) + self.filemenu.addAction(self._actQuit) self.editmenu = self.menuBar().addMenu('&Edit') - self.editmenu.addAction(self.actUndo) - self.editmenu.addAction(self.actRedo) + self.editmenu.addAction(self._actUndo) + self.editmenu.addAction(self._actRedo) self.editmenu.addSeparator() - self.editmenu.addAction(self.actCut) - self.editmenu.addAction(self.actCopy) - self.editmenu.addAction(self.actPaste) + self.editmenu.addAction(self._actCut) + self.editmenu.addAction(self._actCopy) + self.editmenu.addAction(self._actPaste) self.editmenu.addSeparator() - self.editmenu.addAction(self.actDel) + self.editmenu.addAction(self._actDel) self.viewmenu = self.menuBar().addMenu('&View') self.thememenu = self.viewmenu.addMenu('Theme') self.thememenu.aboutToShow.connect(self.updateThemeMenu) - self.viewmenu.addAction(self.actGlobal) + self.viewmenu.addAction(self._actGlobal) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() @@ -188,18 +189,18 @@ def updateThemeMenu(self): def updateWindowMenu(self): self.windowMenu.clear() - self.windowMenu.addAction(self.actClose) - self.windowMenu.addAction(self.actCloseAll) + self.windowMenu.addAction(self._actClose) + self.windowMenu.addAction(self._actCloseAll) self.windowMenu.addSeparator() - self.windowMenu.addAction(self.actTile) - self.windowMenu.addAction(self.actCascade) + self.windowMenu.addAction(self._actTile) + self.windowMenu.addAction(self._actCascade) self.windowMenu.addSeparator() - self.windowMenu.addAction(self.actNext) - self.windowMenu.addAction(self.actPrevious) - self.windowMenu.addAction(self.actSeparator) + self.windowMenu.addAction(self._actNext) + self.windowMenu.addAction(self._actPrevious) + self.windowMenu.addAction(self._actSeparator) windows = self.mdiArea.subWindowList() - self.actSeparator.setVisible(len(windows) != 0) + self._actSeparator.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget()