mirror of
https://github.com/pyapp-kit/superqt.git
synced 2025-07-21 12:11:07 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
cc25733ce8 | ||
|
accb87021f | ||
|
ccad397838 | ||
|
68248c920c | ||
|
f8ac85aaf6 | ||
|
bd6fba96ad | ||
|
7d31812858 | ||
|
f27377ab1b | ||
|
2052fb8310 | ||
|
40d3e20bff | ||
|
f4d9881b0c |
3
.github/workflows/test_and_deploy.yml
vendored
3
.github/workflows/test_and_deploy.yml
vendored
@@ -70,9 +70,6 @@ jobs:
|
||||
- python-version: 3.8
|
||||
platform: ubuntu-18.04
|
||||
backend: pyside2
|
||||
- python-version: 3.6
|
||||
platform: windows-2016
|
||||
backend: pyqt5
|
||||
|
||||
# legacy Qt
|
||||
- python-version: 3.7
|
||||
|
@@ -1,11 +1,11 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0
|
||||
rev: v4.2.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v1.20.0
|
||||
rev: v1.20.1
|
||||
hooks:
|
||||
- id: setup-cfg-fmt
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
@@ -24,16 +24,16 @@ repos:
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.31.0
|
||||
rev: v2.32.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py37-plus, --keep-runtime-typing]
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.1.0
|
||||
rev: 22.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.931
|
||||
rev: v0.950
|
||||
hooks:
|
||||
- id: mypy
|
||||
exclude: examples
|
||||
|
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,5 +1,23 @@
|
||||
# Changelog
|
||||
|
||||
## [0.3.2](https://github.com/napari/superqt/tree/0.3.2) (2022-05-02)
|
||||
|
||||
[Full Changelog](https://github.com/napari/superqt/compare/v0.3.1...0.3.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add QSearchableListWidget and QSearchableComboBox widgets [\#80](https://github.com/napari/superqt/pull/80) ([Czaki](https://github.com/Czaki))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Fix crazy animation loop on Qcollapsible [\#84](https://github.com/napari/superqt/pull/84) ([tlambert03](https://github.com/tlambert03))
|
||||
- Reorder label update signal [\#83](https://github.com/napari/superqt/pull/83) ([tlambert03](https://github.com/tlambert03))
|
||||
- Fix height of expanded QCollapsible when child changes size [\#72](https://github.com/napari/superqt/pull/72) ([tlambert03](https://github.com/tlambert03))
|
||||
|
||||
**Tests & CI:**
|
||||
|
||||
- Fix deprecation warnings in tests [\#82](https://github.com/napari/superqt/pull/82) ([tlambert03](https://github.com/tlambert03))
|
||||
|
||||
## [v0.3.1](https://github.com/napari/superqt/tree/v0.3.1) (2022-03-02)
|
||||
|
||||
[Full Changelog](https://github.com/napari/superqt/compare/v0.3.0...v0.3.1)
|
||||
@@ -12,6 +30,10 @@
|
||||
|
||||
- put SignalInstance in TYPE\_CHECKING clause, check min requirements [\#70](https://github.com/napari/superqt/pull/70) ([tlambert03](https://github.com/tlambert03))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add changelog for v0.3.1 [\#71](https://github.com/napari/superqt/pull/71) ([tlambert03](https://github.com/tlambert03))
|
||||
|
||||
## [v0.3.0](https://github.com/napari/superqt/tree/v0.3.0) (2022-02-16)
|
||||
|
||||
[Full Changelog](https://github.com/napari/superqt/compare/v0.2.5-1...v0.3.0)
|
||||
@@ -126,7 +148,11 @@
|
||||
|
||||
## [v0.2.0rc0](https://github.com/napari/superqt/tree/v0.2.0rc0) (2021-06-26)
|
||||
|
||||
[Full Changelog](https://github.com/napari/superqt/compare/v0.2.0...v0.2.0rc0)
|
||||
[Full Changelog](https://github.com/napari/superqt/compare/v0.2.0rc1...v0.2.0rc0)
|
||||
|
||||
## [v0.2.0rc1](https://github.com/napari/superqt/tree/v0.2.0rc1) (2021-06-26)
|
||||
|
||||
[Full Changelog](https://github.com/napari/superqt/compare/v0.2.0...v0.2.0rc1)
|
||||
|
||||
|
||||
|
||||
|
@@ -61,3 +61,8 @@ combo.setEnumClass(SampleEnum, allow_none=True)
|
||||
```
|
||||
|
||||
In this case there is added option `----` and `currentEnum` will return `None` for it.
|
||||
|
||||
## QSearchableComboBox
|
||||
|
||||
`QSearchableComboBox` is a variant of [`QComboBox`](https://doc.qt.io/qt-5/qcombobox.html) that
|
||||
allow to filter list of options by enter part of text. It could be drop in replacement for `QComboBox`.
|
||||
|
8
docs/listwidgets.md
Normal file
8
docs/listwidgets.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# ListWidget
|
||||
|
||||
## QSearchableListWidget
|
||||
|
||||
`QSearchableListWidget` is a variant of [`QListWidget`](https://doc.qt.io/qt-5/qlistwidget.html) that add text entry above list widget that allow to filter list
|
||||
of available options.
|
||||
|
||||
Because of implementation it does not inherit directly from `QListWidget` but satisfy it all api. The only limitation is that it cannot be used as argument of `QListWidgetItem` constructor.
|
11
examples/searchable_combo_box.py
Normal file
11
examples/searchable_combo_box.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
from superqt import QSearchableComboBox
|
||||
|
||||
app = QApplication([])
|
||||
|
||||
slider = QSearchableComboBox()
|
||||
slider.addItems(["foo", "bar", "baz", "foobar", "foobaz", "barbaz"])
|
||||
slider.show()
|
||||
|
||||
app.exec_()
|
11
examples/searchable_list_widget.py
Normal file
11
examples/searchable_list_widget.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
from superqt import QSearchableListWidget
|
||||
|
||||
app = QApplication([])
|
||||
|
||||
slider = QSearchableListWidget()
|
||||
slider.addItems(["foo", "bar", "baz", "foobar", "foobaz", "barbaz"])
|
||||
slider.show()
|
||||
|
||||
app.exec_()
|
@@ -35,6 +35,7 @@ project_urls =
|
||||
[options]
|
||||
packages = find:
|
||||
install_requires =
|
||||
packaging
|
||||
qtpy>=1.1.0
|
||||
typing-extensions>=3.10.0.0
|
||||
python_requires = >=3.7
|
||||
|
@@ -7,7 +7,8 @@ except ImportError:
|
||||
|
||||
from ._eliding_label import QElidingLabel
|
||||
from .collapsible import QCollapsible
|
||||
from .combobox import QEnumComboBox
|
||||
from .combobox import QEnumComboBox, QSearchableComboBox
|
||||
from .selection import QSearchableListWidget
|
||||
from .sliders import (
|
||||
QDoubleRangeSlider,
|
||||
QDoubleSlider,
|
||||
@@ -26,13 +27,15 @@ __all__ = [
|
||||
"QDoubleRangeSlider",
|
||||
"QDoubleSlider",
|
||||
"QElidingLabel",
|
||||
"QEnumComboBox",
|
||||
"QLabeledDoubleRangeSlider",
|
||||
"QLabeledDoubleSlider",
|
||||
"QLabeledRangeSlider",
|
||||
"QLabeledSlider",
|
||||
"QLargeIntSpinBox",
|
||||
"QMessageHandler",
|
||||
"QSearchableComboBox",
|
||||
"QSearchableListWidget",
|
||||
"QRangeSlider",
|
||||
"QEnumComboBox",
|
||||
"QCollapsible",
|
||||
]
|
||||
|
@@ -1,13 +1,7 @@
|
||||
"""A collapsible widget to hide and unhide child widgets"""
|
||||
from typing import Optional
|
||||
|
||||
from qtpy.QtCore import (
|
||||
QAbstractAnimation,
|
||||
QEasingCurve,
|
||||
QMargins,
|
||||
QPropertyAnimation,
|
||||
Qt,
|
||||
)
|
||||
from qtpy.QtCore import QEasingCurve, QEvent, QMargins, QObject, QPropertyAnimation, Qt
|
||||
from qtpy.QtWidgets import QFrame, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
|
||||
@@ -23,10 +17,11 @@ class QCollapsible(QFrame):
|
||||
def __init__(self, title: str = "", parent: Optional[QWidget] = None):
|
||||
super().__init__(parent)
|
||||
self._locked = False
|
||||
self._is_animating = False
|
||||
|
||||
self._toggle_btn = QPushButton(self._COLLAPSED + title)
|
||||
self._toggle_btn.setCheckable(True)
|
||||
self._toggle_btn.setStyleSheet("text-align: left; background: transparent;")
|
||||
self._toggle_btn.setStyleSheet("text-align: left; border: none; outline: none;")
|
||||
self._toggle_btn.toggled.connect(self._toggle)
|
||||
|
||||
# frame layout
|
||||
@@ -38,6 +33,7 @@ class QCollapsible(QFrame):
|
||||
self._animation = QPropertyAnimation(self)
|
||||
self._animation.setPropertyName(b"maximumHeight")
|
||||
self._animation.setStartValue(0)
|
||||
self._animation.finished.connect(self._on_animation_done)
|
||||
self.setDuration(300)
|
||||
self.setEasingCurve(QEasingCurve.Type.InOutCubic)
|
||||
|
||||
@@ -77,19 +73,21 @@ class QCollapsible(QFrame):
|
||||
|
||||
def addWidget(self, widget: QWidget):
|
||||
"""Add a widget to the central content widget's layout."""
|
||||
widget.installEventFilter(self)
|
||||
self._content.layout().addWidget(widget)
|
||||
|
||||
def removeWidget(self, widget: QWidget):
|
||||
"""Remove widget from the central content widget's layout."""
|
||||
self._content.layout().removeWidget(widget)
|
||||
widget.removeEventFilter(self)
|
||||
|
||||
def expand(self, animate: bool = True):
|
||||
"""Expand (show) the collapsible section"""
|
||||
self._expand_collapse(QAbstractAnimation.Direction.Forward, animate)
|
||||
self._expand_collapse(QPropertyAnimation.Direction.Forward, animate)
|
||||
|
||||
def collapse(self, animate: bool = True):
|
||||
"""Collapse (hide) the collapsible section"""
|
||||
self._expand_collapse(QAbstractAnimation.Direction.Backward, animate)
|
||||
self._expand_collapse(QPropertyAnimation.Direction.Backward, animate)
|
||||
|
||||
def isExpanded(self) -> bool:
|
||||
"""Return whether the collapsible section is visible"""
|
||||
@@ -105,12 +103,12 @@ class QCollapsible(QFrame):
|
||||
return self._locked
|
||||
|
||||
def _expand_collapse(
|
||||
self, direction: QAbstractAnimation.Direction, animate: bool = True
|
||||
self, direction: QPropertyAnimation.Direction, animate: bool = True
|
||||
):
|
||||
if self._locked:
|
||||
return
|
||||
|
||||
forward = direction == QAbstractAnimation.Direction.Forward
|
||||
forward = direction == QPropertyAnimation.Direction.Forward
|
||||
text = self._EXPANDED if forward else self._COLLAPSED
|
||||
|
||||
self._toggle_btn.setChecked(forward)
|
||||
@@ -120,9 +118,23 @@ class QCollapsible(QFrame):
|
||||
if animate:
|
||||
self._animation.setDirection(direction)
|
||||
self._animation.setEndValue(_content_height)
|
||||
self._is_animating = True
|
||||
self._animation.start()
|
||||
else:
|
||||
self._content.setMaximumHeight(_content_height if forward else 0)
|
||||
|
||||
def _toggle(self):
|
||||
self.expand() if self.isExpanded() else self.collapse()
|
||||
|
||||
def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
|
||||
"""If a child widget resizes, we need to update our expanded height."""
|
||||
if (
|
||||
a1.type() == QEvent.Type.Resize
|
||||
and self.isExpanded()
|
||||
and not self._is_animating
|
||||
):
|
||||
self._expand_collapse(QPropertyAnimation.Direction.Forward, animate=False)
|
||||
return False
|
||||
|
||||
def _on_animation_done(self):
|
||||
self._is_animating = False
|
||||
|
@@ -1,3 +1,4 @@
|
||||
from ._enum_combobox import QEnumComboBox
|
||||
from ._searchable_combo_box import QSearchableComboBox
|
||||
|
||||
__all__ = ("QEnumComboBox",)
|
||||
__all__ = ("QEnumComboBox", "QSearchableComboBox")
|
||||
|
48
src/superqt/combobox/_searchable_combo_box.py
Normal file
48
src/superqt/combobox/_searchable_combo_box.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from qtpy import QT_VERSION
|
||||
from qtpy.QtCore import Qt, Signal
|
||||
from qtpy.QtWidgets import QComboBox, QCompleter
|
||||
|
||||
try:
|
||||
is_qt_bellow_5_14 = tuple(int(x) for x in QT_VERSION.split(".")[:2]) < (5, 14)
|
||||
except ValueError:
|
||||
is_qt_bellow_5_14 = False
|
||||
|
||||
|
||||
class QSearchableComboBox(QComboBox):
|
||||
"""
|
||||
ComboCox with completer for fast search in multiple options
|
||||
"""
|
||||
|
||||
if is_qt_bellow_5_14:
|
||||
textActivated = Signal(str) # pragma: no cover
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setEditable(True)
|
||||
self.completer_object = QCompleter()
|
||||
self.completer_object.setCaseSensitivity(Qt.CaseInsensitive)
|
||||
self.completer_object.setCompletionMode(QCompleter.PopupCompletion)
|
||||
self.completer_object.setFilterMode(Qt.MatchContains)
|
||||
self.setCompleter(self.completer_object)
|
||||
self.setInsertPolicy(QComboBox.NoInsert)
|
||||
if is_qt_bellow_5_14: # pragma: no cover
|
||||
self.currentIndexChanged.connect(self._text_activated)
|
||||
|
||||
def _text_activated(self): # pragma: no cover
|
||||
self.textActivated.emit(self.currentText())
|
||||
|
||||
def addItem(self, *args):
|
||||
super().addItem(*args)
|
||||
self.completer_object.setModel(self.model())
|
||||
|
||||
def addItems(self, *args):
|
||||
super().addItems(*args)
|
||||
self.completer_object.setModel(self.model())
|
||||
|
||||
def insertItem(self, *args) -> None:
|
||||
super().insertItem(*args)
|
||||
self.completer_object.setModel(self.model())
|
||||
|
||||
def insertItems(self, *args) -> None:
|
||||
super().insertItems(*args)
|
||||
self.completer_object.setModel(self.model())
|
3
src/superqt/selection/__init__.py
Normal file
3
src/superqt/selection/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from ._searchable_list_widget import QSearchableListWidget
|
||||
|
||||
__all__ = ("QSearchableListWidget",)
|
46
src/superqt/selection/_searchable_list_widget.py
Normal file
46
src/superqt/selection/_searchable_list_widget.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QLineEdit, QListWidget, QVBoxLayout, QWidget
|
||||
|
||||
|
||||
class QSearchableListWidget(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.list_widget = QListWidget()
|
||||
|
||||
self.filter_widget = QLineEdit()
|
||||
self.filter_widget.textChanged.connect(self.update_visible)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.filter_widget)
|
||||
layout.addWidget(self.list_widget)
|
||||
self.setLayout(layout)
|
||||
|
||||
def __getattr__(self, item):
|
||||
if hasattr(self.list_widget, item):
|
||||
return getattr(self.list_widget, item)
|
||||
return super().__getattr__(item)
|
||||
|
||||
def update_visible(self, text):
|
||||
items_text = [
|
||||
x.text() for x in self.list_widget.findItems(text, Qt.MatchContains)
|
||||
]
|
||||
for index in range(self.list_widget.count()):
|
||||
item = self.item(index)
|
||||
item.setHidden(item.text() not in items_text)
|
||||
|
||||
def addItems(self, *args):
|
||||
self.list_widget.addItems(*args)
|
||||
self.update_visible(self.filter_widget.text())
|
||||
|
||||
def addItem(self, *args):
|
||||
self.list_widget.addItem(*args)
|
||||
self.update_visible(self.filter_widget.text())
|
||||
|
||||
def insertItems(self, *args):
|
||||
self.list_widget.insertItems(*args)
|
||||
self.update_visible(self.filter_widget.text())
|
||||
|
||||
def insertItem(self, *args):
|
||||
self.list_widget.insertItem(*args)
|
||||
self.update_visible(self.filter_widget.text())
|
@@ -137,8 +137,8 @@ class QLabeledSlider(_SliderProxy, QAbstractSlider):
|
||||
self._slider.sliderMoved.connect(self.sliderMoved.emit)
|
||||
self._slider.sliderPressed.connect(self.sliderPressed.emit)
|
||||
self._slider.sliderReleased.connect(self.sliderReleased.emit)
|
||||
self._slider.valueChanged.connect(self.valueChanged.emit)
|
||||
self._slider.valueChanged.connect(self._label.setValue)
|
||||
self._slider.valueChanged.connect(self.valueChanged.emit)
|
||||
|
||||
self.setOrientation(orientation)
|
||||
|
||||
|
35
tests/test_searchable_combobox.py
Normal file
35
tests/test_searchable_combobox.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from superqt import QSearchableComboBox
|
||||
|
||||
|
||||
class TestSearchableComboBox:
|
||||
def test_constructor(self, qtbot):
|
||||
widget = QSearchableComboBox()
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
def test_add_items(self, qtbot):
|
||||
widget = QSearchableComboBox()
|
||||
qtbot.addWidget(widget)
|
||||
widget.addItems(["foo", "bar"])
|
||||
assert widget.completer_object.model().rowCount() == 2
|
||||
widget.addItem("foobar")
|
||||
assert widget.completer_object.model().rowCount() == 3
|
||||
widget.insertItem(1, "baz")
|
||||
assert widget.completer_object.model().rowCount() == 4
|
||||
widget.insertItems(2, ["bazbar", "foobaz"])
|
||||
assert widget.completer_object.model().rowCount() == 6
|
||||
assert widget.itemText(0) == "foo"
|
||||
assert widget.itemText(1) == "baz"
|
||||
assert widget.itemText(2) == "bazbar"
|
||||
|
||||
def test_completion(self, qtbot):
|
||||
widget = QSearchableComboBox()
|
||||
qtbot.addWidget(widget)
|
||||
widget.addItems(["foo", "bar", "foobar", "baz", "bazbar", "foobaz"])
|
||||
|
||||
widget.completer_object.setCompletionPrefix("fo")
|
||||
assert widget.completer_object.completionCount() == 3
|
||||
assert widget.completer_object.currentCompletion() == "foo"
|
||||
widget.completer_object.setCurrentRow(1)
|
||||
assert widget.completer_object.currentCompletion() == "foobar"
|
||||
widget.completer_object.setCurrentRow(2)
|
||||
assert widget.completer_object.currentCompletion() == "foobaz"
|
34
tests/test_searchable_list.py
Normal file
34
tests/test_searchable_list.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from superqt import QSearchableListWidget
|
||||
|
||||
|
||||
class TestSearchableListWidget:
|
||||
def test_create(self, qtbot):
|
||||
widget = QSearchableListWidget()
|
||||
qtbot.addWidget(widget)
|
||||
widget.addItem("aaa")
|
||||
assert widget.count() == 1
|
||||
|
||||
def test_add_items(self, qtbot):
|
||||
widget = QSearchableListWidget()
|
||||
qtbot.addWidget(widget)
|
||||
widget.addItems(["foo", "bar"])
|
||||
assert widget.count() == 2
|
||||
widget.insertItems(1, ["baz", "foobaz"])
|
||||
widget.insertItem(2, "foobar")
|
||||
assert widget.count() == 5
|
||||
assert widget.item(0).text() == "foo"
|
||||
assert widget.item(1).text() == "baz"
|
||||
assert widget.item(2).text() == "foobar"
|
||||
|
||||
def test_completion(self, qtbot):
|
||||
widget = QSearchableListWidget()
|
||||
qtbot.addWidget(widget)
|
||||
widget.show()
|
||||
widget.addItems(["foo", "bar", "foobar", "baz", "bazbar", "foobaz"])
|
||||
widget.filter_widget.setText("fo")
|
||||
assert widget.count() == 6
|
||||
for i in range(widget.count()):
|
||||
item = widget.item(i)
|
||||
assert item.isHidden() == ("fo" not in item.text())
|
||||
|
||||
widget.hide()
|
@@ -4,7 +4,7 @@ from platform import system
|
||||
import pytest
|
||||
from qtpy import QT_VERSION
|
||||
from qtpy.QtCore import QEvent, QPoint, QPointF, Qt
|
||||
from qtpy.QtGui import QMouseEvent, QWheelEvent
|
||||
from qtpy.QtGui import QHoverEvent, QMouseEvent, QWheelEvent
|
||||
|
||||
QT_VERSION = tuple(int(x) for x in QT_VERSION.split("."))
|
||||
|
||||
@@ -68,6 +68,17 @@ def _wheel_event(arc):
|
||||
)
|
||||
|
||||
|
||||
def _hover_event(_type, position, old_position, widget=None):
|
||||
with suppress(TypeError):
|
||||
return QHoverEvent(
|
||||
_type,
|
||||
position,
|
||||
widget.mapToGlobal(position),
|
||||
old_position,
|
||||
)
|
||||
return QHoverEvent(_type, position, old_position)
|
||||
|
||||
|
||||
def _linspace(start, stop, n):
|
||||
h = (stop - start) / (n - 1)
|
||||
for i in range(n):
|
||||
|
@@ -3,12 +3,17 @@ import platform
|
||||
|
||||
import pytest
|
||||
from qtpy.QtCore import QEvent, QPoint, QPointF, Qt
|
||||
from qtpy.QtGui import QHoverEvent
|
||||
from qtpy.QtWidgets import QStyle, QStyleOptionSlider
|
||||
|
||||
from superqt.sliders._generic_slider import _GenericSlider, _sliderValueFromPosition
|
||||
|
||||
from ._testutil import _linspace, _mouse_event, _wheel_event, skip_on_linux_qt6
|
||||
from ._testutil import (
|
||||
_hover_event,
|
||||
_linspace,
|
||||
_mouse_event,
|
||||
_wheel_event,
|
||||
skip_on_linux_qt6,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(params=[Qt.Orientation.Horizontal, Qt.Orientation.Vertical])
|
||||
@@ -118,6 +123,7 @@ def test_press_move_release(gslider: _GenericSlider, qtbot):
|
||||
@skip_on_linux_qt6
|
||||
def test_hover(gslider: _GenericSlider):
|
||||
|
||||
# stub
|
||||
opt = QStyleOptionSlider()
|
||||
gslider.initStyleOption(opt)
|
||||
style = gslider.style()
|
||||
@@ -128,11 +134,11 @@ def test_hover(gslider: _GenericSlider):
|
||||
|
||||
assert gslider._hoverControl == QStyle.SubControl.SC_None
|
||||
|
||||
gslider.event(QHoverEvent(QEvent.Type.HoverEnter, handle_pos, QPointF()))
|
||||
gslider.event(_hover_event(QEvent.Type.HoverEnter, handle_pos, QPointF(), gslider))
|
||||
assert gslider._hoverControl == QStyle.SubControl.SC_SliderHandle
|
||||
|
||||
gslider.event(
|
||||
QHoverEvent(QEvent.Type.HoverLeave, QPointF(-1000, -1000), handle_pos)
|
||||
_hover_event(QEvent.Type.HoverLeave, QPointF(-1000, -1000), handle_pos, gslider)
|
||||
)
|
||||
assert gslider._hoverControl == QStyle.SubControl.SC_None
|
||||
|
||||
|
@@ -2,12 +2,17 @@ import math
|
||||
|
||||
import pytest
|
||||
from qtpy.QtCore import QEvent, QPoint, QPointF, Qt
|
||||
from qtpy.QtGui import QHoverEvent
|
||||
from qtpy.QtWidgets import QStyle, QStyleOptionSlider
|
||||
|
||||
from superqt import QDoubleRangeSlider, QRangeSlider
|
||||
|
||||
from ._testutil import _linspace, _mouse_event, _wheel_event, skip_on_linux_qt6
|
||||
from ._testutil import (
|
||||
_hover_event,
|
||||
_linspace,
|
||||
_mouse_event,
|
||||
_wheel_event,
|
||||
skip_on_linux_qt6,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(params=[Qt.Orientation.Horizontal, Qt.Orientation.Vertical])
|
||||
@@ -153,11 +158,11 @@ def test_hover(gslider: QRangeSlider):
|
||||
|
||||
assert gslider._hoverControl == QStyle.SubControl.SC_None
|
||||
|
||||
gslider.event(QHoverEvent(QEvent.Type.HoverEnter, handle_pos, QPointF()))
|
||||
gslider.event(_hover_event(QEvent.Type.HoverEnter, handle_pos, QPointF(), gslider))
|
||||
assert gslider._hoverControl == QStyle.SubControl.SC_SliderHandle
|
||||
|
||||
gslider.event(
|
||||
QHoverEvent(QEvent.Type.HoverLeave, QPointF(-1000, -1000), handle_pos)
|
||||
_hover_event(QEvent.Type.HoverLeave, QPointF(-1000, -1000), handle_pos, gslider)
|
||||
)
|
||||
assert gslider._hoverControl == QStyle.SubControl.SC_None
|
||||
|
||||
|
@@ -4,7 +4,6 @@ from contextlib import suppress
|
||||
|
||||
import pytest
|
||||
from qtpy.QtCore import QEvent, QPoint, QPointF, Qt
|
||||
from qtpy.QtGui import QHoverEvent
|
||||
from qtpy.QtWidgets import QSlider, QStyle, QStyleOptionSlider
|
||||
|
||||
from superqt import QDoubleSlider, QLabeledDoubleSlider, QLabeledSlider
|
||||
@@ -12,6 +11,7 @@ from superqt.sliders._generic_slider import _GenericSlider
|
||||
|
||||
from ._testutil import (
|
||||
QT_VERSION,
|
||||
_hover_event,
|
||||
_linspace,
|
||||
_mouse_event,
|
||||
_wheel_event,
|
||||
@@ -167,12 +167,12 @@ def test_hover(sld: _GenericSlider):
|
||||
with suppress(AttributeError): # for QSlider
|
||||
assert _real_sld._hoverControl == QStyle.SubControl.SC_None
|
||||
|
||||
_real_sld.event(QHoverEvent(QEvent.Type.HoverEnter, handle_pos, QPointF()))
|
||||
_real_sld.event(_hover_event(QEvent.Type.HoverEnter, handle_pos, QPointF(), sld))
|
||||
with suppress(AttributeError): # for QSlider
|
||||
assert _real_sld._hoverControl == QStyle.SubControl.SC_SliderHandle
|
||||
|
||||
_real_sld.event(
|
||||
QHoverEvent(QEvent.Type.HoverLeave, QPointF(-1000, -1000), handle_pos)
|
||||
_hover_event(QEvent.Type.HoverLeave, QPointF(-1000, -1000), handle_pos, sld)
|
||||
)
|
||||
with suppress(AttributeError): # for QSlider
|
||||
assert _real_sld._hoverControl == QStyle.SubControl.SC_None
|
||||
|
Reference in New Issue
Block a user