diff --git a/anylabeling/views/labeling/label_widget.py b/anylabeling/views/labeling/label_widget.py index a428bb55..c9145508 100644 --- a/anylabeling/views/labeling/label_widget.py +++ b/anylabeling/views/labeling/label_widget.py @@ -97,6 +97,12 @@ LABEL_OPACITY = 128 +def _measure_text_width(font_metrics, text): + if hasattr(font_metrics, "horizontalAdvance"): + return font_metrics.horizontalAdvance(text) + return font_metrics.width(text) + + class LabelingWidget(LabelDialog): """The main widget for labeling images""" @@ -3720,12 +3726,12 @@ def update_attributes(self, shape_index): if hasattr(self, "grid_layout_container"): font_metrics = QFontMetrics(self.grid_layout_container.font()) else: - font_metrics = QLabel().font() + font_metrics = QFontMetrics(QLabel().font()) available_width = self.scroll_area.width() - 30 property_display = property - if font_metrics.width(property) > available_width: + if _measure_text_width(font_metrics, property) > available_width: while ( - font_metrics.width(property_display + "...") + _measure_text_width(font_metrics, property_display + "...") > available_width and len(property_display) > 1 ): @@ -3747,18 +3753,19 @@ def update_attributes(self, shape_index): main_layout.setSpacing(2) def get_truncated_text(text, max_width): - if font_metrics.width(text) <= max_width: + if _measure_text_width(font_metrics, text) <= max_width: return text, text truncated = text while ( - font_metrics.width(truncated + "...") > max_width + _measure_text_width(font_metrics, truncated + "...") + > max_width and len(truncated) > 1 ): truncated = truncated[:-1] return truncated + "...", text def get_button_width(text): - return font_metrics.width(text) + 30 + return _measure_text_width(font_metrics, text) + 30 def create_radio_button_with_handler( display_text, original_text, prop, shape_idx diff --git a/tests/test_label_widget_metrics.py b/tests/test_label_widget_metrics.py new file mode 100644 index 00000000..b32ccd96 --- /dev/null +++ b/tests/test_label_widget_metrics.py @@ -0,0 +1,43 @@ +import os +import unittest + +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") + +try: + from PyQt6 import QtGui, QtWidgets + + PYQT_AVAILABLE = True +except Exception: + PYQT_AVAILABLE = False + + +@unittest.skipUnless( + PYQT_AVAILABLE, "PyQt6 is required for label widget metrics tests" +) +class TestLabelWidgetMetrics(unittest.TestCase): + + def setUp(self): + self.app = QtWidgets.QApplication.instance() + if self.app is None: + self.app = QtWidgets.QApplication([]) + + def test_measure_text_width_matches_horizontal_advance(self): + from anylabeling.views.labeling.label_widget import _measure_text_width + + font = self.app.font() + metrics = QtGui.QFontMetrics(font) + + self.assertEqual( + _measure_text_width(metrics, "bodyColor"), + metrics.horizontalAdvance("bodyColor"), + ) + + def test_measure_text_width_falls_back_to_width(self): + from anylabeling.views.labeling.label_widget import _measure_text_width + + class LegacyFontMetrics: + def width(self, text): + return len(text) * 7 + + metrics = LegacyFontMetrics() + self.assertEqual(_measure_text_width(metrics, "vehicle"), 49)