initial fluent-widgets ui
This commit is contained in:
272
qfluentwidgets/components/navigation/pivot.py
Normal file
272
qfluentwidgets/components/navigation/pivot.py
Normal file
@ -0,0 +1,272 @@
|
||||
# coding:utf-8
|
||||
from typing import Dict
|
||||
|
||||
from PySide6.QtCore import Qt, Signal, QRectF
|
||||
from PySide6.QtGui import QPainter, QFont, QColor
|
||||
from PySide6.QtWidgets import QApplication, QPushButton, QWidget, QHBoxLayout, QSizePolicy
|
||||
|
||||
from ...common.font import setFont
|
||||
from ...common.router import qrouter
|
||||
from ...common.style_sheet import themeColor, FluentStyleSheet
|
||||
from ...common.color import autoFallbackThemeColor
|
||||
from ...common.animation import FluentAnimation, FluentAnimationType, FluentAnimationProperty
|
||||
from ..widgets.button import PushButton
|
||||
from .navigation_panel import RouteKeyError
|
||||
|
||||
|
||||
class PivotItem(PushButton):
|
||||
""" Pivot item """
|
||||
|
||||
itemClicked = Signal(bool)
|
||||
|
||||
def _postInit(self):
|
||||
self.isSelected = False
|
||||
self.setProperty('isSelected', False)
|
||||
self.clicked.connect(lambda: self.itemClicked.emit(True))
|
||||
self.setAttribute(Qt.WA_LayoutUsesWidgetRect)
|
||||
|
||||
FluentStyleSheet.PIVOT.apply(self)
|
||||
setFont(self, 18)
|
||||
|
||||
def setSelected(self, isSelected: bool):
|
||||
if self.isSelected == isSelected:
|
||||
return
|
||||
|
||||
self.isSelected = isSelected
|
||||
self.setProperty('isSelected', isSelected)
|
||||
self.setStyle(QApplication.style())
|
||||
self.update()
|
||||
|
||||
|
||||
class Pivot(QWidget):
|
||||
""" Pivot """
|
||||
|
||||
currentItemChanged = Signal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.items = {} # type: Dict[str, PivotItem]
|
||||
self._currentRouteKey = None
|
||||
|
||||
self.lightIndicatorColor = QColor()
|
||||
self.darkIndicatorColor = QColor()
|
||||
|
||||
self.hBoxLayout = QHBoxLayout(self)
|
||||
self.slideAni = FluentAnimation.create(
|
||||
FluentAnimationType.POINT_TO_POINT, FluentAnimationProperty.SCALE, value=0, parent=self)
|
||||
|
||||
FluentStyleSheet.PIVOT.apply(self)
|
||||
|
||||
self.hBoxLayout.setSpacing(0)
|
||||
self.hBoxLayout.setAlignment(Qt.AlignLeft)
|
||||
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.hBoxLayout.setSizeConstraint(QHBoxLayout.SetMinimumSize)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
|
||||
def addItem(self, routeKey: str, text: str, onClick=None, icon=None):
|
||||
""" add item
|
||||
|
||||
Parameters
|
||||
----------
|
||||
routeKey: str
|
||||
the unique name of item
|
||||
|
||||
text: str
|
||||
the text of navigation item
|
||||
|
||||
onClick: callable
|
||||
the slot connected to item clicked signal
|
||||
|
||||
icon: str
|
||||
the icon of navigation item
|
||||
"""
|
||||
return self.insertItem(-1, routeKey, text, onClick, icon)
|
||||
|
||||
def addWidget(self, routeKey: str, widget: PivotItem, onClick=None):
|
||||
""" add widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
routeKey: str
|
||||
the unique name of item
|
||||
|
||||
widget: PivotItem
|
||||
navigation widget
|
||||
|
||||
onClick: callable
|
||||
the slot connected to item clicked signal
|
||||
"""
|
||||
self.insertWidget(-1, routeKey, widget, onClick)
|
||||
|
||||
def insertItem(self, index: int, routeKey: str, text: str, onClick=None, icon=None):
|
||||
""" insert item
|
||||
|
||||
Parameters
|
||||
----------
|
||||
index: int
|
||||
insert position
|
||||
|
||||
routeKey: str
|
||||
the unique name of item
|
||||
|
||||
text: str
|
||||
the text of navigation item
|
||||
|
||||
onClick: callable
|
||||
the slot connected to item clicked signal
|
||||
|
||||
icon: str
|
||||
the icon of navigation item
|
||||
"""
|
||||
if routeKey in self.items:
|
||||
return
|
||||
|
||||
item = PivotItem(text, self)
|
||||
if icon:
|
||||
item.setIcon(icon)
|
||||
|
||||
self.insertWidget(index, routeKey, item, onClick)
|
||||
return item
|
||||
|
||||
def insertWidget(self, index: int, routeKey: str, widget: PivotItem, onClick=None):
|
||||
""" insert item
|
||||
|
||||
Parameters
|
||||
----------
|
||||
index: int
|
||||
insert position
|
||||
|
||||
routeKey: str
|
||||
the unique name of item
|
||||
|
||||
widget: PivotItem
|
||||
navigation widget
|
||||
|
||||
onClick: callable
|
||||
the slot connected to item clicked signal
|
||||
"""
|
||||
if routeKey in self.items:
|
||||
return
|
||||
|
||||
widget.setProperty('routeKey', routeKey)
|
||||
widget.itemClicked.connect(self._onItemClicked)
|
||||
if onClick:
|
||||
widget.itemClicked.connect(onClick)
|
||||
|
||||
self.items[routeKey] = widget
|
||||
self.hBoxLayout.insertWidget(index, widget, 1)
|
||||
|
||||
def removeWidget(self, routeKey: str):
|
||||
""" remove widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
routeKey: str
|
||||
the unique name of item
|
||||
"""
|
||||
if routeKey not in self.items:
|
||||
return
|
||||
|
||||
item = self.items.pop(routeKey)
|
||||
self.hBoxLayout.removeWidget(item)
|
||||
qrouter.remove(routeKey)
|
||||
item.deleteLater()
|
||||
|
||||
if not self.items:
|
||||
self._currentRouteKey = None
|
||||
|
||||
def clear(self):
|
||||
""" clear all navigation items """
|
||||
for k, w in self.items.items():
|
||||
self.hBoxLayout.removeWidget(w)
|
||||
qrouter.remove(k)
|
||||
w.deleteLater()
|
||||
|
||||
self.items.clear()
|
||||
self._currentRouteKey = None
|
||||
|
||||
def currentItem(self):
|
||||
""" Returns the current selected item """
|
||||
if self._currentRouteKey is None:
|
||||
return None
|
||||
|
||||
return self.widget(self._currentRouteKey)
|
||||
|
||||
def currentRouteKey(self):
|
||||
return self._currentRouteKey
|
||||
|
||||
def setCurrentItem(self, routeKey: str):
|
||||
""" set current selected item
|
||||
|
||||
Parameters
|
||||
----------
|
||||
routeKey: str
|
||||
the unique name of item
|
||||
"""
|
||||
if routeKey not in self.items or routeKey == self.currentRouteKey():
|
||||
return
|
||||
|
||||
self._currentRouteKey = routeKey
|
||||
self.slideAni.startAnimation(self.widget(routeKey).x())
|
||||
|
||||
for k, item in self.items.items():
|
||||
item.setSelected(k == routeKey)
|
||||
|
||||
self.currentItemChanged.emit(routeKey)
|
||||
|
||||
def showEvent(self, e):
|
||||
super().showEvent(e)
|
||||
self._adjustIndicatorPos()
|
||||
|
||||
def setItemFontSize(self, size: int):
|
||||
""" set the pixel font size of items """
|
||||
for item in self.items.values():
|
||||
font = item.font()
|
||||
font.setPixelSize(size)
|
||||
item.setFont(font)
|
||||
item.adjustSize()
|
||||
|
||||
def setItemText(self, routeKey: str, text: str):
|
||||
""" set the text of item """
|
||||
item = self.widget(routeKey)
|
||||
item.setText(text)
|
||||
|
||||
def setIndicatorColor(self, light, dark):
|
||||
self.lightIndicatorColor = QColor(light)
|
||||
self.darkIndicatorColor = QColor(dark)
|
||||
self.update()
|
||||
|
||||
def _onItemClicked(self):
|
||||
item = self.sender() # type: PivotItem
|
||||
self.setCurrentItem(item.property('routeKey'))
|
||||
|
||||
def widget(self, routeKey: str):
|
||||
if routeKey not in self.items:
|
||||
raise RouteKeyError(f"`{routeKey}` is illegal.")
|
||||
|
||||
return self.items[routeKey]
|
||||
|
||||
def resizeEvent(self, e) -> None:
|
||||
super().resizeEvent(e)
|
||||
self._adjustIndicatorPos()
|
||||
|
||||
def _adjustIndicatorPos(self):
|
||||
item = self.currentItem()
|
||||
if item:
|
||||
self.slideAni.stop()
|
||||
self.slideAni.setValue(item.x())
|
||||
|
||||
def paintEvent(self, e):
|
||||
super().paintEvent(e)
|
||||
|
||||
if not self.currentItem():
|
||||
return
|
||||
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHints(QPainter.Antialiasing)
|
||||
painter.setPen(Qt.NoPen)
|
||||
painter.setBrush(autoFallbackThemeColor(self.lightIndicatorColor, self.darkIndicatorColor))
|
||||
|
||||
x = int(self.currentItem().width() / 2 - 8 + self.slideAni.value())
|
||||
painter.drawRoundedRect(x, self.height() - 3, 16, 3, 1.5, 1.5)
|
||||
Reference in New Issue
Block a user