diff options
Diffstat (limited to 'silx/gui/widgets')
-rw-r--r-- | silx/gui/widgets/ElidedLabel.py | 137 | ||||
-rwxr-xr-x | silx/gui/widgets/LegendIconWidget.py | 7 | ||||
-rw-r--r-- | silx/gui/widgets/MultiModeAction.py | 83 | ||||
-rw-r--r-- | silx/gui/widgets/RangeSlider.py | 8 | ||||
-rw-r--r-- | silx/gui/widgets/UrlSelectionTable.py | 8 | ||||
-rw-r--r-- | silx/gui/widgets/test/__init__.py | 2 | ||||
-rw-r--r-- | silx/gui/widgets/test/test_elidedlabel.py | 111 |
7 files changed, 349 insertions, 7 deletions
diff --git a/silx/gui/widgets/ElidedLabel.py b/silx/gui/widgets/ElidedLabel.py new file mode 100644 index 0000000..58513c7 --- /dev/null +++ b/silx/gui/widgets/ElidedLabel.py @@ -0,0 +1,137 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2004-2020 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. +# +# ###########################################################################*/ +"""Module contains an elidable label +""" + +__license__ = "MIT" +__date__ = "07/12/2018" + +from silx.gui import qt + + +class ElidedLabel(qt.QLabel): + """QLabel with an edile property. + + By default if the text is too big, it is elided on the right. + + This mode can be changed with :func:`setElideMode`. + + In case the text is elided, the full content is displayed as part of the + tool tip. This behavior can be disabled with :func:`setTextAsToolTip`. + """ + + def __init__(self, parent=None): + super(ElidedLabel, self).__init__(parent) + self.__text = "" + self.__toolTip = "" + self.__textAsToolTip = True + self.__textIsElided = False + self.__elideMode = qt.Qt.ElideRight + self.__updateMinimumSize() + + def resizeEvent(self, event): + self.__updateText() + return qt.QLabel.resizeEvent(self, event) + + def setFont(self, font): + qt.QLabel.setFont(self, font) + self.__updateMinimumSize() + self.__updateText() + + def __updateMinimumSize(self): + metrics = qt.QFontMetrics(self.font()) + width = metrics.width("...") + self.setMinimumWidth(width) + + def __updateText(self): + metrics = qt.QFontMetrics(self.font()) + elidedText = metrics.elidedText(self.__text, self.__elideMode, self.width()) + qt.QLabel.setText(self, elidedText) + wasElided = self.__textIsElided + self.__textIsElided = elidedText != self.__text + if self.__textIsElided or wasElided != self.__textIsElided: + self.__updateToolTip() + + def __updateToolTip(self): + if self.__textIsElided and self.__textAsToolTip: + qt.QLabel.setToolTip(self, self.__text + "<br/>" + self.__toolTip) + else: + qt.QLabel.setToolTip(self, self.__toolTip) + + # Properties + + def setText(self, text): + self.__text = text + self.__updateText() + + def getText(self): + return self.__text + + text = qt.Property(str, getText, setText) + + def setToolTip(self, toolTip): + self.__toolTip = toolTip + self.__updateToolTip() + + def getToolTip(self): + return self.__toolTip + + toolTip = qt.Property(str, getToolTip, setToolTip) + + def setElideMode(self, elideMode): + """Set the elide mode. + + :param qt.Qt.TextElideMode elidMode: Elide mode to use + """ + self.__elideMode = elideMode + self.__updateText() + + def getElideMode(self): + """Returns the used elide mode. + + :rtype: qt.Qt.TextElideMode + """ + return self.__elideMode + + elideMode = qt.Property(qt.Qt.TextElideMode, getToolTip, setToolTip) + + def setTextAsToolTip(self, enabled): + """Enable displaying text as part of the tooltip if it is elided. + + :param bool enabled: Enable the behavior + """ + if self.__textAsToolTip == enabled: + return + self.__textAsToolTip = enabled + self.__updateToolTip() + + def getTextAsToolTip(self): + """True if an elided text is displayed as part of the tooltip. + + :rtype: bool + """ + return self.__textAsToolTip + + textAsToolTip = qt.Property(bool, getTextAsToolTip, setTextAsToolTip) diff --git a/silx/gui/widgets/LegendIconWidget.py b/silx/gui/widgets/LegendIconWidget.py index 1a403cb..1c95e41 100755 --- a/silx/gui/widgets/LegendIconWidget.py +++ b/silx/gui/widgets/LegendIconWidget.py @@ -336,10 +336,11 @@ class LegendIconWidget(qt.QWidget): pixmapRect = qt.QRect(0, 0, _COLORMAP_PIXMAP_SIZE, 1) widthMargin = 0 halfHeight = 4 + widgetRect = self.rect() dest = qt.QRect( - rect.left() + widthMargin, - rect.center().y() - halfHeight + 1, - rect.width() - widthMargin * 2, + widgetRect.left() + widthMargin, + widgetRect.center().y() - halfHeight + 1, + widgetRect.width() - widthMargin * 2, halfHeight * 2, ) painter.drawImage(dest, image, pixmapRect) diff --git a/silx/gui/widgets/MultiModeAction.py b/silx/gui/widgets/MultiModeAction.py new file mode 100644 index 0000000..502275d --- /dev/null +++ b/silx/gui/widgets/MultiModeAction.py @@ -0,0 +1,83 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2004-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. +# +# ###########################################################################*/ +"""Action to hold many mode actions, usually for a tool bar. +""" + +__authors__ = ["V. Valls"] +__license__ = "MIT" +__data__ = "22/04/2020" + + +from silx.gui import qt + + +class MultiModeAction(qt.QWidgetAction): + """This action provides a default checkable action from a list of checkable + actions. + + The default action can be selected from a drop down list. The last one used + became the default one. + + The default action is directly usable without using the drop down list. + """ + + def __init__(self, parent=None): + assert isinstance(parent, qt.QWidget) + qt.QWidgetAction.__init__(self, parent) + button = qt.QToolButton(parent) + button.setPopupMode(qt.QToolButton.MenuButtonPopup) + self.setDefaultWidget(button) + self.__button = button + + def getMenu(self): + """Returns the menu. + + :rtype: qt.QMenu + """ + button = self.__button + menu = button.menu() + if menu is None: + menu = qt.QMenu(button) + button.setMenu(menu) + return menu + + def addAction(self, action): + """Add a new action to the list. + + :param qt.QAction action: New action + """ + menu = self.getMenu() + button = self.__button + menu.addAction(action) + if button.defaultAction() is None: + button.setDefaultAction(action) + if action.isCheckable(): + action.toggled.connect(self._toggled) + + def _toggled(self, checked): + if checked: + action = self.sender() + button = self.__button + button.setDefaultAction(action) diff --git a/silx/gui/widgets/RangeSlider.py b/silx/gui/widgets/RangeSlider.py index c352147..31dbd4e 100644 --- a/silx/gui/widgets/RangeSlider.py +++ b/silx/gui/widgets/RangeSlider.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2015-2019 European Synchrotron Radiation Facility +# Copyright (c) 2015-2020 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 @@ -606,9 +606,9 @@ class RangeSlider(qt.QWidget): -self._SLIDER_WIDTH, 0) def __sliderAreaRect(self): - return self.__drawArea().adjusted(self._SLIDER_WIDTH / 2., + return self.__drawArea().adjusted(self._SLIDER_WIDTH // 2, 0, - -self._SLIDER_WIDTH / 2. + 1, + -self._SLIDER_WIDTH // 2 + 1, 0) def __pixMapRect(self): @@ -722,7 +722,7 @@ class RangeSlider(qt.QWidget): buttonColor = option.palette.button().color() val = qt.qGray(buttonColor.rgb()) buttonColor = buttonColor.lighter(100 + max(1, (180 - val) // 6)) - buttonColor.setHsv(buttonColor.hue(), buttonColor.saturation() * 0.75, buttonColor.value()) + buttonColor.setHsv(buttonColor.hue(), (buttonColor.saturation() * 3) // 4, buttonColor.value()) grooveColor = qt.QColor() grooveColor.setHsv(buttonColor.hue(), diff --git a/silx/gui/widgets/UrlSelectionTable.py b/silx/gui/widgets/UrlSelectionTable.py index 4ac0381..27ea363 100644 --- a/silx/gui/widgets/UrlSelectionTable.py +++ b/silx/gui/widgets/UrlSelectionTable.py @@ -74,6 +74,14 @@ class UrlSelectionTable(TableWidget): self.setSortingEnabled(True) self._checkBoxes = {} + def setUrls(self, urls: list) -> None: + """ + + :param urls: urls to be displayed + """ + for url in urls: + self.addUrl(url=url) + def addUrl(self, url, **kwargs): """ diff --git a/silx/gui/widgets/test/__init__.py b/silx/gui/widgets/test/__init__.py index 8d179bc..b868171 100644 --- a/silx/gui/widgets/test/__init__.py +++ b/silx/gui/widgets/test/__init__.py @@ -33,6 +33,7 @@ from . import test_framebrowser from . import test_boxlayoutdockwidget from . import test_rangeslider from . import test_flowlayout +from . import test_elidedlabel __authors__ = ["V. Valls", "P. Knobel"] __license__ = "MIT" @@ -51,5 +52,6 @@ def suite(): test_boxlayoutdockwidget.suite(), test_rangeslider.suite(), test_flowlayout.suite(), + test_elidedlabel.suite(), ]) return test_suite diff --git a/silx/gui/widgets/test/test_elidedlabel.py b/silx/gui/widgets/test/test_elidedlabel.py new file mode 100644 index 0000000..2856733 --- /dev/null +++ b/silx/gui/widgets/test/test_elidedlabel.py @@ -0,0 +1,111 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2020 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 ElidedLabel""" + +__license__ = "MIT" +__date__ = "08/06/2020" + +import unittest + +from silx.gui import qt +from silx.gui.widgets.ElidedLabel import ElidedLabel +from silx.gui.utils import testutils + + +class TestElidedLabel(testutils.TestCaseQt): + + def setUp(self): + self.label = ElidedLabel() + self.label.show() + self.qWaitForWindowExposed(self.label) + + def tearDown(self): + self.label.setAttribute(qt.Qt.WA_DeleteOnClose) + self.label.close() + del self.label + self.qapp.processEvents() + + def testElidedValue(self): + """Test elided text""" + raw = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" + self.label.setText(raw) + self.label.setFixedWidth(30) + displayedText = qt.QLabel.text(self.label) + self.assertNotEqual(raw, displayedText) + self.assertIn("…", displayedText) + self.assertIn("m", displayedText) + + def testNotElidedValue(self): + """Test elided text""" + raw = "mmmmmmm" + self.label.setText(raw) + self.label.setFixedWidth(200) + displayedText = qt.QLabel.text(self.label) + self.assertNotIn("…", displayedText) + self.assertEqual(raw, displayedText) + + def testUpdateFromElidedToNotElided(self): + """Test tooltip when not elided""" + raw1 = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" + raw2 = "nn" + self.label.setText(raw1) + self.label.setFixedWidth(30) + self.label.setText(raw2) + displayedTooltip = qt.QLabel.toolTip(self.label) + self.assertNotIn(raw1, displayedTooltip) + self.assertNotIn(raw2, displayedTooltip) + + def testUpdateFromNotElidedToElided(self): + """Test tooltip when elided""" + raw1 = "nn" + raw2 = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" + self.label.setText(raw1) + self.label.setFixedWidth(30) + self.label.setText(raw2) + displayedTooltip = qt.QLabel.toolTip(self.label) + self.assertNotIn(raw1, displayedTooltip) + self.assertIn(raw2, displayedTooltip) + + def testUpdateFromElidedToElided(self): + """Test tooltip when elided""" + raw1 = "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" + raw2 = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" + self.label.setText(raw1) + self.label.setFixedWidth(30) + self.label.setText(raw2) + displayedTooltip = qt.QLabel.toolTip(self.label) + self.assertNotIn(raw1, displayedTooltip) + self.assertIn(raw2, displayedTooltip) + + +def suite(): + loader = unittest.defaultTestLoader.loadTestsFromTestCase + test_suite = unittest.TestSuite() + test_suite.addTest(loader(TestElidedLabel)) + return test_suite + + +if __name__ == '__main__': + unittest.main(defaultTest='suite') |