summaryrefslogtreecommitdiff
path: root/src/silx/gui/widgets/FloatEdit.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/silx/gui/widgets/FloatEdit.py')
-rw-r--r--src/silx/gui/widgets/FloatEdit.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/silx/gui/widgets/FloatEdit.py b/src/silx/gui/widgets/FloatEdit.py
new file mode 100644
index 0000000..f9d7331
--- /dev/null
+++ b/src/silx/gui/widgets/FloatEdit.py
@@ -0,0 +1,154 @@
+# /*##########################################################################
+#
+# Copyright (c) 2004-2023 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 a float editor
+"""
+from __future__ import annotations
+
+
+__authors__ = ["V.A. Sole", "T. Vincent"]
+__license__ = "MIT"
+__date__ = "02/10/2017"
+
+from .. import qt
+
+
+class FloatEdit(qt.QLineEdit):
+ """Field to edit a float value.
+
+ The value can be modified with :meth:`value` and :meth:`setValue`.
+
+ The property :meth:`widgetResizable` allow to change the default
+ behaviour in order to automatically resize the widget to the displayed value.
+ Use :meth:`setMinimumWidth` to enforce the minimum width.
+
+ :param parent: Parent of the widget
+ :param value: The value to set the QLineEdit to.
+ """
+
+ _QLineEditPrivateHorizontalMargin = 2
+ """Constant from Qt source code"""
+
+ def __init__(self, parent: qt.QWidget | None = None, value: float | None = None):
+ qt.QLineEdit.__init__(self, parent)
+ validator = qt.QDoubleValidator(self)
+ self.__widgetResizable: bool = False
+ self.__minimumWidth = 30
+ """Store the minimum width requested by the user, the real one is
+ dynamic"""
+ self.setValidator(validator)
+ self.setAlignment(qt.Qt.AlignRight)
+ self.textChanged.connect(self.__textChanged)
+ if value is not None:
+ self.setValue(value)
+
+ def value(self) -> float:
+ """Return the QLineEdit current value as a float."""
+ text = self.text()
+ value, validated = self.validator().locale().toDouble(text)
+ if not validated:
+ self.setValue(value)
+ return value
+
+ def setValue(self, value: float):
+ """Set the current value of the LineEdit
+
+ :param value: The value to set the QLineEdit to.
+ """
+ locale = self.validator().locale()
+ if qt.BINDING == "PySide6":
+ # Fix for PySide6 not selecting the right method
+ text = locale.toString(float(value), "g")
+ else:
+ text = locale.toString(float(value))
+
+ self.setText(text)
+ if self.__widgetResizable:
+ self.__forceMinimumWidthFromContent()
+
+ def __textChanged(self, text: str):
+ if self.__widgetResizable:
+ self.__forceMinimumWidthFromContent()
+
+ def widgetResizable(self) -> bool:
+ """
+ Returns whether or not the widget auto resizes itself based on it's content
+ """
+ return self.__widgetResizable
+
+ def setWidgetResizable(self, resizable: bool):
+ """
+ If true, the widget will automatically resize itself to its displayed content.
+
+ This avoids to have to scroll to see the widget's content, and allow to take
+ advantage of extra space.
+ """
+ if self.__widgetResizable == resizable:
+ return
+ self.__widgetResizable = resizable
+ self.updateGeometry()
+ if resizable:
+ self.__forceMinimumWidthFromContent()
+ else:
+ qt.QLineEdit.setMinimumWidth(self, self.__minimumWidth)
+
+ def __minimumWidthFromContent(self) -> int:
+ """Minimum size for the widget to properly read the actual number"""
+ text = self.text()
+ font = self.font()
+ metrics = qt.QFontMetrics(font)
+ margins = self.textMargins()
+ width = (
+ metrics.horizontalAdvance(text)
+ + self._QLineEditPrivateHorizontalMargin * 2
+ + margins.left()
+ + margins.right()
+ )
+ width = max(self.__minimumWidth, width)
+ opt = qt.QStyleOptionFrame()
+ self.initStyleOption(opt)
+ s = self.style().sizeFromContents(
+ qt.QStyle.CT_LineEdit, opt, qt.QSize(width, self.height())
+ )
+ return s.width()
+
+ def sizeHint(self) -> qt.QSize:
+ sizeHint = qt.QLineEdit.sizeHint(self)
+ if not self.__widgetResizable:
+ return sizeHint
+ width = self.__minimumWidthFromContent()
+ return qt.QSize(width, sizeHint.height())
+
+ def __forceMinimumWidthFromContent(self):
+ width = self.__minimumWidthFromContent()
+ qt.QLineEdit.setMinimumWidth(self, width)
+ self.updateGeometry()
+
+ def setMinimumWidth(self, width: int):
+ self.__minimumWidth = width
+ qt.QLineEdit.setMinimumWidth(self, width)
+ self.updateGeometry()
+
+ def minimumWidth(self) -> int:
+ """Returns the user defined minimum width."""
+ return self.__minimumWidth