class GameWindow(QGraphicsView): def __init__(self, parent=None): super(GameWindow, self).__init__(parent=parent) self.screen = None self.scene = QGraphicsScene() self.scene.setSceneRect( QRect(left=0, top=0, width=PLAYGROUND_SIZEX * SCALE_FACTORX, height=PLAYGROUND_SIZEY * SCALE_FACTORY)) self.setFrameStyle(4) self.setScene(self.scene) self.snake = [] # define SnakeHead self.snake.append(QGraphicsRectItem()) self.snake[0].setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY)) self.snake[0].setBrush(brushHead) self.scene.addItem(self.snake[0]) # define rest of the snake for i in range(1, MAX_LENGTH_SNAKE): self.snake.append(QGraphicsRectItem()) self.snake[i].setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY)) self.snake[i].setBrush(brushBody) self.snake[i].setVisible(False) self.scene.addItem(self.snake[i]) # Create the graphic item for apple self.goal = QGraphicsRectItem() self.goal.setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY)) self.goal.setBrush(brushGoal) self.scene.addItem(self.goal) self.show() def draw(self, state): self.goal.setPos(state.goal.x * SCALE_FACTORX, state.goal.y * SCALE_FACTORY) self.goal.setVisible(True) self.snake[0].setPos(float(state.snake[0].x * SCALE_FACTORX), float(state.snake[0].y * SCALE_FACTORY)) for i in range(1, state.snake_length): self.snake[i].setPos(state.snake[i].x * SCALE_FACTORX, state.snake[i].y * SCALE_FACTORY) self.snake[i].setVisible(True) for i in range(state.snake_length, MAX_LENGTH_SNAKE): self.snake[i].setVisible(False) def screenshot(self): self.screen = self.grab() self.screen.save("./snake_screen.png")
class NotificationListItem(QGraphicsTextItem): def __init__(self): """Notification list graphics item. Used to show notifications for a ProjectItem """ super().__init__() self.bg = QGraphicsRectItem(self.boundingRect(), self) bg_brush = QApplication.palette().brush(QPalette.ToolTipBase) self.bg.setBrush(bg_brush) self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent) self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False) self.setZValue(2) def setHtml(self, html): super().setHtml(html) self.adjustSize() self.bg.setRect(self.boundingRect())
class ObjectLabelItem(QGraphicsTextItem): """Provides a label for ObjectItem's.""" entity_name_edited = Signal(str) def __init__(self, entity_item): """Initializes item. Args: entity_item (spinetoolbox.widgets.graph_view_graphics_items.EntityItem): The parent item. """ super().__init__(entity_item) self.entity_item = entity_item self._font = QApplication.font() self._font.setPointSize(11) self.setFont(self._font) self.bg = QGraphicsRectItem(self) self.bg_color = QGuiApplication.palette().color( QPalette.Normal, QPalette.ToolTipBase) self.bg_color.setAlphaF(0.8) self.bg.setBrush(QBrush(self.bg_color)) self.bg.setPen(Qt.NoPen) self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent) self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False) self.setAcceptHoverEvents(False) self._cursor = self.textCursor() self._text_backup = None def setPlainText(self, text): """Set texts and resets position. Args: text (str) """ super().setPlainText(text) self.reset_position() def reset_position(self): """Adapts item geometry so text is always centered.""" rectf = self.boundingRect() x = -rectf.width() / 2 y = rectf.height() + 4 self.setPos(x, y) self.bg.setRect(self.boundingRect())
class RankIcon(QGraphicsTextItem): def __init__(self, parent): """Rank icon graphics item. Used to show the rank of a ProjectItem within its DAG Args: parent (ProjectItemIcon): the parent item """ super().__init__(parent) self._parent = parent rect_w = parent.rect().width() # Parent rect width self.text_margin = 0.05 * rect_w self.bg = QGraphicsRectItem(self.boundingRect(), self) bg_brush = QApplication.palette().brush(QPalette.ToolTipBase) self.bg.setBrush(bg_brush) self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent) self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False) font = self.font() font.setPointSize(parent.text_font_size) font.setBold(True) self.setFont(font) doc = self.document() doc.setDocumentMargin(0) def set_rank(self, rank): self.setPlainText(str(rank)) self.adjustSize() self.setTextWidth(self.text_margin + self.textWidth()) self.bg.setRect(self.boundingRect()) # Align center fmt = QTextBlockFormat() fmt.setAlignment(Qt.AlignHCenter) cursor = self.textCursor() cursor.select(QTextCursor.Document) cursor.mergeBlockFormat(fmt) cursor.clearSelection() self.setTextCursor(cursor)
class EntityLabelItem(QGraphicsTextItem): """Label item for items in GraphViewForm.""" entity_name_edited = Signal(str) def __init__(self, entity_item): """Initializes item. Args: entity_item (spinetoolbox.widgets.graph_view_graphics_items.EntityItem): The parent item. """ super().__init__(entity_item) self.entity_item = entity_item self._font = QApplication.font() self._font.setPointSize(11) self.setFont(self._font) self.bg = QGraphicsRectItem(self) color = QGuiApplication.palette().color(QPalette.Normal, QPalette.ToolTipBase) color.setAlphaF(0.8) self.set_bg_color(color) self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent) self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False) self.setAcceptHoverEvents(False) self._cursor = self.textCursor() self._text_backup = None def setPlainText(self, text): """Set texts and resets position. Args: text (str) """ super().setPlainText(text) self.reset_position() def reset_position(self): """Adapts item geometry so text is always centered.""" rectf = self.boundingRect() x = -rectf.width() / 2 y = rectf.height() + 4 self.setPos(x, y) self.bg.setRect(self.boundingRect()) def set_bg_color(self, bg_color): """Sets background color. Args: bg_color (QColor) """ self.bg.setBrush(QBrush(bg_color)) def start_editing(self): """Starts editing.""" self.setTextInteractionFlags(Qt.TextEditorInteraction) self.setFocus() cursor = QTextCursor(self._cursor) cursor.select(QTextCursor.Document) self.setTextCursor(cursor) self._text_backup = self.toPlainText() def keyPressEvent(self, event): """Keeps text centered as the user types. Gives up focus when the user presses Enter or Return. Args: event (QKeyEvent) """ if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.clearFocus() elif event.key() == Qt.Key_Escape: self.setPlainText(self._text_backup) self.clearFocus() else: super().keyPressEvent(event) self.reset_position() def focusOutEvent(self, event): """Ends editing and sends entity_name_edited signal.""" super().focusOutEvent(event) self.setTextInteractionFlags(Qt.NoTextInteraction) self.entity_name_edited.emit(self.toPlainText()) self.setTextCursor(self._cursor) def mouseDoubleClickEvent(self, event): """Starts editing the name. Args: event (QGraphicsSceneMouseEvent) """ self.start_editing()
class MaskScene(QGraphicsScene): _stage_text = 'STAGE %s' def __init__(self, main_window, stage=1): super().__init__() self.main_window = main_window self.stage = stage self.upper_mask = QGraphicsRectItem(0, 0, content_width, 0) self.lower_mask = QGraphicsRectItem(0, content_height, content_width, 0) self.stage_text_item = QGraphicsTextItem() self.mask_height = 0 self.animation_timer_1 = QTimer() self.animation_timer_2 = QTimer() self.animation_timer_3 = QTimer() self.selected = None self.init() def init(self): mask_brush = QBrush() mask_brush.setColor(Qt.gray) mask_brush.setStyle(Qt.SolidPattern) mask_pen = QPen() mask_pen.setColor(Qt.gray) self.upper_mask.setBrush(mask_brush) self.lower_mask.setBrush(mask_brush) self.upper_mask.setPen(mask_pen) self.lower_mask.setPen(mask_pen) self.addItem(self.upper_mask) self.addItem(self.lower_mask) font = QFont() font.setPointSize(20) font.setBold(True) self.stage_text_item.setPlainText(self._stage_text % self.stage) self.stage_text_item.setFont(font) self.stage_text_item.setDefaultTextColor(Qt.black) self.stage_text_item.setX(content_width / 2 - int(self.stage_text_item.boundingRect().width() / 2)) self.stage_text_item.setY(content_height / 2 - int(self.stage_text_item.boundingRect().height() / 2)) self.animation_timer_1.setInterval(interval) self.animation_timer_1.timeout.connect(self.animation_in) self.animation_timer_2.setSingleShot(True) self.animation_timer_2.timeout.connect(self.animation_hold) self.animation_timer_2.setInterval(800) self.animation_timer_3.setInterval(interval) self.animation_timer_3.timeout.connect(self.animation_out) def next_stage(self): self.stage += 1 self.stage_text_item.setPlainText(self._stage_text % self.stage) def reset_stage(self): self.stage = 0 self.stage_text_item.setPlainText(self._stage_text % self.stage) def animation_in(self): self.mask_height += 10 finished = False if self.mask_height > content_height / 2: self.mask_height = content_height / 2 finished = True self.upper_mask.setRect(0, 0, content_width, self.mask_height) self.lower_mask.setRect(0, content_height - self.mask_height, content_width, self.mask_height) if finished: self.addItem(self.stage_text_item) self.animation_timer_1.stop() self.animation_timer_2.start() def animation_out(self): self.mask_height -= 10 finished = False if self.mask_height < 0: self.mask_height = 0 finished = True self.upper_mask.setRect(0, 0, content_width, self.mask_height) self.lower_mask.setRect(0, content_height - self.mask_height, content_width, self.mask_height) if finished: self.animation_timer_3.stop() self.main_window.start_game(self.selected) def animation_hold(self): self.removeItem(self.stage_text_item) self.animation_timer_3.start() self.main_window.enter_game_scene() def start_animation(self, selected: int): self.animation_timer_1.start() self.selected = selected
class MonitorItem(QGraphicsRectItem, QObject): z = 0 def __init__(self, *a, **kw): data = kw.pop("data") self.name = kw.pop("name") self.window = kw.pop("window") super().__init__(0, 0, 0, 0) self.setAcceptedMouseButtons(Qt.LeftButton) self.label = QGraphicsTextItem("", self) self.bottom_edge = QGraphicsRectItem(0, 0, 0, 0, self) self.bottom_edge.setBrush(QBrush("red", Qt.SolidPattern)) self.update_visuals(data) def update_visuals(self, monitor): self.setRect(0, 0, monitor.res_x, monitor.res_y) self.setPos(monitor.pos_x, monitor.pos_y) if monitor.orientation == "normal": self.bottom_edge.setRect(0, monitor.res_y - 50, monitor.res_x, 50) elif monitor.orientation == "left": self.bottom_edge.setRect(monitor.res_x - 50, 0, 50, monitor.res_y) elif monitor.orientation == "inverted": self.bottom_edge.setRect(0, 0, monitor.res_x, 50) elif monitor.orientation == "right": self.bottom_edge.setRect(0, 0, 50, monitor.res_y) if monitor.replica_of: label_text = f"{self.name} [{','.join(monitor.replica_of)}]" else: label_text = self.name self.label.setPlainText(label_text) label_scale = min( self.rect().width() / self.label.boundingRect().width(), self.rect().height() / self.label.boundingRect().height(), ) self.label.setScale(label_scale) if monitor.enabled: if monitor.primary: color = QColor("#eee8d5") color.setAlpha(200) self.setBrush(QBrush(color, Qt.SolidPattern)) self.setZValue(1000) else: color = QColor("#ffffff") color.setAlpha(200) self.setBrush(QBrush(color, Qt.SolidPattern)) self.setZValue(self.z) self.z -= 1 self.show() else: color = QColor("#f1f1f1") color.setAlpha(200) self.setBrush(QBrush(color, Qt.SolidPattern)) self.setZValue(-1000) self.hide() def mousePressEvent(self, event): self.window.pos_label.show() self.setCursor(Qt.ClosedHandCursor) self.orig_pos = self.pos() self.window.ui.screenCombo.setCurrentText(self.name) def mouseReleaseEvent(self, event): self.setCursor(Qt.OpenHandCursor) self.window.pos_label.hide() self.window.monitor_moved() def mouseMoveEvent(self, event): snaps_x, snaps_y = self.window.possible_snaps(self.name) view = event.widget().parent() click_pos = event.buttonDownScreenPos(Qt.LeftButton) current_pos = event.screenPos() new_pos = view.mapFromScene(self.orig_pos) + current_pos - click_pos new_pos = view.mapToScene(new_pos) delta = view.mapToScene(0, 20).y() if not event.modifiers() & Qt.AltModifier: # Check for snaps x = new_pos.x() delta_x = min((abs(x - sx), i) for i, sx in enumerate(snaps_x)) if delta_x[0] < delta: # snap new_pos.setX(int(snaps_x[delta_x[1]])) y = new_pos.y() delta_y = min((abs(y - sy), i) for i, sy in enumerate(snaps_y)) if delta_y[0] < delta: # snap new_pos.setY(int(snaps_y[delta_y[1]])) self.setPos(new_pos) self.window.show_pos(int(self.pos().x()), int(self.pos().y()))
class MonitorItem(QGraphicsRectItem, QObject): z = 0 def __init__(self, *a, **kw): data = kw.pop("data") self.name = kw.pop("name") self.window = kw.pop("window") super().__init__(0, 0, 0, 0) self.setAcceptedMouseButtons(Qt.LeftButton) self.label = QGraphicsTextItem("", self) self.bottom_edge = QGraphicsRectItem(0, 0, 0, 0, self) self.bottom_edge.setBrush(QBrush("red", Qt.SolidPattern)) self.update_visuals(data) def update_visuals(self, data): self.setRect(0, 0, data["res_x"], data["res_y"]) self.setPos(data["pos_x"], data["pos_y"]) if data["orientation"] == 0: self.bottom_edge.setRect(0, data["res_y"] - 50, data["res_x"], 50) elif data["orientation"] == 1: self.bottom_edge.setRect(data["res_x"] - 50, 0, 50, data["res_y"]) elif data["orientation"] == 2: self.bottom_edge.setRect(0, 0, data["res_x"], 50) elif data["orientation"] == 3: self.bottom_edge.setRect(0, 0, 50, data["res_y"]) if data["replica_of"]: label_text = f"{self.name} [{','.join(data['replica_of'])}]" else: label_text = self.name self.label.setPlainText(label_text) label_scale = min( self.rect().width() / self.label.boundingRect().width(), self.rect().height() / self.label.boundingRect().height(), ) self.label.setScale(label_scale) if data["enabled"]: if data["primary"]: color = QColor("#eee8d5") color.setAlpha(200) self.setBrush(QBrush(color, Qt.SolidPattern)) self.setZValue(1000) else: color = QColor("#ffffff") color.setAlpha(200) self.setBrush(QBrush(color, Qt.SolidPattern)) self.setZValue(self.z) self.z -= 1 else: color = QColor("#f1f1f1") color.setAlpha(200) self.setBrush(QBrush(color, Qt.SolidPattern)) self.setZValue(-1000) if not data["current_mode"]: # Disconnected or disabled self.hide() else: self.show() def mousePressEvent(self, event): self.window.pos_label.show() self.setCursor(Qt.ClosedHandCursor) self.orig_pos = self.pos() self.window.ui.screenCombo.setCurrentText(self.name) def mouseReleaseEvent(self, event): self.setCursor(Qt.OpenHandCursor) self.window.monitor_moved() self.window.pos_label.hide() def mouseMoveEvent(self, event): view = event.widget().parent() click_pos = event.buttonDownScreenPos(Qt.LeftButton) current_pos = event.screenPos() self.setPos( view.mapToScene( view.mapFromScene(self.orig_pos) + current_pos - click_pos)) self.window.show_pos(int(self.pos().x()), int(self.pos().y()))
class CanvasGraphicsView(QtWidgets.QGraphicsView): capture_complete = QtCore.Signal() def __init__(self, parent=None): super().__init__(parent) self.image = None self.rect_item = None self.start_pos = None def setup_scene(self, img: Image): #if img.mode != "RGB": #img = img.convert("RGB") self.image = img scene = CanvasGraphicsScene() self.setScene(scene) #scene固有の初期化 qtimg = ImageQt(self.image) pixmap = QPixmap.fromImage(qtimg).copy() pixmap_item = QGraphicsPixmapItem(pixmap) self.scene().addItem(pixmap_item) pixmap_item.setPos(0, 0) self.rect_item = QGraphicsRectItem(0, 0, 200, 200) self.rect_item.setPen(QPen(QtCore.Qt.blue, 3)) self.rect_item.hide() self.scene().addItem(self.rect_item) self.frame_rect_item = QGraphicsRectItem(0, 0, self.image.width - 3, self.image.height - 3) self.frame_rect_item.setPen(QPen(QtCore.Qt.red, 5)) self.scene().addItem(self.frame_rect_item) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) img = self.image self.setSceneRect(0, 0, img.width, img.height) self.setFixedSize(img.width, img.height) self._dragging = False pass def mousePressEvent(self, event): event.accept() if event.button() == QtCore.Qt.MouseButton.RightButton: #self._parent_window.accepted() self.capture_complete.emit() return else: self._dragging = True orig_pos = self.mapFromGlobal(QCursor.pos()) scene_pos = self.mapToScene(orig_pos) #self.rect_item.show() self.start_pos = scene_pos def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Escape: self.capture_complete.emit() def mouseMoveEvent(self, event): event.accept() if self._dragging: orig_pos = self.mapFromGlobal(QCursor.pos()) now_pos = self.mapToScene(orig_pos) s_x = self.start_pos.x() s_y = self.start_pos.y() n_x = now_pos.x() n_y = now_pos.y() self.rect_item.setRect(s_x, s_y, max(0, n_x - s_x), n_y - s_y) self.rect_item.show() def mouseReleaseEvent(self, event): event.accept() orig_pos = self.mapFromGlobal(QCursor.pos()) now_pos = self.mapToScene(orig_pos) s_x = self.start_pos.x() s_y = self.start_pos.y() n_x = now_pos.x() n_y = now_pos.y() data = {"rect": (s_x, s_y, n_x, n_y)} res = QtWidgets.QMessageBox.information(None, "確認", "この領域を保存しますか?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if res == QtWidgets.QMessageBox.Yes: import json with open(area_data_path, "w", encoding="utf-8") as f: json.dump(data, f) self.capture_complete.emit() self._dragging = False self.rect_item.hide()
class TextLineItem(QAbstractGraphicsShapeItem): """A one-line text item. Default origin point is at the left side of the baseline. This can change if setAlignMode is called. TextLineItem also supports drawing text background. Its brush can be set using setBackgroundBrush(). Text must not contain newline characters. """ def __init__(self, text=None, parent=None): super().__init__(parent) self._text = text or "" self._elided_text = text or "" self._elide_mode = Qt.ElideRight self._align_mode = Qt.AlignLeft self._max_width = None self._font = QFont() self._bounding_rect = QRectF() """Bounding and drawing rectangle. Determined automatically.""" self.background = QGraphicsRectItem(self) self.background.setPen(Qt.NoPen) self.background.setFlag(QGraphicsItem.ItemStacksBehindParent) self.adjust() def setText(self, text: str, /) -> None: if '\n' in text: raise ValueError("text must not contain newline characters") self.prepareGeometryChange() self._text = text self.adjust() def setElideMode(self, mode: int, /) -> None: """Elide mode specifies where the ellipsis should be located when the text is elided. Default value is Qt.ElideRight. """ self.prepareGeometryChange() self._elide_mode = mode self.adjust() def setAlignMode(self, mode: int, /) -> None: """Align mode specifies text alignment. Text alignment changes the origin point x position: - If mode is Qt.AlignLeft, the origin point is on the left of the baseline. - If mode is Qt.AlignHCenter, the origin point is in the center of the baseline. - If mode is Qt.AlignRight, the origin point is on the right of the baseline. Vertical alignment has no meaning for one line of text and should not be set. Default value is Qt.AlignLeft. """ self.prepareGeometryChange() self._align_mode = mode self.adjust() def setMaximumWidth(self, width, /): """Set the maximum width the text is allowed to be. `None` represents unlimited width.""" self.prepareGeometryChange() self._max_width = width self.adjust() def setFont(self, font: QFont, /) -> None: self.prepareGeometryChange() self._font = font self.adjust() def setBackgroundBrush(self, brush: QBrush, /): self.background.setBrush(brush) def text(self) -> str: return self._text def elidedText(self) -> str: return self._elided_text def elideMode(self) -> int: return self._elide_mode def alignMode(self) -> int: return self._align_mode def maximumWidth(self): """Maximum width the text is allowed to be. `None` represents unlimited width.""" return self._max_width def font(self) -> QFont: return self._font def backgroundBrush(self): return self.background.brush() def adjust(self): """Adjust the item's geometry in response to changes.""" metrics = QFontMetricsF(self.font()) # Get bounding rectangle for full text self._bounding_rect = metrics.boundingRect(self.text()) # Constrain by maximum width if self.maximumWidth() is not None: self._bounding_rect.setWidth(self.maximumWidth()) # Compute elided text self._elided_text = metrics.elidedText(self.text(), self.elideMode(), self.boundingRect().width()) # Get bounding rectangle for elided text self._bounding_rect = metrics.boundingRect(self.elidedText()) # It seems that for small characters like "..." the bounding rect returned is too small. Adjust it by a small # value. metrics_correction = px(1 / 72) self._bounding_rect.adjust(-metrics_correction, 0, metrics_correction, 0) # Move origin point according to the alignment if self.alignMode() & Qt.AlignLeft: self._bounding_rect.moveLeft(0) elif self.alignMode() & Qt.AlignRight: self._bounding_rect.moveRight(0) else: self._bounding_rect.moveLeft(-self._bounding_rect.width() / 2) # Set background rect self.background.setRect(self.boundingRect()) def boundingRect(self) -> QRectF: return self._bounding_rect def paint(self, painter: QPainter, option, widget=...) -> None: painter.setBrush(self.brush()) painter.setPen(self.pen()) painter.setFont(self.font()) painter.drawText(self.boundingRect(), self.alignMode(), self.elidedText())