146 lines
4.5 KiB
Python
146 lines
4.5 KiB
Python
from logging import getLogger
|
|
from typing import Union, Protocol
|
|
|
|
from PyQt5.QtCore import (
|
|
Qt,
|
|
QRect,
|
|
QSize,
|
|
QPoint,
|
|
pyqtSignal,
|
|
)
|
|
from PyQt5.QtGui import QFontMetrics
|
|
from PyQt5.QtWidgets import (
|
|
QStyle,
|
|
QLabel,
|
|
QWidget,
|
|
QStyleOptionTab,
|
|
QStylePainter,
|
|
QTabBar,
|
|
QTabWidget,
|
|
QVBoxLayout,
|
|
QScrollArea, QLayout, QSizePolicy,
|
|
)
|
|
|
|
from rare.utils.misc import qta_icon
|
|
|
|
logger = getLogger("SideTab")
|
|
|
|
|
|
class SideTabBar(QTabBar):
|
|
def __init__(self, padding: int = -1, parent=None):
|
|
super(SideTabBar, self).__init__(parent=parent)
|
|
self.setObjectName(type(self).__name__)
|
|
self.padding = padding
|
|
self.fm = QFontMetrics(self.font())
|
|
|
|
def tabSizeHint(self, index):
|
|
width = QTabBar.tabSizeHint(self, index).height()
|
|
if self.padding < 0:
|
|
width += QTabBar.tabSizeHint(self, index).width()
|
|
else:
|
|
width += self.padding
|
|
return QSize(width, self.fm.height() + 18)
|
|
|
|
def paintEvent(self, event):
|
|
painter = QStylePainter(self)
|
|
opt = QStyleOptionTab()
|
|
|
|
for i in range(self.count()):
|
|
self.initStyleOption(opt, i)
|
|
painter.drawControl(QStyle.CE_TabBarTabShape, opt)
|
|
painter.save()
|
|
|
|
s = opt.rect.size()
|
|
s.transpose()
|
|
r = QRect(QPoint(), s)
|
|
r.moveCenter(opt.rect.center())
|
|
opt.rect = r
|
|
|
|
c = self.tabRect(i).center()
|
|
painter.translate(c)
|
|
painter.rotate(90)
|
|
painter.translate(-c)
|
|
painter.drawControl(QStyle.CE_TabBarTabLabel, opt)
|
|
painter.restore()
|
|
|
|
|
|
class SideTabContents(object):
|
|
# str: title
|
|
set_title = pyqtSignal(str)
|
|
implements_scrollarea: bool = False
|
|
|
|
|
|
class SideTabContentsProtocol(Protocol):
|
|
implements_scrollarea: bool
|
|
|
|
def layout(self) -> QLayout:
|
|
pass
|
|
|
|
def set_title(self) -> pyqtSignal:
|
|
pass
|
|
|
|
def sizeHint(self) -> QSize:
|
|
pass
|
|
|
|
|
|
class SideTabContainer(QWidget):
|
|
def __init__(self, widget: Union[QWidget, SideTabContentsProtocol], title: str = "", parent: QWidget = None):
|
|
super(SideTabContainer, self).__init__(parent=parent)
|
|
self.title = QLabel(self)
|
|
self.setTitle(title)
|
|
|
|
if widget.layout():
|
|
widget.layout().setAlignment(Qt.AlignTop)
|
|
widget.layout().setContentsMargins(0, 0, 3, 0)
|
|
if hasattr(widget, "set_title"):
|
|
widget.set_title.connect(self.setTitle)
|
|
|
|
layout = QVBoxLayout(self)
|
|
layout.addWidget(self.title)
|
|
|
|
if not hasattr(widget, "implements_scrollarea") or not widget.implements_scrollarea:
|
|
scrollarea = QScrollArea(self)
|
|
scrollarea.setSizeAdjustPolicy(QScrollArea.AdjustToContents)
|
|
scrollarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
scrollarea.setFrameStyle(QScrollArea.NoFrame)
|
|
scrollarea.setMinimumWidth(
|
|
widget.sizeHint().width() + scrollarea.verticalScrollBar().sizeHint().width()
|
|
)
|
|
scrollarea.setWidgetResizable(True)
|
|
widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
scrollarea.setWidget(widget)
|
|
scrollarea.widget().setAutoFillBackground(False)
|
|
scrollarea.viewport().setAutoFillBackground(False)
|
|
layout.addWidget(scrollarea)
|
|
else:
|
|
layout.addWidget(widget)
|
|
|
|
layout.setAlignment(Qt.AlignTop)
|
|
|
|
def setTitle(self, text: str) -> None:
|
|
self.title.setText(f"<h2>{text}</h2>")
|
|
self.title.setVisible(bool(text))
|
|
|
|
|
|
class SideTabWidget(QTabWidget):
|
|
back_clicked = pyqtSignal()
|
|
|
|
def __init__(self, show_back: bool = False, padding: int = -1, parent=None):
|
|
super(SideTabWidget, self).__init__(parent=parent)
|
|
self.setTabBar(SideTabBar(padding=padding, parent=self))
|
|
self.setDocumentMode(True)
|
|
self.setTabPosition(QTabWidget.West)
|
|
if show_back:
|
|
super(SideTabWidget, self).addTab(
|
|
QWidget(self), qta_icon("mdi.keyboard-backspace", "ei.backward"), self.tr("Back")
|
|
)
|
|
self.tabBarClicked.connect(self.back_func)
|
|
|
|
def back_func(self, tab):
|
|
# shortcut for tab == 0
|
|
if not tab:
|
|
self.back_clicked.emit()
|
|
|
|
def addTab(self, widget: Union[QWidget, SideTabContentsProtocol], a1: str, title: str = "") -> int:
|
|
container = SideTabContainer(widget, title, parent=self)
|
|
return super(SideTabWidget, self).addTab(container, a1)
|