summaryrefslogtreecommitdiff
path: root/addons/gdUnit4/src/ui/GdUnitUiTools.gd
diff options
context:
space:
mode:
authorradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
committerradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
commita89e744ed0e8c759caf041a580112365bbfe4303 (patch)
treedd61e320904176995727e86a857d00c90d4933ba /addons/gdUnit4/src/ui/GdUnitUiTools.gd
parent6d53d8cac78250dc888aa49d5f9d4175c6652feb (diff)
escoria updateHEADmain
Diffstat (limited to 'addons/gdUnit4/src/ui/GdUnitUiTools.gd')
-rw-r--r--addons/gdUnit4/src/ui/GdUnitUiTools.gd151
1 files changed, 151 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/ui/GdUnitUiTools.gd b/addons/gdUnit4/src/ui/GdUnitUiTools.gd
new file mode 100644
index 0000000..0bcdb1d
--- /dev/null
+++ b/addons/gdUnit4/src/ui/GdUnitUiTools.gd
@@ -0,0 +1,151 @@
+class_name GdUnitUiTools
+extends RefCounted
+
+
+static var _spinner: AnimatedTexture
+
+
+enum ImageFlipMode {
+ HORIZONTAl,
+ VERITCAL
+}
+
+
+## Returns the icon by name, if it exists.
+static func get_icon(icon_name: String, color: = Color.BLACK) -> Texture2D:
+ if not Engine.is_editor_hint():
+ return null
+ var icon := EditorInterface.get_base_control().get_theme_icon(icon_name, "EditorIcons")
+ if icon == null:
+ return null
+ if color != Color.BLACK:
+ icon = _modulate_texture(icon, color)
+ return icon
+
+
+## Returns the icon flipped
+static func get_flipped_icon(icon_name: String, mode: = ImageFlipMode.HORIZONTAl) -> Texture2D:
+ if not Engine.is_editor_hint():
+ return null
+ var icon := EditorInterface.get_base_control().get_theme_icon(icon_name, "EditorIcons")
+ if icon == null:
+ return null
+ return ImageTexture.create_from_image(_flip_image(icon, mode))
+
+
+static func get_spinner() -> AnimatedTexture:
+ if _spinner != null:
+ return _spinner
+ _spinner = AnimatedTexture.new()
+ _spinner.frames = 8
+ _spinner.speed_scale = 2.5
+ for frame in _spinner.frames:
+ _spinner.set_frame_texture(frame, get_icon("Progress%d" % (frame+1)))
+ _spinner.set_frame_duration(frame, 0.2)
+ return _spinner
+
+
+static func get_color_animated_icon(icon_name :String, from :Color, to :Color) -> AnimatedTexture:
+ if not Engine.is_editor_hint():
+ return null
+ var texture := AnimatedTexture.new()
+ texture.frames = 8
+ texture.speed_scale = 2.5
+ var color := from
+ for frame in texture.frames:
+ color = lerp(color, to, .2)
+ texture.set_frame_texture(frame, get_icon(icon_name, color))
+ texture.set_frame_duration(frame, 0.2)
+ return texture
+
+
+static func get_run_overall_icon() -> Texture2D:
+ if not Engine.is_editor_hint():
+ return null
+ var icon := EditorInterface.get_base_control().get_theme_icon("Play", "EditorIcons")
+ var image := _merge_images(icon.get_image(), Vector2i(-2, 0), icon.get_image(), Vector2i(3, 0))
+ return ImageTexture.create_from_image(image)
+
+
+static func get_GDScript_icon(status: String, color: Color) -> Texture2D:
+ if not Engine.is_editor_hint():
+ return null
+ var icon_a := EditorInterface.get_base_control().get_theme_icon("GDScript", "EditorIcons")
+ var icon_b := EditorInterface.get_base_control().get_theme_icon(status, "EditorIcons")
+ var overlay_image := _modulate_image(icon_b.get_image(), color)
+ var image := _merge_images_scaled(icon_a.get_image(), Vector2i(0, 0), overlay_image, Vector2i(5, 5))
+ return ImageTexture.create_from_image(image)
+
+
+static func get_CSharpScript_icon(status: String, color: Color) -> Texture2D:
+ if not Engine.is_editor_hint():
+ return null
+ var icon_a := EditorInterface.get_base_control().get_theme_icon("CSharpScript", "EditorIcons")
+ var icon_b := EditorInterface.get_base_control().get_theme_icon(status, "EditorIcons")
+ var overlay_image := _modulate_image(icon_b.get_image(), color)
+ var image := _merge_images_scaled(icon_a.get_image(), Vector2i(0, 0), overlay_image, Vector2i(5, 5))
+ return ImageTexture.create_from_image(image)
+
+
+static func _modulate_texture(texture: Texture2D, color: Color) -> Texture2D:
+ var image := _modulate_image(texture.get_image(), color)
+ return ImageTexture.create_from_image(image)
+
+
+static func _modulate_image(image: Image, color: Color) -> Image:
+ var data: PackedByteArray = image.data["data"]
+ for pixel in range(0, data.size(), 4):
+ var pixel_a := _to_color(data, pixel)
+ if pixel_a.a8 != 0:
+ pixel_a = pixel_a.lerp(color, .9)
+ data[pixel + 0] = pixel_a.r8
+ data[pixel + 1] = pixel_a.g8
+ data[pixel + 2] = pixel_a.b8
+ data[pixel + 3] = pixel_a.a8
+ var output_image := Image.new()
+ output_image.set_data(image.get_width(), image.get_height(), image.has_mipmaps(), image.get_format(), data)
+ return output_image
+
+
+static func _merge_images(image1: Image, offset1: Vector2i, image2: Image, offset2: Vector2i) -> Image:
+ ## we need to fix the image to have the same size to avoid merge conflicts
+ if image1.get_height() < image2.get_height():
+ image1.resize(image2.get_width(), image2.get_height())
+ # Create a new Image for the merged result
+ var merged_image := Image.create(image1.get_width(), image1.get_height(), false, Image.FORMAT_RGBA8)
+ merged_image.blit_rect_mask(image1, image2, Rect2(Vector2.ZERO, image1.get_size()), offset1)
+ merged_image.blit_rect_mask(image1, image2, Rect2(Vector2.ZERO, image2.get_size()), offset2)
+ return merged_image
+
+
+@warning_ignore("narrowing_conversion")
+static func _merge_images_scaled(image1: Image, offset1: Vector2i, image2: Image, offset2: Vector2i) -> Image:
+ ## we need to fix the image to have the same size to avoid merge conflicts
+ if image1.get_height() < image2.get_height():
+ image1.resize(image2.get_width(), image2.get_height())
+ # Create a new Image for the merged result
+ var merged_image := Image.create(image1.get_width(), image1.get_height(), false, image1.get_format())
+ merged_image.blend_rect(image1, Rect2(Vector2.ZERO, image1.get_size()), offset1)
+ @warning_ignore("narrowing_conversion")
+ image2.resize(image2.get_width()/1.3, image2.get_height()/1.3)
+ merged_image.blend_rect(image2, Rect2(Vector2.ZERO, image2.get_size()), offset2)
+ return merged_image
+
+
+static func _flip_image(texture: Texture2D, mode: ImageFlipMode) -> Image:
+ var flipped_image := Image.new()
+ flipped_image.copy_from(texture.get_image())
+ if mode == ImageFlipMode.VERITCAL:
+ flipped_image.flip_x()
+ else:
+ flipped_image.flip_y()
+ return flipped_image
+
+
+static func _to_color(data: PackedByteArray, position: int) -> Color:
+ var pixel_a := Color()
+ pixel_a.r8 = data[position + 0]
+ pixel_a.g8 = data[position + 1]
+ pixel_a.b8 = data[position + 2]
+ pixel_a.a8 = data[position + 3]
+ return pixel_a