import math from PyQt6.QtCore import QEvent, QPointF, QRectF, QSize, Qt, QTimer, pyqtSignal from PyQt6.QtGui import QColor, QPainter, QPolygonF from PyQt6.QtWidgets import ( QAbstractButton, QFrame, QGridLayout, QHBoxLayout, QLabel, QPushButton, QScrollArea, QSizePolicy, QVBoxLayout, QWidget, ) def cimke(szoveg, nev=None, tordel=False): c = QLabel(szoveg) if nev: c.setObjectName(nev) c.setWordWrap(tordel) return c def gomb(szoveg, fo=False, kicsi=False): g = QPushButton(szoveg) g.setCursor(Qt.CursorShape.PointingHandCursor) if fo: g.setProperty("fo", True) if kicsi: g.setProperty("kicsi", True) return g def frissit_stilus(widget): widget.style().unpolish(widget) widget.style().polish(widget) class Kartya(QFrame): def __init__(self, cim=None, terkoz=10, margo=20): super().__init__() self.setObjectName("kartya") self.elrendezes = QVBoxLayout(self) self.elrendezes.setContentsMargins(margo, margo, margo, margo) self.elrendezes.setSpacing(terkoz) if cim: self.elrendezes.addWidget(cimke(cim.upper(), "kartyacim")) class Racs(QWidget): def __init__(self, min_szelesseg, terkoz=16): super().__init__() self.min_szelesseg = min_szelesseg self.elemek = [] self.rejtett = set() self.oszlopok = 0 self.racs = QGridLayout(self) self.racs.setContentsMargins(0, 0, 0, 0) self.racs.setSpacing(terkoz) def hozzaad(self, widget): self.elemek.append(widget) self._rendez(force=True) def resizeEvent(self, esemeny): super().resizeEvent(esemeny) self._rendez() def szur(self, lathatok): self.rejtett = {w for w in self.elemek if w not in lathatok} for w in self.elemek: w.setVisible(w not in self.rejtett) self._rendez(force=True) def _rendez(self, force=False): terkoz = self.racs.spacing() lathatok = [w for w in self.elemek if w not in self.rejtett] oszlopok = max(1, (self.width() + terkoz) // (self.min_szelesseg + terkoz)) if self.min_szelesseg < 260: oszlopok = min(oszlopok, max(1, len(lathatok))) if oszlopok == self.oszlopok and not force: return self.oszlopok = oszlopok for w in self.elemek: self.racs.removeWidget(w) for i, w in enumerate(lathatok): self.racs.addWidget(w, i // oszlopok, i % oszlopok) self.updateGeometry() oldal = self.parent() while oldal is not None and not isinstance(oldal, Oldal): oldal = oldal.parent() if oldal is not None and oldal.kitolt: QTimer.singleShot(0, oldal._igazit) for o in range(self.racs.columnCount()): self.racs.setColumnStretch(o, 1 if o < oszlopok else 0) class _KitoltoTartalom(QWidget): def sizeHint(self): return self.minimumSizeHint() def heightForWidth(self, szelesseg): elrendezes = self.layout() if elrendezes and elrendezes.hasHeightForWidth(): return elrendezes.minimumHeightForWidth(szelesseg) return self.minimumSizeHint().height() class Oldal(QScrollArea): def __init__(self, kozpont, eyebrow, cim, kitolt=False): super().__init__() self.kozpont = kozpont self.setWidgetResizable(True) self.setFrameShape(QFrame.Shape.NoFrame) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.kitolt = kitolt tartalom = _KitoltoTartalom() if kitolt else QWidget() self.setWidget(tartalom) if kitolt: tartalom.installEventFilter(self) self.torzs = QVBoxLayout(tartalom) self.torzs.setContentsMargins(48, 40, 48, 40) self.torzs.setSpacing(32) fejlec = QHBoxLayout() fejlec.setSpacing(16) cimsor = QVBoxLayout() cimsor.setSpacing(6) self.eyebrow = cimke(eyebrow, "eyebrow") self.cim = cimke(cim.upper(), "h1") cimsor.addWidget(self.eyebrow) cimsor.addWidget(self.cim) fejlec.addLayout(cimsor) fejlec.addStretch(1) self.gombsor = QHBoxLayout() self.gombsor.setSpacing(8) fejlec.addLayout(self.gombsor) fejlec.setAlignment(self.gombsor, Qt.AlignmentFlag.AlignBottom) self.torzs.addLayout(fejlec) def eventFilter(self, objektum, esemeny): if self.kitolt and objektum is self.widget() and esemeny.type() == QEvent.Type.LayoutRequest: QTimer.singleShot(0, self._igazit) return super().eventFilter(objektum, esemeny) def resizeEvent(self, esemeny): super().resizeEvent(esemeny) if self.kitolt: self._igazit() def _igazit(self): tartalom = self.widget() nezet = self.viewport() magassag = max(nezet.height(), tartalom.heightForWidth(nezet.width())) if tartalom.height() != magassag or tartalom.width() != nezet.width(): tartalom.resize(nezet.width(), magassag) def fejlec_gomb(self, gomb_widget): self.gombsor.addWidget(gomb_widget) return gomb_widget def megjelenik(self, *_): pass def indulaskor(self): pass def elerheto(self, *_): return True class Fulsor(QWidget): def __init__(self, fulek, valtas): super().__init__() self.setObjectName("fulsor") self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) sor = QHBoxLayout(self) sor.setContentsMargins(0, 0, 0, 0) sor.setSpacing(0) self.gombok = {} for azon, szoveg in fulek: g = QPushButton(szoveg) g.setObjectName("ful") g.setCursor(Qt.CursorShape.PointingHandCursor) g.clicked.connect(lambda _=False, a=azon: valtas(a)) self.gombok[azon] = g sor.addWidget(g) sor.addStretch(1) def aktiv(self, azon): for a, g in self.gombok.items(): g.setProperty("aktiv", a == azon) frissit_stilus(g) class Verem(QWidget): currentChanged = pyqtSignal(int) def __init__(self): super().__init__() self._lapok = [] self._aktualis = -1 self._elrendezes = QVBoxLayout(self) self._elrendezes.setContentsMargins(0, 0, 0, 0) self._elrendezes.setSpacing(0) def addWidget(self, widget): self._lapok.append(widget) self._elrendezes.addWidget(widget) if self._aktualis < 0: self.setCurrentIndex(0) else: widget.hide() return len(self._lapok) - 1 def count(self): return len(self._lapok) def widget(self, index): return self._lapok[index] if 0 <= index < len(self._lapok) else None def indexOf(self, widget): return self._lapok.index(widget) if widget in self._lapok else -1 def currentIndex(self): return self._aktualis def currentWidget(self): return self.widget(self._aktualis) def setCurrentIndex(self, index): if not 0 <= index < len(self._lapok): return for i, lap in enumerate(self._lapok): lap.setVisible(i == index) valtozott = index != self._aktualis self._aktualis = index self.updateGeometry() if valtozott: self.currentChanged.emit(index) def setCurrentWidget(self, widget): self.setCurrentIndex(self.indexOf(widget)) class Kapcsolo(QAbstractButton): def __init__(self): super().__init__() self.setCheckable(True) self.setCursor(Qt.CursorShape.PointingHandCursor) self.setFixedSize(QSize(44, 24)) self.setAccessibleName("kapcsoló") def sizeHint(self): return QSize(44, 24) def paintEvent(self, _): from raveos_center import stilus festo = QPainter(self) festo.setRenderHint(QPainter.RenderHint.Antialiasing, False) be = self.isChecked() aktiv = self.isEnabled() palya = QColor(stilus.ZOLD if be else stilus.AKTIV) keret = QColor(stilus.ZOLD if be else stilus.KERET_EROS) if not aktiv: palya = QColor(stilus.KERET if not be else "#3d5a36") keret = palya festo.setPen(keret) festo.setBrush(palya) festo.drawRect(QRectF(0.5, 0.5, self.width() - 1, self.height() - 1)) gomb_meret = self.height() - 8 x = self.width() - gomb_meret - 4 if be else 4 festo.setPen(Qt.PenStyle.NoPen) festo.setBrush(QColor(stilus.ZOLDON_SZOVEG if be else stilus.SZOVEG_HALVANY)) festo.drawRect(QRectF(x, 4, gomb_meret, gomb_meret)) festo.end() class Csillagok(QWidget): valasztva = pyqtSignal(int) TERKOZ = 6 LEPESEK = {Qt.Key.Key_Right: 1, Qt.Key.Key_Up: 1, Qt.Key.Key_Left: -1, Qt.Key.Key_Down: -1} SZAMOK = {Qt.Key.Key_1: 1, Qt.Key.Key_2: 2, Qt.Key.Key_3: 3, Qt.Key.Key_4: 4, Qt.Key.Key_5: 5} def __init__(self, meret=22, valaszthato=False): super().__init__() self.meret = meret self.ertek = 0.0 self.mutatott = 0 self.valaszthato = valaszthato self.setFixedSize(self.sizeHint()) self.setAccessibleName("csillagos értékelés") if valaszthato: self.setMouseTracking(True) self.setCursor(Qt.CursorShape.PointingHandCursor) self.setFocusPolicy(Qt.FocusPolicy.StrongFocus) def sizeHint(self): return QSize(self.meret * 5 + self.TERKOZ * 4, self.meret) def beallit(self, ertek): self.ertek = max(0.0, min(5.0, float(ertek))) self.setToolTip(f"{self.ertek:.1f} / 5" if not self.valaszthato else "") self.update() def _index(self, pont): return max(1, min(5, int(pont.x() // (self.meret + self.TERKOZ)) + 1)) def _valaszt(self, ertek): self.beallit(ertek) self.valasztva.emit(int(ertek)) def mouseMoveEvent(self, esemeny): if self.valaszthato and self.isEnabled(): self.mutatott = self._index(esemeny.position()) self.update() def leaveEvent(self, esemeny): self.mutatott = 0 self.update() super().leaveEvent(esemeny) def mouseReleaseEvent(self, esemeny): if self.valaszthato and esemeny.button() == Qt.MouseButton.LeftButton and self.rect().contains( esemeny.position().toPoint() ): self._valaszt(self._index(esemeny.position())) super().mouseReleaseEvent(esemeny) def keyPressEvent(self, esemeny): if not self.valaszthato: return super().keyPressEvent(esemeny) try: kulcs = Qt.Key(esemeny.key()) except ValueError: kulcs = None if kulcs in self.LEPESEK: self._valaszt(max(1, min(5, int(self.ertek) + self.LEPESEK[kulcs]))) elif kulcs in self.SZAMOK: self._valaszt(self.SZAMOK[kulcs]) else: super().keyPressEvent(esemeny) def _sokszog(self, bal): r = self.meret / 2 kozep = QPointF(bal + r, r * 1.05) pontok = [] for i in range(10): sugar = r if i % 2 == 0 else r * 0.42 szog = math.radians(-90 + i * 36) pontok.append(QPointF(kozep.x() + sugar * math.cos(szog), kozep.y() + sugar * math.sin(szog))) return QPolygonF(pontok) def paintEvent(self, _): from raveos_center import stilus festo = QPainter(self) festo.setRenderHint(QPainter.RenderHint.Antialiasing, True) festo.setPen(Qt.PenStyle.NoPen) ertek = self.mutatott or self.ertek tele = QColor(stilus.SARGA if self.isEnabled() else stilus.SZOVEG_HALVANY) for i in range(5): bal = i * (self.meret + self.TERKOZ) csillag = self._sokszog(bal) festo.setBrush(QColor(stilus.KERET_EROS)) festo.drawPolygon(csillag) resz = max(0.0, min(1.0, ertek - i)) if resz > 0: festo.save() festo.setClipRect(QRectF(bal, 0, self.meret * resz, self.meret)) festo.setBrush(tele) festo.drawPolygon(csillag) festo.restore() if self.hasFocus(): festo.setPen(QColor(stilus.ZOLD)) festo.setBrush(Qt.BrushStyle.NoBrush) festo.drawRect(QRectF(0.5, 0.5, self.width() - 1, self.height() - 1)) festo.end() def nyujthato(widget): widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) return widget