def _updateLabel(self, isLeft): """ Called by updatePositionAndAppearance during init, or later by updateConnectivity. Updates drawing and position of the label. """ lbl = self._label if self._idx != None: if lbl == None: bw = _BASE_WIDTH num = self._partner_virtual_helix.number() tbr = _FM.tightBoundingRect(str(num)) half_label_h = tbr.height() / 2.0 half_label_w = tbr.width() / 2.0 # determine x and y positions labelX = bw / 2.0 - half_label_w if self._is_on_top: labelY = -0.25 * half_label_h - 0.5 - 0.5 * bw else: labelY = 2 * half_label_h + 0.5 + 0.5 * bw # adjust x for left vs right labelXoffset = 0.25 * bw if isLeft else -0.25 * bw labelX += labelXoffset # adjust x for numeral 1 if num == 1: labelX -= half_label_w / 2.0 # create text item lbl = QGraphicsSimpleTextItem(str(num), self) lbl.setPos(labelX, labelY) lbl.setBrush(_ENAB_BRUSH) lbl.setFont(_toHelixNumFont) self._label = lbl # end if lbl.setText(str(self._partner_virtual_helix.number()))
def update_items(self): self.item = QGraphicsRectItem(0, 0, self.width, self.row_h * self.coeff_h) seq_width = 0 nopen = QPen(Qt.NoPen) self.item.setPen(nopen) font = QFont(self.ftype, self.fsize) if self.fstyle == "italic": font.setStyle(QFont.StyleItalic) elif self.fstyle == "oblique": font.setStyle(QFont.StyleOblique) rect_cls = QGraphicsRectItem for i, val in enumerate(self.liste): width = self.col_w height = self.row_h * len(str(val)) + 1 rectitem = rect_cls(0, 0, width, height, parent=self.item) rectitem.setX(seq_width) # to give correct X to children item rectitem.setBrush(QBrush(QColor(self.bgcolor))) rectitem.setPen(nopen) # write letter if enough space in height if height >= self.fsize: text = QGraphicsSimpleTextItem(str(val), parent=rectitem) text.setFont(font) text.setBrush(QBrush(QColor(self.fgcolor))) # Center text according to rectitem size txtw = text.boundingRect().width() / 3.0 txth = text.boundingRect().height() text.setRotation(self.rot) text.setX(txth * 1.5) #text.setY(0) seq_width += width self.width = seq_width
def _updateLabel(self, is_left): """ Called by updatePositionAndAppearance during init, or later by updateConnectivity. Updates drawing and position of the label. """ lbl = self._label if self._idx != None: bw = _BASE_WIDTH num = self._partner_virtual_helix.number() tBR = _FM.tightBoundingRect(str(num)) half_label_h = tBR.height() / 2.0 half_label_w = tBR.width() / 2.0 # determine x and y positions label_x = bw / 2.0 - half_label_w if self._is_on_top: label_y = -0.25 * half_label_h - 0.5 - 0.5 * bw else: label_y = 2 * half_label_h + 0.5 + 0.5 * bw # adjust x for left vs right label_x_offset = 0.25 * bw if is_left else -0.25 * bw label_x += label_x_offset # adjust x for numeral 1 if num == 1: label_x -= half_label_w / 2.0 # create text item if lbl == None: lbl = QGraphicsSimpleTextItem(str(num), self) lbl.setPos(label_x, label_y) lbl.setBrush(_ENAB_BRUSH) lbl.setFont(_TO_HELIX_NUM_FONT) self._label = lbl lbl.setText(str(self._partner_virtual_helix.number())) lbl.show()
def drawGrid(self): black_notes = [2,4,6,9,11] scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano) scale_bar.setPos(self.piano_width, 0) scale_bar.setBrush(QColor(100,100,100)) clearpen = QPen(QColor(0,0,0,0)) for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1): for j in range(self.notes_in_octave, 0, -1): scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano) scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1)) scale_bar.setPen(clearpen) if j not in black_notes: scale_bar.setBrush(QColor(120,120,120)) else: scale_bar.setBrush(QColor(100,100,100)) measure_pen = QPen(QColor(0, 0, 0, 120), 3) half_measure_pen = QPen(QColor(0, 0, 0, 40), 2) line_pen = QPen(QColor(0, 0, 0, 40)) for i in range(0, int(self.num_measures) + 1): measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header) measure.setPos(self.measure_width * i, 0.5 * measure_pen.width()) measure.setPen(measure_pen) if i < self.num_measures: number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header) number.setPos(self.measure_width * i + 5, 2) number.setBrush(Qt.white) for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.): line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header) line.setZValue(1.0) line.setPos(self.measure_width * i + self.value_width * j, self.header_height) if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0: line.setPen(half_measure_pen) else: line.setPen(line_pen)
def _updateLabel(self, isLeft): """Called by updatePositionAndAppearance during init. Updates drawing and position of the label. Args: isLeft (TYPE): Description """ lbl = self._label if self._idx is not None: if lbl is None: bw = _BASE_WIDTH num = self._partner_virtual_helix_id_num tbr = _FM.tightBoundingRect(str(num)) half_label_h = tbr.height() / 2.0 half_label_w = tbr.width() / 2.0 # determine x and y positions labelX = bw / 2.0 - half_label_w if self.is_forward: labelY = -0.25 * half_label_h - 0.5 - 0.5 * bw else: labelY = 2 * half_label_h + 0.5 + 0.5 * bw # adjust x for left vs right labelXoffset = 0.25 * bw if isLeft else -0.25 * bw labelX += labelXoffset # adjust x for numeral 1 if num == 1: labelX -= half_label_w / 2.0 # create text item lbl = QGraphicsSimpleTextItem(str(num), self) lbl.setPos(labelX, labelY) lbl.setBrush(_ENAB_BRUSH) lbl.setFont(_toHelixNumFont) self._label = lbl # end if lbl.setText(str(self._partner_virtual_helix_id_num))
def __init__(self, x, y, width=STATION_WIDTH, height=STATION_HEIGHT, name=""): # 此处的初始化 xy 值是以 item coordinate 标记矩形的起始点(左上角) super().__init__(-width / 2, -height / 2, width, height) # 此处的 xy 值是以 scene coordinate 标记矩形,结合上面的初始化,标记点是矩形的几何中心 self.setPos(x, y) # 背景黑色 self.setBrush(black_brush) # icon(相对于父 item 的 xy 值) QGraphicsPixmapItem( QPixmap(RM_path("./source/station.png")).scaled( ICON_WIDTH, ICON_HEIGHT), self).setPos(-width / 2 + 8, -ICON_HEIGHT / 2) # name(相对于父 item 的 xy 值) name = QGraphicsSimpleTextItem(name, self) name.setBrush(white_brush) name.setFont(title_font) name.setPos(-width / 2 + 8 + ICON_WIDTH, -name.boundingRect().height() / 2)
def build_bonus_fields(self): for bonus_field in self._bonus_fields: brush = bonus_field["Brush"] pen = bonus_field["Pen"] bonus_fields = [] for coords in bonus_field["Coords"]: label = bonus_field["Name"] if coords == Coords.central(): label = '✸' square = self._board_squares[coords] square.setZValue(2) bonus_fields.append(square) field_name = QGraphicsSimpleTextItem(label) font = field_name.font() font.setPointSize(10) if coords == Coords.central(): font.setPointSize(20) fm = QFontMetrics(font) field_name.setZValue(2.1) field_name.setFont(font) x = coords.x * SQUARE_SIZE + (SQUARE_SIZE - fm.width(label)) / 2 y = coords.y * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2 field_name.setPos(x, y) field_name.setBrush(bonus_field["Label brush"]) self._labels[(x, y)] = field_name self.scene.addItem(field_name) paint_graphic_items(bonus_fields, pen, brush)
class FloatingTextWidget(QGraphicsWidget): def __init__(self, parent=None, anchor="center"): QGraphicsWidget.__init__(self, parent) assert anchor in {"center", "corner"} self.anchor = anchor self._label = QGraphicsSimpleTextItem(self) self._label.setBrush(QColor(255, 255, 255)) # Add drop shadow self._dropShadowEffect = QGraphicsDropShadowEffect() self.setGraphicsEffect(self._dropShadowEffect) self._dropShadowEffect.setOffset(0.0, 10.0) self._dropShadowEffect.setBlurRadius(8.0) self._dropShadowEffect.setColor(QColor(0, 0, 0, 50)) self._spacingConstant = 5.0 def updateLayout(self): width = self._label.boundingRect().width() height = self._label.boundingRect().height() width = self._spacingConstant + width + self._spacingConstant height = self._spacingConstant + height + self._spacingConstant self._label.setPos(self._spacingConstant, self._spacingConstant) self.resize(width, height) self.update() def paint(self, painter, option, widget): shape = QPainterPath() shape.addRoundedRect(self.rect(), 1, 1) painter.setBrush(QBrush(QColor(0, 0, 0))) painter.drawPath(shape) # painter.setPen(self._pen) # painter.drawPath(self._path) def onUpdated(self, center_position, text): self._label.setText(text) self.updateLayout() rect = self.rect() x_pos = center_position.x() y_pos = center_position.y() if self.anchor == "center": x_pos -= rect.width() / 2 y_pos -= rect.height() / 2 else: y_pos -= rect.height() self.setPos(x_pos, y_pos)
def add_points(self): points = QGraphicsSimpleTextItem(str(self.points), self) font = QFont("Verdana", 10) font_metrics = QFontMetrics(font) height = font_metrics.height() width = font_metrics.width(str(self.points)) points.setFont(font) points.setBrush(QBrush(SEA_GREEN)) points.setX(SQUARE_SIZE - MARGIN - width) points.setY(SQUARE_SIZE - MARGIN - height)
class WotNode(BaseNode): def __init__(self, nx_node, pos): """ Create node in the graph scene :param tuple nx_node: Node info :param x_y: Position of the node """ super().__init__(nx_node, pos) # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('black') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) text_color = QColor('grey') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('black') self.text_item.setBrush(QBrush(text_color)) # center ellipse around text self.setRect(0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2) # set anchor to the center self.setTransform(QTransform().translate( -self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # create gradient inside the ellipse gradient = QRadialGradient( QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) gradient.setColorAt(0, QColor('white')) gradient.setColorAt(1, QColor('darkgrey')) self.setBrush(QBrush(gradient)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1)
class BasicNode(QGraphicsItemGroup): def __init__(self, model, manager, text_color=Qt.black): bg_color = model.get_bg_color() super(BasicNode, self).__init__() self.model = model text = model.get_display_text() self.manager = manager self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.setFlag(QGraphicsItem.ItemIsFocusable, True) self.text_graph = QGraphicsSimpleTextItem(text) self.text_graph.setBrush(text_color) bound = self.text_graph.boundingRect() r = QPointF(bound.width() / 2, bound.height() / 2) text_center = self.text_graph.pos() + r self.text_graph.setPos(-text_center) self.addToGroup(self.text_graph) self.box_graph = BoxOutline(bg_color) empty_space = QPointF(UNIT, UNIT) newr = (empty_space + r) self.box_graph.rect = QRectF(-newr, newr) self.addToGroup(self.box_graph) self.text_graph.setZValue(1.0) self.box_graph.setZValue(0.0) self.children = [] def itemChange(self, change, value): if change == QGraphicsItem.ItemSelectedChange: self.manager.selection_changed(self, value) return value else: return super(BasicNode, self).itemChange(change, value) def get_width(self): return self.boundingRect().width() def set_left_pos(self, pos): pos += QPoint(self.get_width() / 2.0, 0) self.setPos(pos) def left_pos(self): return self.pos() - QPointF(self.get_width() / 2.0, 0) def center_pos(self): return self.pos() def right_pos(self): return self.pos() + QPointF(self.get_width() / 2.0, 0) """
class WotNode(BaseNode): def __init__(self, nx_node, pos): """ Create node in the graph scene :param tuple nx_node: Node info :param x_y: Position of the node """ super().__init__(nx_node, pos) # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('black') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) text_color = QColor('grey') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('black') self.text_item.setBrush(QBrush(text_color)) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) gradient.setColorAt(0, QColor('white')) gradient.setColorAt(1, QColor('darkgrey')) self.setBrush(QBrush(gradient)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1)
def create_chan_labels(self): """Create the channel labels, but don't plot them yet. Notes ----- It's necessary to have the width of the labels, so that we can adjust the main scene. """ self.idx_label = [] for one_grp in self.parent.channels.groups: for one_label in one_grp['chan_to_plot']: item = QGraphicsSimpleTextItem(one_label) item.setBrush(QBrush(QColor(one_grp['color']))) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.idx_label.append(item)
def __init__(self, i, video_item): self.video_item = video_item scene = QGraphicsScene() super().__init__(scene) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setStyleSheet("border-style: none") scene.setBackgroundBrush(QBrush(Qt.black)) scene.addItem(video_item) text = QGraphicsSimpleTextItem(str(i + 1)) font = QFont("Helvetica", 48) brush = QBrush(QColor.fromRgb(255, 255, 0)) text.setBrush(brush) text.setFont(font) text.setPos(50, 50) scene.addItem(text)
def build_exchange_zone(self): brush = QBrush(LIGHT_BROWN) pen = QPen(BROWN, 1, Qt.SolidLine) for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1): square = self.add_square(EXCHANGE_ROW, column, pen, brush) self._other_squares[Coords(column, EXCHANGE_ROW)] = square text = 'Litery do wymiany → ' font = QFont('Verdana', 10) fm = QFontMetrics(font) x = SQUARE_SIZE * LEFT_RACK_BOUND - fm.width(text) y = SQUARE_SIZE * EXCHANGE_ROW + (SQUARE_SIZE - fm.height()) / 2 label = QGraphicsSimpleTextItem(text) label.setPos(x, y) label.setFont(font) label.setBrush(QBrush(Qt.white)) self._labels[(x, y)] = label self.scene.addItem(label)
def updateGraphicsSimpleTextItem(textItem: QGraphicsSimpleTextItem, text: str = None, color: QColor = None, pos: QPointF = None, fontSize: int = 18): """ 更新普通文本QGraphicsSimpleTextItem属性 :param textItem: QGraphicsSimpleTextItem :param text: 显示文字 :param color: 文字颜色 :param pos: 文字位置 :param fontSize: 字体大小 """ if text: textItem.setText(text) if fontSize: font = QFont() font.setPointSize(fontSize) textItem.setFont(font) if color: textItem.setBrush(color) if pos: textItem.setPos(pos)
def init_ui(self): scene = QGraphicsScene() scene.setBackgroundBrush(QColor(100, 100, 100)) scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex) scene.setSceneRect(scene.itemsBoundingRect()) self.setDragMode(QGraphicsView.RubberBandDrag) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) self.frame_item = QGraphicsPixmapItem() self.text_item_offset = 0 self.rect_item_array = [] self.text_item_array = [] for i in range(0, 5): rect_item = QGraphicsRectItem() rect_item.setVisible(False) rect_item.setZValue(20.0) rect_item.setPen(QPen(Qt.red, 5)) rect_item.setRect(20, 20, 20, 20) scene.addItem(rect_item) self.rect_item_array.append(rect_item) text_item = QGraphicsSimpleTextItem("") text_item.setBrush(QBrush(Qt.red)) text_item.setZValue(20.0) text_item.setPos(10, 50) text_item.setFont(QFont("黑体", 24)) text_item.setVisible(False) scene.addItem(text_item) self.text_item_array.append(text_item) scene.addItem(self.frame_item) self.curr_factor = 1.0 self.setScene(scene)
def init_ui(self): scene = QGraphicsScene() scene.setBackgroundBrush(QColor(100, 100, 100)) scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex) scene.setSceneRect(scene.itemsBoundingRect()) self.setDragMode(QGraphicsView.RubberBandDrag) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) self.frame_item = QGraphicsPixmapItem() self.text_item_offset = 0 self.rect_item_array = [] self.text_item_array = [] for i in range(0, 5): rect_item = QGraphicsRectItem() rect_item.setVisible(False) rect_item.setZValue(20.0) rect_item.setPen(QPen(Qt.red, 5)) rect_item.setRect(20, 20, 20, 20) scene.addItem(rect_item) self.rect_item_array.append(rect_item) text_item = QGraphicsSimpleTextItem("") text_item.setBrush(QBrush(Qt.red)) text_item.setZValue(20.0) text_item.setPos(10, 50) text_item.setFont(QFont("黑体", 32)) text_item.setVisible(False) scene.addItem(text_item) self.text_item_array.append(text_item) scene.addItem(self.frame_item) self.curr_factor = 1.0 self.setScene(scene)
def _updateLabel(self, is_left): """Called by updatePositionAndAppearance during init. Updates drawing and position of the label. Args: is_left (TYPE): Description """ lbl = self._label if self._idx is not None: bw = _BASE_WIDTH num = self._partner_virtual_helix.idNum() tBR = _FM.tightBoundingRect(str(num)) half_label_h = tBR.height()/2.0 half_label_w = tBR.width()/2.0 # determine x and y positions label_x = bw/2.0 - half_label_w if self._is_on_top: label_y = -0.25*half_label_h - 0.5 - 0.5*bw else: label_y = 2*half_label_h + 0.5 + 0.5*bw # adjust x for left vs right label_x_offset = 0.25*bw if is_left else -0.25*bw label_x += label_x_offset # adjust x for numeral 1 if num == 1: label_x -= half_label_w/2.0 # create text item if lbl is None: lbl = QGraphicsSimpleTextItem(str(num), self) lbl.setPos(label_x, label_y) lbl.setBrush(_ENAB_BRUSH) lbl.setFont(_TO_HELIX_NUM_FONT) self._label = lbl lbl.setText(str(self._partner_virtual_helix.idNum())) lbl.show()
def build_labels(self): font = QFont('Verdana', 10) fm = QFontMetrics(font) for count in range(LAST_ROW + 1): number = str(count + 1) number_label = QGraphicsSimpleTextItem(number) x = -fm.width(number) - SQUARE_SIZE / 8 y = count * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2 number_label.setPos(x, y) number_label.setFont(font) number_label.setBrush(QBrush(Qt.white)) self._labels[(x, y)] = number_label letter = chr(count + ord('A')) letter_label = QGraphicsSimpleTextItem(letter) x = count * SQUARE_SIZE + (SQUARE_SIZE - fm.width(letter)) / 2 y = -fm.height() - SQUARE_SIZE / 8 letter_label.setPos(x, y) letter_label.setFont(font) letter_label.setBrush(QBrush(Qt.white)) self._labels[(x, y)] = letter_label self.scene.addItem(number_label) self.scene.addItem(letter_label)
class DigitalClock(Desklet): def __init__(self): super().__init__() self.seconds = QGraphicsSimpleTextItem(self.root) self.time = QGraphicsSimpleTextItem(self.root) self.date = QGraphicsSimpleTextItem(self.root) def set_style(self, style): super().set_style(style) self.seconds.setBrush(style.foreground_color) self.time.setBrush(style.foreground_color) self.date.setBrush(style.foreground_color) font = QFont(style.font) font.setPixelSize(192 * 0.5) self.seconds.setFont(font) font = QFont(style.font) font.setPixelSize(192 * 0.75) self.time.setFont(font) font = QFont(style.font) font.setPixelSize(56) self.date.setFont(font) self.layout() def set_rect(self, rect): super().set_rect(rect) self.layout() def layout(self): time_fm = QFontMetrics(self.time.font()) seconds_fm = QFontMetrics(self.seconds.font()) x = self.rect.left() y = self.rect.top() self.time.setPos(x, y) self.seconds.setPos(x + time_fm.width("00:00") + 20, y + time_fm.ascent() - seconds_fm.ascent()) self.date.setPos(x, y + time_fm.ascent()) def update(self, now): date = now.strftime("%A, %d. %B %Y") time = now.strftime("%H:%M") seconds = now.strftime("%S") self.time.setText(time) self.seconds.setText(seconds) self.date.setText(date)
class StopWatch(Desklet): def __init__(self): super().__init__() self.timer = Timer() self.timeout_handle = None self.qtimer = QTimer() self.qtimer.timeout.connect(self.my_update) self.label = QGraphicsSimpleTextItem("Stopwatch:", self.root) self.time = QGraphicsSimpleTextItem("00:00", self.root) self.seconds = QGraphicsSimpleTextItem("00'00", self.root) def update(self): t = self.timer.get_time() time = "%02d:%02d" % (t.seconds / (60 * 60), (t.seconds % (60 * 60)) / 60) seconds = "%02d'%02d" % (t.seconds % 60, t.microseconds / 10000) self.time.setText(time) self.seconds.setText(seconds) def set_style(self, style): super().set_style(style) font = QFont(style.font) font.setPixelSize(24) self.time.setFont(font) self.label.setFont(font) font = QFont(style.font) font.setPixelSize(192 / 2) self.time.setFont(font) font = QFont(style.font) font.setPixelSize(192 / 2 * 0.6) self.seconds.setFont(font) self.label.setBrush(self.style.foreground_color) self.time.setBrush(self.style.foreground_color) self.seconds.setBrush(self.style.foreground_color) self.layout() def set_rect(self, rect): super().set_rect(rect) self.layout() def layout(self): x = self.rect.left() y = self.rect.top() fm = QFontMetrics(self.time.font()) rect = fm.boundingRect("00:00") sfm = QFontMetrics(self.seconds.font()) self.time.setPos(x, y + 20) self.seconds.setPos(x + 20 + rect.width(), y + 20 + fm.ascent() - sfm.ascent()) self.label.setPos(x, y) def my_update(self): self.update() def is_running(self): return self.timer.is_running() def start_stop_watch(self): self.timer.start_stop() if self.timer.is_running(): self.qtimer.setInterval(31) self.qtimer.start() else: self.qtimer.stop() def clear_stop_watch(self): self.timer.reset()
class ExplorerNode(BaseNode): def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max, small): """ Create node in the graph scene :param tuple nx_node: Node info :param center_pos: The position of the center node :param nx_pos: Position of the nodes in the graph :param int steps: The steps from the center identity :param int steps_max: The steps max of the graph :param bool small: Small dots for big networks """ super().__init__(nx_node, nx_pos) self.steps = steps self.steps_max = steps_max self.highlighted = False self.status_sentry = False if small: self.setRect(0, 0, 10, 10) self.text_item = None else: # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) # center ellipse around text self.setRect(0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # set anchor to the center self.setTransform(QTransform().translate( -self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) # animation and moves self.timeline = None self.loading_timer = QTimer() self.loading_timer.timeout.connect(self.next_tick) self.loading_counter = 0 self._refresh_colors() self.setPos(center_pos) self.move_to(nx_pos) def update_metadata(self, metadata): super().update_metadata(metadata) self.status_sentry = self.metadata[ 'is_sentry'] if 'is_sentry' in self.metadata else False self._refresh_colors() def _refresh_colors(self): """ Refresh elements in the node """ # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_width = 2 if not self.status_member: outline_color = QColor('red') if self.status_sentry: outline_color = QColor('black') outline_width = 3 self.setPen(QPen(outline_color, outline_width, outline_style)) if self.highlighted: text_color = QColor('grey') else: text_color = QColor('black') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('grey') if self.text_item: self.text_item.setBrush(QBrush(text_color)) # create gradient inside the ellipse gradient = QRadialGradient( QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) color = QColor() color.setHsv(120 - 60 / self.steps_max * self.steps, 180 + 50 / self.steps_max * self.steps, 60 + 170 / self.steps_max * self.steps) if self.highlighted: color = color.darker(200) color = color.lighter( math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100) gradient.setColorAt(0, color) gradient.setColorAt(1, color.darker(150)) self.setBrush(QBrush(gradient)) def move_to(self, nx_pos): """ Move to corresponding position :param nx_pos: :return: """ origin_x = self.x() origin_y = self.y() final_x = nx_pos[self.id][0] final_y = nx_pos[self.id][1] def frame_move(frame): value = self.timeline.valueForTime(self.timeline.currentTime()) x = origin_x + (final_x - origin_x) * value y = origin_y + (final_y - origin_y) * value self.setPos(x, y) if self.scene(): self.scene().node_moved.emit(self.id, x, y) def timeline_ends(): self.setPos(final_x, final_y) self.timeline = None # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances. # They are not kept anywhere, even if you invoke QTimeLine.start(). self.timeline = QTimeLine(1000) self.timeline.setFrameRange(0, 100) self.timeline.frameChanged.connect(frame_move) self.timeline.finished.connect(timeline_ends) self.timeline.start() def highlight(self): """ Highlight the edge in the scene """ self.highlighted = True self._refresh_colors() self.update(self.boundingRect()) def neutralize(self): """ Neutralize the edge in the scene """ self.highlighted = False self._refresh_colors() self.update(self.boundingRect()) def start_loading_animation(self): """ Neutralize the edge in the scene """ if not self.loading_timer.isActive(): self.loading_timer.start(10) def stop_loading_animation(self): """ Neutralize the edge in the scene """ self.loading_timer.stop() self.loading_counter = 100 self._refresh_colors() self.update(self.boundingRect()) def next_tick(self): """ Next tick :return: """ self.loading_counter += 1 self.loading_counter %= 100 self._refresh_colors() self.update(self.boundingRect())
class Tile(Pixmap): """ Tile class defines on screen tiles """ anim_complete = pyqtSignal() # Signal for completion of animation sheet = None # Sprite sheet def __init__(self, letter, scene, letfile=r"\scrabble_letters.png"): self.alphabet = scene.alphabet if type(self).sheet is None: type(self).sheet = QPixmap(self.alphabet.lang + letfile) # Extract letter tile from sheet, scale to cell size for board image = type(self).sheet.copy(self.alphabet.TILE_POSITIONS[letter][0], self.alphabet.TILE_POSITIONS[letter][1], Cons.TILE_WIDTH, Cons.TILE_HEIGHT) image = image.scaled(Cons.WIDTH, Cons.HEIGHT, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) super(Tile, self).__init__(image) type(self).sheet = None self.letter = letter self.blank_letter = None self.rack_pos = QPointF() self.pos = QPointF() self.txt = None self.scene = scene self.alphabet = self.scene.alphabet self.pixmap_item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.pixmap_item.setTransform(QTransform()) self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton) self.pixmap_item.setZValue(1000) self.pixmap_item.letter = letter self.pixmap_item.tile = self self.pixmap_item.hide() # self.add_to_scene(self.scene) self.scene.addItem(self.pixmap_item) self.pos = QPointF(0, 0) self.animation = None self.fade = None # Draw at position (QPoint) on screen def draw_tile(self, position): """ Extract letter tile from sheet, scale to cell size for board draw at (xpos, ypos) """ self.pos = position self.pixmap_item.show() def get_pos(self): """ Return position of tile """ return self.pixmap_item.pos() def set_pos(self, x, y): """ Move tile to position (x, y) """ self.pixmap_item.setPos(x, y) def hand_cursor(self): """ Change cursor to hand cursor """ self.pixmap_item.setCursor(Qt.PointingHandCursor) def reset_cursor(self): """ Change cursor to pointer cursor """ self.pixmap_item.setCursor(Qt.ArrowCursor) def move_tile(self, dur, *args): """ Create move tile animation *args are time fraction, points in path either as (time, QPointF) or (time, x, y) """ if not self.pixmap_item.isVisible(): self.pixmap_item.setPos( QPointF(Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1])) self.pixmap_item.show() animation = QPropertyAnimation(self, b'pos') animation.setDuration(dur) for val in args: if isinstance(val[1], QPointF): point = val[1] else: point = QPointF(val[1], val[2]) animation.setKeyValueAt(val[0], point) self.animation = animation return self.animation def activate(self, activate): """ Accept mouse presses if activate is True """ if activate: self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton) else: self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton) def dim(self, activate): """ Dim tile if activate is True """ if activate: self.pixmap_item.setOpacity(0.4) else: self.pixmap_item.setOpacity(1) def set_in_board(self): """ Set tile in board No longer moveable """ self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton) def add_letter(self, letter): """ Add small letter to blank tile """ self.txt = QGraphicsSimpleTextItem(letter, self.pixmap_item) self.txt.setFont(QFont("Arial", 14, QFont.DemiBold)) self.txt.setBrush(QBrush(Qt.darkRed)) wd, ht = self.txt.boundingRect().width(), self.txt.boundingRect( ).height() self.txt.setPos((Cons.WIDTH - wd) / 2, (Cons.HEIGHT - ht) / 2) def get_tile(self): """ Move tile from store (bottom centre) to position on rack Used in Group Animation """ return self.move_tile( 1000, (0, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1]), (0.2, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, self.rack_pos.y()), (1, self.rack_pos)) def return_tile(self): """ Return tile to rack Used in Group Animation """ return self.move_tile(400, (0, self.get_pos()), (1, self.rack_pos)) def remove_tile(self): """ Remove tile from board Used in Group Animation """ return self.move_tile( 1000, (0, self.get_pos()), (0.8, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, self.get_pos().y()), (1, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1])) def lift_tile(self): """ Used in exchange tiles Lift chosen tile to set position above rack """ self.animation = self.move_tile( 100, (0, self.rack_pos), (1, self.rack_pos + QPointF(0, Cons.TILE_LIFT))) self.animation.start() def drop_tile(self): """ Used in exchange tiles Drop chosen tile back into rack """ self.animation = self.move_tile(100, (0, self.get_pos()), (1, self.rack_pos)) self.animation.start() def name_tile(self, player): """ Used in names screen Move chosen blank tiles to required position """ point = QPointF( Cons.INPUT_NAMES[player][0] + Cons.INPUT_NAMES[player][2], Cons.INPUT_NAMES[player][1] + 50) self.animation = self.move_tile(100, (0, self.get_pos()), (1, point)) self.animation.start() def return_blank(self): """ Used in names screen Return tile to position on board """ self.animation = self.move_tile(400, (0, self.get_pos()), (1, self.rack_pos)) self.animation.start() def unfade(self): """ Fade in letter on blank tile """ self.fade = QPropertyAnimation(self, b'opacity') self.fade.setDuration(2000) self.fade.setStartValue(0) self.fade.setEndValue(1) self.fade.setEasingCurve(QEasingCurve.InOutSine) self.fade.finished.connect(self._fade_end) self.fade.start() def _fade_end(self): """ end of animation """ self.anim_complete.emit() def hide(self): """ Hide tile """ self.pixmap_item.hide() def setZValue(self, val): """ set ZValue for image """ self.pixmap_item.setZValue(val)
class StickWidget(QGraphicsObject): font: QFont = QFont("monospace", 32) delete_clicked = pyqtSignal(Stick) link_initiated = pyqtSignal('PyQt_PyObject') # Actually StickWidget link_accepted = pyqtSignal('PyQt_PyObject') hovered = pyqtSignal(['PyQt_PyObject', 'PyQt_PyObject']) stick_changed = pyqtSignal('PyQt_PyObject') sibling_changed = pyqtSignal(bool) right_clicked = pyqtSignal('PyQt_PyObject') handle_idle_brush = QBrush(QColor(0, 125, 125, 50)) handle_hover_brush = QBrush(QColor(125, 125, 0, 50)) handle_press_brush = QBrush(QColor(200, 200, 0, 0)) handle_idle_pen = QPen(QColor(0, 0, 0, 255)) handle_press_pen = QPen(QColor(200, 200, 0, 255)) handle_size = 20 normal_color = QColor(0, 200, 120) negative_color = QColor(200, 0, 0) positive_color = QColor(0, 200, 0) mismatched = pyqtSignal('PyQt_PyObject') misplaced = pyqtSignal('PyQt_PyObject') measurement_corrected = pyqtSignal('PyQt_PyObject') clearly_visible = pyqtSignal('PyQt_PyObject') zero_clicked = pyqtSignal('PyQt_PyObject') def __init__(self, stick: Stick, camera: Camera, parent: Optional[QGraphicsItem] = None): QGraphicsObject.__init__(self, parent) self.camera = camera self.stick = stick self.line = QLineF() self.gline = QGraphicsLineItem(self.line) self.stick_label_text = QGraphicsSimpleTextItem("0", self) self.stick_label_text.setFont(StickWidget.font) self.stick_label_text.setPos(self.line.p1() - QPoint(0, 24)) self.stick_label_text.setBrush(QBrush(QColor(0, 255, 0))) self.stick_label_text.hide() self.setZValue(10) self.mode = StickMode.Display self.btn_delete = Button("delete", "x", parent=self) self.btn_delete.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.btn_delete.set_base_color([ButtonColor.RED]) self.btn_delete.setVisible(False) btn_size = max(int(np.linalg.norm(self.stick.top - self.stick.bottom) / 5.0), 15) self.btn_delete.set_height(12) self.btn_delete.clicked.connect(self.handle_btn_delete_clicked) self.btn_delete.setPos(self.line.p1() - QPointF(0.5 * self.btn_delete.boundingRect().width(), 1.1 * self.btn_delete.boundingRect().height())) self.btn_delete.set_opacity(0.7) self.top_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) self.mid_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) self.bottom_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) self.top_handle.setAcceptedMouseButtons(Qt.NoButton) self.mid_handle.setAcceptedMouseButtons(Qt.NoButton) self.bottom_handle.setAcceptedMouseButtons(Qt.NoButton) self.top_handle.setBrush(self.handle_idle_brush) self.top_handle.setPen(self.handle_idle_pen) self.mid_handle.setBrush(self.handle_idle_brush) self.mid_handle.setPen(self.handle_idle_pen) self.bottom_handle.setBrush(self.handle_idle_brush) self.bottom_handle.setPen(self.handle_idle_pen) self.hovered_handle: Optional[QGraphicsRectItem] = None self.handles = [self.top_handle, self.mid_handle, self.bottom_handle] self.link_button = Button("link", "Link to...", parent=self) self.link_button.set_base_color([ButtonColor.GREEN]) self.link_button.set_height(12) self.link_button.set_label("Link", direction="vertical") self.link_button.fit_to_contents() self.link_button.clicked.connect(lambda: self.link_initiated.emit(self)) self.link_button.setVisible(False) self.link_button.setFlag(QGraphicsObject.ItemIgnoresTransformations, False) self.adjust_line() self.setAcceptHoverEvents(True) self.top_handle.setZValue(4) self.bottom_handle.setZValue(4) self.mid_handle.setZValue(4) self.top_handle.hide() self.mid_handle.hide() self.bottom_handle.hide() self.handle_mouse_offset = QPointF(0, 0) self.available_for_linking = False self.link_source = False self.current_highlight_color: QColor = StickWidget.normal_color self.highlighted = False self.frame_color: Optional[None] = self.normal_color self.is_linked = False self.is_master = True self.selected = False self.measured_height: int = -1 self.current_color = self.normal_color self.show_label = False self.highlight_animation = QPropertyAnimation(self, b"highlight_color") self.highlight_animation.valueChanged.connect(self.handle_highlight_animation_value_changed) self.deleting = False self.update_tooltip() self.show_measurements: bool = False self.proposed_snow_height: int = -1 self.zero_btn = Button("zero_btn", "0", parent=self) self.zero_btn.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.zero_btn.setVisible(False) self.zero_btn.setPos(self.boundingRect().center() + QPointF(self.zero_btn.boundingRect().width() * -0.5, self.boundingRect().height() * 0.5)) self.zero_btn.clicked.connect(self.handle_zero) @pyqtSlot() def handle_btn_delete_clicked(self): self.delete_clicked.emit(self.stick) def prepare_for_deleting(self): self.deleting = True self.highlight_animation.stop() self.btn_delete.setParentItem(None) self.scene().removeItem(self.btn_delete) self.btn_delete.deleteLater() def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: Optional[PyQt5.QtWidgets.QWidget] = ...): painter.setPen(QPen(self.current_color, 1.0)) brush = QBrush(self.current_highlight_color) pen = QPen(brush, 4) painter.setPen(pen) if self.highlighted: painter.fillRect(self.boundingRect(), QBrush(self.current_highlight_color)) if self.frame_color is not None and self.mode != StickMode.Edit and self.mode != StickMode.EditDelete: painter.setPen(QPen(self.frame_color, 4)) painter.drawRect(self.boundingRect()) pen = QPen(QColor(0, 255, 0, 255)) pen.setWidth(1.0) pen.setColor(QColor(255, 0, 255, 255)) pen.setStyle(Qt.DotLine) painter.setPen(pen) off = 10 painter.drawLine(self.line.p1() - QPointF(0, off), self.line.p1() + QPointF(0, off)) painter.drawLine(self.line.p1() - QPointF(off, 0), self.line.p1() + QPointF(off, 0)) painter.drawLine(self.line.p2() - QPointF(0, off), self.line.p2() + QPointF(0, off)) painter.drawLine(self.line.p2() - QPointF(off, 0), self.line.p2() + QPointF(off, 0)) pen.setStyle(Qt.SolidLine) pen.setColor(QColor(0, 255, 0, 255)) painter.setPen(pen) if self.mode != StickMode.EditDelete: pen.setWidth(2.0) br = painter.brush() painter.setPen(pen) painter.drawEllipse(self.line.p1(), 10, 10) painter.drawEllipse(self.line.p2(), 10, 10) painter.setBrush(br) if self.mode == StickMode.Measurement and self.proposed_snow_height >= 0: point = QPointF(self.boundingRect().x(), -self.proposed_snow_height + self.line.p2().y()) pen = QPen(QColor(200, 100, 0, 255), 3.0) painter.setPen(pen) painter.drawLine(point, point + QPointF(self.boundingRect().width(), 0.0)) if self.measured_height >= 0: vec = (self.stick.top - self.stick.bottom) / np.linalg.norm(self.stick.top - self.stick.bottom) dist_along_stick = self.measured_height / np.dot(np.array([0.0, -1.0]), vec) point = self.line.p2() + dist_along_stick * QPointF(vec[0], vec[1]) point = QPointF(self.boundingRect().x(), point.y()) pen = QPen(QColor(0, 100, 200, 255), 3.0) painter.setPen(pen) painter.drawLine(point, point + QPointF(self.boundingRect().width(), 0.0)) else: painter.drawLine(self.line.p1(), self.line.p2()) if self.selected: pen.setColor(QColor(255, 125, 0, 255)) pen.setStyle(Qt.DashLine) painter.setPen(pen) painter.drawRect(self.boundingRect().marginsAdded(QMarginsF(5, 5, 5, 5))) if self.show_measurements: painter.fillRect(self.stick_label_text.boundingRect().translated(self.stick_label_text.pos()), QBrush(QColor(0, 0, 0, 120))) def boundingRect(self) -> PyQt5.QtCore.QRectF: return self.gline.boundingRect().united(self.top_handle.boundingRect()).\ united(self.mid_handle.boundingRect()).united(self.bottom_handle.boundingRect()) def set_edit_mode(self, value: bool): if value: self.set_mode(StickMode.EditDelete) else: self.set_mode(StickMode.Display) def set_mode(self, mode: StickMode): if mode == StickMode.Display: self.btn_delete.setVisible(False) self.top_handle.setVisible(False) self.mid_handle.setVisible(False) self.bottom_handle.setVisible(False) self.link_button.setVisible(False) self.available_for_linking = False self.link_source = False self.zero_btn.setVisible(False) self.setVisible(self.stick.is_visible) elif mode == StickMode.EditDelete: self.set_mode(StickMode.Display) self.top_handle.setVisible(True) self.mid_handle.setVisible(True) self.bottom_handle.setVisible(True) self.available_for_linking = False self.link_source = False self.btn_delete.setVisible(True) elif mode == StickMode.LinkSource: self.set_mode(StickMode.Display) self.link_source = True self.available_for_linking = False self.link_button.setPos(self.boundingRect().topLeft()) self.link_button.set_width(int(self.boundingRect().width())) self.link_button.set_button_height(int(self.boundingRect().height())) self.link_button.adjust_text_to_button() elif mode == StickMode.LinkTarget: self.set_mode(StickMode.Display) self.link_source = False self.available_for_linking = True elif mode == StickMode.Edit: self.set_mode(StickMode.EditDelete) self.btn_delete.setVisible(False) elif mode == StickMode.Measurement: self.zero_btn.setVisible(True) self.setVisible(True) self.mode = mode self.update_tooltip() self.update() def mousePressEvent(self, event: QGraphicsSceneMouseEvent): if self.mode != StickMode.EditDelete: return if self.hovered_handle is None: return self.hovered_handle.setBrush(self.handle_press_brush) if self.hovered_handle == self.mid_handle: self.bottom_handle.setBrush(self.handle_press_brush) self.bottom_handle.setPen(self.handle_press_pen) self.bottom_handle.setOpacity(0.5) self.top_handle.setBrush(self.handle_press_brush) self.top_handle.setPen(self.handle_press_pen) self.top_handle.setOpacity(0.5) self.hovered_handle.setPen(self.handle_press_pen) self.hovered_handle.setOpacity(0.5) self.handle_mouse_offset = self.hovered_handle.rect().center() - event.pos() self.btn_delete.setVisible(False) def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent): if self.available_for_linking: self.link_accepted.emit(self) return if self.mode == StickMode.Measurement: old_snow = self.stick.snow_height_px self.measured_height = self.proposed_snow_height self.stick.set_snow_height_px(self.proposed_snow_height) if abs(old_snow - self.proposed_snow_height) > 0: self.measurement_corrected.emit(self) self.proposed_snow_height = -1 if self.mode != StickMode.EditDelete and self.mode != StickMode.Edit: return if self.hovered_handle is not None: self.hovered_handle.setBrush(self.handle_hover_brush) self.hovered_handle.setPen(self.handle_idle_pen) self.hovered_handle.setOpacity(1.0) if self.hovered_handle == self.mid_handle: self.bottom_handle.setBrush(self.handle_idle_brush) self.bottom_handle.setPen(self.handle_idle_pen) self.bottom_handle.setOpacity(1.0) self.top_handle.setBrush(self.handle_idle_brush) self.top_handle.setPen(self.handle_idle_pen) self.top_handle.setOpacity(1.0) self.stick_changed.emit(self) self.hovered_handle = None if self.mode == StickMode.EditDelete: self.btn_delete.setVisible(True) def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent): if self.hovered_handle is None: return if self.hovered_handle == self.top_handle: self.line.setP1((event.pos() + self.handle_mouse_offset).toPoint()) elif self.hovered_handle == self.bottom_handle: self.line.setP2((event.pos() + self.handle_mouse_offset).toPoint()) else: displacement = event.pos() - event.lastPos() self.setPos(self.pos() + displacement) self.adjust_handles() self.adjust_stick() self.scene().update() def set_top(self, pos: QPoint): self.line.setP1(pos) self.adjust_handles() self.adjust_stick() self.scene().update() def set_bottom(self, pos: QPoint): self.line.setP2(pos) self.adjust_handles() self.adjust_stick() self.scene().update() def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent): if self.available_for_linking: self.hovered.emit(True, self) elif self.link_source: self.link_button.setVisible(True) self.scene().update() def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent): for h in self.handles: h.setBrush(self.handle_idle_brush) self.hovered_handle = None if self.available_for_linking: self.hovered.emit(False, self) self.link_button.setVisible(False) self.proposed_snow_height = -1 self.scene().update() def hoverMoveEvent(self, event: QGraphicsSceneHoverEvent): if self.mode != StickMode.EditDelete and self.mode != StickMode.Edit and self.mode != StickMode.Measurement: return if self.mode == StickMode.Measurement: self.proposed_snow_height = max(self.line.p2().y() - event.pos().y(), 0) self.update() return hovered_handle = list(filter(lambda h: h.rect().contains(event.pos()), self.handles)) if len(hovered_handle) == 0: if self.hovered_handle is not None: self.hovered_handle.setBrush(self.handle_idle_brush) self.hovered_handle = None return if self.hovered_handle is not None and self.hovered_handle != hovered_handle[0]: self.hovered_handle.setBrush(self.handle_idle_brush) self.hovered_handle = hovered_handle[0] if self.hovered_handle == self.top_handle: self.top_handle.setBrush(self.handle_hover_brush) elif self.hovered_handle == self.bottom_handle: self.bottom_handle.setBrush(self.handle_hover_brush) else: self.mid_handle.setBrush(self.handle_hover_brush) self.scene().update() def adjust_stick(self): self.stick.top[0] = self.pos().x() + self.line.p1().x() self.stick.top[1] = self.pos().y() + self.line.p1().y() self.stick.bottom[0] = self.pos().x() + self.line.p2().x() self.stick.bottom[1] = self.pos().y() + self.line.p2().y() def adjust_handles(self): if self.line.p1().y() > self.line.p2().y(): p1, p2 = self.line.p1(), self.line.p2() self.line.setP1(p2) self.line.setP2(p1) if self.hovered_handle is not None: self.hovered_handle.setBrush(self.handle_idle_brush) self.hovered_handle.setPen(self.handle_idle_pen) self.hovered_handle = self.top_handle if self.hovered_handle == self.bottom_handle else self.bottom_handle self.hovered_handle.setBrush(self.handle_press_brush) self.hovered_handle.setPen(self.handle_press_pen) rect = self.top_handle.rect() rect.moveCenter(self.line.p1()) self.top_handle.setRect(rect) rect = self.bottom_handle.rect() rect.moveCenter(self.line.p2()) self.bottom_handle.setRect(rect) rect = self.mid_handle.rect() rect.moveCenter(self.line.center()) self.mid_handle.setRect(rect) self.btn_delete.setPos(self.top_handle.rect().center() - QPointF(self.btn_delete.boundingRect().width() / 2, self.btn_delete.boundingRect().height() + self.top_handle.boundingRect().height() / 2)) def set_available_for_linking(self, available: bool): self.available_for_linking = available def set_is_link_source(self, is_source: bool): self.link_source = is_source self.link_button.setPos(self.boundingRect().topLeft()) self.link_button.set_width(int(self.boundingRect().width())) self.link_button.set_button_height(int(self.boundingRect().height())) self.link_button.adjust_text_to_button() def set_frame_color(self, color: Optional[QColor]): self.frame_color = color if color is not None else self.normal_color self.update() def set_is_linked(self, value: bool): self.is_linked = value if not self.is_linked: self.set_frame_color(None) if self.available_for_linking: self.highlight(QColor(0, 255, 0, 100)) else: self.highlight(None) self.update_tooltip() def adjust_line(self): self.setPos(QPointF(0.5 * (self.stick.top[0] + self.stick.bottom[0]), 0.5 * (self.stick.top[1] + self.stick.bottom[1]))) vec = 0.5 * (self.stick.top - self.stick.bottom) self.line.setP1(QPointF(vec[0], vec[1])) self.line.setP2(-self.line.p1()) self.gline.setLine(self.line) self.adjust_handles() self.stick_label_text.setPos(self.line.p1() - QPointF(0.5 * self.stick_label_text.boundingRect().width(), 1.3 * self.stick_label_text.boundingRect().height())) self.update() def set_selected(self, selected: bool): self.selected = selected self.update() def is_selected(self) -> bool: return self.selected def set_snow_height(self, height: int): self.measured_height = height self.update() def border_normal(self): self.current_color = self.normal_color self.update() def border_positive(self): self.current_color = self.positive_color self.update() def border_negative(self): self.current_color = self.negative_color self.update() @pyqtProperty(QColor) def highlight_color(self) -> QColor: return self.current_highlight_color @highlight_color.setter def highlight_color(self, color: QColor): self.current_highlight_color = color def highlight(self, color: Optional[QColor], animated: bool = False): self.highlighted = color is not None if not animated or color is None: self.highlight_animation.stop() self.current_highlight_color = self.normal_color if color is None else color self.update() return self.highlight_animation.setStartValue(color) self.highlight_animation.setEndValue(color) self.highlight_animation.setKeyValueAt(0.5, color.darker()) self.highlight_animation.setDuration(2000) self.highlight_animation.setLoopCount(-1) self.highlight_animation.start() def handle_link_button_hovered(self, btn: Dict[str, Any]): self.link_button.setVisible(btn['hovered']) def handle_highlight_animation_value_changed(self, new: QColor): if not self.deleting: self.update(self.boundingRect().marginsAdded(QMarginsF(10, 10, 10, 10))) def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None: self.right_clicked.emit({'stick_widget': self}) def set_stick_label(self, label: str): self.stick.label = label self.stick_label_text.setText(label) self.update_tooltip() self.update() def get_stick_label(self) -> str: return self.stick.label def get_stick_length_cm(self) -> int: return self.stick.length_cm def set_stick_length_cm(self, length: int): self.stick.length_cm = length self.update_tooltip() self.update() def update_tooltip(self): if self.mode != StickMode.Display or self.mode == StickMode.Measurement: self.setToolTip("") return snow_txt = "Snow height: " if self.stick.snow_height_px >= 0: snow_txt += str(self.stick.snow_height_cm) + " cm" self.stick_label_text.setText(str(self.stick.snow_height_cm)) else: snow_txt = "not measured" self.stick_label_text.setVisible(False) self.stick_label_text.setText(self.stick.label) self.stick_label_text.setVisible(True) stick_view_text = '' role = '' if self.stick.alternative_view is not None: alt_view = self.stick.alternative_view role = " - primary" alt = "Secondary" if not self.stick.primary: role = " - secondary" alt = "Primary" stick_view_text = f'\n{alt} view: {alt_view.label} in {alt_view.camera_folder.name}\n' mark = '*' if self.stick.determines_quality else '' self.setToolTip(f'{mark}{self.stick.label}{role}{stick_view_text}\nLength: {self.stick.length_cm} cm\n{snow_txt}') def set_stick(self, stick: Stick): self.reset_d_btns() self.stick = stick self.adjust_line() self.adjust_handles() self.set_snow_height(stick.snow_height_px) self.update_tooltip() self.set_show_measurements(self.show_measurements) if self.mode == StickMode.Measurement: self.set_frame_color(QColor(200, 100, 0, 100) if not self.stick.is_visible else None) self.setVisible(True) self.clearly_visible_btn.setVisible(not self.stick.is_visible) else: self.setVisible(self.stick.is_visible) def set_show_measurements(self, show: bool): self.show_measurements = show if self.show_measurements: self.stick_label_text.setText(str(self.stick.snow_height_cm) if self.stick.snow_height_cm >= 0 else "n/a") else: self.stick_label_text.setText(self.stick.label) self.update() def handle_zero(self): self.measured_height = 0 self.stick.set_snow_height_px(0) self.measurement_corrected.emit(self) def reset_d_btns(self): self.zero_btn.set_default_state()
class EdgeItem(GraphItem): _qt_pen_styles = { 'dashed': Qt.DashLine, 'dotted': Qt.DotLine, 'solid': Qt.SolidLine, } def __init__(self, highlight_level, spline, label_center, label, from_node, to_node, parent=None, penwidth=1, edge_color=None, style='solid'): super(EdgeItem, self).__init__(highlight_level, parent) self.from_node = from_node self.from_node.add_outgoing_edge(self) self.to_node = to_node self.to_node.add_incoming_edge(self) self._default_edge_color = self._COLOR_BLACK if edge_color is not None: self._default_edge_color = edge_color self._default_text_color = self._COLOR_BLACK self._default_color = self._COLOR_BLACK self._text_brush = QBrush(self._default_color) self._shape_brush = QBrush(self._default_color) if style in ['dashed', 'dotted']: self._shape_brush = QBrush(Qt.transparent) self._label_pen = QPen() self._label_pen.setColor(self._default_text_color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._edge_pen = QPen(self._label_pen) self._edge_pen.setWidth(penwidth) self._edge_pen.setColor(self._default_edge_color) self._edge_pen.setStyle(self._qt_pen_styles.get(style, Qt.SolidLine)) self._sibling_edges = set() self._label = None if label is not None: self._label = QGraphicsSimpleTextItem(label) self._label.setFont(GraphItem._LABEL_FONT) label_rect = self._label.boundingRect() label_rect.moveCenter(label_center) self._label.setPos(label_rect.x(), label_rect.y()) self._label.hoverEnterEvent = self._handle_hoverEnterEvent self._label.hoverLeaveEvent = self._handle_hoverLeaveEvent self._label.setAcceptHoverEvents(True) # spline specification according to # http://www.graphviz.org/doc/info/attrs.html#k:splineType coordinates = spline.split(' ') # extract optional end_point end_point = None if (coordinates[0].startswith('e,')): parts = coordinates.pop(0)[2:].split(',') end_point = QPointF(float(parts[0]), -float(parts[1])) # extract optional start_point if (coordinates[0].startswith('s,')): parts = coordinates.pop(0).split(',') # first point parts = coordinates.pop(0).split(',') point = QPointF(float(parts[0]), -float(parts[1])) path = QPainterPath(point) while len(coordinates) > 2: # extract triple of points for a cubic spline parts = coordinates.pop(0).split(',') point1 = QPointF(float(parts[0]), -float(parts[1])) parts = coordinates.pop(0).split(',') point2 = QPointF(float(parts[0]), -float(parts[1])) parts = coordinates.pop(0).split(',') point3 = QPointF(float(parts[0]), -float(parts[1])) path.cubicTo(point1, point2, point3) self._arrow = None if end_point is not None: # draw arrow self._arrow = QGraphicsPolygonItem() polygon = QPolygonF() polygon.append(point3) offset = QPointF(end_point - point3) corner1 = QPointF(-offset.y(), offset.x()) * 0.35 corner2 = QPointF(offset.y(), -offset.x()) * 0.35 polygon.append(point3 + corner1) polygon.append(end_point) polygon.append(point3 + corner2) self._arrow.setPolygon(polygon) self._arrow.hoverEnterEvent = self._handle_hoverEnterEvent self._arrow.hoverLeaveEvent = self._handle_hoverLeaveEvent self._arrow.setAcceptHoverEvents(True) self._path = QGraphicsPathItem(parent) self._path.setPath(path) self.addToGroup(self._path) self.set_node_color() self.set_label_color() def add_to_scene(self, scene): scene.addItem(self) if self._label is not None: scene.addItem(self._label) if self._arrow is not None: scene.addItem(self._arrow) def setToolTip(self, tool_tip): super(EdgeItem, self).setToolTip(tool_tip) if self._label is not None: self._label.setToolTip(tool_tip) if self._arrow is not None: self._arrow.setToolTip(tool_tip) def add_sibling_edge(self, edge): self._sibling_edges.add(edge) def set_node_color(self, color=None): if color is None: self._label_pen.setColor(self._default_text_color) self._text_brush.setColor(self._default_color) if self._shape_brush.isOpaque(): self._shape_brush.setColor(self._default_edge_color) self._edge_pen.setColor(self._default_edge_color) else: self._label_pen.setColor(color) self._text_brush.setColor(color) if self._shape_brush.isOpaque(): self._shape_brush.setColor(color) self._edge_pen.setColor(color) self._path.setPen(self._edge_pen) if self._arrow is not None: self._arrow.setBrush(self._shape_brush) self._arrow.setPen(self._edge_pen) def set_label_color(self, color=None): if color is None: self._label_pen.setColor(self._default_text_color) else: self._label_pen.setColor(color) if self._label is not None: self._label.setBrush(self._text_brush) self._label.setPen(self._label_pen) def _handle_hoverEnterEvent(self, event): # hovered edge item in red self.set_node_color(self._COLOR_RED) self.set_label_color(self._COLOR_RED) if self._highlight_level > 1: if self.from_node != self.to_node: # from-node in blue self.from_node.set_node_color(self._COLOR_BLUE) # to-node in green self.to_node.set_node_color(self._COLOR_GREEN) else: # from-node/in-node in teal self.from_node.set_node_color(self._COLOR_TEAL) self.to_node.set_node_color(self._COLOR_TEAL) if self._highlight_level > 2: # sibling edges in orange for sibling_edge in self._sibling_edges: sibling_edge.set_node_color(self._COLOR_ORANGE) def _handle_hoverLeaveEvent(self, event): self.set_node_color() self.set_label_color() if self._highlight_level > 1: self.from_node.set_node_color() self.to_node.set_node_color() if self._highlight_level > 2: for sibling_edge in self._sibling_edges: sibling_edge.set_node_color()
class Scene(QGraphicsScene): def __init__(self, parent=None): QGraphicsScene.__init__(self, parent) # set pritisnutih tastera self.keys_pressed = set() # pozadina self.bg = QGraphicsRectItem() self.bg.setRect(-1, -1, SCREEN_WIDTH + 2, SCREEN_HEIGHT + 2) self.bg.setBrush(QBrush(Qt.black)) self.addItem(self.bg) # brojaci za pomeranje protivnika self.left = 1 self.right = 5 # lista protivnika self.enemies = [] # nasumicni indeks protivnika koji puca self.randomEnemyIndex = randint(0, len(self.enemies)) # nasumicna lista indeksa protivnika koji ce imati specijalnu moc self.enemyPowerUps = [] # pravljenje i iscrtavanje protivnika self.threadFinished = False _thread.start_new_thread(self.draw_enemies, ()) while not self.threadFinished: continue self.threadFinished = False # igrac 1 (plavi) self.player1 = Player1() self.player1.setPos(20, 530) self.addItem(self.player1) # igrac 2 (crveni) self.player2 = Player2() self.player2.setPos(589, 530) self.addItem(self.player2) # metak igraca 1 (plavi) self.bullet1 = Bullet1(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y) self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet1) # metak igraca 2 (crveni) self.bullet2 = Bullet2(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y) self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet2) # pobednik self.winner = 0 # power up i power down igraca 1 (plavi) self.player1PowerUp = QGraphicsPixmapItem() self.player1PowerUp.setPixmap(QPixmap("Images/powerUp.png")) self.player1PowerDown = QGraphicsPixmapItem() self.player1PowerDown.setPixmap(QPixmap("Images/powerDown.png")) # power up i power down igraca 2 (crveni) self.player2PowerUp = QGraphicsPixmapItem() self.player2PowerUp.setPixmap(QPixmap("Images/powerUp.png")) self.player2PowerDown = QGraphicsPixmapItem() self.player2PowerDown.setPixmap(QPixmap("Images/powerDown.png")) # protivnicki metak (narandzasti) self.bulletEnemy = BulletEnemy(ENEMY_BULLET_X_OFFSET, ENEMY_BULLET_Y_OFFSET) self.bulletEnemy.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bulletEnemy) # polje za rezultate self.scoreField = QGraphicsRectItem() self.scoreField.setRect(672, -1, 128, SCREEN_HEIGHT + 2) self.scoreField.setBrush(QBrush(Qt.darkGray)) self.addItem(self.scoreField) # trenutni nivo self.level = 1 # iscrtavanje trenutnog nivoa self.levelFont = QFont() self.levelFont.setPixelSize(25) self.levelFont.setBold(1) self.levelField = QGraphicsSimpleTextItem("Level: " + str(self.level)) self.levelField.setBrush(QBrush(Qt.green)) self.levelField.setPos(677, 20) self.levelField.setFont(self.levelFont) self.addItem(self.levelField) self.playerFont = QFont() self.playerFont.setPixelSize(20) self.playerFont.setBold(1) # iscrtavanje broja zivota igraca 1 self.player1Lives = QGraphicsSimpleTextItem("Player 1: ") self.player1Lives.setBrush(QBrush(Qt.blue)) self.player1Lives.setPos(674, 130) self.player1Lives.setFont(self.playerFont) self.addItem(self.player1Lives) self.livesPlayer1 = [ LifePlayer1(680, 175), LifePlayer1(720, 175), LifePlayer1(760, 175) ] for l in self.livesPlayer1: self.addItem(l) # iscrtavanje broja zivota igraca 2 self.player2Lives = QGraphicsSimpleTextItem("Player 2: ") self.player2Lives.setBrush(QBrush(Qt.blue)) self.player2Lives.setPos(674, 330) self.player2Lives.setFont(self.playerFont) self.addItem(self.player2Lives) self.livesPlayer2 = [ LifePlayer2(680, 375), LifePlayer2(720, 375), LifePlayer2(760, 375) ] for l in self.livesPlayer2: self.addItem(l) self.scoreFont = QFont() self.scoreFont.setPixelSize(20) self.scoreFont.setBold(1) # iscrtavanje rezultata igraca 1 self.player1Score = 0 self.player1Scores = QGraphicsSimpleTextItem("Score: \n" + str(self.player1Score)) self.player1Scores.setBrush(QBrush(Qt.blue)) self.player1Scores.setPos(674, 220) self.player1Scores.setFont(self.scoreFont) self.addItem(self.player1Scores) # iscrtavanje rezultata igraca 1 self.player2Score = 0 self.player2Scores = QGraphicsSimpleTextItem("Score: \n" + str(self.player2Score)) self.player2Scores.setBrush(QBrush(Qt.blue)) self.player2Scores.setPos(674, 420) self.player2Scores.setFont(self.scoreFont) self.addItem(self.player2Scores) # tajmer za iscrtavanje slike 60 puta u sekndi (60 fps) self.timer = QBasicTimer() self.timer.start(16, self) # tajmer za pomeranje neprijatelja self.timerEnemy = QTimer() self.timerEnemy.timeout.connect(self.game_update_enemy) self.timerEnemy.start(1000) # icrtavanje scene self.view = QGraphicsView(self) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.show() self.view.setFixedSize(SCREEN_WIDTH, SCREEN_HEIGHT) self.setSceneRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) self.view.setGeometry(560, 240, 0, 0) def keyPressEvent(self, event): self.keys_pressed.add(event.key()) def keyReleaseEvent(self, event): self.keys_pressed.remove(event.key()) def timerEvent(self, event): self.game_update() self.update() def game_update(self): self.player1.game_update(self.keys_pressed) self.player2.game_update(self.keys_pressed) for e in self.enemies: # ako je neprijatelj zavrsio sa padanjem, brisemo ga if e.frames == -1: self.removeItem(e) self.enemies.remove(e) continue # ako je neprijatelj izabran za padanje, nastavlja da pada if e.chosen: e.collapse() # igrac 1 pogodio neprijatelja if e.x() <= self.bullet1.x() <= e.x() + 32: if e.y() <= self.bullet1.y() <= e.y() + 26: if e.powerUp: temp = randint(0, 3) if temp == 0: if self.player1.speed == 2: self.removeItem(self.player1PowerDown) self.player1.speed = 8 self.player1PowerUp.setPos(770, 130) self.addItem(self.player1PowerUp) elif temp == 1: if self.player1.speed == 8: self.removeItem(self.player1PowerUp) self.player1.speed = 2 self.player1PowerDown.setPos(770, 130) self.addItem(self.player1PowerDown) elif temp == 2: if self.player1.lives == 3: pass elif self.player1.lives == 2: self.livesPlayer1.append(LifePlayer1(760, 175)) self.player1.lives += 1 self.addItem(self.livesPlayer1[-1]) elif self.player1.lives == 1: self.livesPlayer1.append(LifePlayer1(720, 175)) self.player1.lives += 1 self.addItem((self.livesPlayer1[-1])) else: pass else: self.player1Score += 100 self.player1Scores.setText("Score: \n" + str(self.player1Score)) self.removeItem(e) self.enemies.remove(e) self.removeItem(self.bullet1) self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet1) self.player1Score += 10 self.player1Scores.setText("Score: \n" + str(self.player1Score)) continue # igrac 2 pogodio neprijatelja if e.x() <= self.bullet2.x() <= e.x() + 32: if e.y() <= self.bullet2.y() <= e.y() + 26: if e.powerUp: temp = randint(0, 3) if temp == 0: if self.player2.speed == 2: self.removeItem(self.player2PowerDown) self.player2.speed = 8 self.player2PowerUp.setPos(770, 330) self.addItem(self.player2PowerUp) elif temp == 1: if self.player2.speed == 8: self.removeItem(self.player2PowerUp) self.player2.speed = 2 self.player2PowerDown.setPos(770, 330) self.addItem(self.player2PowerDown) elif temp == 2: if self.player2.lives == 3: pass elif self.player2.lives == 2: self.livesPlayer2.append(LifePlayer2(760, 375)) self.player2.lives += 1 self.addItem(self.livesPlayer2[-1]) elif self.player2.lives == 1: self.livesPlayer2.append(LifePlayer2(720, 375)) self.player2.lives += 1 self.addItem((self.livesPlayer2[-1])) else: pass else: self.player2Score += 100 self.player2Scores.setText("Score: \n" + str(self.player2Score)) self.removeItem(e) self.enemies.remove(e) self.removeItem(self.bullet2) self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet2) self.player2Score += 10 self.player2Scores.setText("Score: \n" + str(self.player2Score)) continue # na igraca 1 se obrusio neprijatelj if self.player1.y() <= e.y() + 26 <= self.player1.y() + 53: if self.player1.x() <= e.x( ) <= self.player1.x() + 69 or self.player1.x( ) <= e.x() + 32 <= self.player1.x() + 69: if self.player1.lives > 0: if self.player1.speed == 8: self.removeItem(self.player1PowerUp) elif self.player1.speed == 2: self.removeItem(self.player1PowerDown) self.player1.speed = 4 e.frames = -1 self.player1.lives -= 1 self.removeItem(self.livesPlayer1[-1]) self.livesPlayer1.remove(self.livesPlayer1[-1]) self.player1.setPos(20, 530) if self.player1.lives <= 0: self.removeItem(self.player1) if self.player1.speed == 8: self.removeItem(self.player1PowerUp) elif self.player1.speed == 2: self.removeItem(self.player1PowerDown) if self.player2.lives > 0: self.winner = 2 # na igraca 2 se obrusio neprijatelj if self.player2.y() <= e.y() + 26 <= self.player2.y() + 53: if self.player2.x() <= e.x( ) <= self.player2.x() + 69 or self.player2.x( ) <= e.x() + 32 <= self.player2.x() + 69: if self.player2.lives > 0: if self.player2.speed == 8: self.removeItem(self.player1PowerUp) elif self.player2.speed == 2: self.removeItem(self.player2PowerDown) self.player2.speed = 4 e.frames = -1 self.player2.lives -= 1 self.removeItem(self.livesPlayer2[-1]) self.livesPlayer2.remove(self.livesPlayer2[-1]) self.player2.setPos(589, 530) if self.player2.lives <= 0: self.removeItem(self.player2) if self.player2.speed == 8: self.removeItem(self.player2PowerUp) elif self.player2.speed == 2: self.removeItem(self.player2PowerDown) if self.player1.lives > 0: self.winner = 1 # igraca 1 pogodio laser neprijatelja if self.player1.x() + 69 >= self.bulletEnemy.x() >= self.player1.x(): if self.player1.y() + 53 >= self.bulletEnemy.y() >= self.player1.y( ): if self.player1.lives > 0: if self.player1.speed == 8: self.removeItem(self.player1PowerUp) elif self.player1.speed == 2: self.removeItem(self.player1PowerDown) self.player1.speed = 4 self.bulletEnemy.active = False self.player1.lives -= 1 self.removeItem(self.livesPlayer1[-1]) self.livesPlayer1.remove(self.livesPlayer1[-1]) self.player1.setPos(20, 530) if self.player1.lives <= 0: self.removeItem(self.player1) if self.player2.lives > 0: self.winner = 2 # igraca 2 pogodio laser neprijatelja if self.player2.x() + 69 >= self.bulletEnemy.x() >= self.player2.x(): if self.player2.y() + 53 >= self.bulletEnemy.y() >= self.player2.y( ): if self.player2.lives > 0: if self.player2.speed == 8: self.removeItem(self.player2PowerUp) elif self.player2.speed == 2: self.removeItem(self.player2PowerDown) self.player2.speed = 4 self.bulletEnemy.active = False self.player2.lives -= 1 self.removeItem(self.livesPlayer2[-1]) self.livesPlayer2.remove(self.livesPlayer2[-1]) self.player2.setPos(589, 530) if self.player2.lives <= 0: self.removeItem(self.player2) if self.player1.lives > 0: self.winner = 1 # pomeranje metaka self.bullet1.game_update(self.keys_pressed, self.player1) self.bullet2.game_update(self.keys_pressed, self.player2) try: self.bulletEnemy.game_update(self.enemies[self.randomEnemyIndex]) if not self.bulletEnemy.active: self.randomEnemyIndex = randint(0, len(self.enemies)) except: self.randomEnemyIndex = randint(0, len(self.enemies)) # nasumicno biranje obrusavanja try: if randint(0, 500) == 0: self.enemies[randint(0, len(self.enemies))].chosen = True except: pass # kraj igre if self.player1.lives == 0 and self.player2.lives == 0: self.timer.stop() self.timerEnemy.stop() self.removeItem(self.bg) self.bg.setPos(-128, 0) self.addItem(self.bg) fontWinner = QFont() fontWinner.setPixelSize(40) textWinner = QGraphicsSimpleTextItem() textWinner.setFont(fontWinner) if self.winner == 1: textWinner.setText("WINNER PLAYER 1") textWinner.setBrush(QBrush(Qt.blue)) self.player1.setPos(310, 300) self.addItem(self.player1) elif self.winner == 2: textWinner.setText("WINNER PLAYER 2") textWinner.setBrush(QBrush(Qt.red)) self.player2.setPos(310, 300) self.addItem(self.player2) textWinner.setPos(180, 200) self.addItem(textWinner) # pobedjen nivo if len(self.enemies) == 0: self.timer.stop() self.timerEnemy.stop() if self.player1.lives > 0: self.removeItem(self.player1) self.removeItem(self.bullet1) if self.player2.lives > 0: self.removeItem(self.player2) self.removeItem(self.bullet2) self.removeItem(self.bulletEnemy) self.new_level() # pomeranje neprijatelja def game_update_enemy(self): if 0 < self.right < 9: self.right += 1 if self.right == 9: self.right = 0 self.left = 1 for e in self.enemies: e.move_right() elif 0 < self.left < 9: self.left += 1 if self.left == 9: self.left = 0 self.right = 1 for e in self.enemies: e.move_left() # pravljenje novog nivoa def new_level(self): self.level += 1 self.levelField.setText("Level: " + str(self.level)) self.left = 1 self.right = 5 self.threadFinished = False _thread.start_new_thread(self.draw_enemies, ()) while not self.threadFinished: continue self.threadFinished = False for e in self.enemies: e.collapseSpeed += self.level e.collapseFrames = 700 / e.collapseSpeed if self.player1.lives > 0: self.player1.setPos(20, 530) self.bullet1 = Bullet1(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y) self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet1) self.addItem(self.player1) if self.player2.lives > 0: self.player2.setPos(589, 530) self.bullet2 = Bullet2(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y) self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet2) self.addItem(self.player2) self.bulletEnemy = BulletEnemy(ENEMY_BULLET_X_OFFSET, ENEMY_BULLET_Y_OFFSET) self.bulletEnemy.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.bulletEnemy.speed += self.level self.bulletEnemy.frames = 700 / self.bulletEnemy.speed self.addItem(self.bulletEnemy) self.timer.start(16, self) self.timerEnemy.start(1000) def draw_enemies(self): self.threadFinished = False self.enemies = [ Enemy(131, 10), Enemy(173, 10), Enemy(215, 10), Enemy(257, 10), Enemy(299, 10), Enemy(341, 10), Enemy(383, 10), Enemy(425, 10), Enemy(467, 10), Enemy(509, 10), Enemy(131, 50), Enemy(173, 50), Enemy(215, 50), Enemy(257, 50), Enemy(299, 50), Enemy(341, 50), Enemy(383, 50), Enemy(425, 50), Enemy(467, 50), Enemy(509, 50), Enemy(131, 90), Enemy(173, 90), Enemy(215, 90), Enemy(257, 90), Enemy(299, 90), Enemy(341, 90), Enemy(383, 90), Enemy(425, 90), Enemy(467, 90), Enemy(509, 90) ] pool = multiprocessing.Pool(processes=1) result = pool.apply_async(get_enemy_power_ups, (len(self.enemies) - 1, 5)) self.enemyPowerUps = result.get(timeout=1) pool.close() for i in self.enemyPowerUps: self.enemies[i].setPixmap(QPixmap("Images/enemyPowerUp.png")) self.enemies[i].powerUp = True for e in self.enemies: self.addItem(e) self.randomEnemyIndex = randint(0, len(self.enemies)) self.threadFinished = True
class CameraView(QGraphicsObject): font: QFont = QFont("monospace", 16) stick_link_requested = pyqtSignal(StickWidget) stick_context_menu = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject') stick_widgets_out_of_sync = pyqtSignal('PyQt_PyObject') visibility_toggled = pyqtSignal() synchronize_clicked = pyqtSignal('PyQt_PyObject') previous_photo_clicked = pyqtSignal('PyQt_PyObject') next_photo_clicked = pyqtSignal('PyQt_PyObject') sync_confirm_clicked = pyqtSignal('PyQt_PyObject') sync_cancel_clicked = pyqtSignal('PyQt_PyObject') first_photo_clicked = pyqtSignal('PyQt_PyObject') enter_pressed = pyqtSignal() def __init__(self, scale: float, parent: Optional[QGraphicsItem] = None): QGraphicsObject.__init__(self, parent) self.current_highlight_color = QColor(0, 0, 0, 0) self.current_timer = -1 self.scaling = scale self.pixmap = QGraphicsPixmapItem(self) self.stick_widgets: List[StickWidget] = [] self.link_cam_text = QGraphicsSimpleTextItem("Link camera...", self) self.link_cam_text.setZValue(40) self.link_cam_text.setVisible(False) self.link_cam_text.setFont(CameraView.font) self.link_cam_text.setPos(0, 0) self.link_cam_text.setPen(QPen(QColor(255, 255, 255, 255))) self.link_cam_text.setBrush(QBrush(QColor(255, 255, 255, 255))) self.show_add_buttons = False self.camera = None self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) self.show_stick_widgets = False self.setAcceptHoverEvents(True) self.stick_edit_mode = False self.original_pixmap = self.pixmap.pixmap() self.hovered = False self.mode = 0 # TODO make enum Mode self.click_handler = None self.double_click_handler: Callable[[int, int], None] = None self.stick_widget_mode = StickMode.Display self.highlight_animation = QPropertyAnimation(self, b"highlight_color") self.highlight_animation.setEasingCurve(QEasingCurve.Linear) self.highlight_animation.valueChanged.connect( self.handle_highlight_color_changed) self.highlight_rect = QGraphicsRectItem(self) self.highlight_rect.setZValue(4) self.highlight_rect.setPen(QPen(QColor(0, 0, 0, 0))) self.title_btn = Button('btn_title', '', parent=self) self.title_btn.setFlag(QGraphicsItem.ItemIgnoresTransformations, False) self.title_btn.setZValue(5) self.title_btn.setVisible(False) self.sticks_without_width: List[Stick] = [] self.current_image_name: str = '' self.control_widget = ControlWidget(parent=self) self.control_widget.setFlag(QGraphicsItem.ItemIgnoresTransformations, False) self.control_widget.setVisible(True) self._connect_control_buttons() self.image_available = True self.blur_eff = QGraphicsBlurEffect() self.blur_eff.setBlurRadius(5.0) self.blur_eff.setEnabled(False) self.pixmap.setGraphicsEffect(self.blur_eff) self.overlay_message = QGraphicsSimpleTextItem('not available', parent=self) font = self.title_btn.font font.setPointSize(48) self.overlay_message.setFont(font) self.overlay_message.setBrush(QBrush(QColor(200, 200, 200, 200))) self.overlay_message.setPen(QPen(QColor(0, 0, 0, 200), 2.0)) self.overlay_message.setVisible(False) self.overlay_message.setZValue(6) self.stick_box = QGraphicsRectItem(parent=self) self.stick_box.setFlag(QGraphicsItem.ItemIsMovable, True) self.stick_box.setVisible(False) self.stick_box_start_pos = QPoint() def _connect_control_buttons(self): self.control_widget.synchronize_btn.clicked.connect( lambda: self.synchronize_clicked.emit(self)) self.control_widget.prev_photo_btn.clicked.connect( lambda: self.previous_photo_clicked.emit(self)) self.control_widget.next_photo_btn.clicked.connect( lambda: self.next_photo_clicked.emit(self)) self.control_widget.accept_btn.clicked.connect( lambda: self.sync_confirm_clicked.emit(self)) self.control_widget.cancel_btn.clicked.connect( lambda: self.sync_cancel_clicked.emit(self)) self.control_widget.first_photo_btn.clicked.connect( lambda: self.first_photo_clicked.emit(self)) def paint(self, painter: QPainter, option: PyQt5.QtWidgets.QStyleOptionGraphicsItem, widget: QWidget): if self.pixmap.pixmap().isNull(): return painter.setRenderHint(QPainter.Antialiasing, True) if self.show_stick_widgets: brush = QBrush(QColor(255, 255, 255, 100)) painter.fillRect(self.boundingRect(), brush) if self.mode and self.hovered: pen = QPen(QColor(0, 125, 200, 255)) pen.setWidth(4) painter.setPen(pen) def boundingRect(self) -> PyQt5.QtCore.QRectF: return self.pixmap.boundingRect().united( self.title_btn.boundingRect().translated(self.title_btn.pos())) def initialise_with(self, camera: Camera): if self.camera is not None: self.camera.stick_added.disconnect(self.handle_stick_created) self.camera.sticks_added.disconnect(self.handle_sticks_added) self.camera.stick_removed.disconnect(self.handle_stick_removed) self.camera.sticks_removed.disconnect(self.handle_sticks_removed) self.camera.stick_changed.disconnect(self.handle_stick_changed) self.camera = camera self.prepareGeometryChange() self.set_image(camera.rep_image, Path(camera.rep_image_path).name) self.title_btn.set_label(self.camera.folder.name) self.title_btn.set_height(46) self.title_btn.fit_to_contents() self.title_btn.set_width(int(self.boundingRect().width())) self.title_btn.setPos(0, self.boundingRect().height()) self.control_widget.title_btn.set_label(self.camera.folder.name) self.camera.stick_added.connect(self.handle_stick_created) self.camera.sticks_added.connect(self.handle_sticks_added) self.camera.stick_removed.connect(self.handle_stick_removed) self.camera.sticks_removed.connect(self.handle_sticks_removed) self.camera.stick_changed.connect(self.handle_stick_changed) self.control_widget.set_font_height(32) self.control_widget.set_widget_height( self.title_btn.boundingRect().height()) self.control_widget.set_widget_width(int(self.boundingRect().width())) self.control_widget.setPos(0, self.pixmap.boundingRect().height() ) #self.boundingRect().height()) self.control_widget.set_mode('view') self.update_stick_widgets() def set_image(self, img: Optional[np.ndarray] = None, image_name: Optional[str] = None): if img is None: self.show_overlay_message('not available') return self.show_overlay_message(None) self.prepareGeometryChange() barray = QByteArray(img.tobytes()) image = QImage(barray, img.shape[1], img.shape[0], QImage.Format_BGR888) self.original_pixmap = QPixmap.fromImage(image) self.pixmap.setPixmap(self.original_pixmap) self.highlight_rect.setRect(self.boundingRect()) self.current_image_name = image_name def update_stick_widgets(self): stick_length = 60 for stick in self.camera.sticks: sw = StickWidget(stick, self.camera, self) sw.set_mode(self.stick_widget_mode) self.connect_stick_widget_signals(sw) self.stick_widgets.append(sw) stick_length = stick.length_cm self.update_stick_box() self.scene().update() def scale_item(self, factor: float): self.prepareGeometryChange() pixmap = self.original_pixmap.scaledToHeight( int(self.original_pixmap.height() * factor)) self.pixmap.setPixmap(pixmap) self.__update_title() def set_show_stick_widgets(self, value: bool): for sw in self.stick_widgets: sw.setVisible(value) self.scene().update() def hoverEnterEvent(self, e: QGraphicsSceneHoverEvent): self.hovered = True self.scene().update(self.sceneBoundingRect()) def hoverLeaveEvent(self, e: QGraphicsSceneHoverEvent): self.hovered = False self.scene().update(self.sceneBoundingRect()) def mousePressEvent(self, e: QGraphicsSceneMouseEvent): super().mousePressEvent(e) def mouseReleaseEvent(self, e: QGraphicsSceneMouseEvent): if self.mode == 1: self.click_handler(self.camera) def mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent): if self.stick_widget_mode == StickMode.EditDelete: x = event.pos().toPoint().x() y = event.pos().toPoint().y() stick = self.camera.create_new_sticks( [(np.array([[x, y - 50], [x, y + 50]]), 3)], self.current_image_name)[ 0] #self.dataset.create_new_stick(self.camera) self.sticks_without_width.append(stick) def set_button_mode(self, click_handler: Callable[[Camera], None], data: str): self.mode = 1 # TODO make a proper ENUM self.click_handler = lambda c: click_handler(c, data) def set_display_mode(self): self.mode = 0 # TODO make a proper ENUM self.click_handler = None def _remove_stick_widgets(self): for sw in self.stick_widgets: sw.setParentItem(None) self.scene().removeItem(sw) sw.deleteLater() self.stick_widgets.clear() def handle_stick_created(self, stick: Stick): if stick.camera_id != self.camera.id: return sw = StickWidget(stick, self.camera, self) sw.set_mode(self.stick_widget_mode) self.connect_stick_widget_signals(sw) self.stick_widgets.append(sw) self.stick_widgets_out_of_sync.emit(self) self.update() def handle_stick_removed(self, stick: Stick): if stick.camera_id != self.camera.id: return stick_widget = next( filter(lambda sw: sw.stick.id == stick.id, self.stick_widgets)) self.disconnect_stick_widget_signals(stick_widget) self.stick_widgets.remove(stick_widget) stick_widget.setParentItem(None) self.scene().removeItem(stick_widget) stick_widget.deleteLater() self.update() def handle_sticks_removed(self, sticks: List[Stick]): if sticks[0].camera_id != self.camera.id: return for stick in sticks: to_remove: StickWidget = None for sw in self.stick_widgets: if sw.stick.id == stick.id: to_remove = sw break self.stick_widgets.remove(to_remove) to_remove.setParentItem(None) if self.scene() is not None: self.scene().removeItem(to_remove) to_remove.deleteLater() self.update() def handle_sticks_added(self, sticks: List[Stick]): if len(sticks) == 0: return if sticks[0].camera_id != self.camera.id: return for stick in sticks: sw = StickWidget(stick, self.camera, self) sw.set_mode(self.stick_widget_mode) self.connect_stick_widget_signals(sw) self.stick_widgets.append(sw) self.update_stick_box() self.stick_widgets_out_of_sync.emit(self) self.update() def connect_stick_widget_signals(self, stick_widget: StickWidget): stick_widget.delete_clicked.connect( self.handle_stick_widget_delete_clicked) stick_widget.stick_changed.connect(self.handle_stick_widget_changed) stick_widget.link_initiated.connect(self.handle_stick_link_initiated) stick_widget.right_clicked.connect( self.handle_stick_widget_context_menu) def disconnect_stick_widget_signals(self, stick_widget: StickWidget): stick_widget.delete_clicked.disconnect( self.handle_stick_widget_delete_clicked) stick_widget.stick_changed.disconnect(self.handle_stick_widget_changed) stick_widget.link_initiated.disconnect( self.handle_stick_link_initiated) stick_widget.right_clicked.disconnect( self.handle_stick_widget_context_menu) def handle_stick_widget_delete_clicked(self, stick: Stick): self.camera.remove_stick(stick) def set_stick_widgets_mode(self, mode: StickMode): self.stick_widget_mode = mode for sw in self.stick_widgets: sw.set_mode(mode) self.set_stick_edit_mode(mode == StickMode.Edit) def handle_stick_widget_changed(self, stick_widget: StickWidget): self.camera.stick_changed.emit(stick_widget.stick) def handle_stick_changed(self, stick: Stick): if stick.camera_id != self.camera.id: return sw = next( filter(lambda _sw: _sw.stick.id == stick.id, self.stick_widgets)) sw.adjust_line() sw.update_tooltip() def handle_stick_link_initiated(self, stick_widget: StickWidget): self.stick_link_requested.emit(stick_widget) def get_top_left(self) -> QPointF: return self.sceneBoundingRect().topLeft() def get_top_right(self) -> QPointF: return self.sceneBoundingRect().topRight() def highlight(self, color: Optional[QColor]): if color is None: self.highlight_animation.stop() self.highlight_rect.setVisible(False) return alpha = color.alpha() color.setAlpha(0) self.highlight_animation.setStartValue(color) self.highlight_animation.setEndValue(color) color.setAlpha(alpha) self.highlight_animation.setKeyValueAt(0.5, color) self.highlight_animation.setDuration(2000) self.highlight_animation.setLoopCount(-1) self.highlight_rect.setPen(QPen(color)) self.highlight_rect.setVisible(True) self.highlight_animation.start() @pyqtProperty(QColor) def highlight_color(self) -> QColor: return self.current_highlight_color @highlight_color.setter def highlight_color(self, color: QColor): self.current_highlight_color = color def handle_highlight_color_changed(self, color: QColor): self.highlight_rect.setBrush(QBrush(color)) self.update() def handle_stick_widget_context_menu(self, sender: Dict[str, StickWidget]): self.stick_context_menu.emit(sender['stick_widget'], self) def show_overlay_message(self, msg: Optional[str]): if msg is None: self.overlay_message.setVisible(False) self.blur_eff.setEnabled(False) return self.overlay_message.setText(msg) self.overlay_message.setPos( self.pixmap.boundingRect().center() - QPointF(0.5 * self.overlay_message.boundingRect().width(), 0.5 * self.overlay_message.boundingRect().height())) self.overlay_message.setVisible(True) self.blur_eff.setEnabled(True) def show_status_message(self, msg: Optional[str]): if msg is None: self.control_widget.set_title_text(self.camera.folder.name) else: self.control_widget.set_title_text(msg) def update_stick_box(self): left = 9000 right = 0 top = 9000 bottom = -1 for stick in self.camera.sticks: left = min(left, min(stick.top[0], stick.bottom[0])) right = max(right, max(stick.top[0], stick.bottom[0])) top = min(top, min(stick.top[1], stick.bottom[1])) bottom = max(bottom, max(stick.top[1], stick.bottom[1])) left -= 100 right += 100 top -= 100 bottom += 100 self.stick_box.setRect(left, top, right - left, bottom - top) pen = QPen(QColor(0, 100, 200, 200)) pen.setWidth(2) pen.setStyle(Qt.DashLine) self.stick_box.setPen(pen) def set_stick_edit_mode(self, is_edit: bool): if is_edit: self.update_stick_box() self.stick_box_start_pos = self.stick_box.pos() for sw in self.stick_widgets: sw.setParentItem(self.stick_box) else: offset = self.stick_box.pos() - self.stick_box_start_pos for sw in self.stick_widgets: stick = sw.stick stick.translate(np.array([int(offset.x()), int(offset.y())])) sw.setParentItem(self) sw.set_stick(stick) self.stick_box.setParentItem(None) self.stick_box = QGraphicsRectItem(self) self.stick_box.setFlag(QGraphicsItem.ItemIsMovable, True) self.stick_box.setVisible(False) self.stick_box.setVisible(is_edit) def keyPressEvent(self, event: QKeyEvent) -> None: pass def keyReleaseEvent(self, event: QKeyEvent) -> None: if event.key() in [Qt.Key_Right, Qt.Key_Tab, Qt.Key_Space]: self.control_widget.next_photo_btn.click_button(True) elif event.key() in [Qt.Key_Left]: self.control_widget.prev_photo_btn.click_button(True) elif event.key() == Qt.Key_S: self.enter_pressed.emit()
class ActiveSliceItem(QGraphicsRectItem): """ActiveSliceItem for the Path View""" def __init__(self, part_item, active_base_index): super(ActiveSliceItem, self).__init__(part_item) self._part_item = part_item self._getActiveTool = part_item._getActiveTool self._active_slice = 0 self._low_drag_bound = 0 self._high_drag_bound = self.part().maxBaseIdx() self._controller = ActiveSliceItemController(self, part_item.part()) self._label = QGraphicsSimpleTextItem("", parent=self) self._label.setPos(0, -18) self._label.setFont(_FONT) self._label.setBrush(_LABEL_BRUSH) self._label.hide() self.setFlag(QGraphicsItem.ItemIsMovable) self.setAcceptHoverEvents(True) self.setZValue(styles.ZACTIVESLICEHANDLE) self.setRect(QRectF(0, 0, _BASE_WIDTH,\ self._part_item.boundingRect().height())) self.setPos(active_base_index*_BASE_WIDTH, 0) self.setBrush(_BRUSH) self.setPen(_PEN) # reuse select tool methods for other tools self.addSeqToolMousePress = self.selectToolMousePress self.addSeqToolMouseMove = self.selectToolMouseMove self.breakToolMousePress = self.selectToolMousePress self.breakToolMouseMove = self.selectToolMouseMove self.insertionToolMousePress = self.selectToolMousePress self.insertionToolMouseMove = self.selectToolMouseMove self.paintToolMousePress = self.selectToolMousePress self.paintToolMouseMove = self.selectToolMouseMove self.pencilToolMousePress = self.selectToolMousePress self.pencilToolMouseMove = self.selectToolMouseMove self.skipToolMousePress = self.selectToolMousePress self.skipToolMouseMove = self.selectToolMouseMove # end def ### SLOTS ### def strandChangedSlot(self, sender, vh): pass # end def def updateRectSlot(self, part): bw = _BASE_WIDTH new_rect = QRectF(0, 0, bw,\ self._part_item.virtualHelixBoundingRect().height()) if new_rect != self.rect(): self.setRect(new_rect) self._hideIfEmptySelection() self.updateIndexSlot(part, part.activeBaseIndex()) return new_rect # end def def updateIndexSlot(self, part, base_index): """The slot that receives active slice changed notifications from the part and changes the receiver to reflect the part""" label = self._label bw = _BASE_WIDTH bi = util.clamp(int(base_index), 0, self.part().maxBaseIdx()) self.setPos(bi * bw, -styles.PATH_HELIX_PADDING) self._active_slice = bi if label: label.setText("%d" % bi) label.setX((bw - label.boundingRect().width()) / 2) # end def ### ACCESSORS ### def activeBaseIndex(self): return self.part().activeBaseIndex() # end def def part(self): return self._part_item.part() # end def def partItem(self): return self._part_item # end def ### PUBLIC METHODS FOR DRAWING / LAYOUT ### def removed(self): scene = self.scene() scene.removeItem(self._label) scene.removeItem(self) self._part_item = None self._label = None self._controller.disconnectSignals() self.controller = None # end def def resetBounds(self): """Call after resizing virtualhelix canvas.""" self._high_drag_bound = self.part().maxBaseIdx() # end def ### PRIVATE SUPPORT METHODS ### def _hideIfEmptySelection(self): vis = self.part().numberOfVirtualHelices() > 0 self.setVisible(vis) self._label.setVisible(vis) # end def def _setActiveBaseIndex(self, base_index): self.part().setActiveBaseIndex(base_index) # end def ### EVENT HANDLERS ### def hoverEnterEvent(self, event): self.setCursor(Qt.OpenHandCursor) self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex()) QGraphicsItem.hoverEnterEvent(self, event) # end def def hoverLeaveEvent(self, event): self.setCursor(Qt.ArrowCursor) self._part_item.updateStatusBar("") QGraphicsItem.hoverLeaveEvent(self, event) # end def def mousePressEvent(self, event): """ Parses a mousePressEvent, calling the approproate tool method as necessary. Stores _move_idx for future comparison. """ if event.button() != Qt.LeftButton: event.ignore() QGraphicsItem.mousePressEvent(self, event) return self.scene().views()[0].addToPressList(self) self._move_idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH)) tool_method_name = self._getActiveTool().methodPrefix() + "MousePress" if hasattr(self, tool_method_name): # if the tool method exists modifiers = event.modifiers() getattr(self, tool_method_name)(modifiers) # call tool method def mouseMoveEvent(self, event): """ Parses a mouseMoveEvent, calling the approproate tool method as necessary. Updates _move_idx if it changed. """ tool_method_name = self._getActiveTool().methodPrefix() + "MouseMove" if hasattr(self, tool_method_name): # if the tool method exists idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH)) if idx != self._move_idx: # did we actually move? modifiers = event.modifiers() self._move_idx = idx getattr(self, tool_method_name)(modifiers, idx) # call tool method def customMouseRelease(self, event): """ Parses a mouseReleaseEvent, calling the approproate tool method as necessary. Deletes _move_idx if necessary. """ tool_method_name = self._getActiveTool().methodPrefix() + "MouseRelease" if hasattr(self, tool_method_name): # if the tool method exists modifiers = event.modifiers() x = event.pos().x() getattr(self, tool_method_name)(modifiers, x) # call tool method if hasattr(self, '_move_idx'): del self._move_idx ### TOOL METHODS ### def selectToolMousePress(self, modifiers): """ Set the allowed drag bounds for use by selectToolMouseMove. """ if (modifiers & Qt.AltModifier) and (modifiers & Qt.ShiftModifier): self.part().undoStack().beginMacro("Auto-drag Scaffold(s)") for vh in self.part().getVirtualHelices(): # SCAFFOLD # resize 3' first for strand in vh.scaffoldStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx3p) if strand.isDrawn5to3(): strand.resize((idx5p, hi)) else: strand.resize((lo, idx5p)) # resize 5' second for strand in vh.scaffoldStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx5p): lo, hi = strand.getResizeBounds(idx5p) if strand.isDrawn5to3(): strand.resize((lo, idx3p)) else: strand.resize((idx3p, hi)) # STAPLE # resize 3' first for strand in vh.stapleStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx3p) if strand.isDrawn5to3(): strand.resize((idx5p, hi)) else: strand.resize((lo, idx5p)) # resize 5' second for strand in vh.stapleStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx5p) if strand.isDrawn5to3(): strand.resize((lo, idx3p)) else: strand.resize((idx3p, hi)) self.part().undoStack().endMacro() # end def def selectToolMouseMove(self, modifiers, idx): """ Given a new index (pre-validated as different from the prev index), calculate the new x coordinate for self, move there, and notify the parent strandItem to redraw its horizontal line. """ idx = util.clamp(idx, self._low_drag_bound, self._high_drag_bound) x = int(idx * _BASE_WIDTH) self.setPos(x, self.y()) self.updateIndexSlot(None, idx) self._setActiveBaseIndex(idx) self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
class GAction(QtWidgets.QGraphicsPathItem, GTooltipBase): """Base class for all graphical actions.""" def __init__(self, g_data_item, w_data_item, parent=None, eval_gui=None, appending_ports=True): """Initializes GAction. :param g_data_item: Object which holds data describing graphical properties of this GAction. :param w_data_item: Object which holds data about action in workflow. :param parent: Action which holds this subaction: this GAction is inside parent GAction. """ super(GAction, self).__init__(parent) self._width = g_data_item.data(GActionData.WIDTH) self._height = g_data_item.data(GActionData.HEIGHT) self.in_ports = [] self.out_ports = [] self.eval_gui = eval_gui self._hide_name = False self.appending_ports = appending_ports self.setPos(QtCore.QPoint(g_data_item.data(GActionData.X), g_data_item.data(GActionData.Y))) self.setPen(QtGui.QPen(QtCore.Qt.black)) self.setBrush(QtCore.Qt.darkGray) self.setFlag(self.ItemIsMovable) self.setFlag(self.ItemIsSelectable) self.setFlag(self.ItemSendsGeometryChanges) self.setZValue(0.0) self.resize_handle_width = 6 self.type_name = QGraphicsSimpleTextItem(w_data_item.action_name, self) self.type_name.setPos(QtCore.QPoint(self.resize_handle_width, GPort.SIZE / 2)) self.type_name.setBrush(QtCore.Qt.white) self._name = EditableLabel(g_data_item.data(GActionData.NAME), self) self.background = GActionBackground(self) self.background.setZValue(1.0) self.setCacheMode(self.DeviceCoordinateCache) self.g_data_item = g_data_item self.w_data_item = w_data_item self.update_ports() self.level = 0 self.height = self.height self.width = self.width self.progress = 0 def has_const_params(self): if len(self.w_data_item.parameters.parameters) > 0: return self.w_data_item.parameters.parameters[-1].name is not None else: return True def update_ports(self): if len(self.w_data_item.parameters.parameters) > 0: self._add_ports(len(self.w_data_item.arguments), not self.has_const_params()) else: self._add_ports(len(self.w_data_item.arguments)) def __repr__(self): return self.name + "\t" + str(self.level) def hide_name(self, boolean): self._hide_name = boolean if boolean: self._name.setParentItem(None) self._name.hide() else: self._name.setParentItem(self) self._name.show() self._height = self.height - self.inner_area().height() self.position_ports() self.update_gfx() @property def status(self): return self.background.status @status.setter def status(self, status): self.background.status = status self.setBrush(self.background.COLOR_PALETTE[self.status]) self.update() @property def progress(self): return self.background.progress @progress.setter def progress(self, percent): self.background.update_gfx() self.background.progress = percent @property def name(self): return self._name.toPlainText() @name.setter def name(self, name): self._name.setPlainText(name) @property def width(self): return self._width @width.setter def width(self, value): self._width = max(value, self.width_of_ports(), self._name.boundingRect().width() + 2 * self.resize_handle_width, self.type_name.boundingRect().width() + 2 * self.resize_handle_width) self.position_ports() self.update_gfx() # self.resize_handles.update_handles() @property def height(self): return self._height @height.setter def height(self, value): self._height = max(value, self._name.boundingRect().height() + GPort.SIZE + self.type_name.boundingRect().height() + GPort.SIZE) self.position_ports() self.update_gfx() #self.resize_handles.update_handles() def boundingRect(self): return super(GAction, self).boundingRect().united(self.childrenBoundingRect()) def next_actions(self): ret = [] for port in self.out_ports: for conn in port.connections: item = conn.port2.parentItem() if item not in ret: ret.append(item) return ret def previous_actions(self): ret = [] for port in self.in_ports: for conn in port.connections: item = conn.port1.parentItem() if item not in ret: ret.append(item) return ret def name_change(self): self.scene().update() self.width = self.width def name_has_changed(self): if not self.scene().action_name_changed(self.g_data_item, self.name) or self.name == "": return False self.width = self.width self.w_data_item.name(self.name) self.scene().update() return True def width_has_changed(self): self.scene().action_model.width_changed(self.g_data_item, self.width) def height_has_changed(self): self.scene().action_model.height_changed(self.g_data_item, self.height) def get_port(self, input, index): if input: return self.in_ports[index] else: return self.out_ports[index] def _add_ports(self, n_ports, appending=False): for i in range(n_ports): self.add_g_port(True, "Input Port" + str(i)) if appending and self.appending_ports: self.add_g_port(True, "Appending port") self.in_ports[-1].appending_port = True self.add_g_port(False, "Output Port") def inner_area(self): """Returns rectangle of the inner area of GAction.""" return QRectF(self.resize_handle_width, GPort.SIZE / 2 + self.type_name.boundingRect().height() + 4, self.width - 2 * self.resize_handle_width, self.height - GPort.SIZE - self.type_name.boundingRect().height() - 4) def moveBy(self, dx, dy): super(GAction, self).moveBy(dx, dy) self.scene().move(self.g_data_item, self.x() + dx, self.y() + dy) def mousePressEvent(self, press_event): super(GAction, self).mousePressEvent(press_event) self.setCursor(QtCore.Qt.ClosedHandCursor) if press_event.button() == Qt.RightButton: self.setSelected(True) def mouseReleaseEvent(self, release_event): super(GAction, self).mouseReleaseEvent(release_event) self.setCursor(QtCore.Qt.OpenHandCursor) temp = release_event.buttonDownScenePos(Qt.LeftButton) temp2 = release_event.pos() if release_event.buttonDownScenePos(Qt.LeftButton) != self.mapToScene(release_event.pos()): for item in self.scene().selectedItems(): if self.scene().is_action(item): self.scene().move(item.g_data_item, item.x(), item.y()) def mouseDoubleClickEvent(self, event): if self.eval_gui is None: if self._name.contains(self.mapToItem(self._name, event.pos())): self._name.mouseDoubleClickEvent(event) else: self.eval_gui.double_click(self) def itemChange(self, change_type, value): """Update all connections which are attached to this action.""" if change_type == self.ItemPositionHasChanged: for port in self.ports(): for conn in port.connections: conn.update_gfx() ''' elif change_type == self.ItemParentChange: self.setPos(self.mapToItem(value, self.mapToScene(self.pos()))) ''' return super(GAction, self).itemChange(change_type, value) def paint(self, painter, item, widget=None): """Update model of this GAction if necessary.""" #self.setBrush(self.background.COLOR_PALETTE[self.status]) super(GAction, self).paint(painter, item, widget) def paint_pixmap(self): progress = self.progress status = self.status self.progress = 0 self.status = ActionStatus.IDLE rect = self.boundingRect() pixmap = QPixmap(rect.size().toSize()) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing, True) painter.translate(-rect.topLeft()) for child in self.childItems(): if child.flags() & QGraphicsItem.ItemStacksBehindParent: painter.save() painter.translate(child.mapToParent(self.pos())) child.paint(painter, QStyleOptionGraphicsItem(), None) painter.restore() self.paint(painter, QStyleOptionGraphicsItem()) for child in self.childItems(): if not child.flags() & QGraphicsItem.ItemStacksBehindParent: painter.save() painter.translate(child.mapToParent(self.pos())) child.paint(painter, QStyleOptionGraphicsItem(), None) painter.restore() painter.end() self.progress = progress self.status = status return pixmap def update_gfx(self): """Updates model of the GAction.""" self.prepareGeometryChange() p = QtGui.QPainterPath() p.addRoundedRect(QtCore.QRectF(0, 0, self.width, self.height), 6, 6) if not self._hide_name: p.addRoundedRect(self.inner_area(), 4, 4) self.setPath(p) self.update() self.background.update_gfx() def add_g_port(self, is_input, name=""): """Adds a port to this GAction. :param is_input: Decides if the new port will be input or output. """ if is_input: self.in_ports.append(GInputPort(len(self.in_ports), QtCore.QPoint(0, 0), name, self)) else: self.out_ports.clear() self.out_ports.append(GOutputPort(len(self.out_ports), QtCore.QPoint(0, 0), name, self)) self.width = self.width def position_ports(self): if len(self.in_ports): space = self.width / (len(self.in_ports)) for i in range(len(self.in_ports)): self.in_ports[i].setPos(QtCore.QPoint((i + 0.5) * space - GPort.RADIUS, -GPort.RADIUS)) if len(self.out_ports): space = self.width / (len(self.out_ports)) for i in range(len(self.out_ports)): self.out_ports[i].setPos(QtCore.QPoint((i + 0.5) * space - GPort.RADIUS, self.height - GPort.RADIUS)) def width_of_ports(self): return max(len(self.in_ports) * GPort.SIZE, len(self.out_ports) * GPort.SIZE) def ports(self): """Returns input and output ports.""" return self.in_ports + self.out_ports def get_arg_action(self, arg): index = self.w_data_item.arguments.index(arg) if len(self.in_ports[index].connections) == 1: return self.in_ports[index].connections[0].port1.parentItem() else: return None
class IndicatorIconView(QGraphicsPixmapItem): def __init__(self, parent: ViewBox, icon_path: str, icon_pos: int, color: Optional[List[int]] = None, message: str = ""): """An indicator icon for a pyqtgraph ViewBox The icon loaded from icon_path will be displayed in the low right corner of the ViewBox. :param parent: ViewBox to place indicator in :param icon_path: path to icon :param icon_pos: position index. Counting from 0 in lower right. """ super().__init__() self.parent = parent self.icon_pos = icon_pos self.label = QGraphicsSimpleTextItem(message) self.label.setVisible(False) self.parent.scene().addItem(self.label) self.set_icon(icon_path, color) self.icon_size = [32, 32] self.parent.scene().addItem(self) self.position_icon() self.parent.sigResized.connect(self.position_icon) self.setVisible(False) self.setAcceptHoverEvents(True) self.connected_overlay = None self.actions: List[QAction] = [] def set_icon(self, icon_path: str, color: Optional[List[int]] = None): if color is not None: image_data = skio.imread(icon_path, plugin="imageio") # Set the RGB part to the red channel multiplied by the requested color red_channel = image_data[:, :, 0] / 255 image_data[:, :, 0] = red_channel * color[0] image_data[:, :, 1] = red_channel * color[1] image_data[:, :, 2] = red_channel * color[2] h = image_data.shape[0] w = image_data.shape[1] image_qi = QImage(image_data.data, w, h, 4 * w, QImage.Format_RGBA8888) image_pm = QPixmap.fromImage(image_qi) self.label.setBrush(QColor(*color)) else: image_pm = QPixmap(icon_path) self.setPixmap(image_pm) def position_icon(self): # The size of the imageview we are putting the icon ing scene_size = self.parent.size() # The position of the image within the scene scene_pos = self.parent.scenePos() # Lower right corner in scene pixel coordinates corner_pos_x = scene_size.width() + scene_pos.x() corner_pos_y = scene_size.height() + scene_pos.y() icon_pos_x = corner_pos_x - self.icon_size[0] * (1 + self.icon_pos) - 10 icon_pos_y = corner_pos_y - self.icon_size[1] - 30 self.setOffset(icon_pos_x, icon_pos_y) label_width = self.label.boundingRect().width() self.label.setPos(corner_pos_x - label_width, icon_pos_y - self.icon_size[0]) def hoverEnterEvent(self, event): if self.connected_overlay is not None: self.connected_overlay.setVisible(True) self.label.setVisible(True) def hoverLeaveEvent(self, event): if self.connected_overlay is not None: self.connected_overlay.setVisible(False) self.label.setVisible(False) def add_actions(self, actions: List[Tuple[str, Callable]]): for text, method in actions: action = QAction(text) action.triggered.connect(method) self.actions.append(action) def mouseClickEvent(self, event): event.accept() if self.actions: qm = QMenu() for action in self.actions: qm.addAction(action) qm.exec(event.screenPos().toQPoint())
def game_update(self): self.player1.game_update(self.keys_pressed) self.player2.game_update(self.keys_pressed) for e in self.enemies: # ako je neprijatelj zavrsio sa padanjem, brisemo ga if e.frames == -1: self.removeItem(e) self.enemies.remove(e) continue # ako je neprijatelj izabran za padanje, nastavlja da pada if e.chosen: e.collapse() # igrac 1 pogodio neprijatelja if e.x() <= self.bullet1.x() <= e.x() + 32: if e.y() <= self.bullet1.y() <= e.y() + 26: if e.powerUp: temp = randint(0, 3) if temp == 0: if self.player1.speed == 2: self.removeItem(self.player1PowerDown) self.player1.speed = 8 self.player1PowerUp.setPos(770, 130) self.addItem(self.player1PowerUp) elif temp == 1: if self.player1.speed == 8: self.removeItem(self.player1PowerUp) self.player1.speed = 2 self.player1PowerDown.setPos(770, 130) self.addItem(self.player1PowerDown) elif temp == 2: if self.player1.lives == 3: pass elif self.player1.lives == 2: self.livesPlayer1.append(LifePlayer1(760, 175)) self.player1.lives += 1 self.addItem(self.livesPlayer1[-1]) elif self.player1.lives == 1: self.livesPlayer1.append(LifePlayer1(720, 175)) self.player1.lives += 1 self.addItem((self.livesPlayer1[-1])) else: pass else: self.player1Score += 100 self.player1Scores.setText("Score: \n" + str(self.player1Score)) self.removeItem(e) self.enemies.remove(e) self.removeItem(self.bullet1) self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet1) self.player1Score += 10 self.player1Scores.setText("Score: \n" + str(self.player1Score)) continue # igrac 2 pogodio neprijatelja if e.x() <= self.bullet2.x() <= e.x() + 32: if e.y() <= self.bullet2.y() <= e.y() + 26: if e.powerUp: temp = randint(0, 3) if temp == 0: if self.player2.speed == 2: self.removeItem(self.player2PowerDown) self.player2.speed = 8 self.player2PowerUp.setPos(770, 330) self.addItem(self.player2PowerUp) elif temp == 1: if self.player2.speed == 8: self.removeItem(self.player2PowerUp) self.player2.speed = 2 self.player2PowerDown.setPos(770, 330) self.addItem(self.player2PowerDown) elif temp == 2: if self.player2.lives == 3: pass elif self.player2.lives == 2: self.livesPlayer2.append(LifePlayer2(760, 375)) self.player2.lives += 1 self.addItem(self.livesPlayer2[-1]) elif self.player2.lives == 1: self.livesPlayer2.append(LifePlayer2(720, 375)) self.player2.lives += 1 self.addItem((self.livesPlayer2[-1])) else: pass else: self.player2Score += 100 self.player2Scores.setText("Score: \n" + str(self.player2Score)) self.removeItem(e) self.enemies.remove(e) self.removeItem(self.bullet2) self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT) self.addItem(self.bullet2) self.player2Score += 10 self.player2Scores.setText("Score: \n" + str(self.player2Score)) continue # na igraca 1 se obrusio neprijatelj if self.player1.y() <= e.y() + 26 <= self.player1.y() + 53: if self.player1.x() <= e.x( ) <= self.player1.x() + 69 or self.player1.x( ) <= e.x() + 32 <= self.player1.x() + 69: if self.player1.lives > 0: if self.player1.speed == 8: self.removeItem(self.player1PowerUp) elif self.player1.speed == 2: self.removeItem(self.player1PowerDown) self.player1.speed = 4 e.frames = -1 self.player1.lives -= 1 self.removeItem(self.livesPlayer1[-1]) self.livesPlayer1.remove(self.livesPlayer1[-1]) self.player1.setPos(20, 530) if self.player1.lives <= 0: self.removeItem(self.player1) if self.player1.speed == 8: self.removeItem(self.player1PowerUp) elif self.player1.speed == 2: self.removeItem(self.player1PowerDown) if self.player2.lives > 0: self.winner = 2 # na igraca 2 se obrusio neprijatelj if self.player2.y() <= e.y() + 26 <= self.player2.y() + 53: if self.player2.x() <= e.x( ) <= self.player2.x() + 69 or self.player2.x( ) <= e.x() + 32 <= self.player2.x() + 69: if self.player2.lives > 0: if self.player2.speed == 8: self.removeItem(self.player1PowerUp) elif self.player2.speed == 2: self.removeItem(self.player2PowerDown) self.player2.speed = 4 e.frames = -1 self.player2.lives -= 1 self.removeItem(self.livesPlayer2[-1]) self.livesPlayer2.remove(self.livesPlayer2[-1]) self.player2.setPos(589, 530) if self.player2.lives <= 0: self.removeItem(self.player2) if self.player2.speed == 8: self.removeItem(self.player2PowerUp) elif self.player2.speed == 2: self.removeItem(self.player2PowerDown) if self.player1.lives > 0: self.winner = 1 # igraca 1 pogodio laser neprijatelja if self.player1.x() + 69 >= self.bulletEnemy.x() >= self.player1.x(): if self.player1.y() + 53 >= self.bulletEnemy.y() >= self.player1.y( ): if self.player1.lives > 0: if self.player1.speed == 8: self.removeItem(self.player1PowerUp) elif self.player1.speed == 2: self.removeItem(self.player1PowerDown) self.player1.speed = 4 self.bulletEnemy.active = False self.player1.lives -= 1 self.removeItem(self.livesPlayer1[-1]) self.livesPlayer1.remove(self.livesPlayer1[-1]) self.player1.setPos(20, 530) if self.player1.lives <= 0: self.removeItem(self.player1) if self.player2.lives > 0: self.winner = 2 # igraca 2 pogodio laser neprijatelja if self.player2.x() + 69 >= self.bulletEnemy.x() >= self.player2.x(): if self.player2.y() + 53 >= self.bulletEnemy.y() >= self.player2.y( ): if self.player2.lives > 0: if self.player2.speed == 8: self.removeItem(self.player2PowerUp) elif self.player2.speed == 2: self.removeItem(self.player2PowerDown) self.player2.speed = 4 self.bulletEnemy.active = False self.player2.lives -= 1 self.removeItem(self.livesPlayer2[-1]) self.livesPlayer2.remove(self.livesPlayer2[-1]) self.player2.setPos(589, 530) if self.player2.lives <= 0: self.removeItem(self.player2) if self.player1.lives > 0: self.winner = 1 # pomeranje metaka self.bullet1.game_update(self.keys_pressed, self.player1) self.bullet2.game_update(self.keys_pressed, self.player2) try: self.bulletEnemy.game_update(self.enemies[self.randomEnemyIndex]) if not self.bulletEnemy.active: self.randomEnemyIndex = randint(0, len(self.enemies)) except: self.randomEnemyIndex = randint(0, len(self.enemies)) # nasumicno biranje obrusavanja try: if randint(0, 500) == 0: self.enemies[randint(0, len(self.enemies))].chosen = True except: pass # kraj igre if self.player1.lives == 0 and self.player2.lives == 0: self.timer.stop() self.timerEnemy.stop() self.removeItem(self.bg) self.bg.setPos(-128, 0) self.addItem(self.bg) fontWinner = QFont() fontWinner.setPixelSize(40) textWinner = QGraphicsSimpleTextItem() textWinner.setFont(fontWinner) if self.winner == 1: textWinner.setText("WINNER PLAYER 1") textWinner.setBrush(QBrush(Qt.blue)) self.player1.setPos(310, 300) self.addItem(self.player1) elif self.winner == 2: textWinner.setText("WINNER PLAYER 2") textWinner.setBrush(QBrush(Qt.red)) self.player2.setPos(310, 300) self.addItem(self.player2) textWinner.setPos(180, 200) self.addItem(textWinner) # pobedjen nivo if len(self.enemies) == 0: self.timer.stop() self.timerEnemy.stop() if self.player1.lives > 0: self.removeItem(self.player1) self.removeItem(self.bullet1) if self.player2.lives > 0: self.removeItem(self.player2) self.removeItem(self.bullet2) self.removeItem(self.bulletEnemy) self.new_level()
class Scene(QGraphicsScene): entered = pyqtSignal([QGraphicsItem], [QGraphicsEllipseItem]) leave = pyqtSignal([QGraphicsItem], [QGraphicsEllipseItem]) move = pyqtSignal([QGraphicsItem], [QGraphicsEllipseItem]) # press = pyqtSignal([QGraphicsItem],[QGraphicsEllipseItem]) """Each instance holds all image and ellipse data""" def __init__(self, MainWindow, **keywords): # executes QGraphicsScene.__init__() super().__init__() # self.sceneCount=self.counter self.MainWindow = MainWindow self.keywords = keywords self.threshold = self.MainWindow.binary_sb.value() self.populated = False if 'path' in self.keywords.keys(): self.getPathData(self.keywords['path']) self.binarize_image() self.findContours() self.image = Image(self.path) self.addItem(self.image) if 'headers' in self.keywords.keys(): self.headx_px = self.keywords['headers'][0] self.heady_px = self.keywords['headers'][1] xheader = self.headx_px.split("_") yheader = self.heady_px.split("_") self.sceneID = list(set(xheader).intersection(set(yheader)))[0] else: self.headx_px = "%s_x" % self.filename self.heady_px = "%s_y" % self.filename self.sceneID = "%s" % (self.filename) self.dotCoords = {} if 'coords' in self.keywords.keys(): self.pointCount = len(self.keywords['coords'][0]) self.dotCoords['x_px'] = self.keywords['coords'][0] self.dotCoords['y_px'] = self.keywords['coords'][1] else: self.pointCount = 0 self.dotCoords['x_px'] = [None] * len( self.MainWindow.pointData.index) self.dotCoords['y_px'] = [None] * len( self.MainWindow.pointData.index) if self.sceneID in self.MainWindow.scenes: self.sceneID = "%s_copy" % (self.sceneID) self.MainWindow.view_lw.addItem(self.sceneID) def setThreshold(self): self.threshold = self.MainWindow.binary_sb.value() def populateDotsOnLink(self): self.pointCount = 0 for i in range(len(self.MainWindow.pointData.index)): self.circle = Ellipse(0, 0, 10, 10, self.pointCount) self.circle.setPos(self.dotCoords['x_px'][i] - 5, self.dotCoords['y_px'][i] - 5) self.addItem(self.circle) self.pointCount += 1 self.populated = True def linkView(self, path): if path[0] != '': self.getPathData(path[0]) self.clear() self.image = Image(self.path) self.addItem(self.image) self.binarize_image() self.findContours() self.populateDotsOnLink() def getPathData(self, path): self.path = path self.filename_w_ext = os.path.basename(path) self.filename, file_extension = os.path.splitext(self.filename_w_ext) self.root = os.path.dirname(os.path.abspath(path)) def remove_image(self): self.removeItem(self.image) def refresh_image(self, path): self.image = Image(self.path) self.addItem(self.image) def binarize_image(self): self.orig_image = cv2.imread(self.path) self.cnts_image = self.orig_image imageGray = cv2.cvtColor(self.orig_image, cv2.COLOR_BGR2GRAY) ret, self.cvBinaryImage = cv2.threshold(imageGray, self.threshold, 255, cv2.THRESH_BINARY_INV) self.binaryImagePath = self.root + "\\" + self.filename + '_binary.jpg' cv2.imwrite(self.binaryImagePath, self.cvBinaryImage) # self.binarySceneName='%s_binary' % str(self.sceneID) self.binaryImage = Image(self.binaryImagePath) def findContours(self): #Prevents a fatal crash due to version conflict in cv2.findContours try: self.cnts, hierachy = cv2.findContours(self.cvBinaryImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) except ValueError: ret, self.cnts, hierachy = cv2.findContours( self.cvBinaryImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) self.good_cnts = [] for c in self.cnts: if 5 <= cv2.contourArea(c) <= 500: self.good_cnts.append(c) cv2.drawContours(self.cnts_image, [c], -5, (255, 0, 0), 1) (xstart, ystart, w, h) = cv2.boundingRect(c) M = cv2.moments(c) try: cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) cv2.circle(self.cnts_image, (cx, cy), 2, (0, 0, 255), -1) except ZeroDivisionError: continue self.cntsImagePath = self.root + "\\" + self.filename + '_cnts.jpg' cv2.imwrite(self.cntsImagePath, self.cnts_image) self.contourImage = Image(self.cntsImagePath) def clearView(self): self.removeItem(self.image) self.removeItem(self.binaryImage) self.removeItem(self.contourImage) def showBinaryImage(self): self.clearView() self.addItem(self.binaryImage) def showContourImage(self): self.clearView() self.addItem(self.contourImage) def showOriginalImage(self): self.clearView() self.addItem(self.image) def correct_centers(self): self.findContours() for idx, i in enumerate(self.items()): if isinstance(i, Ellipse): for c in self.good_cnts: (xstart, ystart, w, h) = cv2.boundingRect(c) x = i.pos().toPoint().x() + 5 y = i.pos().toPoint().y() + 5 if xstart <= x <= xstart + w and ystart <= y <= ystart + h: M = cv2.moments(c) try: cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) i.setX(cx - 5) i.setY(cy - 5) self.MainWindow.ellipseMove(i) i.setBrush(QColor('green')) except ZeroDivisionError: continue def showCoords(self, event): try: self.removeItem(self.text) self.removeItem(self.dot) except AttributeError: pass p = self.MainWindow.View.mapToScene(event.x(), event.y()) self.dot = QGraphicsEllipseItem(int(p.x()) - 3, int(p.y()) - 3, 6, 6) self.dot.setBrush(Qt.blue) self.addItem(self.dot) self.text = QGraphicsSimpleTextItem( "x%s_y%s" % (str(int(p.x()) + 5), str(int(p.y()) + 5))) self.text.setBrush(Qt.red) self.text.setPos(p.x(), p.y()) self.addItem(self.text) # self.removeItem(self.text) def removeInfo(self, item): self.current_scene.removeItem(self.text) def add_point(self, event): try: self.path except AttributeError: self.MainWindow.errMessage = "Please link calibration point data with a calibration view" self.MainWindow.errorTitle = "Calibration view not linked" self.MainWindow.errorMsg() return None if self.pointCount == self.MainWindow.num_points: self.MainWindow.errMessage = "You have placed all the points listed in the calibration point file. If you wish to add more points, add more rows to the point file and start over." self.MainWindow.errorTitle = "Cannot place any more points" self.MainWindow.errorMsg() return None p = self.MainWindow.View.mapToScene(event.x(), event.y()) self.circle = Ellipse(0, 0, 10, 10, self.pointCount) self.circle.setPos(p.x() - 5, p.y() - 5) self.addItem(self.circle) self.dotCoords['x_px'][self.pointCount] = int(p.x()) self.dotCoords['y_px'][self.pointCount] = int(p.y()) self.MainWindow.refreshTableData() self.pointCount += 1 def updateTableOnEllipseMove(self, x, y, item): self.dotCoords['x_px'][item.count] = int(x) self.dotCoords['y_px'][item.count] = int(y) self.MainWindow.refreshTableData()
class ExplorerNode(BaseNode): def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max): """ Create node in the graph scene :param tuple nx_node: Node info :param center_pos: The position of the center node :param nx_pos: Position of the nodes in the graph :param int steps: The steps from the center identity :param int steps_max: The steps max of the graph """ super().__init__(nx_node, nx_pos) self.steps = steps self.steps_max = steps_max self.highlighted = False # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) # animation and moves self.timeline = None self.loading_timer = QTimer() self.loading_timer.timeout.connect(self.next_tick) self.loading_counter = 0 self._refresh_colors() self.setPos(center_pos) self.move_to(nx_pos) def _refresh_colors(self): """ Refresh elements in the node """ # color around ellipse outline_color = QColor('black') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('grey') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) if self.highlighted: text_color = QColor('grey') else: text_color = QColor('black') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('grey') self.text_item.setBrush(QBrush(text_color)) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) color = QColor() color.setHsv(120 - 60 / self.steps_max * self.steps, 180 + 50 / self.steps_max * self.steps, 60 + 170 / self.steps_max * self.steps) if self.highlighted: color = color.darker(200) color = color.lighter(math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100) gradient.setColorAt(0, color) gradient.setColorAt(1, color.darker(150)) self.setBrush(QBrush(gradient)) def move_to(self, nx_pos): """ Move to corresponding position :param nx_pos: :return: """ origin_x = self.x() origin_y = self.y() final_x = nx_pos[self.id][0] final_y = nx_pos[self.id][1] def frame_move(frame): value = self.timeline.valueForTime(self.timeline.currentTime()) x = origin_x + (final_x - origin_x) * value y = origin_y + (final_y - origin_y) * value self.setPos(x, y) self.scene().node_moved.emit(self.id, x, y) def timeline_ends(): self.setPos(final_x, final_y) self.timeline = None # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances. # They are not kept anywhere, even if you invoke QTimeLine.start(). self.timeline = QTimeLine(1000) self.timeline.setFrameRange(0, 100) self.timeline.frameChanged.connect(frame_move) self.timeline.finished.connect(timeline_ends) self.timeline.start() def highlight(self): """ Highlight the edge in the scene """ self.highlighted = True self._refresh_colors() self.update(self.boundingRect()) def neutralize(self): """ Neutralize the edge in the scene """ self.highlighted = False self._refresh_colors() self.update(self.boundingRect()) def start_loading_animation(self): """ Neutralize the edge in the scene """ if not self.loading_timer.isActive(): self.loading_timer.start(10) def stop_loading_animation(self): """ Neutralize the edge in the scene """ self.loading_timer.stop() self.loading_counter = 100 self._refresh_colors() self.update(self.boundingRect()) def next_tick(self): """ Next tick :return: """ self.loading_counter += 1 self.loading_counter %= 100 self._refresh_colors() self.update(self.boundingRect())
class MainWindow(QMainWindow, user_interface.Ui_MainWindow): """main user interface """ def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setWindowTitle("Calibrate 3D") self.setWindowIcon( QIcon(os.path.dirname(os.path.abspath(__file__)) + '/dice.png')) self.scenes = {} self.calibrate = DLT(3, 2) self.tableCreated = False self.initUI() def initUI(self): #button connects self.addPointFile_b.clicked.connect(self.newGetCalibrationPoints) self.loadFilledTable_b.clicked.connect(self.readInTable) self.loadCal_b.clicked.connect(self.loadCalibration) self.newView_b.clicked.connect(self.new_add_scene) self.link_b.clicked.connect(self.linkView) self.correct_b.clicked.connect(self.button_correct_centers) self.binary_sb.valueChanged.connect(self.redo_binarization) self.saveTable_b.clicked.connect(self.saveTable) self.calibrate_b.clicked.connect(self.calibrate3D) self.loadTest_b.clicked.connect(self.loadTestTableData) self.testCal_b.clicked.connect(self.test3DCalibration) self.delete_b.clicked.connect(self.deleteView) self.saveTest_b.clicked.connect(self.saveTestData) self.saveCalibration_b.clicked.connect(self.saveCalibration) #list widget connects # self.view_lw.clicked.connect(self.change_scene) self.view_lw.currentRowChanged.connect(self.change_scene) self.original_rb.toggled.connect(self.change_scene) self.binary_rb.toggled.connect(self.change_scene) self.contour_rb.toggled.connect(self.change_scene) #other self.View.mouseDoubleClickEvent = self.add_point self.slider.setRange(1, 500) self.slider.setValue(100) self.slider.valueChanged[int].connect(self.onZoom) self.groupBox_8.setVisible(False) self.link_b.setVisible(False) self.radioButton_2.toggled['bool'].connect(self.link_b.setVisible) def linkView(self): if self.view_lw.count() == 0: self.errMessage = "No views available for linking." self.errorTitle = "Cannot link view" self.errorMsg() return None self.selectedItemText = self.view_lw.currentItem().text() self.current_scene = self.scenes[self.selectedItemText] path = QFileDialog.getOpenFileName(self, "Load image view", filter="Image Files( *.png *.jpg)") self.scenes[self.selectedItemText].linkView(path) self.change_scene() self.View.setScene(self.current_scene) def deleteView(self): try: self.selectedItemText = self.view_lw.currentItem().text() except AttributeError: self.errMessage = "Please click on the view to remove." self.errorTitle = "No view selected" self.errorMsg() return None xCol = str(self.scenes[self.selectedItemText].headx_px) yCol = str(self.scenes[self.selectedItemText].heady_px) self.pointData.drop(columns=[xCol, yCol], inplace=True) self.scenes.pop(self.selectedItemText) self.view_lw.takeItem(self.view_lw.currentRow()) try: self.firstSceneKey = list(self.scenes.keys())[0] self.current_scene = self.scenes[self.firstSceneKey] self.current_scene.showOriginalImage() item = self.view_lw.findItems(self.current_scene.sceneID, Qt.MatchExactly)[0] item.setSelected(True) self.view_lw.setCurrentItem(item) self.View.setScene(self.current_scene) except IndexError: self.current_scene.clear() except AttributeError: pass self.tableWidget.setModel(PandasModel(self.pointData)) """ Table loading and manipulation methods """ def newGetCalibrationPoints(self): self.promptSceneDelete() pointFilePath = QFileDialog.getOpenFileName( self, "Load point data file", filter="Text files( *.txt *.csv)") if pointFilePath[0] != '': self.pointData = pd.read_csv(pointFilePath[0]) self.num_points = len(self.pointData.index) self.nmbViews = (len(self.pointData.columns) - 3) / 2 if self.nmbViews > 0: self.errMessage = "Please load a file containing colums for only the point coordinates." self.errorTitle = "File contains view data!" self.errorMsg() return None self.tableWidget.setModel(PandasModel(self.pointData)) self.tabWidget.setCurrentIndex(1) self.pointFile_l.setText(pointFilePath[0]) def refreshTableData(self): for key in self.scenes: for inner_key in self.scenes[key].dotCoords: if inner_key == 'x_px': self.pointData[self.scenes[key].headx_px] = self.scenes[ key].dotCoords[inner_key] if inner_key == 'y_px': self.pointData[self.scenes[key].heady_px] = self.scenes[ key].dotCoords[inner_key] self.tableWidget.setModel(PandasModel(self.pointData)) def promptSceneDelete(self): if self.view_lw.count() > 0: reply = QMessageBox.question( self, 'Continue?', 'Loading a new calibration table will delete existing views, accept?', QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.scenes = {} self.view_lw.clear() else: return None def readInTable(self): self.promptSceneDelete() pointFilePath = QFileDialog.getOpenFileName( self, "Load populated point data file", filter="Text files( *.txt *.csv)") if pointFilePath[0] != '': self.pointData = pd.read_csv(pointFilePath[0]) self.num_points = len(self.pointData.index) self.nmbViews = int((len(self.pointData.columns) - 3) / 2) self.headers = list(self.pointData.columns) if self.nmbViews < 2: self.errMessage = "File does not contain data sufficient for at least two views" self.errorTitle = "Not enough views in file" self.errorMsg() return None col = 3 for i in range(self.nmbViews): colNames = [] colNames.append(self.headers[col]) colNames.append(self.headers[col + 1]) coords = [] coords.append(self.pointData[self.headers[col]]) coords.append(self.pointData[self.headers[col + 1]]) self.current_scene = Scene(self, coords=coords, headers=colNames) self.current_scene.entered.connect(self.displayInfo) self.current_scene.leave.connect(self.removeInfo) self.current_scene.move.connect(self.ellipseMove) self.scenes[self.current_scene.sceneID] = self.current_scene # self.View.setScene(self.current_scene) item = self.view_lw.findItems(self.current_scene.sceneID, Qt.MatchExactly)[0] item.setSelected(True) self.view_lw.setCurrentItem(item) # self.newView_b.setText("Add view") col += 2 self.pointFile_l.setText(pointFilePath[0]) self.tableWidget.setModel(PandasModel(self.pointData)) self.tabWidget.setCurrentIndex(1) def saveTable(self): path = QFileDialog.getSaveFileName(self, 'Save File', '', 'CSV(*.csv)')[0] self.pointData.to_csv(path, index=False) """ View and Scene related methods """ def new_add_scene(self): if not hasattr(self, 'pointData'): self.errMessage = "Please load a point file or a populate calibration file and then try again." self.errorTitle = "Cannot add view!" self.errorMsg() return None viewPath = QFileDialog.getOpenFileName( self, "Load image view", filter="Image Files( *.png *.jpg)") if viewPath[0] != '': self.current_scene = Scene(self, path=viewPath[0]) self.current_scene.entered.connect(self.displayInfo) self.current_scene.leave.connect(self.removeInfo) self.current_scene.move.connect(self.ellipseMove) self.scenes[self.current_scene.sceneID] = self.current_scene self.View.setScene(self.current_scene) item = self.view_lw.findItems(self.current_scene.sceneID, Qt.MatchExactly)[0] item.setSelected(True) self.view_lw.setCurrentItem(item) self.newView_b.setText("Add view") self.pointData[self.current_scene.headx_px] = N.nan self.pointData[self.current_scene.heady_px] = N.nan self.tableWidget.setModel(PandasModel(self.pointData)) def my_decorator(self): for count, scene in enumerate(self.scenes): if scene in self.selectedItemText: self.current_scene = self.scenes[scene] def change_scene(self): self.tabWidget.setCurrentIndex(0) try: self.selectedItemText = self.view_lw.currentItem().text() self.my_decorator() if not hasattr(self.current_scene, 'path'): emptyScene = QGraphicsScene() self.View.setScene(emptyScene) return None self.binary_sb.setValue(self.current_scene.threshold) if self.original_rb.isChecked() == True: self.current_scene.showOriginalImage() elif self.binary_rb.isChecked() == True: self.current_scene.showBinaryImage() elif self.contour_rb.isChecked() == True: self.current_scene.showContourImage() self.View.setScene(self.current_scene) except AttributeError: pass def redo_binarization(self): if not hasattr(self, 'pointData'): self.errMessage = "Please select a view then try again." self.errorTitle = "No view selected!" self.errorMsg() return None try: self.selectedItemText = self.view_lw.currentItem().text() except IndexError: self.errMessage = "Please click on a view to work with." self.errorTitle = "No view selected" self.errorMsg() return None except AttributeError: self.errMessage = "Please click on a view to work with." self.errorTitle = "No view selected" self.errorMsg() return None try: self.my_decorator() self.current_scene.setThreshold() self.current_scene.findContours() self.current_scene.binarize_image() self.change_scene() except AttributeError: pass def onZoom(self, value): val = value / 100 self.View.resetTransform() self.View.scale(val, val) """ Calibration marker methods """ def add_point(self, event): self.current_scene.add_point(event) def showCoords(self, event): self.current_scene.showCoords(event) def button_correct_centers(self): try: self.current_scene.correct_centers() self.change_scene() except AttributeError: pass def displayInfo(self, item): self.text = QGraphicsSimpleTextItem( "P%s_x%s_y%s" % (str(item.count + 1), str(item.pos().toPoint().x() + 5), str(item.pos().toPoint().y() + 5))) self.text.setBrush(Qt.red) self.text.setPos(item.pos().toPoint().x() + 10, item.pos().toPoint().y() + 10) self.current_scene.addItem(self.text) def removeInfo(self, item): self.current_scene.removeItem(self.text) def ellipseMove(self, item): item.setBrush(QColor('red')) self.current_scene.removeItem(self.text) x = str(item.pos().toPoint().x() + 5) y = str(item.pos().toPoint().y() + 5) self.current_scene.updateTableOnEllipseMove(x, y, item) """ Calibration and testing methods """ def calibrate3D(self): try: x = list(self.pointData['x']) y = list(self.pointData['y']) z = list(self.pointData['z']) except AttributeError: self.errMessage = "Fully populate the calibration table to continue." self.errorTitle = "Calibration table not correctly populated!" self.errorMsg() return None #set up xyz coords list xyz = [] for i in range(len(x)): point = [] point.append(x[i]) point.append(y[i]) point.append(z[i]) print(point) xyz.append(point) px_coords = [] for key in self.scenes: view_coords = [] x_px = list(self.pointData[self.scenes[key].headx_px]) y_px = list(self.pointData[self.scenes[key].heady_px]) view_coords.append(x_px) view_coords.append(y_px) px_coords.append(view_coords) self.nmbDim = 3 self.coefficients = [] errors = [] self.nmbCam = self.nmbViews #get parameters for each view for view in px_coords: uv = [] for i in range(len(view[0])): pair = [] pair.append(view[0][i]) pair.append(view[1][i]) uv.append(pair) L, err = self.calibrate.DLTcalib(self.nmbDim, xyz, uv) self.coefficients.append(L) errors.append(err) def loadTestTableData(self): pointFilePath = QFileDialog.getOpenFileName( self, "Load populated test table", filter="Text files( *.txt *.csv)") if pointFilePath[0] != '': self.testData = pd.read_csv(pointFilePath[0]) self.numTestPoints = len(self.testData.index) self.numTestViews = int((len(self.testData.columns) - 3) / 2) self.testHeaders = list(self.testData.columns) if self.numTestViews < 2: self.errMessage = "File contains less than two views" self.errorTitle = "Not enough views in file" self.errorMsg() return None self.test_tableView.setModel(PandasModel(self.testData)) def saveCalibration(self): try: test = self.coefficients except AttributeError: self.errMessage = "Perform a calibration and then try again." self.errorTitle = "No calibration available!" self.errorMsg() return None path = QFileDialog.getSaveFileName(self, 'Save File', '', 'CSV(*.csv)')[0] if path: print(self.coefficients) self.coefficients_df = pd.DataFrame(self.coefficients) self.coefficients_df.to_csv(path, sep=',', index=False, header=False) def loadCalibration(self): pointFilePath = QFileDialog.getOpenFileName( self, "Load calibration file", filter="Text files( *.txt *.csv)") self.coefficients = [] if pointFilePath[0] != '': self.dfCoefficients = pd.read_csv(pointFilePath[0], header=None) for index, row in self.dfCoefficients.iterrows(): self.coefficients.append(N.asarray(list(row))) self.tabWidget.setCurrentIndex(2) def test3DCalibration(self): x = list(self.testData[self.testHeaders[0]]) y = list(self.testData[self.testHeaders[1]]) z = list(self.testData[self.testHeaders[2]]) self.testXYZ = [] for i in range(self.numTestPoints): testCoord = [] testCoord.append(x[i]) testCoord.append(y[i]) testCoord.append(z[i]) self.testXYZ.append(testCoord) testPxCoords = [] col = 3 for i in range(self.numTestViews): colNames = [] colNames.append(self.testHeaders[col]) colNames.append(self.testHeaders[col + 1]) x_px = list(self.testData[self.testHeaders[col]]) y_px = list(self.testData[self.testHeaders[col + 1]]) coords = [] for i in range(len(x_px)): pair = [] pair.append(x_px[i]) pair.append(y_px[i]) coords.append(pair) testPxCoords.append(coords) col += 2 xyz1234 = N.zeros((len(self.testXYZ), 3)) print(self.coefficients) #use parameters to reconstruct input points for i in range(len(testPxCoords[0])): i_px_coords = [] for view in testPxCoords: i_px_coords.append(view[i]) try: xyz1234[i, :] = self.calibrate.DLTrecon( 3, self.numTestViews, self.coefficients, i_px_coords) except AttributeError: self.errMessage = "No calibration available" self.errorTitle = "Perform a calibration, then try again." self.errorMsg() return None except ValueError: self.errMessage = "Ensure you have loaded a valid calibration file and a valid marker test point file. The calibration file should have 12 columns and as many rows as were used to perform the calibration. The test point file should have 2x the number of views used to obtain the calibration plus 3 more columns for the object-space coordinates." self.errorTitle = "Calibration and test point files are incompatabile!" self.errorMsg() return None rec_xyz = pd.DataFrame(xyz1234, columns=['rec_x', 'rec_y', 'rec_z']) xyz = pd.DataFrame(self.testXYZ, columns=['x', 'y', 'z']) self.results = pd.concat([xyz, rec_xyz], axis=1) self.results['x_e'] = self.results['x'] - self.results['rec_x'] self.results['y_e'] = self.results['y'] - self.results['rec_y'] self.results['z_e'] = self.results['z'] - self.results['rec_z'] self.xmean_l.setText( "%.4f" % ((self.results.x - self.results.rec_x)**2).mean()**.5) self.ymean_l.setText( "%.4f" % ((self.results.y - self.results.rec_y)**2).mean()**.5) self.zmean_l.setText( "%.4f" % ((self.results.z - self.results.rec_z)**2).mean()**.5) self.pointsTested_l.setText(str(self.numTestPoints)) self.errorTitle = "Calibration test successful!" self.errMessage = "The test completed with success. If desired, consult the simple statistics below or save the test's results and postprocess with a third party application." self.errorMsg() # print(self.results) # print(N.mean(N.sqrt(N.sum((N.array(xyz1234)-N.array(xyz))**2,1)))) def saveTestData(self): path = QFileDialog.getSaveFileName(self, 'Save File', '', 'CSV(*.csv)')[0] if path: self.results.to_csv(path, sep=',', index=False) """ Utility functions """ def errorMsg(self): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(self.errMessage) msg.setWindowTitle(self.errorTitle) msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) retval = msg.exec_()
class Node(QGraphicsEllipseItem): def __init__(self, metadata, x_y): """ Create node in the graph scene :param dict metadata: Node metadata :param x_y: Position of the node """ # unpack tuple x, y = x_y super(Node, self).__init__() self.metadata = metadata self.id = metadata['id'] self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED self.status_member = not self.metadata['status'] & NODE_STATUS_OUT self.text = self.metadata['text'] self.setToolTip(self.metadata['tooltip']) self.arcs = [] self.menu = None self.action_sign = None self.action_transaction = None self.action_contact = None self.action_show_member = None # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('black') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) text_color = QColor('grey') if self.status_wallet == NODE_STATUS_HIGHLIGHTED: text_color = QColor('black') self.text_item.setBrush(QBrush(text_color)) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) self.setPos(x, y) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) gradient.setColorAt(0, QColor('white')) gradient.setColorAt(1, QColor('darkgrey')) self.setBrush(QBrush(gradient)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) def mousePressEvent(self, event: QMouseEvent): """ Click on mouse button :param event: mouse event """ if event.button() == Qt.LeftButton: # trigger scene signal self.scene().node_clicked.emit(self.metadata) def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent): """ Mouse enter on node zone :param event: scene hover event """ self.setCursor(Qt.ArrowCursor) def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent): """ Right click on node to show node menu Except on wallet node :param event: scene context menu event """ # no menu on the wallet node if self.status_wallet: return None # create node context menus self.menu = QMenu() # action show member QT_TRANSLATE_NOOP('WoT.Node', 'Informations') self.action_show_member = QAction(QCoreApplication.translate('WoT.Node', 'Informations'), self.scene()) self.menu.addAction(self.action_show_member) self.action_show_member.triggered.connect(self.member_action) # action add identity as contact QT_TRANSLATE_NOOP('WoT.Node', 'Add as contact') self.action_contact = QAction(QCoreApplication.translate('WoT.Node', 'Add as contact'), self.scene()) self.menu.addAction(self.action_contact) self.action_contact.triggered.connect(self.contact_action) # action transaction toward identity QT_TRANSLATE_NOOP('WoT.Node', 'Send money') self.action_transaction = QAction(QCoreApplication.translate('WoT.Node', 'Send money'), self.scene()) self.menu.addAction(self.action_transaction) self.action_transaction.triggered.connect(self.transaction_action) # action sign identity QT_TRANSLATE_NOOP('WoT.Node', 'Certify identity') self.action_sign = QAction(QCoreApplication.translate('WoT.Node', 'Certify identity'), self.scene()) self.menu.addAction(self.action_sign) self.action_sign.triggered.connect(self.sign_action) # run menu self.menu.exec(event.screenPos()) def add_arc(self, arc): """ Add arc to the arc list :param arc: Arc """ self.arcs.append(arc) def member_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_member.emit(self.metadata) def contact_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_contact.emit(self.metadata) def sign_action(self): """ Sign identity node """ # trigger scene signal self.scene().node_signed.emit(self.metadata) def transaction_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_transaction.emit(self.metadata)
class Tile(QGraphicsRectItem): def __init__(self, letter, points, coords, scale, on_position_change=None, move_to_rack=None, parent=None): QGraphicsRectItem.__init__(self, MARGIN, MARGIN, SQUARE_SIZE - 2 * MARGIN, SQUARE_SIZE - 2 * MARGIN, parent) if on_position_change: self.on_position_change = on_position_change if move_to_rack: self.move_to_rack = move_to_rack self.setFlag(QGraphicsItem.ItemIsMovable, True) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) self.points = points self.letter = letter self.scale = scale self.setScale(self.scale) self.setZValue(3) self.setPen(QPen(YELLOW2, 0)) self.setBrush(QBrush(YELLOW)) tile_letter = letter.upper() self.letter_item = QGraphicsSimpleTextItem(tile_letter, self) self.font = QFont("Verdana", 20) if not points: self.font.setBold(True) font_metrics = QFontMetrics(self.font) height = font_metrics.height() width = font_metrics.width(tile_letter) self.letter_item.setX((SQUARE_SIZE - width) / 2 - MARGIN) self.letter_item.setY((SQUARE_SIZE - height) / 2 - MARGIN) self.letter_item.setFont(self.font) self.letter_item.setBrush(QBrush(SEA_GREEN)) self.shadow = QGraphicsRectItem(MARGIN * 2, MARGIN * 2, SQUARE_SIZE, SQUARE_SIZE, self) self.shadow.setFlag(QGraphicsItem.ItemStacksBehindParent) self.shadow.setBrush(QBrush(TRANSPARENT_BLACK)) self.shadow.setPen(QPen(TRANSPARENT, 0)) self.shadow.hide() self.setPos(coords.x * SQUARE_SIZE * scale, coords.y * SQUARE_SIZE * scale) self.coords = None self.update_coords() self.old_position = None self.old_coords = None self.is_placed = False if points: self.add_points() def __str__(self): return self.letter def add_points(self): points = QGraphicsSimpleTextItem(str(self.points), self) font = QFont("Verdana", 10) font_metrics = QFontMetrics(font) height = font_metrics.height() width = font_metrics.width(str(self.points)) points.setFont(font) points.setBrush(QBrush(SEA_GREEN)) points.setX(SQUARE_SIZE - MARGIN - width) points.setY(SQUARE_SIZE - MARGIN - height) def resize(self, scale): self.scale = scale self.setScale(scale) self.setPos(self.coords.x * SQUARE_SIZE * scale, self.coords.y * SQUARE_SIZE * scale) def change_to_blank(self, new_letter): if self.letter == BLANK: self.letter = new_letter self.letter_item.setText(new_letter.upper()) self.font.setBold(True) font_metrics = QFontMetrics(self.font) height = font_metrics.height() width = font_metrics.width(self.letter) self.letter_item.setFont(self.font) self.letter_item.setX((SQUARE_SIZE - width) / 2 - MARGIN) self.letter_item.setY((SQUARE_SIZE - height) / 2 - MARGIN) def change_back(self): self.letter = BLANK self.letter_item.setText(BLANK) def get_letter_and_points(self): return self.letter, self.points def mousePressEvent(self, event): if self.is_placed: return if event.button() == Qt.RightButton: return self.setScale(self.scale * 1.1) self.setZValue(10) self.old_position = self.pos() self.old_coords = self.coords self.setPos(self.x() - 2 * MARGIN, self.y() - 2 * MARGIN) self.shadow.show() QGraphicsRectItem.mousePressEvent(self, event) def mouseReleaseEvent(self, event): if self.is_placed: return if event.button() == Qt.RightButton: self.move_to_rack(self) return self.setScale(self.scale) current_position = self.pos() self.setX( round((self.x() + MARGIN * 2) / (SQUARE_SIZE * self.scale)) * SQUARE_SIZE * self.scale) self.setY( round((self.y() + MARGIN * 2) / (SQUARE_SIZE * self.scale)) * SQUARE_SIZE * self.scale) if current_position != self.pos(): self.update_coords() self.on_position_change(self) self.setZValue(3) self.shadow.hide() QGraphicsRectItem.mouseReleaseEvent(self, event) def update_coords(self): x = round(self.x() / SQUARE_SIZE / self.scale) y = round(self.y() / SQUARE_SIZE / self.scale) self.coords = Coords(x, y) def move(self, position): self.setPos(position) self.update_coords() def move_to_coords(self, coords): position = QPoint(coords.x * SQUARE_SIZE * self.scale, coords.y * SQUARE_SIZE * self.scale) self.move(position) def undo_move(self): self.setPos(self.old_position) self.update_coords() def swap_with_other(self, other): other.move(self.old_position) def remove_highlight(self): self.letter_item.setBrush(QBrush(SEA_GREEN)) def place(self): self.letter_item.setBrush(QBrush(LIGHT_SEA_GREEN)) self.setBrush(QBrush(YELLOW2)) self.setPen(QPen(YELLOW2, 0)) self.setFlag(QGraphicsItem.ItemIsMovable, False) self.is_placed = True
class ActiveSliceItem(QGraphicsRectItem): """ActiveSliceItem for the Path View""" def __init__(self, part_item, active_base_index): super(ActiveSliceItem, self).__init__(part_item) self._part_item = part_item self._getActiveTool = part_item._getActiveTool self._active_slice = 0 self._low_drag_bound = 0 self._high_drag_bound = self.part().maxBaseIdx() self._controller = ActiveSliceItemController(self, part_item.part()) self._label = QGraphicsSimpleTextItem("", parent=self) self._label.setPos(0, -18) self._label.setFont(_FONT) self._label.setBrush(_LABEL_BRUSH) self._label.hide() self.setFlag(QGraphicsItem.ItemIsMovable) self.setAcceptHoverEvents(True) self.setZValue(styles.ZACTIVESLICEHANDLE) self.setRect(QRectF(0, 0, _BASE_WIDTH,\ self._part_item.boundingRect().height())) self.setPos(active_base_index * _BASE_WIDTH, 0) self.setBrush(_BRUSH) self.setPen(_PEN) # reuse select tool methods for other tools self.addSeqToolMousePress = self.selectToolMousePress self.addSeqToolMouseMove = self.selectToolMouseMove self.breakToolMousePress = self.selectToolMousePress self.breakToolMouseMove = self.selectToolMouseMove self.insertionToolMousePress = self.selectToolMousePress self.insertionToolMouseMove = self.selectToolMouseMove self.paintToolMousePress = self.selectToolMousePress self.paintToolMouseMove = self.selectToolMouseMove self.pencilToolMousePress = self.selectToolMousePress self.pencilToolMouseMove = self.selectToolMouseMove self.skipToolMousePress = self.selectToolMousePress self.skipToolMouseMove = self.selectToolMouseMove # end def ### SLOTS ### def strandChangedSlot(self, sender, vh): pass # end def def updateRectSlot(self, part): bw = _BASE_WIDTH new_rect = QRectF(0, 0, bw,\ self._part_item.virtualHelixBoundingRect().height()) if new_rect != self.rect(): self.setRect(new_rect) self._hideIfEmptySelection() self.updateIndexSlot(part, part.activeBaseIndex()) return new_rect # end def def updateIndexSlot(self, part, base_index): """The slot that receives active slice changed notifications from the part and changes the receiver to reflect the part""" label = self._label bw = _BASE_WIDTH bi = util.clamp(int(base_index), 0, self.part().maxBaseIdx()) self.setPos(bi * bw, -styles.PATH_HELIX_PADDING) self._active_slice = bi if label: label.setText("%d" % bi) label.setX((bw - label.boundingRect().width()) / 2) # end def ### ACCESSORS ### def activeBaseIndex(self): return self.part().activeBaseIndex() # end def def part(self): return self._part_item.part() # end def def partItem(self): return self._part_item # end def ### PUBLIC METHODS FOR DRAWING / LAYOUT ### def removed(self): scene = self.scene() scene.removeItem(self._label) scene.removeItem(self) self._part_item = None self._label = None self._controller.disconnectSignals() self.controller = None # end def def resetBounds(self): """Call after resizing virtualhelix canvas.""" self._high_drag_bound = self.part().maxBaseIdx() # end def ### PRIVATE SUPPORT METHODS ### def _hideIfEmptySelection(self): vis = self.part().numberOfVirtualHelices() > 0 self.setVisible(vis) self._label.setVisible(vis) # end def def _setActiveBaseIndex(self, base_index): self.part().setActiveBaseIndex(base_index) # end def ### EVENT HANDLERS ### def hoverEnterEvent(self, event): self.setCursor(Qt.OpenHandCursor) self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex()) QGraphicsItem.hoverEnterEvent(self, event) # end def def hoverLeaveEvent(self, event): self.setCursor(Qt.ArrowCursor) self._part_item.updateStatusBar("") QGraphicsItem.hoverLeaveEvent(self, event) # end def def mousePressEvent(self, event): """ Parses a mousePressEvent, calling the approproate tool method as necessary. Stores _move_idx for future comparison. """ if event.button() != Qt.LeftButton: event.ignore() QGraphicsItem.mousePressEvent(self, event) return self.scene().views()[0].addToPressList(self) self._move_idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH)) tool_method_name = self._getActiveTool().methodPrefix() + "MousePress" if hasattr(self, tool_method_name): # if the tool method exists modifiers = event.modifiers() getattr(self, tool_method_name)(modifiers) # call tool method def mouseMoveEvent(self, event): """ Parses a mouseMoveEvent, calling the approproate tool method as necessary. Updates _move_idx if it changed. """ tool_method_name = self._getActiveTool().methodPrefix() + "MouseMove" if hasattr(self, tool_method_name): # if the tool method exists idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH)) if idx != self._move_idx: # did we actually move? modifiers = event.modifiers() self._move_idx = idx getattr(self, tool_method_name)(modifiers, idx) # call tool method def customMouseRelease(self, event): """ Parses a mouseReleaseEvent, calling the approproate tool method as necessary. Deletes _move_idx if necessary. """ tool_method_name = self._getActiveTool().methodPrefix( ) + "MouseRelease" if hasattr(self, tool_method_name): # if the tool method exists modifiers = event.modifiers() x = event.pos().x() getattr(self, tool_method_name)(modifiers, x) # call tool method if hasattr(self, '_move_idx'): del self._move_idx ### TOOL METHODS ### def selectToolMousePress(self, modifiers): """ Set the allowed drag bounds for use by selectToolMouseMove. """ if (modifiers & Qt.AltModifier) and (modifiers & Qt.ShiftModifier): self.part().undoStack().beginMacro("Auto-drag Scaffold(s)") for vh in self.part().getVirtualHelices(): # SCAFFOLD # resize 3' first for strand in vh.scaffoldStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx3p) if strand.isDrawn5to3(): strand.resize((idx5p, hi)) else: strand.resize((lo, idx5p)) # resize 5' second for strand in vh.scaffoldStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx5p): lo, hi = strand.getResizeBounds(idx5p) if strand.isDrawn5to3(): strand.resize((lo, idx3p)) else: strand.resize((idx3p, hi)) # STAPLE # resize 3' first for strand in vh.stapleStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx3p) if strand.isDrawn5to3(): strand.resize((idx5p, hi)) else: strand.resize((lo, idx5p)) # resize 5' second for strand in vh.stapleStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx5p) if strand.isDrawn5to3(): strand.resize((lo, idx3p)) else: strand.resize((idx3p, hi)) self.part().undoStack().endMacro() # end def def selectToolMouseMove(self, modifiers, idx): """ Given a new index (pre-validated as different from the prev index), calculate the new x coordinate for self, move there, and notify the parent strandItem to redraw its horizontal line. """ idx = util.clamp(idx, self._low_drag_bound, self._high_drag_bound) x = int(idx * _BASE_WIDTH) self.setPos(x, self.y()) self.updateIndexSlot(None, idx) self._setActiveBaseIndex(idx) self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
def mainFunc(self, playing, scriptList, scriptPos): if self.inputImg is not None: self.outputImg = self.inputImg pass_ = 0 fx = 1.0 fy = 1.0 offset_x = 0.0 offset_y = 0.0 for i in range(scriptPos): widget = scriptList[i][1] if widget.objectName() == 'resize': fx *= widget.dblFx.value() fy *= widget.dblFx.value() pass_ += widget.pass_ for item in widget.graphicsItems: try: # ~ print('item.rect() ', item.rect()) if fx != 1.0: item.setScale(1 / fx) # ~ if fy != 1.0: # ~ item.setHeight(item.height()/fy) if offset_x: item.setX((item.x() + offset_x) / fx) # ~ item.setX( (item.x() + offset_x)/1.0 ) # ~ print('offset_x: ', offset_x, ' fx: ', fx) if offset_y: item.setY((item.y() + offset_y) / fy) # ~ item.setY( (item.y() + offset_y)/1.0 ) self.graphicsView.scene().addItem(item) item.setZValue(1) except RuntimeError as e: print(time.time(), 'Runtime Error show_graphics_items mainFunc') print(e) if widget.objectName() == 'circles': if widget.chkCrop.isChecked(): try: circle = widget.graphicsItems[0] # ~ circle = item offset_x = circle.x() offset_x = circle.rect().left() offset_y = circle.y() offset_y = circle.rect().top() # ~ print('offer setter ', offset_x) except IndexError as e: print(e) if self.chkShowPass.isChecked(): # ~ h = self.graphicsView.scene().height() # ~ w = self.graphicsView.scene().width() h = self.inputImg.shape[0] w = self.inputImg.shape[1] # ~ sfh = float(h)/float(self.graphicsView.minimumHeight()) # ~ sfw = float(w)/float(self.graphicsView.minimumWidth()) # ~ sf = min(sfh,sfw) outlineRect = QGraphicsRectItem(0, 0, w, h) outlineLine = QGraphicsLineItem(0, h, w, 0) font = QFont("DejaVu Sans", 45) if pass_ == scriptPos: # the overall result is pass text = 'PASS' pen = QPen(QColor(0, 255, 0), 8) #green for pass brush = QBrush(QColor(0, 255, 0)) else: # overall result is fail text = 'FAIL' pen = QPen(QColor(255, 0, 0), 8) #red for fail brush = QBrush(QColor(255, 0, 0)) outlineLine.setPen(pen) self.graphicsView.scene().addItem(outlineLine) outlineLine.setZValue(1) outlineRect.setPen(pen) self.graphicsView.scene().addItem(outlineRect) textItem = QGraphicsSimpleTextItem(text, ) textItem.setFont(font) textItem.setBrush(brush) textItem.setPos(w / 10.0, h / 10.0) self.graphicsView.scene().addItem(textItem) textItem.setZValue(1)
class CalendarDesklet(Desklet): def __init__(self): super().__init__() self.model = CalendarModel() self.cursor_pos = None self.cursor = QGraphicsRectItem(self.root) self.header = QGraphicsSimpleTextItem(self.root) self.weekdays = [] days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] for day in days: self.weekdays.append(QGraphicsSimpleTextItem(day, self.root)) self.header_line = QGraphicsLineItem(self.root) self.days = [] for _ in range(0, 6 * 7): self.days.append(QGraphicsSimpleTextItem(self.root)) def next_month(self): self.model.next_month() self.layout() def previous_month(self): self.model.previous_month() self.layout() def set_rect(self, rect): super().set_rect(rect) self.layout() def set_style(self, style): super().set_style(style) font = QFont(style.font) font.setPixelSize(48) self.header.setBrush(style.midcolor) self.header.setFont(font) font = QFont(style.font) font.setPixelSize(32) self.header_line.setPen(style.foreground_color) self.cursor.setBrush(style.midcolor) self.cursor.setPen(QPen(Qt.NoPen)) for widget in self.weekdays: widget.setFont(font) widget.setBrush(style.foreground_color) for widget in self.days: widget.setFont(font) widget.setBrush(self.style.foreground_color) self.layout() def layout(self): cell_width = (self.rect.width()) / 7.0 cell_height = (self.rect.height() - 64) / 7.0 x = self.rect.left() y = self.rect.top() fm = QFontMetrics(self.header.font()) rect = fm.boundingRect(self.header.text()) self.header.setPos(x + self.rect.width() / 2 - rect.width() / 2, y) y += fm.height() for row, day in enumerate(self.weekdays): fm = QFontMetrics(day.font()) rect = fm.boundingRect(day.text()) day.setPos(x + row * cell_width + cell_width / 2 - rect.width() / 2, y) y += fm.height() self.header_line.setLine(x, y, x + self.rect.width() - 3, y) y += 8 for n, widget in enumerate(self.days): col = n % 7 row = n // 7 rect = fm.boundingRect(widget.text()) widget.setPos(x + col * cell_width + cell_width / 2 - rect.width() / 2, y + row * cell_height + cell_height / 2 - fm.height() / 2) # if day.month != self.now.month: # widget.setBrush(self.style.midcolor) # else: if self.cursor_pos is not None: self.cursor.setRect(x + self.cursor_pos[0] * cell_width, y + self.cursor_pos[1] * cell_height, cell_width, cell_height) self.cursor.show() else: self.cursor.hide() def update(self, now): self.model.update(now) # update header self.header.setText( date(self.model.year, self.model.month, 1).strftime("%B %Y")) # calculate the date of the top/left calendar entry current_date = date(self.model.year, self.model.month, 1) current_date = current_date - timedelta(current_date.weekday()) self.cursor_pos = None for n, widget in enumerate(self.days): col = n % 7 row = n // 7 if current_date == self.model.today: self.cursor_pos = (col, row) widget.setText("%d" % current_date.day) self.days[n] = widget current_date += timedelta(days=1) self.layout()