summaryrefslogtreecommitdiff
path: root/silx/gui/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/widgets')
-rw-r--r--silx/gui/widgets/BoxLayoutDockWidget.py90
-rw-r--r--silx/gui/widgets/FrameBrowser.py75
-rw-r--r--silx/gui/widgets/PrintGeometryDialog.py2
-rw-r--r--silx/gui/widgets/PrintPreview.py4
-rw-r--r--silx/gui/widgets/test/__init__.py6
-rw-r--r--silx/gui/widgets/test/test_boxlayoutdockwidget.py83
-rw-r--r--silx/gui/widgets/test/test_framebrowser.py73
7 files changed, 299 insertions, 34 deletions
diff --git a/silx/gui/widgets/BoxLayoutDockWidget.py b/silx/gui/widgets/BoxLayoutDockWidget.py
new file mode 100644
index 0000000..3d2b853
--- /dev/null
+++ b/silx/gui/widgets/BoxLayoutDockWidget.py
@@ -0,0 +1,90 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""A QDockWidget that update the layout direction of its widget
+"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "06/03/2018"
+
+
+from .. import qt
+
+
+class BoxLayoutDockWidget(qt.QDockWidget):
+ """QDockWidget adjusting its child widget QBoxLayout direction.
+
+ The child widget layout direction is set according to dock widget area.
+ The child widget MUST use a QBoxLayout
+
+ :param parent: See :class:`QDockWidget`
+ :param flags: See :class:`QDockWidget`
+ """
+
+ def __init__(self, parent=None, flags=qt.Qt.Widget):
+ super(BoxLayoutDockWidget, self).__init__(parent, flags)
+ self._currentArea = qt.Qt.NoDockWidgetArea
+ self.dockLocationChanged.connect(self._dockLocationChanged)
+ self.topLevelChanged.connect(self._topLevelChanged)
+
+ def setWidget(self, widget):
+ """Set the widget of this QDockWidget
+
+ See :meth:`QDockWidget.setWidget`
+ """
+ super(BoxLayoutDockWidget, self).setWidget(widget)
+ # Update widget's layout direction
+ self._dockLocationChanged(self._currentArea)
+
+ def _dockLocationChanged(self, area):
+ self._currentArea = area
+
+ widget = self.widget()
+ if widget is not None:
+ layout = widget.layout()
+ if isinstance(layout, qt.QBoxLayout):
+ if area in (qt.Qt.LeftDockWidgetArea, qt.Qt.RightDockWidgetArea):
+ direction = qt.QBoxLayout.TopToBottom
+ else:
+ direction = qt.QBoxLayout.LeftToRight
+ layout.setDirection(direction)
+ self.resize(widget.minimumSize())
+ self.adjustSize()
+
+ def _topLevelChanged(self, topLevel):
+ widget = self.widget()
+ if widget is not None and topLevel:
+ layout = widget.layout()
+ if isinstance(layout, qt.QBoxLayout):
+ layout.setDirection(qt.QBoxLayout.LeftToRight)
+ self.resize(widget.minimumSize())
+ self.adjustSize()
+
+ def showEvent(self, event):
+ """Make sure this dock widget is raised when it is shown.
+
+ This is useful for tabbed dock widgets.
+ """
+ self.raise_()
diff --git a/silx/gui/widgets/FrameBrowser.py b/silx/gui/widgets/FrameBrowser.py
index a8c0349..b4f88fc 100644
--- a/silx/gui/widgets/FrameBrowser.py
+++ b/silx/gui/widgets/FrameBrowser.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,7 @@
"""
from silx.gui import qt
from silx.gui import icons
+from silx.utils import deprecation
__authors__ = ["V.A. Sole", "P. Knobel"]
__license__ = "MIT"
@@ -50,7 +51,9 @@ class FrameBrowser(qt.QWidget):
:param QWidget parent: Parent widget
:param int n: Number of frames. This will set the range
of frame indices to 0--n-1.
- If None, the range is initialized to the default QSlider range (0--99)."""
+ If None, the range is initialized to the default QSlider range (0--99).
+ """
+
sigIndexChanged = qt.pyqtSignal(object)
def __init__(self, parent=None, n=None):
@@ -123,25 +126,19 @@ class FrameBrowser(qt.QWidget):
def _firstClicked(self):
"""Select first/lowest frame number"""
- self._lineEdit.setText("%d" % self._lineEdit.validator().bottom())
- self._textChangedSlot()
+ self.setValue(self.getRange()[0])
def _previousClicked(self):
"""Select previous frame number"""
- if self._index > self._lineEdit.validator().bottom():
- self._lineEdit.setText("%d" % (self._index - 1))
- self._textChangedSlot()
+ self.setValue(self.getValue() - 1)
def _nextClicked(self):
"""Select next frame number"""
- if self._index < (self._lineEdit.validator().top()):
- self._lineEdit.setText("%d" % (self._index + 1))
- self._textChangedSlot()
+ self.setValue(self.getValue() + 1)
def _lastClicked(self):
"""Select last/highest frame number"""
- self._lineEdit.setText("%d" % self._lineEdit.validator().top())
- self._textChangedSlot()
+ self.setValue(self.getRange()[1])
def _textChangedSlot(self):
"""Select frame number typed in the line edit widget"""
@@ -161,17 +158,17 @@ class FrameBrowser(qt.QWidget):
self._index = new_value
self.sigIndexChanged.emit(ddict)
- def setRange(self, first, last):
- """Set minimum and maximum frame indices
- Initialize the frame index to *first*.
- Update the label text to *" limits: first, last"*
+ def getRange(self):
+ """Returns frame range
- :param int first: Minimum frame index
- :param int last: Maximum frame index"""
- return self.setLimits(first, last)
+ :return: (first_index, last_index)
+ """
+ validator = self.lineEdit().validator()
+ return validator.bottom(), validator.top()
- def setLimits(self, first, last):
+ def setRange(self, first, last):
"""Set minimum and maximum frame indices.
+
Initialize the frame index to *first*.
Update the label text to *" limits: first, last"*
@@ -181,34 +178,52 @@ class FrameBrowser(qt.QWidget):
top = max(first, last)
self._lineEdit.validator().setTop(top)
self._lineEdit.validator().setBottom(bottom)
- self._index = bottom
- self._lineEdit.setText("%d" % self._index)
+ self.setValue(bottom)
+
+ # Update limits
self._label.setText(" limits: %d, %d " % (bottom, top))
+ @deprecation.deprecated(replacement="FrameBrowser.setRange",
+ since_version="0.8")
+ def setLimits(self, first, last):
+ return self.setRange(first, last)
+
def setNFrames(self, nframes):
"""Set minimum=0 and maximum=nframes-1 frame numbers.
+
Initialize the frame index to 0.
Update the label text to *"1 of nframes"*
:param int nframes: Number of frames"""
- bottom = 0
top = nframes - 1
- self._lineEdit.validator().setTop(top)
- self._lineEdit.validator().setBottom(bottom)
- self._index = bottom
- self._lineEdit.setText("%d" % self._index)
+ self.setRange(0, top)
# display 1-based index in label
- self._label.setText(" %d of %d " % (self._index + 1, top + 1))
+ self._label.setText(" of %d " % top)
+ @deprecation.deprecated(replacement="FrameBrowser.getValue",
+ since_version="0.8")
def getCurrentIndex(self):
- """Get 0-based frame index
- """
+ return self._index
+
+ def getValue(self):
+ """Return current frame index"""
return self._index
def setValue(self, value):
"""Set 0-based frame index
+ Value is clipped to current range.
+
:param int value: Frame number"""
+ bottom = self.lineEdit().validator().bottom()
+ top = self.lineEdit().validator().top()
+ value = int(value)
+
+ if value < bottom:
+ value = bottom
+ elif value > top:
+ value = top
+
self._lineEdit.setText("%d" % value)
self._textChangedSlot()
diff --git a/silx/gui/widgets/PrintGeometryDialog.py b/silx/gui/widgets/PrintGeometryDialog.py
index 0613ce0..db0f3b3 100644
--- a/silx/gui/widgets/PrintGeometryDialog.py
+++ b/silx/gui/widgets/PrintGeometryDialog.py
@@ -40,7 +40,7 @@ class PrintGeometryWidget(qt.QWidget):
self.mainLayout = qt.QGridLayout(self)
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.mainLayout.setSpacing(2)
- hbox = qt.QWidget()
+ hbox = qt.QWidget(self)
hboxLayout = qt.QHBoxLayout(hbox)
hboxLayout.setContentsMargins(0, 0, 0, 0)
hboxLayout.setSpacing(2)
diff --git a/silx/gui/widgets/PrintPreview.py b/silx/gui/widgets/PrintPreview.py
index 2b4c433..78d1bd7 100644
--- a/silx/gui/widgets/PrintPreview.py
+++ b/silx/gui/widgets/PrintPreview.py
@@ -31,7 +31,7 @@ The user can interactively move and resize the items.
"""
import sys
import logging
-from silx.gui import qt
+from silx.gui import qt, printer
__authors__ = ["V.A. Sole", "P. Knobel"]
@@ -387,7 +387,7 @@ class PrintPreviewDialog(qt.QDialog):
*None*.
"""
if self.printer is None:
- self.printer = qt.QPrinter()
+ self.printer = printer.getDefaultPrinter()
if self.printDialog is None:
self.printDialog = qt.QPrintDialog(self.printer, self)
if self.printDialog.exec_():
diff --git a/silx/gui/widgets/test/__init__.py b/silx/gui/widgets/test/__init__.py
index 7affc20..5e62393 100644
--- a/silx/gui/widgets/test/__init__.py
+++ b/silx/gui/widgets/test/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,8 @@ from . import test_tablewidget
from . import test_threadpoolpushbutton
from . import test_hierarchicaltableview
from . import test_printpreview
+from . import test_framebrowser
+from . import test_boxlayoutdockwidget
__authors__ = ["V. Valls", "P. Knobel"]
__license__ = "MIT"
@@ -43,5 +45,7 @@ def suite():
test_periodictable.suite(),
test_printpreview.suite(),
test_hierarchicaltableview.suite(),
+ test_framebrowser.suite(),
+ test_boxlayoutdockwidget.suite(),
])
return test_suite
diff --git a/silx/gui/widgets/test/test_boxlayoutdockwidget.py b/silx/gui/widgets/test/test_boxlayoutdockwidget.py
new file mode 100644
index 0000000..0df262b
--- /dev/null
+++ b/silx/gui/widgets/test/test_boxlayoutdockwidget.py
@@ -0,0 +1,83 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Tests for BoxLayoutDockWidget"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "06/03/2018"
+
+import unittest
+
+from silx.gui.widgets.BoxLayoutDockWidget import BoxLayoutDockWidget
+from silx.gui import qt
+from silx.gui.test.utils import TestCaseQt
+
+
+class TestBoxLayoutDockWidget(TestCaseQt):
+ """Tests for BoxLayoutDockWidget"""
+
+ def setUp(self):
+ """Create and show a main window"""
+ self.window = qt.QMainWindow()
+ self.qWaitForWindowExposed(self.window)
+
+ def tearDown(self):
+ """Delete main window"""
+ self.window.setAttribute(qt.Qt.WA_DeleteOnClose)
+ self.window.close()
+ del self.window
+ self.qapp.processEvents()
+
+ def test(self):
+ """Test update of layout direction according to dock area"""
+ # Create a widget with a QBoxLayout
+ layout = qt.QBoxLayout(qt.QBoxLayout.LeftToRight)
+ layout.addWidget(qt.QLabel('First'))
+ layout.addWidget(qt.QLabel('Second'))
+ widget = qt.QWidget()
+ widget.setLayout(layout)
+
+ # Add it to a BoxLayoutDockWidget
+ dock = BoxLayoutDockWidget()
+ dock.setWidget(widget)
+
+ self.window.addDockWidget(qt.Qt.BottomDockWidgetArea, dock)
+ self.qapp.processEvents()
+ self.assertEqual(layout.direction(), qt.QBoxLayout.LeftToRight)
+
+ self.window.addDockWidget(qt.Qt.LeftDockWidgetArea, dock)
+ self.qapp.processEvents()
+ self.assertEqual(layout.direction(), qt.QBoxLayout.TopToBottom)
+
+
+def suite():
+ loader = unittest.defaultTestLoader.loadTestsFromTestCase
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(loader(TestBoxLayoutDockWidget))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/widgets/test/test_framebrowser.py b/silx/gui/widgets/test/test_framebrowser.py
new file mode 100644
index 0000000..9988d16
--- /dev/null
+++ b/silx/gui/widgets/test/test_framebrowser.py
@@ -0,0 +1,73 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "23/03/2018"
+
+
+import unittest
+
+from silx.gui.test.utils import TestCaseQt
+from silx.gui.widgets.FrameBrowser import FrameBrowser
+
+
+class TestFrameBrowser(TestCaseQt):
+ """Test for FrameBrowser"""
+
+ def test(self):
+ """Test FrameBrowser"""
+ widget = FrameBrowser()
+ widget.show()
+ self.qWaitForWindowExposed(widget)
+
+ nFrames = 20
+ widget.setNFrames(nFrames)
+ self.assertEqual(widget.getRange(), (0, nFrames - 1))
+ self.assertEqual(widget.getValue(), 0)
+
+ range_ = -100, 100
+ widget.setRange(*range_)
+ self.assertEqual(widget.getRange(), range_)
+ self.assertEqual(widget.getValue(), range_[0])
+
+ widget.setValue(0)
+ self.assertEqual(widget.getValue(), 0)
+
+ widget.setValue(range_[1] + 100)
+ self.assertEqual(widget.getValue(), range_[1])
+
+ widget.setValue(range_[0] - 100)
+ self.assertEqual(widget.getValue(), range_[0])
+
+
+def suite():
+ loader = unittest.defaultTestLoader.loadTestsFromTestCase
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(loader(TestFrameBrowser))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')