class RepeatLegendItem(QGraphicsRectItem): Type = 70000 + 7 def __init__(self, color, parent = None): super(RepeatLegendItem, self).__init__(parent) # NOTE: need this distinction for cache mode based on # the Qt version otherwise rendering is broken if NO_ITEM_CACHING: self.setCacheMode(QGraphicsItem.NoCache) else: self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.setZValue(1) self.setFlag(QGraphicsItem.ItemIsMovable) self._position = self.pos() self.penColor = color self.itemHeight = 20 self.itemWidth = 40 self._pen = QPen() self._pen.setWidthF(3.0) self._pen.setColor(self.penColor) self.setPen(self._pen) self.setRect(0, 0, self.itemWidth, self.itemHeight) self.setAcceptsHoverEvents(True) self._outline = None @property def height(self): return self.itemHeight @property def width(self): return self.itemWidth @property def color(self): return self.penColor @color.setter def color(self, newColor): self.penColor = newColor self._pen.setColor(self.penColor) self.setPen(self._pen) def hoverEnterEvent(self, event): """ Stuff related to hover enter events. For now we just show a rectangular outline. """ if not self._outline: self._outline = QGraphicsRectItem(\ self.boundingRect().adjusted(-1,-1,1,1), self) highlightColor = QColor(Qt.blue) highlightColor.setAlpha(30) self._outline.setBrush(highlightColor) highlightPen = QPen(Qt.blue) highlightPen.setWidth(2) self._outline.setPen(highlightPen) else: self._outline.show() def hoverLeaveEvent(self, event): """ Stuff related to hover leave events. For now we just show a rectangular outline. """ self._outline.hide() def mousePressEvent(self, event): """ We reimplement this function to store the position of the item when a user issues a mouse press. """ self._position = self.pos() if (event.modifiers() & Qt.ControlModifier): QApplication.setOverrideCursor(QCursor(Qt.SizeAllCursor)) else: event.ignore() return QGraphicsRectItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ We reimplement this function to check if its position has changed since the last mouse click. If yes we let the canvas know so it can store the action as a Redo/Undo event. """ QApplication.restoreOverrideCursor() # this is needed for undo/redo if self._position != self.pos(): self.scene().canvas_item_position_changed(self, self._position, self.pos()) return QGraphicsRectItem.mouseReleaseEvent(self, event)
class PatternLegendItem(QGraphicsSvgItem): Type = 70000 + 2 def __init__(self, unitDim, width, height, defaultSymbol, defaultColor = QColor(Qt.white), zValue = 1, parent = None): super(PatternLegendItem, self).__init__(parent) # NOTE: need this distinction for cache mode based on # the Qt version otherwise rendering is broken if NO_ITEM_CACHING: self.setCacheMode(QGraphicsItem.NoCache) else: self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.setZValue(zValue) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.origin = QPointF(0.0, 0.0) self.unitDim = unitDim self.width = width self.height = height self.size = QSizeF(self.unitDim.width() * width, self.unitDim.height() * height) self.color = defaultColor self.symbol = None self._set_symbol(defaultSymbol) self._penSize = 1.0 self._pen = QPen() self._pen.setWidthF(self._penSize) self._pen.setJoinStyle(Qt.MiterJoin) self._pen.setColor(Qt.black) self.setAcceptsHoverEvents(True) self._outline = None def hoverEnterEvent(self, event): """ Stuff related to hover enter events. For now we just show a rectangular outline. """ if not self._outline: self._outline = QGraphicsRectItem(\ self.boundingRect().adjusted(-1,-1,1,1), self) highlightColor = QColor(Qt.blue) highlightColor.setAlpha(30) self._outline.setBrush(highlightColor) highlightPen = QPen(Qt.blue) highlightPen.setWidth(2) self._outline.setPen(highlightPen) else: self._outline.show() def hoverLeaveEvent(self, event): """ Stuff related to hover leave events. For now we just show a rectangular outline. """ self._outline.hide() def mousePressEvent(self, event): """ We reimplement this function to store the position of the item when a user issues a mouse press. """ self._position = self.pos() if (event.modifiers() & Qt.ControlModifier): QApplication.setOverrideCursor(QCursor(Qt.SizeAllCursor)) else: event.ignore() return QGraphicsSvgItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ We reimplement this function to check if its position has changed since the last mouse click. If yes we let the canvas know so it can store the action as a Redo/Undo event. """ QApplication.restoreOverrideCursor() # this is needed for redo/undo if self._position != self.pos(): self.scene().canvas_item_position_changed(self, self._position, self.pos()) return QGraphicsSvgItem.mouseReleaseEvent(self, event) def change_geometry(self, newDim): """ This slot changes the unit dimensions of the item. """ self.unitDim = newDim self.size = QSizeF(self.unitDim.width() * self.width, self.unitDim.height() * self.height) @property def name(self): """ Return the name of the knitting symbol we contain. """ return self.symbol["name"] def _set_symbol(self, newSymbol): """ Adds a new svg image of a knitting symbol to the scene. """ self.symbol = newSymbol svgPath = newSymbol["svgPath"] if not self.renderer().load(svgPath): errorMessage = ("PatternLegendItem._set_symbol: failed to load " "symbol %s" % svgPath) logger.error(errorMessage) return # apply color if present if "backgroundColor" in newSymbol: self.color = QColor(newSymbol["backgroundColor"]) def boundingRect(self): """ Return the bounding rectangle of the item. """ halfPen = self._penSize * 0.5 return QRectF(self.origin, self.size).adjusted(halfPen, halfPen, halfPen, halfPen) def paint(self, painter, option, widget): """ Paint ourselves. """ painter.setPen(self._pen) brush = QBrush(self.color) painter.setBrush(brush) halfPen = self._penSize * 0.5 painter.drawRect(\ QRectF(self.origin, self.size).adjusted(halfPen, halfPen, halfPen, halfPen)) self.renderer().render(painter, QRectF(self.origin, self.size))
class PatternLegendText(QGraphicsTextItem): Type = 70000 + 3 def __init__(self, text, parent = None): super(PatternLegendText, self).__init__(text, parent) # NOTE: need this distinction for cache mode based on # the Qt version otherwise rendering is broken if NO_ITEM_CACHING: self.setCacheMode(QGraphicsItem.NoCache) else: self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.setZValue(1) self.setFlag(QGraphicsItem.ItemIsMovable) self.setTextInteractionFlags(Qt.TextEditorInteraction) self._position = self.pos() self._outline = None def hoverEnterEvent(self, event): """ Stuff related to hover enter events. For now we just show a rectangular outline. """ if not self._outline: self._outline = QGraphicsRectItem(self.boundingRect(), self) highlightColor = QColor(Qt.blue) highlightColor.setAlpha(30) self._outline.setBrush(highlightColor) highlightPen = QPen(Qt.blue) highlightPen.setWidth(2) self._outline.setPen(highlightPen) else: self._outline.show() def hoverLeaveEvent(self, event): """ Stuff related to hover leave events. For now we just show a rectangular outline. """ self._outline.hide() def keyPressEvent(self, event): """ Stuff to do during key press events. For now we have to adjust the outline box. """ QGraphicsTextItem.keyPressEvent(self, event) self.adjust_size() def adjust_size(self): """ This function takes care of changing the size of the outline rectangle, e.g., when text is added or removed or during font size changes. """ if self._outline: self._outline.setRect(self.boundingRect()) def mousePressEvent(self, event): """ We reimplement this function to store the position of the item when a user issues a mouse press. """ self._position = self.pos() if (event.modifiers() & Qt.ControlModifier): QApplication.setOverrideCursor(QCursor(Qt.SizeAllCursor)) self.setTextInteractionFlags(Qt.NoTextInteraction) return QGraphicsTextItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ We reimplement this function to check if its position has changed since the last mouse click. If yes we let the canvas know so it can store the action as a Redo/Undo event. """ self.setTextInteractionFlags(Qt.TextEditorInteraction) QApplication.restoreOverrideCursor() # this is needed for undo/redo if self._position != self.pos(): self.scene().canvas_item_position_changed(self, self._position, self.pos()) return QGraphicsTextItem.mouseReleaseEvent(self, event)
class MJScene(QGraphicsScene): """our scene with a potential Qt bug fix""" def __init__(self): QGraphicsScene.__init__(self) self.__disableFocusRect = False self._focusBoard = None self.focusRect = QGraphicsRectItem() pen = QPen(QColor(Qt.blue)) pen.setWidth(6) self.focusRect.setPen(pen) self.addItem(self.focusRect) self.focusRect.setZValue(ZValues.marker) self.focusRect.hide() def __focusRectVisible(self): """should we show it?""" game = InternalParameters.field.game board = self._focusBoard return bool(not self.__disableFocusRect and board and board.hasFocus and board.focusTile and game and not game.autoPlay) @apply def disableFocusRect(): # pylint: disable=E0202 """suppress focusrect""" def fget(self): # pylint: disable=W0212 return self.__disableFocusRect def fset(self, value): # pylint: disable=W0212 # always place or hide, even if value does not change self.__disableFocusRect = value if value: self.focusRect.hide() else: self.placeFocusRect() return property(**locals()) @apply def focusBoard(): # pylint: disable=E0202 """get / set the board that has its focusRect shown""" def fget(self): # pylint: disable=W0212 return self._focusBoard def fset(self, board): # pylint: disable=W0212 self._focusBoard = board focusTile = board.focusTile if board else None if focusTile: focusTile.graphics.setFocus() self.placeFocusRect() self.focusRect.setVisible(self.__focusRectVisible()) return property(**locals()) def placeFocusRect(self): """show a blue rect around tile""" board = self._focusBoard if isAlive(board) and self.__focusRectVisible(): rect = board.tileFaceRect() rect.setWidth(rect.width()*board.focusRectWidth()) self.focusRect.setRect(rect) self.focusRect.setPos(board.focusTile.graphics.pos()) self.focusRect.setRotation(board.sceneRotation()) self.focusRect.setScale(board.scale()) self.focusRect.show() else: self.focusRect.hide() def graphicsTileItems(self): """returns all GraphicsTileItems in the scene""" return (x for x in self.items() if isinstance(x, GraphicsTileItem)) def nonTiles(self): """returns all other items in the scene""" return (x for x in self.items() if not isinstance(x, GraphicsTileItem)) def removeTiles(self): """remove all tiles from scene""" for item in self.graphicsTileItems(): self.removeItem(item) self.focusRect.hide()
class MJScene(QGraphicsScene): """our scene with a potential Qt bug fix""" def __init__(self): QGraphicsScene.__init__(self) self.__disableFocusRect = False self._focusBoard = None self.focusRect = QGraphicsRectItem() pen = QPen(QColor(Qt.blue)) pen.setWidth(6) self.focusRect.setPen(pen) self.addItem(self.focusRect) self.focusRect.setZValue(ZValues.marker) self.focusRect.hide() def focusInEvent(self, event): """work around a qt bug. See https://bugreports.qt-project.org/browse/QTBUG-32890 This can be reproduced as follows: ./kajongg.py --game=whatever --autoplay=SomeRuleset such that the human player is the first one to discard a tile. wait until the main screen has been built click with the mouse into the middle of that window press left arrow key this will violate the assertion in GraphicsTileItem.keyPressEvent """ prev = self.focusItem() QGraphicsScene.focusInEvent(self, event) if prev and bool(prev.flags() & QGraphicsItem.ItemIsFocusable) and prev != self.focusItem(): self.setFocusItem(prev) def __focusRectVisible(self): """should we show it?""" game = Internal.field.game board = self._focusBoard return bool(not self.__disableFocusRect and board and board.hasFocus and board.focusTile and game and not game.autoPlay) @property def disableFocusRect(self): """suppress focusrect""" return self.__disableFocusRect @disableFocusRect.setter def disableFocusRect(self, value): """always place or hide, even if value does not change""" self.__disableFocusRect = value if value: self.focusRect.hide() else: self.placeFocusRect() @property def focusBoard(self): """get / set the board that has its focusRect shown""" return self._focusBoard @focusBoard.setter def focusBoard(self, board): """get / set the board that has its focusRect shown""" self._focusBoard = board focusTile = board.focusTile if board else None if focusTile: focusTile.graphics.setFocus() self.placeFocusRect() self.focusRect.setVisible(self.__focusRectVisible()) def placeFocusRect(self): """show a blue rect around tile""" board = self._focusBoard if isAlive(board) and self.__focusRectVisible(): rect = board.tileFaceRect() rect.setWidth(rect.width()*board.focusRectWidth()) self.focusRect.setRect(rect) self.focusRect.setPos(board.focusTile.graphics.pos()) self.focusRect.setRotation(board.sceneRotation()) self.focusRect.setScale(board.scale()) self.focusRect.show() else: self.focusRect.hide() def graphicsTileItems(self): """returns all GraphicsTileItems in the scene""" return (x for x in self.items() if isinstance(x, GraphicsTileItem)) def nonTiles(self): """returns all other items in the scene""" return (x for x in self.items() if not isinstance(x, GraphicsTileItem)) def removeTiles(self): """remove all tiles from scene""" for item in self.graphicsTileItems(): self.removeItem(item) self.focusRect.hide()
class RepeatLegendItem(QGraphicsRectItem): Type = 70000 + 7 def __init__(self, color, parent=None): super(RepeatLegendItem, self).__init__(parent) # NOTE: need this distinction for cache mode based on # the Qt version otherwise rendering is broken if NO_ITEM_CACHING: self.setCacheMode(QGraphicsItem.NoCache) else: self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.setZValue(1) self.setFlag(QGraphicsItem.ItemIsMovable) self._position = self.pos() self.penColor = color self.itemHeight = 20 self.itemWidth = 40 self._pen = QPen() self._pen.setWidthF(3.0) self._pen.setColor(self.penColor) self.setPen(self._pen) self.setRect(0, 0, self.itemWidth, self.itemHeight) self.setAcceptsHoverEvents(True) self._outline = None @property def height(self): return self.itemHeight @property def width(self): return self.itemWidth @property def color(self): return self.penColor @color.setter def color(self, newColor): self.penColor = newColor self._pen.setColor(self.penColor) self.setPen(self._pen) def hoverEnterEvent(self, event): """ Stuff related to hover enter events. For now we just show a rectangular outline. """ if not self._outline: self._outline = QGraphicsRectItem(\ self.boundingRect().adjusted(-1,-1,1,1), self) highlightColor = QColor(Qt.blue) highlightColor.setAlpha(30) self._outline.setBrush(highlightColor) highlightPen = QPen(Qt.blue) highlightPen.setWidth(2) self._outline.setPen(highlightPen) else: self._outline.show() def hoverLeaveEvent(self, event): """ Stuff related to hover leave events. For now we just show a rectangular outline. """ self._outline.hide() def mousePressEvent(self, event): """ We reimplement this function to store the position of the item when a user issues a mouse press. """ self._position = self.pos() if (event.modifiers() & Qt.ControlModifier): QApplication.setOverrideCursor(QCursor(Qt.SizeAllCursor)) else: event.ignore() return QGraphicsRectItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ We reimplement this function to check if its position has changed since the last mouse click. If yes we let the canvas know so it can store the action as a Redo/Undo event. """ QApplication.restoreOverrideCursor() # this is needed for undo/redo if self._position != self.pos(): self.scene().canvas_item_position_changed(self, self._position, self.pos()) return QGraphicsRectItem.mouseReleaseEvent(self, event)
class PatternLegendText(QGraphicsTextItem): Type = 70000 + 3 def __init__(self, text, itemID=0, parent=None): super(PatternLegendText, self).__init__(text, parent) # NOTE: need this distinction for cache mode based on # the Qt version otherwise rendering is broken if NO_ITEM_CACHING: self.setCacheMode(QGraphicsItem.NoCache) else: self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.itemID = itemID self.setZValue(1) self.setFlag(QGraphicsItem.ItemIsMovable) self.setTextInteractionFlags(Qt.TextEditorInteraction) self._position = self.pos() self._outline = None def hoverEnterEvent(self, event): """ Stuff related to hover enter events. For now we just show a rectangular outline. """ if not self._outline: self._outline = QGraphicsRectItem(self.boundingRect(), self) highlightColor = QColor(Qt.blue) highlightColor.setAlpha(30) self._outline.setBrush(highlightColor) highlightPen = QPen(Qt.blue) highlightPen.setWidth(2) self._outline.setPen(highlightPen) else: self._outline.show() def hoverLeaveEvent(self, event): """ Stuff related to hover leave events. For now we just show a rectangular outline. """ self._outline.hide() def keyPressEvent(self, event): """ Stuff to do during key press events. For now we have to adjust the outline box. """ QGraphicsTextItem.keyPressEvent(self, event) self.adjust_size() def adjust_size(self): """ This function takes care of changing the size of the outline rectangle, e.g., when text is added or removed or during font size changes. """ if self._outline: self._outline.setRect(self.boundingRect()) def mousePressEvent(self, event): """ We reimplement this function to store the position of the item when a user issues a mouse press. """ self._position = self.pos() if (event.modifiers() & Qt.ControlModifier): QApplication.setOverrideCursor(QCursor(Qt.SizeAllCursor)) self.setTextInteractionFlags(Qt.NoTextInteraction) return QGraphicsTextItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ We reimplement this function to check if its position has changed since the last mouse click. If yes we let the canvas know so it can store the action as a Redo/Undo event. """ self.setTextInteractionFlags(Qt.TextEditorInteraction) QApplication.restoreOverrideCursor() # this is needed for undo/redo if self._position != self.pos(): self.scene().canvas_item_position_changed(self, self._position, self.pos()) return QGraphicsTextItem.mouseReleaseEvent(self, event)
class PatternLegendItem(QGraphicsSvgItem): Type = 70000 + 2 def __init__(self, unitDim, width, height, defaultSymbol, itemID=0, defaultColor=QColor(Qt.white), zValue=1, parent=None): super(PatternLegendItem, self).__init__(parent) # NOTE: need this distinction for cache mode based on # the Qt version otherwise rendering is broken if NO_ITEM_CACHING: self.setCacheMode(QGraphicsItem.NoCache) else: self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.itemID = itemID self.setZValue(zValue) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.origin = QPointF(0.0, 0.0) self.unitDim = unitDim self.width = width self.height = height self.size = QSizeF(self.unitDim.width() * width, self.unitDim.height() * height) self.color = defaultColor self.symbol = None self._set_symbol(defaultSymbol) self._penSize = 1.0 self._pen = QPen() self._pen.setWidthF(self._penSize) self._pen.setJoinStyle(Qt.MiterJoin) self._pen.setColor(Qt.black) self.setAcceptsHoverEvents(True) self._outline = None def hoverEnterEvent(self, event): """ Stuff related to hover enter events. For now we just show a rectangular outline. """ if not self._outline: self._outline = QGraphicsRectItem(\ self.boundingRect().adjusted(-1,-1,1,1), self) highlightColor = QColor(Qt.blue) highlightColor.setAlpha(30) self._outline.setBrush(highlightColor) highlightPen = QPen(Qt.blue) highlightPen.setWidth(2) self._outline.setPen(highlightPen) else: self._outline.show() def hoverLeaveEvent(self, event): """ Stuff related to hover leave events. For now we just show a rectangular outline. """ self._outline.hide() def mousePressEvent(self, event): """ We reimplement this function to store the position of the item when a user issues a mouse press. """ self._position = self.pos() if (event.modifiers() & Qt.ControlModifier): QApplication.setOverrideCursor(QCursor(Qt.SizeAllCursor)) else: event.ignore() return QGraphicsSvgItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ We reimplement this function to check if its position has changed since the last mouse click. If yes we let the canvas know so it can store the action as a Redo/Undo event. """ QApplication.restoreOverrideCursor() # this is needed for redo/undo if self._position != self.pos(): self.scene().canvas_item_position_changed(self, self._position, self.pos()) return QGraphicsSvgItem.mouseReleaseEvent(self, event) def change_geometry(self, newDim): """ This slot changes the unit dimensions of the item. """ self.unitDim = newDim self.size = QSizeF(self.unitDim.width() * self.width, self.unitDim.height() * self.height) @property def name(self): """ Return the name of the knitting symbol we contain. """ return self.symbol["name"] def _set_symbol(self, newSymbol): """ Adds a new svg image of a knitting symbol to the scene. """ self.symbol = newSymbol svgPath = newSymbol["svgPath"] if not self.renderer().load(svgPath): errorMessage = ("PatternLegendItem._set_symbol: failed to load " "symbol %s" % svgPath) logger.error(errorMessage) return # apply color if present if "backgroundColor" in newSymbol: self.color = QColor(newSymbol["backgroundColor"]) def boundingRect(self): """ Return the bounding rectangle of the item. """ halfPen = self._penSize * 0.5 return QRectF(self.origin, self.size).adjusted(halfPen, halfPen, halfPen, halfPen) def paint(self, painter, option, widget): """ Paint ourselves. """ painter.setPen(self._pen) brush = QBrush(self.color) painter.setBrush(brush) halfPen = self._penSize * 0.5 painter.drawRect(\ QRectF(self.origin, self.size).adjusted(halfPen, halfPen, halfPen, halfPen)) self.renderer().render(painter, QRectF(self.origin, self.size))