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 __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 _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 __init__(self, v_from: Vertex, v_to: Vertex, node: Vertex, oriented: bool, weight: int = 1, weighted: bool = True): super().__init__() self.v_from = v_from self.v_to = v_to self.node = node self.weighted = weighted self.weight = weight # self.pen = QPen(QBrush(QColor(0, 0, 0)), 3) if weighted: self.ellipse = QGraphicsEllipseItem(self.node.x - 8, self.node.y - 8, 16, 16) self.ellipse.setBrush(QBrush(QColor(0, 0, 0))) self.addToGroup(self.ellipse) text = QGraphicsSimpleTextItem(str(self.weight)) font = QFont() font.setPixelSize(8) text.setPen(QColor(255, 255, 255)) text.setFont(font) # настраиваем расположение текста if self.weight < 10: text.setPos(self.node.x - 16 / 6, self.node.y - 16 / 3) else: text.setPos(self.node.x - 4, self.node.y - 16 / 3) self.addToGroup(text) else: self.ellipse = QGraphicsEllipseItem(self.node.x - 4, self.node.y - 4, 8, 8) self.ellipse.setBrush(QBrush(QColor(0, 0, 0))) self.addToGroup(self.ellipse)
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, 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 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)
def drawPiano(self): piano_keys_width = self.piano_width - self.padding labels = ('B', 'Bb', 'A', 'Ab', 'G', 'Gb', 'F', 'E', 'Eb', 'D', 'Db', 'C') black_notes = (2, 4, 6, 9, 11) piano_label = QFont() piano_label.setPointSize(6) self.piano = QGraphicsRectItem(0, 0, piano_keys_width, self.piano_height) self.piano.setPos(0, self.header_height) self.addItem(self.piano) key = PianoKeyItem(piano_keys_width, self.note_height, 78, self.piano) label = QGraphicsSimpleTextItem('C9', key) label.setPos(18, 1) label.setFont(piano_label) key.setBrush(QColor(255, 255, 255)) for i in range(self.end_octave - self.start_octave, 0, -1): for j in range(self.notes_in_octave, 0, -1): note = (self.end_octave - i + 3) * 12 - j if j in black_notes: key = PianoKeyItem(piano_keys_width / 1.4, self.note_height, note, self.piano) key.setBrush(QColor(0, 0, 0)) key.setZValue(1.0) key.setPos( 0, self.note_height * j + self.octave_height * (i - 1)) elif (j - 1) and (j + 1) in black_notes: key = PianoKeyItem(piano_keys_width, self.note_height * 2, note, self.piano) key.setBrush(QColor(255, 255, 255)) key.setPos( 0, self.note_height * j + self.octave_height * (i - 1) - self.note_height / 2.) elif (j - 1) in black_notes: key = PianoKeyItem(piano_keys_width, self.note_height * 3. / 2, note, self.piano) key.setBrush(QColor(255, 255, 255)) key.setPos( 0, self.note_height * j + self.octave_height * (i - 1) - self.note_height / 2.) elif (j + 1) in black_notes: key = PianoKeyItem(piano_keys_width, self.note_height * 3. / 2, note, self.piano) key.setBrush(QColor(255, 255, 255)) key.setPos( 0, self.note_height * j + self.octave_height * (i - 1)) if j == 12: label = QGraphicsSimpleTextItem( '{}{}'.format(labels[j - 1], self.end_octave - i + 1), key) label.setPos(18, 6) label.setFont(piano_label) self.piano_keys.append(key)
def createLabel(self) -> QGraphicsSimpleTextItem: """ Returns: the label item """ label = QGraphicsSimpleTextItem("%d" % (self._id_num)) label.setFont(_FONT) label.setZValue(styles.ZPATHHELIX) label.setParentItem(self) return label
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 createLabel(self): """Summary Returns: TYPE: Description """ label = QGraphicsSimpleTextItem("%d" % (self._id_num)) label.setFont(_FONT) label.setZValue(styles.ZPATHHELIX) label.setParentItem(self) return label
class GridViewerCell(QGraphicsPolygonItem): def __init__(self, gridViewer, x, y): super(GridViewerCell, self).__init__() self.gridViewer = gridViewer self.x = x self.y = y self.selected = False def generate(self, points, show_label=False): qpolygon = QPolygonF([QPointF(xp, yp) for xp, yp in points]) self.setPolygon(qpolygon) pen = QPen() pen.setWidth(3) self.setPen(pen) self.setFlag(QGraphicsItem.ItemIsFocusable) self.label = QGraphicsSimpleTextItem("{}-{}".format(self.x, self.y), parent=self) self.label.setVisible(show_label) if len(points) == 6: k = 0.5 if (self.x % 2) != 0 else 0 self.label.setPos( QPointF(((self.x * 0.866) + 0.2886) * 120, (self.y + k + 0.5) * 120)) else: self.label.setPos(QPointF(self.x * 120, self.y * 120)) font = QFont() font.setPointSize(20) self.label.setFont(font) def select(self): self.setBrush(QBrush(QColor(200, 0, 0, 100))) self.selected = True self.gridViewer.add_to_selection(self.x, self.y) def unselect(self): self.setBrush(QBrush()) self.selected = False self.gridViewer.remove_from_selection(self.x, self.y) def mousePressEvent(self, *args, **kwargs): if self.selected: self.unselect() else: self.select() def show_label(self, visible): self.label.setVisible(visible)
def createLabel(self) -> QGraphicsSimpleTextItem: """Creates a text label to display the ID number. Font and Z are set in gridstyles. Returns: the label """ label = QGraphicsSimpleTextItem("%d" % self.idNum()) label.setFont(_FONT) label.setZValue(_ZVALUE) label.setParentItem(self) return label
def drawHRefs(self): if self.xvmax < self.xvmin or self.awidth <= 0: return minsep = 30 factor = 1 unitincrement = self.awidth/float(self.xvmax-self.xvmin) xmaxint = self.xvmax vx = int(self.xvmin) pstart = self.value2point(vx, self.yvmin) px = pstart.x() pystart = pstart.y() pend = self.value2point(xmaxint, self.yvmin) pxend = pend.x() pyend = pend.y()-2 try: minsep = 10 * max([len(h) for h in self.hheaders]) except Exception: pass while (unitincrement*factor < minsep): provfactor = 2*factor if(unitincrement*provfactor > minsep): factor = provfactor break provfactor = 5*factor if(unitincrement*provfactor > minsep): factor = provfactor break factor = 10*factor # px+=unitincrement*factor # vx +=factor while(px <= pxend): colour = QtGui.QColor(0, 0, 0, 255) PlotLine(px+0.5, pystart+2, px+0.5, pyend, 1.5, colour, self) try: header = self.hheaders[vx] except IndexError: header = vx nlabel = QGraphicsSimpleTextItem( "{}".format(header), self) font = nlabel.font() font.setPixelSize(20) nlabel.setFont(font) nlabelrect = nlabel.boundingRect() nlabel.setPos(px + 0.5 - nlabelrect.width()/2, pystart+3) px += unitincrement*factor vx += factor
def addRectText(x, w, parent, text="", level=0, tooltip=""): deltaH = LEVEL_HEIGHT if level else 0 r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text) r.setPos(x, deltaH) txt = QGraphicsSimpleTextItem(text, r) f = txt.font() f.setPointSize(8) fm = QFontMetricsF(f) elidedText = fm.elidedText(text, Qt.ElideMiddle, w) txt.setFont(f) txt.setText(elidedText) txt.setPos(r.boundingRect().center() - txt.boundingRect().center()) txt.setY(0) return r
def _draw_node(self, node: Node, x: float, y: float): """ Drawing the Node on the map. """ text_item = QGraphicsSimpleTextItem() font = text_item.font() font.setPointSize(font.pointSize() - 2) font.setPixelSize(self._font_size) text_item.setText(str(node.value())) text_item.setPos(x, y) text_item.setFont(font) self._scene.addItem(text_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 drawVRefs(self): if self.yvmax < self.yvmin or self.aheight <= 0: return minsep = 30 factor = 1 try: unitincrement = self.aheight/float(self.yvmax-self.yvmin) except ZeroDivisionError: msg = "Division by zero in drawVRefs. Limits are {}-{}" print(msg.format(self.yvmin, self.yvmax)) while (unitincrement*factor < minsep): provfactor = 2*factor if(unitincrement*provfactor > minsep): factor = provfactor break provfactor = 5*factor if(unitincrement*provfactor > minsep): factor = provfactor break factor = 10*factor if (self.yvmin <= 0): vy = int(self.yvmin/factor)*factor else: vy = (int(self.yvmin/factor)+1)*factor pstart = self.value2point(self.xvmin, vy) pxstart = pstart.x() py = pstart.y() pend = self.value2point(self.xvmax, self.yvmax) pxend = pend.x() pyend = pend.y() while(py > pyend): colour = QtGui.QColor(0, 0, 0, 200) if vy == 0: PlotLine(pxstart-2, py, pxend, py, 1.5, QtCore.Qt.black, self) else: PlotLine(pxstart-2, py, pxend, py, 0.5, colour, self) nlabel = QGraphicsSimpleTextItem("{}".format(vy), self) font = nlabel.font() font.setPixelSize(20) nlabel.setFont(font) nlabelrect = nlabel.boundingRect() nlabel.setPos(pxstart - nlabelrect.width() - 5, py-nlabelrect.height()/2) py -= unitincrement*factor vy += factor
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__(self, v: Vertex): super().__init__() dark = 20 self.vertex_radius = VERTEX_RADIUS self.pen = QPen(QBrush(QColor(68, 191, 46)), 3) if v.color is None \ else QPen(QBrush(QColor(v.color.red() - dark, v.color.green() - dark, v.color.blue() - dark)), 3) self.brush = QBrush(QColor(91, 255, 62)) if v.color is None else QBrush(v.color) self.v = v self.offset_coords = QPointF() self.setFlag(QGraphicsItem.ItemIgnoresTransformations) # создаем элипс для вершины ellipse = QGraphicsEllipseItem(v.x - (self.vertex_radius / 2), v.y - (self.vertex_radius / 2), self.vertex_radius, self.vertex_radius) ellipse.setPen(self.pen) ellipse.setBrush(self.brush) # создаем текст для имени вершины text = QGraphicsSimpleTextItem(v.name) font = QFont() font.setPixelSize(self.vertex_radius / 2) text.setFont(font) # настраиваем расположение текста if int(v.name) < 10: text.setPos(v.x - self.vertex_radius / 6, v.y - self.vertex_radius / 3) else: text.setPos(v.x - self.vertex_radius / 4, v.y - self.vertex_radius / 3) # объединяем self.addToGroup(ellipse) self.addToGroup(text) self.startPos = None self.rightButtonPressed = False self.edge_from = None
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 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 drawPiano(self): piano_keys_width = self.piano_width - self.padding labels = ('B','Bb','A','Ab','G','Gb','F','E','Eb','D','Db','C') black_notes = (2,4,6,9,11) piano_label = QFont() piano_label.setPointSize(6) self.piano = QGraphicsRectItem(0, 0, piano_keys_width, self.piano_height) self.piano.setPos(0, self.header_height) self.addItem(self.piano) key = PianoKeyItem(piano_keys_width, self.note_height, self.piano) label = QGraphicsSimpleTextItem('C8', key) label.setPos(18, 1) label.setFont(piano_label) key.setBrush(QColor(255, 255, 255)) 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): if j in black_notes: key = PianoKeyItem(piano_keys_width/1.4, self.note_height, self.piano) key.setBrush(QColor(0, 0, 0)) key.setZValue(1.0) key.setPos(0, self.note_height * j + self.octave_height * (i - 1)) elif (j - 1) and (j + 1) in black_notes: key = PianoKeyItem(piano_keys_width, self.note_height * 2, self.piano) key.setBrush(QColor(255, 255, 255)) key.setPos(0, self.note_height * j + self.octave_height * (i - 1) - self.note_height/2.) elif (j - 1) in black_notes: key = PianoKeyItem(piano_keys_width, self.note_height * 3./2, self.piano) key.setBrush(QColor(255, 255, 255)) key.setPos(0, self.note_height * j + self.octave_height * (i - 1) - self.note_height/2.) elif (j + 1) in black_notes: key = PianoKeyItem(piano_keys_width, self.note_height * 3./2, self.piano) key.setBrush(QColor(255, 255, 255)) key.setPos(0, self.note_height * j + self.octave_height * (i - 1)) if j == 12: label = QGraphicsSimpleTextItem('{}{}'.format(labels[j - 1], self.end_octave - i), key ) label.setPos(18, 6) label.setFont(piano_label) self.piano_keys.append(key)
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)
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()
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)
def createLabel(self): label = QGraphicsSimpleTextItem("%d" % self._virtual_helix.number()) label.setFont(_FONT) label.setZValue(styles.ZPATHHELIX) label.setParentItem(self) return label
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 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 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 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()
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 ModuleItem(UMLItem): """ Class implementing a module item. """ ItemType = "module" def __init__(self, model=None, x=0, y=0, rounded=False, parent=None, scene=None): """ Constructor @param model module model containing the module data (ModuleModel) @param x x-coordinate (integer) @param y y-coordinate (integer) @keyparam rounded flag indicating a rounded corner (boolean) @keyparam parent reference to the parent object (QGraphicsItem) @keyparam scene reference to the scene object (QGraphicsScene) """ UMLItem.__init__(self, model, x, y, rounded, parent) scene.addItem(self) if self.model: self.__createTexts() self.__calculateSize() def __createTexts(self): """ Private method to create the text items of the module item. """ if self.model is None: return boldFont = QFont(self.font) boldFont.setBold(True) classes = self.model.getClasses() x = self.margin + self.rect().x() y = self.margin + self.rect().y() self.header = QGraphicsSimpleTextItem(self) self.header.setFont(boldFont) self.header.setText(self.model.getName()) self.header.setPos(x, y) y += self.header.boundingRect().height() + self.margin if classes: txt = "\n".join(classes) else: txt = " " self.classes = QGraphicsSimpleTextItem(self) self.classes.setFont(self.font) self.classes.setText(txt) self.classes.setPos(x, y) def __calculateSize(self): """ Private method to calculate the size of the module item. """ if self.model is None: return width = self.header.boundingRect().width() height = self.header.boundingRect().height() if self.classes: width = max(width, self.classes.boundingRect().width()) height = height + self.classes.boundingRect().height() self.setSize(width + 2 * self.margin, height + 2 * self.margin) def setModel(self, model): """ Public method to set the module model. @param model module model containing the module data (ModuleModel) """ self.scene().removeItem(self.header) self.header = None if self.classes: self.scene().removeItem(self.classes) self.meths = None self.model = model self.__createTexts() self.__calculateSize() def paint(self, painter, option, widget=None): """ Public method to paint the item in local coordinates. @param painter reference to the painter object (QPainter) @param option style options (QStyleOptionGraphicsItem) @param widget optional reference to the widget painted on (QWidget) """ pen = self.pen() if (option.state & QStyle.State_Selected) == \ QStyle.State(QStyle.State_Selected): pen.setWidth(2) else: pen.setWidth(1) painter.setPen(pen) painter.setBrush(self.brush()) painter.setFont(self.font) offsetX = self.rect().x() offsetY = self.rect().y() w = self.rect().width() h = self.rect().height() painter.drawRect(offsetX, offsetY, w, h) y = self.margin + self.header.boundingRect().height() painter.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y) self.adjustAssociations() def buildItemDataString(self): """ Public method to build a string to persist the specific item data. This string must start with ", " and should be built like "attribute=value" with pairs separated by ", ". value must not contain ", " or newlines. @return persistence data (string) """ entries = [ "name={0}".format(self.model.getName()), ] classes = self.model.getClasses() if classes: entries.append("classes={0}".format("||".join(classes))) return ", " + ", ".join(entries) def parseItemDataString(self, version, data): """ Public method to parse the given persistence data. @param version version of the data (string) @param data persisted data to be parsed (string) @return flag indicating success (boolean) """ parts = data.split(", ") if len(parts) < 1: return False name = "" classes = [] for part in parts: key, value = part.split("=", 1) if key == "name": name = value.strip() elif key == "classes": classes = value.strip().split("||") else: return False self.model = ModuleModel(name, classes) self.__createTexts() self.__calculateSize() return True
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 PackageItem(UMLItem): """ Class implementing a package item. """ ItemType = "package" def __init__(self, model=None, x=0, y=0, rounded=False, noModules=False, parent=None, scene=None): """ Constructor @param model package model containing the package data (PackageModel) @param x x-coordinate (integer) @param y y-coordinate (integer) @param rounded flag indicating a rounded corner (boolean) @keyparam noModules flag indicating, that no module names should be shown (boolean) @keyparam parent reference to the parent object (QGraphicsItem) @keyparam scene reference to the scene object (QGraphicsScene) """ UMLItem.__init__(self, model, x, y, rounded, parent) self.noModules = noModules scene.addItem(self) if self.model: self.__createTexts() self.__calculateSize() def __createTexts(self): """ Private method to create the text items of the class item. """ if self.model is None: return boldFont = QFont(self.font) boldFont.setBold(True) modules = self.model.getModules() x = self.margin + self.rect().x() y = self.margin + self.rect().y() self.header = QGraphicsSimpleTextItem(self) self.header.setFont(boldFont) self.header.setText(self.model.getName()) self.header.setPos(x, y) y += self.header.boundingRect().height() + self.margin if not self.noModules: if modules: txt = "\n".join(modules) else: txt = " " self.modules = QGraphicsSimpleTextItem(self) self.modules.setFont(self.font) self.modules.setText(txt) self.modules.setPos(x, y) else: self.modules = None def __calculateSize(self): """ Private method to calculate the size of the package widget. """ if self.model is None: return width = self.header.boundingRect().width() height = self.header.boundingRect().height() if self.modules: width = max(width, self.modules.boundingRect().width()) height = height + self.modules.boundingRect().height() latchW = width / 3.0 latchH = min(15.0, latchW) self.setSize(width + 2 * self.margin, height + latchH + 2 * self.margin) x = self.margin + self.rect().x() y = self.margin + self.rect().y() + latchH self.header.setPos(x, y) y += self.header.boundingRect().height() + self.margin if self.modules: self.modules.setPos(x, y) def setModel(self, model): """ Public method to set the package model. @param model package model containing the package data (PackageModel) """ self.scene().removeItem(self.header) self.header = None if self.modules: self.scene().removeItem(self.modules) self.modules = None self.model = model self.__createTexts() self.__calculateSize() def paint(self, painter, option, widget=None): """ Public method to paint the item in local coordinates. @param painter reference to the painter object (QPainter) @param option style options (QStyleOptionGraphicsItem) @param widget optional reference to the widget painted on (QWidget) """ pen = self.pen() if (option.state & QStyle.State_Selected) == \ QStyle.State(QStyle.State_Selected): pen.setWidth(2) else: pen.setWidth(1) offsetX = self.rect().x() offsetY = self.rect().y() w = self.rect().width() latchW = w / 3.0 latchH = min(15.0, latchW) h = self.rect().height() - latchH + 1 painter.setPen(pen) painter.setBrush(self.brush()) painter.setFont(self.font) painter.drawRect(offsetX, offsetY, latchW, latchH) painter.drawRect(offsetX, offsetY + latchH, w, h) y = self.margin + self.header.boundingRect().height() + latchH painter.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y) self.adjustAssociations() def buildItemDataString(self): """ Public method to build a string to persist the specific item data. This string must start with ", " and should be built like "attribute=value" with pairs separated by ", ". value must not contain ", " or newlines. @return persistence data (string) """ entries = [ "no_modules={0}".format(self.noModules), "name={0}".format(self.model.getName()), ] modules = self.model.getModules() if modules: entries.append("modules={0}".format("||".join(modules))) return ", " + ", ".join(entries) def parseItemDataString(self, version, data): """ Public method to parse the given persistence data. @param version version of the data (string) @param data persisted data to be parsed (string) @return flag indicating success (boolean) """ parts = data.split(", ") if len(parts) < 2: return False name = "" modules = [] for part in parts: key, value = part.split("=", 1) if key == "no_modules": self.external = Utilities.toBool(value.strip()) elif key == "name": name = value.strip() elif key == "modules": modules = value.strip().split("||") else: return False self.model = PackageModel(name, modules) self.__createTexts() self.__calculateSize() return True
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 View(): def __init__(self): self.window = QtWidgets.QWidget() # создание главного окна self.window.resize(1250, 1000) self.window.setWindowTitle('Кристалл Гука') self.scene = QtWidgets.QGraphicsScene( 250, 0, 1000, 1000, self.window) # создание графической сцены self.view = QtWidgets.QGraphicsView(self.window) self.view.setGeometry(250, 0, 1000, 1000) # задаем видимую часть сцены self.view.setScene(self.scene) self.btn_start = QtWidgets.QPushButton('&Запустить', self.window) # кнопка запуска self.btn_start.clicked.connect(self.start) self.btn_stop = QtWidgets.QPushButton('&Остановить', self.window) # кнопка паузы self.btn_stop.clicked.connect(self.stop) self.btn_graph = QtWidgets.QPushButton( '&Графики', self.window) # кнопка для вывода графиков self.btn_graph.clicked.connect(self.create_dialogwindow) self.btn_help = QtWidgets.QPushButton('&Справка', self.window) # справка self.btn_help.clicked.connect(self.help_dialogwindow) self.font = QtGui.QFont("Times", 11, QtGui.QFont.Bold) self.btn_start.setFont(self.font) self.btn_stop.setFont(self.font) self.btn_graph.setFont(self.font) self.btn_help.setFont(self.font) self.btn_start.setGeometry(50, 25, 150, 40) self.btn_stop.setGeometry(50, 70, 150, 40) self.btn_graph.setGeometry(50, 115, 150, 40) self.btn_help.setGeometry(50, 950, 150, 40) self.btn_start_pressed = False # флаг для проверки состояния кнопки "старт" self.btn_stop.setEnabled(False) # делаем кнопку паузы неактивной self.btn_start.setEnabled(False) # делаем кнопку запуска неактивной self.btn_graph.setEnabled( False) # делаем кнопку запуска графиков неактивной self.vvod_a_b_m_k_l_dt = [ QtWidgets.QSpinBox(self.window) for i in range(2) ] # создание полей ввода исходных данных for i in range(4): self.vvod = QtWidgets.QDoubleSpinBox(self.window) self.vvod_a_b_m_k_l_dt.append(self.vvod) for i in range(len(self.vvod_a_b_m_k_l_dt)): self.vvod_a_b_m_k_l_dt[i].setGeometry(5, 125 + 50 * (i + 1), 240, 30) self.vvod_a_b_m_k_l_dt[i].setRange(0, 1000) self.vvod_a_b_m_k_l_dt[0].setMinimum(3) self.vvod_a_b_m_k_l_dt[1].setMinimum(3) self.vvod.setDecimals(4) self.vvod.setMinimum(0.0001) self.vvod.setMaximum(0.0012) self.vvod_a_b_m_k_l_dt[0].setValue(5) # задаем исходные данные self.vvod_a_b_m_k_l_dt[1].setValue(5) self.vvod_a_b_m_k_l_dt[2].setValue(93) self.vvod_a_b_m_k_l_dt[3].setValue(5) self.vvod_a_b_m_k_l_dt[4].setValue(100) self.vvod_a_b_m_k_l_dt[5].setValue(0.0008) self.vvod_a_b_m_k_l_dt[0].setPrefix('Высота сетки: ') self.vvod_a_b_m_k_l_dt[1].setPrefix('Ширина сетки: ') self.vvod_a_b_m_k_l_dt[2].setPrefix('Масса частиц, *10^-27 кг: ') self.vvod_a_b_m_k_l_dt[3].setPrefix('Жесткость пружин, *10^-20 н/м: ') self.vvod_a_b_m_k_l_dt[4].setPrefix( 'Начальное расстояние, *10^-11 м: ') self.vvod_a_b_m_k_l_dt[5].setPrefix('Промежуток времени, с: ') self.vvod_a_b_m_k_l_dt[0].setSingleStep(1) self.vvod_a_b_m_k_l_dt[1].setSingleStep(1) self.vvod_a_b_m_k_l_dt[2].setSingleStep(1) self.vvod_a_b_m_k_l_dt[3].setSingleStep(0.1) self.vvod_a_b_m_k_l_dt[4].setSingleStep(10) self.vvod_a_b_m_k_l_dt[5].setSingleStep(0.0001) self.a = self.vvod_a_b_m_k_l_dt[0].value() self.b = self.vvod_a_b_m_k_l_dt[1].value() self.m = self.vvod_a_b_m_k_l_dt[2].value() * 10**(-27) self.k = self.vvod_a_b_m_k_l_dt[3].value() * 10**(-20) self.l = self.vvod_a_b_m_k_l_dt[4].value() self.dt = self.vvod_a_b_m_k_l_dt[5].value() self.radio_3_4_6 = [ QtWidgets.QRadioButton(self.window) for i in range(3) ] # создание радиокнопок для смены формы ячеек self.radio_3_4_6[1].setChecked(True) self.radio_check = [False, True, False] self.radio_group = QtWidgets.QGroupBox( 'Выберите форму элементарной ячейки:', self.window) self.radio_group.setGeometry(10, 500, 230, 350) self.vbox = QtWidgets.QVBoxLayout(self.window) self.images = [ QtGui.QPixmap('images\треугольник'), QtGui.QPixmap('images\квадрат.png'), QtGui.QPixmap('images\шестиугольник.png') ] for i in range(len(self.radio_3_4_6)): self.radio_3_4_6[i].toggled.connect(self.radiobutton) self.icon = QtGui.QIcon(self.images[i]) self.radio_3_4_6[i].setIcon(self.icon) self.radio_3_4_6[i].setIconSize(QtCore.QSize(100, 100)) self.vbox.addWidget(self.radio_3_4_6[i]) self.radio_group.setLayout(self.vbox) for i in self.vvod_a_b_m_k_l_dt: i.valueChanged.connect(self.options) self.draw() # выводим изображение на сцену self.window.show() self.help_dialogwindow() def radiobutton(self): # метод, меняющий форму ячеек self.resh.matrix[0][0].ell.pause = True self.scene.clear() for i in range(len(self.radio_3_4_6)): self.radio_check[i] = self.radio_3_4_6[i].isChecked() self.draw() self.btn_stop.setEnabled(False) self.btn_start_pressed = False self.btn_start.setEnabled(False) self.btn_start.setText('&Запустить') self.btn_stop.setText('&Остановить') for i in self.vvod_a_b_m_k_l_dt: i.setEnabled(True) def options( self): # изменение значений переменных при работе с полями ввода if not self.btn_start_pressed: self.a = self.vvod_a_b_m_k_l_dt[0].value() # число строк в сетке self.b = self.vvod_a_b_m_k_l_dt[1].value( ) # чисто столбцов в сетке self.m = self.vvod_a_b_m_k_l_dt[2].value() * 10**(-27 ) # масса частиц self.k = self.vvod_a_b_m_k_l_dt[3].value() * 10**( -20) # коэффициент жесткости пружин self.l = self.vvod_a_b_m_k_l_dt[4].value( ) # длина нерастянутой пружины self.dt = self.vvod_a_b_m_k_l_dt[5].value() # промежуток времени self.btn_start.setEnabled(False) self.scene.clear() self.draw() def start(self): # запуск процессов/сброс if not self.btn_start_pressed: self.btn_start_pressed = True self.btn_stop.setEnabled(True) self.btn_graph.setEnabled(True) self.btn_stop.setText('&Остановить') self.btn_start.setText('&Сброс') for i in self.vvod_a_b_m_k_l_dt: i.setEnabled(False) for i in range(self.a): for j in range(self.b): self.resh.matrix[i][j].ell.pause = False self.resh.matrix[i][j].setEnabled(False) for i in self.resh.lines: self.scene.removeItem(i) self.programm = Processy(self.resh, self.radio_check, self.a, self.b, self) # переход в основной цикл else: self.radiobutton() def move_graphics(self, matrix): # перемещение изображений if self.resh.matrix[0][0].ell.pause == False: for i in self.lines_list: self.scene.removeItem(i) self.lines_list = [] for i in self.resh.lines: self.line = QtWidgets.QGraphicsLineItem( i.line.x1, i.line.y1, i.line.x2, i.line.y2) self.lines_list.append(self.line) self.scene.addItem(self.line) for i in range(self.a): for j in range(self.b): x = matrix[i][j].ell.x - matrix[i][j].ell.x_ y = matrix[i][j].ell.y - matrix[i][j].ell.y_ self.resh.matrix[i][j].moveBy(x, y) self.M_center = QGraphicsEllipseItem( sum(self.resh.list_Mx) / len(self.resh.list_Mx) + 300, sum(self.resh.list_My) / len(self.resh.list_My) + 50, 10, 10) # метки, указывающие на положение центра энергии self.M_center.setBrush( QtGui.QBrush(QtGui.QColor(200, 0, 0), style=QtCore.Qt.SolidPattern)) self.scene.addItem(self.M_center) self.center_list.append(self.M_center) self.M_center_now = QGraphicsEllipseItem( self.resh.list_Mx[-1] + 300, self.resh.list_My[-1] + 50, 10, 10) self.M_center_now.setBrush( QtGui.QBrush(QtGui.QColor(0, 200, 0), style=QtCore.Qt.SolidPattern)) self.scene.addItem(self.M_center_now) self.now_center_list.append(self.M_center_now) if len(self.center_list) > 1: self.scene.removeItem(self.center_list[0]) self.center_list.pop(0) self.scene.removeItem(self.now_center_list[0]) self.now_center_list.pop(0) def stop(self): # остановка/продолжение всех процессов for i in range(self.a): for j in range(self.b): self.resh.matrix[i][ j].ell.pause = not self.resh.matrix[i][j].ell.pause if self.resh.matrix[0][0].ell.pause == True: self.btn_stop.setText('&Продолжить') else: self.btn_stop.setText('&Остановить') self.programm = Processy(self.resh, self.radio_check, self.a, self.b, self) def draw(self): # вывод изображения на сцену self.resh = Reshetka(self.a, self.b, self.dt, self.l, self.k, self.m, self.radio_check, self) # создание новой решетки self.lines_list = [] self.center_list = [] self.now_center_list = [] for i in range(self.a): for j in range(self.b): self.resh.matrix[i][j].setBrush( QtGui.QBrush(self.resh.matrix[i][j].color, style=QtCore.Qt.SolidPattern)) self.scene.addItem(self.resh.matrix[i][j]) for i in self.resh.lines: self.lines_list.append(i) self.scene.addItem(i) for i in range(self.a): # нанесение разметки (координаты) self.text = QGraphicsSimpleTextItem( str(round(self.resh.matrix[i][0].ell.y - 50))) self.text.setPos(270, self.resh.matrix[i][0].ell.y + 20) self.scene.addItem(self.text) for i in range(self.b): self.text = QGraphicsSimpleTextItem( str(round(self.resh.matrix[0][i].ell.x - 300))) self.text.setPos(self.resh.matrix[0][i].ell.x + 15, self.resh.matrix[0][i].ell.y - 30) self.scene.addItem(self.text) def create_dialogwindow(self): # вывод графиков в диалоговом окне self.graph = Energy(self.resh.list_Wp, self.resh.list_Wk, self.resh.list_W, self.resh.list_Mx, self.resh.list_My, self.resh.list_t, self.resh.t) result = self.graph.exec() def help_dialogwindow(self): self.help = QDialog() self.help.resize(700, 450) self.help.setWindowTitle('Справка') self.file = open("help.txt", 'r', encoding='utf-8') self.file_lines_list = self.file.readlines() for i in self.file_lines_list: self.text = QtWidgets.QLabel(i, self.help) self.font = QtGui.QFont("Times", 11, QtGui.QFont.Bold) # изменение шрифта self.text.setFont(self.font) self.text.setGeometry(20, 20 * (1 + self.file_lines_list.index(i)), 660, 18) self.file.close() result = self.help.exec()
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)
def createLabel(self): label = QGraphicsSimpleTextItem("%d" % self._virtual_helix.number()) label.setFont(_FONT) label.setZValue(_ZVALUE) label.setParentItem(self) return label