def __init__(self, text='', width=0, font=None, img=None, max_height=100, align=Qt.AlignmentFlag.AlignCenter): self.layouts = [] self._position = Point(0, 0) self.leading = self.line_spacing = 0 if font is not None: fm = QFontMetrics(font, img) self.leading = fm.leading() self.line_spacing = fm.lineSpacing() for text in text.split('<br>') if text else (): text, formats = parse_text_formatting(sanitize(text)) l = QTextLayout(unescape_formatting(text), font, img) l.setAdditionalFormats(formats) to = QTextOption(align) to.setWrapMode(QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere) l.setTextOption(to) l.beginLayout() height = 0 while height + 3*self.leading < max_height: line = l.createLine() if not line.isValid(): break line.setLineWidth(width) height += self.leading line.setPosition(QPointF(0, height)) height += line.height() max_height -= height l.endLayout() if self.layouts: self.layouts.append(self.leading) else: self._position = Point(l.position().x(), l.position().y()) self.layouts.append(l) if self.layouts: self.layouts.append(self.leading)
class LayoutItem(QWidget): def __init__(self, button, parent=None): QWidget.__init__(self, parent) self.mouse_over = False self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.button = button self.text = button.label self.setCursor(Qt.CursorShape.PointingHandCursor) self.fm = QFontMetrics(self.font()) self._bi = self._di = None @property def bright_icon(self): if self._bi is None: self._bi = self.button.icon().pixmap(ICON_SZ, ICON_SZ) return self._bi @property def dull_icon(self): if self._di is None: self._di = self.button.icon().pixmap(ICON_SZ, ICON_SZ, mode=QIcon.Mode.Disabled) return self._di def event(self, ev): m = None et = ev.type() if et == QEvent.Type.Enter: m = True elif et == QEvent.Type.Leave: m = False if m is not None and m != self.mouse_over: self.mouse_over = m self.update() return QWidget.event(self, ev) def sizeHint(self): br = self.fm.boundingRect(self.text) w = max(br.width(), ICON_SZ) + 10 h = 2 * self.fm.lineSpacing() + ICON_SZ + 8 return QSize(w, h) def paintEvent(self, ev): shown = self.button.isChecked() ls = self.fm.lineSpacing() painter = QStylePainter(self) if self.mouse_over: tool = QStyleOption() tool.initFrom(self) tool.rect = self.rect() tool.state = QStyle.StateFlag.State_Raised | QStyle.StateFlag.State_Active | QStyle.StateFlag.State_MouseOver painter.drawPrimitive(QStyle.PrimitiveElement.PE_PanelButtonTool, tool) painter.drawText( 0, 0, self.width(), ls, Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextSingleLine, self.text) text = _('Hide') if shown else _('Show') f = self.font() f.setBold(True) painter.setFont(f) painter.drawText( 0, self.height() - ls, self.width(), ls, Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextSingleLine, text) x = (self.width() - ICON_SZ) // 2 y = ls + (self.height() - ICON_SZ - 2 * ls) // 2 pmap = self.bright_icon if shown else self.dull_icon painter.drawPixmap(x, y, pmap) painter.end()