class ActionItem(GraphicsItem): def __init__(self, model_item: SimulatorItem, parent=None): super().__init__(model_item=model_item, parent=parent) self.setFlag(QGraphicsTextItem.ItemIsPanel, True) self.text = QGraphicsTextItem(self) self.text.setFont(self.font) def update_flags(self): if self.scene().mode == 0: self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True) def update_position(self, x_pos, y_pos): self.setPos(x_pos, y_pos) start_x = (self.scene().items_width() - self.labels_width()) / 2 self.number.setPos(start_x, 0) start_x += self.number.boundingRect().width() self.text.setPos(start_x, 0) width = self.scene().items_width() self.prepareGeometryChange() self.bounding_rect = QRectF(0, 0, width, self.childrenBoundingRect().height() + 5) def labels_width(self): width = self.number.boundingRect().width() width += self.text.boundingRect().width() return width
def createImage(self, transform): if self.type == DemoTextItem.DYNAMIC_TEXT: return None sx = min(transform.m11(), transform.m22()) sy = max(transform.m22(), sx) textItem = QGraphicsTextItem() textItem.setHtml(self.text) textItem.setTextWidth(self.textWidth) textItem.setFont(self.font) textItem.setDefaultTextColor(self.textColor) textItem.document().setDocumentMargin(2) w = textItem.boundingRect().width() h = textItem.boundingRect().height() image = QImage(int(w * sx), int(h * sy), QImage.Format_ARGB32_Premultiplied) image.fill(QColor(0, 0, 0, 0).rgba()) painter = QPainter(image) painter.scale(sx, sy) style = QStyleOptionGraphicsItem() textItem.paint(painter, style, None) return image
class AnimatedClock(QGraphicsView): def __init__(self, parent=None): QGraphicsView.__init__(self, parent) self.updateSecs = 0.5 # Border self.setLineWidth(0) self.setFrameShape(QtWidgets.QFrame.NoFrame) # Size sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHeightForWidth(True) self.setSizePolicy(sizePolicy) # No scrollbars self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Scene self.scene = QGraphicsScene() self.setScene(self.scene) self.setBackgroundBrush(QColor("black")) # Text of clock self.textItem = QGraphicsTextItem() self.textItem.color = QColor(QColor("black")) self.textItem.setFont(QFont("Segoe UI", 80)) self.textItem.setDefaultTextColor(QColor("white")) self.textItem.setHtml("") self.textItem.setZValue(20) self.scene.addItem(self.textItem) # Start ticking self.start() def sizeHint(self): return QSize(300, 150) def start(self): self.updateTimer = QTimer() self.updateTimer.setInterval(self.updateSecs * 990) self.updateTimer.timeout.connect(self.updateClock) self.updateTimer.start() print("Animated clock - starting") def stop(self): if self.updateTimer != None: self.updateTimer.stop() print("Animated clock - stopping") def updateClock(self): localtime = time.localtime() timeString = time.strftime("%H:%M:%S", localtime) self.textItem.setHtml(timeString) width = self.frameGeometry().width() self.textItem.setFont(QFont("Segoe UI", width / 8)) self.textItem.update() def heightForWidth(self, width): return width * .32 def keyPressEvent(self, event): #QKeyEvent event.ignore()
def showImage(self): (newImg, newImgInfo) = self.loadImage() # return PicItem(Pixmap(QPixmap(newImg)), -1, -1, xFactor, yFactor, newImgInfo) self.scene.clear() imgSz = newImgInfo.imgSize self.setSceneRect(QRectF(0,0,imgSz.width(), imgSz.height())) pixMap = QPixmap.fromImage(newImg) # # pixMap.setWidth(self.width()) pixMapItem = self.scene.addPixmap(pixMap) # pixMapItem.setPos(50,50) # self.fitInView(QRectF(0, 0, self.width(), self.height()), Qt.KeepAspectRatio) # Add caption caption = QGraphicsTextItem() caption.setDefaultTextColor(QColor(255,255,255)) caption.setPos(0, self.height()*0.94) caption.setFont(QFont("Segoe UI", 30)) caption.setTextWidth(self.width()) # caption.setPos(100, 100) # caption.setTextWidth(1500) # if newImgInfo.createDate is not None: # caption.setPlainText(newImgInfo.createDate.format()); # else: # caption.setPlainText("Image is called bananas"); # print("Tags", newImgInfo.tags) # tagStr = "" # for tag in newImgInfo.tags: # if tag != "Duplicate": # tagStr += (", " if len(tagStr) != 0 else "") + tag # if tagStr == "": # tagStr = "NO TAGS" # captionStr = '<h1 style="text-align:center;width:100%">' + tagStr + '</h1>' # if newImgInfo.createDate is not None: # print(newImgInfo.createDate.format()) # captionStr += '<BR><h2>' + newImgInfo.createDate.format() + '</h2>' captionStr = "" try: if newImgInfo.rating is not None: for i in range(newImgInfo.rating): captionStr += "★" for i in range(5-newImgInfo.rating): captionStr += "☆" if newImgInfo.mainDate is not None: if len(captionStr) != 0: captionStr += " " captionStr += newImgInfo.mainDate.strftime("%d %b %Y") except Exception as excp: print("StaticPhotos: Cannot set caption") captionStr = '<div style="background-color:#000000;text-align: right;padding-right:10dp;">' + captionStr + "</div>" print(captionStr) caption.setHtml(captionStr) self.scene.addItem(caption) self.scene.update()
class ParticipantItem(QGraphicsItem): def __init__(self, model_item: Participant, parent=None): super().__init__(parent) self.model_item = model_item self.text = QGraphicsTextItem(self) self.line = QGraphicsLineItem(self) self.line.setPen(QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin)) self.refresh() def update_position(self, x_pos=-1, y_pos=-1): if x_pos == -1: x_pos = self.x_pos() if y_pos == -1: y_pos = self.line.line().y2() self.text.setPos(x_pos - (self.text.boundingRect().width() / 2), 0) self.line.setLine(x_pos, 30, x_pos, y_pos) def x_pos(self): return self.line.line().x1() def width(self): return self.boundingRect().width() def refresh(self): self.text.setPlainText("?" if not self.model_item else self.model_item.shortname) if hasattr(self.model_item, "simulate") and self.model_item.simulate: font = QFont() font.setBold(True) self.text.setFont(font) self.text.setDefaultTextColor(Qt.darkGreen) self.line.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) else: self.text.setFont(QFont()) self.text.setDefaultTextColor(constants.LINECOLOR) self.line.setPen(QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin)) def boundingRect(self): return self.childrenBoundingRect() def paint(self, painter, option, widget): pass
class AnimatedClock(): updateTimer = None calDataLock = threading.Lock() calDataUpdated = False curCalendars = None def __init__(self, scene, widthClkTextArea, heightClkTextArea, borders, updateSecs): self.masterScene = scene self.widthClkTextArea = widthClkTextArea self.heightClkTextArea = heightClkTextArea self.borders = borders self.updateSecs = updateSecs # Background self.textBkgd = QGraphicsRectItem(0, 0, self.widthClkTextArea, self.heightClkTextArea) self.textBkgd.setPos(self.borders[3], self.borders[0]) self.textBkgd.setBrush(QColor("light green")) self.textBkgd.setZValue(10) scene.addItem(self.textBkgd) # Text Item self.textItem = QGraphicsTextItem() self.textItem.setFont(QFont("Segoe UI", 80)) self.textItem.setDefaultTextColor(QColor("black")) self.textItem.setPos(QPointF(self.borders[3]+10,self.borders[0]+5)) self.textItem.setHtml("<B>Clock</B>") self.textItem.setZValue(20) self.textItem.setTextWidth(self.widthClkTextArea-20) scene.addItem(self.textItem) def start(self): self.updateTimer = QTimer() self.updateTimer.setInterval(self.updateSecs * 1000) self.updateTimer.timeout.connect(self.updateClock) self.updateTimer.start() def stop (self): if self.updateTimer != None: self.updateTimer.stop() def updateClock(self): localtime = time.localtime() # dateString = time.strftime("%a %d %b %Y", localtime) timeString = time.strftime("%H:%M:%S", localtime) self.textItem.setHtml(timeString) # self.textItem.setTextWidth(self.widthCalTextArea-20) self.textItem.update()
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 drawAxis(self, data, points): xmin = data['xmin'] xmax = data['xmax'] ymin = data['ymin'] ymax = data['ymax'] xmarg = data['xmarg'] ymarg = data['xmarg'] xscale = data['xscale'] yscale = data['yscale'] scene = self.uiFunctionGraph.scene() scene.addLine(xmarg - 10, ymarg + 10, (xmax - xmin) * xscale + xmarg + 10, ymarg + 10) scene.addLine((xmax - xmin) * xscale + xmarg + 8, ymarg + 8, (xmax - xmin) * xscale + xmarg + 10, ymarg + 10) scene.addLine((xmax - xmin) * xscale + xmarg + 8, ymarg + 13, (xmax - xmin) * xscale + xmarg + 10, ymarg + 11) scene.addLine(xmarg - 10, ymarg + 10, xmarg - 10, (ymax - ymin) * yscale + ymarg - 10) scene.addLine(xmarg - 8, (ymax - ymin) * yscale + ymarg - 9, xmarg - 10, (ymax - ymin) * yscale + ymarg - 11) scene.addLine(xmarg - 12, (ymax - ymin) * yscale + ymarg - 8, xmarg - 10, (ymax - ymin) * yscale + ymarg - 10) y = ymin step = (ymax - ymin) / 4 for i in range(5): scene.addLine(xmarg - 12, (y - ymin) * yscale + ymarg, xmarg - 8, (y - ymin) * yscale + ymarg) text = QGraphicsTextItem() text.setPos(0, (y - ymin) * yscale + ymarg - 7) text.setPlainText('%s' % format(round(y, 3), '.3f')) text.setFont(QFont('Sans', 6)) scene.addItem(text) y += step x = xmin step = (xmax - xmin) / 19 for i in range(20): scene.addLine((x - xmin) * xscale + xmarg, ymarg + 8, (x - xmin) * xscale + xmarg, ymarg + 12) text = QGraphicsTextItem() text.setPos((x - xmin) * xscale + xmarg - 14, ymarg + 10) text.setPlainText('%s' % format(round(x, 3), '.3f')) text.setFont(QFont('Sans', 6)) scene.addItem(text) x += step
def define(self, cells): index = 0 cell_sum = 0 for y in range(self.height): for x in range(self.width): try: required_bridges = int(cells[y][x]) new_island = Island(index, x, y, required_bridges) self.islands.append(new_island) self.grid[y][x] = new_island text_item = QGraphicsTextItem(str(required_bridges)) text_item.setFont(self.font) text_item.setPos(30*x+5, 30*y-2) self.scene.addItem(text_item) cell_sum += required_bridges index += 1 except ValueError: pass if cell_sum % 2 == 0: self.total_required_bridges = int(cell_sum / 2) print("Found {} islands that require a total of {} bridges".format(index, self.total_required_bridges)) else: print("The grid is not valid!")
class Robot(VisualizerGraphicItem): def __init__(self, ID=0, x=0, y=0): super(self.__class__, self).__init__(ID, x, y) self._kind_name = 'robot' self._carries = None self._initial_carries = None self._tasks = [] self._graphics_item = QGraphicsRectItem(self) self._text = QGraphicsTextItem(self) self.setZValue(1.0) def set_position(self, x, y): super(self.__class__, self).set_position(x, y) if self._carries is not None: self._carries.set_position(x, y) def set_starting_position(self, x, y): super(self.__class__, self).set_starting_position(x, y) if self._initial_carries is not None: self._initial_carries.set_starting_position(x, y) def set_carries(self, shelf): if shelf == self._carries: return old = self._carries self._carries = shelf if old != None: old.set_carried(None) if self._carries != None: self._carries.set_carried(self) def set_initial_carries(self, shelf): self._initial_carries = shelf def set_rect(self, rect): scale = config.get('display', 'id_font_scale') bold = config.get('display', 'id_font_bold') self._text.setFont(QFont('', rect.width() * 0.08 * scale)) self._text.setPos(rect.x(), rect.y() + 0.2 * rect.height()) self._text.setDefaultTextColor( QColor(config.get('display', 'id_font_color'))) if self._display_mode == 0: if bold: self._text.setHtml('<b>R(' + str(self._id) + ')</b>') else: self._text.setHtml('R(' + str(self._id) + ')') self._graphics_item.setRect( rect.x() + 0.25 * rect.width(), rect.y() + 0.25 * rect.height(), rect.width() * 0.5, rect.height() * 0.5, ) elif self._display_mode == 1: self._text.setPlainText('') self._graphics_item.setRect(rect.x() + 0.05 * rect.width(), rect.y() + 0.05 * rect.height(), rect.width() * 0.9, rect.height() * 0.9) if self._carries is not None: self._carries.set_rect(rect) def add_task(self, task): if task is None: return if task in self._tasks: return self._tasks.append(task) task.set_robot(self) def parse_init_value(self, name, value): result = super(self.__class__, self).parse_init_value(name, value) if result <= 0: return result if name == 'carries': shelf = self._model.get_item('shelf', value, True, True) self.set_initial_carries(shelf) self.set_carries(shelf) return 0 return 1 def restart(self): super(self.__class__, self).restart() self.set_carries(self._initial_carries) def to_init_str(self): s = super(self.__class__, self).to_init_str() if self._initial_carries is not None: s += ("init(object(robot," + str(self._id) + "),value(carries," + str(self._initial_carries.get_id()) + ")).") return s def do_action(self, time_step): if time_step >= len(self._actions): return 0 #break, if no action is defined if self._actions[time_step] == None: return 0 #break, if no action is defined if self._model is None: return -3 try: action = self._actions[time_step].arguments[0] value = self._actions[time_step].arguments[1] except: return -1 if action.name == 'move': if len(value.arguments) != 2: return -1 try: move_x = value.arguments[0].number move_y = value.arguments[1].number self.set_position(self._position[0] + move_x, self._position[1] + move_y) except: self.set_position(self._position[0], self._position[1]) for task in self._tasks: for checkpoint in task.get_checkpoints(): checkpoint = checkpoint[0] pos = checkpoint.get_position() if pos[0] == self._position[0] and pos[ 1] == self._position[1]: task.visit_checkpoint(checkpoint) break return 1 elif action.name == 'pickup': shelf = self._model.filter_items(item_kind='shelf', position=self._position, return_first=True)[0] if shelf is None: return -2 self.set_carries(shelf) return 2 elif action.name == 'putdown': if self._carries == None: return -2 self.set_carries(None) return 3 elif action.name == 'deliver' and len(value.arguments) > 2: try: order = self._model.filter_items(item_kind='order', ID=value.arguments[0], return_first=True)[0] if order is None: return -2 order.deliver(value.arguments[1], value.arguments[2].number, time_step) except: return -3 return 4 elif action.name == 'deliver' and len(value.arguments) > 1: try: if self._carries is not None: self._carries.remove_product(value.arguments[1], 0) order = self._model.filter_items(item_kind='order', ID=value.arguments[0], return_first=True)[0] if order is None: return -2 order.deliver(value.arguments[1], 0, time_step) except: return -3 return 5 return 0 def undo_action(self, time_step): if time_step >= len(self._actions): return 0 #break, if no action is defined if self._actions[time_step] == None: return 0 #break, if no action is defined if self._model is None: return -3 try: action = self._actions[time_step].arguments[0] value = self._actions[time_step].arguments[1] except: return -1 if action.name == 'move': if len(value.arguments) != 2: return -1 for task in self._tasks: for checkpoint in task.get_checkpoints(): checkpoint = checkpoint[0] pos = checkpoint.get_position() if pos[0] == self._position[0] and pos[ 1] == self._position[1]: task.unvisit_checkpoint(checkpoint) break try: move_x = value.arguments[0].number move_y = value.arguments[1].number self.set_position(self._position[0] - move_x, self._position[1] - move_y) except: self.set_position(self._position[0], self._position[1]) if self._carries is not None: self._carries.set_position(self._position[0], self._position[1]) return 1 elif action.name == 'putdown': shelf = self._model.filter_items(item_kind='shelf', position=self._position, return_first=True)[0] if shelf is None: return -2 self.set_carries(shelf) return 3 elif action.name == 'pickup': if self._carries == None: return -2 self.set_carries(None) return 2 elif action.name == 'deliver' and len(value.arguments) > 2: try: if self._carries is not None: self._carries.remove_product(value.arguments[1], -value.arguments[2].number) order = self._model.filter_items(item_kind='order', ID=value.arguments[0], return_first=True)[0] if order is None: return -2 order.deliver(value.arguments[1], -value.arguments[2].number, time_step) except: return -3 return 4 elif action.name == 'deliver' and len(value.arguments) > 1: try: order = self._model.filter_items(item_kind='order', ID=value.arguments[0], return_first=True)[0] if order is None: return -2 order.deliver(value.arguments[1], 0, time_step) except: return -3 return 5 return 0 def determine_color(self, number, count, pattern=None): color = calculate_color(self._colors[0], self._colors[1], (float)(number) / count) brush = QBrush(color) self._graphics_item.setBrush(brush) def get_rect(self): if self._display_mode == 0: rect = self._graphics_item.rect() width = rect.width() * 2 height = rect.height() * 2 rect.setLeft(rect.x() - 0.25 * width) rect.setTop(rect.y() - 0.25 * height) rect.setWidth(width) rect.setHeight(height) return rect elif self._display_mode == 1: rect = self._graphics_item.rect() width = rect.width() / 0.9 height = rect.height() / 0.9 rect.setLeft(rect.x() - 0.05 * width) rect.setTop(rect.y() - 0.05 * height) rect.setWidth(width) rect.setHeight(height) return rect def get_carries(self): return self._carries def get_initial_carries(self): return self._initial_carries def edit_position_to(self, x, y): if (x, y) == self._position: return item2 = self._model.filter_items(item_kind=self._kind_name, position=(x, y), return_first=True)[0] shelf = self._model.filter_items('shelf', position=self._position, return_first=True)[0] shelf2 = self._model.filter_items('shelf', position=(x, y), return_first=True)[0] if shelf2 is not None and shelf is not None: if shelf.get_carried() is not None or shelf2.get_carried( ) is not None: shelf.set_position(x, y) shelf.set_starting_position(x, y) shelf2.set_position(self._position[0], self._position[1]) shelf2.set_starting_position(self._position, self._position[1]) if item2 is not None: item2.set_position(self._position[0], self._position[1]) item2.set_starting_position(self._position[0], self._position[1]) self.set_position(x, y) self.set_starting_position(x, y)
class OcrArea(QGraphicsRectItem): ## static data resizeBorder = .0 def __init__(self, pos, size, type_, parent = None, scene = None, areaBorder = 2, index = 0, textSize = 50): QGraphicsRectItem.__init__(self, 0, 0, size.width(), size.height(), parent) self.setPos(pos) self.newEvent = IsClicked() self.newEvent.area = self #self.setAcceptedMouseButtons(QtCore.Qt.NoButton) self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsSelectable) ## set index label self.text = QGraphicsTextItem("%d" % index, self) self.setTextSize(textSize) ## TODO: How to create constants for the type? ## (such as constants in Qt) (enum?) self.kind = type_ pen = QPen(self.color, areaBorder, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.setPen(pen) # self.setAcceptsHoverEvents(True) # TODO # self.text.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations) def setIndex(self, idx): self.text.setPlainText(str(idx)) def setTextSize(self, size): font = QFont() font.setPointSizeF(size) self.text.setFont(font) def contextMenuEvent(self, event): menu = QMenu() removeAction = menu.addAction(QA.translate('QOcrWidget', "Remove")) #Action = menu.addAction(self.scene().tr("Remove")) menu.addSeparator() textAction = menu.addAction(QA.translate('QOcrWidget', "Text")) graphicsAction = menu.addAction(QA.translate('QOcrWidget', "Graphics")) ## verification of the type of the selection and ## setting a check box near the type that is in use textAction.setCheckable(True) graphicsAction.setCheckable(True) if self.kind == 1: textAction.setChecked(True) elif self.kind == 2: graphicsAction.setChecked(True) selectedAction = menu.exec_(event.screenPos()) if selectedAction == removeAction: self.scene().removeArea(self) elif selectedAction == textAction: self.kind = 1 elif selectedAction == graphicsAction: self.kind = 2 # when the area is selected the signal "isClicked()" is raised def mousePressEvent(self, event): self.newEvent.isClicked.emit() QGraphicsRectItem.mousePressEvent(self, event) # type property def _setType(self, type_): self.__type = type_ if self.__type == 1: self.color = Qt.darkGreen else: ## TODO: else -> elif ... + else raise exception self.color = Qt.blue self.text.setDefaultTextColor(self.color) pen = self.pen() pen.setColor(self.color) self.setPen(pen) def _type(self): return self.__type kind = property(fget=_type, fset=_setType)
class RuleConditionItem(GraphicsItem): def __init__(self, model_item: SimulatorRuleCondition, parent=None): assert isinstance(model_item, SimulatorRuleCondition) super().__init__(model_item=model_item, parent=parent) font_10_bold = QFont(GraphicsItem.font) font_10_bold.setPointSize(10) font_10_bold.setWeight(QFont.DemiBold) self.number.setFont(font_10_bold) self.text = QGraphicsTextItem(self) self.text.setPlainText(self.model_item.type.value) self.text.setFont(font_10_bold) self.desc = QGraphicsTextItem(self) self.desc.setFont(GraphicsItem.font) def update_flags(self): if self.scene().mode == 0: self.set_flags(is_selectable=True, accept_hover_events=True, accept_drops=True) else: self.set_flags(is_selectable=True, accept_hover_events=True) def labels_width(self): return max( self.number.boundingRect().width() + self.text.boundingRect().width(), self.desc.boundingRect().width()) def refresh(self): if len(self.model_item.condition): if len(self.model_item.condition) > 20: self.desc.setPlainText(self.model_item.condition[:20] + "...") else: self.desc.setPlainText(self.model_item.condition) elif self.model_item.type != ConditionType.ELSE: self.desc.setPlainText("<Condition>") def update_position(self, x_pos, y_pos): self.setPos(x_pos, y_pos) start_y = 0 start_x = ((self.scene().items_width() + 40) - (self.number.boundingRect().width() + self.text.boundingRect().width())) / 2 self.number.setPos(start_x, start_y) start_x += self.number.boundingRect().width() self.text.setPos(start_x, start_y) start_y += round(self.number.boundingRect().height()) start_x = ((self.scene().items_width() + 40) - self.desc.boundingRect().width()) / 2 self.desc.setPos(start_x, start_y) if self.model_item.type != ConditionType.ELSE: start_y += round(self.desc.boundingRect().height()) start_y += 5 for child in self.get_scene_children(): child.update_position(20, start_y) start_y += round(child.boundingRect().height()) width = self.scene().items_width() self.prepareGeometryChange() self.bounding_rect = QRectF(0, 0, width + 40, self.childrenBoundingRect().height() + 5) def update_drop_indicator(self, pos): rect = self.boundingRect() if pos.y() - rect.top() < rect.height() / 3: self.drop_indicator_position = QAbstractItemView.AboveItem elif rect.bottom() - pos.y() < rect.height() / 3: self.drop_indicator_position = QAbstractItemView.BelowItem else: self.drop_indicator_position = QAbstractItemView.OnItem self.update() def paint(self, painter, option, widget): if self.scene().mode == 1: self.setOpacity(1 if self.model_item.logging_active else 0.3) painter.setOpacity(constants.SELECTION_OPACITY) if self.hover_active or self.isSelected(): painter.setBrush(constants.SELECTION_COLOR) elif not self.is_valid(): painter.setBrush(QColor(255, 0, 0, 150)) else: painter.setBrush(QColor.fromRgb(204, 204, 204, 255)) height = self.number.boundingRect().height() if self.model_item.type != ConditionType.ELSE: height += self.desc.boundingRect().height() painter.drawRect(QRectF(0, 0, self.boundingRect().width(), height)) painter.setBrush(Qt.NoBrush) painter.drawRect(self.boundingRect()) if self.drag_over: self.paint_drop_indicator(painter) def paint_drop_indicator(self, painter): painter.setPen(QPen(Qt.darkRed, 2, Qt.SolidLine)) painter.setBrush(Qt.NoBrush) rect = self.boundingRect() if self.drop_indicator_position == QAbstractItemView.AboveItem: painter.drawLine(QLineF(rect.topLeft(), rect.topRight())) elif self.drop_indicator_position == QAbstractItemView.OnItem: painter.drawRect(rect) else: painter.drawLine(QLineF(rect.bottomLeft(), rect.bottomRight()))
class MessageItem(GraphicsItem): def __init__(self, model_item: SimulatorMessage, parent=None): assert isinstance(model_item, SimulatorMessage) super().__init__(model_item=model_item, parent=parent) self.setFlag(QGraphicsItem.ItemIsPanel, True) self.arrow = MessageArrowItem(self) self.repeat_text = QGraphicsTextItem(self) self.repeat_text.setFont(self.font) def update_flags(self): if self.scene().mode == 0: self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True) def width(self): labels = self.labels() width = self.number.boundingRect().width() # width += 5 width += sum([lbl.boundingRect().width() for lbl in labels]) width += 5 * (len(labels) - 1) width += self.repeat_text.boundingRect().width() return width def refresh(self): self.repeat_text.setPlainText("(" + str(self.model_item.repeat) + "x)" if self.model_item.repeat > 1 else "") def labels(self): self.refresh_unlabeled_range_marker() unlabeled_range_items = [uri for uri in self.childItems() if isinstance(uri, UnlabeledRangeItem)] result = [] start = 0 i = 0 message = self.model_item if len(message) and not message.message_type: result.append(unlabeled_range_items[0]) else: for lbl in message.message_type: if lbl.start > start: result.append(unlabeled_range_items[i]) i += 1 result.append(self.scene().model_to_scene(lbl)) start = lbl.end if start < len(message): result.append(unlabeled_range_items[i]) return result def refresh_unlabeled_range_marker(self): msg = self.model_item urm = [item for item in self.childItems() if isinstance(item, UnlabeledRangeItem)] if len(msg): num_unlabeled_ranges = len(msg.message_type.unlabeled_ranges) if msg.message_type and msg.message_type[-1].end >= len(msg): num_unlabeled_ranges -= 1 else: num_unlabeled_ranges = 0 if len(urm) < num_unlabeled_ranges: for i in range(num_unlabeled_ranges - len(urm)): UnlabeledRangeItem(self) else: for i in range(len(urm) - num_unlabeled_ranges): self.scene().removeItem(urm[i]) def update_position(self, x_pos, y_pos): labels = self.labels() self.setPos(QPointF(x_pos, y_pos)) p_source = self.mapFromItem(self.source.line, self.source.line.line().p1()) p_destination = self.mapFromItem(self.destination.line, self.destination.line.line().p1()) arrow_width = abs(p_source.x() - p_destination.x()) start_x = min(p_source.x(), p_destination.x()) start_x += (arrow_width - self.width()) / 2 start_y = 0 self.number.setPos(start_x, start_y) start_x += self.number.boundingRect().width() for label in labels: label.setPos(start_x, start_y) start_x += label.boundingRect().width() + 5 self.repeat_text.setPos(start_x, start_y) if labels: start_y += labels[0].boundingRect().height() + 5 else: start_y += 26 self.arrow.setLine(p_source.x(), start_y, p_destination.x(), start_y) super().update_position(x_pos, y_pos) @property def source(self): return self.scene().participants_dict[self.model_item.participant] @property def destination(self): return self.scene().participants_dict[self.model_item.destination]
class GraphicsItem(QGraphicsObject): def __init__(self, model_item: SimulatorItem, parent=None): super().__init__(parent) self.model_item = model_item self.hover_active = False self.drag_over = False self.bounding_rect = QRectF() self.drop_indicator_position = None self.item_under_mouse = None self.font = util.get_monospace_font() self.font_bold = QFont(self.font) self.font_bold.setWeight(QFont.DemiBold) self.number = QGraphicsTextItem(self) self.number.setFont(self.font_bold) self.setFlag(QGraphicsItem.ItemIgnoresParentOpacity, True) def set_flags(self, is_selectable=False, is_movable=False, accept_hover_events=False, accept_drops=False): self.setFlag(QGraphicsItem.ItemIsSelectable, is_selectable) self.setFlag(QGraphicsItem.ItemIsMovable, is_movable) self.setAcceptHoverEvents(accept_hover_events) self.setAcceptDrops(accept_drops) def update_flags(self): pass def hoverEnterEvent(self, event): self.hover_active = True self.update() def hoverLeaveEvent(self, event): self.hover_active = False self.update() def dragEnterEvent(self, event: QGraphicsSceneDragDropEvent): self.drag_over = True self.update() def dragLeaveEvent(self, event: QGraphicsSceneDragDropEvent): self.drag_over = False self.update() def dropEvent(self, event: QDropEvent): self.drag_over = False self.update() def dragMoveEvent(self, event: QDropEvent): self.update_drop_indicator(event.pos()) def get_scene_children(self): return [ self.scene().model_to_scene(child) for child in self.model_item.children ] def is_selectable(self): return self.flags() & QGraphicsItem.ItemIsSelectable def is_movable(self): return self.flags() & QGraphicsItem.ItemIsMovable def select_all(self): self.setSelected(True) for child in self.get_scene_children(): child.select_all() def next(self): if not self.scene(): return None next_item = self.model_item while next_item is not None: next_item = next_item.next() if (not isinstance(next_item, SimulatorProtocolLabel) and not isinstance(next_item, SimulatorRule)): break return self.scene().model_to_scene(next_item) def prev(self): prev_item = self.model_item while prev_item is not None: prev_item = prev_item.prev() if (not isinstance(prev_item, SimulatorProtocolLabel) and not isinstance(prev_item, SimulatorRule)): break return self.scene().model_to_scene(prev_item) def is_valid(self): return self.model_item.is_valid def update_drop_indicator(self, pos): rect = self.boundingRect() if pos.y() - rect.top() < rect.height() / 2: self.drop_indicator_position = QAbstractItemView.AboveItem else: self.drop_indicator_position = QAbstractItemView.BelowItem self.update() def paint(self, painter, option, widget): if self.scene().mode == 1: self.setOpacity(1 if self.model_item.logging_active else 0.3) if self.hover_active or self.isSelected(): painter.setOpacity(constants.SELECTION_OPACITY) painter.setBrush(constants.SELECTION_COLOR) painter.setPen(QPen(QColor(Qt.transparent), 0)) painter.drawRect(self.boundingRect()) elif not self.is_valid(): painter.setOpacity(constants.SELECTION_OPACITY) painter.setBrush(QColor(255, 0, 0, 150)) painter.setPen(QPen(QColor(Qt.transparent), 0)) painter.drawRect(self.boundingRect()) if self.drag_over: self.paint_drop_indicator(painter) def paint_drop_indicator(self, painter): brush = QBrush(QColor(Qt.darkRed)) pen = QPen(brush, 2, Qt.SolidLine) painter.setPen(pen) rect = self.boundingRect() if self.drop_indicator_position == QAbstractItemView.AboveItem: painter.drawLine(QLineF(rect.topLeft(), rect.topRight())) else: painter.drawLine(QLineF(rect.bottomLeft(), rect.bottomRight())) def update_position(self, x_pos, y_pos): width = self.scene().items_width() self.prepareGeometryChange() self.bounding_rect = QRectF(0, 0, width, self.childrenBoundingRect().height()) def refresh(self): pass def boundingRect(self): return self.bounding_rect def update_numbering(self): self.number.setPlainText(self.model_item.index() + ".") for child in self.get_scene_children(): child.update_numbering() def mouseMoveEvent(self, event): items = [] for item in self.scene().items(event.scenePos()): if isinstance( item, GraphicsItem) and item != self and item.acceptDrops(): items.append(item) item = None if len(items) == 0 else items[0] if self.item_under_mouse and self.item_under_mouse != item: self.item_under_mouse.dragLeaveEvent(None) self.item_under_mouse = None if item: self.item_under_mouse = item self.item_under_mouse.dragEnterEvent(None) elif self.item_under_mouse and self.item_under_mouse == item: self.item_under_mouse.update_drop_indicator( self.mapToItem(self.item_under_mouse, event.pos())) elif item: self.item_under_mouse = item self.item_under_mouse.dragEnterEvent(None) super().mouseMoveEvent(event) def mouseReleaseEvent(self, event): if self.item_under_mouse: self.item_under_mouse.dragLeaveEvent(None) self.item_under_mouse.setSelected(False) drag_nodes = self.scene().get_drag_nodes() ref_item = self.item_under_mouse position = self.item_under_mouse.drop_indicator_position self.scene().move_items(drag_nodes, ref_item, position) self.item_under_mouse = None super().mouseReleaseEvent(event) self.scene().update_view()
class MessageItem(GraphicsItem): def __init__(self, model_item: SimulatorMessage, parent=None): assert isinstance(model_item, SimulatorMessage) super().__init__(model_item=model_item, parent=parent) self.setFlag(QGraphicsItem.ItemIsPanel, True) self.arrow = MessageArrowItem(self) self.repeat_text = QGraphicsTextItem(self) self.repeat_text.setFont(self.font) def update_flags(self): if self.scene().mode == 0: self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True) def width(self): labels = self.labels() width = self.number.boundingRect().width() #width += 5 width += sum([lbl.boundingRect().width() for lbl in labels]) width += 5 * (len(labels) - 1) width += self.repeat_text.boundingRect().width() return width def refresh(self): self.repeat_text.setPlainText( "(" + str(self.model_item.repeat) + "x)" if self.model_item.repeat > 1 else "") def labels(self): self.refresh_unlabeled_range_marker() unlabeled_range_items = [ uri for uri in self.childItems() if isinstance(uri, UnlabeledRangeItem) ] result = [] start = 0 i = 0 message = self.model_item if len(message) and not message.message_type: result.append(unlabeled_range_items[0]) else: for lbl in message.message_type: if lbl.start > start: result.append(unlabeled_range_items[i]) i += 1 result.append(self.scene().model_to_scene(lbl)) start = lbl.end if start < len(message): result.append(unlabeled_range_items[i]) return result def refresh_unlabeled_range_marker(self): msg = self.model_item urm = [ item for item in self.childItems() if isinstance(item, UnlabeledRangeItem) ] if len(msg): num_unlabeled_ranges = len(msg.message_type.unlabeled_ranges) if msg.message_type and msg.message_type[-1].end >= len(msg): num_unlabeled_ranges -= 1 else: num_unlabeled_ranges = 0 if len(urm) < num_unlabeled_ranges: for i in range(num_unlabeled_ranges - len(urm)): UnlabeledRangeItem(self) else: for i in range(len(urm) - num_unlabeled_ranges): self.scene().removeItem(urm[i]) def update_position(self, x_pos, y_pos): labels = self.labels() self.setPos(QPointF(x_pos, y_pos)) p_source = self.mapFromItem(self.source.line, self.source.line.line().p1()) p_destination = self.mapFromItem(self.destination.line, self.destination.line.line().p1()) arrow_width = abs(p_source.x() - p_destination.x()) start_x = min(p_source.x(), p_destination.x()) start_x += (arrow_width - self.width()) / 2 start_y = 0 self.number.setPos(start_x, start_y) start_x += self.number.boundingRect().width() for label in labels: label.setPos(start_x, start_y) start_x += label.boundingRect().width() + 5 self.repeat_text.setPos(start_x, start_y) if labels: start_y += labels[0].boundingRect().height() + 5 else: start_y += 26 self.arrow.setLine(p_source.x(), start_y, p_destination.x(), start_y) super().update_position(x_pos, y_pos) @property def source(self): return self.scene().participants_dict[self.model_item.participant] @property def destination(self): return self.scene().participants_dict[self.model_item.destination]
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 Shelf(VisualizerGraphicItem): def __init__(self, ID=0, x=0, y=0): super(self.__class__, self).__init__(ID, x, y) self._kind_name = 'shelf' self._carried = None self._products = [] self._graphics_item = QGraphicsEllipseItem(self) self._graphics_carried = QGraphicsEllipseItem() self._text = QGraphicsTextItem(self) self.setZValue(2.0) self.update_tooltip() def set_rect(self, rect): if self._carried is not None: rect = self._carried.get_rect() scale = config.get('display', 'id_font_scale') bold = config.get('display', 'id_font_bold') self._text.setFont(QFont('', rect.width() * 0.08 * scale)) self._text.setPos(rect.x(), rect.y() + 0.4 * rect.height()) self._text.setDefaultTextColor( QColor(config.get('display', 'id_font_color'))) if self._display_mode == 0: if bold: self._text.setHtml('<b>S(' + str(self._id) + ')</b>') else: self._text.setHtml('S(' + str(self._id) + ')') self._graphics_item.setRect(rect.x() + 0.25 * rect.width(), rect.y() + 0.25 * rect.height(), rect.width() * 0.5, rect.height() * 0.5) self._graphics_carried.setRect(rect.x() + 0.325 * rect.width(), rect.y() + 0.325 * rect.height(), rect.width() * 0.35, rect.height() * 0.35) elif self._display_mode == 1: self._text.setPlainText('') self._graphics_item.setRect(rect.x() + 0.05 * rect.width(), rect.y() + 0.05 * rect.height(), rect.width() * 0.9, rect.height() * 0.9) self._graphics_carried.setRect(rect.x() + 0.125 * rect.width(), rect.y() + 0.125 * rect.height(), rect.width() * 0.75, rect.height() * 0.75) def set_carried(self, robot): if robot == self._carried: return temp = self._carried self._carried = robot if temp is not None: temp.set_carries(None) if self._carried is not None: self._graphics_carried.setParentItem(self._graphics_item) self._carried.set_carries(self) else: self._graphics_carried.setParentItem(None) def restart(self): super(self.__class__, self).restart() products = [] for product in self._products: products.append((product[0], product[1], 0)) self._products = products def to_init_str(self): s = super(self.__class__, self).to_init_str() for product in self._products: s += ('init(object(product,' + str(product[0]) + '),value(on,(' + str(self._id) + ',' + str(product[1]) + '))).') return s def update_tooltip(self): tooltip = "shelf(" + str(self._id) + ")\nproducts:\n" for product in self._products: tooltip = tooltip + str(product) + "\n" self.setToolTip(tooltip) def find_product(self, product_id): for product in self._products: if str(product_id) == str(product[0]): return product return None def set_product_amount(self, product_id, amount): product = self.find_product(product_id) if product is None: self._products.append((product_id, amount, 0)) else: self._products.remove(product) self._products.append((product_id, amount, product[2])) self.update_tooltip() def add_product(self, product_id, amount): product = self.find_product(product_id) if product is None: if amount == 0: amount = 1 self._products.append((product_id, amount, 0)) else: if amount == 0: self._products.append((product_id, 0, 0)) else: self._products.append((product_id, product[1] + amount, 0)) self._products.remove(product) self.update_tooltip() def remove_product(self, product_id, amount): product = self.find_product(product_id) if product is not None: self._products.append( (product_id, product[1], product[2] + amount)) self._products.remove(product) def delete_product(self, product_id): product = self.find_product(product_id) if product is not None: self._products.remove(product) self.update_tooltip() def determine_color(self, number, count, pattern=None): color = calculate_color(self._colors[0], self._colors[1], (float)(number) / count) brush = QBrush(color) self._graphics_item.setBrush(brush) self._graphics_carried.setBrush(QBrush(self._colors[2])) def get_product_amount(self, product_id): product = self.find_product(product_id) if product is None: return 0 return product[1] - product[2] def get_rect(self): if self._display_mode == 0: rect = self._graphics_item.rect() width = rect.width() * 2 height = rect.height() * 2 rect.setLeft(rect.x() - 0.25 * width) rect.setTop(rect.y() - 0.25 * height) rect.setWidth(width) rect.setHeight(height) return rect elif self._display_mode == 1: rect = self._graphics_item.rect() width = rect.width() / 0.9 height = rect.height() / 0.9 rect.setLeft(rect.x() - 0.05 * width) rect.setTop(rect.y() - 0.05 * height) rect.setWidth(width) rect.setHeight(height) return rect def get_carried(self): return self._carried def iterate_products(self): for product in self._products: yield product def edit_position_to(self, x, y): if (x, y) == self._position: return if self._carried is not None: return item2 = self._model.filter_items(item_kind=self._kind_name, position=(x, y), return_first=True)[0] if item2 is not None: if item2.get_carried() is not None: return item2.set_position(self._position[0], self._position[1]) item2.set_starting_position(self._position[0], self._position[1]) self.set_position(x, y) self.set_starting_position(x, y) def mousePressEvent(self, event): if self._carried is not None: self._carried.mousePressEvent(event) else: super(self.__class__, self).mousePressEvent(event) def mouseMoveEvent(self, event): if self._carried is not None: self._carried.mouseMoveEvent(event) else: super(self.__class__, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): if self._carried is not None: self._carried.mouseReleaseEvent(event) else: super(self.__class__, self).mouseReleaseEvent(event)
class RuleConditionItem(GraphicsItem): def __init__(self, model_item: SimulatorRuleCondition, parent=None): assert isinstance(model_item, SimulatorRuleCondition) super().__init__(model_item=model_item, parent=parent) self.number.setFont(self.font_bold) self.text = QGraphicsTextItem(self) self.text.setPlainText(self.model_item.type.value) self.text.setFont(self.font_bold) self.desc = QGraphicsTextItem(self) self.desc.setFont(self.font) def update_flags(self): if self.scene().mode == 0: self.set_flags(is_selectable=True, accept_hover_events=True, accept_drops=True) else: self.set_flags(is_selectable=True, accept_hover_events=True) def labels_width(self): return max(self.number.boundingRect().width() + self.text.boundingRect().width(), self.desc.boundingRect().width()) def refresh(self): if len(self.model_item.condition): if len(self.model_item.condition) > 20: self.desc.setPlainText(self.model_item.condition[:20] + "...") else: self.desc.setPlainText(self.model_item.condition) elif self.model_item.type != ConditionType.ELSE: self.desc.setPlainText("<Condition>") def update_position(self, x_pos, y_pos): self.setPos(x_pos, y_pos) start_y = 0 start_x = ((self.scene().items_width() + 40) - ( self.number.boundingRect().width() + self.text.boundingRect().width())) / 2 self.number.setPos(start_x, start_y) start_x += self.number.boundingRect().width() self.text.setPos(start_x, start_y) start_y += round(self.number.boundingRect().height()) start_x = ((self.scene().items_width() + 40) - self.desc.boundingRect().width()) / 2 self.desc.setPos(start_x, start_y) if self.model_item.type != ConditionType.ELSE: start_y += round(self.desc.boundingRect().height()) start_y += 5 for child in self.get_scene_children(): child.update_position(20, start_y) start_y += round(child.boundingRect().height()) width = self.scene().items_width() self.prepareGeometryChange() self.bounding_rect = QRectF(0, 0, width + 40, self.childrenBoundingRect().height() + 5) def update_drop_indicator(self, pos): rect = self.boundingRect() if pos.y() - rect.top() < rect.height() / 3: self.drop_indicator_position = QAbstractItemView.AboveItem elif rect.bottom() - pos.y() < rect.height() / 3: self.drop_indicator_position = QAbstractItemView.BelowItem else: self.drop_indicator_position = QAbstractItemView.OnItem self.update() def paint(self, painter, option, widget): if self.scene().mode == 1: self.setOpacity(1 if self.model_item.logging_active else 0.3) painter.setOpacity(constants.SELECTION_OPACITY) if self.hover_active or self.isSelected(): painter.setBrush(constants.SELECTION_COLOR) elif not self.is_valid(): painter.setBrush(QColor(255, 0, 0, 150)) else: painter.setBrush(QColor.fromRgb(204, 204, 204, 255)) height = self.number.boundingRect().height() if self.model_item.type != ConditionType.ELSE: height += self.desc.boundingRect().height() painter.drawRect(QRectF(0, 0, self.boundingRect().width(), height)) painter.setBrush(Qt.NoBrush) painter.drawRect(self.boundingRect()) if self.drag_over: self.paint_drop_indicator(painter) def paint_drop_indicator(self, painter): painter.setPen(QPen(Qt.darkRed, 2, Qt.SolidLine)) painter.setBrush(Qt.NoBrush) rect = self.boundingRect() if self.drop_indicator_position == QAbstractItemView.AboveItem: painter.drawLine(QLineF(rect.topLeft(), rect.topRight())) elif self.drop_indicator_position == QAbstractItemView.OnItem: painter.drawRect(rect) else: painter.drawLine(QLineF(rect.bottomLeft(), rect.bottomRight()))
def __init__(self, radius=200, parent=None, categories=[], loglevel=logging.DEBUG): super(WheelScene, self).__init__(parent) self.logger = logs.build_logger(__name__, loglevel) self.loglevel = loglevel #super(TestWheelScene, self).__init__(parent) families = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] if len(categories) == 0: sector_names = [ "freespin", "bankruptcy", "dogs", "cats", "PC", "OP", "loseturn", "colors", "numbers", "states", "countries", "people" ] else: sector_names = categories self.radius = radius total = 0 set_angle = 0 count1 = 0 colours = [] total = sum(families) for count in range(len(families)): number = [] for count in range(3): number.append(random.randrange(0, 255)) colours.append(QColor(number[0], number[1], number[2])) for i, family in enumerate(families): # Max span is 5760, so we have to calculate corresponding span angle angle = round(float(family * 5760) / total) subangle = round(float((family * 5760) / total / 2)) subangle += 120 # ellipse = QGraphicsEllipseItem(0,0,400,400) ellipse = QGraphicsEllipseItem(0, 0, self.radius * 2, self.radius * 2) #ellipse.setPos(QPointF(0, 0)) # ellipse.setPos(ellipse.boundingRect().center()) #print(ellipse.rect().center()) #ellipse.setTransformOriginPoint(200, 200) # ellipse.setRect(-200,200,400,400) ellipse.setStartAngle(set_angle) ellipse.setSpanAngle(angle) ellipse.setBrush(colours[count1]) # https://stackoverflow.com/questions/3312016/text-in-a-qgraphicsscene text = QGraphicsTextItem() #text.setFont(QFont("Helvetica", 65)) #text.setTextWidth(20) # print("angle=%s, set_angle=%s, sector_name=%s" % (angle, set_angle, sector_names[i])) document = QtGui.QTextDocument() document.setDocumentMargin(0) text.setDocument(document) self.font = QFont() self.default_font_size = 14 self.font.setPointSize(self.default_font_size) self.font.setBold(True) self.font.setFamily("Helvetica") self.font.setCapitalization(True) text.setPlainText(textwrap.fill(sector_names[i], width=1)) text.setFont(self.font) # print("render_piece label=%s, textangle=%s sub_angle=%s, set_angle=%s, angle=%s" % # (sector_names[i], # ((set_angle+subangle)/5760)*360, # subangle, # set_angle, # angle)) #print("textpos=%s" % ellipse.rect().center()) reduction_factor = 0 while text.boundingRect().height() > self.radius - (self.radius * .01): # print("category=%s, real_height=%s, radius=%s" % (sector_names[i], # text.boundingRect().height(), # self.radius)) # print("trying changing reduction factor from %s to %s" % (reduction_factor, # reduction_factor + 1)) reduction_factor += 1 self.font.setPointSize(self.default_font_size - reduction_factor) text.deleteLater() text = None text = QGraphicsTextItem() text.setDocument(document) #text.setFont(QFont("Helvetica", 65- reduction_factor)) text.setPlainText(textwrap.fill(sector_names[i], width=1)) text.setFont(self.font) text.setZValue(2) if sector_names[i] == False: #scrap this part for now until we can figure out how to safely offset titles. # print("ellipse center=%s" % ellipse.rect().center()) hypotenuse = self.radius * .01 degree_subangle = (((set_angle + subangle) / 5760) * 360) degree_subangle += 90 degree_subangle = degree_subangle % 360 doTranslate = True if doTranslate: #math.cos(degree_subangle) = adjacent/hypotenuse x = math.cos(degree_subangle) * hypotenuse y = math.sin(degree_subangle) * hypotenuse extra = True if extra: if degree_subangle > 0. and degree_subangle < 90.: pass elif degree_subangle > 90 and degree_subangle < 180: pass elif degree_subangle > 180 and degree_subangle < 270: pass #y = -y elif degree_subangle > 270: pass target = ellipse.rect().center() target.setX(x + target.x()) target.setY(y + target.y()) # print("target=%s" % target) print( "do_move_text_offset cat=%s, offset=%s degree_subangle=%s, x=%s, y=%s" % (sector_names[i], target, degree_subangle, x, y)) text.setPos(target) else: text.setPos(ellipse.rect().center()) text.setPos(ellipse.rect().center()) self.logger.debug("ellipse rect: %s" % ellipse.rect()) text.setRotation((((set_angle + subangle) / 5760) * 360)) #text.setRotation(30) # set_angle+=1 set_angle += angle count1 += 1 self.addItem(ellipse) self.addItem(text) self.setSceneRect(0, 0, self.radius * 2, self.radius * 2) self.logger.debug("scenesize= %s" % self.sceneRect())
class Checkpoint(VisualizerGraphicItem): def __init__(self, ID=0, x=0, y=0): super(self.__class__, self).__init__(ID, x, y) self._kind_name = 'checkpoint' self._ids = {} self._graphics_item = QGraphicsRectItem(self) self._text = QGraphicsTextItem(self._graphics_item) self._shine = False def set_rect(self, rect): scale = config.get('display', 'id_font_scale') bold = config.get('display', 'id_font_bold') font = QFont('', rect.width() * 0.08 * scale) self._text.setFont(font) self._text.setPos(rect.x(), rect.y() + 0.6 * rect.height()) self._text.setDefaultTextColor( QColor(config.get('display', 'id_font_color'))) if self._display_mode == 0: ss = '' if bold: ss = '<b>' for key in self._ids: count = 0 for ii in self._ids[key]: if count == 0: ss = ss + '(' + key + ': ' + ii[0] else: ss = ss + ', ' + ii[0] count += 1 ss = ss + ')\n' if bold: ss += '</b>' self._text.setHtml(ss) self._graphics_item.setRect(rect.x(), rect.y(), rect.width(), rect.height()) elif self._display_mode == 1: self._text.setPlainText('') self._graphics_item.setRect(rect.x(), rect.y(), rect.width(), rect.height()) def do_action(self, time_step): self._shine = False return def undo_action(self, time_step): self._shine = False return def visit(self): self._shine = True def determine_color(self, number, count, pattern=None): color = None if len(self._ids) == 1: for key in self._ids: color_id = self._ids[key][0][1] + 1 if color_id < len(self._colors): color = self._colors[color_id] if color is None: color = self._colors[0] if self._shine: color = calculate_color(color, QColor(255, 255, 255), 0.4) self._graphics_item.setBrush(QBrush(color)) def parse_init_value(self, name, value): result = super(self.__class__, self).parse_init_value(name, value) if result != 1: return result if name == 'checkpoint' and len(value.arguments) == 3: if str(value.arguments[0]) not in self._ids: self._ids[str(value.arguments[0])] = [] self._ids[str(value.arguments[0])].append( (str(value.arguments[1]), value.arguments[2].number)) return 0 return 1 def get_rect(self): return self._graphics_item.rect()
class painter(QGraphicsView): narrowRatio = int(sys.argv[4]) if len(sys.argv) >= 5 else 1 useBlur = sys.argv[5] != "False" if len(sys.argv) >= 6 else True pixelSize = int(15 / narrowRatio) width = int (480 / narrowRatio) height = int(360 / narrowRatio) fontSize = int(30 / narrowRatio) anchorLineSize = int(100 / narrowRatio) ellipseRadius = int(8 / narrowRatio) textInterval = int(90 / narrowRatio) col = width / pixelSize line = height / pixelSize centerIndex = int(round(((line / 2 - 1) * col) + col / 2)) frameCount = 0 baseZValue = 0 textLineHeight = fontSize + 10 blurRaduis = 50 # Smoother improvement def __init__(self): super(painter, self).__init__() self.setFixedSize(self.width, self.height + self.textLineHeight) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene() self.setScene(self.scene) # center het text item self.centerTextItem = QGraphicsTextItem() self.centerTextItem.setPos(self.width / 4 - self.fontSize, 0) self.centerTextItem.setZValue(self.baseZValue + 1) self.scene.addItem(self.centerTextItem) # center anchor item centerX = self.width / 2 centerY = self.height / 2 self.ellipseItem = QGraphicsEllipseItem( 0, 0, self.ellipseRadius * 2, self.ellipseRadius * 2 ) self.horLineItem = QGraphicsLineItem(0, 0, self.anchorLineSize, 0) self.verLineItem = QGraphicsLineItem(0, 0, 0, self.anchorLineSize) self.ellipseItem.setPos( centerX - self.ellipseRadius, centerY - self.ellipseRadius ) self.horLineItem.setPos(centerX - self.anchorLineSize / 2, centerY) self.verLineItem.setPos(centerX, centerY - self.anchorLineSize / 2) self.ellipseItem.setPen(QColor(Qt.white)) self.horLineItem.setPen(QColor(Qt.white)) self.verLineItem.setPen(QColor(Qt.white)) self.ellipseItem.setZValue(self.baseZValue + 1) self.horLineItem.setZValue(self.baseZValue + 1) self.verLineItem.setZValue(self.baseZValue + 1) self.scene.addItem(self.ellipseItem) self.scene.addItem(self.horLineItem) self.scene.addItem(self.verLineItem) # camera item self.cameraBuffer = QPixmap(self.width, self.height + self.textLineHeight) self.cameraItem = QGraphicsPixmapItem() if self.useBlur: self.gusBlurEffect = QGraphicsBlurEffect() self.gusBlurEffect.setBlurRadius(self.blurRaduis) self.cameraItem.setGraphicsEffect(self.gusBlurEffect) self.cameraItem.setPos(0, 0) self.cameraItem.setZValue(self.baseZValue) self.scene.addItem(self.cameraItem) # het text item self.hetTextBuffer = QPixmap(self.width, self.textLineHeight) self.hetTextItem = QGraphicsPixmapItem() self.hetTextItem.setPos(0, self.height) self.hetTextItem.setZValue(self.baseZValue) self.scene.addItem(self.hetTextItem) def draw(self): if len(hetaData) == 0: return font = QFont() color = QColor() font.setPointSize(self.fontSize) font.setFamily("Microsoft YaHei") font.setLetterSpacing(QFont.AbsoluteSpacing, 0) index = 0 lock.acquire() frame = hetaData.pop(0) lock.release() maxHet = frame["maxHet"] minHet = frame["minHet"] frame = frame["frame"] p = QPainter(self.cameraBuffer) p.fillRect( 0, 0, self.width, self.height + self.textLineHeight, QBrush(QColor(Qt.black)) ) # draw camera color = QColor() for yIndex in range(int(self.height / self.pixelSize)): for xIndex in range(int(self.width / self.pixelSize)): tempData = constrain(mapValue(frame[index], minHet, maxHet, minHue, maxHue), minHue, maxHue) color.setHsvF(tempData / 360, 1.0, 1.0) p.fillRect( xIndex * self.pixelSize, yIndex * self.pixelSize, self.pixelSize, self.pixelSize, QBrush(color) ) index = index + 1 self.cameraItem.setPixmap(self.cameraBuffer) # draw text p = QPainter(self.hetTextBuffer) p.fillRect( 0, 0, self.width, self.height + self.textLineHeight, QBrush(QColor(Qt.black)) ) hetDiff = maxHet - minHet bastNum = round(minHet) interval = round(hetDiff / 5) for i in range(5): hue = constrain(mapValue((bastNum + (i * interval)), minHet, maxHet, minHue, maxHue), minHue, maxHue) color.setHsvF(hue / 360, 1.0, 1.0) p.setPen(color) p.setFont(font) p.drawText(i * self.textInterval, self.fontSize + 3, str(bastNum + (i * interval)) + "°") self.hetTextItem.setPixmap(self.hetTextBuffer) # draw center het text cneter = round(frame[self.centerIndex], 1) off_cneter = float(cneter) - 1.5 centerText = "<font color=white>%s</font>" self.centerTextItem.setFont(font) if off_cneter > 37.5: self.centerTextItem.setHtml(centerText % (str(off_cneter) + "° FEVER")) GPIO.output(rly_grn, GPIO.LOW) GPIO.output(rly_red, GPIO.LOW) elif off_cneter < 37.5: self.centerTextItem.setHtml(centerText % (str(off_cneter) + "° NORMAL")) GPIO.output(rly_grn, GPIO.HIGH) # out GPIO.output(rly_red, GPIO.HIGH) self.frameCount = self.frameCount + 1
class AnimatedCalendar(): updatesRunning = False updateTimer = None listUpdateThread = None calDataLock = threading.Lock() calDataUpdated = False curCalendars = None def __init__(self, scene, widthCalTextArea, heightCalTextArea, borders, calFeeds, calUpdateSecs): self.masterScene = scene self.widthCalTextArea = widthCalTextArea self.heightCalTextArea = heightCalTextArea self.borders = borders self.calFeeds = calFeeds self.calendarUpdateSecs = calUpdateSecs # Background self.textBkgd = QGraphicsRectItem(0, 0, self.widthCalTextArea, self.heightCalTextArea) self.textBkgd.setPos(self.borders[3], self.borders[0]) self.textBkgd.setBrush(QColor("light green")) self.textBkgd.setZValue(10) scene.addItem(self.textBkgd) # Text Item self.textItem = QGraphicsTextItem() self.textItem.setFont(QFont("Segoe UI", 24)) self.textItem.setDefaultTextColor(QColor("black")) self.textItem.setPos(QPointF(self.borders[3]+10,self.borders[0]+10)) self.textItem.setHtml("<B>Hello</B>Hello") self.textItem.setZValue(20) self.textItem.setTextWidth(self.widthCalTextArea-20) scene.addItem(self.textItem) def start(self): self.updatesRunning = True QTimer.singleShot(100, self.updateCalendar) self.listUpdateThread = CalendarUpdateThread(self, self.calFeeds, self.calendarUpdateSecs) self.listUpdateThread.start() # print("CalStarted") def stop (self): self.updatesRunning = False if self.updateTimer != None: self.updateTimer.stop() if self.listUpdateThread != None: self.listUpdateThread.stop() def setNewCalendarEntries(self, calendars): with self.calDataLock: self.curCalendars = calendars self.calDataUpdated = True def updateCalendar(self): # print("Update cal") with self.calDataLock: if self.calDataUpdated and self.curCalendars != None: for calEvents in self.curCalendars: calStr = "" lastDay = -1 for anEvent in calEvents: # date, duration, summary, location, UID eventDate = anEvent[0] duration = anEvent[1] summary = anEvent[2] location = anEvent[3] if lastDay != eventDate.day: if lastDay != -1: calStr += "<br/>" calStr += "<b>" + anEvent[0].strftime("%a") + " (" + anEvent[0].strftime("%d %B)") + ")</b><br/>" lastDay = eventDate.day strDurTime = str(duration).rpartition(":")[0] durStr = (str(duration.days) + "day" + ("s" if duration.days != 1 else "")) if duration.days > 0 else strDurTime locStr = "<small>("+location+")</small>" if location != "" else "" calStr += anEvent[0].strftime("%H:%M") + " <small>(" + durStr + ")</small> " + summary + " " + locStr + "<br/>" # print (anEvent) # print(date) self.textItem.setHtml(calStr) self.textItem.setTextWidth(self.widthCalTextArea-20) self.textItem.update() self.calDataUpdated = False if not self.updatesRunning: return self.updateTimer = QTimer() self.updateTimer.setInterval(5000) self.updateTimer.setSingleShot(True) self.updateTimer.timeout.connect(self.updateCalendar) self.updateTimer.start()
def createGraphics(self): """ Create the graphical representation of the FMU's inputs and outputs """ def variableColor(variable): if variable.type == 'Real': return QColor.fromRgb(0, 0, 127) elif variable.type in ['Integer', 'Enumeration']: return QColor.fromRgb(255, 127, 0) elif variable.type == 'Boolean': return QColor.fromRgb(255, 0, 255) elif variable.type == 'String': return QColor.fromRgb(0, 128, 0) else: return QColor.fromRgb(0, 0, 0) inputVariables = [] outputVariables = [] maxInputLabelWidth = 0 maxOutputLabelWidth = 0 textItem = QGraphicsTextItem() fontMetrics = QFontMetricsF(textItem.font()) for variable in self.modelDescription.modelVariables: if variable.causality == 'input': inputVariables.append(variable) elif variable.causality == 'output': outputVariables.append(variable) for variable in inputVariables: maxInputLabelWidth = max(maxInputLabelWidth, fontMetrics.width(variable.name)) for variable in outputVariables: maxOutputLabelWidth = max(maxOutputLabelWidth, fontMetrics.width(variable.name)) from math import floor scene = QGraphicsScene() self.ui.graphicsView.setScene(scene) group = QGraphicsItemGroup() scene.addItem(group) group.setPos(200.5, -50.5) lh = 15 # line height w = max(150., maxInputLabelWidth + maxOutputLabelWidth + 20) h = max(50., 10 + lh * max(len(inputVariables), len(outputVariables))) block = QGraphicsRectItem(0, 0, w, h, group) block.setPen(QColor.fromRgb(0, 0, 255)) pen = QPen() pen.setWidthF(1) font = QFont() font.setPixelSize(10) # inputs y = floor((h - len(inputVariables) * lh) / 2 - 2) for variable in inputVariables: text = QGraphicsTextItem(variable.name, group) text.setDefaultTextColor(QColor.fromRgb(0, 0, 255)) text.setFont(font) text.setX(3) text.setY(y) polygon = QPolygonF([ QPointF(-13.5, y + 4), QPointF(1, y + 11), QPointF(-13.5, y + 18) ]) path = QPainterPath() path.addPolygon(polygon) path.closeSubpath() contour = QGraphicsPathItem(path, group) contour.setPen(QPen(Qt.NoPen)) contour.setBrush(variableColor(variable)) y += lh # outputs y = floor((h - len(outputVariables) * lh) / 2 - 2) for variable in outputVariables: text = QGraphicsTextItem(variable.name, group) text.setDefaultTextColor(QColor.fromRgb(0, 0, 255)) text.setFont(font) text.setX(w - 3 - text.boundingRect().width()) text.setY(y) polygon = QPolygonF([ QPointF(w, y + 0 + 7.5), QPointF(w + 7, y + 3.5 + 7.5), QPointF(w, y + 7 + 7.5) ]) path = QPainterPath() path.addPolygon(polygon) path.closeSubpath() contour = QGraphicsPathItem(path, group) pen = QPen() pen.setColor(variableColor(variable)) pen.setJoinStyle(Qt.MiterJoin) contour.setPen(pen) y += lh
class Edge(Connection): ''' B-spline/Bezier connection shape ''' def __init__(self, edge, graph): ''' Set generic parameters from Connection class ''' self.text_label = None super(Edge, self).__init__(edge['source'], edge['target']) self.edge = edge self.graph = graph # Set connection points as not visible, by default self.bezier_visible = False # Initialize control point coordinates self.bezier = [self.mapFromScene(*self.edge['spline'][0])] # Bezier control points (groups of three points): assert(len(self.edge['spline']) % 3 == 1) for i in xrange(1, len(self.edge['spline']), 3): self.bezier.append([Controlpoint( self.mapFromScene(*self.edge['spline'][i + j]), self) for j in range(3)]) # Create connection points at start and end of the edge self.source_connection = Connectionpoint( self.start_point or self.bezier[0], self, self.parent) self.parent.movable_points.append(self.source_connection) self.end_connection = Connectionpoint( self.end_point or self.bezier[-1], self, self.child) self.child.movable_points.append(self.end_connection) self.reshape() @property def start_point(self): ''' Compute connection origin - redefine in subclasses ''' # Start point is optional - graphviz decision return self.mapFromScene(*self.edge['start']) \ if self.edge.get('start') else None @property def end_point(self): ''' Compute connection end point - redefine in subclasses ''' return self.mapFromScene(*self.edge['end']) \ if self.edge.get('end') else None def bezier_set_visible(self, visible=True): ''' Display or hide the edge control points ''' self.bezier_visible = visible for group in self.bezier[1:]: for ctrl_point in group: if visible: ctrl_point.show() else: ctrl_point.hide() if visible: self.end_connection.show() self.source_connection.show() else: self.end_connection.hide() self.source_connection.hide() self.update() def mousePressEvent(self, event): ''' On a mouse click, display the control points ''' self.bezier_set_visible(True) # pylint: disable=R0914 def reshape(self): ''' Update the shape of the edge (redefined function) ''' path = QPainterPath() # If there is a starting point, draw a line to the first curve point if self.start_point: path.moveTo(self.source_connection.center) path.lineTo(self.bezier[0]) else: path.moveTo(self.source_connection.center) # Loop over the curve points: for group in self.bezier[1:]: path.cubicTo(*[point.center for point in group]) # If there is an ending point, draw a line to it if self.end_point: path.lineTo(self.end_connection.center) end_point = path.currentPosition() arrowhead = self.angle_arrow(path) path.lineTo(arrowhead[0]) path.moveTo(end_point) path.lineTo(arrowhead[1]) path.moveTo(end_point) try: # Add the transition label, if any (none for the START edge) font = QFont('arial', pointSize=8) metrics = QFontMetrics(font) label = self.edge.get('label', '') lines = label.split('\n') width = metrics.width(max(lines)) # longest line height = metrics.height() * len(lines) # lp is the position of the center of the text pos = self.mapFromScene(*self.edge['lp']) if not self.text_label: self.text_label = QGraphicsTextItem( self.edge.get('label', ''), parent=self) self.text_label.setX(pos.x() - width / 2) self.text_label.setY(pos.y() - height / 2) self.text_label.setFont(font) # Make horizontal center alignment, as dot does self.text_label.setTextWidth(self.text_label.boundingRect().width()) fmt = QTextBlockFormat() fmt.setAlignment(Qt.AlignHCenter) cursor = self.text_label.textCursor() cursor.select(QTextCursor.Document) cursor.mergeBlockFormat(fmt) cursor.clearSelection() self.text_label.setTextCursor(cursor) self.text_label.show() except KeyError: # no label pass self.setPath(path) def __str__(self): ''' user-friendly information about the edge coordinates ''' return('Edge between ' + self.edge['source'].name + ' and ' + self.edge['target'].name + str(self.edge['spline'][0])) def paint(self, painter, option, widget): ''' Apply anti-aliasing to Edge Connections ''' painter.setRenderHint(QPainter.Antialiasing, True) super(Edge, self).paint(painter, option, widget) # Draw lines between connection points, if visible if self.bezier_visible: painter.setPen( QPen(Qt.lightGray, 0, Qt.SolidLine)) painter.setBrush(Qt.NoBrush) points_flat = [point.center for sub1 in self.bezier[1:] for point in sub1] painter.drawPolyline([self.source_connection.center] + points_flat + [self.end_connection.center])
class ItemConfigDialog(QMainWindow, Ui_MainWindow): """ Окно настроек элемента """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) self.text_aligns = [ ('center', 'По центру'), ('left', 'По левому краю'), ('right', 'По правому краю'), ] self.text_align = 'center' for align, align_text in self.text_aligns: self.textPosH.addItem(align_text) self.item: QGraphicsRectItem = QGraphicsRectItem() self.main_view: QGraphicsView = QGraphicsView() self.fontSelect.currentFontChanged.connect(self.render_text) self.fontSize.valueChanged.connect(self.render_text) self.textPosH.currentTextChanged.connect(self.render_text) self.exText.textChanged.connect(self.render_text) self.font_color = QColor('black') self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.text = QGraphicsTextItem() self.buttonBox.accepted.connect(self.accepted) self.colorPicker.clicked.connect(self.select_color) def show(self): super(ItemConfigDialog, self).show() self.text = QGraphicsTextItem() self.name.setText(self.item.toolTip()) font = QFont() font_name = self.item.data(int(const.ITEM_DATA_KEY_FONT)) if font_name: font.fromString(font_name) font_size = self.item.data(int(const.ITEM_DATA_KEY_FONT_SIZE)) if font_size: font.setPointSize(font_size) else: font.setPointSize(12) font_color = self.item.data(int(const.ITEM_DATA_KEY_FONT_COLOR)) if font_color: self.font_color.setRgb(*font_color) self.text.setFont(font) self.text_align = self.item.data(int(const.ITEM_DATA_KEY_FONT_ALIGN)) self.render_text() self.render_item() def select_color(self): color = QColorDialog.getColor() if color.isValid(): self.font_color = color self.render_text() def render_text(self, event=None): font = self.fontSelect.currentFont() font.setPointSize(self.fontSize.value()) self.text.setFont(font) self.text.setTextWidth(self.item.rect().width()) self.text.setDefaultTextColor(self.font_color) for align, align_text in self.text_aligns: if align_text == self.textPosH.currentText(): self.text_align = align self.text.setHtml(f"<div align='{self.text_align}'>{self.exText.text()}</div>") def render_item(self): self.scene.clear() pos_from = self.main_view.mapFromScene(self.item.sceneBoundingRect()) pos = self.main_view.mapToScene(pos_from) point = pos.boundingRect() width, height = point.width(), point.height() img = QImage(width, height, QImage.Format_ARGB32_Premultiplied) painter = QPainter(img) painter.setRenderHint(QPainter.Antialiasing) self.item.scene().render(painter, source=QRectF(point.x(), point.y(), width, height)) painter.end() self.scene.addItem(QGraphicsPixmapItem(QPixmap(img))) self.scene.addItem(self.text) self.graphicsView.fitInView(QRectF(0, 0, width, height), Qt.KeepAspectRatio) self.scene.update() def accepted(self): self.item.setData(int(const.ITEM_DATA_KEY_FONT), self.text.font().toString().split(',')[0]) self.item.setData(int(const.ITEM_DATA_KEY_FONT_SIZE), self.text.font().pointSize()) self.item.setData(int(const.ITEM_DATA_KEY_FONT_ALIGN), self.text_align) self.item.setData(int(const.ITEM_DATA_KEY_FONT_COLOR), self.font_color.getRgb()) self.item.setToolTip(self.name.text()) self.item.scene().update() self.close()