def drawGrid(self): black_notes = [2,4,6,9,11] scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano) scale_bar.setPos(self.piano_width, 0) scale_bar.setBrush(QColor(100,100,100)) clearpen = QPen(QColor(0,0,0,0)) for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1): for j in range(self.notes_in_octave, 0, -1): scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano) scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1)) scale_bar.setPen(clearpen) if j not in black_notes: scale_bar.setBrush(QColor(120,120,120)) else: scale_bar.setBrush(QColor(100,100,100)) measure_pen = QPen(QColor(0, 0, 0, 120), 3) half_measure_pen = QPen(QColor(0, 0, 0, 40), 2) line_pen = QPen(QColor(0, 0, 0, 40)) for i in range(0, int(self.num_measures) + 1): measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header) measure.setPos(self.measure_width * i, 0.5 * measure_pen.width()) measure.setPen(measure_pen) if i < self.num_measures: number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header) number.setPos(self.measure_width * i + 5, 2) number.setBrush(Qt.white) for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.): line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header) line.setZValue(1.0) line.setPos(self.measure_width * i + self.value_width * j, self.header_height) if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0: line.setPen(half_measure_pen) else: line.setPen(line_pen)
def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size-1][n] yBot += self.baseWidth*0.4/self.baseRectRatio xBot -= self.baseWidth*0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth*1.2 yLeft -= self.baseWidth*0.3/self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords()
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()))
class BasicNode(QGraphicsItemGroup): def __init__(self, model, manager, text_color=Qt.black): bg_color = model.get_bg_color() super(BasicNode, self).__init__() self.model = model text = model.get_display_text() self.manager = manager self.setFlag(QGraphicsItem.ItemIsSelectable, True) self.setFlag(QGraphicsItem.ItemIsFocusable, True) self.text_graph = QGraphicsSimpleTextItem(text) self.text_graph.setBrush(text_color) bound = self.text_graph.boundingRect() r = QPointF(bound.width() / 2, bound.height() / 2) text_center = self.text_graph.pos() + r self.text_graph.setPos(-text_center) self.addToGroup(self.text_graph) self.box_graph = BoxOutline(bg_color) empty_space = QPointF(UNIT, UNIT) newr = (empty_space + r) self.box_graph.rect = QRectF(-newr, newr) self.addToGroup(self.box_graph) self.text_graph.setZValue(1.0) self.box_graph.setZValue(0.0) self.children = [] def itemChange(self, change, value): if change == QGraphicsItem.ItemSelectedChange: self.manager.selection_changed(self, value) return value else: return super(BasicNode, self).itemChange(change, value) def get_width(self): return self.boundingRect().width() def set_left_pos(self, pos): pos += QPoint(self.get_width() / 2.0, 0) self.setPos(pos) def left_pos(self): return self.pos() - QPointF(self.get_width() / 2.0, 0) def center_pos(self): return self.pos() def right_pos(self): return self.pos() + QPointF(self.get_width() / 2.0, 0) """
class WotNode(BaseNode): def __init__(self, nx_node, pos): """ Create node in the graph scene :param tuple nx_node: Node info :param x_y: Position of the node """ super().__init__(nx_node, pos) # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('black') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) text_color = QColor('grey') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('black') self.text_item.setBrush(QBrush(text_color)) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) gradient.setColorAt(0, QColor('white')) gradient.setColorAt(1, QColor('darkgrey')) self.setBrush(QBrush(gradient)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1)
def 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 add_color_scale(self): x_init = self.position[0] + self.margin + self.width y_init = self.position[1] + self.margin square_size = 20 text_title = QGraphicsSimpleTextItem("clearance") text_title.setPos(x_init, y_init - square_size) self.addToGroup(text_title) for i in range(10): x = x_init y = y_init + 9 * square_size - i * square_size rect = QGraphicsRectItem(x, y, square_size, square_size) pen = QPen() pen.setWidth(0.01) value = (float(i)/9 * (self.vertical_clearance_max - self.vertical_clearance_min)) + self.vertical_clearance_min color = self.color_interpolation.get_interpolation_from_value(value) brush = QBrush(color) rect.setPen(pen) rect.setBrush(brush) self.addToGroup(rect) if i == 0: text_start = QGraphicsSimpleTextItem("%.2f m" % float(self.vertical_clearance_min)) text_start.setPos(x + square_size + 5, y) self.addToGroup(text_start) if i == 9: text_end = QGraphicsSimpleTextItem("%.2f m" % float(self.vertical_clearance_max)) text_end.setPos(x + square_size + 5, y) self.addToGroup(text_end) else: value = self.vertical_clearance_min + (self.vertical_clearance_max-self.vertical_clearance_min) * i/9 text = QGraphicsSimpleTextItem("%.2f m" % value) text.setPos(x + square_size + 5, y) self.addToGroup(text)
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 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 create_material_legend(self, *args): self.position = args[0], args[1] square_size = 20 material_list_key = sorted(self.material_dict) x_init = self.position[0] + self.left_margin y_init = self.position[1] + self.top_margin i = 0 for key in material_list_key: scene_y = y_init + i * (square_size + 5) material = self.material_dict[key] surface_colour = material.get_surface_colour() rect = QGraphicsRectItem(x_init, scene_y, square_size, square_size) pen = QPen() pen.setWidthF(0.5) rect.setPen(pen) BaseGraphic.set_rect_fill(self.visualization_mode, rect, surface_colour) self.graphic_items.append(rect) text = QGraphicsSimpleTextItem(key) text.setPos(x_init + square_size + 5, scene_y) self.graphic_items.append(text) i += 1
def create_scale(self): section_num = len(self.section_analyzer.section_list) section_distance = self.section_analyzer.section_distance total_distance = section_num * section_distance div = int(Math.integer_division(total_distance, 1.0)) print(total_distance) for i in range(div+1): x = self.graph_zero[0] + i * self.length_multiplier + self.line_extend y = self.graph_zero[1] scale_text = QGraphicsSimpleTextItem("%.2f" % float(i)) scale_text.setPos(x, y) self.addToGroup(scale_text) start_to_zero = self.graph_zero[1] - self.position[1] step = abs(start_to_zero) // 25 x = self.graph_zero[0] - 15 y = self.graph_zero[1] for i in range(int(step)-1): if i > 0: value = i * 25 / 100 scene_y = y - i * 25 text = QGraphicsSimpleTextItem("-%.2f" % value) text.setPos(x, scene_y) self.addToGroup(text) start_to_zero = self.position[1] + self.height - self.graph_zero[1] step = abs(start_to_zero) // 25 x = self.graph_zero[0] - 15 y = self.graph_zero[1] for i in range(int(step)-1): if i > 0: value = i * 25 / 100 scene_y = y + i * 25 text = QGraphicsSimpleTextItem("%.2f" % value) text.setPos(x, scene_y) self.addToGroup(text)
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 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 _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 add_title(self): if self.label: title = QGraphicsSimpleTextItem(self.label) title.setPos(self.position[0] + self.margin, self.position[1] + self.line_extend) self.addToGroup(title)
class SocketRow(QGraphicsWidget): def __init__(self, qt_node, pin): super(SocketRow, self).__init__() assert qt_node is not None self.setParentItem(qt_node) self._parent_node = weakref.ref(qt_node) self._pin = pin self._spacerConstant = 5.0 self._label = QGraphicsSimpleTextItem(self) self._socket = None self._outputHook = None socket_colour = QColor(*pin.colour) socket_type = pin.shape if pin.io_type == "input": self._socket = QtSocket(self, "input", socket_type) self._socket.setColor(socket_colour) else: self._socket = QtSocket(self, "output", socket_type) self._socket.setColor(socket_colour) self.setLabelColor(self.defaultColor()) self.setLabelText(self._pin.name) self._socket.setVisible(True) def parentNode(self): return self._parent_node() def pin(self): return self._pin def socket(self): return self._socket def defaultColor(self): return self._parent_node().labelColor() def labelColor(self): return self._label.brush().color() def setLabelColor(self, color): self._label.setBrush(color) def labelText(self): return self._label.text() def setLabelText(self, text): self._label.setText(text) def refresh(self): # Update cosmetics colour = QColor(*self._pin.colour) self._socket.setColor(colour) self._socket.setShape(self._pin.shape) self._socket.update() def updateLayout(self): height = self._label.boundingRect().height() hook = self._socket if hook.mode() == "output": hook_y_pos = (height - hook.boundingRect().height()) / 2.0 else: hook_y_pos = (height - hook.boundingRect().height()) / 2.0 hook.setPos(0.0, hook_y_pos) input_width = self._spacerConstant * 2.0 self._label.setPos(input_width + self._spacerConstant, 0) if hook.mode() == "output": hook.setPos(self._label.pos().x() + self._label.boundingRect().width() + self._spacerConstant, hook_y_pos) self.resize(hook.pos().x() + hook.boundingRect().width(), height) else: self.resize(self._label.pos().x() + self._label.boundingRect().width(), height) def onDeleted(self): if self._socket: self._socket.onDeleted()
class ExplorerNode(BaseNode): def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max): """ Create node in the graph scene :param tuple nx_node: Node info :param center_pos: The position of the center node :param nx_pos: Position of the nodes in the graph :param int steps: The steps from the center identity :param int steps_max: The steps max of the graph """ super().__init__(nx_node, nx_pos) self.steps = steps self.steps_max = steps_max self.highlighted = False # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) # animation and moves self.timeline = None self.loading_timer = QTimer() self.loading_timer.timeout.connect(self.next_tick) self.loading_counter = 0 self._refresh_colors() self.setPos(center_pos) self.move_to(nx_pos) def _refresh_colors(self): """ Refresh elements in the node """ # color around ellipse outline_color = QColor('black') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('grey') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) if self.highlighted: text_color = QColor('grey') else: text_color = QColor('black') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('grey') self.text_item.setBrush(QBrush(text_color)) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) color = QColor() color.setHsv(120 - 60 / self.steps_max * self.steps, 180 + 50 / self.steps_max * self.steps, 60 + 170 / self.steps_max * self.steps) if self.highlighted: color = color.darker(200) color = color.lighter(math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100) gradient.setColorAt(0, color) gradient.setColorAt(1, color.darker(150)) self.setBrush(QBrush(gradient)) def move_to(self, nx_pos): """ Move to corresponding position :param nx_pos: :return: """ origin_x = self.x() origin_y = self.y() final_x = nx_pos[self.id][0] final_y = nx_pos[self.id][1] def frame_move(frame): value = self.timeline.valueForTime(self.timeline.currentTime()) x = origin_x + (final_x - origin_x) * value y = origin_y + (final_y - origin_y) * value self.setPos(x, y) self.scene().node_moved.emit(self.id, x, y) def timeline_ends(): self.setPos(final_x, final_y) self.timeline = None # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances. # They are not kept anywhere, even if you invoke QTimeLine.start(). self.timeline = QTimeLine(1000) self.timeline.setFrameRange(0, 100) self.timeline.frameChanged.connect(frame_move) self.timeline.finished.connect(timeline_ends) self.timeline.start() def highlight(self): """ Highlight the edge in the scene """ self.highlighted = True self._refresh_colors() self.update(self.boundingRect()) def neutralize(self): """ Neutralize the edge in the scene """ self.highlighted = False self._refresh_colors() self.update(self.boundingRect()) def start_loading_animation(self): """ Neutralize the edge in the scene """ if not self.loading_timer.isActive(): self.loading_timer.start(10) def stop_loading_animation(self): """ Neutralize the edge in the scene """ self.loading_timer.stop() self.loading_counter = 100 self._refresh_colors() self.update(self.boundingRect()) def next_tick(self): """ Next tick :return: """ self.loading_counter += 1 self.loading_counter %= 100 self._refresh_colors() self.update(self.boundingRect())
class 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()
def refresh(self): if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos: pass LINE_HEIGHT = 18 SPACING = 3 TEXT_WIDTH = self.sldTxtSize.value() CIRCLE_WIDTH = 10 LEVEL_HEIGHT = 12 s = self.scene s.clear() # Get Max Level (max depth) root = self._mdlOutline.rootItem def maxLevel(item, level=0, max=0): if level > max: max = level for c in item.children(): m = maxLevel(c, level + 1) if m > max: max = m return max MAX_LEVEL = maxLevel(root) # Generate left entries # (As of now, plot only) plotsID = self._mdlPlots.getPlotsByImportance() trackedItems = [] fm = QFontMetrics(s.font()) max_name = 0 for importance in plotsID: for ID in importance: name = self._mdlPlots.getPlotNameByID(ID) ref = references.plotReference(ID, searchable=True) trackedItems.append((ID, ref, name)) max_name = max(fm.width(name), max_name) ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING ) TITLE_WIDTH = max_name + 2 * SPACING # Add Folders and Texts outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT) s.addItem(outline) outline.setPos(TITLE_WIDTH + SPACING, 0) refCircles = [] # a list of all references, to be added later on the lines # A Function to add a rect with centered elided text 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 # A function to returns an item's width, by counting its children def itemWidth(item): if item.isFolder(): r = 0 for c in item.children(): r += itemWidth(c) return r or TEXT_WIDTH else: return TEXT_WIDTH def listItems(item, rect, level=0): delta = 0 for child in item.children(): w = itemWidth(child) if child.isFolder(): parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title()) parent.setToolTip(references.tooltip(references.textReference(child.ID()))) listItems(child, parent, level + 1) else: rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title()) rectChild.setToolTip(references.tooltip(references.textReference(child.ID()))) # Find tracked references in that scene (or parent folders) for ID, ref, name in trackedItems: result = [] c = child while c: result += references.findReferencesTo(ref, c, recursive=False) c = c.parent() if result: ref2 = result[0] # Create a RefCircle with the reference c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2) # Store it, with the position of that item, to display it on the line later on refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos()))) delta += w listItems(root, outline) OUTLINE_WIDTH = itemWidth(root) # Add Plots i = 0 itemsRect = s.addRect(0, 0, 0, 0) itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING) for ID, ref, name in trackedItems: color = randomColor() # Rect r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect) r.setPen(QPen(Qt.NoPen)) r.setBrush(QBrush(color)) r.setPos(0, i * LINE_HEIGHT + i * SPACING) i += 1 # Text txt = QGraphicsSimpleTextItem(name, r) txt.setPos(r.boundingRect().center() - txt.boundingRect().center()) # Line line = PlotLine(0, 0, OUTLINE_WIDTH + SPACING, 0) line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y()) s.addItem(line) line.setPen(QPen(color, 5)) line.setToolTip(self.tr("Plot: ") + name) # We add the circles / references to text, on the line for ref2, circle, pos in refCircles: if ref2 == ref: circle.setParentItem(line) circle.setPos(pos.x(), 0) # self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio self.view.setSceneRect(0, 0, 0, 0)
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 QtNode(QGraphicsWidget): def __init__(self, node, view): super(QtNode, self).__init__() self._spacingConstant = 5.0 self._roundness = 3 self._labelColor = QColor(255, 255, 255) self._label = QGraphicsSimpleTextItem(self) self._label.setBrush(self._labelColor) self._label.setText(node.name) self._selectedColor = QColor(255, 255, 255) self._shapePen = QPen(Qt.NoPen) self._shapePen.setColor(self._selectedColor) self._shapePen.setWidthF(1.5) self._brush = QBrush(QColor(*COLOUR_THEMES[node.node_type])) self._dropShadowEffect = QGraphicsDropShadowEffect() self.setGraphicsEffect(self._dropShadowEffect) self._dropShadowEffect.setOffset(0.0, 10.0) self._dropShadowEffect.setBlurRadius(8.0) self._dropShadowEffect.setColor(QColor(0, 0, 0, 50)) self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setAcceptHoverEvents(True) self.setToolTip(node.tooltip) self._name = node.name self._node = node self._view = weakref.ref(view) self._busy = False self._socketRows = OrderedDict() # Build IO pin socket rows for pin_name in node.pin_order: if pin_name in node.inputs: pin = node.inputs[pin_name] else: pin = node.outputs[pin_name] socket_row = SocketRow(self, pin) self._socketRows[pin_name] = socket_row self.updateLayout() def node(self): return self._node def view(self): return self._view() def name(self): return self._name def setName(self, name): self._name = name self._label.setText(name) self.updateLayout() def labelColor(self): return self._labelColor def onDeleted(self): if self.isSelected(): self.setSelected(False) for socket_row in self._socketRows.values(): socket_row.onDeleted() self._socketRows.clear() def hoverEnterEvent(self, event): self.view().guiOnHoverEnter(self) def hoverLeaveEvent(self, event): self.view().guiOnHoverExit(self) def itemChange(self, change, value): if change == QGraphicsItem.ItemPositionHasChanged: for socket_row in self._socketRows.values(): socket_row.socket().updateConnectionPositions() # Move node if not self._busy: self._busy = True self.view().guiOnMoved(self) self._busy = False elif change == QGraphicsItem.ItemSelectedHasChanged: self.onSelected() return QGraphicsItem.itemChange(self, change, value) def contextMenuEvent(self, event): self.view().guiOnNodeRightClick(self, event) def onSelected(self): if self.isSelected(): self._shapePen.setStyle(Qt.SolidLine) self.view().guiOnNodeSelected(self) else: self._shapePen.setStyle(Qt.NoPen) self.view().guiOnNodeDeselected(self) def paint(self, painter, option, widget): shape = QPainterPath() shape.addRoundedRect(self.rect(), self._roundness, self._roundness) painter.setPen(self._shapePen) painter.setBrush(self._brush) painter.drawPath(shape) def setPos(self, *pos): if len(pos) == 1: point = QPointF(pos[0]) else: point = QPointF(*pos) self._lastPos = point QGraphicsWidget.setPos(self, point) def mouseDoubleClickEvent(self, event): pass def mousePressEvent(self, event): if event.button() == Qt.RightButton: pass else: QGraphicsWidget.mousePressEvent(self, event) def mouseReleaseEvent(self, event): self.view().guiOnFinishedMove() QGraphicsWidget.mouseReleaseEvent(self, event) def mouseMoveEvent(self, event): QGraphicsWidget.mouseMoveEvent(self, event) def dragMoveEvent(self, *args, **kwargs): pass def getSocketRow(self, name): return self._socketRows[name] def refreshSocketRows(self): for socket_row in self._socketRows.values(): socket_row.refresh() def updateLayout(self): label_width = self._label.boundingRect().width() width = label_width y_pos = self._label.boundingRect().bottom() + self._spacingConstant for socket_row in self._socketRows.values(): if socket_row.isVisible(): socket_row.updateLayout() socket_row.setPos(self._spacingConstant, y_pos) height = socket_row.boundingRect().height() y_pos += height attributeWidth = socket_row.boundingRect().width() if attributeWidth > width: width = attributeWidth for socket_row in self._socketRows.values(): if socket_row.isVisible(): hook = socket_row.socket() if hook.isOutput(): hook.setPos(width - hook.boundingRect().width(), hook.pos().y()) width = self._spacingConstant + width + self._spacingConstant self._label.setPos((width - label_width) / 2.0, self._spacingConstant) self.resize(width, y_pos + self._spacingConstant) self.update()
class Tile(Pixmap): """ Tile class defines on screen tiles """ anim_complete = pyqtSignal() # Signal for completion of animation sheet = None # Sprite sheet def __init__(self, letter, scene, letfile=r"\scrabble_letters.png"): self.alphabet = scene.alphabet if type(self).sheet is None: type(self).sheet = QPixmap(self.alphabet.lang + letfile) # Extract letter tile from sheet, scale to cell size for board image = type(self).sheet.copy(self.alphabet.TILE_POSITIONS[letter][0], self.alphabet.TILE_POSITIONS[letter][1], Cons.TILE_WIDTH, Cons.TILE_HEIGHT) image = image.scaled(Cons.WIDTH, Cons.HEIGHT, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) super(Tile, self).__init__(image) type(self).sheet = None self.letter = letter self.blank_letter = None self.rack_pos = QPointF() self.pos = QPointF() self.txt = None self.scene = scene self.alphabet = self.scene.alphabet self.pixmap_item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) self.pixmap_item.setTransform(QTransform()) self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton) self.pixmap_item.setZValue(1000) self.pixmap_item.letter = letter self.pixmap_item.tile = self self.pixmap_item.hide() # self.add_to_scene(self.scene) self.scene.addItem(self.pixmap_item) self.pos = QPointF(0, 0) self.animation = None self.fade = None # Draw at position (QPoint) on screen def draw_tile(self, position): """ Extract letter tile from sheet, scale to cell size for board draw at (xpos, ypos) """ self.pos = position self.pixmap_item.show() def get_pos(self): """ Return position of tile """ return self.pixmap_item.pos() def set_pos(self, x, y): """ Move tile to position (x, y) """ self.pixmap_item.setPos(x, y) def hand_cursor(self): """ Change cursor to hand cursor """ self.pixmap_item.setCursor(Qt.PointingHandCursor) def reset_cursor(self): """ Change cursor to pointer cursor """ self.pixmap_item.setCursor(Qt.ArrowCursor) def move_tile(self, dur, *args): """ Create move tile animation *args are time fraction, points in path either as (time, QPointF) or (time, x, y) """ if not self.pixmap_item.isVisible(): self.pixmap_item.setPos( QPointF(Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1])) self.pixmap_item.show() animation = QPropertyAnimation(self, b'pos') animation.setDuration(dur) for val in args: if isinstance(val[1], QPointF): point = val[1] else: point = QPointF(val[1], val[2]) animation.setKeyValueAt(val[0], point) self.animation = animation return self.animation def activate(self, activate): """ Accept mouse presses if activate is True """ if activate: self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton) else: self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton) def dim(self, activate): """ Dim tile if activate is True """ if activate: self.pixmap_item.setOpacity(0.4) else: self.pixmap_item.setOpacity(1) def set_in_board(self): """ Set tile in board No longer moveable """ self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton) def add_letter(self, letter): """ Add small letter to blank tile """ self.txt = QGraphicsSimpleTextItem(letter, self.pixmap_item) self.txt.setFont(QFont("Arial", 14, QFont.DemiBold)) self.txt.setBrush(QBrush(Qt.darkRed)) wd, ht = self.txt.boundingRect().width(), self.txt.boundingRect( ).height() self.txt.setPos((Cons.WIDTH - wd) / 2, (Cons.HEIGHT - ht) / 2) def get_tile(self): """ Move tile from store (bottom centre) to position on rack Used in Group Animation """ return self.move_tile( 1000, (0, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1]), (0.2, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, self.rack_pos.y()), (1, self.rack_pos)) def return_tile(self): """ Return tile to rack Used in Group Animation """ return self.move_tile(400, (0, self.get_pos()), (1, self.rack_pos)) def remove_tile(self): """ Remove tile from board Used in Group Animation """ return self.move_tile( 1000, (0, self.get_pos()), (0.8, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, self.get_pos().y()), (1, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1])) def lift_tile(self): """ Used in exchange tiles Lift chosen tile to set position above rack """ self.animation = self.move_tile( 100, (0, self.rack_pos), (1, self.rack_pos + QPointF(0, Cons.TILE_LIFT))) self.animation.start() def drop_tile(self): """ Used in exchange tiles Drop chosen tile back into rack """ self.animation = self.move_tile(100, (0, self.get_pos()), (1, self.rack_pos)) self.animation.start() def name_tile(self, player): """ Used in names screen Move chosen blank tiles to required position """ point = QPointF( Cons.INPUT_NAMES[player][0] + Cons.INPUT_NAMES[player][2], Cons.INPUT_NAMES[player][1] + 50) self.animation = self.move_tile(100, (0, self.get_pos()), (1, point)) self.animation.start() def return_blank(self): """ Used in names screen Return tile to position on board """ self.animation = self.move_tile(400, (0, self.get_pos()), (1, self.rack_pos)) self.animation.start() def unfade(self): """ Fade in letter on blank tile """ self.fade = QPropertyAnimation(self, b'opacity') self.fade.setDuration(2000) self.fade.setStartValue(0) self.fade.setEndValue(1) self.fade.setEasingCurve(QEasingCurve.InOutSine) self.fade.finished.connect(self._fade_end) self.fade.start() def _fade_end(self): """ end of animation """ self.anim_complete.emit() def hide(self): """ Hide tile """ self.pixmap_item.hide() def setZValue(self, val): """ set ZValue for image """ self.pixmap_item.setZValue(val)
def print_side_view(self): """ draw vessel, usbl and vessel reference point on a side_graphicsView """ # clear previous scene self.side_scene.clear() self.side_graphicsView.viewport().update() # get vessel spinbox values v_length = self.vessel_length_doubleSpinBox.value() v_height = v_length / 3 vrp_x_on_vessel = self.vrp_x_offset_doubleSpinBox.value() if util.find_spec('usblcontroller') is not None: usbl_x_on_vessel = self.usbl_x_offset_doubleSpinBox.value() usbl_z_on_vessel = self.usbl_z_offset_doubleSpinBox.value() else: usbl_x_on_vessel = 0 usbl_z_on_vessel = 0 # get width and height from view w_max = self.side_graphicsView.width() h_max = self.side_graphicsView.height() # set max if v_height > v_length: max_pix = v_height else: max_pix = v_length # set pixel ratio if w_max < h_max: pix_ratio = (w_max - 20) / max_pix else: pix_ratio = (h_max - 20) / max_pix # set the size of the vessel vessel = QPolygonF([ QPointF(0, 0), QPointF(pix_ratio * v_length, 0), QPointF(pix_ratio * v_length * 3 / 4, pix_ratio * v_height), QPointF(0, pix_ratio * v_height) ]) self.item = QGraphicsPolygonItem(vessel) # set brown color self.item.setBrush(QColor(210, 180, 140)) x_origin_scene = (pix_ratio * v_length / 2) y_origin_scene = (pix_ratio * v_height / 2) # coordinate system line_x_coord = QGraphicsLineItem( x_origin_scene, y_origin_scene, pix_ratio * v_length - (pix_ratio * v_length - pix_ratio * v_length * 3 / 4) / 2, y_origin_scene) line_z_coord = QGraphicsLineItem(x_origin_scene, y_origin_scene, x_origin_scene, pix_ratio * v_height) x_label = QGraphicsSimpleTextItem("X", line_x_coord) x_label.setPos( pix_ratio * v_length - (pix_ratio * v_length - pix_ratio * v_length * 3 / 4) / 2 - 30, y_origin_scene) z_label = QGraphicsSimpleTextItem("Z", line_z_coord) z_label.setPos(x_origin_scene - 20, pix_ratio * v_height - 20) # set sea background sea_polygon = QPolygonF([ QPointF(-w_max, y_origin_scene), QPointF(w_max, y_origin_scene), QPointF(x_origin_scene + w_max, h_max + usbl_z_on_vessel * pix_ratio), QPointF(-w_max, h_max + usbl_z_on_vessel * pix_ratio) ]) sea = QGraphicsPolygonItem(sea_polygon) sea.setBrush(QColor(204, 229, 255)) x_origin_scene += vrp_x_on_vessel * pix_ratio # draw origin point origin = QGraphicsEllipseItem(x_origin_scene - 10, y_origin_scene - 10, 20, 20) origin.setBrush(Qt.white) line_one_origin = QGraphicsLineItem(x_origin_scene - 10, y_origin_scene, x_origin_scene + 10, y_origin_scene) line_two_origin = QGraphicsLineItem(x_origin_scene, y_origin_scene - 10, x_origin_scene, y_origin_scene + 10) if util.find_spec('usblcontroller') is not None: # usbl position usbl_circle = QGraphicsEllipseItem( x_origin_scene - 10 + usbl_x_on_vessel * pix_ratio, y_origin_scene - 10 + usbl_z_on_vessel * pix_ratio, 20, 20) usbl_circle.setBrush(QColor(255, 99, 71)) line_one_usbl = QGraphicsLineItem( x_origin_scene - 10 + usbl_x_on_vessel * pix_ratio, y_origin_scene + usbl_z_on_vessel * pix_ratio, x_origin_scene + 10 + usbl_x_on_vessel * pix_ratio, y_origin_scene + usbl_z_on_vessel * pix_ratio) line_two_usbl = QGraphicsLineItem( x_origin_scene + usbl_x_on_vessel * pix_ratio, y_origin_scene - 10 + usbl_z_on_vessel * pix_ratio, x_origin_scene + usbl_x_on_vessel * pix_ratio, y_origin_scene + 10 + usbl_z_on_vessel * pix_ratio) # define labels usbl_label = QGraphicsSimpleTextItem("USBL", usbl_circle) usbl_label.setPos( x_origin_scene - 10 + usbl_x_on_vessel * pix_ratio, y_origin_scene + 10 + usbl_z_on_vessel * pix_ratio) origin_label = QGraphicsSimpleTextItem("VRP", origin) if usbl_x_on_vessel == 0 and usbl_z_on_vessel == 0: origin_label.setPos(x_origin_scene + 10, y_origin_scene - 10) else: origin_label.setPos(x_origin_scene - 10, y_origin_scene + 10) # fit view/scene self.side_scene.setSceneRect( 0, 0, pix_ratio * v_length, pix_ratio * v_height + usbl_z_on_vessel * pix_ratio) self.side_graphicsView.scene().addItem(sea) # add vessel to the scene self.side_graphicsView.scene().addItem(self.item) # add origin to the scene self.side_graphicsView.scene().addItem(origin) self.side_graphicsView.scene().addItem(line_one_origin) self.side_graphicsView.scene().addItem(line_two_origin) if util.find_spec('usblcontroller') is not None: # add usbl self.side_graphicsView.scene().addItem(usbl_circle) self.side_graphicsView.scene().addItem(line_one_usbl) self.side_graphicsView.scene().addItem(line_two_usbl) # add coord system self.side_graphicsView.scene().addItem(line_x_coord) self.side_graphicsView.scene().addItem(line_z_coord) # set background self.side_scene.setBackgroundBrush(Qt.white) # set antialiasing renderhint self.side_graphicsView.setRenderHint(QPainter.Antialiasing)
def print_top_view(self): """ draw draw vessel, gps, usbl and vessel reference point on a top_graphicsView """ # clear previous scene self.top_scene.clear() self.top_graphicsView.viewport().update() # get vessel spinbox values v_width = self.vessel_width_doubleSpinBox.value() v_length = self.vessel_length_doubleSpinBox.value() vrp_x_on_vessel = self.vrp_x_offset_doubleSpinBox.value() vrp_y_on_vessel = self.vrp_y_offset_doubleSpinBox.value() gps_x_on_vessel = self.gps_x_offset_doubleSpinBox.value() gps_y_on_vessel = self.gps_y_offset_doubleSpinBox.value() if util.find_spec('usblcontroller') is not None: usbl_x_on_vessel = self.usbl_x_offset_doubleSpinBox.value() usbl_y_on_vessel = self.usbl_y_offset_doubleSpinBox.value() else: usbl_x_on_vessel = 0 usbl_y_on_vessel = 0 # get width and height from view w_max = self.top_graphicsView.width() h_max = self.top_graphicsView.height() # set max if v_width > v_length: max_pix = v_width else: max_pix = v_length # set pixel ratio if w_max < h_max: pix_ratio = (w_max - 20) / max_pix else: pix_ratio = (h_max - 20) / max_pix # set the size of the vessel vessel = QPolygonF([ QPointF(pix_ratio * v_width / 2, 0), QPointF(pix_ratio * v_width, pix_ratio * v_length / 4), QPointF(pix_ratio * v_width, pix_ratio * v_length), QPointF(0, pix_ratio * v_length), QPointF(0, pix_ratio * v_length / 4) ]) self.item = QGraphicsPolygonItem(vessel) # set brown color self.item.setBrush(QColor(210, 180, 140)) x_origin_scene = (pix_ratio * v_width / 2) y_origin_scene = (pix_ratio * v_length / 2) # coordinate system line_x_coord = QGraphicsLineItem(x_origin_scene, 0, x_origin_scene, y_origin_scene) line_y_coord = QGraphicsLineItem(x_origin_scene, y_origin_scene, pix_ratio * v_width, y_origin_scene) x_label = QGraphicsSimpleTextItem("X", line_x_coord) x_label.setPos(x_origin_scene - 10, 0 + 10) y_label = QGraphicsSimpleTextItem("Y", line_y_coord) y_label.setPos(pix_ratio * v_width - 20, y_origin_scene) x_origin_scene += vrp_y_on_vessel * pix_ratio y_origin_scene += -vrp_x_on_vessel * pix_ratio # draw origin point origin = QGraphicsEllipseItem(x_origin_scene - 10, y_origin_scene - 10, 20, 20) origin.setBrush(Qt.white) line_one_origin = QGraphicsLineItem(x_origin_scene - 10, y_origin_scene, x_origin_scene + 10, y_origin_scene) line_two_origin = QGraphicsLineItem(x_origin_scene, y_origin_scene - 10, x_origin_scene, y_origin_scene + 10) # gps position gps_circle = QGraphicsEllipseItem( x_origin_scene - 10 + gps_y_on_vessel * pix_ratio, y_origin_scene - 10 - gps_x_on_vessel * pix_ratio, 20, 20) gps_circle.setBrush(QColor(143, 188, 143)) line_one_gps = QGraphicsLineItem( x_origin_scene - 10 + gps_y_on_vessel * pix_ratio, y_origin_scene - gps_x_on_vessel * pix_ratio, x_origin_scene + 10 + gps_y_on_vessel * pix_ratio, y_origin_scene - gps_x_on_vessel * pix_ratio) line_two_gps = QGraphicsLineItem( x_origin_scene + gps_y_on_vessel * pix_ratio, y_origin_scene - 10 - gps_x_on_vessel * pix_ratio, x_origin_scene + gps_y_on_vessel * pix_ratio, y_origin_scene + 10 - gps_x_on_vessel * pix_ratio) # gps label gps_label = QGraphicsSimpleTextItem("GPS", gps_circle) gps_label.setPos(x_origin_scene - 10 + gps_y_on_vessel * pix_ratio, y_origin_scene + 10 - gps_x_on_vessel * pix_ratio) if util.find_spec('usblcontroller') is not None: # usbl position usbl_circle = QGraphicsEllipseItem( x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio, y_origin_scene - 10 - usbl_x_on_vessel * pix_ratio, 20, 20) usbl_circle.setBrush(QColor(255, 99, 71)) line_one_usbl = QGraphicsLineItem( x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio, y_origin_scene - usbl_x_on_vessel * pix_ratio, x_origin_scene + 10 + usbl_y_on_vessel * pix_ratio, y_origin_scene - usbl_x_on_vessel * pix_ratio) line_two_usbl = QGraphicsLineItem( x_origin_scene + usbl_y_on_vessel * pix_ratio, y_origin_scene - 10 - usbl_x_on_vessel * pix_ratio, x_origin_scene + usbl_y_on_vessel * pix_ratio, y_origin_scene + 10 - usbl_x_on_vessel * pix_ratio) # usbl label usbl_label = QGraphicsSimpleTextItem("USBL", usbl_circle) if usbl_x_on_vessel == gps_x_on_vessel and usbl_y_on_vessel == gps_y_on_vessel: usbl_label.setPos( x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio, y_origin_scene - 30 - usbl_x_on_vessel * pix_ratio) else: usbl_label.setPos( x_origin_scene - 10 + usbl_y_on_vessel * pix_ratio, y_origin_scene + 10 - usbl_x_on_vessel * pix_ratio) origin_label = QGraphicsSimpleTextItem("VRP", origin) if (usbl_x_on_vessel == 0 and usbl_y_on_vessel == 0) or (gps_x_on_vessel == 0 and gps_y_on_vessel == 0): origin_label.setPos(x_origin_scene + 10, y_origin_scene - 10) else: origin_label.setPos(x_origin_scene - 10, y_origin_scene + 10) # fit view/scene self.top_graphicsView.setSceneRect(0, 0, pix_ratio * v_width, pix_ratio * v_length) # add vessel to the scene self.top_graphicsView.scene().addItem(self.item) # add origin to the scene self.top_graphicsView.scene().addItem(origin) self.top_graphicsView.scene().addItem(line_one_origin) self.top_graphicsView.scene().addItem(line_two_origin) # add gps self.top_graphicsView.scene().addItem(gps_circle) self.top_graphicsView.scene().addItem(line_one_gps) self.top_graphicsView.scene().addItem(line_two_gps) if util.find_spec('usblcontroller') is not None: # add usbl self.top_graphicsView.scene().addItem(usbl_circle) self.top_graphicsView.scene().addItem(line_one_usbl) self.top_graphicsView.scene().addItem(line_two_usbl) # add coord system self.top_graphicsView.scene().addItem(line_x_coord) self.top_graphicsView.scene().addItem(line_y_coord) # set background self.top_scene.setBackgroundBrush(QColor(204, 229, 255)) # set antialiasing renderhint self.top_graphicsView.setRenderHint(QPainter.Antialiasing)
class PreXoverItem(QGraphicsPathItem): def __init__(self, from_virtual_helix_item, to_virtual_helix_item, index, strand_type, is_low_idx): super(PreXoverItem, self).__init__(from_virtual_helix_item) self._from_vh_item = from_virtual_helix_item self._to_vh_item = to_virtual_helix_item self._idx = index self._strand_type = strand_type # translate from Low to Left for the Path View self._is_low_index = is_low_idx self._is_active = False self._pen = _SCAF_PEN if strand_type == StrandType.SCAFFOLD else _STAP_PEN is_on_top = from_virtual_helix_item.isStrandTypeOnTop(strand_type) bw = _BASE_WIDTH x = bw * index y = (-1.25 if is_on_top else 2.25) * bw self.setPos(x, y) num = to_virtual_helix_item.number() tBR = _FM.tightBoundingRect(str(num)) half_label_H = tBR.height()/2.0 half_label_W = tBR.width()/2.0 labelX = bw/2.0 - half_label_W # if num == 1: # adjust for the number one labelX -= half_label_W/2.0 if is_on_top: labelY = -0.25*half_label_H - .5 else: labelY = 2*half_label_H + .5 self._label = QGraphicsSimpleTextItem(self) self._label.setPos(labelX, labelY) # create a bounding rect item to process click events # over a wide area self._clickArea = c_a = QGraphicsRectItem(_RECT, self) c_a.mousePressEvent = self.mousePress yoffset = 0.2*bw if is_on_top else -0.4*bw c_a.setPos(0, yoffset) c_a.setPen(QPen(Qt.NoPen)) self.updateStyle() self._updateLabel() self.setPainterPath() # end def ### DRAWING METHODS ### def remove(self): scene = self.scene() if scene: scene.removeItem(self._label) scene.removeItem(self._clickArea) scene.removeItem(self) self._label = None self._clickArea = None self._from_vh_item = None self._to_vh_item = None # end def def _updateLabel(self): lbl = self._label lbl.setBrush(self._label_brush) lbl.setFont(_TO_HELIX_NUM_FONT) lbl.setText( str(self._to_vh_item.number() ) ) # end def ### TOOL METHODS ### def selectToolMousePress(self, event): """removexover(from_strand, from_idx, to_strand, to_idx)""" pass
def refresh(self): if not self._mdlPlots or not self._mdlOutline or not self._mdlCharacter: return if not self.isVisible(): return LINE_HEIGHT = 18 SPACING = 3 TEXT_WIDTH = self.sldTxtSize.value() CIRCLE_WIDTH = 10 LEVEL_HEIGHT = 12 s = self.scene s.clear() # Get Max Level (max depth) root = self._mdlOutline.rootItem def maxLevel(item, level=0, max=0): if level > max: max = level for c in item.children(): m = maxLevel(c, level + 1) if m > max: max = m return max MAX_LEVEL = maxLevel(root) # Get the list of tracked items (array of references) trackedItems = [] if self.actPlots.isChecked(): trackedItems += self.plotReferences() if self.actCharacters.isChecked(): trackedItems += self.charactersReferences() ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING ) fm = QFontMetrics(s.font()) max_name = 0 for ref in trackedItems: name = references.title(ref) max_name = max(fm.width(name), max_name) TITLE_WIDTH = max_name + 2 * SPACING # Add Folders and Texts outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT) s.addItem(outline) outline.setPos(TITLE_WIDTH + SPACING, 0) refCircles = [] # a list of all references, to be added later on the lines # A Function to add a rect with centered elided text 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 # A function to returns an item's width, by counting its children def itemWidth(item): if item.isFolder(): r = 0 for c in item.children(): r += itemWidth(c) return r or TEXT_WIDTH else: return TEXT_WIDTH def listItems(item, rect, level=0): delta = 0 for child in item.children(): w = itemWidth(child) if child.isFolder(): parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title()) parent.setToolTip(references.tooltip(references.textReference(child.ID()))) listItems(child, parent, level + 1) else: rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title()) rectChild.setToolTip(references.tooltip(references.textReference(child.ID()))) # Find tracked references in that scene (or parent folders) for ref in trackedItems: result = [] # Tests if POV scenePOV = False # Will hold true of character is POV of the current text, not containing folder if references.type(ref) == references.CharacterLetter: ID = references.ID(ref) c = child while c: if c.POV() == ID: result.append(c.ID()) if c == child: scenePOV = True c = c.parent() # Search in notes/references c = child while c: result += references.findReferencesTo(ref, c, recursive=False) c = c.parent() if result: ref2 = result[0] # Create a RefCircle with the reference c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2, important=scenePOV) # Store it, with the position of that item, to display it on the line later on refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos()))) delta += w listItems(root, outline) OUTLINE_WIDTH = itemWidth(root) # Add Tracked items i = 0 itemsRect = s.addRect(0, 0, 0, 0) itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING) # Set of colors for plots (as long as they don't have their own colors) colors = [ "#D97777", "#AE5F8C", "#D9A377", "#FFC2C2", "#FFDEC2", "#D2A0BC", "#7B0F0F", "#7B400F", "#620C3D", "#AA3939", "#AA6C39", "#882D61", "#4C0000", "#4C2200", "#3D0022", ] for ref in trackedItems: if references.type(ref) == references.CharacterLetter: color = self._mdlCharacter.getCharacterByID(references.ID(ref)).color() else: color = QColor(colors[i % len(colors)]) # Rect r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect) r.setPen(QPen(Qt.NoPen)) r.setBrush(QBrush(color)) r.setPos(0, i * LINE_HEIGHT + i * SPACING) r.setToolTip(references.tooltip(ref)) i += 1 # Text name = references.title(ref) txt = QGraphicsSimpleTextItem(name, r) txt.setPos(r.boundingRect().center() - txt.boundingRect().center()) # Line line = PlotLine(0, 0, OUTLINE_WIDTH + SPACING, 0) line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y()) s.addItem(line) line.setPen(QPen(color, 5)) line.setToolTip(references.tooltip(ref)) # We add the circles / references to text, on the line for ref2, circle, pos in refCircles: if ref2 == ref: circle.setParentItem(line) circle.setPos(pos.x(), 0) # self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio self.view.setSceneRect(0, 0, 0, 0)
class Node(QGraphicsEllipseItem): def __init__(self, metadata, x_y): """ Create node in the graph scene :param dict metadata: Node metadata :param x_y: Position of the node """ # unpack tuple x, y = x_y super(Node, self).__init__() self.metadata = metadata self.id = metadata['id'] self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED self.status_member = not self.metadata['status'] & NODE_STATUS_OUT self.text = self.metadata['text'] self.setToolTip(self.metadata['tooltip']) self.arcs = [] self.menu = None self.action_sign = None self.action_transaction = None self.action_contact = None self.action_show_member = None # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('black') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) text_color = QColor('grey') if self.status_wallet == NODE_STATUS_HIGHLIGHTED: text_color = QColor('black') self.text_item.setBrush(QBrush(text_color)) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) self.setPos(x, y) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) gradient.setColorAt(0, QColor('white')) gradient.setColorAt(1, QColor('darkgrey')) self.setBrush(QBrush(gradient)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) def mousePressEvent(self, event: QMouseEvent): """ Click on mouse button :param event: mouse event """ if event.button() == Qt.LeftButton: # trigger scene signal self.scene().node_clicked.emit(self.metadata) def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent): """ Mouse enter on node zone :param event: scene hover event """ self.setCursor(Qt.ArrowCursor) def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent): """ Right click on node to show node menu Except on wallet node :param event: scene context menu event """ # no menu on the wallet node if self.status_wallet: return None # create node context menus self.menu = QMenu() # action show member QT_TRANSLATE_NOOP('WoT.Node', 'Informations') self.action_show_member = QAction(QCoreApplication.translate('WoT.Node', 'Informations'), self.scene()) self.menu.addAction(self.action_show_member) self.action_show_member.triggered.connect(self.member_action) # action add identity as contact QT_TRANSLATE_NOOP('WoT.Node', 'Add as contact') self.action_contact = QAction(QCoreApplication.translate('WoT.Node', 'Add as contact'), self.scene()) self.menu.addAction(self.action_contact) self.action_contact.triggered.connect(self.contact_action) # action transaction toward identity QT_TRANSLATE_NOOP('WoT.Node', 'Send money') self.action_transaction = QAction(QCoreApplication.translate('WoT.Node', 'Send money'), self.scene()) self.menu.addAction(self.action_transaction) self.action_transaction.triggered.connect(self.transaction_action) # action sign identity QT_TRANSLATE_NOOP('WoT.Node', 'Certify identity') self.action_sign = QAction(QCoreApplication.translate('WoT.Node', 'Certify identity'), self.scene()) self.menu.addAction(self.action_sign) self.action_sign.triggered.connect(self.sign_action) # run menu self.menu.exec(event.screenPos()) def add_arc(self, arc): """ Add arc to the arc list :param arc: Arc """ self.arcs.append(arc) def member_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_member.emit(self.metadata) def contact_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_contact.emit(self.metadata) def sign_action(self): """ Sign identity node """ # trigger scene signal self.scene().node_signed.emit(self.metadata) def transaction_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_transaction.emit(self.metadata)
class VCTemporalSeries(VCCommons): def __init__(self): VCCommons.__init__(self) self.__chart=QChart() #After setChart you must call it with chart() self._allowHideSeries=True #Axis cration self.axisX=QDateTimeAxis() self.axisX.setTickCount(8); self.axisX.setFormat("yyyy-MM"); self.maxx=None self.maxy=None self.minx=None self.miny=None self.__ohclduration=eOHCLDuration.Day self.axisY = QValueAxis() self.axisY.setLabelFormat("%i") self.setRenderHint(QPainter.Antialiasing); self.series=[] self.popup=MyPopup(self) def appendCandlestickSeries(self, name): ls=QCandlestickSeries() ls.setName(name) ls.setIncreasingColor(QColor(Qt.green)); ls.setDecreasingColor(QColor(Qt.red)); self.series.append(ls) return ls def appendCandlestickSeriesData(self, ls, dtaware, ope, hig, clo, low): x=dtaware2epochms(dtaware) ls.append(QCandlestickSet(float(ope), float(hig), float(clo), float(low), x )) if self.maxy==None: self.maxy=float(hig) self.miny=float(low) self.maxx=x self.minx=x if hig>self.maxy: self.maxy=float(hig) if low<self.miny: self.miny=float(low) if x>self.maxx: self.maxx=x if x<self.minx: self.minx=x def setOHCLDuration(self, ohclduration): self.__ohclduration=ohclduration def appendScatterSeries(self, name): ls=QScatterSeries() ls.setName(name) self.series.append(ls) return ls def appendScatterSeriesData(self, ls, x, y): self.appendTemporalSeriesData(ls, x, y) def setAxisFormat(self, axis, min, max, type, zone=None): """ type=0 #Value type=1 # Datetime if zone=None remains in UTC, zone is a zone object. """ if type==0: if max-min<=Decimal(0.01): axis.setLabelFormat("%.4f") elif max-min<=Decimal(100): axis.setLabelFormat("%.2f") else: axis.setLabelFormat("%i") elif type==1: max=epochms2dtaware(max)#UTC aware min=epochms2dtaware(min) if max-min<timedelta(days=1): axis.setFormat("hh:mm") else: axis.setFormat("yyyy-MM-dd") def setAllowHideSeries(self, boolean): self._allowHideSeries=boolean def appendTemporalSeries(self, name): ls=QLineSeries() ls.setName(name) self.series.append(ls) return ls def appendTemporalSeriesData(self, ls, x, y): """ x is a datetime zone aware """ x=dtaware2epochms(x) x=float(x) y=float(y) ls.append(x, y) if self.maxy==None:#Gives first maxy and miny self.maxy=y*1.01 self.miny=y*0.99 self.maxx=x*1.01 self.minx=x*0.99 if y>self.maxy: self.maxy=y if y<self.miny: self.miny=y if x>self.maxx: self.maxx=x if x<self.minx: self.minx=x def mouseMoveEvent(self, event): ##Sets the place of the popup in the windows to avoid getout of the screen ##frmshow can be a frmShowCasilla or a frmShowFicha def placePopUp(): resultado=QPoint(event.x()+15, event.y()+15) if event.x()>self.width()-self.popup.width()-15: resultado.setX(event.x()-self.popup.width()-15) if event.y()>self.height()-self.popup.height()-15: resultado.setY(event.y()-self.popup.height()-15) return resultado def showCurrentPosition(): if hasattr(self, "qgstiCurrentX")==False: self.qgstiCurrentX=QGraphicsSimpleTextItem(self.chart()) self.qgstiCurrentY=QGraphicsSimpleTextItem(self.chart()) self.qgstiCurrentX.setPos(event.pos().x(), maxY-10) self.qgstiCurrentY.setPos(self.chart().size().width()-47, event.pos().y()) self.qgstiCurrentX.setText(str(epochms2dtaware(xVal).date())) self.qgstiCurrentY.setText(str(round(yVal,2))) # --------------------------------------- QChartView.mouseMoveEvent(self, event) xVal = self.chart().mapToValue(event.pos()).x() yVal = self.chart().mapToValue(event.pos()).y() maxX = self.axisX.max().toMSecsSinceEpoch() minX = self.axisX.min().toMSecsSinceEpoch() maxY = self.axisY.max() minY = self.axisY.min() if xVal <= maxX and xVal >= minX and yVal <= maxY and yVal >= minY: self.popup.move(self.mapToGlobal(placePopUp())) self.popup.refresh(self, xVal, yVal) showCurrentPosition() self.popup.show() else: self.popup.hide() ## Return the value of the serie in x def series_value(self, serie, x): for point in serie.pointsVector(): if point.x()>=x: return point.y() @pyqtSlot() def on_marker_clicked(self): marker=QObject.sender(self)#Busca el objeto que ha hecho la signal en el slot en el que está conectado, ya que estaban conectados varios objetos a una misma señal marker.series().setVisible(not marker.series().isVisible()) marker.setVisible(True) if marker.series().isVisible(): alpha = 1 else: alpha=0.5 lbrush=marker.labelBrush() color=lbrush.color() color.setAlphaF(alpha) lbrush.setColor(color) marker.setLabelBrush(lbrush) brush=marker.brush() color=brush.color() color.setAlphaF(alpha) brush.setColor(color) marker.setBrush(brush) pen=marker.pen() color=pen.color() color.setAlphaF(alpha) pen.setColor(color) marker.setPen(pen) ## Used to display chart. You cannot use it twice. close the view widget and create another one def display(self): if self.__chart!=None: del self.__chart self.__chart=QChart() self.setChart(self.__chart) if self._animations==True: self.chart().setAnimationOptions(QChart.AllAnimations); else: self.chart().setAnimationOptions(QChart.NoAnimation) self.chart().layout().setContentsMargins(0,0,0,0) self._display_set_title() self.setAxisFormat(self.axisX, self.minx, self.maxx, 1) self.setAxisFormat(self.axisY, self.miny, self.maxy, 0) self.chart().addAxis(self.axisY, Qt.AlignLeft); self.chart().addAxis(self.axisX, Qt.AlignBottom); for s in self.series: self.chart().addSeries(s) s.attachAxis(self.axisX) s.attachAxis(self.axisY) self.axisY.setRange(self.miny, self.maxy) #Legend positions if len(self.chart().legend().markers())>6: self.chart().legend().setAlignment(Qt.AlignLeft) else: self.chart().legend().setAlignment(Qt.AlignTop) if self._allowHideSeries==True: for marker in self.chart().legend().markers(): try: marker.clicked.disconnect() except: pass marker.clicked.connect(self.on_marker_clicked) self.repaint()
class ClearanceWidthGraph(BaseGraphic): def __init__(self, *args): super(ClearanceWidthGraph, self).__init__(*args) self.dimension_analysis = self.section_analyzer.dimension_analysis self.clearance_analysis = self.section_analyzer.clearance_analysis self.min_horizontal_clearance = self.dimension_analysis.min_horizontal_clearance self.graph_zero = [None, None] self.graph_end = [None, None] self.clearance_label = QGraphicsSimpleTextItem() self.addToGroup(self.clearance_label) self.clearance_label.setZValue(1.0) self.init_dimension() def init_dimension(self): super(ClearanceWidthGraph, self).init_dimension() height_start = self.dimension_analysis.bounding_rect[2] height_end = self.dimension_analysis.bounding_rect[3] self.content_height = (height_end - height_start) * self.height_multiplier self.update_graph_size() self.create_axis() self.create_scale() self.add_clearance_graph() def create_axis(self): bounding_end = abs(self.dimension_analysis.bounding_rect[3]) bounding_start = abs(self.dimension_analysis.bounding_rect[2]) pen = QPen() pen.setWidthF(0.5) # horizontal line self.graph_zero[0] = self.position[0] + self.margin - self.line_extend self.graph_zero[1] = self.position[1] + bounding_start * self.height_multiplier + self.margin self.graph_end[0] = self.graph_zero[0] + self.content_width + self.line_extend self.graph_end[1] = self.graph_zero[1] line_item_horizontal = QGraphicsLineItem(self.graph_zero[0], self.graph_zero[1], self.graph_end[0], self.graph_end[1]) line_item_horizontal.setPen(pen) self.addToGroup(line_item_horizontal) center = (self.graph_zero[0] + self.line_extend), self.graph_zero[1] y_top = center[1] - (bounding_start*self.height_multiplier) y_bottom = center[1]+(bounding_end*self.height_multiplier) line_item_vertical = QGraphicsLineItem(center[0], y_top, center[0], y_bottom) line_item_vertical.setPen(pen) self.addToGroup(line_item_vertical) pen_thin = QPen() pen_thin.setWidthF(0.2) start_graph = center[1] - 10 while start_graph > center[1] - bounding_start * self.height_multiplier: line_item_horizontal = QGraphicsLineItem(self.graph_zero[0], start_graph, self.graph_end[0], start_graph) line_item_horizontal.setPen(pen_thin) line_item_horizontal.setZValue(-0.5) self.addToGroup(line_item_horizontal) start_graph -= 10 start_graph = center[1] + 10 while start_graph < center[1] + bounding_end * self.height_multiplier: line_item_horizontal = QGraphicsLineItem(self.graph_zero[0], start_graph, self.graph_end[0], start_graph) line_item_horizontal.setPen(pen_thin) line_item_horizontal.setZValue(-0.5) self.addToGroup(line_item_horizontal) start_graph += 10 def create_scale(self): section_num = len(self.section_analyzer.section_list) section_distance = self.section_analyzer.section_distance total_distance = section_num * section_distance div = int(Math.integer_division(total_distance, 1.0)) print(total_distance) for i in range(div+1): x = self.graph_zero[0] + i * self.length_multiplier + self.line_extend y = self.graph_zero[1] scale_text = QGraphicsSimpleTextItem("%.2f" % float(i)) scale_text.setPos(x, y) self.addToGroup(scale_text) start_to_zero = self.graph_zero[1] - self.position[1] step = abs(start_to_zero) // 25 x = self.graph_zero[0] - 15 y = self.graph_zero[1] for i in range(int(step)-1): if i > 0: value = i * 25 / 100 scene_y = y - i * 25 text = QGraphicsSimpleTextItem("-%.2f" % value) text.setPos(x, scene_y) self.addToGroup(text) start_to_zero = self.position[1] + self.height - self.graph_zero[1] step = abs(start_to_zero) // 25 x = self.graph_zero[0] - 15 y = self.graph_zero[1] for i in range(int(step)-1): if i > 0: value = i * 25 / 100 scene_y = y + i * 25 text = QGraphicsSimpleTextItem("%.2f" % value) text.setPos(x, scene_y) self.addToGroup(text) def add_clearance_graph(self): print("-----------------------------------------") horizontal_clearance = self.clearance_analysis.horizontal_clearance x_init = self.graph_zero[0] + self.line_extend y_init = self.graph_zero[1] for i in range(len(horizontal_clearance)): clearance_points = horizontal_clearance[i] x = x_init + i * self.dimension_analysis.section_distance * self.length_multiplier left = -self.dimension_analysis.domain_length right = self.dimension_analysis.domain_length if clearance_points[0]: left = clearance_points[0] if clearance_points[1]: right = clearance_points[1] clearance = right - left y_top = y_init + left * self.height_multiplier y_bottom = y_init + right * self.height_multiplier pen_red = QPen() red = Color.create_qcolor_from_rgb_tuple(Color.red) pen_red.setColor(red) pen_green = QPen() green = Color.create_qcolor_from_rgb_tuple(Color.green) pen_green.setColor(green) line = QGraphicsLineItem(x, y_top, x, y_bottom) if clearance < self.min_horizontal_clearance: line.setPen(pen_red) else: line.setPen(pen_green) self.addToGroup(line) pass def set_distance_pointer(self, distance): horizontal_clearance = self.clearance_analysis.horizontal_clearance super(ClearanceWidthGraph, self).set_distance_pointer(distance) index = int(distance/self.section_distance) clearance = None if index < len(horizontal_clearance): clearance = horizontal_clearance[index] x = self.distance_pointer.line().x1() y = self.distance_pointer.line().y1() + (self.distance_pointer.line().y2() - self.distance_pointer.line().y1())/8 self.clearance_label.setPos(x, y) if clearance: if clearance[1] and clearance[0]: distance = clearance[1] - clearance[0] self.clearance_label.setText("clearance = %.2f" % distance)
class BaseGraphic(object): def __init__(self, *args): super(BaseGraphic, self).__init__() self.label = args[3] self.parent = args[0] self.section_analyzer = self.parent.section_analyzer self.width = None self.height = None self.margin = None self.position = args[1], args[2] self.content_width = None self.content_height = None self.distance_pointer = None self.distance_label = None self.section_num = len(self.section_analyzer.section_list) self.section_distance = self.section_analyzer.section_distance self.length_multiplier = 100.0 self.height_multiplier = 100.0 self.line_extend = 20 self.margin = 50 self.material_legend = MaterialLegend(self) self._inited = False self.items = [] self.add_title() def add_title(self): if self.label: title = QGraphicsSimpleTextItem(self.label) title.setPos(self.position[0] + self.margin, self.position[1] + self.line_extend) self.addToGroup(title) def addToGroup(self, item): self.items.append(item) def create_distance_pointer(self): self.distance_pointer = QGraphicsLineItem() pen = QPen() pen.setWidthF(1.0) pen.setStyle(Qt.DashDotLine) color = Color.create_qcolor_from_rgb_tuple_f((1,0,0)) pen.setColor(color) self.distance_pointer.setPen(pen) self.distance_pointer.setZValue(1.0) self.addToGroup(self.distance_pointer) self.distance_label = QGraphicsSimpleTextItem() self.distance_label.setZValue(1.0) self.addToGroup(self.distance_label) def init_dimension(self): section_num = len(self.section_analyzer.section_list) section_distance = self.section_analyzer.section_distance self.content_width = section_num * section_distance * self.length_multiplier self.create_distance_pointer() self._inited = True def update_graph_size(self): if self.content_height and self.content_width: self.width = self.content_width + self.margin * 2 self.height = self.content_height + self.margin * 2 # bounding_rect.setWidth(self.width) # bounding_rect.setHeight(self.height) def set_distance_pointer(self, distance): if self._inited: x1 = self.position[0] + self.margin + distance * self.length_multiplier y1 = self.position[1] x2 = x1 y2 = y1 + self.height self.distance_pointer.setLine(x1, y1, x2, y2) self.distance_label.setText("%.2f" % distance) self.distance_label.setPos(x2,y2) pass @staticmethod def set_rect_fill(*args): if args[0] == 0: #surface color mode rect = args[1] color = args[2] qcolor = Color.create_qcolor_from_rgb_tuple_f(color) brush = QBrush(qcolor) rect.setBrush(brush) def create_legend(self): x = self.position[0] + self.width y = self.position[1] self.material_legend.create_material_legend(x, y) for item in self.material_legend.graphic_items: self.addToGroup(item)
class PreXoverItem(QGraphicsPathItem): def __init__(self, from_virtual_helix_item, to_virtual_helix_item, index, strand_type, is_low_idx): super(PreXoverItem, self).__init__(from_virtual_helix_item) self._from_vh_item = from_virtual_helix_item self._to_vh_item = to_virtual_helix_item self._idx = index self._strand_type = strand_type # translate from Low to Left for the Path View self._is_low_index = is_low_idx self._is_active = False self._pen = _SCAF_PEN if strand_type == StrandType.SCAFFOLD else _STAP_PEN is_on_top = from_virtual_helix_item.isStrandTypeOnTop(strand_type) bw = _BASE_WIDTH x = bw * index y = (-1.25 if is_on_top else 2.25) * bw self.setPos(x, y) num = to_virtual_helix_item.number() tBR = _FM.tightBoundingRect(str(num)) half_label_H = tBR.height()/2.0 half_label_W = tBR.width()/2.0 labelX = bw/2.0 - half_label_W # if num == 1: # adjust for the number one labelX -= half_label_W/2.0 if is_on_top: labelY = -0.25*half_label_H - .5 else: labelY = 2*half_label_H + .5 self._label = QGraphicsSimpleTextItem(self) self._label.setPos(labelX, labelY) # create a bounding rect item to process click events # over a wide area self._clickArea = c_a = QGraphicsRectItem(_RECT, self) c_a.mousePressEvent = self.mousePress yoffset = 0.2*bw if is_on_top else -0.4*bw c_a.setPos(0, yoffset) c_a.setPen(QPen(Qt.NoPen)) self.updateStyle() self._updateLabel() self.setPainterPath() # end def ### DRAWING METHODS ### def remove(self): scene = self.scene() if scene: scene.removeItem(self._label) scene.removeItem(self._clickArea) scene.removeItem(self) self._label = None self._clickArea = None self._from_vh_item = None self._to_vh_item = None # end def def setPainterPath(self): """ Sets the PainterPath according to the index (low = Left, high = Right) and strand position (top = Up, bottom = Down). """ path_LUT = (_PPATH_RD, _PPATH_RU, _PPATH_LD, _PPATH_LU) # Lookup table vhi = self._from_vh_item st = self._strand_type path = path_LUT[2*int(self._is_low_index) + int(vhi.isStrandTypeOnTop(st))] self.setPath(path) # end def def updateStyle(self): """ If a PreXover can be installed the pen is a bold color, otherwise the PreXover is drawn with a disabled or muted color """ from_vh = self._from_vh_item.virtualHelix() to_vh = self._to_vh_item.virtualHelix() part = self._from_vh_item.part() pen = _DISAB_PEN self._label_brush = _DISAB_BRUSH if part.possibleXoverAt(from_vh, to_vh, self._strand_type, self._idx): pen = self._pen self._is_active = True self._label_brush = _ENAB_BRUSH self.setPen(pen) # end def def _updateLabel(self): lbl = self._label lbl.setBrush(self._label_brush) lbl.setFont(_TO_HELIX_NUM_FONT) lbl.setText( str(self._to_vh_item.number() ) ) # end def ### TOOL METHODS ### def selectToolMousePress(self, event): """removexover(from_strand, from_idx, to_strand, to_idx)""" pass # end def def mousePress(self, event): if event.button() != Qt.LeftButton: return QGraphicsPathItem.mousePressEvent(self, event) if event.modifiers() & Qt.ShiftModifier: return # ignore shift click, user is probably trying to merge if self._is_active: from_vh = self._from_vh_item.virtualHelix() to_vh = self._to_vh_item.virtualHelix() from_ss = from_vh.getStrandSetByType(self._strand_type) to_ss = to_vh.getStrandSetByType(self._strand_type) from_strand = from_ss.getStrand(self._idx) to_strand = to_ss.getStrand(self._idx) part = self._from_vh_item.part() # determine if we are a 5' or a 3' end if self.path() in [_PPATH_LU, _PPATH_RD]: # 3' end of strand5p clicked strand5p = from_strand strand3p = to_strand else: # 5' strand5p = to_strand strand3p = from_strand # Gotta clear selections when installing a prexover # otherwise parenting in screwed up self._from_vh_item.viewroot().clearStrandSelections() part.createXover(strand5p, self._idx, strand3p, self._idx) else: event.setAccepted(False)
class Node(QGraphicsEllipseItem): def __init__(self, metadata, x_y): """ Create node in the graph scene :param dict metadata: Node metadata :param x_y: Position of the node """ # unpack tuple x, y = x_y super(Node, self).__init__() self.metadata = metadata self.id = metadata['id'] self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED self.status_member = not self.metadata['status'] & NODE_STATUS_OUT self.text = self.metadata['text'] self.setToolTip(self.metadata['tooltip']) self.arcs = [] self.menu = None self.action_sign = None self.action_transaction = None self.action_contact = None self.action_show_member = None # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('black') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) text_color = QColor('grey') if self.status_wallet == NODE_STATUS_HIGHLIGHTED: text_color = QColor('black') self.text_item.setBrush(QBrush(text_color)) # center ellipse around text self.setRect(0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2) # set anchor to the center self.setTransform(QTransform().translate( -self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) self.setPos(x, y) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # create gradient inside the ellipse gradient = QRadialGradient( QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) gradient.setColorAt(0, QColor('white')) gradient.setColorAt(1, QColor('darkgrey')) self.setBrush(QBrush(gradient)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) def mousePressEvent(self, event: QMouseEvent): """ Click on mouse button :param event: mouse event """ if event.button() == Qt.LeftButton: # trigger scene signal self.scene().node_clicked.emit(self.metadata) def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent): """ Mouse enter on node zone :param event: scene hover event """ self.setCursor(Qt.ArrowCursor) def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent): """ Right click on node to show node menu Except on wallet node :param event: scene context menu event """ # no menu on the wallet node if self.status_wallet: return None # create node context menus self.menu = QMenu() # action show member QT_TRANSLATE_NOOP('WoT.Node', 'Informations') self.action_show_member = QAction( QCoreApplication.translate('WoT.Node', 'Informations'), self.scene()) self.menu.addAction(self.action_show_member) self.action_show_member.triggered.connect(self.member_action) # action add identity as contact QT_TRANSLATE_NOOP('WoT.Node', 'Add as contact') self.action_contact = QAction( QCoreApplication.translate('WoT.Node', 'Add as contact'), self.scene()) self.menu.addAction(self.action_contact) self.action_contact.triggered.connect(self.contact_action) # action transaction toward identity QT_TRANSLATE_NOOP('WoT.Node', 'Send money') self.action_transaction = QAction( QCoreApplication.translate('WoT.Node', 'Send money'), self.scene()) self.menu.addAction(self.action_transaction) self.action_transaction.triggered.connect(self.transaction_action) # action sign identity QT_TRANSLATE_NOOP('WoT.Node', 'Certify identity') self.action_sign = QAction( QCoreApplication.translate('WoT.Node', 'Certify identity'), self.scene()) self.menu.addAction(self.action_sign) self.action_sign.triggered.connect(self.sign_action) # run menu self.menu.exec(event.screenPos()) def add_arc(self, arc): """ Add arc to the arc list :param arc: Arc """ self.arcs.append(arc) def member_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_member.emit(self.metadata) def contact_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_contact.emit(self.metadata) def sign_action(self): """ Sign identity node """ # trigger scene signal self.scene().node_signed.emit(self.metadata) def transaction_action(self): """ Transaction action to identity node """ # trigger scene signal self.scene().node_transaction.emit(self.metadata)
class NodeItem(GraphItem): def __init__(self, highlight_level, bounding_box, label, shape, color=None, parent=None, label_pos=None, tooltip=None): super(NodeItem, self).__init__(highlight_level, parent) self._default_color = self._COLOR_BLACK if color is None else color self._brush = QBrush(self._default_color) self._label_pen = QPen() self._label_pen.setColor(self._default_color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._ellipse_pen = QPen(self._label_pen) self._ellipse_pen.setWidth(1) self._incoming_edges = set() self._outgoing_edges = set() self.parse_shape(shape, bounding_box) self.addToGroup(self._graphics_item) self._label = QGraphicsSimpleTextItem(label) self._label.setFont(GraphItem._LABEL_FONT) label_rect = self._label.boundingRect() if label_pos is None: label_rect.moveCenter(bounding_box.center()) else: label_rect.moveCenter(label_pos) self._label.setPos(label_rect.x(), label_rect.y()) self.addToGroup(self._label) if tooltip is not None: self.setToolTip(tooltip) self.set_node_color() self.setAcceptHoverEvents(True) self.hovershape = None def parse_shape(self, shape, bounding_box): if shape in ('box', 'rect', 'rectangle'): self._graphics_item = QGraphicsRectItem(bounding_box) elif shape in ('ellipse', 'oval', 'circle'): self._graphics_item = QGraphicsEllipseItem(bounding_box) elif shape in ('box3d', ): self._graphics_item = QGraphicsBox3dItem(bounding_box) else: print("Invalid shape '%s', defaulting to ellipse" % shape, file=sys.stderr) self._graphics_item = QGraphicsEllipseItem(bounding_box) def set_hovershape(self, newhovershape): self.hovershape = newhovershape def shape(self): if self.hovershape is not None: path = QPainterPath() path.addRect(self.hovershape) return path else: return super(self.__class__, self).shape() def add_incoming_edge(self, edge): self._incoming_edges.add(edge) def add_outgoing_edge(self, edge): self._outgoing_edges.add(edge) def set_node_color(self, color=None): if color is None: color = self._default_color self._brush.setColor(color) self._ellipse_pen.setColor(color) self._label_pen.setColor(color) self._graphics_item.setPen(self._ellipse_pen) self._label.setBrush(self._brush) self._label.setPen(self._label_pen) def hoverEnterEvent(self, event): # hovered node item in red self.set_node_color(self._COLOR_RED) if self._highlight_level > 1: cyclic_edges = self._incoming_edges.intersection( self._outgoing_edges) # incoming edges in blue incoming_nodes = set() for incoming_edge in self._incoming_edges.difference(cyclic_edges): incoming_edge.set_node_color(self._COLOR_BLUE) incoming_edge.set_label_color(self._COLOR_BLUE) if incoming_edge.from_node != self: incoming_nodes.add(incoming_edge.from_node) # outgoing edges in green outgoing_nodes = set() for outgoing_edge in self._outgoing_edges.difference(cyclic_edges): outgoing_edge.set_node_color(self._COLOR_GREEN) outgoing_edge.set_label_color(self._COLOR_GREEN) if outgoing_edge.to_node != self: outgoing_nodes.add(outgoing_edge.to_node) # incoming/outgoing edges in teal for edge in cyclic_edges: edge.set_node_color(self._COLOR_TEAL) if self._highlight_level > 2: cyclic_nodes = incoming_nodes.intersection(outgoing_nodes) # incoming nodes in blue for incoming_node in incoming_nodes.difference(cyclic_nodes): incoming_node.set_node_color(self._COLOR_BLUE) # outgoing nodes in green for outgoing_node in outgoing_nodes.difference(cyclic_nodes): outgoing_node.set_node_color(self._COLOR_GREEN) # incoming/outgoing nodes in teal for node in cyclic_nodes: node.set_node_color(self._COLOR_TEAL) def hoverLeaveEvent(self, event): self.set_node_color() if self._highlight_level > 1: for incoming_edge in self._incoming_edges: incoming_edge.set_node_color() incoming_edge.set_label_color() if self._highlight_level > 2 and incoming_edge.from_node != self: incoming_edge.from_node.set_node_color() for outgoing_edge in self._outgoing_edges: outgoing_edge.set_node_color() outgoing_edge.set_label_color() if self._highlight_level > 2 and outgoing_edge.to_node != self: outgoing_edge.to_node.set_node_color()
class VLineChartView(QChartView): bar_hovered = pyqtSignal(bool, str) def __init__(self, data: pd.DataFrame): super(VLineChartView, self).__init__() self._stocks = data self._category = self._stocks['trade_date'] self._chart = QChart() self._chart.setAnimationOptions(QChart.SeriesAnimations) self._series = QStackedBarSeries() # 成交量以万股为单位 self._vol_multiple = 10000 self.init_chart() self._zero_value = (0, self._chart.axisY().min()) self._max_value = (len(self._chart.axisX().categories()), self._chart.axisY().max()) self._zero_point = self._chart.mapToPosition( QPointF(self._zero_value[0], self._zero_value[1])) self._max_point = self._chart.mapToPosition( QPointF(self._max_value[0], self._max_value[1])) # 计算x轴单个cate的宽度,用来处理横线不能画到边界 self._cate_width = (self._max_point.x() - self._zero_point.x()) / len( self._category) self._series.hovered.connect(self.on_series_hovered) x_index_list = np.percentile(range(len(self._category)), [0, 25, 50, 75, 100]) self._x_axis_list = [ QGraphicsSimpleTextItem(self._category[int(index)], self._chart) for index in x_index_list ] [axis.setText(axis.text()[4:]) for axis in self._x_axis_list[1:]] self._v_b = QGraphicsSimpleTextItem('B', self._chart) self._v_b.setZValue(100) def on_series_hovered(self, status, index): self.bar_hovered.emit(status, self._category[index]) def clear_series_value(self): self._series.clear() self._stocks = None self._chart.axisY().setRange(0, 10) self._chart.axisX().setCategories(list()) def add_series_values(self, data: pd.DataFrame, is_init=False): self._stocks = data bar_red = QBarSet('red') bar_red.setColor(Qt.red) bar_green = QBarSet('green') bar_green.setColor(Qt.green) for _, stock in self._stocks.iterrows(): if stock['open'] < stock['close']: bar_red.append(stock['vol'] / self._vol_multiple) bar_green.append(0) else: bar_red.append(0) bar_green.append(stock['vol'] / self._vol_multiple) self._series.append(bar_red) self._series.append(bar_green) if not is_init: self._stocks = data self._category = self._stocks['trade_date'] axis_x = self._chart.axisX() axis_y = self._chart.axisY() axis_x.setCategories(self._category) max_p = self._stocks[[ 'vol', ]].stack().max() min_p = self._stocks[[ 'vol', ]].stack().min() axis_y.setRange(min_p / self._vol_multiple * 0.9, max_p / self._vol_multiple * 1.1) self._zero_value = (0, self._chart.axisY().min()) self._max_value = (len(self._chart.axisX().categories()), self._chart.axisY().max()) # 计算x轴单个cate的宽度,用来处理横线不能画到边界 self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(self._category) def resizeEvent(self, event): super(VLineChartView, self).resizeEvent(event) self._zero_point = self._chart.mapToPosition( QPointF(self._zero_value[0], self._zero_value[1])) self._max_point = self._chart.mapToPosition( QPointF(self._max_value[0], self._max_value[1])) self._cate_width = (self._max_point.x() - self._zero_point.x()) / len( self._category) # 绘制自定义X轴 self._x_axis_list[0].setPos(self._zero_point.x() - self._cate_width, self._zero_point.y() + 10) self._x_axis_list[1].setPos(self._max_point.x() * 0.25, self._zero_point.y() + 10) self._x_axis_list[2].setPos(self._max_point.x() * 0.5, self._zero_point.y() + 10) self._x_axis_list[3].setPos(self._max_point.x() * 0.75, self._zero_point.y() + 10) self._x_axis_list[4].setPos( self._max_point.x() - self._x_axis_list[-1].boundingRect().width(), self._zero_point.y() + 10) # 20180207 这个日期的柱形图上面画一个字母b vol = self._stocks[self._stocks['trade_date'] == '20180207']['vol'] / self._vol_multiple print('vol:', vol, ' trade_date:', '20180207') pos = self._chart.mapToPosition( QPointF(list(self._category).index('20180207'), vol)) pos = QPointF(pos.x() - self._cate_width / 2, pos.y() - self._v_b.boundingRect().height()) self._v_b.setPos(pos) def max_point(self): return QPointF(self._max_point.x() + self._cate_width / 2, self._max_point.y()) def min_point(self): return QPointF(self._zero_point.x() - self._cate_width / 2, self._zero_point.y()) def init_chart(self): self.add_series_values(self._stocks, True) self._chart.addSeries(self._series) self._chart.createDefaultAxes() self._chart.setLocalizeNumbers(True) axis_x = self._chart.axisX() axis_y = self._chart.axisY() axis_x.setGridLineVisible(False) axis_y.setGridLineVisible(False) axis_y.setLabelFormat("%.2f") axis_x.setCategories(self._category) axis_x.setLabelsVisible(False) max_p = self._stocks[[ 'vol', ]].stack().max() min_p = self._stocks[[ 'vol', ]].stack().min() axis_y.setRange(min_p / self._vol_multiple * 0.9, max_p / self._vol_multiple * 1.1) # chart的图例 legend = self._chart.legend() legend.hide() # 设置图例由Series来决定样式 # legend.setMarkerShape(QLegend.MarkerShapeFromSeries) self.setChart(self._chart) self._chart.layout().setContentsMargins(0, 0, 0, 0) # 设置内边界的bottom为0 # margins = self._chart.margins() # self._chart.setMargins(QMargins(margins.left(), 0, margins.right(), 0)) self._chart.setBackgroundRoundness(0)
class IndicatorIconView(QGraphicsPixmapItem): def __init__(self, parent: ViewBox, icon_path: str, icon_pos: int, color: Optional[List[int]] = None, message: str = ""): """An indicator icon for a pyqtgraph ViewBox The icon loaded from icon_path will be displayed in the low right corner of the ViewBox. :param parent: ViewBox to place indicator in :param icon_path: path to icon :param icon_pos: position index. Counting from 0 in lower right. """ super().__init__() self.parent = parent self.icon_pos = icon_pos self.label = QGraphicsSimpleTextItem(message) self.label.setVisible(False) self.parent.scene().addItem(self.label) self.set_icon(icon_path, color) self.icon_size = [32, 32] self.parent.scene().addItem(self) self.position_icon() self.parent.sigResized.connect(self.position_icon) self.setVisible(False) self.setAcceptHoverEvents(True) self.connected_overlay = None self.actions: List[QAction] = [] def set_icon(self, icon_path: str, color: Optional[List[int]] = None): if color is not None: image_data = skio.imread(icon_path, plugin="imageio") # Set the RGB part to the red channel multiplied by the requested color red_channel = image_data[:, :, 0] / 255 image_data[:, :, 0] = red_channel * color[0] image_data[:, :, 1] = red_channel * color[1] image_data[:, :, 2] = red_channel * color[2] h = image_data.shape[0] w = image_data.shape[1] image_qi = QImage(image_data.data, w, h, 4 * w, QImage.Format_RGBA8888) image_pm = QPixmap.fromImage(image_qi) self.label.setBrush(QColor(*color)) else: image_pm = QPixmap(icon_path) self.setPixmap(image_pm) def position_icon(self): # The size of the imageview we are putting the icon ing scene_size = self.parent.size() # The position of the image within the scene scene_pos = self.parent.scenePos() # Lower right corner in scene pixel coordinates corner_pos_x = scene_size.width() + scene_pos.x() corner_pos_y = scene_size.height() + scene_pos.y() icon_pos_x = corner_pos_x - self.icon_size[0] * (1 + self.icon_pos) - 10 icon_pos_y = corner_pos_y - self.icon_size[1] - 30 self.setOffset(icon_pos_x, icon_pos_y) label_width = self.label.boundingRect().width() self.label.setPos(corner_pos_x - label_width, icon_pos_y - self.icon_size[0]) def hoverEnterEvent(self, event): if self.connected_overlay is not None: self.connected_overlay.setVisible(True) self.label.setVisible(True) def hoverLeaveEvent(self, event): if self.connected_overlay is not None: self.connected_overlay.setVisible(False) self.label.setVisible(False) def add_actions(self, actions: List[Tuple[str, Callable]]): for text, method in actions: action = QAction(text) action.triggered.connect(method) self.actions.append(action) def mouseClickEvent(self, event): event.accept() if self.actions: qm = QMenu() for action in self.actions: qm.addAction(action) qm.exec(event.screenPos().toQPoint())
class Scene(QGraphicsScene): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # initialize 2D grid of cell data self.cells = { (i,j): Cell(val = CellType.empty) for i in range(Config.NUM_CELLS_X) for j in range(Config.NUM_CELLS_Y) } self.animations = dict() self.setItemIndexMethod(QGraphicsScene.NoIndex) self.draw_grid() self.init_start_goal() self.set_diagonal() self.repaint_cells() self.display_text = QGraphicsSimpleTextItem() self.display_text.setPos(5, self.height() - 60) self.display_text.setFont(QFont("Helvetica", 12, QFont.Bold)) def drawForeground(self, *args, **kwargs): if self.display_text in self.items(): self.removeItem(self.display_text) self.addItem(self.display_text) else: self.addItem(self.display_text) def set_text_log(self, s: str) -> None: self.display_text.setText(s) def init_start_goal(self) -> None: """Initialize start and goal positions""" height = (Config.NUM_CELLS_Y // 2) - 1 self.start = Vector2D(1, height) self.goal = Vector2D(Config.NUM_CELLS_X - 1, height) self.set_cell(self.start, Cell(val = CellType.start)) self.set_cell(self.goal, Cell(val = CellType.goal)) def set_diagonal(self) -> None: """Generates array of possible moves based on Config.DIAGONALS""" if Config.DIAGONALS: self.neighbor_steps = np.array([[1, 1], [1, -1], [-1, 1], [-1, -1], [-1, 0], [0, 1], [1, 0], [0, -1]]) else: self.neighbor_steps = np.array([[-1, 0], [0, 1], [1, 0], [0, -1]]) def get_unexplored_neighbors(self, cell: Vector2D) -> list: """Return neighbors to Vector2D inside the scene""" result = [] curr_cell = np.array([cell.x, cell.y]) for step in self.neighbor_steps: neighbor = step + curr_cell neighbor = Vector2D(x = neighbor[0], y = neighbor[1]) if in_bounds(neighbor) and not self.is_barrier(neighbor) and self.cell_type(neighbor) != CellType.searched: result.append(neighbor) return result def cost(self, coord: Vector2D) -> float: """Return weight of traversing cell at 'coord'""" return self.cells[coord].weight def set_cell(self, coord: Vector2D, new_cell: Cell) -> None: """Set value of cell at cells[x][y]""" self.cells[coord] = new_cell def is_barrier(self, coord: Vector2D): """Return whether cell at 'coord' is barrier""" return self.cells[coord].val == CellType.barrier def cell_type(self, coord: Vector2D): """Return type of cell at 'coord'""" return self.cells[coord].val def draw_grid(self) -> None: """Draws NUM_CELLS_X by NUM_CELLS_Y grid""" width = Config.CELL_LENGTH * Config.NUM_CELLS_X height = Config.CELL_LENGTH * Config.NUM_CELLS_Y self.setSceneRect(0, 0, width, height) pen = QPen(QColor(128, 128, 128), 1) # draw cells for x in range(0, Config.NUM_CELLS_X + 1): col = x * Config.CELL_LENGTH self.addLine(col, 0, col, height, pen) for y in range(0, Config.NUM_CELLS_Y + 1): row = y * Config.CELL_LENGTH self.addLine(0, row, width, row, pen) def resize_update(self) -> None: """Resizes grid and keeps 'start' and 'goal' cells inside of view""" self.clear() self.draw_grid() if self.start.x >= Config.NUM_CELLS_X - 1: self.start = Vector2D(Config.NUM_CELLS_X - 2, self.start.y) if self.start.y >= Config.NUM_CELLS_Y - 1: self.start = Vector2D(self.start.x, Config.NUM_CELLS_Y - 2) if self.goal.x >= Config.NUM_CELLS_X - 1: self.goal = Vector2D(Config.NUM_CELLS_X - 2, self.goal.y) if self.goal.y >= Config.NUM_CELLS_Y - 1: self.goal = Vector2D(self.goal.x, Config.NUM_CELLS_Y - 2) self.cells = { (i,j): Cell(val = CellType.empty) for i in range(Config.NUM_CELLS_X) for j in range(Config.NUM_CELLS_Y) } self.set_cell(self.start, Cell(val = CellType.start)) self.set_cell(self.goal, Cell(val = CellType.goal)) self.repaint_cells() def color_cell(self, coord: Vector2D, animate: bool = False) -> None: """Colors cell using the specified color. If 'animate' true, drawing is animated""" row = coord.y * Config.CELL_LENGTH + 1 # +1 so as to not paint over grid lines col = coord.x * Config.CELL_LENGTH + 1 color = self.cells[coord].val pen = QPen(color, 1) brush = QBrush(color) if animate: threading.Thread ( target=self.animate_rect, \ args=(col, row, Config.CELL_LENGTH - 2, Config.CELL_LENGTH - 2, pen, brush), \ daemon=True \ ).start() else: self.addRect(col, row, Config.CELL_LENGTH - 2, Config.CELL_LENGTH - 2, pen, brush) # -2 so as to not paint over grid lines def animate_rect(self, x: int, y: int, w: int, h: int, pen: QPen, brush: QBrush, duration: float = 0.125, n_steps: float = 16) -> list: """Creates RectObject that transposes from dimensions 0 x 0 to 'w' x 'h' in 'n_steps' steps over the course of 'duration' seconds""" rect = RectObject(x, y, w, h, pen, brush) rect.setScale(0.0) self.addItem(rect) time_step = duration / n_steps scale_step = 1.0 / n_steps scale = 0.0 while scale <= 1.0: rect.setScale(scale) sleep(time_step) scale += scale_step self.update() # this fixes random issue where drawing completely hangs def repaint_cells(self) -> None: """Repaints all cells""" self.set_cell(self.start, Cell(val = CellType.start)) self.set_cell(self.goal, Cell(val = CellType.goal)) for x in range(Config.NUM_CELLS_X): for y in range(Config.NUM_CELLS_Y): self.color_cell(Vector2D(x,y)) def clear_path(self) -> None: """Removes searched and explored-type cells from grid""" for x in range(Config.NUM_CELLS_X): for y in range(Config.NUM_CELLS_Y): if self.cells[Vector2D(x,y)].val == CellType.path \ or self.cells[Vector2D(x,y)].val == CellType.searched: self.set_cell(Vector2D(x,y), Cell(val = CellType.empty)) self.color_cell(Vector2D(x,y)) def draw_cell_sequence(self, cell_sequence: list, cell_type: CellType, animate: bool = False, prev_thread: threading.Thread = None): """ Draws a sequence of cells and sets them to a given type. If 'animate', animate cells. If 'prev_thread', wait for 'prev_thread' before beginning to draw cells """ if prev_thread: # supports waiting for a previous animation prev_thread.join() for current_cell in cell_sequence: if self.cell_type(current_cell) not in (CellType.goal, CellType.start): self.set_cell(current_cell, Cell(val = cell_type)) self.color_cell(current_cell, animate) sleep(0.03125)
class ClassItem(UMLItem): """ Class implementing an UML like class item. """ ItemType = "class" def __init__(self, model=None, external=False, x=0, y=0, rounded=False, noAttrs=False, parent=None, scene=None): """ Constructor @param model class model containing the class data (ClassModel) @param external flag indicating a class defined outside our scope (boolean) @param x x-coordinate (integer) @param y y-coordinate (integer) @keyparam rounded flag indicating a rounded corner (boolean) @keyparam noAttrs flag indicating, that no attributes 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.external = external self.noAttrs = noAttrs 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) attrs = self.model.getAttributes() meths = self.model.getMethods() 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.noAttrs and not self.external: if attrs: txt = "\n".join(attrs) else: txt = " " self.attrs = QGraphicsSimpleTextItem(self) self.attrs.setFont(self.font) self.attrs.setText(txt) self.attrs.setPos(x, y) y += self.attrs.boundingRect().height() + self.margin else: self.attrs = None if meths: txt = "\n".join(meths) else: txt = " " self.meths = QGraphicsSimpleTextItem(self) self.meths.setFont(self.font) self.meths.setText(txt) self.meths.setPos(x, y) def __calculateSize(self): """ Private method to calculate the size of the class item. """ if self.model is None: return width = self.header.boundingRect().width() height = self.header.boundingRect().height() if self.attrs: width = max(width, self.attrs.boundingRect().width()) height = height + self.attrs.boundingRect().height() + self.margin if self.meths: width = max(width, self.meths.boundingRect().width()) height = height + self.meths.boundingRect().height() self.setSize(width + 2 * self.margin, height + 2 * self.margin) def setModel(self, model): """ Public method to set the class model. @param model class model containing the class data (ClassModel) """ self.scene().removeItem(self.header) self.header = None if self.attrs: self.scene().removeItem(self.attrs) self.attrs = None if self.meths: self.scene().removeItem(self.meths) 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) if self.attrs: y += self.margin + self.attrs.boundingRect().height() painter.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y) self.adjustAssociations() def isExternal(self): """ Public method returning the external state. @return external state (boolean) """ return self.external 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 = [ "is_external={0}".format(self.external), "no_attributes={0}".format(self.noAttrs), "name={0}".format(self.model.getName()), ] attributes = self.model.getAttributes() if attributes: entries.append("attributes={0}".format("||".join(attributes))) methods = self.model.getMethods() if methods: entries.append("methods={0}".format("||".join(methods))) 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) < 3: return False name = "" attributes = [] methods = [] for part in parts: key, value = part.split("=", 1) if key == "is_external": self.external = Utilities.toBool(value.strip()) elif key == "no_attributes": self.noAttrs = Utilities.toBool(value.strip()) elif key == "name": name = value.strip() elif key == "attributes": attributes = value.strip().split("||") elif key == "methods": methods = value.strip().split("||") else: return False self.model = ClassModel(name, methods, attributes) self.__createTexts() self.__calculateSize() return True
class ActiveSliceItem(QGraphicsRectItem): """ActiveSliceItem for the Path View""" def __init__(self, part_item, active_base_index): super(ActiveSliceItem, self).__init__(part_item) self._part_item = part_item self._getActiveTool = part_item._getActiveTool self._active_slice = 0 self._low_drag_bound = 0 self._high_drag_bound = self.part().maxBaseIdx() self._controller = ActiveSliceItemController(self, part_item.part()) self._label = QGraphicsSimpleTextItem("", parent=self) self._label.setPos(0, -18) self._label.setFont(_FONT) self._label.setBrush(_LABEL_BRUSH) self._label.hide() self.setFlag(QGraphicsItem.ItemIsMovable) self.setAcceptHoverEvents(True) self.setZValue(styles.ZACTIVESLICEHANDLE) self.setRect(QRectF(0, 0, _BASE_WIDTH,\ self._part_item.boundingRect().height())) self.setPos(active_base_index*_BASE_WIDTH, 0) self.setBrush(_BRUSH) self.setPen(_PEN) # reuse select tool methods for other tools self.addSeqToolMousePress = self.selectToolMousePress self.addSeqToolMouseMove = self.selectToolMouseMove self.breakToolMousePress = self.selectToolMousePress self.breakToolMouseMove = self.selectToolMouseMove self.insertionToolMousePress = self.selectToolMousePress self.insertionToolMouseMove = self.selectToolMouseMove self.paintToolMousePress = self.selectToolMousePress self.paintToolMouseMove = self.selectToolMouseMove self.pencilToolMousePress = self.selectToolMousePress self.pencilToolMouseMove = self.selectToolMouseMove self.skipToolMousePress = self.selectToolMousePress self.skipToolMouseMove = self.selectToolMouseMove # end def ### SLOTS ### def strandChangedSlot(self, sender, vh): pass # end def def updateRectSlot(self, part): bw = _BASE_WIDTH new_rect = QRectF(0, 0, bw,\ self._part_item.virtualHelixBoundingRect().height()) if new_rect != self.rect(): self.setRect(new_rect) self._hideIfEmptySelection() self.updateIndexSlot(part, part.activeBaseIndex()) return new_rect # end def def updateIndexSlot(self, part, base_index): """The slot that receives active slice changed notifications from the part and changes the receiver to reflect the part""" label = self._label bw = _BASE_WIDTH bi = util.clamp(int(base_index), 0, self.part().maxBaseIdx()) self.setPos(bi * bw, -styles.PATH_HELIX_PADDING) self._active_slice = bi if label: label.setText("%d" % bi) label.setX((bw - label.boundingRect().width()) / 2) # end def ### ACCESSORS ### def activeBaseIndex(self): return self.part().activeBaseIndex() # end def def part(self): return self._part_item.part() # end def def partItem(self): return self._part_item # end def ### PUBLIC METHODS FOR DRAWING / LAYOUT ### def removed(self): scene = self.scene() scene.removeItem(self._label) scene.removeItem(self) self._part_item = None self._label = None self._controller.disconnectSignals() self.controller = None # end def def resetBounds(self): """Call after resizing virtualhelix canvas.""" self._high_drag_bound = self.part().maxBaseIdx() # end def ### PRIVATE SUPPORT METHODS ### def _hideIfEmptySelection(self): vis = self.part().numberOfVirtualHelices() > 0 self.setVisible(vis) self._label.setVisible(vis) # end def def _setActiveBaseIndex(self, base_index): self.part().setActiveBaseIndex(base_index) # end def ### EVENT HANDLERS ### def hoverEnterEvent(self, event): self.setCursor(Qt.OpenHandCursor) self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex()) QGraphicsItem.hoverEnterEvent(self, event) # end def def hoverLeaveEvent(self, event): self.setCursor(Qt.ArrowCursor) self._part_item.updateStatusBar("") QGraphicsItem.hoverLeaveEvent(self, event) # end def def mousePressEvent(self, event): """ Parses a mousePressEvent, calling the approproate tool method as necessary. Stores _move_idx for future comparison. """ if event.button() != Qt.LeftButton: event.ignore() QGraphicsItem.mousePressEvent(self, event) return self.scene().views()[0].addToPressList(self) self._move_idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH)) tool_method_name = self._getActiveTool().methodPrefix() + "MousePress" if hasattr(self, tool_method_name): # if the tool method exists modifiers = event.modifiers() getattr(self, tool_method_name)(modifiers) # call tool method def mouseMoveEvent(self, event): """ Parses a mouseMoveEvent, calling the approproate tool method as necessary. Updates _move_idx if it changed. """ tool_method_name = self._getActiveTool().methodPrefix() + "MouseMove" if hasattr(self, tool_method_name): # if the tool method exists idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH)) if idx != self._move_idx: # did we actually move? modifiers = event.modifiers() self._move_idx = idx getattr(self, tool_method_name)(modifiers, idx) # call tool method def customMouseRelease(self, event): """ Parses a mouseReleaseEvent, calling the approproate tool method as necessary. Deletes _move_idx if necessary. """ tool_method_name = self._getActiveTool().methodPrefix() + "MouseRelease" if hasattr(self, tool_method_name): # if the tool method exists modifiers = event.modifiers() x = event.pos().x() getattr(self, tool_method_name)(modifiers, x) # call tool method if hasattr(self, '_move_idx'): del self._move_idx ### TOOL METHODS ### def selectToolMousePress(self, modifiers): """ Set the allowed drag bounds for use by selectToolMouseMove. """ if (modifiers & Qt.AltModifier) and (modifiers & Qt.ShiftModifier): self.part().undoStack().beginMacro("Auto-drag Scaffold(s)") for vh in self.part().getVirtualHelices(): # SCAFFOLD # resize 3' first for strand in vh.scaffoldStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx3p) if strand.isDrawn5to3(): strand.resize((idx5p, hi)) else: strand.resize((lo, idx5p)) # resize 5' second for strand in vh.scaffoldStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx5p): lo, hi = strand.getResizeBounds(idx5p) if strand.isDrawn5to3(): strand.resize((lo, idx3p)) else: strand.resize((idx3p, hi)) # STAPLE # resize 3' first for strand in vh.stapleStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx3p) if strand.isDrawn5to3(): strand.resize((idx5p, hi)) else: strand.resize((lo, idx5p)) # resize 5' second for strand in vh.stapleStrandSet(): idx5p = strand.idx5Prime() idx3p = strand.idx3Prime() if not strand.hasXoverAt(idx3p): lo, hi = strand.getResizeBounds(idx5p) if strand.isDrawn5to3(): strand.resize((lo, idx3p)) else: strand.resize((idx3p, hi)) self.part().undoStack().endMacro() # end def def selectToolMouseMove(self, modifiers, idx): """ Given a new index (pre-validated as different from the prev index), calculate the new x coordinate for self, move there, and notify the parent strandItem to redraw its horizontal line. """ idx = util.clamp(idx, self._low_drag_bound, self._high_drag_bound) x = int(idx * _BASE_WIDTH) self.setPos(x, self.y()) self.updateIndexSlot(None, idx) self._setActiveBaseIndex(idx) self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
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()