butterfly_viewer.aux_dialogs

QDialog widgets for SplitView.

Not intended as a script. Used in Butterfly Viewer.

Creates a dialog window for users to calculate the pixel-unit conversion for rulers in SplitView.

  1#!/usr/bin/env python3
  2
  3"""QDialog widgets for SplitView.
  4
  5Not intended as a script. Used in Butterfly Viewer.
  6
  7Creates a dialog window for users to calculate the pixel-unit conversion for rulers in SplitView.
  8"""
  9# SPDX-License-Identifier: GPL-3.0-or-later
 10
 11
 12
 13from PyQt5 import QtWidgets, QtCore
 14
 15
 16
 17class PixelUnitConversionInputDialog(QtWidgets.QDialog):
 18    """Create a dialog window to calculate the conversion for pixels to other units of length in SplitView.
 19    
 20    Currently only supports millimeters.
 21    Emits the value of the px-per-mm conversion if user clicks "Ok" on dialog.
 22
 23    Args:
 24        parent: Do not set OR only set to None.
 25        unit (str): Unit of length to which to convert from pixels, abbreviated. 
 26            Currently only supports "mm" (millimeters).
 27        px_conversion (float): Quantity of pixels in a known distance.
 28        unit_conversion (float): Quantity of the specified unit of length in a known distance.
 29        px_per_unit (float): Pixel-per-unit conversion. Set to None if not previously calculated.
 30    """  
 31
 32    def __init__(self, parent=None, unit="mm", px_conversion=1.0, unit_conversion=1.0, px_per_unit=None):
 33        super().__init__(parent)
 34        self.setWindowTitle("Set conversion factor for pixel-per-" + unit + " conversion for this image window")
 35        self.setWindowFlags(QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint)
 36
 37        frame_rect = self.frameGeometry()
 38        center_point = QtWidgets.QDesktopWidget().availableGeometry().center()
 39        frame_rect.moveCenter(center_point)
 40        self.move(frame_rect.topLeft())
 41
 42        self.unit = unit
 43        if unit == "mm":
 44            self.unit_longform = "millimeter"
 45            self.unit_longform_cap = "Millimeter"
 46        else:
 47            self.unit_longform = unit
 48            self.unit_longform_cap = self.unit_longform
 49        self.px_conversion = px_conversion # e.g., 100 pixels
 50        self.unit_conversion = unit_conversion # e.g., 50 mm
 51        self.px_per_unit = px_per_unit
 52        if self.px_per_unit is None:
 53            self.px_per_unit = self.px_conversion/self.unit_conversion # e.g., 100 px per 50 mm = 2 px/mm
 54
 55        buttonbox = QtWidgets.QDialogButtonBox()
 56        buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 57        buttonbox.accepted.connect(self.accept) 
 58        buttonbox.rejected.connect(self.reject)
 59
 60        dialog_string = "Enter the pixel and " + self.unit_longform + " length for a known distance in the base image of the active window."
 61        dialog_string = dialog_string + "\n\n" + "Tip: First use a pixel ruler to measure a known distance in the image (such as the width of a painting canvas or the length of a calibration ruler) and then enter the distance in pixels and " + self.unit_longform + "s here.\n"
 62        dialog_label = QtWidgets.QLabel(dialog_string)
 63        dialog_label.setWordWrap(True)
 64
 65        values_layout = QtWidgets.QGridLayout()
 66        px_label = QtWidgets.QLabel("Pixels in a known distance: ")
 67        px_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 68        px_string = "{:.2f}".format(self.px_conversion)
 69        self.px_textedit = QtWidgets.QLineEdit(px_string)
 70        self.px_textedit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
 71        self.px_textedit.textEdited.connect(self.on_px_textedit_edited)
 72        self.px_textedit.editingFinished.connect(lambda: self.px_textedit.setText("{:.2f}".format(self.px_conversion)))
 73
 74        unit_label = QtWidgets.QLabel(self.unit_longform_cap + "s" + " in a known distance: ")
 75        unit_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 76        unit_string = "{:.2f}".format(self.unit_conversion) # + " " + "px"
 77        self.unit_textedit = QtWidgets.QLineEdit(unit_string)
 78        self.unit_textedit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
 79        self.unit_textedit.textEdited.connect(self.on_unit_textedit_edited)
 80        self.unit_textedit.editingFinished.connect(lambda: self.unit_textedit.setText("{:.2f}".format(self.unit_conversion)))
 81
 82        px_per_unit_label = QtWidgets.QLabel("Calculated pixels per " + self.unit_longform + " for the known distance: ")
 83        px_per_unit_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 84        px_per_unit_string = "{:.2f}".format(self.px_per_unit)
 85        self.px_per_unit_textedit = QtWidgets.QLineEdit(px_per_unit_string)
 86        self.px_per_unit_textedit.setStyleSheet("""
 87            QLineEdit {
 88                background-color: transparent;
 89                border: 0px transparent;
 90            }
 91            """)
 92        self.px_per_unit_textedit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
 93        self.px_per_unit_textedit.setReadOnly(True)
 94
 95        values_layout.addWidget(px_label, 0, 0)
 96        values_layout.addWidget(self.px_textedit, 0, 1)
 97        values_layout.addWidget(unit_label, 1, 0)
 98        values_layout.addWidget(self.unit_textedit, 1, 1)
 99        values_layout.addWidget(px_per_unit_label, 2, 0)
100        values_layout.addWidget(self.px_per_unit_textedit, 2, 1)
101
102        values_layout_widget = QtWidgets.QWidget()
103        values_layout_widget.setLayout(values_layout)
104
105        layout = QtWidgets.QGridLayout()
106        self.setLayout(layout)
107
108        layout.addWidget(dialog_label)
109        layout.addWidget(values_layout_widget)
110        layout.addWidget(buttonbox)
111
112        self.setStyleSheet("font-size: 9pt")
113
114    def on_px_textedit_edited(self, text):
115        """Filter and correct text typed into pixel field.
116        
117        Corrects the following:
118            Decimal comma to decimal point (0,2 > 0.2).
119            No leading zero to leading zero (.2 > 0.2).
120            Hanging decimal to zero in tenths place (2. > 2.0).
121
122        Filters:
123            Non-numeric text.
124            Non float-to-text convertible numbers.
125            Zeroes (distances cannot be zero).
126
127        Triggered by QLineEdit.textEdited.
128        
129        Args:
130            text (str): From QLineEdit.textEdited.
131        """
132        if text is None:
133            return
134        text = text.replace(" ", "")
135        if text is "":
136            return
137        text = text.replace(",", ".")
138        text_filter = text
139        text_filter = text.replace(".", "")
140        if not text_filter.isnumeric():
141            return
142        if text.endswith("."):
143            text.replace(".", ".0")
144        if text.startswith("."):
145            text.replace(".", "0.")
146        
147        try: 
148            px_conversion = float(text)
149        except:
150            return
151        
152        try: #: Ensure not zero.
153            1/px_conversion
154        except:
155            return
156       
157        self.px_conversion = px_conversion
158        self.px_per_unit = self.px_conversion/self.unit_conversion
159        self.px_per_unit_textedit.setText("{:.2f}".format(self.px_per_unit))
160
161    def on_unit_textedit_edited(self, text):
162        """Filter and correct text typed into unit of length field.
163        
164        Corrects the following:
165            Decimal comma to decimal point (0,2 > 0.2).
166            No leading zero to leading zero (.2 > 0.2).
167            Hanging decimal to zero in tenths place (2. > 2.0).
168
169        Filters:
170            Non-numeric text.
171            Non float-to-text convertible numbers.
172            Zeroes.
173
174        Triggered by QLineEdit.textEdited.
175        
176        Args:
177            text (str): From QLineEdit.textEdited.
178        """
179        if text is None:
180            return
181        text = text.replace(" ", "")
182        if text is "":
183            return
184        text = text.replace(",", ".")
185        text_filter = text
186        text_filter = text.replace(".", "")
187        if not text_filter.isnumeric():
188            return
189        if text.endswith("."):
190            text.replace(".", ".0")
191        if text.startswith("."):
192            text.replace(".", "0.")
193            
194        try:
195            unit_conversion = float(text)
196        except:
197            return
198        
199        try: #: Ensure not dividing by zero.
200            px_per_unit = self.px_conversion/unit_conversion
201        except:
202            return
203        
204        self.unit_conversion = unit_conversion
205        self.px_per_unit = px_per_unit
206        self.px_per_unit_textedit.setText("{:.2f}".format(self.px_per_unit))
class PixelUnitConversionInputDialog(PyQt5.QtWidgets.QDialog):
 18class PixelUnitConversionInputDialog(QtWidgets.QDialog):
 19    """Create a dialog window to calculate the conversion for pixels to other units of length in SplitView.
 20    
 21    Currently only supports millimeters.
 22    Emits the value of the px-per-mm conversion if user clicks "Ok" on dialog.
 23
 24    Args:
 25        parent: Do not set OR only set to None.
 26        unit (str): Unit of length to which to convert from pixels, abbreviated. 
 27            Currently only supports "mm" (millimeters).
 28        px_conversion (float): Quantity of pixels in a known distance.
 29        unit_conversion (float): Quantity of the specified unit of length in a known distance.
 30        px_per_unit (float): Pixel-per-unit conversion. Set to None if not previously calculated.
 31    """  
 32
 33    def __init__(self, parent=None, unit="mm", px_conversion=1.0, unit_conversion=1.0, px_per_unit=None):
 34        super().__init__(parent)
 35        self.setWindowTitle("Set conversion factor for pixel-per-" + unit + " conversion for this image window")
 36        self.setWindowFlags(QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint)
 37
 38        frame_rect = self.frameGeometry()
 39        center_point = QtWidgets.QDesktopWidget().availableGeometry().center()
 40        frame_rect.moveCenter(center_point)
 41        self.move(frame_rect.topLeft())
 42
 43        self.unit = unit
 44        if unit == "mm":
 45            self.unit_longform = "millimeter"
 46            self.unit_longform_cap = "Millimeter"
 47        else:
 48            self.unit_longform = unit
 49            self.unit_longform_cap = self.unit_longform
 50        self.px_conversion = px_conversion # e.g., 100 pixels
 51        self.unit_conversion = unit_conversion # e.g., 50 mm
 52        self.px_per_unit = px_per_unit
 53        if self.px_per_unit is None:
 54            self.px_per_unit = self.px_conversion/self.unit_conversion # e.g., 100 px per 50 mm = 2 px/mm
 55
 56        buttonbox = QtWidgets.QDialogButtonBox()
 57        buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 58        buttonbox.accepted.connect(self.accept) 
 59        buttonbox.rejected.connect(self.reject)
 60
 61        dialog_string = "Enter the pixel and " + self.unit_longform + " length for a known distance in the base image of the active window."
 62        dialog_string = dialog_string + "\n\n" + "Tip: First use a pixel ruler to measure a known distance in the image (such as the width of a painting canvas or the length of a calibration ruler) and then enter the distance in pixels and " + self.unit_longform + "s here.\n"
 63        dialog_label = QtWidgets.QLabel(dialog_string)
 64        dialog_label.setWordWrap(True)
 65
 66        values_layout = QtWidgets.QGridLayout()
 67        px_label = QtWidgets.QLabel("Pixels in a known distance: ")
 68        px_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 69        px_string = "{:.2f}".format(self.px_conversion)
 70        self.px_textedit = QtWidgets.QLineEdit(px_string)
 71        self.px_textedit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
 72        self.px_textedit.textEdited.connect(self.on_px_textedit_edited)
 73        self.px_textedit.editingFinished.connect(lambda: self.px_textedit.setText("{:.2f}".format(self.px_conversion)))
 74
 75        unit_label = QtWidgets.QLabel(self.unit_longform_cap + "s" + " in a known distance: ")
 76        unit_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 77        unit_string = "{:.2f}".format(self.unit_conversion) # + " " + "px"
 78        self.unit_textedit = QtWidgets.QLineEdit(unit_string)
 79        self.unit_textedit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
 80        self.unit_textedit.textEdited.connect(self.on_unit_textedit_edited)
 81        self.unit_textedit.editingFinished.connect(lambda: self.unit_textedit.setText("{:.2f}".format(self.unit_conversion)))
 82
 83        px_per_unit_label = QtWidgets.QLabel("Calculated pixels per " + self.unit_longform + " for the known distance: ")
 84        px_per_unit_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 85        px_per_unit_string = "{:.2f}".format(self.px_per_unit)
 86        self.px_per_unit_textedit = QtWidgets.QLineEdit(px_per_unit_string)
 87        self.px_per_unit_textedit.setStyleSheet("""
 88            QLineEdit {
 89                background-color: transparent;
 90                border: 0px transparent;
 91            }
 92            """)
 93        self.px_per_unit_textedit.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
 94        self.px_per_unit_textedit.setReadOnly(True)
 95
 96        values_layout.addWidget(px_label, 0, 0)
 97        values_layout.addWidget(self.px_textedit, 0, 1)
 98        values_layout.addWidget(unit_label, 1, 0)
 99        values_layout.addWidget(self.unit_textedit, 1, 1)
100        values_layout.addWidget(px_per_unit_label, 2, 0)
101        values_layout.addWidget(self.px_per_unit_textedit, 2, 1)
102
103        values_layout_widget = QtWidgets.QWidget()
104        values_layout_widget.setLayout(values_layout)
105
106        layout = QtWidgets.QGridLayout()
107        self.setLayout(layout)
108
109        layout.addWidget(dialog_label)
110        layout.addWidget(values_layout_widget)
111        layout.addWidget(buttonbox)
112
113        self.setStyleSheet("font-size: 9pt")
114
115    def on_px_textedit_edited(self, text):
116        """Filter and correct text typed into pixel field.
117        
118        Corrects the following:
119            Decimal comma to decimal point (0,2 > 0.2).
120            No leading zero to leading zero (.2 > 0.2).
121            Hanging decimal to zero in tenths place (2. > 2.0).
122
123        Filters:
124            Non-numeric text.
125            Non float-to-text convertible numbers.
126            Zeroes (distances cannot be zero).
127
128        Triggered by QLineEdit.textEdited.
129        
130        Args:
131            text (str): From QLineEdit.textEdited.
132        """
133        if text is None:
134            return
135        text = text.replace(" ", "")
136        if text is "":
137            return
138        text = text.replace(",", ".")
139        text_filter = text
140        text_filter = text.replace(".", "")
141        if not text_filter.isnumeric():
142            return
143        if text.endswith("."):
144            text.replace(".", ".0")
145        if text.startswith("."):
146            text.replace(".", "0.")
147        
148        try: 
149            px_conversion = float(text)
150        except:
151            return
152        
153        try: #: Ensure not zero.
154            1/px_conversion
155        except:
156            return
157       
158        self.px_conversion = px_conversion
159        self.px_per_unit = self.px_conversion/self.unit_conversion
160        self.px_per_unit_textedit.setText("{:.2f}".format(self.px_per_unit))
161
162    def on_unit_textedit_edited(self, text):
163        """Filter and correct text typed into unit of length field.
164        
165        Corrects the following:
166            Decimal comma to decimal point (0,2 > 0.2).
167            No leading zero to leading zero (.2 > 0.2).
168            Hanging decimal to zero in tenths place (2. > 2.0).
169
170        Filters:
171            Non-numeric text.
172            Non float-to-text convertible numbers.
173            Zeroes.
174
175        Triggered by QLineEdit.textEdited.
176        
177        Args:
178            text (str): From QLineEdit.textEdited.
179        """
180        if text is None:
181            return
182        text = text.replace(" ", "")
183        if text is "":
184            return
185        text = text.replace(",", ".")
186        text_filter = text
187        text_filter = text.replace(".", "")
188        if not text_filter.isnumeric():
189            return
190        if text.endswith("."):
191            text.replace(".", ".0")
192        if text.startswith("."):
193            text.replace(".", "0.")
194            
195        try:
196            unit_conversion = float(text)
197        except:
198            return
199        
200        try: #: Ensure not dividing by zero.
201            px_per_unit = self.px_conversion/unit_conversion
202        except:
203            return
204        
205        self.unit_conversion = unit_conversion
206        self.px_per_unit = px_per_unit
207        self.px_per_unit_textedit.setText("{:.2f}".format(self.px_per_unit))

Create a dialog window to calculate the conversion for pixels to other units of length in SplitView.

Currently only supports millimeters. Emits the value of the px-per-mm conversion if user clicks "Ok" on dialog.

Arguments:
  • parent: Do not set OR only set to None.
  • unit (str): Unit of length to which to convert from pixels, abbreviated. Currently only supports "mm" (millimeters).
  • px_conversion (float): Quantity of pixels in a known distance.
  • unit_conversion (float): Quantity of the specified unit of length in a known distance.
  • px_per_unit (float): Pixel-per-unit conversion. Set to None if not previously calculated.
def on_px_textedit_edited(self, text):
115    def on_px_textedit_edited(self, text):
116        """Filter and correct text typed into pixel field.
117        
118        Corrects the following:
119            Decimal comma to decimal point (0,2 > 0.2).
120            No leading zero to leading zero (.2 > 0.2).
121            Hanging decimal to zero in tenths place (2. > 2.0).
122
123        Filters:
124            Non-numeric text.
125            Non float-to-text convertible numbers.
126            Zeroes (distances cannot be zero).
127
128        Triggered by QLineEdit.textEdited.
129        
130        Args:
131            text (str): From QLineEdit.textEdited.
132        """
133        if text is None:
134            return
135        text = text.replace(" ", "")
136        if text is "":
137            return
138        text = text.replace(",", ".")
139        text_filter = text
140        text_filter = text.replace(".", "")
141        if not text_filter.isnumeric():
142            return
143        if text.endswith("."):
144            text.replace(".", ".0")
145        if text.startswith("."):
146            text.replace(".", "0.")
147        
148        try: 
149            px_conversion = float(text)
150        except:
151            return
152        
153        try: #: Ensure not zero.
154            1/px_conversion
155        except:
156            return
157       
158        self.px_conversion = px_conversion
159        self.px_per_unit = self.px_conversion/self.unit_conversion
160        self.px_per_unit_textedit.setText("{:.2f}".format(self.px_per_unit))

Filter and correct text typed into pixel field.

Corrects the following:

Decimal comma to decimal point (0,2 > 0.2). No leading zero to leading zero (.2 > 0.2). Hanging decimal to zero in tenths place (2. > 2.0).

Filters:

Non-numeric text. Non float-to-text convertible numbers. Zeroes (distances cannot be zero).

Triggered by QLineEdit.textEdited.

Arguments:
  • text (str): From QLineEdit.textEdited.
def on_unit_textedit_edited(self, text):
162    def on_unit_textedit_edited(self, text):
163        """Filter and correct text typed into unit of length field.
164        
165        Corrects the following:
166            Decimal comma to decimal point (0,2 > 0.2).
167            No leading zero to leading zero (.2 > 0.2).
168            Hanging decimal to zero in tenths place (2. > 2.0).
169
170        Filters:
171            Non-numeric text.
172            Non float-to-text convertible numbers.
173            Zeroes.
174
175        Triggered by QLineEdit.textEdited.
176        
177        Args:
178            text (str): From QLineEdit.textEdited.
179        """
180        if text is None:
181            return
182        text = text.replace(" ", "")
183        if text is "":
184            return
185        text = text.replace(",", ".")
186        text_filter = text
187        text_filter = text.replace(".", "")
188        if not text_filter.isnumeric():
189            return
190        if text.endswith("."):
191            text.replace(".", ".0")
192        if text.startswith("."):
193            text.replace(".", "0.")
194            
195        try:
196            unit_conversion = float(text)
197        except:
198            return
199        
200        try: #: Ensure not dividing by zero.
201            px_per_unit = self.px_conversion/unit_conversion
202        except:
203            return
204        
205        self.unit_conversion = unit_conversion
206        self.px_per_unit = px_per_unit
207        self.px_per_unit_textedit.setText("{:.2f}".format(self.px_per_unit))

Filter and correct text typed into unit of length field.

Corrects the following:

Decimal comma to decimal point (0,2 > 0.2). No leading zero to leading zero (.2 > 0.2). Hanging decimal to zero in tenths place (2. > 2.0).

Filters:

Non-numeric text. Non float-to-text convertible numbers. Zeroes.

Triggered by QLineEdit.textEdited.

Arguments:
  • text (str): From QLineEdit.textEdited.