From a40771f48f682286fa27999f3ee1fffdb9a27d8f Mon Sep 17 00:00:00 2001 From: Maic Siemering Date: Sun, 29 Sep 2024 21:26:05 +0200 Subject: [PATCH] feat(gui):support angle in UIImage --- arcade/gui/widgets/image.py | 56 +++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/arcade/gui/widgets/image.py b/arcade/gui/widgets/image.py index b234d9d57..44f7a0219 100644 --- a/arcade/gui/widgets/image.py +++ b/arcade/gui/widgets/image.py @@ -1,5 +1,6 @@ from __future__ import annotations +import math from typing import Union from typing_extensions import override @@ -28,6 +29,9 @@ class UIImage(UIWidget): alpha = Property(255) """Alpha value of the texture, value between 0 and 255. 0 is fully transparent, 255 is fully visible.""" + angle = Property(0) + """Angle of the texture in degrees. + The image will be rotated around its center and fitted into the widget size.""" def __init__( self, @@ -46,17 +50,51 @@ def __init__( ) bind(self, "texture", self.trigger_render) bind(self, "alpha", self.trigger_full_render) + bind(self, "angle", self.trigger_full_render) @override def do_render(self, surface: Surface): """Render the stored texture in the size of the widget.""" - self.prepare_render(surface) if self.texture: - surface.draw_texture( - x=0, - y=0, - width=self.content_width, - height=self.content_height, - tex=self.texture, - alpha=self.alpha, - ) + self.prepare_render(surface) + + if self.angle == 0: + surface.draw_texture( + x=0, + y=0, + width=self.content_width, + height=self.content_height, + tex=self.texture, + alpha=self.alpha, + ) + else: + w = self.content_width + h = self.content_height + angle_radians = math.radians(self.angle) + cos_value = abs(math.cos(angle_radians)) + sin_value = abs(math.sin(angle_radians)) + + # https://stackoverflow.com/a/33867165/2947505 + # Calculate the minimum size of the rotated image + # W = w·|cos φ| + h·|sin φ| + w_rotated = w * cos_value + h * sin_value + # H = w·|sin φ| + h·|cos φ| + h_rotated = w * sin_value + h * cos_value + # a = min(wo / W, ho / H) + factor = min(w / w_rotated, h / h_rotated) + # W′ = a·w + w_fitted = factor * w + # H′ = a·h + h_fitted = factor * h + + draw_rect = self.content_rect.align_left(0).align_bottom(0) + draw_rect = draw_rect.resize(w_fitted, h_fitted) + surface.draw_texture( + x=draw_rect.left, + y=draw_rect.bottom, + width=draw_rect.width, + height=draw_rect.height, + tex=self.texture, + alpha=self.alpha, + angle=self.angle, + )