def __paint_title_background(self, painter: "QPainter"): """Paints a little background behind the title text, at the top of the node.""" title_rect = self.__graphics_title.boundingRect() path_title_background = QPainterPath() path_title_background.setFillRule(Qt.WindingFill) path_title_background.addRoundedRect( 0, 0, self.background_paint_area().width(), title_rect.height(), self.round_edge_size, self.round_edge_size, ) # (Drawing rects to hide the two botton round edges) path_title_background.addRect( 0, title_rect.height() - self.round_edge_size, self.round_edge_size, self.round_edge_size, ) path_title_background.addRect( self.background_paint_area().width() - self.round_edge_size, title_rect.height() - self.round_edge_size, self.round_edge_size, self.round_edge_size, ) painter.setPen(Qt.NoPen) painter.setBrush(self.__title_background_brush) painter.drawPath(path_title_background.simplified())
def paint(self, painter, *args, **kwargs): margin = QMarginsF(3, 0, 3, 0) box = self.boundingRect().marginsAdded(margin) path = QPainterPath() path.addRoundedRect(box, 5, 5) painter.fillPath(path, QColor(*self.background_color)) super().paint(painter, *args, **kwargs)
def paintEvent(self, event): super(BubbleLabel, self).paintEvent(event) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿 rectPath = QPainterPath() # 圆角矩形 triPath = QPainterPath() # 底部三角形 height = self.height() - 8 # 往上偏移8 rectPath.addRoundedRect(QRectF(0, 0, self.width(), height), 5, 5) x = self.width() / 5 * 4 triPath.moveTo(x, height) # 移动到底部横线4/5处 # 画三角形 triPath.lineTo(x + 6, height + 8) triPath.lineTo(x + 12, height) rectPath.addPath(triPath) # 添加三角形到之前的矩形上 # 边框画笔 painter.setPen(QPen(self.BorderColor, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) # 背景画刷 painter.setBrush(self.BackgroundColor) # 绘制形状 painter.drawPath(rectPath) # 三角形底边绘制一条线保证颜色与背景一样 painter.setPen(QPen(self.BackgroundColor, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(x, height, x + 12, height)
def group_object_pixmap(self, object_class_name): if object_class_name in self.group_obj_pixmap_cache: return self.group_obj_pixmap_cache[object_class_name] object_pixmap = self.object_pixmap(object_class_name) size = object_pixmap.size() width, height = size.width(), size.height() radius = width / 8 pen_width = width / 32 margin = width / 16 pen = QPen(QApplication.palette().shadow().color()) pen.setWidth(pen_width) path = QPainterPath() path.addRoundedRect(0, 0, width, height, radius, radius) pixmap = QPixmap(size) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing, True) painter.fillPath(path, QApplication.palette().window()) painter.setPen(pen) painter.drawRoundedRect(pixmap.rect().adjusted(pen_width, pen_width, -pen_width, -pen_width), radius, radius) painter.drawPixmap( pixmap.rect().adjusted(margin, margin, -width / 2, -height / 2), object_pixmap, object_pixmap.rect() ) painter.drawPixmap( pixmap.rect().adjusted(width / 2, margin, -margin, -height / 2), object_pixmap, object_pixmap.rect() ) painter.drawPixmap( pixmap.rect().adjusted(width / 2, height / 2, -margin, -margin), object_pixmap, object_pixmap.rect() ) painter.drawPixmap( pixmap.rect().adjusted(margin, height / 2, -width / 2, -margin), object_pixmap, object_pixmap.rect() ) painter.end() self.group_obj_pixmap_cache[object_class_name] = pixmap return pixmap
def paint(self, painter, option, widget): path = QPainterPath() path.addRoundedRect(self.rect, 5, 5) painter.setBrush(QColor(255, 255, 255)) painter.drawPath(path) painter.drawText(self.text_rect, self.text)
def paint(self, painter, option, widget): path = QPainterPath() path.addRoundedRect(self.rect, 5, 5) anchor = self.mapFromParent(self.chart.mapToPosition(self.anchor)) if not self.rect.contains(anchor): point1 = QPointF() point2 = QPointF() # establish the position of the anchor point in relation to m_rect above = anchor.y() <= self.rect.top() aboveCenter = anchor.y() > self.rect.top() and anchor.y( ) <= self.rect.center().y() belowCenter = anchor.y() > self.rect.center().y() and anchor.y( ) <= self.rect.bottom() below = anchor.y() > self.rect.bottom() onLeft = anchor.x() <= self.rect.left() leftOfCenter = anchor.x() > self.rect.left() and anchor.x( ) <= self.rect.center().x() rightOfCenter = anchor.x() > self.rect.center().x() and anchor.x( ) <= self.rect.right() onRight = anchor.x() > self.rect.right() # get the nearest m_rect corner x = (onRight + rightOfCenter) * self.rect.width() y = (below + belowCenter) * self.rect.height() cornerCase = (above and onLeft) or (above and onRight) or ( below and onLeft) or (below and onRight) vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y) x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * ( not vertical) * (onLeft * 10 - onRight * 20) y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * ( above * 10 - below * 20) x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * ( not vertical) * (onLeft * 20 - onRight * 10) y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * ( above * 20 - below * 10) point1.setX(x1) point1.setY(y1) point2.setX(x2) point2.setY(y2) path.moveTo(point1) path.lineTo(anchor) path.lineTo(point2) path = path.simplified() painter.setBrush(QColor(255, 255, 255)) painter.drawPath(path) painter.drawText(self.text_rect, self.text)
def shape(self): frame_corner_radius = self.style().pixelMetric( Style.NodeFrameCornerRadius) path = QPainterPath() path.addRoundedRect(QRectF(QPointF(0, 0), self.size()), frame_corner_radius, frame_corner_radius) return path
def paint(self, painter, *args, **kwargs): if self.hovered: margin = QMarginsF(7, 5, 7, 5) else: margin = QMarginsF(3, 0, 3, 0) box = self.boundingRect().marginsAdded(margin) path = QPainterPath() path.addRoundedRect(box, 5, 5) painter.fillPath(path, self.background_color) super().paint(painter, *args, **kwargs)
def paint(self, painter, option, widget): path = QPainterPath() path.addRoundedRect(self._rect, 5, 5) anchor = self.mapFromParent(self._chart.mapToPosition(self._anchor)) if not self._rect.contains(anchor) and not self._anchor.isNull(): point1 = QPointF() point2 = QPointF() # establish the position of the anchor point in relation to _rect above = anchor.y() <= self._rect.top() aboveCenter = (anchor.y() > self._rect.top() and anchor.y() <= self._rect.center().y()) belowCenter = (anchor.y() > self._rect.center().y() and anchor.y() <= self._rect.bottom()) below = anchor.y() > self._rect.bottom() onLeft = anchor.x() <= self._rect.left() leftOfCenter = (anchor.x() > self._rect.left() and anchor.x() <= self._rect.center().x()) rightOfCenter = (anchor.x() > self._rect.center().x() and anchor.x() <= self._rect.right()) onRight = anchor.x() > self._rect.right() # get the nearest _rect corner. x = (onRight + rightOfCenter) * self._rect.width() y = (below + belowCenter) * self._rect.height() cornerCase = ((above and onLeft) or (above and onRight) or (below and onLeft) or (below and onRight)) vertical = abs(anchor.x() - x) > abs(anchor.y() - y) x1 = (x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * int(not vertical) * (onLeft * 10 - onRight * 20)) y1 = (y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20)) point1.setX(x1) point1.setY(y1) x2 = (x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * int(not vertical) * (onLeft * 20 - onRight * 10)) y2 = (y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10)) point2.setX(x2) point2.setY(y2) path.moveTo(point1) path.lineTo(anchor) path.lineTo(point2) path = path.simplified() painter.setBrush(QColor(255, 255, 255)) painter.drawPath(path) painter.drawText(self._textRect, self._text)
def __paint_outline(self, painter: "QPainter"): """Paints the outline of the node. Depending on if its selected or not, the color of the outline changes.""" path_outline = QPainterPath() path_outline.addRoundedRect( self.boundingRect(), self.round_edge_size, self.round_edge_size, ) painter.setPen(self.__outline_pen) painter.setBrush(Qt.NoBrush) painter.drawPath(path_outline.simplified())
def __paint_background(self, painter: "QPainter"): """Paints the background of the node. Plain color, no lines.""" path_background = QPainterPath() path_background.addRoundedRect( self.background_paint_area(), self.round_edge_size, self.round_edge_size, ) painter.setPen(Qt.NoPen) painter.setBrush(self.__background_brush) painter.drawPath(path_background.simplified())
def paintEvent(self, event): super(QtBubbleLabel, self).paintEvent(event) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿 rectPath = QPainterPath() # 圆角矩形 height = self.height() - 8 # 往上偏移8 rectPath.addRoundedRect(QRectF(0, 0, self.width(), height), 5, 5) x = self.width() / 5 * 4 # 边框画笔 painter.setPen( QPen(self.BorderColor, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) # 背景画刷 painter.setBrush(self.BackgroundColor) # 绘制形状 painter.drawPath(rectPath)
def styleChange(self): self.prepareGeometryChange() style = self.style() # Size and Frame frame_width = style.pixelMetric(Style.NodeWidth) self._size.setWidth(frame_width) self._body_item.setPen(style.framePen(self.palette())) path = QPainterPath() path.addRoundedRect(QRectF(QPointF(), self.size()), style.pixelMetric(Style.NodeFrameCornerRadius), style.pixelMetric(Style.NodeFrameCornerRadius)) self._body_item.setPath(path) # Title item title_font = style.font(Style.NodeTitleFont) title_metrics = QFontMetricsF(title_font) padding = style.pixelMetric(Style.NodeFrameTextPadding) self._title_item.setFont(title_font) self._title_item.setPos(padding, padding) self._title_item.moveBy(0, title_metrics.capHeight()) self._title_item.setMaximumWidth(frame_width - padding * 2) # Divider item div_margin = style.pixelMetric(Style.NodeDividerTextMargin) div_voffset = padding + title_metrics.capHeight( ) + title_metrics.descent() + div_margin self._divider.setLine(0, div_voffset, frame_width, div_voffset) self._divider.setPen(style.framePen(self.palette())) # Description item self._description_item.setFont(style.font(Style.NodeDescriptionFont)) self._description_item.setPos(padding, div_voffset + div_margin) self._description_item.setFrame( QRectF( QPointF(0, 0), QSizeF( px(frame_width) - padding * 2, (px(self.size().height()) - padding) - (div_voffset + padding))))
def paint(self, painter=QPainter, option=QStyleOptionGraphicsItem, widget=QWidget): corners = 5 body = self.boundingRect() height = body.height() width = body.width() percentage = height / 10 painter.setRenderHint(QPainter.Antialiasing) path = QPainterPath() path.addRoundedRect(body, corners, corners) pen = QPen(QColor(255, 255, 255, 100), 3) if self.hover and not self.isPressed else QPen( Qt.black, 0.1) pen.setJoinStyle(Qt.RoundJoin) pen.setCosmetic(True) painter.setPen(pen) painter.fillPath(path, self._model["bgColor"]) painter.drawPath(path) if not self.isPressed: grad = QLinearGradient(0, height, 0, height - percentage) grad.setColorAt(0, QColor(175, 175, 175, 255)) grad.setColorAt(1, QColor(175, 175, 175, 0)) path = QPainterPath() path.addRoundedRect(body, corners, corners) painter.setCompositionMode(QPainter.CompositionMode_Multiply) painter.setPen(Qt.NoPen) painter.fillPath(path, grad) painter.drawPath(path) grad = QLinearGradient(0, percentage, 0, 0) grad.setColorAt(1, QColor(255, 255, 255, 255)) grad.setColorAt(0, QColor(255, 255, 255, 0)) path = QPainterPath() path.addRoundedRect(body, corners, corners) painter.setCompositionMode(QPainter.CompositionMode_Overlay) painter.setPen(Qt.NoPen) painter.fillPath(path, grad) painter.drawPath(path) painter.setCompositionMode(QPainter.CompositionMode_Source) else: path = QPainterPath() path.addRoundedRect(body, corners, corners) painter.setCompositionMode(QPainter.CompositionMode_Overlay) painter.setPen(Qt.NoPen) painter.fillPath(path, QColor(255, 255, 255)) painter.drawPath(path) painter.setCompositionMode(QPainter.CompositionMode_Source) super(ButtonNode, self).paint(painter, option, widget)
def resizeEvent(self, r: QResizeEvent) -> None: """ Qt Resize Event - does two things: 1) applies rounded corners if window transparency has been disabled 2) ensures resizer widgets and titlebar buttons stay in place TODO: the 'rounded_corner_px' value is harcoded. It relates to in '.TitleTabBar::tab' in widgetstyle/tabwidget_titlebar.py (border-width and border-image QSS attribute). Action: investigate a way so that this value doesn't have to be hard-coded. """ # if transparency is turned off, set a mask for some basic rounded corners: if not self.__transparent_window and self.__style.window.WINDOW_CORNER_RADIUS_PX > 0: path = QPainterPath() path.addRoundedRect( QRectF(self.rect()), self.__style.window.WINDOW_CORNER_RADIUS_PX + 1, # add 1 to avoid drawing artifacts self.__style.window.WINDOW_CORNER_RADIUS_PX + 1) reg = QRegion(path.toFillPolygon().toPolygon()) self.setMask(reg) # adjust window button positions if not isinstance(self.__window, QDIALOG_TYPES): self.resizer_bl.adjust_resizers(self.geometry( )) # adjusting one resizer adjusts all other resizers too if self.__window_buttons_position == WINDOW_BUTTONS_RIGHT: self.__move_window_buttons() # if a titlebar tab widget is set, mask it so that the empty area can be used to drag the window if self.__tab_widget is not None: width = 0 tab_bar = self.__tab_widget.tabBar() for i in range(0, tab_bar.count() - 1): # don't count invisible tab at end if tab_bar.isTabVisible(i): width += tab_bar.tabRect(i).width() rounder_corner_px = 8 # TODO # related to hardcoded border-image value in widgetstyle/tabwidget_titlebar.py r = QRect(0, 0, width + rounder_corner_px, self.__titlebar_height) self.__tab_widget.tabBar().setMask(r)
def setupUI(self): currentFilePath = os.path.dirname(__file__) # .uiファイルを読み込み loader = QUiLoader() uiFilePath = os.path.join(currentFilePath, 'kkDisplayVertexColorSeparatelyGUI.ui') self.uiFIle = loader.load(uiFilePath) self.setCentralWidget(self.uiFIle) # scriptJobのparent設定のためにオブジェクト名を設定 self.setObjectName("kkDisplayVertexColorSeparatelyWindow") # ウインドウのタイトルを指定 self.setWindowTitle("kkDisplayVertexColorSeparately") # ウインドウのサイズを指定 self.resize(200, 300) # UI要素にシグナルを追加 self.setSignals() # SelectedNameに選択オブジェクト名を表示 self.uiFIle.lineEdit_SelObj.setText(self.targetObj.name()) # 内蔵のpaintVertexColourツールアイコンをセットする self.uiFIle.btn_PaintTool.setIcon(QIcon(':/paintVertexColour.png')) # フレームレスにする self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) # ウィンドウ自体の角を丸くする path = QPainterPath() path.addRoundedRect(self.rect(), 10, 10) region = QRegion(path.toFillPolygon().toPolygon()) self.setMask(region)
class QBlock(QCachedGraphicsItem): TOP_PADDING = 5 BOTTOM_PADDING = 5 LEFT_PADDING = 10 RIGHT_PADDING = 10 SPACING = 0 AIL_SHOW_CONDITIONAL_JUMP_TARGETS = True SHADOW_OFFSET_X = 0 SHADOW_OFFSET_Y = 0 def __init__(self, workspace, func_addr, disasm_view, disasm, infodock, addr, cfg_nodes, out_branches, scene, parent=None): super().__init__(parent=parent) # initialization self.workspace = workspace self.func_addr = func_addr self.disasm_view = disasm_view self.disasm = disasm self.infodock = infodock self.variable_manager = infodock.variable_manager self.addr = addr self.cfg_nodes = cfg_nodes self.out_branches = out_branches self.scene = scene self._config = Conf self.objects = [] # instructions and labels self._block_item = None # type: QPainterPath self._block_item_obj = None # type: QGraphicsPathItem self.addr_to_insns = {} self.addr_to_labels = {} self.qblock_annotations = {} self._block_code_options: QBlockCodeOptions = QBlockCodeOptions() self._update_block_code_options() self._init_widgets() self._objects_are_hidden = False self._objects_are_temporarily_hidden = False self._create_block_item() self.setAcceptHoverEvents(True) # # Properties # @property def mode(self): raise NotImplementedError @property def width(self): return self.boundingRect().width() @property def height(self): return self.boundingRect().height() # # Public methods # def clear_cache(self): super().clear_cache() for obj in self.objects: obj.clear_cache() def _update_block_code_options(self): self._block_code_options.show_conditional_jump_targets = self.AIL_SHOW_CONDITIONAL_JUMP_TARGETS self._block_code_options.show_variables = self.disasm_view.show_variable self._block_code_options.show_variable_identifiers = self.disasm_view.show_variable_identifier def refresh(self): self._update_block_code_options() for obj in self.objects: obj.refresh() self.layout_widgets() self.recalculate_size() self._create_block_item() self.update() def reload(self): self._init_widgets() self.refresh() def size(self): return self.width, self.height def instruction_position(self, insn_addr): if insn_addr in self.addr_to_insns: insn = self.addr_to_insns[insn_addr] pos = insn.pos() return pos.x(), pos.y() return None # # Initialization # def _create_block_item(self): """ Create the block background and border. """ if self._block_item_obj is not None and self.scene is not None: self.scene.removeItem(self._block_item_obj) self._block_item = None self._block_item_obj = None self._block_item = QPainterPath() self._block_item.addRoundedRect(0, 0, self.width - self.SHADOW_OFFSET_X, self.height - self.SHADOW_OFFSET_Y, self._config.disasm_view_node_rounding, self._config.disasm_view_node_rounding) def _init_ail_block_widgets(self): bn = self.cfg_nodes if bn.addr in self.disasm.kb.labels: label = QBlockLabel(bn.addr, get_label_text(bn.addr, self.disasm.kb), self._config, self.disasm_view, self.workspace, self.infodock, parent=self) self.objects.append(label) self.addr_to_labels[bn.addr] = label # always add the block name as a label and instruction: block_name_label = QBlockLabel(bn.addr, f"loc_{hex(bn.addr)}:", self._config, self.disasm_view, self.workspace, self.infodock, parent=self) self.objects.append(block_name_label) self.addr_to_labels[bn.addr] = block_name_label for stmt in bn.statements: code_obj = QAilObj(stmt, self.workspace, self.infodock, parent=None, options=self._block_code_options) obj = QBlockCode(stmt.ins_addr, code_obj, self._config, self.disasm_view, self.workspace, self.infodock, parent=self) code_obj.parent = obj # Reparent self.objects.append(obj) self.addr_to_insns[bn.addr] = obj def _init_disassembly_block_widgets(self): for obj in get_block_objects(self.disasm, self.cfg_nodes, self.func_addr): if isinstance(obj, Instruction): out_branch = get_out_branches_for_insn(self.out_branches, obj.addr) insn = QInstruction(self.workspace, self.func_addr, self.disasm_view, self.disasm, self.infodock, obj, out_branch, self._config, parent=self) self.objects.append(insn) self.addr_to_insns[obj.addr] = insn elif isinstance(obj, Label): label = QBlockLabel(obj.addr, obj.text, self._config, self.disasm_view, self.workspace, self.infodock, parent=self) self.objects.append(label) self.addr_to_labels[obj.addr] = label elif isinstance(obj, IROp): code_obj = QIROpObj(obj, self.infodock, parent=None) disp_obj = QBlockCode(obj.addr, code_obj, self._config, self.disasm_view, self.workspace, self.infodock, parent=self) code_obj.parent = disp_obj # Reparent self.objects.append(disp_obj) elif isinstance(obj, PhiVariable): if not isinstance(obj.variable, SimRegisterVariable): phivariable = QPhiVariable(self.workspace, self.disasm_view, obj, self._config, parent=self) self.objects.append(phivariable) elif isinstance(obj, Variables): for var in obj.variables: variable = QVariable(self.workspace, self.disasm_view, var, self._config, parent=self) self.objects.append(variable) elif isinstance(obj, FunctionHeader): self.objects.append( QFunctionHeader(self.func_addr, obj.name, obj.prototype, obj.args, self._config, self.disasm_view, self.workspace, self.infodock, parent=self)) def _init_widgets(self): if self.scene is not None: for obj in self.objects: self.scene.removeItem(obj) self.objects.clear() if isinstance(self.disasm, Clinic): self._init_ail_block_widgets() else: self._init_disassembly_block_widgets() self.layout_widgets() def layout_widgets(self): raise NotImplementedError()