Skip to content

Commit

Permalink
Add mypy support for mdi window
Browse files Browse the repository at this point in the history
  • Loading branch information
don4get committed Jul 6, 2020
1 parent d740cf8 commit 835cb6a
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 203 deletions.
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Nodedge is a free and open-source software for graphical programming. Try it out
:maxdepth: 2

intro
.. conventions
conventions

apidoc/nodedge
examples
Expand Down
2 changes: 1 addition & 1 deletion nodedge/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-

DEBUG_ITEMS_PRESSED = True
DEBUG_ITEMS_PRESSED: bool = True
24 changes: 21 additions & 3 deletions nodedge/edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(

self.scene.addEdge(self)

def __str__(self):
def __str__(self) -> str:
"""
:return: Edge(hex id, start socket hex id, end socket hex id, edge type)
:rtype: ``string``
Expand Down Expand Up @@ -343,7 +343,13 @@ def reconnect(self, sourceSocket: Socket, targetSocket: Socket):
elif self.targetSocket == sourceSocket:
self.targetSocket = targetSocket

def serialize(self):
def serialize(self) -> OrderedDict:
"""
Serialization method.
:return: Serialized edge
:rtype: ``OrderedDict``
"""
return OrderedDict(
[
("id", self.id),
Expand All @@ -366,7 +372,19 @@ def deserialize(
restoreId: bool = True,
*args,
**kwargs,
):
) -> bool:
"""
Deserialization method.
:param data:
:type data: ``dict``
:param hashmap:
:type hashmap: ``Optional[dict]``
:param restoreId:
:type restoreId: ``bool``
:return: success status
:rtype: ``bool``
"""
if hashmap is None:
hashmap = {}
if restoreId:
Expand Down
2 changes: 1 addition & 1 deletion nodedge/editor_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def loadFile(self, filename: str) -> bool:
self.scene.loadFromFile(filename)
self.filename = filename
# Don't store initial stamp because the file has still not been changed.
self.scene.history.clear(storeInitialStamp=True)
self.scene.history.clear()
QApplication.restoreOverrideCursor()
self.evalNodes()
return True
Expand Down
48 changes: 36 additions & 12 deletions nodedge/editor_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self, parent: Optional[QWidget] = None):

super().__init__(parent)

# noinspection SpellCheckingInspection
logging.basicConfig(
format="%(asctime)s|%(levelname).4s|%(filename)10s|"
"%(lineno).3s|%(message)s|%(funcName)s"
Expand All @@ -63,15 +64,17 @@ def __init__(self, parent: Optional[QWidget] = None):
self.clipboard: QClipboard = self.instance.clipboard()

# Pycharm does not recognise resolve connect method so the inspection is
# disabled. noinspection PyUnresolvedReferences
# noinspection PyUnresolvedReferences
self.clipboard.dataChanged.connect(self.onClipboardChanged) # type: ignore

self.lastActiveEditorWidget = None
self.lastActiveEditorWidget: Optional[EditorWidget] = None

self.debugMode: bool = False

self.initUI()

@property
def currentEditorWidget(self) -> EditorWidget:
def currentEditorWidget(self) -> Optional[EditorWidget]:
"""
:getter: Get current :class:`~nodedge.editor_widget.EditorWidget`
Expand All @@ -82,7 +85,7 @@ def currentEditorWidget(self) -> EditorWidget:
by the :class:`~nodedge.mdi_window.MdiWindow` which may have several
:class:`~nodedge.editor_widget.EditorWidget`.
:rtype: :class:`~nodedge.editor_widget`
:rtype: Optional[:class:`~nodedge.editor_widget`]
"""
centralWidget = self.centralWidget()
if isinstance(centralWidget, EditorWidget):
Expand All @@ -97,14 +100,15 @@ def initUI(self) -> None:
Create :class:`~nodedge.editor_widget.EditorWidget`, Actions and Menus
"""
self.createActions()

self.createMenus()

self.editorWidget = self.__class__.EditorWidgetClass()
self.setCentralWidget(self.editorWidget)
self.editorWidget.scene.addHasBeenModifiedListener(self.updateTitle)

self.createActions()

self.createMenus()

# Initialize status bar
self.createStatusBar()

Expand All @@ -123,6 +127,10 @@ def createStatusBar(self) -> None:
self.statusBar().showMessage("")
self.statusMousePos = QLabel("")
self.statusBar().addPermanentWidget(self.statusMousePos)

if self.currentEditorWidget is None:
return

self.currentEditorWidget.view.scenePosChanged.connect(self.OnScenePosChanged)

# noinspection PyArgumentList, PyAttributeOutsideInit
Expand Down Expand Up @@ -222,7 +230,13 @@ def createEditMenu(self):
self.editMenu.addSeparator()
self.editMenu.addAction(self.deleteAct)

def sizeHint(self):
def sizeHint(self) -> QSize:
"""
Qt's size hint handle.
TODO: Investigate if we really need to overwrite this method.
:return: ``None``
"""
return QSize(800, 600)

def updateTitle(self) -> None:
Expand All @@ -244,6 +258,11 @@ def updateTitle(self) -> None:
self.currentEditorWidget.updateTitle()

def onClipboardChanged(self) -> None:
"""
Slot called when the clipboard has changed.
:return: ``None``
"""
self.__logger.debug(f"Clipboard changed: {self.clipboard.text()}")

def OnScenePosChanged(self, x: float, y: float):
Expand Down Expand Up @@ -347,7 +366,12 @@ def closeEvent(self, event: QCloseEvent) -> None:
else:
event.ignore()

def quit(self):
def quit(self) -> None:
"""
Callback when the user decides to close the application.
:return: ``None``
"""
self.close()

def undo(self) -> None:
Expand Down Expand Up @@ -392,9 +416,7 @@ def copy(self) -> None:
"""
self.__logger.debug("Copying selected items")
if self.currentEditorWidget:
data = self.currentEditorWidget.scene.clipboard.serializeSelected(
delete=False
)
data = self.currentEditorWidget.scene.clipboard.serializeSelected()
strData = json.dumps(data, indent=4)
self.__logger.debug(strData)
self.clipboard.setText(strData)
Expand Down Expand Up @@ -472,6 +494,7 @@ def readSettings(self):
settings = QSettings(self.companyName, self.productName)
pos = settings.value("pos", QPoint(200, 200))
size = settings.value("size", QSize(400, 400))
self.debugMode = settings.value("debug", False)
self.move(pos)
self.resize(size)

Expand All @@ -482,6 +505,7 @@ def writeSettings(self):
settings = QSettings(self.companyName, self.productName)
settings.setValue("pos", self.pos())
settings.setValue("size", self.size())
settings.setValue("debug", self.debugMode)

def beforeSaveFileAs(
self, currentEditorWidget: EditorWidget, filename: str
Expand Down
62 changes: 31 additions & 31 deletions nodedge/graphics_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,33 @@ def __init__(
self.scene = scene
self.initUI()

def initUI(self):
def initUI(self) -> None:
"""Set up this ``QGraphicsScene``"""
self.initSizes()
self.initStyle()
self.setBackgroundBrush(self._color_background)
self.setBackgroundBrush(self._colorBackground)

# noinspection PyAttributeOutsideInit
def initStyle(self):
def initStyle(self) -> None:
"""Initialize ``QObjects`` like ``QColor``, ``QPten`` and ``QBrush``"""
self._color_background = QColor("#DFE0DC")
self._color_light = QColor("#ffffff")
self._color_dark = QColor("#ffffff")
self._colorBackground = QColor("#DFE0DC")
self._colorLight = QColor("#ffffff")
self._colorDark = QColor("#ffffff")

self._pen_light = QPen(self._color_light)
self._pen_light.setWidth(1)
self._penLight = QPen(self._colorLight)
self._penLight.setWidth(1)

self._pen_dark = QPen(self._color_dark)
self._pen_dark.setWidth(2)
self._penDark = QPen(self._colorDark)
self._penDark.setWidth(2)

# noinspection PyAttributeOutsideInit
def initSizes(self):
def initSizes(self) -> None:
"""Set up internal attributes like `grid_size`, `scene_width` and
`scene_height`. """
self.grid_size = 20
self.grid_squares = 5
self.scene_width = 64000
self.scene_height = 64000
self.gridSize = 20
self.gridSquares = 5
self.sceneWidth = 64000
self.sceneHeight = 64000

def setScene(self, width, height) -> None:
"""
Expand All @@ -94,38 +94,38 @@ def drawBackground(self, painter, rectangle) -> None:
top = int(math.floor(rectangle.top()))
bottom = int(math.ceil(rectangle.bottom()))

first_left = left - (left % self.grid_size)
first_top = top - (top % self.grid_size)
firstLeft = left - (left % self.gridSize)
first_top = top - (top % self.gridSize)

# Compute all lines to be drawn
lines_light, lines_dark = [], []
for x in range(first_left, right, self.grid_size):
linesLight, linesDark = [], []
for x in range(firstLeft, right, self.gridSize):
line = QLine(x, top, x, bottom)
if (x // self.grid_size) % self.grid_squares == 0:
lines_dark.append(line)
if (x // self.gridSize) % self.gridSquares == 0:
linesDark.append(line)
else:
lines_light.append(line)
linesLight.append(line)

for y in range(first_top, bottom, self.grid_size):
for y in range(first_top, bottom, self.gridSize):
line = QLine(left, y, right, y)
if (y // self.grid_size) % self.grid_squares == 0:
lines_dark.append(line)
if (y // self.gridSize) % self.gridSquares == 0:
linesDark.append(line)
else:
lines_light.append(line)
linesLight.append(line)

# Draw the lines
painter.setPen(self._pen_light)
painter.drawLines(*lines_light)
painter.setPen(self._penLight)
painter.drawLines(*linesLight)

painter.setPen(self._pen_dark)
painter.drawLines(*lines_dark)
painter.setPen(self._penDark)
painter.drawLines(*linesDark)

def dragMoveEvent(self, event: QGraphicsSceneDragDropEvent) -> None:
"""
Handle Qt's mouse's drag move event.
:param event: Mouse release event
:type event: ``QGraphicsSceneDragDropEvent``
:type event: ``QGraphicsSceneDragDropEvent.py``
"""
pass

Expand Down
28 changes: 22 additions & 6 deletions nodedge/mdi_area.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# -*- coding: utf-8 -*-
"""
<ModuleName> module containing :class:`~nodedge.<Name>.<ClassName>` class.
mdi_area module containing :class:`~nodedge.mdi_area.MdiArea` class.
"""
import logging
import os

from PyQt5.QtCore import QSize, Qt, pyqtSignal
from PyQt5.QtGui import QMouseEvent, QPainter, QPalette, QPixmap
from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QPalette, QPixmap
from PyQt5.QtWidgets import QMdiArea

from nodedge import DEBUG_ITEMS_PRESSED
from nodedge.utils import widgetsAt


class MdiArea(QMdiArea):
"""
:class:`~nodedge.mdi_area.MdiArea` class.
"""

itemsPressed = pyqtSignal(list)

def __init__(self, parent=None):
def __init__(self, parent=None) -> None:
self.__logger = logging.getLogger(__file__)
self.__logger.setLevel(logging.DEBUG)

Expand All @@ -31,7 +35,13 @@ def __init__(self, parent=None):
QSize(1024 * scale, 768 * scale), Qt.KeepAspectRatio
)

def paintEvent(self, event):
def paintEvent(self, event: QPaintEvent) -> None:
"""
Qt's paint event handle.
:param event:
:type event: ``QPaintEvent.py``
"""

painter = QPainter()
painter.begin(self.viewport())
Expand All @@ -42,8 +52,8 @@ def paintEvent(self, event):
)
else:
painter.fillRect(event.rect(), self.palette().color(QPalette.Window))
x = (self.width() - self.display_pixmap.width()) / 2
y = (self.height() - self.display_pixmap.height()) / 2
x: int = (self.width() - self.display_pixmap.width()) // 2
y: int = (self.height() - self.display_pixmap.height()) // 2
painter.drawPixmap(x, y, self.display_pixmap)

painter.end()
Expand All @@ -56,6 +66,12 @@ def paintEvent(self, event):
# )

def mousePressEvent(self, e: QMouseEvent) -> None:
"""
Qt's mouse press handle.
:param e:
:type e: ``QMouseEvent``
"""
if DEBUG_ITEMS_PRESSED:
pos = e.globalPos()
self.__logger.debug([w.__class__.__name__ for w in widgetsAt(pos)])
Expand Down
4 changes: 3 additions & 1 deletion nodedge/mdi_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def getNodeClassFromData(data):
return Node
return getClassFromOperationCode(data["operationCode"])

def addCloseEventListener(self, callback: Callable[[], None]):
def addCloseEventListener(
self, callback: Callable[[EditorWidget, QCloseEvent], None]
):
"""
Register callback for `Has Been Modified` event
Expand Down

0 comments on commit 835cb6a

Please sign in to comment.