replace ScaledScrollBar with BigScrollBar

step 4 - add repeat actions

This has probably a problem. The repeat action is triggering updates asynchronously.
Which means we do not wait until it is done. Which means we can DOS ourselves.
This commit is contained in:
2024-04-14 19:12:37 +02:00
parent 7a574f7ed4
commit 3e793596c2

View File

@@ -2,7 +2,7 @@ import enum
from PySide6.QtGui import QWheelEvent
from PySide6.QtWidgets import QWidget, QStylePainter, QStyle, QStyleOptionSlider, QSlider, QAbstractSlider
from PySide6.QtCore import Qt, QSize, QEvent, QRect, QPoint, Signal
from PySide6.QtCore import Qt, QSize, QEvent, QRect, QPoint, Signal, QTimer, QElapsedTimer
class BigScrollBar(QWidget):
@@ -33,6 +33,11 @@ class BigScrollBar(QWidget):
def __init__(self):
super(BigScrollBar, self).__init__()
self.repeat_action_timer = QTimer()
self.repeat_action_control = QStyle.SubControl.SC_None
self.repeat_action_timer.setSingleShot(True)
self.repeat_action_timer.timeout.connect(self.execute_control)
self.repeat_action_timer.setInterval(50)
def setMinimum(self, min: int):
self.minimum = min
@@ -110,8 +115,14 @@ class BigScrollBar(QWidget):
return super().event(event)
def mousePressEvent(self, event):
if self.repeat_action_timer.isActive():
self.stopRepeatAction()
if not (event.button() == Qt.MouseButton.LeftButton or event.button() == Qt.MouseButton.MiddleButton):
return
style_options = self.style_options()
style_options.keyboardModifiers = event.modifiers() ## not sure why, copied from https://github.com/qt/qtbase/blob/dev/src/widgets/widgets/qscrollbar.cpp#L535
self.pressedControl = self.style().hitTestComplexControl(QStyle.ComplexControl.CC_ScrollBar, style_options,
event.position().toPoint(), self)
@@ -120,14 +131,11 @@ class BigScrollBar(QWidget):
sr: QRect = self.style().subControlRect(QStyle.ComplexControl.CC_ScrollBar, style_options,
QStyle.SubControl.SC_ScrollBarSlider, self)
click: QPoint = event.position().toPoint()
press_y_value = click.y() - sr.center().y() + sr.topLeft().y()
press_y_value = self.pixelPosToRangeValue(press_y_value)
# print(f"pressYValue {pressYValue}")
if self.pressedControl == QStyle.SubControl.SC_ScrollBarSlider:
self.click_offset = click.y() - sr.y()
# todo
if (self.pressedControl == QStyle.SubControl.SC_ScrollBarAddPage
or self.pressedControl == QStyle.SubControl.SC_ScrollBarSubPage) \
and event.button() == Qt.MouseButton.MiddleButton:
@@ -135,30 +143,44 @@ class BigScrollBar(QWidget):
self.set_value(self.pixelPosToRangeValue(event.position().toPoint().y()))
self.pressedControl = QStyle.SubControl.SC_ScrollBarSlider
self.click_offset = slider_length / 2
pass
return
self.activateControl(self.pressedControl)
self.repeat_action_control = self.pressedControl
self.execute_control()
# self.repaint(self.style().subControlRect(QStyle.ComplexControl.CC_ScrollBar, style_options, self.pressedControl))
def activateControl(self, control):
match control:
def execute_control(self):
# print(f"execute_control: {self.repeat_action_control}")
trigger_repeat_action = True
match self.repeat_action_control:
case QStyle.SubControl.SC_ScrollBarAddPage:
self.scroll_event.emit(self.ScrollEvent.PageDown)
case QStyle.SubControl.SC_ScrollBarSubPage:
self.scroll_event.emit(self.ScrollEvent.PageUp)
if self.value <= self.minimum:
trigger_repeat_action = False
case QStyle.SubControl.SC_ScrollBarAddLine:
self.scroll_event.emit(self.ScrollEvent.LinesDown)
case QStyle.SubControl.SC_ScrollBarSubLine:
self.scroll_event.emit(self.ScrollEvent.LinesUp)
if self.value <= self.minimum:
trigger_repeat_action = False
case QStyle.SubControl.SC_ScrollBarFirst:
self.set_value(self.minimum)
trigger_repeat_action = False
case QStyle.SubControl.SC_ScrollBarLast:
self.set_value(self.maximum)
trigger_repeat_action = False
case _:
pass
trigger_repeat_action = False
if trigger_repeat_action:
# print(f"schedule repeat action: {self.repeat_action_control}")
self.repeat_action_timer.start()
def mouseReleaseEvent(self, event):
self.pressedControl = QStyle.SubControl.SC_None
self.stopRepeatAction()
def mouseMoveEvent(self, event):
if self.pressedControl == QStyle.SubControl.SC_None:
@@ -177,6 +199,12 @@ class BigScrollBar(QWidget):
# print(f"move to value: {new_position}")
self.set_value(new_position)
# stop repeat action when pointer leaves control
pr: QRect = self.style().subControlRect(QStyle.ComplexControl.CC_ScrollBar, self.style_options(),
self.pressedControl, self)
if not pr.contains(event.position().toPoint()):
self.stopRepeatAction()
def wheelEvent(self, event: QWheelEvent):
event.ignore()
@@ -188,7 +216,6 @@ class BigScrollBar(QWidget):
scroll_event = self.ScrollEvent.LinesDown if event.angleDelta().y() < 0 else self.ScrollEvent.LinesUp
self.scroll_event.emit(scroll_event)
def pixelPosToRangeValue(self, pos: int):
opt: QStyleOptionSlider = self.style_options()
@@ -198,18 +225,24 @@ class BigScrollBar(QWidget):
QStyle.SubControl.SC_ScrollBarSlider, self)
# only for vertical scrollbars
sliderLength = sr.height();
sliderMin = gr.y();
sliderMax = gr.bottom() - sliderLength + 1;
slider_length = sr.height();
slider_min = gr.y();
slider_max = gr.bottom() - slider_length + 1;
val = QStyle.sliderValueFromPosition(opt.minimum, opt.maximum, pos - sliderMin,
sliderMax - sliderMin, opt.upsideDown)
val = QStyle.sliderValueFromPosition(opt.minimum, opt.maximum, pos - slider_min,
slider_max - slider_min, opt.upsideDown)
t = self.scale / self.maximum
val = int(val / t)
# print(f"pixelPosToRangeValue({pos}) -> {val}")
return val
def stopRepeatAction(self):
self.repeat_action_control = QStyle.SubControl.SC_None
# print(f"stop repeat action: {self.repeat_action_control}")
self.repeat_action_timer.stop()
#self.update()
def set_value(self, value: int):
self.value = value
self.value_changed.emit(str(self.value))