diff --git a/changes/3914.feature.md b/changes/3914.feature.1.md similarity index 100% rename from changes/3914.feature.md rename to changes/3914.feature.1.md diff --git a/changes/3914.feature.3.md b/changes/3914.feature.3.md new file mode 100644 index 0000000000..8cd17b0887 --- /dev/null +++ b/changes/3914.feature.3.md @@ -0,0 +1 @@ +The ImageView widget is now supported in the Qt backend. diff --git a/docs/en/reference/data/apis_by_platform.yaml b/docs/en/reference/data/apis_by_platform.yaml index b5628d1a39..07dbae809d 100644 --- a/docs/en/reference/data/apis_by_platform.yaml +++ b/docs/en/reference/data/apis_by_platform.yaml @@ -81,7 +81,6 @@ General widgets: unsupported: - web - textual - - qt Label: description: A text label for annotating forms or interfaces. diff --git a/docs/en/reference/images/imageview.png b/docs/en/reference/images/imageview-qt.png similarity index 100% rename from docs/en/reference/images/imageview.png rename to docs/en/reference/images/imageview-qt.png diff --git a/qt/src/toga_qt/factory.py b/qt/src/toga_qt/factory.py index 0ebee67fd1..0afae1ff39 100644 --- a/qt/src/toga_qt/factory.py +++ b/qt/src/toga_qt/factory.py @@ -14,6 +14,7 @@ from .widgets.activityindicator import ActivityIndicator from .widgets.box import Box from .widgets.button import Button + from .widgets.imageview import ImageView from .widgets.label import Label from .widgets.textinput import TextInput from .window import MainWindow, Window @@ -44,6 +45,7 @@ "Box", "Label", "TextInput", + "ImageView", "dialogs", ] diff --git a/qt/src/toga_qt/widgets/box.py b/qt/src/toga_qt/widgets/box.py index 026e6be969..3f845f7d09 100644 --- a/qt/src/toga_qt/widgets/box.py +++ b/qt/src/toga_qt/widgets/box.py @@ -11,7 +11,7 @@ def create(self): self.native.setAutoFillBackground(True) # Background is not autofilled by default; but since we're # enabling it here, let the default color be transparent - # so it autofills nothing. + # so it autofills nothing by default. self._default_background_color = TRANSPARENT def rehint(self): diff --git a/qt/src/toga_qt/widgets/imageview.py b/qt/src/toga_qt/widgets/imageview.py new file mode 100644 index 0000000000..56609eb7c1 --- /dev/null +++ b/qt/src/toga_qt/widgets/imageview.py @@ -0,0 +1,46 @@ +from PySide6.QtCore import Qt +from PySide6.QtGui import QPixmap +from PySide6.QtWidgets import QLabel +from travertino.constants import TRANSPARENT + +from toga.widgets.imageview import rehint_imageview + +from .base import Widget + + +class ImageView(Widget): + def create(self): + self.native = QLabel() + self.native.setAlignment(Qt.AlignCenter) + self._aspect_ratio = None + self.native.setAutoFillBackground(True) + # Background is not autofilled by default; but since we're + # enabling it here, let the default color be transparent + # so it autofills nothing by default. + self._default_background_color = TRANSPARENT + + def set_image(self, image): + if image: + self.set_scaled_pixbuf(image._impl.native) + else: + self.native.setPixmap(QPixmap()) + + def set_scaled_pixbuf(self, image): + scaled = QPixmap.fromImage(image).scaled( + self.native.size(), + Qt.KeepAspectRatio if self._aspect_ratio else Qt.IgnoreAspectRatio, + Qt.SmoothTransformation, + ) + self.native.setPixmap(scaled) + + def set_bounds(self, *args): + super().set_bounds(*args) + if self.interface.image: + self.set_scaled_pixbuf(self.interface.image._impl.native) + + def rehint(self): + width, height, self._aspect_ratio = rehint_imageview( + image=self.interface.image, style=self.interface.style + ) + self.interface.intrinsic.width = width + self.interface.intrinsic.height = height diff --git a/qt/tests_backend/widgets/box.py b/qt/tests_backend/widgets/box.py index 35abe58b44..99b89e0536 100644 --- a/qt/tests_backend/widgets/box.py +++ b/qt/tests_backend/widgets/box.py @@ -6,3 +6,7 @@ class BoxProbe(SimpleProbe): native_class = QWidget invalid_size_while_hidden = False + + def __init__(self, widget): + super().__init__(widget) + assert self.native.autoFillBackground() diff --git a/qt/tests_backend/widgets/imageview.py b/qt/tests_backend/widgets/imageview.py new file mode 100644 index 0000000000..bb0b75f508 --- /dev/null +++ b/qt/tests_backend/widgets/imageview.py @@ -0,0 +1,19 @@ +from PySide6.QtWidgets import QLabel + +from .base import SimpleProbe + + +class ImageViewProbe(SimpleProbe): + native_class = QLabel + + def __init__(self, widget): + super().__init__(widget) + assert self.native.autoFillBackground() + + @property + def preserve_aspect_ratio(self): + return self.impl._aspect_ratio is not None + + def assert_image_size(self, width, height): + pixmap = self.native.pixmap() + assert (pixmap.width(), pixmap.height()) == (width, height) diff --git a/qt/tests_backend/widgets/label.py b/qt/tests_backend/widgets/label.py index d59544ae38..0682f54646 100644 --- a/qt/tests_backend/widgets/label.py +++ b/qt/tests_backend/widgets/label.py @@ -7,6 +7,10 @@ class LabelProbe(SimpleProbe): native_class = QLabel + def __init__(self, widget): + super().__init__(widget) + assert self.native.autoFillBackground() + @property def text(self): return self.native.text()