You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
5.0 KiB
138 lines
5.0 KiB
# coding:utf-8
|
|
from PySide6.QtCore import QSize, Qt, Signal, QPoint, QRectF
|
|
from PySide6.QtGui import QColor, QMouseEvent, QPainter, QPainterPath
|
|
from PySide6.QtWidgets import (QProxyStyle, QSlider, QStyle, QStyleOptionSlider,
|
|
QWidget)
|
|
|
|
from ...common.style_sheet import FluentStyleSheet
|
|
from ...common.overload import singledispatchmethod
|
|
|
|
|
|
class Slider(QSlider):
|
|
""" A slider can be clicked """
|
|
|
|
clicked = Signal(int)
|
|
|
|
@singledispatchmethod
|
|
def __init__(self, parent: QWidget = None):
|
|
super().__init__(parent)
|
|
FluentStyleSheet.SLIDER.apply(self)
|
|
|
|
@__init__.register
|
|
def _(self, orientation: Qt.Orientation, parent: QWidget = None):
|
|
super().__init__(orientation, parent=parent)
|
|
FluentStyleSheet.SLIDER.apply(self)
|
|
|
|
def mousePressEvent(self, e: QMouseEvent):
|
|
super().mousePressEvent(e)
|
|
|
|
if self.orientation() == Qt.Horizontal:
|
|
value = int(e.pos().x() / self.width() * self.maximum())
|
|
else:
|
|
value = int((self.height()-e.pos().y()) /
|
|
self.height() * self.maximum())
|
|
|
|
self.setValue(value)
|
|
self.clicked.emit(self.value())
|
|
|
|
|
|
class HollowHandleStyle(QProxyStyle):
|
|
""" Hollow handle style """
|
|
|
|
def __init__(self, config: dict = None):
|
|
"""
|
|
Parameters
|
|
----------
|
|
config: dict
|
|
style config
|
|
"""
|
|
super().__init__()
|
|
self.config = {
|
|
"groove.height": 3,
|
|
"sub-page.color": QColor(255, 255, 255),
|
|
"add-page.color": QColor(255, 255, 255, 64),
|
|
"handle.color": QColor(255, 255, 255),
|
|
"handle.ring-width": 4,
|
|
"handle.hollow-radius": 6,
|
|
"handle.margin": 4
|
|
}
|
|
config = config if config else {}
|
|
self.config.update(config)
|
|
|
|
# get handle size
|
|
w = self.config["handle.margin"]+self.config["handle.ring-width"] + \
|
|
self.config["handle.hollow-radius"]
|
|
self.config["handle.size"] = QSize(2*w, 2*w)
|
|
|
|
def subControlRect(self, cc: QStyle.ComplexControl, opt: QStyleOptionSlider, sc: QStyle.SubControl, widget: QSlider):
|
|
""" get the rectangular area occupied by the sub control """
|
|
if cc != self.ComplexControl.CC_Slider or widget.orientation() != Qt.Horizontal \
|
|
or sc == self.SubControl.SC_SliderTickmarks:
|
|
return super().subControlRect(cc, opt, sc, widget)
|
|
|
|
rect = widget.rect()
|
|
|
|
if sc == self.SubControl.SC_SliderGroove:
|
|
h = self.config["groove.height"]
|
|
grooveRect = QRectF(0, (rect.height()-h)//2, rect.width(), h)
|
|
return grooveRect.toRect()
|
|
|
|
elif sc == self.SubControl.SC_SliderHandle:
|
|
size = self.config["handle.size"]
|
|
x = self.sliderPositionFromValue(
|
|
widget.minimum(), widget.maximum(), widget.value(), rect.width())
|
|
|
|
# solve the situation that the handle runs out of slider
|
|
x *= (rect.width()-size.width())/rect.width()
|
|
sliderRect = QRectF(x, 0, size.width(), size.height())
|
|
return sliderRect.toRect()
|
|
|
|
def drawComplexControl(self, cc: QStyle.ComplexControl, opt: QStyleOptionSlider, painter: QPainter, widget: QSlider):
|
|
""" draw sub control """
|
|
if cc != self.ComplexControl.CC_Slider or widget.orientation() != Qt.Horizontal:
|
|
return super().drawComplexControl(cc, opt, painter, widget)
|
|
|
|
grooveRect = self.subControlRect(cc, opt, self.SubControl.SC_SliderGroove, widget)
|
|
handleRect = self.subControlRect(cc, opt, self.SubControl.SC_SliderHandle, widget)
|
|
painter.setRenderHints(QPainter.Antialiasing)
|
|
painter.setPen(Qt.NoPen)
|
|
|
|
# paint groove
|
|
painter.save()
|
|
painter.translate(grooveRect.topLeft())
|
|
|
|
# paint the crossed part
|
|
w = handleRect.x()-grooveRect.x()
|
|
h = self.config['groove.height']
|
|
painter.setBrush(self.config["sub-page.color"])
|
|
painter.drawRect(0, 0, w, h)
|
|
|
|
# paint the uncrossed part
|
|
x = w+self.config['handle.size'].width()
|
|
painter.setBrush(self.config["add-page.color"])
|
|
painter.drawRect(x, 0, grooveRect.width()-w, h)
|
|
painter.restore()
|
|
|
|
# paint handle
|
|
ringWidth = self.config["handle.ring-width"]
|
|
hollowRadius = self.config["handle.hollow-radius"]
|
|
radius = ringWidth + hollowRadius
|
|
|
|
path = QPainterPath()
|
|
path.moveTo(0, 0)
|
|
center = handleRect.center() + QPoint(1, 1)
|
|
path.addEllipse(center, radius, radius)
|
|
path.addEllipse(center, hollowRadius, hollowRadius)
|
|
|
|
handleColor = self.config["handle.color"] # type:QColor
|
|
handleColor.setAlpha(255 if opt.activeSubControls !=
|
|
self.SubControl.SC_SliderHandle else 153)
|
|
painter.setBrush(handleColor)
|
|
painter.drawPath(path)
|
|
|
|
# press handle
|
|
if widget.isSliderDown():
|
|
handleColor.setAlpha(255)
|
|
painter.setBrush(handleColor)
|
|
painter.drawEllipse(handleRect)
|