Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
beat
beat.editor
Commits
b4dca197
Commit
b4dca197
authored
Apr 01, 2019
by
Samuel GAIST
Browse files
[widgets] Implement spin boxes for 64bit integer types
parent
0e275a04
Changes
2
Hide whitespace changes
Inline
Side-by-side
beat/editor/test/test_spinboxes.py
0 → 100644
View file @
b4dca197
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2019 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.editor module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from
..widgets.spinboxes
import
Int64SpinBox
from
..widgets.spinboxes
import
Uint64SpinBox
class
SpinBoxBaseTest
:
klass
=
None
def
test_range
(
self
,
qtbot
):
spinbox
=
self
.
klass
()
qtbot
.
addWidget
(
spinbox
)
minimum
=
0
maximum
=
10
spinbox
.
setRange
(
minimum
,
maximum
)
assert
spinbox
.
minimum
()
==
minimum
assert
spinbox
.
maximum
()
==
maximum
spinbox
.
setValue
(
-
10
)
assert
spinbox
.
value
()
==
spinbox
.
minimum
()
spinbox
.
setValue
(
20
)
assert
spinbox
.
value
()
==
spinbox
.
maximum
()
def
test_valid_input
(
self
,
qtbot
):
spinbox
=
self
.
klass
()
qtbot
.
addWidget
(
spinbox
)
value
=
"42"
with
qtbot
.
waitSignal
(
spinbox
.
valueChanged
):
qtbot
.
keyClicks
(
spinbox
,
value
)
assert
spinbox
.
value
()
==
spinbox
.
numpy_type
(
value
)
def
test_invalid_input
(
self
,
qtbot
):
spinbox
=
self
.
klass
()
qtbot
.
addWidget
(
spinbox
)
value
=
"44444444444444444444444444444444444444444444444444444444444"
expected_value
=
4444444444444444444
with
qtbot
.
waitSignal
(
spinbox
.
valueChanged
):
qtbot
.
keyClicks
(
spinbox
,
value
)
assert
spinbox
.
value
()
==
spinbox
.
numpy_type
(
expected_value
)
class
TestIn64SpinBox
(
SpinBoxBaseTest
):
klass
=
Int64SpinBox
def
test_values
(
self
,
qtbot
):
spinbox
=
Int64SpinBox
()
qtbot
.
addWidget
(
spinbox
)
spinbox
.
setRange
(
0
,
10
)
spinbox
.
setValue
(
5
)
assert
spinbox
.
value
()
==
5
spinbox
.
setValue
(
-
5
)
assert
spinbox
.
value
()
==
spinbox
.
minimum
()
class
TestUin64SpinBox
(
SpinBoxBaseTest
):
klass
=
Uint64SpinBox
def
test_invalid_range
(
self
,
qtbot
):
spinbox
=
Uint64SpinBox
()
qtbot
.
addWidget
(
spinbox
)
spinbox
.
setRange
(
-
10
,
10
)
assert
spinbox
.
minimum
()
==
0
def
test_values
(
self
,
qtbot
):
spinbox
=
Uint64SpinBox
()
qtbot
.
addWidget
(
spinbox
)
spinbox
.
setRange
(
0
,
10
)
spinbox
.
setValue
(
-
10
)
assert
spinbox
.
value
()
==
spinbox
.
minimum
()
spinbox
.
setValue
(
20
)
assert
spinbox
.
value
()
==
spinbox
.
maximum
()
beat/editor/widgets/spinboxes.py
0 → 100644
View file @
b4dca197
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2019 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.editor module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
import
numpy
as
np
from
PyQt5.QtCore
import
pyqtSignal
from
PyQt5.QtCore
import
Qt
from
PyQt5.QtGui
import
QValidator
from
PyQt5.QtWidgets
import
QAbstractSpinBox
from
..utils
import
frozen
@
frozen
class
AbstractNumpySpinBox
(
QAbstractSpinBox
):
"""Spinbox base class using numpy types
Subclasses must provide the nump_type with the numpy
type that will be used.
They also must declare the following signals:
- valueChanged
- minimumChanged
- maximumChanged
Based on https://stackoverflow.com/a/32628421/5843716
"""
numpy_type
=
None
def
__init__
(
self
,
parent
=
None
):
"""Constructor
:param parent QWidget: parent widget
"""
super
(
AbstractNumpySpinBox
,
self
).
__init__
(
parent
)
self
.
_info
=
np
.
iinfo
(
self
.
numpy_type
)
self
.
_minimum
=
self
.
_info
.
min
self
.
_maximum
=
self
.
_info
.
max
self
.
_value
=
0
self
.
setInputMethodHints
(
Qt
.
ImhFormattedNumbersOnly
)
self
.
lineEdit
().
textEdited
.
connect
(
self
.
__on_text_edited
)
def
__on_text_edited
(
self
):
"""Act when the spinbox line edit content has been changed"""
input_
=
self
.
lineEdit
().
text
()
pos
=
0
is_valid
,
input_
,
pos
=
self
.
validate
(
input_
,
pos
)
if
is_valid
==
QValidator
.
Acceptable
:
self
.
setValue
(
self
.
valueFromText
(
input_
,
pos
))
else
:
self
.
lineEdit
().
setText
(
self
.
textFromValue
(
self
.
value
()))
def
textFromValue
(
self
,
value
):
"""Returns the text version of value
:param value numpy_type: value to change to text
"""
return
"{}"
.
format
(
value
)
def
valueFromText
(
self
,
text
,
pos
):
"""Returns the value contained in the text
:param text str: text to change in numpy_type
:param pos int: position to start considerating the text from
"""
return
self
.
numpy_type
(
text
)
def
minimum
(
self
):
"""Returns the spin box minimum value"""
return
self
.
_minimum
def
setMinimum
(
self
,
minimum
):
"""Set the minium value of the spin box.
In case the value given is outside of the spin box range,
it will be adapated.
:param minimum numpy_type: minimum value
"""
if
self
.
_minimum
==
minimum
:
return
if
minimum
>
self
.
maximum
():
minimum
=
self
.
maximum
()
elif
minimum
<
self
.
_info
.
min
:
minimum
=
self
.
_info
.
min
self
.
_minimum
=
self
.
numpy_type
(
minimum
)
self
.
minimumChanged
.
emit
(
self
.
_minimum
)
def
maximum
(
self
):
"""Returns the spin box maximum value"""
return
self
.
_maximum
def
setMaximum
(
self
,
maximum
):
"""Set the maximum value of the spin box.
In case the value given is outside of the spin box range,
it will be adapated.
:param maximum numpy_type: maximum value
"""
if
self
.
_maximum
==
maximum
:
return
if
maximum
<
self
.
minimum
():
maximum
=
self
.
minimum
()
elif
maximum
>
self
.
_info
.
max
:
maximum
=
self
.
_info
.
max
self
.
_maximum
=
self
.
numpy_type
(
maximum
)
self
.
maximumChanged
.
emit
(
self
.
_maximum
)
def
setRange
(
self
,
minimum
,
maximum
):
"""Set the range of the spin box.
In case the values given are outside of the type range,
they will be adapated.
:param minimum numpy_type: minimum value
:param maximum numpy_type: maximum value
"""
self
.
setMinimum
(
minimum
)
self
.
setMaximum
(
maximum
)
def
value
(
self
):
"""Returns the spin box current value"""
return
self
.
_value
def
setValue
(
self
,
value
):
"""Set the value of the spin box.
If the value is outside the spin box range, it will
be adapted.
:param value numpy_type: value to set
"""
if
self
.
_value
==
value
:
return
if
value
>
self
.
maximum
():
value
=
self
.
maximum
()
elif
value
<
self
.
minimum
():
value
=
self
.
minimum
()
self
.
lineEdit
().
setText
(
self
.
textFromValue
(
value
))
self
.
_value
=
self
.
numpy_type
(
value
)
self
.
valueChanged
.
emit
(
self
.
_value
)
def
stepBy
(
self
,
steps
):
"""Update the value of the spin box by steps.
This method is called for example when clicking on the arrow
or using the keyboard.
:param steps int: step to increment/decrement the spin box
"""
new_value
=
self
.
value
()
if
steps
<
0
and
new_value
+
steps
<
self
.
minimum
():
new_value
=
self
.
minimum
()
elif
steps
>
0
and
new_value
+
steps
>
self
.
maximum
():
new_value
=
self
.
maximum
()
else
:
new_value
+=
steps
self
.
setValue
(
new_value
)
def
validate
(
self
,
input_
,
pos
):
"""Validate the input value
:param input_ text: text to to validate
:param pos int: start of text to consider
"""
is_valid
=
QValidator
.
Acceptable
try
:
value
=
self
.
valueFromText
(
input_
,
pos
)
except
(
ValueError
,
OverflowError
):
is_valid
=
QValidator
.
Invalid
else
:
if
value
<
self
.
minimum
()
or
value
>
self
.
maximum
():
is_valid
=
QValidator
.
Invalid
return
is_valid
,
input_
,
pos
def
stepEnabled
(
self
):
"""Returns which kind of steps are available to modify the value
of the spin box
"""
return
QAbstractSpinBox
.
StepUpEnabled
|
QAbstractSpinBox
.
StepDownEnabled
@
frozen
class
Int64SpinBox
(
AbstractNumpySpinBox
):
"""Spin box handling the int64 type"""
numpy_type
=
np
.
int64
valueChanged
=
pyqtSignal
(
numpy_type
)
minimumChanged
=
pyqtSignal
(
numpy_type
)
maximumChanged
=
pyqtSignal
(
numpy_type
)
@
frozen
class
Uint64SpinBox
(
AbstractNumpySpinBox
):
"""Spin box handling the uint64 type"""
numpy_type
=
np
.
uint64
valueChanged
=
pyqtSignal
(
numpy_type
)
minimumChanged
=
pyqtSignal
(
numpy_type
)
maximumChanged
=
pyqtSignal
(
numpy_type
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment