Move to to qwidgets
commit 466fc7c19ace1343d23739e4058758cd21328511 Author: Talley Lambert <talley.lambert@gmail.com> Date: Wed Jun 2 20:22:38 2021 -0400 add deploy cond commit e9965e71490689935b61099225acc7f3bf5c2d48 Author: Talley Lambert <talley.lambert@gmail.com> Date: Wed Jun 2 20:20:45 2021 -0400 more precommit commit b39150b16d7d64a5530ec9a0e29e673e2b6ed0a4 Author: Talley Lambert <talley.lambert@gmail.com> Date: Wed Jun 2 19:52:42 2021 -0400 updating precommit commit d5018b38e7bc59f81cc161cca06fae829e493e3c Author: Talley Lambert <talley.lambert@gmail.com> Date: Wed Jun 2 19:42:32 2021 -0400 big reorg
11
.coveragerc
@@ -1,11 +0,0 @@
|
|||||||
[report]
|
|
||||||
exclude_lines =
|
|
||||||
pragma: no cover
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
\.\.\.
|
|
||||||
except ImportError*
|
|
||||||
raise NotImplementedError()
|
|
||||||
omit =
|
|
||||||
qtrangeslider/_version.py
|
|
||||||
qtrangeslider/qtcompat/*
|
|
||||||
*_tests*
|
|
||||||
7
.github/workflows/test_and_deploy.yml
vendored
@@ -89,6 +89,7 @@ jobs:
|
|||||||
sudo apt-get install -y libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 \
|
sudo apt-get install -y libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 \
|
||||||
libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \
|
libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \
|
||||||
libxcb-xinerama0 libxcb-xfixes0
|
libxcb-xinerama0 libxcb-xfixes0
|
||||||
|
|
||||||
- name: Linux opengl
|
- name: Linux opengl
|
||||||
if: runner.os == 'Linux' && ( matrix.backend == 'pyside6' || matrix.backend == 'pyqt6' )
|
if: runner.os == 'Linux' && ( matrix.backend == 'pyside6' || matrix.backend == 'pyqt6' )
|
||||||
run: sudo apt-get install -y libopengl0 libegl1-mesa libxcb-xinput0
|
run: sudo apt-get install -y libopengl0 libegl1-mesa libxcb-xinput0
|
||||||
@@ -111,13 +112,13 @@ jobs:
|
|||||||
if: matrix.screenshot
|
if: matrix.screenshot
|
||||||
run: pip install . ${{ matrix.backend }}
|
run: pip install . ${{ matrix.backend }}
|
||||||
|
|
||||||
- name: Screenshots
|
- name: Screenshots (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.screenshot
|
if: runner.os == 'Linux' && matrix.screenshot
|
||||||
uses: GabrielBB/xvfb-action@v1
|
uses: GabrielBB/xvfb-action@v1
|
||||||
with:
|
with:
|
||||||
run: python examples/demo_widget.py -snap
|
run: python examples/demo_widget.py -snap
|
||||||
|
|
||||||
- name: Screenshots
|
- name: Screenshots (macOS/Win)
|
||||||
if: runner.os != 'Linux' && matrix.screenshot
|
if: runner.os != 'Linux' && matrix.screenshot
|
||||||
run: python examples/demo_widget.py -snap
|
run: python examples/demo_widget.py -snap
|
||||||
|
|
||||||
@@ -133,8 +134,8 @@ jobs:
|
|||||||
# and requires that you have put your twine API key in your
|
# and requires that you have put your twine API key in your
|
||||||
# github secrets (see readme for details)
|
# github secrets (see readme for details)
|
||||||
needs: [test]
|
needs: [test]
|
||||||
|
if: ${{ github.repository == 'napari/qwidgets' && contains(github.ref, 'tags') }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: contains(github.ref, 'tags')
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
|
|||||||
@@ -4,20 +4,32 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
|
rev: v1.17.0
|
||||||
|
hooks:
|
||||||
|
- id: setup-cfg-fmt
|
||||||
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: 3.9.2
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
additional_dependencies:
|
||||||
|
[flake8-typing-imports==1.7.0]
|
||||||
|
exclude: examples
|
||||||
|
- repo: https://github.com/myint/autoflake
|
||||||
|
rev: v1.4
|
||||||
|
hooks:
|
||||||
|
- id: autoflake
|
||||||
|
args: ["--in-place", "--remove-all-unused-imports"]
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.8.0
|
rev: 5.8.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.19.0
|
rev: v2.19.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
|
args: [--py37-plus]
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 21.5b2
|
rev: 21.5b2
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
- repo: https://github.com/PyCQA/flake8
|
|
||||||
rev: 3.9.2
|
|
||||||
hooks:
|
|
||||||
- id: flake8
|
|
||||||
pass_filenames: true
|
|
||||||
|
|||||||
54
CONTRIBUTING.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Contributing to this repository
|
||||||
|
|
||||||
|
This repository seeks to accumulate Qt-based widgets for python (PyQt & PySide)
|
||||||
|
that are not provided in the native QtWidgets module.
|
||||||
|
|
||||||
|
## Clone
|
||||||
|
|
||||||
|
To get started fork this repository, and clone your fork:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# clone your fork
|
||||||
|
git clone https://github.com/<your_organization>/qwidgets
|
||||||
|
cd qwidgets
|
||||||
|
|
||||||
|
# install pre-commit hooks
|
||||||
|
pre-commit install
|
||||||
|
|
||||||
|
# install in editable mode
|
||||||
|
pip install -e .[dev]
|
||||||
|
|
||||||
|
# run tests & make sure everything is working!
|
||||||
|
pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Targeted platforms
|
||||||
|
|
||||||
|
All widgets must be well-tested, and should work on:
|
||||||
|
|
||||||
|
- Python 3.7 and above
|
||||||
|
- PyQt5 (5.11 and above) & PyQt6
|
||||||
|
- PySide2 (5.11 and above) & PySide6
|
||||||
|
- macOS, Windows, & Linux
|
||||||
|
|
||||||
|
Until [qtpy](https://github.com/spyder-ide/qtpy) supports PyQt6/PySide6, imports
|
||||||
|
should use (and modify if necessary) `qwidgets.qtcompat`.
|
||||||
|
|
||||||
|
## Style Guide
|
||||||
|
|
||||||
|
All widgets should try to match the native Qt API as much as possible:
|
||||||
|
|
||||||
|
- Methods should use `camelCase` naming.
|
||||||
|
- Getters/setters use the `attribute()/setAttribute()` pattern.
|
||||||
|
- Private methods should use `_camelCaseNaming`.
|
||||||
|
- `__init__` methods should be like Qt constructors, meaning they often don't
|
||||||
|
include parameters for most of the widgets properties.
|
||||||
|
- When possible, widgets should inherit from the most similar native widget
|
||||||
|
available. It should strictly match the Qt API where it exists, and attempt to
|
||||||
|
cover as much of the native API as possible; this includes properties, public
|
||||||
|
functions, signals, and public slots.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Tests can be run in the current environment with `pytest`. Or, to run tests
|
||||||
|
against all supported python & Qt versions, run `tox`.
|
||||||
2
LICENSE
@@ -12,7 +12,7 @@ modification, are permitted provided that the following conditions are met:
|
|||||||
this list of conditions and the following disclaimer in the documentation
|
this list of conditions and the following disclaimer in the documentation
|
||||||
and/or other materials provided with the distribution.
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
* Neither the name of QtRangeSlider nor the names of its
|
* Neither the name of qwidgets nor the names of its
|
||||||
contributors may be used to endorse or promote products derived from
|
contributors may be used to endorse or promote products derived from
|
||||||
this software without specific prior written permission.
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
|||||||
271
README.md
@@ -1,262 +1,27 @@
|
|||||||
# QtRangeSlider
|
# qwidgets
|
||||||
|
|
||||||
[](https://github.com/tlambert03/QtRangeSlider/raw/master/LICENSE)
|
**Missing widgets for PyQt/PySide**
|
||||||
[](https://pypi.org/project/QtRangeSlider)
|
|
||||||
|
[](https://github.com/napari/qwidgets/raw/master/LICENSE)
|
||||||
|
[](https://pypi.org/project/qwidgets)
|
||||||
[](https://python.org)
|
Version](https://img.shields.io/pypi/pyversions/qwidgets.svg?color=green)](https://python.org)
|
||||||
[](https://github.com/tlambert03/QtRangeSlider/actions/workflows/test_and_deploy.yml)
|
[](https://github.com/napari/qwidgets/actions/workflows/test_and_deploy.yml)
|
||||||
[](https://codecov.io/gh/tlambert03/QtRangeSlider)
|
[](https://codecov.io/gh/napari/qwidgets)
|
||||||
|
|
||||||
**The missing multi-handle range slider widget for PyQt & PySide**
|
|
||||||
|
|
||||||

|
## Widgets
|
||||||
|
|
||||||
The goal of this package is to provide a Range Slider (a slider with 2 or more
|
Widgets include:
|
||||||
handles) that feels as "native" as possible. Styles should match the OS by
|
|
||||||
default, and the slider should behave like a standard
|
|
||||||
[`QSlider`](https://doc.qt.io/qt-5/qslider.html)... but with multiple handles!
|
|
||||||
|
|
||||||
- `QRangeSlider` inherits from [`QSlider`](https://doc.qt.io/qt-5/qslider.html)
|
- Float Slider
|
||||||
and attempts to match the Qt API as closely as possible
|
- Range Slider (multi-handle slider)
|
||||||
- Uses platform-specific styles (for handle, groove, & ticks) but also supports
|
- Labeled Sliders (sliders with linked spinboxes)
|
||||||
QSS style sheets.
|
- Unbound Integer SpinBox (backed by python `int`)
|
||||||
- Supports mouse wheel and keypress (soon) events
|
|
||||||
- Supports PyQt5, PyQt6, PySide2 and PySide6
|
|
||||||
- Supports more than 2 handles (e.g. `slider.setValue([0, 10, 60, 80])`)
|
|
||||||
|
|
||||||
## Installation
|
## Contributing
|
||||||
|
|
||||||
You can install `QtRangeSlider` via pip:
|
This repository seeks to accumulate Qt-based widgets for python (PyQt & PySide)
|
||||||
|
that are not provided in the native QtWidgets module. We welcome contributions!
|
||||||
|
|
||||||
```sh
|
Please see the [Contributing Guide](CONTRIBUTING.md)
|
||||||
pip install qtrangeslider
|
|
||||||
|
|
||||||
# NOTE: you must also install a Qt Backend.
|
|
||||||
# PyQt5, PySide2, PyQt6, and PySide6 are supported
|
|
||||||
# As a convenience you can install them as extras:
|
|
||||||
pip install qtrangeslider[pyqt5]
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
To create a slider:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from qtrangeslider import QRangeSlider
|
|
||||||
|
|
||||||
# as usual:
|
|
||||||
# you must create a QApplication before create a widget.
|
|
||||||
range_slider = QRangeSlider()
|
|
||||||
```
|
|
||||||
|
|
||||||
As `QRangeSlider` inherits from `QtWidgets.QSlider`, you can use all of the
|
|
||||||
same methods available in the [QSlider API](https://doc.qt.io/qt-5/qslider.html). The major difference is that `value` and `sliderPosition` are reimplemented as `tuples` of `int` (where the length of the tuple is equal to the number of handles in the slider.)
|
|
||||||
|
|
||||||
### `value: Tuple[int, ...]`
|
|
||||||
|
|
||||||
This property holds the current value of all handles in the slider.
|
|
||||||
|
|
||||||
The slider forces all values to be within the legal range:
|
|
||||||
`minimum <= value <= maximum`.
|
|
||||||
|
|
||||||
Changing the value also changes the sliderPosition.
|
|
||||||
|
|
||||||
##### Access Functions:
|
|
||||||
|
|
||||||
```python
|
|
||||||
range_slider.value() -> Tuple[int, ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
range_slider.setValue(val: Sequence[int]) -> None
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Notifier Signal:
|
|
||||||
|
|
||||||
```python
|
|
||||||
valueChanged(Tuple[int, ...])
|
|
||||||
```
|
|
||||||
|
|
||||||
### `sliderPosition: Tuple[int, ...]`
|
|
||||||
|
|
||||||
This property holds the current slider positions. It is a `tuple` with length equal to the number of handles.
|
|
||||||
|
|
||||||
If [tracking](https://doc.qt.io/qt-5/qabstractslider.html#tracking-prop) is enabled (the default), this is identical to [`value`](#value--tupleint-).
|
|
||||||
|
|
||||||
##### Access Functions:
|
|
||||||
|
|
||||||
```python
|
|
||||||
range_slider.sliderPosition() -> Tuple[int, ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
range_slider.setSliderPosition(val: Sequence[int]) -> None
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Notifier Signal:
|
|
||||||
|
|
||||||
```python
|
|
||||||
sliderMoved(Tuple[int, ...])
|
|
||||||
```
|
|
||||||
|
|
||||||
### Additional properties
|
|
||||||
|
|
||||||
These options are in addition to the Qt QSlider API, and control the behavior of the bar between handles.
|
|
||||||
|
|
||||||
| getter | setter | type | default | description |
|
|
||||||
| -------------------- | ------------------------------------------- | ------ | ------- | ------------------------------------------------------------------------------------------------ |
|
|
||||||
| `barIsVisible` | `setBarIsVisible` <br>`hideBar` / `showBar` | `bool` | `True` | <small>Whether the bar between handles is visible.</small> |
|
|
||||||
| `barMovesAllHandles` | `setBarMovesAllHandles` | `bool` | `True` | <small>Whether clicking on the bar moves all handles or just the nearest</small> |
|
|
||||||
| `barIsRigid` | `setBarIsRigid` | `bool` | `True` | <small>Whether bar length is constant or "elastic" when dragging the bar beyond min/max.</small> |
|
|
||||||
------
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
These screenshots show `QRangeSlider` (multiple handles) next to the native `QSlider`
|
|
||||||
(single handle). With no styles applied, `QRangeSlider` will match the native OS
|
|
||||||
style of `QSlider` – with or without tick marks. When styles have been applied
|
|
||||||
using [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet-reference.html), then
|
|
||||||
`QRangeSlider` will inherit any styles applied to `QSlider` (since it inherits
|
|
||||||
from QSlider). If you'd like to style `QRangeSlider` differently than `QSlider`,
|
|
||||||
then you can also target it directly in your style sheet. The one "special"
|
|
||||||
property for QRangeSlider is `qproperty-barColor`, which sets the color of the
|
|
||||||
bar between the handles.
|
|
||||||
|
|
||||||
> The code for these example widgets is [here](examples/demo_widget.py)
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary><em>See style sheet used for this example</em></summary>
|
|
||||||
|
|
||||||
```css
|
|
||||||
/*
|
|
||||||
Because QRangeSlider inherits from QSlider, it will also inherit styles
|
|
||||||
*/
|
|
||||||
QSlider {
|
|
||||||
min-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSlider::groove:horizontal {
|
|
||||||
border: 0px;
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
|
|
||||||
stop:0 #777, stop:1 #aaa);
|
|
||||||
height: 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSlider::handle {
|
|
||||||
background: qradialgradient(cx:0, cy:0, radius: 1.2, fx:0.5,
|
|
||||||
fy:0.5, stop:0 #eef, stop:1 #000);
|
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
"QSlider::sub-page" is the one exception ...
|
|
||||||
(it styles the area to the left of the QSlider handle)
|
|
||||||
*/
|
|
||||||
QSlider::sub-page:horizontal {
|
|
||||||
background: #447;
|
|
||||||
border-top-left-radius: 10px;
|
|
||||||
border-bottom-left-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
for QRangeSlider: use "qproperty-barColor". "sub-page" will not work.
|
|
||||||
*/
|
|
||||||
QRangeSlider {
|
|
||||||
qproperty-barColor: #447;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
|
|
||||||
##### Catalina
|
|
||||||

|
|
||||||
|
|
||||||
##### Big Sur
|
|
||||||

|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Linux
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## Labeled Sliders
|
|
||||||
|
|
||||||
This package also includes two "labeled" slider variants. One for `QRangeSlider`, and one for the native `QSlider`:
|
|
||||||
|
|
||||||
### `QLabeledRangeSlider`
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
```python
|
|
||||||
from qtrangeslider import QLabeledRangeSlider
|
|
||||||
```
|
|
||||||
|
|
||||||
This has the same API as `QRangeSlider` with the following additional options:
|
|
||||||
|
|
||||||
#### `handleLabelPosition`/`setHandleLabelPosition`
|
|
||||||
|
|
||||||
Where/whether labels are shown adjacent to slider handles.
|
|
||||||
|
|
||||||
**type:** `QLabeledRangeSlider.LabelPosition`
|
|
||||||
|
|
||||||
**default:** `LabelPosition.LabelsAbove`
|
|
||||||
|
|
||||||
*options:*
|
|
||||||
|
|
||||||
- `LabelPosition.NoLabel` (no labels shown adjacent to handles)
|
|
||||||
- `LabelPosition.LabelsAbove`
|
|
||||||
- `LabelPosition.LabelsBelow`
|
|
||||||
- `LabelPosition.LabelsRight` (alias for `LabelPosition.LabelsAbove`)
|
|
||||||
- `LabelPosition.LabelsLeft` (alias for `LabelPosition.LabelsBelow`)
|
|
||||||
|
|
||||||
|
|
||||||
#### `edgeLabelMode`/`setEdgeLabelMode`
|
|
||||||
|
|
||||||
**type:** `QLabeledRangeSlider.EdgeLabelMode`
|
|
||||||
|
|
||||||
**default:** `EdgeLabelMode.LabelIsRange`
|
|
||||||
|
|
||||||
*options:*
|
|
||||||
|
|
||||||
- `EdgeLabelMode.NoLabel`: no labels shown at slider extremes
|
|
||||||
- `EdgeLabelMode.LabelIsRange`: edge labels shown the min/max values
|
|
||||||
- `EdgeLabelMode.LabelIsValue`: edge labels shown the slider range
|
|
||||||
|
|
||||||
|
|
||||||
#### fine tuning position of labels:
|
|
||||||
|
|
||||||
If you find that you need to fine tune the position of the handle labels:
|
|
||||||
|
|
||||||
- `QLabeledRangeSlider.label_shift_x`: adjust horizontal label position
|
|
||||||
- `QLabeledRangeSlider.label_shift_y`: adjust vertical label position
|
|
||||||
|
|
||||||
### `QLabeledSlider`
|
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
```python
|
|
||||||
from qtrangeslider import QLabeledSlider
|
|
||||||
```
|
|
||||||
|
|
||||||
(no additional options at this point)
|
|
||||||
|
|
||||||
## Issues
|
|
||||||
|
|
||||||
If you encounter any problems, please [file an issue] along with a detailed
|
|
||||||
description.
|
|
||||||
|
|
||||||
[file an issue]: https://github.com/tlambert03/QtRangeSlider/issues
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
ignore:
|
ignore:
|
||||||
- qtrangeslider/_version.py
|
- qwidgets/_version.py
|
||||||
- qtrangeslider/qtcompat/*
|
- qwidgets/qtcompat/*
|
||||||
- '*_tests*'
|
- '*_tests*'
|
||||||
coverage:
|
coverage:
|
||||||
status:
|
status:
|
||||||
|
|||||||
235
docs/RangeSlider.md
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
# QRangeSlider
|
||||||
|
|
||||||
|
**The missing multi-handle range slider widget for PyQt & PySide**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- `QRangeSlider` inherits from [`QSlider`](https://doc.qt.io/qt-5/qslider.html)
|
||||||
|
and attempts to match the Qt API as closely as possible
|
||||||
|
- Uses platform-specific styles (for handle, groove, & ticks) but also supports
|
||||||
|
QSS style sheets.
|
||||||
|
- Supports mouse wheel and keypress (soon) events
|
||||||
|
- Supports more than 2 handles (e.g. `slider.setValue([0, 10, 60, 80])`)
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
To create a slider:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from qwidgets import QRangeSlider
|
||||||
|
|
||||||
|
# as usual:
|
||||||
|
# you must create a QApplication before create a widget.
|
||||||
|
range_slider = QRangeSlider()
|
||||||
|
```
|
||||||
|
|
||||||
|
As `QRangeSlider` inherits from `QtWidgets.QSlider`, you can use all of the
|
||||||
|
same methods available in the [QSlider API](https://doc.qt.io/qt-5/qslider.html). The major difference is that `value` and `sliderPosition` are reimplemented as `tuples` of `int` (where the length of the tuple is equal to the number of handles in the slider.)
|
||||||
|
|
||||||
|
### `value: Tuple[int, ...]`
|
||||||
|
|
||||||
|
This property holds the current value of all handles in the slider.
|
||||||
|
|
||||||
|
The slider forces all values to be within the legal range:
|
||||||
|
`minimum <= value <= maximum`.
|
||||||
|
|
||||||
|
Changing the value also changes the sliderPosition.
|
||||||
|
|
||||||
|
##### Access Functions:
|
||||||
|
|
||||||
|
```python
|
||||||
|
range_slider.value() -> Tuple[int, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
range_slider.setValue(val: Sequence[int]) -> None
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Notifier Signal:
|
||||||
|
|
||||||
|
```python
|
||||||
|
valueChanged(Tuple[int, ...])
|
||||||
|
```
|
||||||
|
|
||||||
|
### `sliderPosition: Tuple[int, ...]`
|
||||||
|
|
||||||
|
This property holds the current slider positions. It is a `tuple` with length equal to the number of handles.
|
||||||
|
|
||||||
|
If [tracking](https://doc.qt.io/qt-5/qabstractslider.html#tracking-prop) is enabled (the default), this is identical to [`value`](#value--tupleint-).
|
||||||
|
|
||||||
|
##### Access Functions:
|
||||||
|
|
||||||
|
```python
|
||||||
|
range_slider.sliderPosition() -> Tuple[int, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
range_slider.setSliderPosition(val: Sequence[int]) -> None
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Notifier Signal:
|
||||||
|
|
||||||
|
```python
|
||||||
|
sliderMoved(Tuple[int, ...])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Additional properties
|
||||||
|
|
||||||
|
These options are in addition to the Qt QSlider API, and control the behavior of the bar between handles.
|
||||||
|
|
||||||
|
| getter | setter | type | default | description |
|
||||||
|
| -------------------- | ------------------------------------------- | ------ | ------- | ------------------------------------------------------------------------------------------------ |
|
||||||
|
| `barIsVisible` | `setBarIsVisible` <br>`hideBar` / `showBar` | `bool` | `True` | <small>Whether the bar between handles is visible.</small> |
|
||||||
|
| `barMovesAllHandles` | `setBarMovesAllHandles` | `bool` | `True` | <small>Whether clicking on the bar moves all handles or just the nearest</small> |
|
||||||
|
| `barIsRigid` | `setBarIsRigid` | `bool` | `True` | <small>Whether bar length is constant or "elastic" when dragging the bar beyond min/max.</small> |
|
||||||
|
------
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
These screenshots show `QRangeSlider` (multiple handles) next to the native `QSlider`
|
||||||
|
(single handle). With no styles applied, `QRangeSlider` will match the native OS
|
||||||
|
style of `QSlider` – with or without tick marks. When styles have been applied
|
||||||
|
using [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet-reference.html), then
|
||||||
|
`QRangeSlider` will inherit any styles applied to `QSlider` (since it inherits
|
||||||
|
from QSlider). If you'd like to style `QRangeSlider` differently than `QSlider`,
|
||||||
|
then you can also target it directly in your style sheet. The one "special"
|
||||||
|
property for QRangeSlider is `qproperty-barColor`, which sets the color of the
|
||||||
|
bar between the handles.
|
||||||
|
|
||||||
|
> The code for these example widgets is [here](examples/demo_widget.py)
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><em>See style sheet used for this example</em></summary>
|
||||||
|
|
||||||
|
```css
|
||||||
|
/*
|
||||||
|
Because QRangeSlider inherits from QSlider, it will also inherit styles
|
||||||
|
*/
|
||||||
|
QSlider {
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSlider::groove:horizontal {
|
||||||
|
border: 0px;
|
||||||
|
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
|
||||||
|
stop:0 #777, stop:1 #aaa);
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSlider::handle {
|
||||||
|
background: qradialgradient(cx:0, cy:0, radius: 1.2, fx:0.5,
|
||||||
|
fy:0.5, stop:0 #eef, stop:1 #000);
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
"QSlider::sub-page" is the one exception ...
|
||||||
|
(it styles the area to the left of the QSlider handle)
|
||||||
|
*/
|
||||||
|
QSlider::sub-page:horizontal {
|
||||||
|
background: #447;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
for QRangeSlider: use "qproperty-barColor". "sub-page" will not work.
|
||||||
|
*/
|
||||||
|
QRangeSlider {
|
||||||
|
qproperty-barColor: #447;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
##### Catalina
|
||||||
|

|
||||||
|
|
||||||
|
##### Big Sur
|
||||||
|

|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## Labeled Sliders
|
||||||
|
|
||||||
|
This package also includes two "labeled" slider variants. One for `QRangeSlider`, and one for the native `QSlider`:
|
||||||
|
|
||||||
|
### `QLabeledRangeSlider`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```python
|
||||||
|
from qwidgets import QLabeledRangeSlider
|
||||||
|
```
|
||||||
|
|
||||||
|
This has the same API as `QRangeSlider` with the following additional options:
|
||||||
|
|
||||||
|
#### `handleLabelPosition`/`setHandleLabelPosition`
|
||||||
|
|
||||||
|
Where/whether labels are shown adjacent to slider handles.
|
||||||
|
|
||||||
|
**type:** `QLabeledRangeSlider.LabelPosition`
|
||||||
|
|
||||||
|
**default:** `LabelPosition.LabelsAbove`
|
||||||
|
|
||||||
|
*options:*
|
||||||
|
|
||||||
|
- `LabelPosition.NoLabel` (no labels shown adjacent to handles)
|
||||||
|
- `LabelPosition.LabelsAbove`
|
||||||
|
- `LabelPosition.LabelsBelow`
|
||||||
|
- `LabelPosition.LabelsRight` (alias for `LabelPosition.LabelsAbove`)
|
||||||
|
- `LabelPosition.LabelsLeft` (alias for `LabelPosition.LabelsBelow`)
|
||||||
|
|
||||||
|
|
||||||
|
#### `edgeLabelMode`/`setEdgeLabelMode`
|
||||||
|
|
||||||
|
**type:** `QLabeledRangeSlider.EdgeLabelMode`
|
||||||
|
|
||||||
|
**default:** `EdgeLabelMode.LabelIsRange`
|
||||||
|
|
||||||
|
*options:*
|
||||||
|
|
||||||
|
- `EdgeLabelMode.NoLabel`: no labels shown at slider extremes
|
||||||
|
- `EdgeLabelMode.LabelIsRange`: edge labels shown the min/max values
|
||||||
|
- `EdgeLabelMode.LabelIsValue`: edge labels shown the slider range
|
||||||
|
|
||||||
|
|
||||||
|
#### fine tuning position of labels:
|
||||||
|
|
||||||
|
If you find that you need to fine tune the position of the handle labels:
|
||||||
|
|
||||||
|
- `QLabeledRangeSlider.label_shift_x`: adjust horizontal label position
|
||||||
|
- `QLabeledRangeSlider.label_shift_y`: adjust vertical label position
|
||||||
|
|
||||||
|
### `QLabeledSlider`
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```python
|
||||||
|
from qwidgets import QLabeledSlider
|
||||||
|
```
|
||||||
|
|
||||||
|
(no additional options at this point)
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
If you encounter any problems, please [file an issue] along with a detailed
|
||||||
|
description.
|
||||||
|
|
||||||
|
[file an issue]: https://github.com/napari/qwidgets/issues
|
||||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
@@ -1,6 +1,6 @@
|
|||||||
from qtrangeslider import QRangeSlider
|
from qwidgets import QRangeSlider
|
||||||
from qtrangeslider.qtcompat.QtCore import Qt
|
from qwidgets.qtcompat.QtCore import Qt
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QApplication
|
from qwidgets.qtcompat.QtWidgets import QApplication
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from qtrangeslider import QDoubleSlider
|
from qwidgets import QDoubleSlider
|
||||||
from qtrangeslider.qtcompat.QtCore import Qt
|
from qwidgets.qtcompat.QtCore import Qt
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QApplication
|
from qwidgets.qtcompat.QtWidgets import QApplication
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from qtrangeslider import QRangeSlider
|
from qwidgets import QRangeSlider
|
||||||
from qtrangeslider.qtcompat import QtCore
|
from qwidgets.qtcompat import QtCore
|
||||||
from qtrangeslider.qtcompat import QtWidgets as QtW
|
from qwidgets.qtcompat import QtWidgets as QtW
|
||||||
|
|
||||||
QSS = """
|
QSS = """
|
||||||
QSlider {
|
QSlider {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from qtrangeslider import QDoubleRangeSlider, QDoubleSlider, QRangeSlider
|
from qwidgets import QDoubleRangeSlider, QDoubleSlider, QRangeSlider
|
||||||
from qtrangeslider.qtcompat.QtCore import Qt
|
from qwidgets.qtcompat.QtCore import Qt
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QApplication, QVBoxLayout, QWidget
|
from qwidgets.qtcompat.QtWidgets import QApplication, QVBoxLayout, QWidget
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from qtrangeslider import QDoubleSlider
|
from qwidgets import QDoubleSlider
|
||||||
from qtrangeslider.qtcompat.QtCore import Qt
|
from qwidgets.qtcompat.QtCore import Qt
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QApplication
|
from qwidgets.qtcompat.QtWidgets import QApplication
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
from qtrangeslider._labeled import (
|
from qwidgets import (
|
||||||
QLabeledDoubleRangeSlider,
|
QLabeledDoubleRangeSlider,
|
||||||
QLabeledDoubleSlider,
|
QLabeledDoubleSlider,
|
||||||
QLabeledRangeSlider,
|
QLabeledRangeSlider,
|
||||||
QLabeledSlider,
|
QLabeledSlider,
|
||||||
)
|
)
|
||||||
from qtrangeslider.qtcompat.QtCore import Qt
|
from qwidgets.qtcompat.QtCore import Qt
|
||||||
from qtrangeslider.qtcompat.QtWidgets import (
|
from qwidgets.qtcompat.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QWidget
|
||||||
QApplication,
|
|
||||||
QHBoxLayout,
|
|
||||||
QVBoxLayout,
|
|
||||||
QWidget,
|
|
||||||
)
|
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from qtrangeslider import QRangeSlider
|
from qwidgets import QRangeSlider
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QApplication
|
from qwidgets.qtcompat.QtWidgets import QApplication
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
||||||
|
|||||||
26
qwidgets/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"""qwidgets is a collection of QtWidgets for python."""
|
||||||
|
try:
|
||||||
|
from ._version import version as __version__
|
||||||
|
except ImportError:
|
||||||
|
__version__ = "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
from .sliders import (
|
||||||
|
QDoubleRangeSlider,
|
||||||
|
QDoubleSlider,
|
||||||
|
QLabeledDoubleRangeSlider,
|
||||||
|
QLabeledDoubleSlider,
|
||||||
|
QLabeledRangeSlider,
|
||||||
|
QLabeledSlider,
|
||||||
|
QRangeSlider,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"QDoubleRangeSlider",
|
||||||
|
"QDoubleSlider",
|
||||||
|
"QLabeledDoubleRangeSlider",
|
||||||
|
"QLabeledDoubleSlider",
|
||||||
|
"QLabeledRangeSlider",
|
||||||
|
"QLabeledSlider",
|
||||||
|
"QRangeSlider",
|
||||||
|
]
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Copyright © 2014-2015 Colin Duquesnoy
|
# Copyright © 2014-2015 Colin Duquesnoy
|
||||||
# Copyright © 2009- The Spyder Development Team
|
# Copyright © 2009- The Spyder Development Team
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Copyright © 2014-2015 Colin Duquesnoy
|
# Copyright © 2014-2015 Colin Duquesnoy
|
||||||
# Copyright © 2009- The Spyder Development Team
|
# Copyright © 2009- The Spyder Development Team
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Copyright © 2014-2015 Colin Duquesnoy
|
# Copyright © 2014-2015 Colin Duquesnoy
|
||||||
# Copyright © 2009- The Spyder Developmet Team
|
# Copyright © 2009- The Spyder Developmet Team
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Copyright © 2009- The Spyder Development Team
|
# Copyright © 2009- The Spyder Development Team
|
||||||
# Copyright © 2014-2015 Colin Duquesnoy
|
# Copyright © 2014-2015 Colin Duquesnoy
|
||||||
@@ -147,7 +146,7 @@ if API in PYSIDE6_API:
|
|||||||
if API is None:
|
if API is None:
|
||||||
raise PythonQtError(
|
raise PythonQtError(
|
||||||
"No Qt bindings could be found.\nYou must install one of the following packages "
|
"No Qt bindings could be found.\nYou must install one of the following packages "
|
||||||
"to use QtRangeSlider: PyQt5, PyQt6, PySide2, or PySide6"
|
"to use qwidgets: PyQt5, PyQt6, PySide2, or PySide6"
|
||||||
)
|
)
|
||||||
|
|
||||||
# If a correct API name is passed to QT_API and it could not be found,
|
# If a correct API name is passed to QT_API and it could not be found,
|
||||||
@@ -1,8 +1,3 @@
|
|||||||
try:
|
|
||||||
from ._version import version as __version__
|
|
||||||
except ImportError:
|
|
||||||
__version__ = "unknown"
|
|
||||||
|
|
||||||
from ._labeled import (
|
from ._labeled import (
|
||||||
QLabeledDoubleRangeSlider,
|
QLabeledDoubleRangeSlider,
|
||||||
QLabeledDoubleSlider,
|
QLabeledDoubleSlider,
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
from typing import Generic, List, Sequence, Tuple, TypeVar, Union
|
from typing import Generic, List, Sequence, Tuple, TypeVar, Union
|
||||||
|
|
||||||
from ._generic_slider import CC_SLIDER, SC_GROOVE, SC_HANDLE, SC_NONE, _GenericSlider
|
from ..qtcompat import QtGui
|
||||||
from ._range_style import RangeSliderStyle, update_styles_from_stylesheet
|
from ..qtcompat.QtCore import (
|
||||||
from .qtcompat import QtGui
|
|
||||||
from .qtcompat.QtCore import (
|
|
||||||
Property,
|
Property,
|
||||||
QEvent,
|
QEvent,
|
||||||
QPoint,
|
QPoint,
|
||||||
@@ -13,7 +11,9 @@ from .qtcompat.QtCore import (
|
|||||||
Qt,
|
Qt,
|
||||||
Signal,
|
Signal,
|
||||||
)
|
)
|
||||||
from .qtcompat.QtWidgets import QSlider, QStyle, QStyleOptionSlider, QStylePainter
|
from ..qtcompat.QtWidgets import QSlider, QStyle, QStyleOptionSlider, QStylePainter
|
||||||
|
from ._generic_slider import CC_SLIDER, SC_GROOVE, SC_HANDLE, SC_NONE, _GenericSlider
|
||||||
|
from ._range_style import RangeSliderStyle, update_styles_from_stylesheet
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
@@ -22,9 +22,9 @@ QRangeSlider.
|
|||||||
|
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, TypeVar
|
||||||
|
|
||||||
from .qtcompat import QtGui
|
from ..qtcompat import QtGui
|
||||||
from .qtcompat.QtCore import QEvent, QPoint, QPointF, QRect, Qt, Signal
|
from ..qtcompat.QtCore import QEvent, QPoint, QPointF, QRect, Qt, Signal
|
||||||
from .qtcompat.QtWidgets import (
|
from ..qtcompat.QtWidgets import (
|
||||||
QApplication,
|
QApplication,
|
||||||
QSlider,
|
QSlider,
|
||||||
QStyle,
|
QStyle,
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from ._sliders import QDoubleRangeSlider, QDoubleSlider, QRangeSlider
|
from ..qtcompat.QtCore import QPoint, QSize, Qt, Signal
|
||||||
from .qtcompat.QtCore import QPoint, QSize, Qt, Signal
|
from ..qtcompat.QtGui import QFontMetrics, QValidator
|
||||||
from .qtcompat.QtGui import QFontMetrics, QValidator
|
from ..qtcompat.QtWidgets import (
|
||||||
from .qtcompat.QtWidgets import (
|
|
||||||
QAbstractSlider,
|
QAbstractSlider,
|
||||||
QApplication,
|
QApplication,
|
||||||
QDoubleSpinBox,
|
QDoubleSpinBox,
|
||||||
@@ -16,6 +15,7 @@ from .qtcompat.QtWidgets import (
|
|||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QWidget,
|
QWidget,
|
||||||
)
|
)
|
||||||
|
from ._sliders import QDoubleRangeSlider, QDoubleSlider, QRangeSlider
|
||||||
|
|
||||||
|
|
||||||
class LabelPosition(IntEnum):
|
class LabelPosition(IntEnum):
|
||||||
@@ -32,7 +32,7 @@ class EdgeLabelMode(IntEnum):
|
|||||||
LabelIsValue = 2
|
LabelIsValue = 2
|
||||||
|
|
||||||
|
|
||||||
class SliderProxy:
|
class _SliderProxy:
|
||||||
_slider: QSlider
|
_slider: QSlider
|
||||||
|
|
||||||
def value(self):
|
def value(self):
|
||||||
@@ -112,7 +112,7 @@ def _handle_overloaded_slider_sig(args, kwargs):
|
|||||||
return parent, orientation
|
return parent, orientation
|
||||||
|
|
||||||
|
|
||||||
class QLabeledSlider(SliderProxy, QAbstractSlider):
|
class QLabeledSlider(_SliderProxy, QAbstractSlider):
|
||||||
_slider_class = QSlider
|
_slider_class = QSlider
|
||||||
_slider: QSlider
|
_slider: QSlider
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ class QLabeledDoubleSlider(QLabeledSlider):
|
|||||||
self._label.setDecimals(prec)
|
self._label.setDecimals(prec)
|
||||||
|
|
||||||
|
|
||||||
class QLabeledRangeSlider(SliderProxy, QAbstractSlider):
|
class QLabeledRangeSlider(_SliderProxy, QAbstractSlider):
|
||||||
valueChanged = Signal(tuple)
|
valueChanged = Signal(tuple)
|
||||||
LabelPosition = LabelPosition
|
LabelPosition = LabelPosition
|
||||||
EdgeLabelMode = EdgeLabelMode
|
EdgeLabelMode = EdgeLabelMode
|
||||||
@@ -5,9 +5,9 @@ import re
|
|||||||
from dataclasses import dataclass, replace
|
from dataclasses import dataclass, replace
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from .qtcompat import PYQT_VERSION
|
from ..qtcompat import PYQT_VERSION
|
||||||
from .qtcompat.QtCore import Qt
|
from ..qtcompat.QtCore import Qt
|
||||||
from .qtcompat.QtGui import (
|
from ..qtcompat.QtGui import (
|
||||||
QBrush,
|
QBrush,
|
||||||
QColor,
|
QColor,
|
||||||
QGradient,
|
QGradient,
|
||||||
@@ -15,7 +15,7 @@ from .qtcompat.QtGui import (
|
|||||||
QPalette,
|
QPalette,
|
||||||
QRadialGradient,
|
QRadialGradient,
|
||||||
)
|
)
|
||||||
from .qtcompat.QtWidgets import QApplication, QSlider, QStyleOptionSlider
|
from ..qtcompat.QtWidgets import QApplication, QSlider, QStyleOptionSlider
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ._generic_range_slider import _GenericRangeSlider
|
from ._generic_range_slider import _GenericRangeSlider
|
||||||
@@ -241,7 +241,7 @@ def parse_color(color: str, default_attr) -> QColor | QGradient:
|
|||||||
# try linear gradient:
|
# try linear gradient:
|
||||||
match = qlineargrad_pattern.search(color)
|
match = qlineargrad_pattern.search(color)
|
||||||
if match:
|
if match:
|
||||||
grad = QLinearGradient(*[float(i) for i in match.groups()[:4]])
|
grad = QLinearGradient(*(float(i) for i in match.groups()[:4]))
|
||||||
grad.setColorAt(0, QColor(match.groupdict()["stop0"]))
|
grad.setColorAt(0, QColor(match.groupdict()["stop0"]))
|
||||||
grad.setColorAt(1, QColor(match.groupdict()["stop1"]))
|
grad.setColorAt(1, QColor(match.groupdict()["stop1"]))
|
||||||
return grad
|
return grad
|
||||||
@@ -249,7 +249,7 @@ def parse_color(color: str, default_attr) -> QColor | QGradient:
|
|||||||
# try linear gradient:
|
# try linear gradient:
|
||||||
match = qradial_pattern.search(color)
|
match = qradial_pattern.search(color)
|
||||||
if match:
|
if match:
|
||||||
grad = QRadialGradient(*[float(i) for i in match.groups()[:5]])
|
grad = QRadialGradient(*(float(i) for i in match.groups()[:5]))
|
||||||
grad.setColorAt(0, QColor(match.groupdict()["stop0"]))
|
grad.setColorAt(0, QColor(match.groupdict()["stop0"]))
|
||||||
grad.setColorAt(1, QColor(match.groupdict()["stop1"]))
|
grad.setColorAt(1, QColor(match.groupdict()["stop1"]))
|
||||||
return grad
|
return grad
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
from ..qtcompat.QtCore import Signal
|
||||||
from ._generic_range_slider import _GenericRangeSlider
|
from ._generic_range_slider import _GenericRangeSlider
|
||||||
from ._generic_slider import _GenericSlider
|
from ._generic_slider import _GenericSlider
|
||||||
from .qtcompat.QtCore import Signal
|
|
||||||
|
|
||||||
|
|
||||||
class _IntMixin:
|
class _IntMixin:
|
||||||
@@ -4,9 +4,9 @@ from platform import system
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qtrangeslider.qtcompat import QT_VERSION
|
from qwidgets.qtcompat import QT_VERSION
|
||||||
from qtrangeslider.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
from qwidgets.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
||||||
from qtrangeslider.qtcompat.QtGui import QMouseEvent, QWheelEvent
|
from qwidgets.qtcompat.QtGui import QMouseEvent, QWheelEvent
|
||||||
|
|
||||||
QT_VERSION = LooseVersion(QT_VERSION)
|
QT_VERSION = LooseVersion(QT_VERSION)
|
||||||
|
|
||||||
@@ -2,13 +2,13 @@ import os
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qtrangeslider import (
|
from qwidgets import (
|
||||||
QDoubleRangeSlider,
|
QDoubleRangeSlider,
|
||||||
QDoubleSlider,
|
QDoubleSlider,
|
||||||
QLabeledDoubleRangeSlider,
|
QLabeledDoubleRangeSlider,
|
||||||
QLabeledDoubleSlider,
|
QLabeledDoubleSlider,
|
||||||
)
|
)
|
||||||
from qtrangeslider.qtcompat import API_NAME
|
from qwidgets.qtcompat import API_NAME
|
||||||
|
|
||||||
range_types = {QDoubleRangeSlider, QLabeledDoubleRangeSlider}
|
range_types = {QDoubleRangeSlider, QLabeledDoubleRangeSlider}
|
||||||
|
|
||||||
@@ -2,10 +2,10 @@ import math
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qtrangeslider._generic_slider import _GenericSlider
|
from qwidgets.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
||||||
from qtrangeslider.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
from qwidgets.qtcompat.QtGui import QHoverEvent
|
||||||
from qtrangeslider.qtcompat.QtGui import QHoverEvent
|
from qwidgets.qtcompat.QtWidgets import QStyle, QStyleOptionSlider
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QStyle, QStyleOptionSlider
|
from qwidgets.sliders._generic_slider import _GenericSlider
|
||||||
|
|
||||||
from ._testutil import _linspace, _mouse_event, _wheel_event, skip_on_linux_qt6
|
from ._testutil import _linspace, _mouse_event, _wheel_event, skip_on_linux_qt6
|
||||||
|
|
||||||
@@ -2,10 +2,10 @@ import math
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qtrangeslider import QDoubleRangeSlider, QRangeSlider
|
from qwidgets import QDoubleRangeSlider, QRangeSlider
|
||||||
from qtrangeslider.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
from qwidgets.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
||||||
from qtrangeslider.qtcompat.QtGui import QHoverEvent
|
from qwidgets.qtcompat.QtGui import QHoverEvent
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QStyle, QStyleOptionSlider
|
from qwidgets.qtcompat.QtWidgets import QStyle, QStyleOptionSlider
|
||||||
|
|
||||||
from ._testutil import _linspace, _mouse_event, _wheel_event, skip_on_linux_qt6
|
from ._testutil import _linspace, _mouse_event, _wheel_event, skip_on_linux_qt6
|
||||||
|
|
||||||
@@ -4,11 +4,11 @@ from distutils.version import LooseVersion
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qtrangeslider import QDoubleSlider, QLabeledDoubleSlider, QLabeledSlider
|
from qwidgets import QDoubleSlider, QLabeledDoubleSlider, QLabeledSlider
|
||||||
from qtrangeslider._generic_slider import _GenericSlider
|
from qwidgets.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
||||||
from qtrangeslider.qtcompat.QtCore import QEvent, QPoint, QPointF, Qt
|
from qwidgets.qtcompat.QtGui import QHoverEvent
|
||||||
from qtrangeslider.qtcompat.QtGui import QHoverEvent
|
from qwidgets.qtcompat.QtWidgets import QSlider, QStyle, QStyleOptionSlider
|
||||||
from qtrangeslider.qtcompat.QtWidgets import QSlider, QStyle, QStyleOptionSlider
|
from qwidgets.sliders._generic_slider import _GenericSlider
|
||||||
|
|
||||||
from ._testutil import (
|
from ._testutil import (
|
||||||
QT_VERSION,
|
QT_VERSION,
|
||||||
@@ -2,10 +2,10 @@ import platform
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from qtrangeslider import QRangeSlider
|
from qwidgets import QRangeSlider
|
||||||
from qtrangeslider._generic_range_slider import SC_BAR, SC_HANDLE, SC_NONE
|
from qwidgets.qtcompat import API_NAME
|
||||||
from qtrangeslider.qtcompat import API_NAME
|
from qwidgets.qtcompat.QtCore import Qt
|
||||||
from qtrangeslider.qtcompat.QtCore import Qt
|
from qwidgets.sliders._generic_range_slider import SC_BAR, SC_HANDLE, SC_NONE
|
||||||
|
|
||||||
NOT_LINUX = platform.system() != "Linux"
|
NOT_LINUX = platform.system() != "Linux"
|
||||||
NOT_PYSIDE2 = API_NAME != "PySide2"
|
NOT_PYSIDE2 = API_NAME != "PySide2"
|
||||||
75
setup.cfg
@@ -1,18 +1,13 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = QtRangeSlider
|
name = qwidgets
|
||||||
url = https://github.com/tlambert03/QtRangeSlider
|
description = Missing widgets for PyQt/PySide
|
||||||
license = BSD-3
|
long_description = file: README.md
|
||||||
license_file = LICENSE
|
|
||||||
description = Multi-handle range slider widget for PyQt/PySide
|
|
||||||
long_description = file: README.md, CHANGELOG.md
|
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
|
url = https://github.com/napari/qwidgets
|
||||||
author = Talley Lambert
|
author = Talley Lambert
|
||||||
author_email = talley.lambert@gmail.com
|
author_email = talley.lambert@gmail.com
|
||||||
keywords = qt, range slider, widget
|
license = BSD-3-Clause
|
||||||
project_urls =
|
license_file = LICENSE
|
||||||
Source = https://github.com/tlambert03/QtRangeSlider
|
|
||||||
Tracker = https://github.com/tlambert03/QtRangeSlider/issues
|
|
||||||
Changelog = https://github.com/tlambert03/QtRangeSlider/blob/master/CHANGELOG.md
|
|
||||||
classifiers =
|
classifiers =
|
||||||
Development Status :: 4 - Beta
|
Development Status :: 4 - Beta
|
||||||
Environment :: X11 Applications :: Qt
|
Environment :: X11 Applications :: Qt
|
||||||
@@ -20,49 +15,69 @@ classifiers =
|
|||||||
License :: OSI Approved :: BSD License
|
License :: OSI Approved :: BSD License
|
||||||
Operating System :: OS Independent
|
Operating System :: OS Independent
|
||||||
Programming Language :: Python
|
Programming Language :: Python
|
||||||
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3 :: Only
|
Programming Language :: Python :: 3 :: Only
|
||||||
Programming Language :: Python :: 3.6
|
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
Topic :: Desktop Environment
|
Topic :: Desktop Environment
|
||||||
Topic :: Software Development
|
Topic :: Software Development
|
||||||
Topic :: Software Development :: User Interfaces
|
Topic :: Software Development :: User Interfaces
|
||||||
Topic :: Software Development :: Widget Sets
|
Topic :: Software Development :: Widget Sets
|
||||||
|
keywords = qt, range slider, widget
|
||||||
|
project_urls =
|
||||||
|
Source = https://github.com/napari/qwidgets
|
||||||
|
Tracker = https://github.com/napari/qwidgets/issues
|
||||||
|
Changelog = https://github.com/napari/qwidgets/blob/master/CHANGELOG.md
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
zip_safe = False
|
|
||||||
packages = find:
|
packages = find:
|
||||||
python_requires = >=3.6
|
python_requires = >=3.7
|
||||||
setup_requires = setuptools_scm
|
setup_requires =
|
||||||
|
setuptools_scm
|
||||||
|
zip_safe = False
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
pyside2 = pyside2
|
|
||||||
pyqt5 = pyqt5
|
|
||||||
pyside6 = pyside6
|
|
||||||
pyqt6 = pyqt6
|
|
||||||
testing =
|
|
||||||
tox
|
|
||||||
tox-conda
|
|
||||||
pytest
|
|
||||||
pytest-qt
|
|
||||||
pytest-cov
|
|
||||||
dev =
|
dev =
|
||||||
ipython
|
ipython
|
||||||
jedi<0.18.0
|
|
||||||
isort
|
isort
|
||||||
|
jedi<0.18.0
|
||||||
mypy
|
mypy
|
||||||
pre-commit
|
pre-commit
|
||||||
%(testing)s
|
pyside2
|
||||||
%(pyqt5)s
|
pytest
|
||||||
|
pytest-cov
|
||||||
|
pytest-qt
|
||||||
|
tox
|
||||||
|
tox-conda
|
||||||
|
pyqt5 =
|
||||||
|
pyqt5
|
||||||
|
pyqt6 =
|
||||||
|
pyqt6
|
||||||
|
pyside2 =
|
||||||
|
pyside2
|
||||||
|
pyside6 =
|
||||||
|
pyside6
|
||||||
|
testing =
|
||||||
|
pytest
|
||||||
|
pytest-cov
|
||||||
|
pytest-qt
|
||||||
|
tox
|
||||||
|
tox-conda
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
exclude = _version.py,.eggs,examples
|
exclude = _version.py,.eggs,examples
|
||||||
docstring-convention = numpy
|
docstring-convention = numpy
|
||||||
ignore = E203,W503,E501,C901,F403,F405
|
ignore = E203,W503,E501,C901,F403,F405,D100
|
||||||
|
|
||||||
|
[pydocstyle]
|
||||||
|
convention = numpy
|
||||||
|
add_select = D402,D415,D417
|
||||||
|
ignore = D100
|
||||||
|
|
||||||
[isort]
|
[isort]
|
||||||
profile=black
|
profile = black
|
||||||
|
|
||||||
[tool:pytest]
|
[tool:pytest]
|
||||||
addopts = -W error
|
addopts = -W error
|
||||||
|
|||||||
6
setup.py
@@ -1,10 +1,6 @@
|
|||||||
"""
|
|
||||||
PEP 517 doesn’t support editable installs
|
|
||||||
so this file is currently here to support "pip install -e ."
|
|
||||||
"""
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
use_scm_version={"write_to": "qtrangeslider/_version.py"},
|
use_scm_version={"write_to": "qwidgets/_version.py"},
|
||||||
setup_requires=["setuptools_scm"],
|
setup_requires=["setuptools_scm"],
|
||||||
)
|
)
|
||||||
|
|||||||
14
tox.ini
@@ -3,6 +3,18 @@
|
|||||||
envlist = py{37,38,39}-{linux,macos,windows}-{pyqt5,pyside2,pyqt6,pyside6},py37-{linux,macos,windows}-{pyqt511,pyside511}
|
envlist = py{37,38,39}-{linux,macos,windows}-{pyqt5,pyside2,pyqt6,pyside6},py37-{linux,macos,windows}-{pyqt511,pyside511}
|
||||||
toxworkdir=/tmp/.tox
|
toxworkdir=/tmp/.tox
|
||||||
|
|
||||||
|
[coverage:report]
|
||||||
|
exclude_lines =
|
||||||
|
pragma: no cover
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
\.\.\.
|
||||||
|
except ImportError*
|
||||||
|
raise NotImplementedError()
|
||||||
|
omit =
|
||||||
|
qwidgets/_version.py
|
||||||
|
qwidgets/qtcompat/*
|
||||||
|
*_tests*
|
||||||
|
|
||||||
[gh-actions]
|
[gh-actions]
|
||||||
python =
|
python =
|
||||||
3.6: py36
|
3.6: py36
|
||||||
@@ -45,4 +57,4 @@ extras =
|
|||||||
pyside6: pyside6
|
pyside6: pyside6
|
||||||
commands_pre =
|
commands_pre =
|
||||||
pyqt6,pyside6: pip install -U pytest-qt@git+https://github.com/pytest-dev/pytest-qt.git
|
pyqt6,pyside6: pip install -U pytest-qt@git+https://github.com/pytest-dev/pytest-qt.git
|
||||||
commands = pytest --color=yes --cov=qtrangeslider --cov-report=xml {posargs}
|
commands = pytest --color=yes --cov=qwidgets --cov-report=xml {posargs}
|
||||||
|
|||||||