diff options
Diffstat (limited to 'silx/gui/widgets')
-rw-r--r-- | silx/gui/widgets/BoxLayoutDockWidget.py | 90 | ||||
-rw-r--r-- | silx/gui/widgets/FrameBrowser.py | 75 | ||||
-rw-r--r-- | silx/gui/widgets/PrintGeometryDialog.py | 2 | ||||
-rw-r--r-- | silx/gui/widgets/PrintPreview.py | 4 | ||||
-rw-r--r-- | silx/gui/widgets/test/__init__.py | 6 | ||||
-rw-r--r-- | silx/gui/widgets/test/test_boxlayoutdockwidget.py | 83 | ||||
-rw-r--r-- | silx/gui/widgets/test/test_framebrowser.py | 73 |
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') |