204 lines
6.6 KiB
Python
204 lines
6.6 KiB
Python
|
|
# coding:utf-8
|
||
|
|
from typing import List
|
||
|
|
from PySide6.QtCore import Qt, QRect, QRectF, QSize
|
||
|
|
from PySide6.QtGui import QPainter, QColor, QPainterPath, QAction
|
||
|
|
from PySide6.QtWidgets import QLineEdit, QListWidgetItem, QListWidget
|
||
|
|
|
||
|
|
from ..widgets.menu import (RoundMenu, MenuAnimationType, MenuAnimationManager, MenuActionListWidget,
|
||
|
|
IndicatorMenuItemDelegate, LineEditMenu, MenuIndicatorType, CheckableMenu)
|
||
|
|
from ..widgets.line_edit import CompleterMenu, LineEdit
|
||
|
|
from ..widgets.acrylic_label import AcrylicBrush
|
||
|
|
from ...common.style_sheet import isDarkTheme
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicMenuActionListWidget(MenuActionListWidget):
|
||
|
|
|
||
|
|
def __init__(self, parent=None):
|
||
|
|
super().__init__(parent)
|
||
|
|
self.acrylicBrush = AcrylicBrush(self.viewport(), 35)
|
||
|
|
self.setViewportMargins(0, 0, 0, 0)
|
||
|
|
self.setProperty("transparent", True)
|
||
|
|
|
||
|
|
super().addItem(self.createPlaceholderItem(self._topMargin()))
|
||
|
|
super().addItem(self.createPlaceholderItem(self._bottomMargin()))
|
||
|
|
|
||
|
|
def _updateAcrylicColor(self):
|
||
|
|
if isDarkTheme():
|
||
|
|
tintColor = QColor(32, 32, 32, 200)
|
||
|
|
luminosityColor = QColor(0, 0, 0, 0)
|
||
|
|
else:
|
||
|
|
tintColor = QColor(255, 255, 255, 160)
|
||
|
|
luminosityColor = QColor(255, 255, 255, 50)
|
||
|
|
|
||
|
|
self.acrylicBrush.tintColor = tintColor
|
||
|
|
self.acrylicBrush.luminosityColor = luminosityColor
|
||
|
|
|
||
|
|
def _topMargin(self):
|
||
|
|
return 6
|
||
|
|
|
||
|
|
def _bottomMargin(self):
|
||
|
|
return 6
|
||
|
|
|
||
|
|
def setItemHeight(self, height: int):
|
||
|
|
""" set the height of item """
|
||
|
|
if height == self._itemHeight:
|
||
|
|
return
|
||
|
|
|
||
|
|
for i in range(1, self.count() - 1):
|
||
|
|
item = self.item(i)
|
||
|
|
if not self.itemWidget(item):
|
||
|
|
item.setSizeHint(QSize(item.sizeHint().width(), height))
|
||
|
|
|
||
|
|
self._itemHeight = height
|
||
|
|
self.adjustSize()
|
||
|
|
|
||
|
|
def addItem(self, item):
|
||
|
|
return super().insertItem(self.count() - 1, item)
|
||
|
|
|
||
|
|
def createPlaceholderItem(self, height=2):
|
||
|
|
item = QListWidgetItem()
|
||
|
|
item.setSizeHint(QSize(1, height))
|
||
|
|
item.setFlags(Qt.ItemFlag.NoItemFlags)
|
||
|
|
return item
|
||
|
|
|
||
|
|
def clipPath(self):
|
||
|
|
path = QPainterPath()
|
||
|
|
path.addRoundedRect(QRectF(self.rect()).adjusted(0, 0, -2.5, -2.5), 8, 8)
|
||
|
|
return path
|
||
|
|
|
||
|
|
def paintEvent(self, e) -> None:
|
||
|
|
painter = QPainter(self.viewport())
|
||
|
|
painter.setRenderHints(QPainter.Antialiasing |
|
||
|
|
QPainter.SmoothPixmapTransform)
|
||
|
|
|
||
|
|
self.acrylicBrush.clipPath = self.clipPath()
|
||
|
|
self._updateAcrylicColor()
|
||
|
|
self.acrylicBrush.paint()
|
||
|
|
|
||
|
|
super().paintEvent(e)
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicMenuBase:
|
||
|
|
|
||
|
|
def __init__(self, *args, **kwargs):
|
||
|
|
super().__init__(*args, **kwargs)
|
||
|
|
|
||
|
|
def setUpMenu(self, view):
|
||
|
|
self.hBoxLayout.removeWidget(self.view)
|
||
|
|
self.view.deleteLater()
|
||
|
|
|
||
|
|
self.view = view
|
||
|
|
self.hBoxLayout.addWidget(self.view)
|
||
|
|
|
||
|
|
self.setShadowEffect()
|
||
|
|
|
||
|
|
self.view.itemClicked.connect(self._onItemClicked)
|
||
|
|
self.view.itemEntered.connect(self._onItemEntered)
|
||
|
|
|
||
|
|
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||
|
|
p = MenuAnimationManager.make(self, aniType)._endPosition(pos)
|
||
|
|
self.view.acrylicBrush.grabImage(QRect(p, self.layout().sizeHint()))
|
||
|
|
super().exec(pos, ani, aniType)
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicMenu(AcrylicMenuBase, RoundMenu):
|
||
|
|
""" Acrylic menu """
|
||
|
|
|
||
|
|
def __init__(self, title="", parent=None):
|
||
|
|
super().__init__(title, parent)
|
||
|
|
self.setUpMenu(AcrylicMenuActionListWidget(self))
|
||
|
|
|
||
|
|
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||
|
|
return super().exec(pos, ani, aniType)
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicCompleterMenuActionListWidget(AcrylicMenuActionListWidget):
|
||
|
|
|
||
|
|
def clipPath(self):
|
||
|
|
path = QPainterPath()
|
||
|
|
path.setFillRule(Qt.FillRule.WindingFill)
|
||
|
|
path.addRoundedRect(QRectF(self.rect()).adjusted(1, 1, -2.5, -2.5), 8, 8)
|
||
|
|
|
||
|
|
if self.property("dropDown"):
|
||
|
|
path.addRect(1, 1, 11, 11)
|
||
|
|
path.addRect(self.width() - 12, 1, 11, 11)
|
||
|
|
else:
|
||
|
|
path.addRect(1, self.height() - 11, 11, 11)
|
||
|
|
path.addRect(self.width() - 12, self.height() - 11, 11, 11)
|
||
|
|
|
||
|
|
return path
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicCompleterMenu(AcrylicMenuBase, CompleterMenu):
|
||
|
|
""" Acrylic completer menu """
|
||
|
|
|
||
|
|
def __init__(self, lineEdit: LineEdit):
|
||
|
|
super().__init__(lineEdit)
|
||
|
|
self.setUpMenu(AcrylicCompleterMenuActionListWidget(self))
|
||
|
|
|
||
|
|
self.view.setObjectName('completerListWidget')
|
||
|
|
self.view.setItemDelegate(IndicatorMenuItemDelegate())
|
||
|
|
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||
|
|
self.setItemHeight(33)
|
||
|
|
|
||
|
|
def _onItemClicked(self, item):
|
||
|
|
self._hideMenu(False)
|
||
|
|
self._onCompletionItemSelected(item.text(), self.view.row(item)-1)
|
||
|
|
|
||
|
|
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||
|
|
return super().exec(pos, ani, aniType)
|
||
|
|
|
||
|
|
def setItems(self, items):
|
||
|
|
""" set completion items """
|
||
|
|
self.view.clear()
|
||
|
|
|
||
|
|
self.items = items
|
||
|
|
|
||
|
|
QListWidget.addItem(self.view, self.view.createPlaceholderItem(self.view._topMargin()))
|
||
|
|
self.view.addItems(items)
|
||
|
|
|
||
|
|
for i in range(1, self.view.count()):
|
||
|
|
item = self.view.item(i)
|
||
|
|
item.setSizeHint(QSize(1, self.itemHeight))
|
||
|
|
|
||
|
|
QListWidget.addItem(self.view, self.view.createPlaceholderItem(self.view._bottomMargin()))
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicLineEditMenu(AcrylicMenuBase, LineEditMenu):
|
||
|
|
""" Acrylic line edit menu """
|
||
|
|
|
||
|
|
def __init__(self, parent: QLineEdit):
|
||
|
|
super().__init__(parent)
|
||
|
|
self.setUpMenu(AcrylicMenuActionListWidget(self))
|
||
|
|
|
||
|
|
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||
|
|
return super().exec(pos, ani, aniType)
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicCheckableMenu(AcrylicMenuBase, CheckableMenu):
|
||
|
|
""" Checkable menu """
|
||
|
|
|
||
|
|
def __init__(self, title="", parent=None, indicatorType=MenuIndicatorType.CHECK):
|
||
|
|
super().__init__(title, parent, indicatorType)
|
||
|
|
self.setUpMenu(AcrylicMenuActionListWidget(self))
|
||
|
|
self.view.setObjectName('checkableListWidget')
|
||
|
|
|
||
|
|
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||
|
|
return super().exec(pos, ani, aniType)
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicSystemTrayMenu(AcrylicMenu):
|
||
|
|
""" System tray menu """
|
||
|
|
|
||
|
|
def showEvent(self, e):
|
||
|
|
super().showEvent(e)
|
||
|
|
self.adjustPosition()
|
||
|
|
self.view.acrylicBrush.grabImage(QRect(self.pos(), self.layout().sizeHint()))
|
||
|
|
|
||
|
|
|
||
|
|
class AcrylicCheckableSystemTrayMenu(AcrylicCheckableMenu):
|
||
|
|
""" Checkable system tray menu """
|
||
|
|
|
||
|
|
def showEvent(self, e):
|
||
|
|
super().showEvent(e)
|
||
|
|
self.adjustPosition()
|