def __iniGraphicsSystem(self): ##初始化 graphics View系统 rect = QRectF(-200, -100, 400, 200) self.scene = QGraphicsScene(rect) #scene逻辑坐标系定义 self.view.setScene(self.scene) ## 画一个矩形框,大小等于scene item = QGraphicsRectItem(rect) #矩形框正好等于scene的大小 item.setFlag(QGraphicsItem.ItemIsSelectable) #可选, item.setFlag(QGraphicsItem.ItemIsFocusable) #可以有焦点 pen = QPen() pen.setWidth(2) item.setPen(pen) self.scene.addItem(item) ##一个位于scene中心的椭圆,测试局部坐标 #矩形框内创建椭圆,绘图项的局部坐标,左上角(-100,-50),宽200,高100 item2 = QGraphicsEllipseItem(-100, -50, 200, 100) item2.setPos(0, 0) item2.setBrush(QBrush(Qt.blue)) item2.setFlag(QGraphicsItem.ItemIsSelectable) #可选, item2.setFlag(QGraphicsItem.ItemIsFocusable) #可以有焦点 item2.setFlag(QGraphicsItem.ItemIsMovable) #可移动 self.scene.addItem(item2) ##一个圆,中心位于scene的边缘 item3 = QGraphicsEllipseItem(-50, -50, 100, 100) #矩形框内创建椭圆,绘图项的局部坐标 item3.setPos(rect.right(), rect.bottom()) item3.setBrush(QBrush(Qt.red)) item3.setFlag(QGraphicsItem.ItemIsSelectable) #可选, item3.setFlag(QGraphicsItem.ItemIsFocusable) #可以有焦点 item3.setFlag(QGraphicsItem.ItemIsMovable) #可移动 self.scene.addItem(item3) self.scene.clearSelection()
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 display_markers(self): """Mark all the markers, from the dataset. This function should be called only when we load the dataset or when we change the settings. """ for rect in self.idx_markers: self.scene.removeItem(rect) self.idx_markers = [] markers = [] if self.parent.info.markers is not None: if self.parent.value('marker_show'): markers = self.parent.info.markers for mrk in markers: rect = QGraphicsRectItem(mrk['start'], BARS['markers']['pos0'], mrk['end'] - mrk['start'], BARS['markers']['pos1']) self.scene.addItem(rect) color = self.parent.value('marker_color') rect.setPen(QPen(QColor(color))) rect.setBrush(QBrush(QColor(color))) rect.setZValue(-5) self.idx_markers.append(rect)
def __init__(self, tree, width, height): QGraphicsScene.__init__(self) rect = QGraphicsRectItem(0, 0, width + 100, height) rect.setPen(Qt.white) self.addItem(rect) self.tree = tree self.constructTree()
def mark_quality(self, start_time, length, qual_name): """Mark signal quality, only add the new ones. Parameters ---------- start_time : int start time in s of the epoch being scored. length : int duration in s of the epoch being scored. qual_name : str one of the stages defined in global stages. """ y_pos = BARS['quality']['pos0'] height = 10 # the -1 is really important, otherwise we stay on the edge of the rect old_score = self.scene.itemAt(start_time + length / 2, y_pos + height - 1, self.transform()) # check we are not removing the black border if old_score is not None and old_score.pen() == NoPen: lg.debug('Removing old score at {}'.format(start_time)) self.scene.removeItem(old_score) self.idx_annot.remove(old_score) if qual_name == 'Poor': rect = QGraphicsRectItem(start_time, y_pos, length, height) rect.setPen(NoPen) rect.setBrush(Qt.black) self.scene.addItem(rect) self.idx_annot.append(rect)
def __init__(self, part_instance: ObjectInstance, viewroot: GridRootItemT): """Summary Args: part_instance: ``ObjectInstance`` of the ``Part`` viewroot: ``GridRootItem`` parent: Default is ``None`` """ super(GridNucleicAcidPartItem, self).__init__(part_instance, viewroot) self._getActiveTool = viewroot.manager.activeToolGetter m_p = self._model_part self._controller = NucleicAcidPartItemController(self, m_p) self.scale_factor: float = self._RADIUS / m_p.radius() self.active_virtual_helix_item: GridVirtualHelixItem = None self.prexover_manager = PreXoverManager(self) self.hide() # hide while until after attemptResize() to avoid flicker # set this to a token value self._rect: QRectF = QRectF(0., 0., 1000., 1000.) self.boundRectToModel() self.setPen(getNoPen()) self.setRect(self._rect) self.setAcceptHoverEvents(True) # Cache of VHs that were active as of last call to activeGridChanged # If None, all grids will be redrawn and the cache will be filled. # Connect destructor. This is for removing a part from scenes. # initialize the NucleicAcidPartItem with an empty set of old coords self.setZValue(styles.ZPARTITEM) outline = QGraphicsRectItem(self) self.outline: QGraphicsRectItem = outline o_rect = self._configureOutline(outline) outline.setFlag(QGraphicsItem.ItemStacksBehindParent) outline.setZValue(styles.ZDESELECTOR) model_color = m_p.getColor() outline.setPen(getPenObj(model_color, _DEFAULT_WIDTH)) GC_SIZE = 10 self.grab_cornerTL: GrabCornerItem = GrabCornerItem( GC_SIZE, model_color, True, self) self.grab_cornerTL.setTopLeft(o_rect.topLeft()) self.grab_cornerBR: GrabCornerItem = GrabCornerItem( GC_SIZE, model_color, True, self) self.grab_cornerBR.setBottomRight(o_rect.bottomRight()) self.griditem: GridItem = GridItem(self, self._model_props['grid_type']) self.griditem.setZValue(1) self.grab_cornerTL.setZValue(2) self.grab_cornerBR.setZValue(2) # select upon creation for part in m_p.document().children(): if part is m_p: part.setSelected(True) else: part.setSelected(False) self.show()
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 create_fromDB(self,pos_list=[],obj_type=""): if obj_type =="rois": num_rois = len(pos_list) for i in range(num_rois): points = pos_list[i] rect=QGraphicsRectItem() rect.setPen(QPen(Qt.green)) rect.setRect(points[0],points[1],points[2],points[3]) self.rectgroup.addToGroup(rect) self.scene.addItem(self.rectgroup) elif obj_type =="vector1": num_vec = len(pos_list) for i in range(num_vec): points = pos_list[i] vec=QGraphicsLineItem() vec.setPen(QPen(Qt.green)) vec.setLine(points[0],points[1],points[2],points[3]) self.linegroup.addToGroup(vec) self.scene.addItem(self.linegroup) elif obj_type =="vector2": num_vec = len(pos_list) for i in range(num_vec): points = pos_list[i] vec=QGraphicsLineItem() vec.setPen(QPen(Qt.green)) vec.setLine(points[0],points[1],points[2],points[3]) self.linegroup2.addToGroup(vec) self.scene.addItem(self.linegroup2)
def mark_stages(self, start_time, length, stage_name): """Mark stages, only add the new ones. Parameters ---------- start_time : int start time in s of the epoch being scored. length : int duration in s of the epoch being scored. stage_name : str one of the stages defined in global stages. """ y_pos = BARS['stage']['pos0'] # the -1 is really important, otherwise we stay on the edge of the rect old_score = self.scene.itemAt( start_time + length / 2, y_pos + STAGES[stage_name]['pos0'] + STAGES[stage_name]['pos1'] - 1, self.transform()) # check we are not removing the black border if old_score is not None and old_score.pen() == NoPen: lg.debug('Removing old score at {}'.format(start_time)) self.scene.removeItem(old_score) self.idx_annot.remove(old_score) rect = QGraphicsRectItem(start_time, y_pos + STAGES[stage_name]['pos0'], length, STAGES[stage_name]['pos1']) rect.setPen(NoPen) rect.setBrush(STAGES[stage_name]['color']) self.scene.addItem(rect) self.idx_annot.append(rect)
def mark_stages(self, start_time, length, stage_name): """Mark stages, only add the new ones. Parameters ---------- start_time : int start time in s of the epoch being scored. length : int duration in s of the epoch being scored. stage_name : str one of the stages defined in global stages. """ y_pos = BARS['stage']['pos0'] # the -1 is really important, otherwise we stay on the edge of the rect old_score = self.scene.itemAt(start_time + length / 2, y_pos + STAGES[stage_name]['pos0'] + STAGES[stage_name]['pos1'] - 1, self.transform()) # check we are not removing the black border if old_score is not None and old_score.pen() == NoPen: lg.debug('Removing old score at {}'.format(start_time)) self.scene.removeItem(old_score) self.idx_annot.remove(old_score) rect = QGraphicsRectItem(start_time, y_pos + STAGES[stage_name]['pos0'], length, STAGES[stage_name]['pos1']) rect.setPen(NoPen) rect.setBrush(STAGES[stage_name]['color']) self.scene.addItem(rect) self.idx_annot.append(rect)
class Window(QMainWindow, QGraphicsView): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('Proof of concept') self.setWindowIcon(QIcon('web.png')) # self.setGeometry(3000, 3000, 250, 150) # vbox = QVBoxLayout() # self.setLayout(vbox) self.initView() self.button = QPushButton('Test', self) self.button.move(50, 50) self.button.clicked.connect(self.myButtonClicked) self.statusBar() self.showMaximized() def myButtonClicked(self, event): sender = self.sender() self.statusBar().showMessage(sender.text() + ' was pressed') def initView(self): QGraphicsView.__init__(self) self.scene = QGraphicsScene() blueBrush =QBrush(QColor('blue')) outlinePen=QPen(QColor('black')) self.myRect = QGraphicsRectItem(100, 30, 80, 100) self.myRect.setBrush(blueBrush) self.myRect.setPen(outlinePen) self.scene.addItem(self.myRect) self.scene.setSceneRect(0, 0, 3000, 3000) self.view = QGraphicsView(self.scene,self) self.view.resize(3000,3000) def keyPressEvent(self, e): # override ! if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_W: self.statusBar().showMessage("UP pressed") self.myRect.setY(self.myRect.y()+1) self.show() elif e.key() == Qt.Key_D: self.statusBar().showMessage("RIGHT pressed") self.myRect.setX(self.myRect.x()+1) self.show() elif e.key() == Qt.Key_S: self.statusBar().showMessage("DOWN pressed") self.myRect.setY(self.myRect.y()-1) self.show() elif e.key() == Qt.Key_A: self.statusBar().showMessage("LEFT pressed") self.myRect.setX(self.myRect.x()-1) # self.myRect.setPos(self.myRect.x(),self.myRect.y()-) self.show()
def drawRect(self): rect = QRectF(self.originPos, self.currentPos) rect_item = QGraphicsRectItem(rect) rect_item.setPen(self.pen) rect_item.setFlag(QGraphicsItem.ItemIsMovable, True) if len(self.items()) > 0: self.clearLastItem() self.addItem(rect_item)
def set_boxes(self, boxes): for box in boxes: box_item = QGraphicsRectItem() box_item.setPen(QPen(Qt.red, 4)) box_item.setBrush(QBrush(Qt.NoBrush)) box_item.setZValue(1) self.scene.addItem(box_item) box_item.hide() box_item.setRect(QRectF(box[0], box[1], box[2]-box[0], box[3]-box[1])) self.box_item_list.append(box_item)
class ImageCropper(QGraphicsView): cropped = pyqtSignal(QPointF, QPointF) def __init__( self, parent=None, ): super().__init__(QGraphicsScene(), parent) self.setAlignment(Qt.AlignCenter) self._click_pos = None self._release_pos = None def set_image(self, image): qtimage = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888).rgbSwapped() self.scene().clear() self._rect = QGraphicsRectItem() self._rect.setPen(QPen(Qt.red, 2, Qt.SolidLine)) self._image = self.scene().addPixmap(QPixmap.fromImage(qtimage)) self.scene().addItem(self._rect) def mousePressEvent(self, event): scene_position = self.mapToScene(event.pos()) image_position = self._image.mapFromScene(scene_position) if self._image.contains(image_position): self._click_pos = image_position self._release_pos = None else: self._click_pos = None self._release_pos = None def mouseReleaseEvent(self, event): scene_position = self.mapToScene(event.pos()) image_position = self._image.mapFromScene(scene_position) if self._image.contains(image_position): self._release_pos = image_position if self._click_pos is not None: self.cropped.emit(self._click_pos, self._release_pos) else: self._click_pos = None else: self._click_pos = None self._release_pos = None def mouseMoveEvent(self, event): scene_position = self.mapToScene(event.pos()) image_position = self._image.mapFromScene(scene_position) if (self._click_pos is not None) and (self._image.contains(image_position)): self._rect.setRect(QRectF(self._click_pos, scene_position)) else: self._rect.setRect(QRectF())
def printAttributes(self, background, border, text): """ Prints the attributes of the node The attributes are a key, value pair :param background: background color of the node :param border: border color for the node :param text: text color for the node """ y = self.y() + self.headerHeight x = self.x() self.attributesHeight = 0 for k, v in self.node.attributes.items(): key = QGraphicsTextItem() key.setFont(Configuration.font) key.setDefaultTextColor(QColor(text)) key.setTextWidth(100) key.setPlainText(k) keyHeight = int(key.boundingRect().height() / 20 + 0.5) * 20 value = QGraphicsTextItem() value.setFont(Configuration.font) value.setDefaultTextColor(QColor(text)) value.setTextWidth(100) value.setPlainText(v) valueHeight = int(value.boundingRect().height() / 20 + 0.5) * 20 height = valueHeight if valueHeight > keyHeight else keyHeight keyRect = QGraphicsRectItem() keyRect.setRect(x, y, 100, height) valueRect = QGraphicsRectItem() valueRect.setRect(x + 100, y, 100, height) keyRect.setBrush(QBrush(QColor(background))) valueRect.setBrush(QBrush(QColor(background))) keyRect.setPen(QPen(QColor(border), 2)) valueRect.setPen(QPen(QColor(border), 2)) key.setPos(x, y - 2) value.setPos(x + 100, y - 2) self.attributes.addToGroup(keyRect) self.attributes.addToGroup(valueRect) self.attributes.addToGroup(key) self.attributes.addToGroup(value) y = y + height self.attributesHeight += height self.addToGroup(self.attributes)
def display_annotations(self): """Mark all the bookmarks/events, from annotations. This function is similar to display_markers, but they are called at different stages (f.e. when loading annotations file), so we keep them separate """ for rect in self.idx_annot: self.scene.removeItem(rect) self.idx_annot = [] if self.parent.notes.annot is None: return bookmarks = [] events = [] if self.parent.value('annot_show'): bookmarks = self.parent.notes.annot.get_bookmarks() events = self.parent.notes.get_selected_events() annotations = bookmarks + events for annot in annotations: rect = QGraphicsRectItem(annot['start'], BARS['annot']['pos0'], annot['end'] - annot['start'], BARS['annot']['pos1']) self.scene.addItem(rect) if annot in bookmarks: color = self.parent.value('annot_bookmark_color') if annot in events: color = convert_name_to_color(annot['name']) rect.setPen(QPen(QColor(color), LINE_WIDTH)) rect.setBrush(QBrush(QColor(color))) rect.setZValue(-5) self.idx_annot.append(rect) for epoch in self.parent.notes.annot.epochs: self.mark_stages(epoch['start'], epoch['end'] - epoch['start'], epoch['stage']) self.mark_quality(epoch['start'], epoch['end'] - epoch['start'], epoch['quality']) cycles = self.parent.notes.annot.rater.find('cycles') cyc_starts = [float(mrkr.text) for mrkr in cycles.findall('cyc_start')] cyc_ends = [float(mrkr.text) for mrkr in cycles.findall('cyc_end')] for mrkr in cyc_starts: self.mark_cycles(mrkr, 30) # TODO: better width solution for mrkr in cyc_ends: self.mark_cycles(mrkr, 30, end=True)
def findChild(self): """ When called when self isa QGraphicsItem, iterates through self's childItems(), placing a red rectangle (a sibling of self) around each item in sequence (press return to move between items). Since the index of each child item is displayed as it is highlighted, one can use findChild() to quickly get a reference to one of self's children. At each step, one can type a command letter before hitting return. The command will apply to the current child. Command Letter: Action: <return> Advance to next child s<return> Show current child S<return> Show current child, hide siblings h<return> Hide current child r<return> return current child """ from PyQt5.QtWidgets import QGraphicsRectItem from PyQt5.QtGui import QPen from PyQt5.QtCore import Qt children = self.childItems() parent = self.parentItem() childVisibility = [(child, child.isVisible()) for child in children] for n in range(len(children)): child = children[n] print("Highlighting %s.childItems()[%i] = %s" % (self, n, child)) childBR = child.mapToItem(parent, child.boundingRect()) childBR = childBR.boundingRect() # xform gives us a QPolygonF debugHighlighter = QGraphicsRectItem(childBR, parent) debugHighlighter.setPen(QPen(Qt.red)) debugHighlighter.setZValue(9001) while True: # wait for return to be pressed while spinning the event loop. # also process single-character commands. command = raw_input() if command == 's': # Show current child child.show() elif command == 'h': # Hde current child child.hide() elif command == 'S': # Show only current child for c in children: c.hide() child.show() elif command == 'r': # Return current child for child, wasVisible in childVisibility: child.setVisible(wasVisible) return child else: break debugHighlighter.scene().removeItem(debugHighlighter) for child, wasVisible in childVisibility: child.setVisible(wasVisible)
def findChild(self): """ When called when self isa QGraphicsItem, iterates through self's childItems(), placing a red rectangle (a sibling of self) around each item in sequence (press return to move between items). Since the index of each child item is displayed as it is highlighted, one can use findChild() to quickly get a reference to one of self's children. At each step, one can type a command letter before hitting return. The command will apply to the current child. Command Letter: Action: <return> Advance to next child s<return> Show current child S<return> Show current child, hide siblings h<return> Hide current child r<return> return current child """ from PyQt5.QtWidgets import QGraphicsRectItem from PyQt5.QtGui import QPen from PyQt5.QtCore import Qt children = self.childItems() parent = self.parentItem() childVisibility = [(child, child.isVisible()) for child in children] for n in range(len(children)): child = children[n] print("Highlighting %s.childItems()[%i] = %s"%(self, n, child)) childBR = child.mapToItem(parent, child.boundingRect()) childBR = childBR.boundingRect() # xform gives us a QPolygonF debugHighlighter = QGraphicsRectItem(childBR, parent) debugHighlighter.setPen(QPen(Qt.red)) debugHighlighter.setZValue(9001) while True: # wait for return to be pressed while spinning the event loop. # also process single-character commands. command = raw_input() if command == 's': # Show current child child.show() elif command == 'h': # Hde current child child.hide() elif command == 'S': # Show only current child for c in children: c.hide() child.show() elif command == 'r': # Return current child for child, wasVisible in childVisibility: child.setVisible(wasVisible) return child else: break debugHighlighter.scene().removeItem(debugHighlighter) for child, wasVisible in childVisibility: child.setVisible(wasVisible)
def show_bounding_rect(item, local=False): """Highlight the boundingRect of item.""" if local: rect = item.boundingRect() else: rect = item.sceneBoundingRect() br = QGraphicsRectItem(rect) pen = QPen(Qt.lightGray, 1.5, Qt.DashLine) pen.setCosmetic(True) # thickness does not scale br.setPen(pen) item.scene().addItem(br) return br
def create_scene_tile(self, x: int, y: int, tile) -> QGraphicsItem: x, y = self.pos_to_scene(x, y) width = 2 * qt_drawings.tile_size if tile.is_horizontal else qt_drawings.tile_size height = qt_drawings.tile_size if tile.is_horizontal else 2 * qt_drawings.tile_size item = QGraphicsRectItem(0, 0, width, height) item.setPos(x, y) item.setBrush(qt_drawings.tile_to_brush(tile)) item.setPen(qt_drawings.black_pen) self.scene.addItem(item) return item
def updateGraphicsRectItem(rect: QGraphicsRectItem, rectF: QRectF = None, pen: QPen = None, brush: QBrush = None): """ 更新QGraphicsRectItem属性 :param rect: QGraphicsRectItem :param rectF: 矩形rect :param pen: 边框画笔 :param brush: 填充画刷 """ if rectF: rect.setRect(rectF) if pen: rect.setPen(pen) if brush: rect.setBrush(brush)
def render_monitors(self, monitors): pen = QPen() pen.setWidth(10) brush = QBrush() scene = QGraphicsScene() for mon in monitors: this_rect = QGraphicsRectItem(mon.x(), mon.y(), mon.width(), mon.height()) this_rect.setPen(pen) this_rect.setBrush(brush) this_rect.setZValue(1) scene.addItem(this_rect) self.monitor_display.setScene(scene) self.monitor_display.fitInView(scene.sceneRect(), Qt.KeepAspectRatio)
def __init__(self, size, scene: QGraphicsScene): self.rectItems = [] self.pixmap = QPixmap(QSize(820,820)) self.painter = QPainter(self.pixmap) self.scene = scene self.owners = None self.values = None pen = QPen() pen.setStyle(Qt.NoPen) for index in range(size**2): item = QGraphicsRectItem() item.setRect(int(index/size), int(index%size), 0.9, 0.9) item.setPen(pen) scene.addItem(item) self.rectItems.append(item)
def __init__(self, size, scene: QGraphicsScene): self.rectItems = [] self.pixmap = QPixmap(QSize(820, 820)) self.painter = QPainter(self.pixmap) self.scene = scene self.owners = None self.values = None pen = QPen() pen.setStyle(Qt.NoPen) for index in range(size**2): item = QGraphicsRectItem() item.setRect(int(index / size), int(index % size), 0.9, 0.9) item.setPen(pen) scene.addItem(item) self.rectItems.append(item)
def display_current(self): """Create a rectangle showing the current window.""" if self.idx_current in self.scene.items(): self.scene.removeItem(self.idx_current) item = QGraphicsRectItem(0, CURR['pos0'], self.parent.value('window_length'), CURR['pos1']) # it's necessary to create rect first, and then move it item.setPos(self.parent.value('window_start'), 0) item.setPen(QPen(Qt.lightGray)) item.setBrush(QBrush(Qt.lightGray)) item.setZValue(-10) self.scene.addItem(item) self.idx_current = item
def on_mouseDoubleClick(self, point): # 鼠标双击事件,调用相应的对话框,设置填充颜色、线条颜色或字体 # QMessageBox.warning(self, "debug","on_mouseDoubleClick!") pointScene = self.view.mapToScene(point) # 转换到Scene坐标 # QGraphicsItem *item=NULL item = self.scene.itemAt(pointScene, self.view.transform()) # 获取光标下的绘图项 item_type = item.type() # QMessageBox.warning(self, "debug",str(item_type)+'<==>'+str(QGraphicsLineItem.Type)) if item == None or item_type == None: # 没有绘图项 QMessageBox.warning(self, "debug", "No item found!") return # switch (item_type): #绘图项的类型 if item_type == 3: # QGraphicsRectItem.Type: #矩形框 # 强制类型转换 theItem = QGraphicsRectItem(item) self.setBrushColor(theItem) return elif item_type == 4: # QGraphicsEllipseItem.Type: #椭圆和圆都是 QGraphicsEllipseItem theItem = QGraphicsEllipseItem(item) self.setBrushColor(theItem) return elif item_type == 5: # QGraphicsPolygonItem.Type: #梯形和三角形 theItem = QGraphicsPolygonItem(item) self.setBrushColor(theItem) return elif item_type == 6: # QGraphicsLineItem.Type: #直线,设置线条颜色 theItem = QGraphicsLineItem(item) pen = theItem.pen() color = theItem.pen().color() color = QColorDialog.getColor(color, self, "选择线条颜色") if color.isValid(): pen.setColor(color) theItem.setPen(pen) return elif item_type == 8: # QGraphicsTextItem.Type: #文字,设置字体 theItem = QGraphicsTextItem(item) font = theItem.font() ok = False font, ok = QFontDialog.getFont(self) if ok: theItem.setFont(font) return
def plot(self): #時間がキーで、その時間にアナウンスされたエッジ全て(重み集計なし) f = open("../data/pickles/%s" % announceFile, "rb") self.announce = pickle.load(f) f = open("../data/pickles/%s" % withdrawFile, "rb") self.withdraw = pickle.load(f) timeRangeFrom = "0802241824" timeRangeTo = "0802241923" startDate = timeRangeFrom[:len(timeRangeFrom) - 4] startMin = int(timeRangeFrom[len(timeRangeFrom) - 2:]) #下2桁 startHour = int(timeRangeFrom[len(timeRangeFrom) - 4:len(timeRangeFrom) - 2]) #下4桁〜下2桁 # withdrawならそのまま for i in range(timeRange): min = i + startMin #時間繰り上げなしの分カウント if min > 59: currentMin = min % 60 if currentMin < 10: strMin = "0" + str(currentMin) #"00 ~ 09" else: strMin = str(currentMin) #"10 ~ 59" else: strMin = str(min) hour = min // 60 currentHour = startHour + hour strHour = str(currentHour) time = startDate + strHour + strMin print(time) value = math.log(len(self.announce[time]), 1.1) announcebar = QGraphicsRectItem(i * barWidth, 200, barWidth, -value) announcebar.setPen(announcebarPen) announcebar.setBrush(announcebarBrush) announcebar.setFlags(QGraphicsItem.ItemIsSelectable) self.plotScene.addItem(announcebar) withdrawbar = QGraphicsRectItem(i * barWidth, 200, barWidth, value) withdrawbar.setPen(withdrawbarPen) withdrawbar.setBrush(withdrawbarBrush) withdrawbar.setFlags(QGraphicsItem.ItemIsSelectable) self.plotScene.addItem(withdrawbar) vertivalCenter = self.height / 2 horizontalCenter = self.width / 2
def create_map_points(self): self.map_points_text_items = [] self.map_points_items = [] for map_point in self.map_data.map_points: color = QColor().fromRgb(map_point.r, map_point.g, map_point.b) rect = QGraphicsRectItem( QRectF( QPointF(map_point.x, map_point.y), QSizeF(5 / self.scale_ratio, 5 / self.scale_ratio) ) ) rect.setPen(QPen(Qt.black, 1 / self.scale_ratio)) rect.setBrush(color) self.map_points_items.append(rect) text = QGraphicsTextItem(map_point.text) text.setDefaultTextColor(color) text.setPos(map_point.x, map_point.y) text.setFont(QFont('Times New Roman', 8 / self.scale_ratio, 2)) self.map_points_text_items.append(text)
def label_maker(node, label): """Form correctly formatted leaf label.""" face = QGraphicsTextItem() face.setHtml(label) # Create parent RectItem with TextItem in center fbox = face.boundingRect() rect = QGraphicsRectItem(0, 0, fbox.width(), fbox.height()) rbox = rect.boundingRect() face.setPos(rbox.x(), rbox.center().y() - fbox.height() / 2) # Remove border rect.setPen(QPen(QtCore.Qt.NoPen)) # Set as parent item so DynamicItemFace can use .rect() method face.setParentItem(rect) return rect
def display_annotations(self): """Mark all the bookmarks/events, from annotations. This function is similar to display_markers, but they are called at different stages (f.e. when loading annotations file), so we keep them separate """ for rect in self.idx_annot: self.scene.removeItem(rect) self.idx_annot = [] if self.parent.notes.annot is None: return bookmarks = [] events = [] if self.parent.value('annot_show'): bookmarks = self.parent.notes.annot.get_bookmarks() events = self.parent.notes.get_selected_events() annotations = bookmarks + events for annot in annotations: rect = QGraphicsRectItem(annot['start'], BARS['annot']['pos0'], annot['end'] - annot['start'], BARS['annot']['pos1']) self.scene.addItem(rect) if annot in bookmarks: color = self.parent.value('annot_bookmark_color') if annot in events: color = convert_name_to_color(annot['name']) rect.setPen(QPen(QColor(color), LINE_WIDTH)) rect.setBrush(QBrush(QColor(color))) rect.setZValue(-5) self.idx_annot.append(rect) for epoch in self.parent.notes.annot.epochs: self.mark_stages(epoch['start'], epoch['end'] - epoch['start'], epoch['stage'])
class CustomDragWidget(QGraphicsWidget): def __init__(self,): super().__init__() self.squareItem = QGraphicsRectItem() self.squareItem.setBrush(QBrush(QColor(Qt.blue))) self.squareItem.setPen(QPen(QColor(Qt.black), 2)) self.squareItem.setRect(0, 0, 50, 50) self.squareItem.setParentItem(self) self.setAcceptDrops(True) def mousePressEvent(self, event): mime = QMimeData() itemData = QByteArray() mime.setData('application/x-dnditemdata', itemData) drag = QDrag(self) drag.setMimeData(mime) drag.exec_(Qt.MoveAction) def dropEvent(self, event): event.accept()
def render_drop_shadow_frame(pixmap, shadow_rect, shadow_color, offset, radius, rect_fill_color): pixmap.fill(QColor(0, 0, 0, 0)) scene = QGraphicsScene() rect = QGraphicsRectItem(shadow_rect) rect.setBrush(QColor(rect_fill_color)) rect.setPen(QPen(Qt.NoPen)) scene.addItem(rect) effect = QGraphicsDropShadowEffect(color=shadow_color, blurRadius=radius, offset=offset) rect.setGraphicsEffect(effect) scene.setSceneRect(QRectF(QPointF(0, 0), QSizeF(pixmap.size()))) painter = QPainter(pixmap) scene.render(painter) painter.end() scene.clear() scene.deleteLater() return pixmap
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 display_hotel(self): if self.hotel: width, height = self.color_rect.boundingRect().getRect()[2:] houses = self.color_rect.childItems() for house in houses: house.setParentItem(None) rect_color = QColor() rect_color.setNamedColor("#FF0000") pen_color = QColor() pen_color.setNamedColor("#00A500") pen = QPen() pen.setBrush(QBrush(pen_color)) pen.setWidth(2) hotel = QGraphicsRectItem(width / 4, height / 4, width / 2, height / 2) hotel.setParentItem(self.color_rect) hotel.setBrush(QBrush(rect_color, style=Qt.Dense1Pattern)) hotel.setPen(pen)
def approve_obj(self): self.scene.removeItem(self.rect) self.scene.removeItem(self.line) viewBBox = self.zoomStack[-1] if len( self.zoomStack) else self.sceneRect() selectionBBox = self.scene.selectionArea().boundingRect().intersected( viewBBox) rect = QGraphicsRectItem() rect.setRect(selectionBBox) rect.setPen(QPen(Qt.green)) self.rectgroup.addToGroup(rect) self.scene.addItem(self.rectgroup) line = QGraphicsLineItem() line.setLine(QLineF(self.start, self.current)) line.setPen(QPen(Qt.green)) self.linegroup.addToGroup(line) self.scene.addItem(self.linegroup) return (selectionBBox, self.start, self.current)
def display_markers(self): """Add markers on top of first plot.""" for item in self.idx_markers: self.scene.removeItem(item) self.idx_markers = [] window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length y_distance = self.parent.value('y_distance') markers = [] if self.parent.info.markers is not None: if self.parent.value('marker_show'): markers = self.parent.info.markers for mrk in markers: if window_start <= mrk['end'] and window_end >= mrk['start']: mrk_start = max((mrk['start'], window_start)) mrk_end = min((mrk['end'], window_end)) color = QColor(self.parent.value('marker_color')) item = QGraphicsRectItem(mrk_start, 0, mrk_end - mrk_start, len(self.idx_label) * y_distance) item.setPen(color) item.setBrush(color) item.setZValue(-9) self.scene.addItem(item) item = TextItem_with_BG(color.darker(200)) item.setText(mrk['name']) item.setPos(mrk['start'], len(self.idx_label) * self.parent.value('y_distance')) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) item.setRotation(-90) self.scene.addItem(item) self.idx_markers.append(item)
def draw_sep_area(self, centers: np.ndarray, show_symbols=False): x = self.sceneRect().x() y = self.sceneRect().y() w = self.sceneRect().width() h = self.sceneRect().height() reversed_centers = list(reversed(centers)) num_areas = len(centers) + 1 if num_areas != len(self.separation_areas): for area in self.separation_areas: self.removeItem(area) self.separation_areas.clear() for i in range(num_areas): area = QGraphicsRectItem(0, 0, 0, 0) if i % 2 == 0: area.setBrush(settings.ZEROS_AREA_COLOR) else: area.setBrush(settings.ONES_AREA_COLOR) area.setOpacity(settings.SEPARATION_OPACITY) area.setPen(QPen(settings.TRANSPARENT_COLOR, 0)) self.addItem(area) self.separation_areas.append(area) start = y for i, area in enumerate(self.separation_areas): area.show() try: self.separation_areas[i].setRect( x, start, w, abs(start - reversed_centers[i])) start += abs(start - reversed_centers[i]) except IndexError: self.separation_areas[i].setRect(x, start, w, abs(start - h)) if self.noise_area is not None: self.noise_area.hide() self.centers = centers self.redraw_legend(show_symbols)
def add_game_grid(self): ''' Adds an QGraphicsItem for each square in the game. Qt uses QGraphicsItems to draw objects in the QGraphicsScene. QGraphicsRectItem is a subclass of QGraphicsItem, and is useful for easily drawing rectangular items. This method should only be called once, otherwise it creates duplicates! ''' x = 0 y = 0 for i in range(self.game.get_width()): for j in range(self.game.get_height()): new_square = QGraphicsRectItem(x, y, self.square_size, self.square_size) self.scene.addItem(new_square) if self.game.get_square(Location( x, y, self.game)).is_element_square(): # ground new_square.setBrush(QtGui.QColor(21, 73, 8)) new_square.setPen(QtGui.QColor(21, 73, 8)) elif self.game.get_square(Location( x, y, self.game)).is_armament_square(): # weapon box new_square.setBrush(QtGui.QColor(244, 206, 66)) new_square.setPen(QtGui.QColor(244, 206, 66)) else: new_square.setBrush(QtGui.QColor(181, 210, 251)) # sky new_square.setPen(QtGui.QColor(181, 210, 251)) y += self.square_size x += self.square_size y = 0
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 add_height_clearance_graph(self): vertical_clearance = self.clearance_analysis.vertical_clearance x_init = self.graph_zero[0] + self.line_extend y_init = self.graph_zero[1] y_unit_distance = self.clearance_analysis.sampling_distance * self.height_multiplier x_unit_distance = self.clearance_analysis.section_distance * self.length_multiplier for i in range(len(vertical_clearance)): for j in range(len(vertical_clearance[i])): vertical_distance = vertical_clearance[i][j] if vertical_distance: vertical_distance_value = vertical_distance[0] scene_x = (vertical_distance[1].point.Y() * self.length_multiplier + x_init) - x_unit_distance/2 scene_y = (vertical_distance[1].point.X() * self.height_multiplier + y_init) - y_unit_distance/2 rect = QGraphicsRectItem(scene_x, scene_y, x_unit_distance, y_unit_distance) color = self.color_interpolation.get_interpolation_from_value(vertical_distance_value) pen = QPen() pen.setStyle(Qt.NoPen) brush = QBrush(color) rect.setPen(pen) rect.setBrush(brush) rect.setZValue(-1.0) self.addToGroup(rect) pass
class Desklet(object): def __init__(self): self.rect = QRectF() self.style = Style() self.root = QGraphicsItemGroup() if False: self.debug_rect = QGraphicsRectItem(self.root) self.debug_rect.setPen(QPen(QColor(255, 0, 0))) else: self.debug_rect = None def set_style(self, style): self.style = style def set_rect(self, rect): self.rect = rect if self.debug_rect: self.debug_rect.setRect(rect) def layout(self): 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)
def __init__(self, part_instance: ObjectInstance, viewroot: GridRootItemT): """Summary Args: part_instance: ``ObjectInstance`` of the ``Part`` viewroot: ``GridRootItem`` parent: Default is ``None`` """ super(GridNucleicAcidPartItem, self).__init__( part_instance, viewroot) self._getActiveTool = viewroot.manager.activeToolGetter m_p = self._model_part self._controller = NucleicAcidPartItemController(self, m_p) self.scale_factor: float = self._RADIUS / m_p.radius() self.active_virtual_helix_item: GridVirtualHelixItem = None self.prexover_manager = PreXoverManager(self) self.hide() # hide while until after attemptResize() to avoid flicker # set this to a token value self._rect: QRectF = QRectF(0., 0., 1000., 1000.) self.boundRectToModel() self.setPen(getNoPen()) self.setRect(self._rect) self.setAcceptHoverEvents(True) # Cache of VHs that were active as of last call to activeGridChanged # If None, all grids will be redrawn and the cache will be filled. # Connect destructor. This is for removing a part from scenes. # initialize the NucleicAcidPartItem with an empty set of old coords self.setZValue(styles.ZPARTITEM) outline = QGraphicsRectItem(self) self.outline: QGraphicsRectItem = outline o_rect = self._configureOutline(outline) outline.setFlag(QGraphicsItem.ItemStacksBehindParent) outline.setZValue(styles.ZDESELECTOR) model_color = m_p.getColor() outline.setPen(getPenObj(model_color, _DEFAULT_WIDTH)) GC_SIZE = 10 self.grab_cornerTL: GrabCornerItem = GrabCornerItem(GC_SIZE, model_color, True, self) self.grab_cornerTL.setTopLeft(o_rect.topLeft()) self.grab_cornerBR: GrabCornerItem = GrabCornerItem(GC_SIZE, model_color, True, self) self.grab_cornerBR.setBottomRight(o_rect.bottomRight()) self.griditem: GridItem = GridItem(self, self._model_props['grid_type']) self.griditem.setZValue(1) self.grab_cornerTL.setZValue(2) self.grab_cornerBR.setZValue(2) # select upon creation for part in m_p.document().children(): if part is m_p: part.setSelected(True) else: part.setSelected(False) self.show()
class BankNodeItem (NodeItem): maincolor = FlPalette.bank altcolor = FlPalette.bankvar label = "%s Bank" def __init__ (self, nodeobj, parent=None, view=None, state=1): super().__init__(nodeobj, parent, view, state) self.rect = QRectF() self.setZValue(-1) self.updatecomment() self.updatebanktype() self.updatebankmode() def nudgechildren(self): super().nudgechildren() for sub in self.sublist(): sub.setrank(self) def sublist (self): ID = self.nodeobj.ID itemtable = self.view.itemtable if self.state == 1 and ID in itemtable and not self.iscollapsed(): children = [] for child in self.nodeobj.subnodes: if child in itemtable[ID]: item = itemtable[ID][child] else: continue if item.state > -1: children.append(item) return children else: return [] def treeposition (self, ranks=None): self.updatelayout(external=True) return super().treeposition(ranks) def graphicsetup (self): super().graphicsetup() darkbrush = QBrush(FlPalette.bg) nopen = QPen(0) viewport = self.view.viewport() self.btypeicon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.btypeicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.btypeicon.x() self.fggroup.addToGroup(self.btypeicon) self.centerbox = QGraphicsRectItem(self) self.centerbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.centerbox.setRect(QRectF()) self.centerbox.setBrush(darkbrush) self.centerbox.setPen(nopen) self.centerbox.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin*2) self.fggroup.addToGroup(self.centerbox) def updatebanktype (self): types = {"talk": "(T)", "response": "(R)", "": ""} self.nodelabel.setText("%s Bank %s" % (self.realid(), types[self.nodeobj.banktype])) def updatebankmode (self): icons = {"First": "bank-first", "All": "bank-all", "Append": "bank-append", "": "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.bankmode]) self.btypeicon.setPixmap(pixmap) if self.nodeobj.bankmode: self.btypeicon.setToolTip("Bank mode: %s" % self.nodeobj.bankmode) else: self.btypeicon.setToolTip("") def updatecenterbox (self): verticalpos = self.centerbox.y() maxwidth = self.style.nodetextwidth subnodes = self.sublist() for subnode in subnodes: if subnode.nodeobj.typename == "bank": subnode.updatelayout(external=True) noderect = subnode.boundingRect() nodeheight = noderect.height() nodewidth = noderect.width() subnode.show() subnode.yoffset = self.mapToScene(0,verticalpos + nodeheight/2+self.style.activemargin).y()-self.y_bottom() verticalpos += nodeheight+self.style.activemargin*2 maxwidth = max(maxwidth, nodewidth) centerrect = self.centerbox.rect() centerrect.setWidth(maxwidth+self.style.selectmargin*2) centerrect.setHeight(verticalpos-self.centerbox.y()) self.centerbox.setRect(centerrect) centerrect = self.centerbox.mapRectToParent(centerrect) self.comment.setY(centerrect.bottom()+self.style.itemmargin) def updatelayout (self, external=False): subnodes = self.sublist() if self.iscollapsed(): rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect()) else: self.updatecenterbox() rect = self.fggroup.childrenBoundingRect() mainrect = rect.marginsAdded(self.style.banknodemargins) self.mainbox.setRect(mainrect) self.shadowbox.setRect(mainrect) self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins)) activerect = mainrect.marginsAdded(self.style.activemargins) self.activebox.setRect(activerect) oldypos = self.centerbox.mapToScene(self.centerbox.pos()).y() self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y()) newypos = self.centerbox.mapToScene(self.centerbox.pos()).y() for subnode in subnodes: subnode.yoffset += newypos - oldypos subnode.setY(self.y()) self.prepareGeometryChange() self.rect = self.graphgroup.mapRectToParent(mainrect) if not external: self.view.updatelayout() def setY (self, y): super().setY(y) for subnode in self.sublist(): subnode.setY(y) def contextMenuEvent (self, event): menu = QMenu() if self.isselected(): window = FlGlob.mainwindow menu.addAction(window.actions["collapse"]) if self.isghost(): menu.addAction(window.actions["selectreal"]) menu.addAction(window.actions["copynode"]) menu.addMenu(window.subnodemenu) menu.addMenu(window.addmenu) menu.addAction(window.actions["moveup"]) menu.addAction(window.actions["movedown"]) menu.addAction(window.actions["parentswap"]) menu.addAction(window.actions["unlinknode"]) menu.addAction(window.actions["unlinkstree"]) menu.addAction(window.actions["settemplate"]) menu.addMenu(window.transformmenu) if not menu.isEmpty(): menu.exec_(event.screenPos())
class CalendarDesklet(Desklet): def __init__(self): super().__init__() self.model = CalendarModel() self.cursor_pos = None self.cursor = QGraphicsRectItem(self.root) self.header = QGraphicsSimpleTextItem(self.root) self.weekdays = [] days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] for day in days: self.weekdays.append(QGraphicsSimpleTextItem(day, self.root)) self.header_line = QGraphicsLineItem(self.root) self.days = [] for _ in range(0, 6 * 7): self.days.append(QGraphicsSimpleTextItem(self.root)) def next_month(self): self.model.next_month() self.layout() def previous_month(self): self.model.previous_month() self.layout() def set_rect(self, rect): super().set_rect(rect) self.layout() def set_style(self, style): super().set_style(style) font = QFont(style.font) font.setPixelSize(48) self.header.setBrush(style.midcolor) self.header.setFont(font) font = QFont(style.font) font.setPixelSize(32) self.header_line.setPen(style.foreground_color) self.cursor.setBrush(style.midcolor) self.cursor.setPen(QPen(Qt.NoPen)) for widget in self.weekdays: widget.setFont(font) widget.setBrush(style.foreground_color) for widget in self.days: widget.setFont(font) widget.setBrush(self.style.foreground_color) self.layout() def layout(self): cell_width = (self.rect.width()) / 7.0 cell_height = (self.rect.height() - 64) / 7.0 x = self.rect.left() y = self.rect.top() fm = QFontMetrics(self.header.font()) rect = fm.boundingRect(self.header.text()) self.header.setPos(x + self.rect.width() / 2 - rect.width() / 2, y) y += fm.height() for row, day in enumerate(self.weekdays): fm = QFontMetrics(day.font()) rect = fm.boundingRect(day.text()) day.setPos(x + row * cell_width + cell_width / 2 - rect.width() / 2, y) y += fm.height() self.header_line.setLine(x, y, x + self.rect.width() - 3, y) y += 8 for n, widget in enumerate(self.days): col = n % 7 row = n // 7 rect = fm.boundingRect(widget.text()) widget.setPos(x + col * cell_width + cell_width / 2 - rect.width() / 2, y + row * cell_height + cell_height / 2 - fm.height() / 2) # if day.month != self.now.month: # widget.setBrush(self.style.midcolor) # else: if self.cursor_pos is not None: self.cursor.setRect(x + self.cursor_pos[0] * cell_width, y + self.cursor_pos[1] * cell_height, cell_width, cell_height) self.cursor.show() else: self.cursor.hide() def update(self, now): self.model.update(now) # update header self.header.setText( date(self.model.year, self.model.month, 1).strftime("%B %Y")) # calculate the date of the top/left calendar entry current_date = date(self.model.year, self.model.month, 1) current_date = current_date - timedelta(current_date.weekday()) self.cursor_pos = None for n, widget in enumerate(self.days): col = n % 7 row = n // 7 if current_date == self.model.today: self.cursor_pos = (col, row) widget.setText("%d" % current_date.day) self.days[n] = widget current_date += timedelta(days=1) self.layout()
class PreXoverLabel(QGraphicsSimpleTextItem): """ Attributes: is_fwd (bool): Description """ _XO_FONT = styles.XOVER_LABEL_FONT _XO_BOLD = styles.XOVER_LABEL_FONT_BOLD _FM = QFontMetrics(_XO_FONT) def __init__(self, is_fwd: bool, pre_xover_item: 'PreXoverItem'): """ Args: is_fwd: Description pre_xover_item: Description """ super(QGraphicsSimpleTextItem, self).__init__(pre_xover_item) self.is_fwd = is_fwd self._tbr = None self._outline = QGraphicsRectItem(self) self.setFont(self._XO_FONT) self.setBrush(getBrushObj('#666666')) # end def def resetItem(self, is_fwd: bool, color: str): """ Args: is_fwd: Description color: Description """ self.resetTransform() self.is_fwd = is_fwd self.color = color # end def def setTextAndStyle(self, text: str, outline: bool = False): """ Args: text: Description outline: Default is ``False`` """ str_txt = str(text) self._tbr = tBR = self._FM.tightBoundingRect(str_txt) half_label_H = tBR.height() / 2.0 half_label_W = tBR.width() / 2.0 labelX = BASE_WIDTH/2.0 - half_label_W if str_txt == '1': # adjust for the number one labelX -= tBR.width() labelY = half_label_H if self.is_fwd else (BASE_WIDTH - tBR.height())/2 self.setPos(labelX, labelY) self.setText(str_txt) if outline: self.setFont(self._XO_BOLD) self.setBrush(getBrushObj('#ff0000')) else: self.setFont(self._XO_FONT) self.setBrush(getBrushObj('#666666')) if outline: r = QRectF(self._tbr).adjusted(-half_label_W, 0, half_label_W, half_label_H) self._outline.setRect(r) self._outline.setPen(getPenObj('#ff0000', 0.25)) self._outline.setY(2*half_label_H) self._outline.show() else: self._outline.hide()
class MapScene(QGraphicsScene): selectedObjectItemsChanged = pyqtSignal() ## # Constructor. ## def __init__(self, parent): super().__init__(parent) self.mMapDocument = None self.mSelectedTool = None self.mActiveTool = None self.mObjectSelectionItem = None self.mUnderMouse = False self.mCurrentModifiers = Qt.NoModifier, self.mDarkRectangle = QGraphicsRectItem() self.mDefaultBackgroundColor = Qt.darkGray self.mLayerItems = QVector() self.mObjectItems = QMap() self.mObjectLineWidth = 0.0 self.mSelectedObjectItems = QSet() self.mLastMousePos = QPointF() self.mShowTileObjectOutlines = False self.mHighlightCurrentLayer = False self.mGridVisible = False self.setBackgroundBrush(self.mDefaultBackgroundColor) tilesetManager = TilesetManager.instance() tilesetManager.tilesetChanged.connect(self.tilesetChanged) tilesetManager.repaintTileset.connect(self.tilesetChanged) prefs = preferences.Preferences.instance() prefs.showGridChanged.connect(self.setGridVisible) prefs.showTileObjectOutlinesChanged.connect(self.setShowTileObjectOutlines) prefs.objectTypesChanged.connect(self.syncAllObjectItems) prefs.highlightCurrentLayerChanged.connect(self.setHighlightCurrentLayer) prefs.gridColorChanged.connect(self.update) prefs.objectLineWidthChanged.connect(self.setObjectLineWidth) self.mDarkRectangle.setPen(QPen(Qt.NoPen)) self.mDarkRectangle.setBrush(Qt.black) self.mDarkRectangle.setOpacity(darkeningFactor) self.addItem(self.mDarkRectangle) self.mGridVisible = prefs.showGrid() self.mObjectLineWidth = prefs.objectLineWidth() self.mShowTileObjectOutlines = prefs.showTileObjectOutlines() self.mHighlightCurrentLayer = prefs.highlightCurrentLayer() # Install an event filter so that we can get key events on behalf of the # active tool without having to have the current focus. QCoreApplication.instance().installEventFilter(self) ## # Destructor. ## def __del__(self): if QCoreApplication.instance(): QCoreApplication.instance().removeEventFilter(self) ## # Returns the map document this scene is displaying. ## def mapDocument(self): return self.mMapDocument ## # Sets the map this scene displays. ## def setMapDocument(self, mapDocument): if (self.mMapDocument): self.mMapDocument.disconnect() if (not self.mSelectedObjectItems.isEmpty()): self.mSelectedObjectItems.clear() self.selectedObjectItemsChanged.emit() self.mMapDocument = mapDocument if (self.mMapDocument): renderer = self.mMapDocument.renderer() renderer.setObjectLineWidth(self.mObjectLineWidth) renderer.setFlag(RenderFlag.ShowTileObjectOutlines, self.mShowTileObjectOutlines) self.mMapDocument.mapChanged.connect(self.mapChanged) self.mMapDocument.regionChanged.connect(self.repaintRegion) self.mMapDocument.tileLayerDrawMarginsChanged.connect(self.tileLayerDrawMarginsChanged) self.mMapDocument.layerAdded.connect(self.layerAdded) self.mMapDocument.layerRemoved.connect(self.layerRemoved) self.mMapDocument.layerChanged.connect(self.layerChanged) self.mMapDocument.objectGroupChanged.connect(self.objectGroupChanged) self.mMapDocument.imageLayerChanged.connect(self.imageLayerChanged) self.mMapDocument.currentLayerIndexChanged.connect(self.currentLayerIndexChanged) self.mMapDocument.tilesetTileOffsetChanged.connect(self.tilesetTileOffsetChanged) self.mMapDocument.objectsInserted.connect(self.objectsInserted) self.mMapDocument.objectsRemoved.connect(self.objectsRemoved) self.mMapDocument.objectsChanged.connect(self.objectsChanged) self.mMapDocument.objectsIndexChanged.connect(self.objectsIndexChanged) self.mMapDocument.selectedObjectsChanged.connect(self.updateSelectedObjectItems) self.refreshScene() ## # Returns whether the tile grid is visible. ## def isGridVisible(self): return self.mGridVisible ## # Returns the set of selected map object items. ## def selectedObjectItems(self): return QSet(self.mSelectedObjectItems) ## # Sets the set of selected map object items. This translates to a call to # MapDocument.setSelectedObjects. ## def setSelectedObjectItems(self, items): # Inform the map document about the newly selected objects selectedObjects = QList() #selectedObjects.reserve(items.size()) for item in items: selectedObjects.append(item.mapObject()) self.mMapDocument.setSelectedObjects(selectedObjects) ## # Returns the MapObjectItem associated with the given \a mapObject. ## def itemForObject(self, object): return self.mObjectItems[object] ## # Enables the selected tool at this map scene. # Therefore it tells that tool, that this is the active map scene. ## def enableSelectedTool(self): if (not self.mSelectedTool or not self.mMapDocument): return self.mActiveTool = self.mSelectedTool self.mActiveTool.activate(self) self.mCurrentModifiers = QApplication.keyboardModifiers() if (self.mCurrentModifiers != Qt.NoModifier): self.mActiveTool.modifiersChanged(self.mCurrentModifiers) if (self.mUnderMouse): self.mActiveTool.mouseEntered() self.mActiveTool.mouseMoved(self.mLastMousePos, Qt.KeyboardModifiers()) def disableSelectedTool(self): if (not self.mActiveTool): return if (self.mUnderMouse): self.mActiveTool.mouseLeft() self.mActiveTool.deactivate(self) self.mActiveTool = None ## # Sets the currently selected tool. ## def setSelectedTool(self, tool): self.mSelectedTool = tool ## # QGraphicsScene.drawForeground override that draws the tile grid. ## def drawForeground(self, painter, rect): if (not self.mMapDocument or not self.mGridVisible): return offset = QPointF() # Take into account the offset of the current layer layer = self.mMapDocument.currentLayer() if layer: offset = layer.offset() painter.translate(offset) prefs = preferences.Preferences.instance() self.mMapDocument.renderer().drawGrid(painter, rect.translated(-offset), prefs.gridColor()) ## # Override for handling enter and leave events. ## def event(self, event): x = event.type() if x==QEvent.Enter: self.mUnderMouse = True if (self.mActiveTool): self.mActiveTool.mouseEntered() elif x==QEvent.Leave: self.mUnderMouse = False if (self.mActiveTool): self.mActiveTool.mouseLeft() else: pass return super().event(event) def keyPressEvent(self, event): if (self.mActiveTool): self.mActiveTool.keyPressed(event) if (not (self.mActiveTool and event.isAccepted())): super().keyPressEvent(event) def mouseMoveEvent(self, mouseEvent): self.mLastMousePos = mouseEvent.scenePos() if (not self.mMapDocument): return super().mouseMoveEvent(mouseEvent) if (mouseEvent.isAccepted()): return if (self.mActiveTool): self.mActiveTool.mouseMoved(mouseEvent.scenePos(), mouseEvent.modifiers()) mouseEvent.accept() def mousePressEvent(self, mouseEvent): super().mousePressEvent(mouseEvent) if (mouseEvent.isAccepted()): return if (self.mActiveTool): mouseEvent.accept() self.mActiveTool.mousePressed(mouseEvent) def mouseReleaseEvent(self, mouseEvent): super().mouseReleaseEvent(mouseEvent) if (mouseEvent.isAccepted()): return if (self.mActiveTool): mouseEvent.accept() self.mActiveTool.mouseReleased(mouseEvent) ## # Override to ignore drag enter events. ## def dragEnterEvent(self, event): event.ignore() ## # Sets whether the tile grid is visible. ## def setGridVisible(self, visible): if (self.mGridVisible == visible): return self.mGridVisible = visible self.update() def setObjectLineWidth(self, lineWidth): if (self.mObjectLineWidth == lineWidth): return self.mObjectLineWidth = lineWidth if (self.mMapDocument): self.mMapDocument.renderer().setObjectLineWidth(lineWidth) # Changing the line width can change the size of the object items if (not self.mObjectItems.isEmpty()): for item in self.mObjectItems: item[1].syncWithMapObject() self.update() def setShowTileObjectOutlines(self, enabled): if (self.mShowTileObjectOutlines == enabled): return self.mShowTileObjectOutlines = enabled if (self.mMapDocument): self.mMapDocument.renderer().setFlag(RenderFlag.ShowTileObjectOutlines, enabled) if (not self.mObjectItems.isEmpty()): self.update() ## # Sets whether the current layer should be highlighted. ## def setHighlightCurrentLayer(self, highlightCurrentLayer): if (self.mHighlightCurrentLayer == highlightCurrentLayer): return self.mHighlightCurrentLayer = highlightCurrentLayer self.updateCurrentLayerHighlight() ## # Refreshes the map scene. ## def refreshScene(self): self.mLayerItems.clear() self.mObjectItems.clear() self.removeItem(self.mDarkRectangle) self.clear() self.addItem(self.mDarkRectangle) if (not self.mMapDocument): self.setSceneRect(QRectF()) return self.updateSceneRect() map = self.mMapDocument.map() self.mLayerItems.resize(map.layerCount()) if (map.backgroundColor().isValid()): self.setBackgroundBrush(map.backgroundColor()) else: self.setBackgroundBrush(self.mDefaultBackgroundColor) layerIndex = 0 for layer in map.layers(): layerItem = self.createLayerItem(layer) layerItem.setZValue(layerIndex) self.addItem(layerItem) self.mLayerItems[layerIndex] = layerItem layerIndex += 1 tileSelectionItem = TileSelectionItem(self.mMapDocument) tileSelectionItem.setZValue(10000 - 2) self.addItem(tileSelectionItem) self.mObjectSelectionItem = ObjectSelectionItem(self.mMapDocument) self.mObjectSelectionItem.setZValue(10000 - 1) self.addItem(self.mObjectSelectionItem) self.updateCurrentLayerHighlight() ## # Repaints the specified region. The region is in tile coordinates. ## def repaintRegion(self, region, layer): renderer = self.mMapDocument.renderer() margins = self.mMapDocument.map().drawMargins() for r in region.rects(): boundingRect = QRectF(renderer.boundingRect(r)) self.update(QRectF(renderer.boundingRect(r).adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom()))) boundingRect.translate(layer.offset()) self.update(boundingRect) def currentLayerIndexChanged(self): self.updateCurrentLayerHighlight() # New layer may have a different offset, affecting the grid if self.mGridVisible: self.update() ## # Adapts the scene, layers and objects to new map size, orientation or # background color. ## def mapChanged(self): self.updateSceneRect() for item in self.mLayerItems: tli = item if type(tli) == TileLayerItem: tli.syncWithTileLayer() for item in self.mObjectItems.values(): item.syncWithMapObject() map = self.mMapDocument.map() if (map.backgroundColor().isValid()): self.setBackgroundBrush(map.backgroundColor()) else: self.setBackgroundBrush(self.mDefaultBackgroundColor) def tilesetChanged(self, tileset): if (not self.mMapDocument): return if (contains(self.mMapDocument.map().tilesets(), tileset)): self.update() def tileLayerDrawMarginsChanged(self, tileLayer): index = self.mMapDocument.map().layers().indexOf(tileLayer) item = self.mLayerItems.at(index) item.syncWithTileLayer() def layerAdded(self, index): layer = self.mMapDocument.map().layerAt(index) layerItem = self.createLayerItem(layer) self.addItem(layerItem) self.mLayerItems.insert(index, layerItem) z = 0 for item in self.mLayerItems: item.setZValue(z) z += 1 def layerRemoved(self, index): self.mLayerItems.remove(index) ## # A layer has changed. This can mean that the layer visibility, opacity or # offset changed. ## def layerChanged(self, index): layer = self.mMapDocument.map().layerAt(index) layerItem = self.mLayerItems.at(index) layerItem.setVisible(layer.isVisible()) multiplier = 1 if (self.mHighlightCurrentLayer and self.mMapDocument.currentLayerIndex() < index): multiplier = opacityFactor layerItem.setOpacity(layer.opacity() * multiplier) layerItem.setPos(layer.offset()) # Layer offset may have changed, affecting the scene rect and grid self.updateSceneRect() if self.mGridVisible: self.update() ## # When an object group has changed it may mean its color or drawing order # changed, which affects all its objects. ## def objectGroupChanged(self, objectGroup): self.objectsChanged(objectGroup.objects()) self.objectsIndexChanged(objectGroup, 0, objectGroup.objectCount() - 1) ## # When an image layer has changed, it may change size and it may look # differently. ## def imageLayerChanged(self, imageLayer): index = self.mMapDocument.map().layers().indexOf(imageLayer) item = self.mLayerItems.at(index) item.syncWithImageLayer() item.update() ## # When the tile offset of a tileset has changed, it can affect the bounding # rect of all tile layers and tile objects. It also requires a full repaint. ## def tilesetTileOffsetChanged(self, tileset): self.update() for item in self.mLayerItems: tli = item if type(tli) == TileLayerItem: tli.syncWithTileLayer() for item in self.mObjectItems: cell = item.mapObject().cell() if (not cell.isEmpty() and cell.tile.tileset() == tileset): item.syncWithMapObject() ## # Inserts map object items for the given objects. ## def objectsInserted(self, objectGroup, first, last): ogItem = None # Find the object group item for the object group for item in self.mLayerItems: ogi = item if type(ogi)==ObjectGroupItem: if (ogi.objectGroup() == objectGroup): ogItem = ogi break drawOrder = objectGroup.drawOrder() for i in range(first, last+1): object = objectGroup.objectAt(i) item = MapObjectItem(object, self.mMapDocument, ogItem) if (drawOrder == ObjectGroup.DrawOrder.TopDownOrder): item.setZValue(item.y()) else: item.setZValue(i) self.mObjectItems.insert(object, item) ## # Removes the map object items related to the given objects. ## def objectsRemoved(self, objects): for o in objects: i = self.mObjectItems.find(o) self.mSelectedObjectItems.remove(i) # python would not force delete QGraphicsItem self.removeItem(i) self.mObjectItems.erase(o) ## # Updates the map object items related to the given objects. ## def objectsChanged(self, objects): for object in objects: item = self.itemForObject(object) item.syncWithMapObject() ## # Updates the Z value of the objects when appropriate. ## def objectsIndexChanged(self, objectGroup, first, last): if (objectGroup.drawOrder() != ObjectGroup.DrawOrder.IndexOrder): return for i in range(first, last+1): item = self.itemForObject(objectGroup.objectAt(i)) item.setZValue(i) def updateSelectedObjectItems(self): objects = self.mMapDocument.selectedObjects() items = QSet() for object in objects: item = self.itemForObject(object) if item: items.insert(item) self.mSelectedObjectItems = items self.selectedObjectItemsChanged.emit() def syncAllObjectItems(self): for item in self.mObjectItems: item.syncWithMapObject() def createLayerItem(self, layer): layerItem = None tl = layer.asTileLayer() if tl: layerItem = TileLayerItem(tl, self.mMapDocument) else: og = layer.asObjectGroup() if og: drawOrder = og.drawOrder() ogItem = ObjectGroupItem(og) objectIndex = 0 for object in og.objects(): item = MapObjectItem(object, self.mMapDocument, ogItem) if (drawOrder == ObjectGroup.DrawOrder.TopDownOrder): item.setZValue(item.y()) else: item.setZValue(objectIndex) self.mObjectItems.insert(object, item) objectIndex += 1 layerItem = ogItem else: il = layer.asImageLayer() if il: layerItem = ImageLayerItem(il, self.mMapDocument) layerItem.setVisible(layer.isVisible()) return layerItem def updateSceneRect(self): mapSize = self.mMapDocument.renderer().mapSize() sceneRect = QRectF(0, 0, mapSize.width(), mapSize.height()) margins = self.mMapDocument.map().computeLayerOffsetMargins() sceneRect.adjust(-margins.left(), -margins.top(), margins.right(), margins.bottom()) self.setSceneRect(sceneRect) self.mDarkRectangle.setRect(sceneRect) def updateCurrentLayerHighlight(self): if (not self.mMapDocument): return currentLayerIndex = self.mMapDocument.currentLayerIndex() if (not self.mHighlightCurrentLayer or currentLayerIndex == -1): self.mDarkRectangle.setVisible(False) # Restore opacity for all layers for i in range(self.mLayerItems.size()): layer = self.mMapDocument.map().layerAt(i) self.mLayerItems.at(i).setOpacity(layer.opacity()) return # Darken layers below the current layer self.mDarkRectangle.setZValue(currentLayerIndex - 0.5) self.mDarkRectangle.setVisible(True) # Set layers above the current layer to half opacity for i in range(1, self.mLayerItems.size()): layer = self.mMapDocument.map().layerAt(i) if currentLayerIndex < i: _x = opacityFactor else: _x = 1 multiplier = _x self.mLayerItems.at(i).setOpacity(layer.opacity() * multiplier) def eventFilter(self, object, event): x = event.type() if x==QEvent.KeyPress or x==QEvent.KeyRelease: keyEvent = event newModifiers = keyEvent.modifiers() if (self.mActiveTool and newModifiers != self.mCurrentModifiers): self.mActiveTool.modifiersChanged(newModifiers) self.mCurrentModifiers = newModifiers else: pass return False
def mouseMoveEvent(self, event): """When normal selection, update power spectrum with current selection. Otherwise, show the range of the new marker. """ if not self.scene: return if self.idx_sel in self.scene.items(): self.scene.removeItem(self.idx_sel) self.idx_sel = None chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if chk_marker or chk_event: xy_scene = self.mapToScene(event.pos()) y_distance = self.parent.value('y_distance') pos = QRectF(self.sel_xy[0], 0, xy_scene.x() - self.sel_xy[0], len(self.idx_label) * y_distance) item = QGraphicsRectItem(pos.normalized()) item.setPen(NoPen) if chk_marker: color = QColor(self.parent.value('annot_bookmark_color')) elif chk_event: eventtype = self.parent.notes.idx_eventtype.currentText() color = convert_name_to_color(eventtype) item.setBrush(QBrush(color.lighter(115))) item.setZValue(-10) self.scene.addItem(item) self.idx_sel = item return xy_scene = self.mapToScene(event.pos()) pos = QRectF(self.sel_xy[0], self.sel_xy[1], xy_scene.x() - self.sel_xy[0], xy_scene.y() - self.sel_xy[1]) self.idx_sel = QGraphicsRectItem(pos.normalized()) self.idx_sel.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH)) self.scene.addItem(self.idx_sel) if self.idx_info in self.scene.items(): self.scene.removeItem(self.idx_info) duration = '{0:0.2f}s'.format(abs(xy_scene.x() - self.sel_xy[0])) # get y-size, based on scaling too y = abs(xy_scene.y() - self.sel_xy[1]) scale = self.parent.value('y_scale') * self.chan_scale[self.sel_chan] height = '{0:0.3f}uV'.format(y / scale) item = TextItem_with_BG() item.setText(duration + ' ' + height) item.setPos(self.sel_xy[0], self.sel_xy[1]) self.scene.addItem(item) self.idx_info = item trial = 0 time = self.parent.traces.data.axis['time'][trial] beg_win = min((self.sel_xy[0], xy_scene.x())) end_win = max((self.sel_xy[0], xy_scene.x())) time_of_interest = time[(time >= beg_win) & (time < end_win)] if len(time_of_interest) > MINIMUM_N_SAMPLES: data = self.parent.traces.data(trial=trial, chan=self.chan[self.sel_chan], time=time_of_interest) n_data = len(data) n_pad = (power(2, ceil(log2(n_data))) - n_data) / 2 data = pad(data, (int(ceil(n_pad)), int(floor(n_pad))), 'constant') self.parent.spectrum.display(data)
class SimpleBlackbox(PyreeNode): """Blackbox node template with inputs on the left and outputs on the right""" # Here we define some information about the node author = "DrLuke" # Author of this node (only used for namespacing, never visible to users) modulename = "simplebb" # Internal name of the module, make this something distinguishable name = "Simple Blackbox" # Human-readable name placeable = False # Whether or not this node should be placeable from within the editor Category = ["Builtin"] # Nested categories this Node should be sorted in # Description, similar to python docstrings (Brief summary on first line followed by a long description) description = """This node is the base class for all nodes. It should never be placeable in the editor. However if you DO see this in the editor, something went wrong!""" # Class implementing this node. implementation = BaseImplementation def defineIO(self): raise NotImplementedError("This method must be implemented in derived class") def addInput(self, type, name, displayname): self.inputs.append([type, name, displayname]) def addOutput(self, type, name, displayname): self.outputs.append([type, name, displayname]) def addIO(self): """Add/Update IO""" self.inputs = [] self.outputs = [] self.defineIO() indexOffset = 2 verticalIoSpacing = 20 # Vertical Space between 2 IOs verticalIoStartOffset = (verticalIoSpacing * (max(len(self.inputs), len(self.outputs)) + indexOffset)) / 2 horizontalIoDistance = 10 maxInputWidth = 0 maxOutputWidth = 0 nodeTitleWidth = self.nodeTitle.boundingRect().width() titlePadding = 10 horizontalTextToIoDistance = 5 for ioDefinition in self.inputs: if ioDefinition[0] is not None: if ioDefinition[0] is execType: ioDefinition.append(ExecInput(ioDefinition[0], parent=self, name=ioDefinition[1], displaystr=ioDefinition[2])) else: ioDefinition.append(NodeInput(ioDefinition[0], parent=self, name=ioDefinition[1], displaystr=ioDefinition[2])) ioDefinition.append(QGraphicsTextItem(ioDefinition[2], ioDefinition[3])) maxInputWidth = max(maxInputWidth, ioDefinition[4].boundingRect().width()) ioDefinition[4].setPos(QPointF(horizontalTextToIoDistance, - ioDefinition[3].boundingRect().height() / 2 - ioDefinition[4].boundingRect().height() / 4)) self.IO[ioDefinition[1]] = ioDefinition[3] for ioDefinition in self.outputs: if ioDefinition[0] is not None: if ioDefinition[0] is execType: ioDefinition.append(ExecOutput(ioDefinition[0], parent=self, name=ioDefinition[1], displaystr=ioDefinition[2])) else: ioDefinition.append(NodeOutput(ioDefinition[0], parent=self, name=ioDefinition[1], displaystr=ioDefinition[2])) ioDefinition.append(QGraphicsTextItem(ioDefinition[2], ioDefinition[3])) maxOutputWidth = max(maxInputWidth, ioDefinition[4].boundingRect().width()) ioDefinition[4].setPos(QPointF(- horizontalTextToIoDistance - ioDefinition[4].boundingRect().width(), - ioDefinition[3].boundingRect().height() / 2 - ioDefinition[4].boundingRect().height() / 4)) self.IO[ioDefinition[1]] = ioDefinition[3] width = max(maxInputWidth + maxOutputWidth + horizontalIoDistance, nodeTitleWidth + titlePadding) height = verticalIoSpacing * (max(len(self.inputs), len(self.outputs)) + indexOffset - 1) self.mainRect.setRect(QRectF(-width/2, -height/2, width, height)) for ioDefinition in self.inputs: if ioDefinition[0] is not None: ioDefinition[3].setPos(QPointF(-width/2, - verticalIoStartOffset + (self.inputs.index(ioDefinition) + indexOffset) * verticalIoSpacing)) for ioDefinition in self.outputs: if ioDefinition[0] is not None: ioDefinition[3].setPos(QPointF(width / 2, - verticalIoStartOffset + (self.outputs.index(ioDefinition) + indexOffset) * verticalIoSpacing)) self.nodeTitle.setPos(QPointF(- nodeTitleWidth / 2, -height / 2)) def boundingRect(self): return self.mainRect.rect() def addGraphicsItems(self): self.mainRect = QGraphicsRectItem(QRectF(-15, -15, 30, 30), self) self.nodeTitle = QGraphicsTextItem(type(self).name, self) titleFont = QFont() titleFont.setBold(True) self.nodeTitle.setFont(titleFont) self.selectedChanged(self.isSelected()) def selectedChanged(self, state): if state: self.mainRect.setPen(QPen(Qt.red)) else: self.mainRect.setPen(QPen(Qt.black)) def serialize(self): return None def deserialize(self, data): pass
class Traces(QGraphicsView): """Main widget that contains the recordings to be plotted. Attributes ---------- parent : instance of QMainWindow the main window. config : instance of ConfigTraces settings for this widget y_scrollbar_value : int position of the vertical scrollbar data : instance of ChanTime filtered and reref'ed data chan : list of str list of channels (labels and channel group) chan_pos : list of int y-position of each channel (based on value at 0) chan_scale : list of float scaling factor for each channel time_pos : list of QPointF we need to keep track of the position of time label during creation sel_chan : int index of self.chan of the first selected channel sel_xy : tuple of 2 floats x and y position of the first selected point scene : instance of QGraphicsScene the main scene. idx_label : list of instance of QGraphicsSimpleTextItem the channel labels on the y-axis idx_time : list of instance of QGraphicsSimpleTextItem the time labels on the x-axis idx_sel : instance of QGraphicsRectItem the rectangle showing the selection (both for selection and event) idx_info : instance of QGraphicsSimpleTextItem the rectangle showing the selection idx_markers : list of QGraphicsRectItem list of markers in the dataset idx_annot : list of QGraphicsRectItem list of user-made annotations """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigTraces(self.parent.overview.update_position) self.y_scrollbar_value = 0 self.data = None self.chan = [] self.chan_pos = [] # used later to find out which channel we're using self.chan_scale = [] self.time_pos = [] self.sel_chan = None self.sel_xy = (None, None) self.scene = None self.idx_label = [] self.idx_time = [] self.idx_sel = None self.idx_info = None self.idx_markers = [] self.idx_annot = [] self.create_action() def create_action(self): """Create actions associated with this widget.""" actions = {} act = QAction(QIcon(ICON['step_prev']), 'Previous Step', self) act.setShortcut(QKeySequence.MoveToPreviousChar) act.triggered.connect(self.step_prev) actions['step_prev'] = act act = QAction(QIcon(ICON['step_next']), 'Next Step', self) act.setShortcut(QKeySequence.MoveToNextChar) act.triggered.connect(self.step_next) actions['step_next'] = act act = QAction(QIcon(ICON['page_prev']), 'Previous Page', self) act.setShortcut(QKeySequence.MoveToPreviousPage) act.triggered.connect(self.page_prev) actions['page_prev'] = act act = QAction(QIcon(ICON['page_next']), 'Next Page', self) act.setShortcut(QKeySequence.MoveToNextPage) act.triggered.connect(self.page_next) actions['page_next'] = act act = QAction(QIcon(ICON['zoomprev']), 'Wider Time Window', self) act.setShortcut(QKeySequence.ZoomIn) act.triggered.connect(self.X_more) actions['X_more'] = act act = QAction(QIcon(ICON['zoomnext']), 'Narrower Time Window', self) act.setShortcut(QKeySequence.ZoomOut) act.triggered.connect(self.X_less) actions['X_less'] = act act = QAction(QIcon(ICON['zoomin']), 'Larger Amplitude', self) act.setShortcut(QKeySequence.MoveToPreviousLine) act.triggered.connect(self.Y_more) actions['Y_less'] = act act = QAction(QIcon(ICON['zoomout']), 'Smaller Amplitude', self) act.setShortcut(QKeySequence.MoveToNextLine) act.triggered.connect(self.Y_less) actions['Y_more'] = act act = QAction(QIcon(ICON['ydist_more']), 'Larger Y Distance', self) act.triggered.connect(self.Y_wider) actions['Y_wider'] = act act = QAction(QIcon(ICON['ydist_less']), 'Smaller Y Distance', self) act.triggered.connect(self.Y_tighter) actions['Y_tighter'] = act act = QAction(QIcon(ICON['chronometer']), '6 Hours Earlier', self) act.triggered.connect(partial(self.add_time, -6 * 60 * 60)) actions['addtime_-6h'] = act act = QAction(QIcon(ICON['chronometer']), '1 Hour Earlier', self) act.triggered.connect(partial(self.add_time, -60 * 60)) actions['addtime_-1h'] = act act = QAction(QIcon(ICON['chronometer']), '10 Minutes Earlier', self) act.triggered.connect(partial(self.add_time, -10 * 60)) actions['addtime_-10min'] = act act = QAction(QIcon(ICON['chronometer']), '10 Minutes Later', self) act.triggered.connect(partial(self.add_time, 10 * 60)) actions['addtime_10min'] = act act = QAction(QIcon(ICON['chronometer']), '1 Hour Later', self) act.triggered.connect(partial(self.add_time, 60 * 60)) actions['addtime_1h'] = act act = QAction(QIcon(ICON['chronometer']), '6 Hours Later', self) act.triggered.connect(partial(self.add_time, 6 * 60 * 60)) actions['addtime_6h'] = act self.action = actions def read_data(self): """Read the data to plot.""" window_start = self.parent.value('window_start') window_end = window_start + self.parent.value('window_length') dataset = self.parent.info.dataset groups = self.parent.channels.groups chan_to_read = [] for one_grp in groups: chan_to_read.extend(one_grp['chan_to_plot'] + one_grp['ref_chan']) if not chan_to_read: return data = dataset.read_data(chan=chan_to_read, begtime=window_start, endtime=window_end) max_s_freq = self.parent.value('max_s_freq') if data.s_freq > max_s_freq: q = int(data.s_freq / max_s_freq) lg.debug('Decimate (no low-pass filter) at ' + str(q)) data.data[0] = data.data[0][:, slice(None, None, q)] data.axis['time'][0] = data.axis['time'][0][slice(None, None, q)] data.s_freq = int(data.s_freq / q) self.data = _create_data_to_plot(data, self.parent.channels.groups) def display(self): """Display the recordings.""" if self.data is None: return if self.scene is not None: self.y_scrollbar_value = self.verticalScrollBar().value() self.scene.clear() self.create_chan_labels() self.create_time_labels() window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') time_height = max([x.boundingRect().height() for x in self.idx_time]) label_width = window_length * self.parent.value('label_ratio') scene_height = (len(self.idx_label) * self.parent.value('y_distance') + time_height) self.scene = QGraphicsScene(window_start - label_width, 0, window_length + label_width, scene_height) self.setScene(self.scene) self.idx_markers = [] self.idx_annot = [] self.add_chan_labels() self.add_time_labels() self.add_traces() self.display_grid() self.display_markers() self.display_annotations() self.resizeEvent(None) self.verticalScrollBar().setValue(self.y_scrollbar_value) self.parent.info.display_view() self.parent.overview.display_current() def create_chan_labels(self): """Create the channel labels, but don't plot them yet. Notes ----- It's necessary to have the width of the labels, so that we can adjust the main scene. """ self.idx_label = [] for one_grp in self.parent.channels.groups: for one_label in one_grp['chan_to_plot']: item = QGraphicsSimpleTextItem(one_label) item.setBrush(QBrush(QColor(one_grp['color']))) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.idx_label.append(item) def create_time_labels(self): """Create the time labels, but don't plot them yet. Notes ----- It's necessary to have the height of the time labels, so that we can adjust the main scene. Not very robust, because it uses seconds as integers. """ min_time = int(floor(min(self.data.axis['time'][0]))) max_time = int(ceil(max(self.data.axis['time'][0]))) n_time_labels = self.parent.value('n_time_labels') self.idx_time = [] self.time_pos = [] for one_time in linspace(min_time, max_time, n_time_labels): x_label = (self.data.start_time + timedelta(seconds=one_time)).strftime('%H:%M:%S') item = QGraphicsSimpleTextItem(x_label) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.idx_time.append(item) self.time_pos.append(QPointF(one_time, len(self.idx_label) * self.parent.value('y_distance'))) def add_chan_labels(self): """Add channel labels on the left.""" window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') label_width = window_length * self.parent.value('label_ratio') for row, one_label_item in enumerate(self.idx_label): self.scene.addItem(one_label_item) one_label_item.setPos(window_start - label_width, self.parent.value('y_distance') * row + self.parent.value('y_distance') / 2) def add_time_labels(self): """Add time labels at the bottom.""" for text, pos in zip(self.idx_time, self.time_pos): self.scene.addItem(text) text.setPos(pos) def add_traces(self): """Add traces based on self.data.""" y_distance = self.parent.value('y_distance') self.chan = [] self.chan_pos = [] self.chan_scale = [] row = 0 for one_grp in self.parent.channels.groups: for one_chan in one_grp['chan_to_plot']: # channel name chan_name = one_chan + ' (' + one_grp['name'] + ')' # trace dat = (self.data(trial=0, chan=chan_name) * self.parent.value('y_scale')) dat *= -1 # flip data, upside down path = self.scene.addPath(Path(self.data.axis['time'][0], dat)) path.setPen(QPen(QColor(one_grp['color']), LINE_WIDTH)) # adjust position chan_pos = y_distance * row + y_distance / 2 path.setPos(0, chan_pos) row += 1 self.chan.append(chan_name) self.chan_scale.append(one_grp['scale']) self.chan_pos.append(chan_pos) def display_grid(self): """Display grid on x-axis and y-axis.""" window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length if self.parent.value('grid_x'): x_tick = self.parent.value('grid_xtick') x_ticks = arange(window_start, window_end + x_tick, x_tick) for x in x_ticks: x_pos = [x, x] y_pos = [0, self.parent.value('y_distance') * len(self.idx_label)] path = self.scene.addPath(Path(x_pos, y_pos)) path.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DotLine)) if self.parent.value('grid_y'): for one_label_item in self.idx_label: x_pos = [window_start, window_end] y_pos = [one_label_item.y(), one_label_item.y()] path = self.scene.addPath(Path(x_pos, y_pos)) path.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DotLine)) def display_markers(self): """Add markers on top of first plot.""" for item in self.idx_markers: self.scene.removeItem(item) self.idx_markers = [] window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length y_distance = self.parent.value('y_distance') markers = [] if self.parent.info.markers is not None: if self.parent.value('marker_show'): markers = self.parent.info.markers for mrk in markers: if window_start <= mrk['end'] and window_end >= mrk['start']: mrk_start = max((mrk['start'], window_start)) mrk_end = min((mrk['end'], window_end)) color = QColor(self.parent.value('marker_color')) item = QGraphicsRectItem(mrk_start, 0, mrk_end - mrk_start, len(self.idx_label) * y_distance) item.setPen(color) item.setBrush(color) item.setZValue(-9) self.scene.addItem(item) item = TextItem_with_BG(color.darker(200)) item.setText(mrk['name']) item.setPos(mrk['start'], len(self.idx_label) * self.parent.value('y_distance')) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) item.setRotation(-90) self.scene.addItem(item) self.idx_markers.append(item) def display_annotations(self): """Mark all the bookmarks/events, on top of first plot.""" for item in self.idx_annot: self.scene.removeItem(item) self.idx_annot = [] window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length y_distance = self.parent.value('y_distance') raw_chan_name = list(map(take_raw_name, self.chan)) bookmarks = [] events = [] if self.parent.notes.annot is not None: if self.parent.value('annot_show'): bookmarks = self.parent.notes.annot.get_bookmarks() events = self.parent.notes.get_selected_events((window_start, window_end)) annotations = bookmarks + events for annot in annotations: if window_start <= annot['end'] and window_end >= annot['start']: mrk_start = max((annot['start'], window_start)) mrk_end = min((annot['end'], window_end)) if annot in bookmarks: color = QColor(self.parent.value('annot_bookmark_color')) if annot in events: color = convert_name_to_color(annot['name']) if annot['chan'] == ['']: h_annot = len(self.idx_label) * y_distance y_annot = (0, ) item = TextItem_with_BG(color.darker(200)) item.setText(annot['name']) item.setPos(annot['start'], len(self.idx_label) * y_distance) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) item.setRotation(-90) self.scene.addItem(item) self.idx_annot.append(item) zvalue = -8 else: h_annot = y_distance # find indices of channels with annotations chan_idx_in_mrk = in1d(raw_chan_name, annot['chan']) y_annot = asarray(self.chan_pos)[chan_idx_in_mrk] y_annot -= y_distance / 2 zvalue = -7 for y in y_annot: item = QGraphicsRectItem(mrk_start, y, mrk_end - mrk_start, h_annot) item.setPen(color) item.setBrush(color) item.setZValue(zvalue) self.scene.addItem(item) self.idx_annot.append(item) def step_prev(self): """Go to the previous step.""" window_start = (self.parent.value('window_start') - self.parent.value('window_length') / self.parent.value('window_step')) self.parent.overview.update_position(window_start) def step_next(self): """Go to the next step.""" window_start = (self.parent.value('window_start') + self.parent.value('window_length') / self.parent.value('window_step')) self.parent.overview.update_position(window_start) def page_prev(self): """Go to the previous page.""" window_start = (self.parent.value('window_start') - self.parent.value('window_length')) self.parent.overview.update_position(window_start) def page_next(self): """Go to the next page.""" window_start = (self.parent.value('window_start') + self.parent.value('window_length')) self.parent.overview.update_position(window_start) def add_time(self, extra_time): """Go to the predefined time forward.""" window_start = self.parent.value('window_start') + extra_time self.parent.overview.update_position(window_start) def X_more(self): """Zoom in on the x-axis.""" self.parent.value('window_length', self.parent.value('window_length') * 2) self.parent.overview.update_position() def X_less(self): """Zoom out on the x-axis.""" self.parent.value('window_length', self.parent.value('window_length') / 2) self.parent.overview.update_position() def X_length(self, new_window_length): """Use presets for length of the window.""" self.parent.value('window_length', new_window_length) self.parent.overview.update_position() def Y_more(self): """Increase the amplitude.""" self.parent.value('y_scale', self.parent.value('y_scale') * 2) self.parent.traces.display() def Y_less(self): """Decrease the amplitude.""" self.parent.value('y_scale', self.parent.value('y_scale') / 2) self.parent.traces.display() def Y_ampl(self, new_y_scale): """Make amplitude on Y axis using predefined values""" self.parent.value('y_scale', new_y_scale) self.parent.traces.display() def Y_wider(self): """Increase the distance of the lines.""" self.parent.value('y_distance', self.parent.value('y_distance') * 1.4) self.parent.traces.display() def Y_tighter(self): """Decrease the distance of the lines.""" self.parent.value('y_distance', self.parent.value('y_distance') / 1.4) self.parent.traces.display() def Y_dist(self, new_y_distance): """Use preset values for the distance between lines.""" self.parent.value('y_distance', new_y_distance) self.parent.traces.display() def mousePressEvent(self, event): """Create a marker or start selection Parameters ---------- event : instance of QtCore.QEvent it contains the position that was clicked. """ if not self.scene: return xy_scene = self.mapToScene(event.pos()) chan_idx = argmin(abs(asarray(self.chan_pos) - xy_scene.y())) self.sel_chan = chan_idx self.sel_xy = (xy_scene.x(), xy_scene.y()) chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if not (chk_marker or chk_event): channame = self.chan[self.sel_chan] + ' in selected window' self.parent.spectrum.show_channame(channame) def mouseMoveEvent(self, event): """When normal selection, update power spectrum with current selection. Otherwise, show the range of the new marker. """ if not self.scene: return if self.idx_sel in self.scene.items(): self.scene.removeItem(self.idx_sel) self.idx_sel = None chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if chk_marker or chk_event: xy_scene = self.mapToScene(event.pos()) y_distance = self.parent.value('y_distance') pos = QRectF(self.sel_xy[0], 0, xy_scene.x() - self.sel_xy[0], len(self.idx_label) * y_distance) item = QGraphicsRectItem(pos.normalized()) item.setPen(NoPen) if chk_marker: color = QColor(self.parent.value('annot_bookmark_color')) elif chk_event: eventtype = self.parent.notes.idx_eventtype.currentText() color = convert_name_to_color(eventtype) item.setBrush(QBrush(color.lighter(115))) item.setZValue(-10) self.scene.addItem(item) self.idx_sel = item return xy_scene = self.mapToScene(event.pos()) pos = QRectF(self.sel_xy[0], self.sel_xy[1], xy_scene.x() - self.sel_xy[0], xy_scene.y() - self.sel_xy[1]) self.idx_sel = QGraphicsRectItem(pos.normalized()) self.idx_sel.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH)) self.scene.addItem(self.idx_sel) if self.idx_info in self.scene.items(): self.scene.removeItem(self.idx_info) duration = '{0:0.2f}s'.format(abs(xy_scene.x() - self.sel_xy[0])) # get y-size, based on scaling too y = abs(xy_scene.y() - self.sel_xy[1]) scale = self.parent.value('y_scale') * self.chan_scale[self.sel_chan] height = '{0:0.3f}uV'.format(y / scale) item = TextItem_with_BG() item.setText(duration + ' ' + height) item.setPos(self.sel_xy[0], self.sel_xy[1]) self.scene.addItem(item) self.idx_info = item trial = 0 time = self.parent.traces.data.axis['time'][trial] beg_win = min((self.sel_xy[0], xy_scene.x())) end_win = max((self.sel_xy[0], xy_scene.x())) time_of_interest = time[(time >= beg_win) & (time < end_win)] if len(time_of_interest) > MINIMUM_N_SAMPLES: data = self.parent.traces.data(trial=trial, chan=self.chan[self.sel_chan], time=time_of_interest) n_data = len(data) n_pad = (power(2, ceil(log2(n_data))) - n_data) / 2 data = pad(data, (int(ceil(n_pad)), int(floor(n_pad))), 'constant') self.parent.spectrum.display(data) def mouseReleaseEvent(self, event): """Create a new event or marker, or show the previous power spectrum """ if not self.scene: return chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if chk_marker or chk_event: x_in_scene = self.mapToScene(event.pos()).x() # it can happen that selection is empty (f.e. double-click) if self.sel_xy[0] is not None: # max resolution = sampling frequency # in case there is no data s_freq = self.parent.info.dataset.header['s_freq'] at_s_freq = lambda x: round(x * s_freq) / s_freq start = at_s_freq(self.sel_xy[0]) end = at_s_freq(x_in_scene) if abs(end - start) < self.parent.value('min_marker_dur'): end = start if start <= end: time = (start, end) else: time = (end, start) if chk_marker: self.parent.notes.add_bookmark(time) elif chk_event: eventtype = self.parent.notes.idx_eventtype.currentText() self.parent.notes.add_event(eventtype, time) else: # normal selection if self.idx_info in self.scene.items(): self.scene.removeItem(self.idx_info) self.idx_info = None # restore spectrum self.parent.spectrum.update() self.parent.spectrum.display_window() # general garbage collection self.sel_chan = None self.sel_xy = (None, None) if self.idx_sel in self.scene.items(): self.scene.removeItem(self.idx_sel) self.idx_sel = None def resizeEvent(self, event): """Resize scene so that it fits the whole widget. Parameters ---------- event : instance of QtCore.QEvent not important Notes ----- This function overwrites Qt function, therefore the non-standard name. Argument also depends on Qt. The function is used to change the scale of view, so that the scene fits the whole scene. There are two problems that I could not fix: 1) how to give the width of the label in absolute width, 2) how to strech scene just enough that it doesn't trigger a scrollbar. However, it's pretty good as it is now. """ if self.scene is not None: ratio = self.width() / (self.scene.width() * 1.1) self.resetTransform() self.scale(ratio, 1) def reset(self): self.y_scrollbar_value = 0 self.data = None self.chan = [] self.chan_pos = [] self.chan_scale = [] self.sel_chan = None self.sel_xy = (None, None) if self.scene is not None: self.scene.clear() self.scene = None self.idx_sel = None self.idx_info = None self.idx_label = [] self.idx_time = [] self.time_pos = []
class NodeItem(QGraphicsItem): def __init__ (self, nodeobj, parent=None, view=None, state=1): super().__init__() self.edge = None self.linkIDs = None self.children = None self.childpos = None self.nodeobj = nodeobj self.style = FlGlob.mainwindow.style self.view = weakref.proxy(view) self.refID = parent.realid() if parent is not None else None self.state = state self.setrank(parent) self.setCursor(Qt.ArrowCursor) self.yoffset = 0 self.graphicsetup() self.setstate(state) def id (self): return (self.refID, self.nodeobj.ID) def realid (self): return self.nodeobj.ID def childlist (self, generate=False): ID = self.nodeobj.ID itemtable = self.view.itemtable if self.state == 1 and ID in itemtable and not self.iscollapsed(): if self.children and self.nodeobj.linkIDs == self.linkIDs and None not in [c() for c in self.children]: ret = self.children else: children = [] for child in self.nodeobj.linkIDs: if child in itemtable[ID]: item = itemtable[ID][child] else: continue children.append(weakref.ref(item)) self.linkIDs = self.nodeobj.linkIDs.copy() self.children = children ret = children else: ret = [] if generate: x = self.x() y = self.y() self.childpos = [] for target in ret: t = target() self.childpos.append((t.x()+t.boundingRect().left()-self.style.activemargin-x, t.y()-y)) if self.edge: if self.childpos != self.edge.childpos: self.edge.prepareGeometryChange() self.edge.sourceright = self.boundingRect().right() self.edge.update(self.edge.boundingRect()) return ret def setedge (self, edge): self.edge = edge edge.setX(self.x()) def setactive (self, active): if active: self.activebox.show() self.mainbox.setBrush(QBrush(self.altcolor)) else: self.activebox.hide() self.mainbox.setBrush(QBrush(self.maincolor)) def setselected (self, selected): if selected: self.selectbox.show() else: self.selectbox.hide() def setstate (self, state): self.state = state if state == 1: # normal self.show() self.graphgroup.setOpacity(1) self.shadowbox.show() elif state == 0: # ghost self.show() self.graphgroup.setOpacity(0.7) self.shadowbox.hide() elif state == -1: # hidden self.hide() def setplaymode (self, playmode): if playmode: self.setOpacity(0.5) else: self.setOpacity(1) def setY (self, y): parent = self.view.itembyID(self.refID) y += self.getyoffset() if self.edge is not None: self.edge.setY(y) super().setY(y) def setrank (self, parent): if parent is None: return if self.issubnode(): x = parent.x() self.setX(x) else: x = parent.x()+self.style.rankwidth self.setX(x) self.nudgechildren() if self.edge is not None: self.edge.setX(x) def nudgechildren (self): for child in self.childlist(): child().setrank(self) def getyoffset (self): if self.nodeobj.nodebank == -1: return self.yoffset else: return self.view.itembyID(self.refID).getyoffset() + self.yoffset def hide (self): super().hide() if self.edge: self.edge.hide() def show (self): super().show() if self.edge: self.edge.show() def issubnode (self): return self.nodeobj.nodebank is not -1 def isghost (self): return not self.state def realnode (self): return self.view.itembyID(self.nodeobj.ID) def isactive (self): return self.view.activenode is self def isselected (self): return self.view.selectednode is self def iscollapsed (self): return self.id() in self.view.collapsednodes def y_top (self): return self.y() - self.boundingRect().height()//2 def y_bottom (self): return self.y() + self.boundingRect().height()//2 def bulkshift (self, children, diff): self.setY(self.y() + diff) if children is None: children = [c() for c in self.childlist()] for child in children: child.bulkshift(None, diff) def treeposition (self, ranks=None): if ranks is None: ranks = dict() localranks = dict() children = [c() for c in self.childlist()] for child in children: localranks = child.treeposition(localranks) rank = self.x() // self.style.rankwidth if children: top = children[0].y_top() bottom = children[-1].y_bottom() self.setY((top+bottom)//2) localranks[rank] = [self.y_top, self.y_bottom] streeshift = None for r in localranks: if r in ranks: rankshift = ranks[r][1]() + self.style.rowgap - localranks[r][0]() if streeshift is None or rankshift > streeshift: streeshift = rankshift ranks[r][1] = localranks[r][1] else: ranks[r] = localranks[r] if streeshift: self.bulkshift(children, streeshift) return ranks def siblings (self): if self.refID is None: return None parent = self.view.nodecontainer.nodes[self.refID] if self.issubnode(): return parent.subnodes else: return parent.linkIDs def siblingabove (self): sibs = self.siblings() if sibs is None or self.nodeobj.ID not in sibs: return None myindex = sibs.index(self.nodeobj.ID) if myindex: sibID = (self.refID, sibs[myindex-1]) return self.view.itembyfullID(sibID) else: return None def siblingbelow (self): sibs = self.siblings() if sibs is None or self.nodeobj.ID not in sibs: return None myindex = sibs.index(self.nodeobj.ID) if len(sibs) > myindex+1: sibID = (self.refID, sibs[myindex+1]) return self.view.itembyfullID(sibID) else: return None def subtreesize (self, depth=-1): """Find vertical extents of a subtree. Returns min/max y coordinates up to given depth (negative depth means whole subtree).""" # calculate child positions for EgdeItem only once when calculating scenerect if depth<0: generate = True else: generate = False children = [c() for c in self.childlist(generate=generate)] maxdepth = abs(depth) if children and depth: nextdepth = depth-1 ymin = self.y_top() ymax = self.y_bottom() for child in children: top, bottom, depth = child.subtreesize(nextdepth) ymin = min(ymin, top) ymax = max(ymax, bottom) maxdepth = max(maxdepth, depth) else: ymin = self.y_top() ymax = self.y_bottom() return ymin, ymax, maxdepth def boundingRect (self): return self.rect def paint (self, painter, style, widget): pass def pixmap (self, path): return QPixmap(path).scaledToWidth(self.style.boldheight, Qt.SmoothTransformation) def graphicsetup (self): lightbrush = QBrush(FlPalette.light) mainbrush = QBrush(self.maincolor) altbrush = QBrush(self.altcolor) nopen = QPen(0) viewport = self.view.viewport() self.graphgroup = QGraphicsItemGroup(self) self.fggroup = QGraphicsItemGroup(self) self.shadowbox = QGraphicsRectItem(self) self.shadowbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.shadowbox.setBrush(FlPalette.dark) self.shadowbox.setPen(nopen) self.shadowbox.setPos(*(self.style.shadowoffset,)*2) self.graphgroup.addToGroup(self.shadowbox) self.activebox = QGraphicsRectItem(self) self.activebox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) activepen = QPen(self.maincolor, self.style.selectmargin, join=Qt.MiterJoin) self.activebox.setPen(activepen) self.activebox.hide() self.graphgroup.addToGroup(self.activebox) self.selectbox = QGraphicsRectItem(self) self.selectbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) selectpen = QPen(FlPalette.light, self.style.selectmargin, join=Qt.MiterJoin) self.selectbox.setPen(selectpen) self.selectbox.hide() self.graphgroup.addToGroup(self.selectbox) self.mainbox = QGraphicsRectItem(self) self.mainbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.mainbox.setBrush(mainbrush) self.mainbox.setPen(nopen) self.graphgroup.addToGroup(self.mainbox) self.nodelabel = QGraphicsSimpleTextItemCond(self, viewport) self.nodelabel.setBrush(lightbrush) self.nodelabel.setFont(self.style.boldfont) self.nodelabel.setText(self.label % self.realid()) self.nodelabel.setPos(self.style.itemmargin, self.style.itemmargin) self.fggroup.addToGroup(self.nodelabel) self.icon = self.pixmap("images/blank.png") self.iwidth = self.icon.width() self.iconx = self.style.nodetextwidth self.condicon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.condicon.setPos(self.iconx-self.iwidth, self.style.itemmargin) self.iconx = self.condicon.x() self.fggroup.addToGroup(self.condicon) self.randicon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.randicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.randicon.x() self.fggroup.addToGroup(self.randicon) self.exiticon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.exiticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.exiticon.x() self.fggroup.addToGroup(self.exiticon) self.entericon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.entericon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.entericon.x() self.fggroup.addToGroup(self.entericon) self.persisticon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.persisticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.persisticon.x() self.fggroup.addToGroup(self.persisticon) self.comment = QGraphicsTextItemCond(self, viewport) self.comment.setTextWidth(self.style.nodetextwidth) self.comment.setDefaultTextColor(FlPalette.light) self.comment.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin) self.fggroup.addToGroup(self.comment) self.graphgroup.addToGroup(self.fggroup) self.view.nodedocs[self.realid()]["comment"].contentsChanged.connect(self.updatecomment) self.updatecondition() self.updateenterscripts() self.updateexitscripts() self.updaterandweight() self.updatepersistence() # Never call updatelayout() from here (or any inheritable reimplementation)! def collapse (self, collapse): for item in self.fggroup.childItems(): if item is not self.nodelabel: if collapse: item.hide() else: item.show() self.updatelayout() def updatecondition (self): icons = {True: "key", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hascond()]) self.condicon.setPixmap(pixmap) if self.nodeobj.hascond(): self.condicon.setToolTip("Condition") else: self.condicon.setToolTip("") def updateenterscripts (self): icons = {True: "script-enter", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasenterscripts()]) self.entericon.setPixmap(pixmap) if self.nodeobj.hasenterscripts(): self.entericon.setToolTip("Enter Scripts") else: self.entericon.setToolTip("") def updateexitscripts (self): icons = {True: "script-exit", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasexitscripts()]) self.exiticon.setPixmap(pixmap) if self.nodeobj.hasexitscripts(): self.exiticon.setToolTip("Exit Scripts") else: self.exiticon.setToolTip("") def updaterandweight (self): icons = {True: "dice", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[bool(self.nodeobj.randweight)]) self.randicon.setPixmap(pixmap) if self.nodeobj.randweight: self.randicon.setToolTip("Random Weight: %s" % self.nodeobj.randweight) else: self.randicon.setToolTip("") def updatepersistence (self): icons = {"Mark": "mark", "OncePerConv": "once", "OnceEver": "onceever", "": "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.persistence]) self.persisticon.setPixmap(pixmap) if self.nodeobj.persistence: self.persisticon.setToolTip("Persistence: %s" % self.nodeobj.persistence) else: self.persisticon.setToolTip("") def updatecomment (self): self.fggroup.removeFromGroup(self.comment) contents = self.view.nodedocs[self.realid()]["comment"].toPlainText() if not contents: self.comment.hide() else: self.comment.show() self.comment.setPlainText(contents) self.fggroup.addToGroup(self.comment) self.updatelayout() def updatelayout (self): if self.iscollapsed(): rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect()) else: rect = self.fggroup.childrenBoundingRect() mainrect = rect.marginsAdded(self.style.nodemargins) self.mainbox.setRect(mainrect) self.shadowbox.setRect(mainrect) self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins)) activerect = mainrect.marginsAdded(self.style.activemargins) self.activebox.setRect(activerect) self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y()) self.prepareGeometryChange() self.rect = self.graphgroup.mapRectToParent(mainrect) self.view.updatelayout() def mouseDoubleClickEvent (self, event): super().mouseDoubleClickEvent(event) event.accept() if event.button() == Qt.LeftButton: self.view.setactivenode(self) def mousePressEvent (self, event): super().mousePressEvent(event) if event.button() & (Qt.LeftButton | Qt.RightButton) : self.view.setselectednode(self) event.accept() def __repr__ (self): return "<%s %s>" % (type(self).__name__, self.id())
class PaintArea(QGraphicsView): def __init__(self, width=10, parent=None): QGraphicsView.__init__(self, parent) self._frame = None self._instructions = None self.setScene(QGraphicsScene(self)) self._items = self.scene().createItemGroup([]) self.setMouseTracking(True) self.pen = QPen(Qt.black, width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.painting = False self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) self.viewport().setCursor(self.getCursor()) self.updateScene() def updateScene(self): if self._frame: self.scene().setBackgroundBrush(Qt.gray) oldCanvas = self.canvas() self.setSceneRect(QRectF(self.contentsRect())) self.centerScene() self.scaleItems(oldCanvas, self.canvas()) def centerScene(self): self.centerFrame() self.centerInstructions() def scaleItems(self, oldCanvas, newCanvas): pass def canvas(self): if self._frame: return self._frame.rect() return QRectF(self.contentsRect()) def fitInstructions(self): textSize = self._instructions.document().size() factor = min(self.canvas().size().width() / textSize.width(), self.canvas().size().height() / textSize.height()) f = self._instructions.font() f.setPointSizeF(f.pointSizeF() * factor) self._instructions.setFont(f) def centerInstructions(self): if self._instructions: self.fitInstructions() size = self.size() textSize = self._instructions.document().size() self._instructions.setPos((size.width() - textSize.width()) / 2.0, (size.height() - textSize.height()) / 2.0) def setInstructions(self, text): if self._instructions: self._instructions.setPlainText(text) else: self._instructions = self.scene().addText(text, QFont('Arial', 10, QFont.Bold)) self._instructions.setZValue(-1) self._instructions.setDefaultTextColor(QColor(220, 220, 220)) self._text = text self.centerInstructions() def setFrame(self, width, height): if self._frame: self._frame.setRect(0, 0, width, height) else: self.addFrame(QRectF(0, 0, width, height)) self.centerScene() def addFrame(self, rect): self._frame = QGraphicsRectItem(rect) self._frame.setPen(QPen(Qt.NoPen)) self._frame.setBrush(Qt.white) self._frame.setZValue(-2) self.scene().addItem(self._frame) def centerFrame(self): if self._frame: rect = self._frame.rect() size = self.contentsRect() factor = min((size.width() + 1) / rect.width(), (size.height() + 1) / rect.height()) w, h = rect.width() * factor, rect.height() * factor self._frame.setRect(size.x() + (size.width() - w) / 2.0, size.y() + (size.height() - h) / 2.0, w, h) def resizeEvent(self, event): self.updateScene() def setBrushSize(self, size): self.pen.setWidth(size) self.viewport().setCursor(self.getCursor()) def render(self, painter): if self._instructions: self.scene().removeItem(self._instructions) self.scene().render(painter, source=self.scene().itemsBoundingRect()) if self._instructions: self.scene().addItem(self._instructions) def getLines(self): items = [item for item in self.scene().items() if item.group() == self._items] return self.canvas(), items def clear(self): for item in self.scene().items(): if item.group() == self._items: self._items.removeFromGroup(item) def getCursor(self): antialiasing_margin = 1 size = self.pen.width() pixmap = QPixmap(size + antialiasing_margin * 2, size + antialiasing_margin * 2) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) painter.drawEllipse(QRectF(QPointF(antialiasing_margin, antialiasing_margin), QSizeF(size, size))) painter.end() return QCursor(pixmap) def addLine(self, start, end): if start == end: delta = QPointF(.0001, 0) end = start - delta line = self.scene().addLine(QLineF(start, end), self.pen) self._items.addToGroup(line) def drawPoint(self, pos): delta = QPointF(.0001, 0) line = self.scene().addLine(QLineF(pos, pos - delta), self.pen) self._items.addToGroup(line) def mousePressEvent(self, event): self.start = QPointF(self.mapToScene(event.pos())) self.painting = True self.addLine(self.start, self.start) def mouseReleaseEvent(self, event): self.painting = False def mouseMoveEvent(self, event): pos = QPointF(self.mapToScene(event.pos())) if self.painting: self.addLine(self.start, pos) self.start = pos
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 SvgView(QGraphicsView): Native, OpenGL, Image = range(3) def __init__(self, parent=None): super(SvgView, self).__init__(parent) self.renderer = SvgView.Native self.svgItem = None self.backgroundItem = None self.outlineItem = None self.image = QImage() self.setScene(QGraphicsScene(self)) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # Prepare background check-board pattern. tilePixmap = QPixmap(64, 64) tilePixmap.fill(Qt.white) tilePainter = QPainter(tilePixmap) color = QColor(220, 220, 220) tilePainter.fillRect(0, 0, 32, 32, color) tilePainter.fillRect(32, 32, 32, 32, color) tilePainter.end() self.setBackgroundBrush(QBrush(tilePixmap)) def drawBackground(self, p, rect): p.save() p.resetTransform() p.drawTiledPixmap(self.viewport().rect(), self.backgroundBrush().texture()) p.restore() def openFile(self, svg_file): if not svg_file.exists(): return s = self.scene() if self.backgroundItem: drawBackground = self.backgroundItem.isVisible() else: drawBackground = False if self.outlineItem: drawOutline = self.outlineItem.isVisible() else: drawOutline = True s.clear() self.resetTransform() self.svgItem = QGraphicsSvgItem(svg_file.fileName()) self.svgItem.setFlags(QGraphicsItem.ItemClipsToShape) self.svgItem.setCacheMode(QGraphicsItem.NoCache) self.svgItem.setZValue(0) self.backgroundItem = QGraphicsRectItem(self.svgItem.boundingRect()) self.backgroundItem.setBrush(Qt.white) self.backgroundItem.setPen(QPen(Qt.NoPen)) self.backgroundItem.setVisible(drawBackground) self.backgroundItem.setZValue(-1) self.outlineItem = QGraphicsRectItem(self.svgItem.boundingRect()) outline = QPen(Qt.black, 2, Qt.DashLine) outline.setCosmetic(True) self.outlineItem.setPen(outline) self.outlineItem.setBrush(QBrush(Qt.NoBrush)) self.outlineItem.setVisible(drawOutline) self.outlineItem.setZValue(1) s.addItem(self.backgroundItem) s.addItem(self.svgItem) s.addItem(self.outlineItem) s.setSceneRect(self.outlineItem.boundingRect().adjusted(-10, -10, 10, 10)) def setRenderer(self, renderer): self.renderer = renderer if self.renderer == SvgView.OpenGL: if QGLFormat.hasOpenGL(): self.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers))) else: self.setViewport(QWidget()) def setHighQualityAntialiasing(self, highQualityAntialiasing): if QGLFormat.hasOpenGL(): self.setRenderHint(QPainter.HighQualityAntialiasing, highQualityAntialiasing) def setViewBackground(self, enable): if self.backgroundItem: self.backgroundItem.setVisible(enable) def setViewOutline(self, enable): if self.outlineItem: self.outlineItem.setVisible(enable) def paintEvent(self, event): if self.renderer == SvgView.Image: if self.image.size() != self.viewport().size(): self.image = QImage(self.viewport().size(), QImage.Format_ARGB32_Premultiplied) imagePainter = QPainter(self.image) QGraphicsView.render(self, imagePainter) imagePainter.end() p = QPainter(self.viewport()) p.drawImage(0, 0, self.image) else: super(SvgView, self).paintEvent(event) def wheelEvent(self, event): print(event.angleDelta().y()) factor = pow(1.2, event.angleDelta().y() / 240.0) self.scale(factor, factor) event.accept()
class ZoomableScene(QGraphicsScene): def __init__(self, parent=None): super().__init__(parent) self.noise_area = None self.ones_area = None self.zeros_area = None self.ones_arrow = None self.zeros_arrow = None self.selection_area = ROI(0, 0, 0, 0, fillcolor=constants.SELECTION_COLOR, opacity=constants.SELECTION_OPACITY) self.addItem(self.selection_area) def draw_noise_area(self, y, h): x = self.sceneRect().x() w = self.sceneRect().width() if self.ones_area is not None: self.ones_area.hide() if self.zeros_area is not None: self.zeros_area.hide() if self.noise_area is None or self.noise_area.scene() != self: roi = ROI(x, y, w, h, fillcolor=constants.NOISE_COLOR, opacity=constants.NOISE_OPACITY) # roi.setPen(QPen(constants.NOISE_COLOR, Qt.FlatCap)) self.noise_area = roi self.addItem(self.noise_area) else: self.noise_area.show() self.noise_area.setY(y) self.noise_area.height = h def draw_sep_area(self, y_mid): x = self.sceneRect().x() y = self.sceneRect().y() h = self.sceneRect().height() w = self.sceneRect().width() if self.noise_area is not None: self.noise_area.hide() if self.ones_area is None: self.ones_area = QGraphicsRectItem(x, y, w, h / 2 + y_mid) self.ones_area.setBrush(constants.ONES_AREA_COLOR) self.ones_area.setOpacity(constants.SEPARATION_OPACITY) self.ones_area.setPen(QPen(constants.TRANSPARENT_COLOR, Qt.FlatCap)) self.addItem(self.ones_area) else: self.ones_area.show() self.ones_area.setRect(x, y, w, h / 2 + y_mid) start = y + h / 2 + y_mid if self.zeros_area is None: self.zeros_area = QGraphicsRectItem(x, start, w, (y + h) - start) self.zeros_area.setBrush(constants.ZEROS_AREA_COLOR) self.zeros_area.setOpacity(constants.SEPARATION_OPACITY) self.zeros_area.setPen(QPen(constants.TRANSPARENT_COLOR, Qt.FlatCap)) self.addItem(self.zeros_area) else: self.zeros_area.show() self.zeros_area.setRect(x, start, w, (y + h) - start) def clear(self): self.noise_area = None self.ones_area = None self.zeros_area = None self.zeros_arrow = None self.ones_arrow = None self.selection_area = None super().clear() def dragEnterEvent(self, event: QGraphicsSceneDragDropEvent): event.accept() def dragMoveEvent(self, event: QGraphicsSceneDragDropEvent): event.accept()