Replace the broken test suite with working GdUnit4 tests

The previous tests never compiled: they used GUT's assert functions,
Godot 3 APIs and reassigned autoload functions, so no test ran.

- 90 tests: unit tests for the playlist, songs, player scoring, time
  formatting, search and the server client, plus integration tests
  that run MainWindow and SyncWindow against a fake server
- Keybind tests check that Alt+<number> and Ctrl+Alt+<number> keep
  following the player rows while players are added and removed
- run_tests.sh finds Godot and runs the suite headless (~10 seconds)
- CI runs the tests before the build job in gitea-build.yaml; the
  separate test.yml used a GitHub action that does not exist
- GdUnit4 is committed instead of ignored, since the project enables
  it, and .gitea/ is no longer ignored
- Exported builds leave out tests/ and addons/gdUnit4/
This commit is contained in:
Sansan committed 2026-10-05 19:33:41 +02:00
1 parent 87ff3d899b
commit 91adf52cf4
559 files changed
+32474 -2100

No files matched your search

+89
View File
@@ -0,0 +1,89 @@
@tool
extends Control
const GdUnitUpdateClient = preload("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd")
const TITLE = "gdUnit4 ${version} Console"
@onready var header := $VBoxContainer/Header
@onready var title: RichTextLabel = $VBoxContainer/Header/header_title
@onready var output: RichTextLabel = $VBoxContainer/Console/TextEdit
var _test_reporter: GdUnitConsoleTestReporter
func _ready() -> void:
GdUnitFonts.init_fonts(output)
output.add_theme_constant_override("line_separation", 3)
GdUnit4Version.init_version_label(title)
GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event)
GdUnitSignals.instance().gdunit_message.connect(_on_gdunit_message)
GdUnitSignals.instance().gdunit_client_connected.connect(_on_gdunit_client_connected)
GdUnitSignals.instance().gdunit_client_disconnected.connect(_on_gdunit_client_disconnected)
_test_reporter = GdUnitConsoleTestReporter.new(GdUnitRichTextMessageWriter.new(output))
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
var instance := GdUnitSignals.instance()
if instance.gdunit_event.is_connected(_on_gdunit_event):
instance.gdunit_event.disconnect(_on_gdunit_event)
if instance.gdunit_message.is_connected(_on_gdunit_event):
instance.gdunit_message.disconnect(_on_gdunit_message)
if instance.gdunit_client_connected.is_connected(_on_gdunit_event):
instance.gdunit_client_connected.disconnect(_on_gdunit_client_connected)
if instance.gdunit_client_disconnected.is_connected(_on_gdunit_event):
instance.gdunit_client_disconnected.disconnect(_on_gdunit_client_disconnected)
func setup_update_notification(control: Button) -> void:
if not GdUnitSettings.is_update_notification_enabled():
_test_reporter.println_message("The search for updates is deactivated.", Color.CORNFLOWER_BLUE)
return
_test_reporter.print_message("Searching for updates... ", Color.CORNFLOWER_BLUE)
var update_client := GdUnitUpdateClient.new()
add_child(update_client)
var response :GdUnitUpdateClient.HttpResponse = await update_client.request_latest_version()
if response.status() != 200:
_test_reporter.println_message("Information cannot be retrieved from GitHub!", GdUnitEditorColorTheme.state_failure)
_test_reporter.println_message("Error: %s" % response.response(), GdUnitEditorColorTheme.state_failure)
return
var latest_version := update_client.extract_latest_version(response)
if not latest_version.is_greater(GdUnit4Version.current()):
_test_reporter.println_message("GdUnit4 is up-to-date.", GdUnitEditorColorTheme.state_success)
return
_test_reporter.println_message("A new update is available %s" % latest_version, GdUnitEditorColorTheme.state_warning)
_test_reporter.println_message("Open the GdUnit4 settings and check the update tab.", GdUnitEditorColorTheme.state_warning)
control.icon = GdUnitUiTools.get_icon("Notification", GdUnitEditorColorTheme.state_warning)
var tween := create_tween()
tween.tween_property(control, "self_modulate", Color.VIOLET, .2).set_trans(Tween.TransitionType.TRANS_LINEAR)
tween.tween_property(control, "self_modulate", GdUnitEditorColorTheme.state_warning, .2).set_trans(Tween.TransitionType.TRANS_BOUNCE)
tween.parallel()
tween.tween_property(control, "scale", Vector2.ONE*1.05, .4).set_trans(Tween.TransitionType.TRANS_LINEAR)
tween.tween_property(control, "scale", Vector2.ONE, .4).set_trans(Tween.TransitionType.TRANS_BOUNCE)
tween.set_loops(-1)
tween.play()
func _on_gdunit_event(event: GdUnitEvent) -> void:
match event.type():
GdUnitEvent.SESSION_START:
_test_reporter.test_session = GdUnitTestSession.new(GdUnitTestDiscoverGuard.instance().get_discovered_tests(), "")
GdUnitEvent.SESSION_CLOSE:
_test_reporter.test_session = null
func _on_gdunit_client_connected(client_id: int) -> void:
_test_reporter.clear()
_test_reporter.println_message("GdUnit Test Client connected with id: %d" % client_id, GdUnitEditorColorTheme.folder_color)
func _on_gdunit_client_disconnected(client_id: int) -> void:
_test_reporter.println_message("GdUnit Test Client disconnected with id: %d" % client_id, GdUnitEditorColorTheme.folder_color)
func _on_gdunit_message(message: String) -> void:
_test_reporter.println_message(message, GdUnitEditorColorTheme.folder_color)
@@ -0,0 +1 @@
uid://bn251drwdfko7
+70
View File
@@ -0,0 +1,70 @@
[gd_scene format=4 uid="uid://dm0wvfyeew7vd"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/GdUnitConsole.gd" id="1"]
[node name="Control" type="Control" unique_id=1838139573]
use_parent_material = true
clip_contents = true
custom_minimum_size = Vector2(0, 200)
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1")
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1582573516]
use_parent_material = true
clip_contents = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Header" type="Control" parent="VBoxContainer" unique_id=1823073031]
auto_translate_mode = 2
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_vertical = 0
localize_numeral_system = false
[node name="header_title" type="RichTextLabel" parent="VBoxContainer/Header" unique_id=20617532]
auto_translate_mode = 2
custom_minimum_size = Vector2(0, 36)
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
localize_numeral_system = false
bbcode_enabled = true
scroll_active = false
autowrap_mode = 0
shortcut_keys_enabled = false
horizontal_alignment = 1
vertical_alignment = 1
[node name="Console" type="ScrollContainer" parent="VBoxContainer" unique_id=547060555]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="TextEdit" type="RichTextLabel" parent="VBoxContainer/Console" unique_id=1121183605]
use_parent_material = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
focus_mode = 2
bbcode_enabled = true
scroll_following = true
context_menu_enabled = true
selection_enabled = true
+36
View File
@@ -0,0 +1,36 @@
@tool
class_name GdUnitFonts
extends RefCounted
static func init_fonts(item: CanvasItem) -> float:
# set default size
item.set("theme_override_font_sizes/font_size", 16)
if Engine.is_editor_hint():
var base_control := EditorInterface.get_base_control()
# source modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
# https://github.com/godotengine/godot/blob/9ee1873ae1e09c217ac24a5800007f63cb895615/editor/editor_log.cpp#L65
var output_source_mono := base_control.get_theme_font("output_source_mono", "EditorFonts")
var output_source_bold_italic := base_control.get_theme_font("output_source_bold_italic", "EditorFonts")
var output_source_italic := base_control.get_theme_font("output_source_italic", "EditorFonts")
var output_source_bold := base_control.get_theme_font("output_source_bold", "EditorFonts")
#var output_source := base_control.get_theme_font("output_source", "EditorFonts")
var settings := EditorInterface.get_editor_settings()
var scale_factor := EditorInterface.get_editor_scale()
var font_size: float = settings.get_setting("interface/editor/main_font_size")
font_size *= scale_factor
#item.set("theme_override_fonts/normal_font", output_source)
item.set("theme_override_fonts/bold_font", output_source_bold)
item.set("theme_override_fonts/italics_font", output_source_italic)
item.set("theme_override_fonts/bold_italics_font", output_source_bold_italic)
item.set("theme_override_fonts/mono_font", output_source_mono)
item.set("theme_override_font_sizes/font_size", font_size)
item.set("theme_override_font_sizes/normal_font_size", font_size)
item.set("theme_override_font_sizes/bold_font_size", font_size)
item.set("theme_override_font_sizes/italics_font_size", font_size)
item.set("theme_override_font_sizes/bold_italics_font_size", font_size)
item.set("theme_override_font_sizes/mono_font_size", font_size)
return font_size
return 16.0
+1
View File
@@ -0,0 +1 @@
uid://c6j408ijvlfgg
+33
View File
@@ -0,0 +1,33 @@
@tool
class_name GdUnitInspecor
extends Control
var _command_handler := GdUnitCommandHandler.instance()
var _wait_time := 0.0
func _ready() -> void:
@warning_ignore("return_value_discarded")
GdUnitSignals.instance().gdunit_event.connect(func(event: GdUnitEvent) -> void:
if event.type() != GdUnitEvent.SESSION_START:
return
var control: Control = get_parent_control()
# if the tab is floating we dont need to set as current
if control is TabContainer:
var tab_container :TabContainer = control
for tab_index in tab_container.get_tab_count():
if tab_container.get_tab_title(tab_index) == "GdUnit":
tab_container.set_current_tab(tab_index)
)
# Register for editor theme updates
add_child(GdUnitEditorColorTheme.new(), true, Node.INTERNAL_MODE_BACK)
func _process(delta: float) -> void:
_wait_time += delta
if _wait_time > 2.0:
_wait_time = 0
_command_handler._do_process()
@@ -0,0 +1 @@
uid://d3o6hpe80hpbx
@@ -0,0 +1,68 @@
[gd_scene format=3 uid="uid://mpo5o6d4uybu"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorToolBar.tscn" id="1"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/GdUnitInspector.gd" id="1_j37cs"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorProgressBar.tscn" id="2"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorStatusBar.tscn" id="3"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorTreeMainPanel.tscn" id="7"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/network/GdUnitServer.tscn" id="7_721no"]
[node name="GdUnit" type="Control" unique_id=272268338]
clip_contents = true
custom_minimum_size = Vector2(360, 440)
layout_mode = 3
anchors_preset = 9
anchor_bottom = 1.0
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
focus_mode = 2
script = ExtResource("1_j37cs")
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1550259230]
clip_contents = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_vertical = 11
theme_override_constants/separation = 0
[node name="Header" type="VBoxContainer" parent="VBoxContainer" unique_id=876343251]
use_parent_material = true
clip_contents = true
layout_mode = 2
[node name="ToolBar" parent="VBoxContainer/Header" unique_id=185399834 instance=ExtResource("1")]
layout_mode = 2
size_flags_vertical = 3
[node name="ProgressBar" parent="VBoxContainer/Header" unique_id=360281822 instance=ExtResource("2")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 5
[node name="StatusBar" parent="VBoxContainer/Header" unique_id=625414847 instance=ExtResource("3")]
layout_mode = 2
size_flags_horizontal = 1
[node name="MainPanel" parent="VBoxContainer" unique_id=1133307707 instance=ExtResource("7")]
unique_name_in_owner = true
clip_contents = true
layout_mode = 2
[node name="event_server" parent="." unique_id=756999253 instance=ExtResource("7_721no")]
[connection signal="select_error_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [7]]
[connection signal="select_error_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [7]]
[connection signal="select_failure_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [6]]
[connection signal="select_failure_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [6]]
[connection signal="select_flaky_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [5]]
[connection signal="select_flaky_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [5]]
[connection signal="select_orphan_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [9]]
[connection signal="select_orphan_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [9]]
[connection signal="select_skipped_next" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_next_item_by_state" binds= [2]]
[connection signal="select_skipped_prevous" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_select_previous_item_by_state" binds= [2]]
[connection signal="tree_view_mode_changed" from="VBoxContainer/Header/StatusBar" to="VBoxContainer/MainPanel" method="_on_status_bar_tree_view_mode_changed"]
@@ -0,0 +1,32 @@
class_name GdUnitInspectorTreeConstants
extends RefCounted
# the inspector panel presantation
enum TREE_VIEW_MODE {
TREE,
FLAT
}
# The inspector sort modes
enum SORT_MODE {
UNSORTED,
NAME_ASCENDING,
NAME_DESCENDING,
EXECUTION_TIME
}
enum STATE {
INITIAL,
RUNNING,
SKIPPED,
SUCCESS,
WARNING,
FLAKY,
FAILED,
ERROR,
ABORDED,
ORPHAN
}
@@ -0,0 +1 @@
uid://c3gaj34a5hqu5
@@ -0,0 +1,108 @@
# A tool to provide extended script editor functionallity
class_name GdUnitScriptEditorControls
extends RefCounted
static var _command_ids_initalizied := false
static var FILE_CLOSE := -1
static var FILE_CLOSE_ALL := -1
static var FILE_SAVE := -1
static var FILE_SAVE_ALL := -1
## We scan the file popup menu to find the file command ids to trigger it on save, close, etc.
static func init_file_command_ids() -> void:
if _command_ids_initalizied:
return
var popup := get_file_menu_popup()
for itemIndex in popup.item_count:
var command := popup.get_item_text(itemIndex)
var command_id := popup.get_item_id(itemIndex)
match command:
"Close":
FILE_CLOSE = command_id
"Close All":
FILE_CLOSE_ALL = command_id
"Save":
FILE_SAVE = command_id
"Save All":
FILE_SAVE_ALL = command_id
if FILE_CLOSE == -1:
push_error("Can't determine ScriptEditor 'Close' command.")
if FILE_CLOSE_ALL == -1:
push_error("Can't determine ScriptEditor 'Close All' command.")
if FILE_SAVE == -1:
push_error("Can't determine ScriptEditor 'Save' command.")
if FILE_SAVE_ALL == -1:
push_error("Can't determine ScriptEditor 'Save All' command.")
_command_ids_initalizied = true
# Saves the given script and closes if requested by <close=true>
# The script is saved when is opened in the editor.
# The script is closed when <close> is set to true.
static func save_and_close_script(script_path: String, close := false) -> bool:
if !Engine.is_editor_hint():
return false
init_file_command_ids()
var editor := EditorInterface.get_script_editor()
# search for the script in all opened editor scrips
for open_script in editor.get_open_scripts():
if open_script.resource_path == script_path:
# select the script in the editor
EditorInterface.edit_script(open_script, 0);
run_file_command(FILE_SAVE)
if close:
run_file_command(FILE_CLOSE)
return true
return false
# Saves all opened script
static func save_all_open_script() -> void:
init_file_command_ids()
run_file_command(FILE_SAVE_ALL)
static func close_open_editor_scripts() -> void:
init_file_command_ids()
run_file_command(FILE_CLOSE_ALL)
# Edits the given script.
# The script is openend in the current editor and selected in the file system dock.
# The line and column on which to open the script can also be specified.
# The script will be open with the user-configured editor for the script's language which may be an external editor.
static func edit_script(script_path: String, line_number := -1) -> void:
if Engine.is_editor_hint():
# scan() is required — update_file() alone does not refresh the dock for newly created files
var file_system := EditorInterface.get_resource_filesystem()
file_system.update_file(script_path)
file_system.scan()
var file_system_dock := EditorInterface.get_file_system_dock()
file_system_dock.navigate_to_path(script_path)
EditorInterface.select_file(script_path)
var script: GDScript = load(script_path)
EditorInterface.edit_script(script, line_number)
static func get_file_menu_popup() -> PopupMenu:
@warning_ignore("unsafe_method_access")
return EditorInterface.get_script_editor().get_child(0).get_child(0).get_child(0).get_popup()
static func run_file_command(command_id: int) -> void:
if Engine.is_editor_hint():
get_file_menu_popup().id_pressed.emit(command_id)
static func _print_menu(popup: PopupMenu) -> void:
for itemIndex in popup.item_count:
prints("get_item_id", popup.get_item_id(itemIndex))
prints("get_item_accelerator", popup.get_item_accelerator(itemIndex))
prints("get_item_shortcut", popup.get_item_shortcut(itemIndex))
prints("get_item_text", popup.get_item_text(itemIndex))
prints()
@@ -0,0 +1 @@
uid://b065hlwt6wa6w
+171
View File
@@ -0,0 +1,171 @@
@tool
class_name GdUnitUiTools
extends RefCounted
const STATE = GdUnitInspectorTreeConstants.STATE
enum ImageFlipMode {
HORIZONTAl,
VERITCAL
}
static var _spinner: AnimatedTexture
static var icon_cache: Dictionary[STATE, Texture2D]
static func get_state_icon(state: STATE) -> Texture2D:
if icon_cache.has(state):
return icon_cache.get(state)
if not Engine.is_editor_hint():
return null
var icon: Texture2D
match state:
STATE.INITIAL:
icon = get_icon("EditorHandleDisabled", GdUnitEditorColorTheme.state_initial)
STATE.RUNNING:
icon = get_spinner()
STATE.SUCCESS:
icon = get_icon("ImportCheck", GdUnitEditorColorTheme.state_success)
STATE.WARNING:
icon = get_icon("ImportCheck", GdUnitEditorColorTheme.state_warning)
STATE.FAILED:
icon = get_icon("ImportFail", GdUnitEditorColorTheme.state_failure)
STATE.ERROR:
icon = get_icon("StatusError", GdUnitEditorColorTheme.state_error)
STATE.FLAKY:
icon = get_icon("CheckBox", GdUnitEditorColorTheme.state_flaky)
STATE.SKIPPED:
icon = get_icon("EditorHandleDisabled", GdUnitEditorColorTheme.state_skipped)
STATE.ORPHAN:
icon = get_icon("Unlinked", GdUnitEditorColorTheme.state_orphan)
if icon == null:
push_error("missing icon for state:", STATE.keys()[state])
icon_cache[state] = icon
return icon
## 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, 0.2)
texture.set_frame_texture(frame, get_icon(icon_name, color))
texture.set_frame_duration(frame, .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 _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] = 1
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(image1, Rect2(Vector2.ZERO, image1.get_size()), offset1)
merged_image.blit_rect_mask(image2, 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.blit_rect_mask(image2, 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
@@ -0,0 +1 @@
uid://b7lv64pwq2wab
@@ -0,0 +1,45 @@
class_name GdUnitContextMenuItem
var command_id: String:
set(value):
command_id = value
get:
return command_id
var name: StringName:
set(value):
name = value
get:
return name
var visible: Callable:
set(value):
visible = value
get:
return visible
var icon: Texture2D:
get:
return GdUnitCommandHandler.instance().command_icon(command_id)
func _init(p_command_id: String, p_name: StringName, p_is_visible: Callable) -> void:
assert(p_command_id != null and not p_command_id.is_empty(), "(%s) missing command id " % p_command_id)
assert(p_is_visible != null, "(%s) missing parameter 'GdUnitCommand'" % p_name)
self.command_id = p_command_id
self.name = p_name
self.visible = p_is_visible
func shortcut() -> Shortcut:
return GdUnitCommandHandler.instance().command_shortcut(command_id)
func is_visible(...args: Array) -> bool:
return visible.callv(args)
func execute(...args: Array) -> void:
GdUnitCommandHandler.instance().command_execute(command_id, args)
@@ -0,0 +1 @@
uid://buds1hj2v8ho8
@@ -0,0 +1,45 @@
@tool
extends EditorContextMenuPlugin
var _context_menus: Array[GdUnitContextMenuItem] = []
func _init() -> void:
var is_test_suite := func is_visible(script: Script, is_ts: bool) -> bool:
if script == null:
return false
return GdUnitTestSuiteScanner.is_test_suite(script) == is_ts
# setup shortcuts
_context_menus.append(GdUnitContextMenuItem.new(
GdUnitCommandFileSystemRunTests.ID,
"Run Testsuites",
is_test_suite.bind(true)
))
_context_menus.append(GdUnitContextMenuItem.new(
GdUnitCommandFileSystemDebugTests.ID,
"Debug Testsuites",
is_test_suite.bind(true)
))
func _popup_menu(paths: PackedStringArray) -> void:
# Filter for directories and test suite files
var valid_paths := Array(paths)\
.filter(func(path: String) -> bool:
if DirAccess.dir_exists_absolute(path):
return true
if path.get_extension() in ["gd", "cs"]:
var script := GdUnitTestSuiteScanner.load_with_disabled_warnings(path)
return GdUnitTestSuiteScanner.is_test_suite(script)
return false)
# If no valid paths selected don't extend the context menu
if valid_paths.is_empty():
return
for menu_item in _context_menus:
if menu_item.shortcut():
add_menu_shortcut(menu_item.shortcut(), menu_item.execute.bindv(valid_paths).unbind(1))
add_context_menu_item_from_shortcut(menu_item.name, menu_item.shortcut(), menu_item.icon)
else:
add_context_menu_item(menu_item.name, menu_item.execute.bindv(valid_paths).unbind(1), menu_item.icon)
@@ -0,0 +1 @@
uid://bssaao2gxa6vq
@@ -0,0 +1,63 @@
@tool
class_name GdUnitInspectorContextMenu
extends PopupMenu
const CONTEXT_MENU_RUN_ID = 0
const CONTEXT_MENU_DEBUG_ID = 1
const CONTEXT_MENU_RERUN_UNTIL_ID = 2
# id 3 is the seperator
const CONTEXT_MENU_COLLAPSE_ALL = 4
const CONTEXT_MENU_EXPAND_ALL = 5
var command_handler: GdUnitCommandHandler
func _ready() -> void:
if not Engine.is_editor_hint():
return
command_handler = GdUnitCommandHandler.instance()
_setup_item(CONTEXT_MENU_RUN_ID, "Run Tests", GdUnitCommandInspectorRunTests.ID)
_setup_item(CONTEXT_MENU_DEBUG_ID, "Debug Tests", GdUnitCommandInspectorDebugTests.ID)
_setup_item(CONTEXT_MENU_RERUN_UNTIL_ID, "Run Tests Until Fail", GdUnitCommandInspectorRerunTestsUntilFailure.ID)
_setup_item(CONTEXT_MENU_EXPAND_ALL, "Expand All", GdUnitCommandInspectorTreeExpand.ID)
_setup_item(CONTEXT_MENU_COLLAPSE_ALL, "Collapse All", GdUnitCommandInspectorTreeCollapse.ID)
func _setup_item(item_id: int, item_name: String, command_id: String) -> void:
set_item_text(item_id, item_name)
set_item_icon(item_id, command_handler.command_icon(command_id))
set_item_shortcut(item_id, command_handler.command_shortcut(command_id))
func disable_items() -> void:
set_item_disabled(CONTEXT_MENU_RUN_ID, true)
set_item_disabled(CONTEXT_MENU_DEBUG_ID, true)
set_item_disabled(CONTEXT_MENU_RERUN_UNTIL_ID, true)
func enable_items() -> void:
set_item_disabled(CONTEXT_MENU_RUN_ID, false)
set_item_disabled(CONTEXT_MENU_DEBUG_ID, false)
set_item_disabled(CONTEXT_MENU_RERUN_UNTIL_ID, false)
func _on_tree_item_mouse_selected(mouse_position: Vector2, mouse_button_index: int, source: Tree) -> void:
if mouse_button_index == MOUSE_BUTTON_RIGHT:
position = source.get_screen_position() + mouse_position
popup()
func _on_index_pressed(index: int) -> void:
match index:
CONTEXT_MENU_RUN_ID:
command_handler.command_execute(GdUnitCommandInspectorRunTests.ID)
CONTEXT_MENU_DEBUG_ID:
command_handler.command_execute(GdUnitCommandInspectorDebugTests.ID)
CONTEXT_MENU_RERUN_UNTIL_ID:
command_handler.command_execute(GdUnitCommandInspectorRerunTestsUntilFailure.ID)
CONTEXT_MENU_EXPAND_ALL:
command_handler.command_execute(GdUnitCommandInspectorTreeExpand.ID)
CONTEXT_MENU_COLLAPSE_ALL:
command_handler.command_execute(GdUnitCommandInspectorTreeCollapse.ID)
@@ -0,0 +1 @@
uid://b8vsj8d7fh4kw
@@ -0,0 +1,70 @@
[gd_scene format=3 uid="uid://bjcc71p2h1trr"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/menu/GdUnitInspectorContextMenu.gd" id="1_0x0vc"]
[sub_resource type="DPITexture" id="DPITexture_miuuy"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"M4 12a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 4 4z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[sub_resource type="DPITexture" id="DPITexture_ern2r"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"M3 3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1zm4.975 0A1 1 0 0 0 7 3.998v8a1 1 0 0 0 1.625.781l5-4a1 1 0 0 0 0-1.56l-5-4A1 1 0 0 0 7.975 3z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[sub_resource type="DPITexture" id="DPITexture_qdci2"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"m8 9.669-3.536 2.583H7v2.537h2v-2.537h2.536zm0-3.314L4.464 3.772H7V1.235h2v2.537h2.536zm-7.296.73h14.591v1.831H.704z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[sub_resource type="DPITexture" id="DPITexture_hed0i"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"m8 16-3.5-2.5H7V11h2v2.5h2.5zM8 0 4.5 2.5H7V5h2V2.5h2.5zM1 7h14v2H1z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[node name="contextMenu" type="PopupMenu" unique_id=1824556050]
auto_translate_mode = 2
oversampling_override = 1.0
size = Vector2i(241, 170)
visible = true
item_count = 6
item_0/text = "Run Tests"
item_0/icon = SubResource("DPITexture_miuuy")
item_0/id = 0
item_1/text = "Debug Tests"
item_1/icon = SubResource("DPITexture_ern2r")
item_1/id = 1
item_2/text = "Run Tests Until Fail"
item_2/icon = SubResource("DPITexture_miuuy")
item_2/id = 2
item_3/id = 3
item_3/separator = true
item_4/text = "Collapse All"
item_4/icon = SubResource("DPITexture_qdci2")
item_4/id = 4
item_5/text = "Expand All"
item_5/icon = SubResource("DPITexture_hed0i")
item_5/id = 5
script = ExtResource("1_0x0vc")
[connection signal="index_pressed" from="." to="." method="_on_index_pressed"]
@@ -0,0 +1,38 @@
@tool
extends EditorContextMenuPlugin
var _context_menus: Array[GdUnitContextMenuItem] = []
func _init() -> void:
var is_test_suite := func is_visible(script: Script, is_ts: bool) -> bool:
return GdUnitTestSuiteScanner.is_test_suite(script) == is_ts
# setup shortcuts
_context_menus.append(GdUnitContextMenuItem.new(
GdUnitCommandScriptEditorRunTests.ID,
"Run Tests",
is_test_suite.bind(true)
))
_context_menus.append(GdUnitContextMenuItem.new(
GdUnitCommandScriptEditorDebugTests.ID,
"Debug Tests",
is_test_suite.bind(true)
))
_context_menus.append(GdUnitContextMenuItem.new(
GdUnitCommandScriptEditorCreateTest.ID,
"Create Test",
is_test_suite.bind(false)
))
func _popup_menu(_paths: PackedStringArray) -> void:
var current_script := EditorInterface.get_script_editor().get_current_script()
for menu_item in _context_menus:
if menu_item.is_visible(current_script):
if menu_item.shortcut():
add_menu_shortcut(menu_item.shortcut(), menu_item.execute.unbind(1))
add_context_menu_item_from_shortcut(menu_item.name, menu_item.shortcut())
else:
add_context_menu_item(menu_item.name, menu_item.execute.unbind(1))
@@ -0,0 +1 @@
uid://m83gistw0jpv
@@ -0,0 +1,56 @@
@tool
extends ProgressBar
@onready var progress_counter: Label = %progess_counter
@onready var style: StyleBoxFlat = get("theme_override_styles/fill")
var _state: GdUnitInspectorTreeConstants.STATE
func _ready() -> void:
style.bg_color = Color.TRANSPARENT
value = 0
max_value = 0
update_text()
# register for progress changes
if Engine.is_editor_hint():
@warning_ignore("unsafe_property_access", "unsafe_method_access")
if get_parent().get_parent().get_parent().find_child("MainPanel", true, false).test_counters_changed.connect(_on_test_counter_changed) != OK:
push_error("ProgressBar: Can't connect to MainPanel")
func update_text() -> void:
progress_counter.text = "%d:%d" % [value, max_value]
func _on_test_counter_changed(index: int, total: int, state: GdUnitInspectorTreeConstants.STATE) -> void:
value = index
max_value = total
update_text()
# inital state
if index == 0:
_state = GdUnitInspectorTreeConstants.STATE.INITIAL
style.bg_color = Color.TRANSPARENT
# do only update the state is higher prio than current state
if state <= _state:
return
_state = state
if is_failed(state):
style.bg_color = Color.DARK_RED
else:
style.bg_color = Color.DARK_GREEN
func is_failed(state: GdUnitInspectorTreeConstants.STATE) -> bool:
return state in [
GdUnitInspectorTreeConstants.STATE.FAILED,
GdUnitInspectorTreeConstants.STATE.ERROR,
GdUnitInspectorTreeConstants.STATE.ABORDED]
func is_flaky(state: GdUnitInspectorTreeConstants.STATE) -> bool:
return state == GdUnitInspectorTreeConstants.STATE.FLAKY
@@ -0,0 +1 @@
uid://5jlhfo21m5f4
@@ -0,0 +1,49 @@
[gd_scene format=3 uid="uid://dva3tonxsxrlk"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorProgressBar.gd" id="1"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ayfir"]
bg_color = Color(1, 1, 1, 0)
[node name="MarginContainer" type="MarginContainer" unique_id=542070056]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 2
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 2
[node name="ProgressBar" type="ProgressBar" parent="." unique_id=419200362]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 9
theme_override_styles/fill = SubResource("StyleBoxFlat_ayfir")
allow_greater = true
show_percentage = false
script = ExtResource("1")
[node name="progess_counter" type="Label" parent="ProgressBar" unique_id=648033469]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -11.5
offset_top = -11.5
offset_right = 11.5
offset_bottom = 11.5
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 6
size_flags_vertical = 6
horizontal_alignment = 1
vertical_alignment = 1
autowrap_trim_flags = 0
justification_flags = 0
max_lines_visible = 1
@@ -0,0 +1,303 @@
@tool
extends Control
signal select_failure_next()
signal select_failure_prevous()
signal select_error_next()
signal select_error_prevous()
signal select_flaky_next()
signal select_flaky_prevous()
signal select_skipped_next()
signal select_skipped_prevous()
signal select_orphan_next()
signal select_orphan_prevous()
@warning_ignore("unused_signal")
signal tree_view_mode_changed(flat :bool)
@onready var _button_sync: Button = %btn_tree_sync
@onready var _button_view_mode: MenuButton = %btn_tree_mode
@onready var _button_sort_mode: MenuButton = %btn_tree_sort
@onready var _icon_template: SpinBox = %icon_template
@onready var time_value: Label = %time_value
@onready var time_icon: TextureRect = %time_icon
const STATE = GdUnitInspectorTreeConstants.STATE
var total_failed := 0
var total_errors := 0
var total_flaky := 0
var total_skipped := 0
var total_orphans := 0
var _timer: LocalTime
var icon_mappings := {
# tree sort modes
0x100 + GdUnitInspectorTreeConstants.SORT_MODE.UNSORTED : GdUnitUiTools.get_icon("TripleBar"),
0x100 + GdUnitInspectorTreeConstants.SORT_MODE.NAME_ASCENDING : GdUnitUiTools.get_icon("Sort"),
0x100 + GdUnitInspectorTreeConstants.SORT_MODE.NAME_DESCENDING : GdUnitUiTools.get_flipped_icon("Sort"),
0x100 + GdUnitInspectorTreeConstants.SORT_MODE.EXECUTION_TIME : GdUnitUiTools.get_icon("History"),
# tree view modes
0x200 + GdUnitInspectorTreeConstants.TREE_VIEW_MODE.TREE : GdUnitUiTools.get_icon("Tree", Color.GHOST_WHITE),
0x200 + GdUnitInspectorTreeConstants.TREE_VIEW_MODE.FLAT : GdUnitUiTools.get_icon("AnimationTrackGroup", Color.GHOST_WHITE)
}
@warning_ignore("return_value_discarded")
func _ready() -> void:
_button_sync.icon = GdUnitUiTools.get_icon("Loop")
_set_sort_mode_menu_options()
_set_view_mode_menu_options()
_init_status_pannels()
time_value.text = "0ms"
time_icon.texture = GdUnitUiTools.get_icon("Time")
GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event)
GdUnitSignals.instance().gdunit_settings_changed.connect(_on_settings_changed)
func _process(_delta: float) -> void:
if _timer:
time_value.text = _timer.elapsed_since()
func _init_status_pannels() -> void:
_init_statistic_panels(STATE.FAILED)
_init_statistic_panels(STATE.ERROR)
_init_statistic_panels(STATE.FLAKY)
_init_statistic_panels(STATE.SKIPPED)
_init_statistic_panels(STATE.ORPHAN)
func _notification(what: int) -> void:
if what == EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED:
_init_status_pannels()
func _init_statistic_panels(state: STATE) -> void:
var panel: Control = find_child(str(STATE.keys()[state]), true, false)
var icon: TextureRect = panel.find_child("icon")
if icon.texture == null:
icon.texture = GdUnitUiTools.get_state_icon(state)
icon.tooltip_text = panel.get_tooltip_text()
var value: LineEdit = panel.find_child("value")
value.text = "0"
value.tooltip_text = panel.get_tooltip_text()
var btn_up: TextureButton = panel.find_child("up")
var btn_down: TextureButton = panel.find_child("down")
var up_icon := _icon_template.get_theme_icon("up_hover")
var texture_normal := ImageTexture.create_from_image(
GdUnitUiTools._modulate_image(up_icon.get_image(),
Color.GRAY)
)
var texture_hover := ImageTexture.create_from_image(
GdUnitUiTools._modulate_image(up_icon.get_image(),
Color.WHITE)
)
var texture_pressed := ImageTexture.create_from_image(
GdUnitUiTools._modulate_image(up_icon.get_image(),
Color.SKY_BLUE)
)
btn_up.texture_normal = texture_normal
btn_up.texture_hover = texture_hover
btn_up.texture_pressed = texture_pressed
btn_down.texture_normal = texture_normal
btn_down.texture_hover = texture_hover
btn_down.texture_pressed = texture_pressed
if not btn_up.pressed.is_connected(_on_button_up):
btn_up.pressed.connect(_on_button_up.bind(state))
if not btn_down.pressed.is_connected(_on_button_down):
btn_down.pressed.connect(_on_button_down.bind(state))
func _on_button_up(state: STATE) -> void:
match state:
STATE.FAILED:
select_failure_prevous.emit()
STATE.ERROR:
select_error_prevous.emit()
STATE.FLAKY:
select_flaky_prevous.emit()
STATE.SKIPPED:
select_skipped_prevous.emit()
STATE.ORPHAN:
select_orphan_prevous.emit()
func _on_button_down(state: STATE) -> void:
match state:
STATE.FAILED:
select_failure_next.emit()
STATE.ERROR:
select_error_next.emit()
STATE.FLAKY:
select_flaky_next.emit()
STATE.SKIPPED:
select_skipped_next.emit()
STATE.ORPHAN:
select_orphan_next.emit()
func _update_statistics(state: STATE, count: int) -> void:
var panel: Node = find_child(str(STATE.keys()[state]), true, false)
var value: LineEdit = panel.find_child("value")
value.text = str(count)
func _set_sort_mode_menu_options() -> void:
_button_sort_mode.icon = GdUnitUiTools.get_icon("Sort")
# construct context sort menu according to the available modes
var context_menu :PopupMenu = _button_sort_mode.get_popup()
context_menu.clear()
if not context_menu.index_pressed.is_connected(_on_sort_mode_changed):
@warning_ignore("return_value_discarded")
context_menu.index_pressed.connect(_on_sort_mode_changed)
var configured_sort_mode := GdUnitSettings.get_inspector_tree_sort_mode()
for sort_mode: String in GdUnitInspectorTreeConstants.SORT_MODE.keys():
var enum_value :int = GdUnitInspectorTreeConstants.SORT_MODE.get(sort_mode)
var icon :Texture2D = icon_mappings[0x100 + enum_value]
context_menu.add_icon_check_item(icon, normalise(sort_mode), enum_value)
context_menu.set_item_checked(enum_value, configured_sort_mode == enum_value)
func _set_view_mode_menu_options() -> void:
_button_view_mode.icon = GdUnitUiTools.get_icon("Tree", Color.GHOST_WHITE)
# construct context tree view menu according to the available modes
var context_menu :PopupMenu = _button_view_mode.get_popup()
context_menu.clear()
if not context_menu.index_pressed.is_connected(_on_tree_view_mode_changed):
@warning_ignore("return_value_discarded")
context_menu.index_pressed.connect(_on_tree_view_mode_changed)
var configured_tree_view_mode := GdUnitSettings.get_inspector_tree_view_mode()
for tree_view_mode: String in GdUnitInspectorTreeConstants.TREE_VIEW_MODE.keys():
var enum_value :int = GdUnitInspectorTreeConstants.TREE_VIEW_MODE.get(tree_view_mode)
var icon :Texture2D = icon_mappings[0x200 + enum_value]
context_menu.add_icon_check_item(icon, normalise(tree_view_mode), enum_value)
context_menu.set_item_checked(enum_value, configured_tree_view_mode == enum_value)
func normalise(value: String) -> String:
var parts := value.to_lower().split("_")
parts[0] = parts[0].capitalize()
return " ".join(parts)
func status_changed(errors: int, failed: int, flaky: int, skipped: int, orphans: int) -> void:
total_failed += failed
total_errors += errors
total_flaky += flaky
total_skipped += skipped
total_orphans += orphans
_update_statistics(STATE.FAILED, total_failed)
_update_statistics(STATE.ERROR, total_errors)
_update_statistics(STATE.FLAKY, total_flaky)
_update_statistics(STATE.SKIPPED, total_skipped)
_update_statistics(STATE.ORPHAN, total_orphans)
func disable_buttons(value :bool) -> void:
_button_sync.set_disabled(value)
_button_sort_mode.set_disabled(value)
_button_view_mode.set_disabled(value)
func _on_gdunit_event(event: GdUnitEvent) -> void:
match event.type():
GdUnitEvent.DISCOVER_START:
disable_buttons(true)
GdUnitEvent.DISCOVER_END:
disable_buttons(false)
GdUnitEvent.INIT:
total_errors = 0
total_failed = 0
total_flaky = 0
total_skipped = 0
total_orphans = 0
status_changed(total_errors, total_failed, total_flaky, total_skipped, total_orphans)
GdUnitEvent.TESTCASE_AFTER:
status_changed(event.error_count(), event.failed_count(), event.is_flaky(), event.is_skipped(), event.orphan_nodes())
GdUnitEvent.TESTSUITE_AFTER:
status_changed(event.error_count(), event.failed_count(), event.is_flaky(), 0, event.orphan_nodes())
GdUnitEvent.SESSION_START:
disable_buttons(true)
_timer = LocalTime.now()
GdUnitEvent.SESSION_CLOSE, GdUnitEvent.STOP:
disable_buttons(false)
_timer = null
func _on_btn_error_up_pressed() -> void:
select_error_prevous.emit()
func _on_btn_error_down_pressed() -> void:
select_error_next.emit()
func _on_failure_up_pressed() -> void:
select_failure_prevous.emit()
func _on_failure_down_pressed() -> void:
select_failure_next.emit()
func _on_btn_flaky_up_pressed() -> void:
select_flaky_prevous.emit()
func _on_btn_flaky_down_pressed() -> void:
select_flaky_next.emit()
func _on_btn_skipped_up_pressed() -> void:
select_skipped_prevous.emit()
func _on_btn_skipped_down_pressed() -> void:
select_skipped_next.emit()
func _on_btn_orphan_up_pressed() -> void:
select_orphan_prevous.emit()
func _on_btn_orphan_down_pressed() -> void:
select_orphan_next.emit()
func _on_btn_tree_sync_pressed() -> void:
await GdUnitTestDiscoverer.run()
func _on_sort_mode_changed(index: int) -> void:
var selected_sort_mode :GdUnitInspectorTreeConstants.SORT_MODE = GdUnitInspectorTreeConstants.SORT_MODE.values()[index]
GdUnitSettings.set_inspector_tree_sort_mode(selected_sort_mode)
func _on_tree_view_mode_changed(index: int) ->void:
var selected_tree_mode :GdUnitInspectorTreeConstants.TREE_VIEW_MODE = GdUnitInspectorTreeConstants.TREE_VIEW_MODE.values()[index]
GdUnitSettings.set_inspector_tree_view_mode(selected_tree_mode)
################################################################################
# external signal receiver
################################################################################
func _on_settings_changed(property :GdUnitProperty) -> void:
if property.name() == GdUnitSettings.INSPECTOR_TREE_SORT_MODE:
_set_sort_mode_menu_options()
if property.name() == GdUnitSettings.INSPECTOR_TREE_VIEW_MODE:
_set_view_mode_menu_options()
@@ -0,0 +1 @@
uid://cbrfyg1fv3eb6
@@ -0,0 +1,362 @@
[gd_scene format=3 uid="uid://c22l4odk7qesc"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorStatusBar.gd" id="3"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mb3ih"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wo03e"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_jh28t"]
[node name="StatusBar" type="VBoxContainer" unique_id=214621769]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 132.0
grow_horizontal = 2
size_flags_horizontal = 3
size_flags_vertical = 2
script = ExtResource("3")
[node name="tree_tools" type="HBoxContainer" parent="." unique_id=1524945370]
layout_mode = 2
size_flags_vertical = 0
[node name="Label" type="Label" parent="tree_tools" unique_id=226892195]
layout_mode = 2
size_flags_horizontal = 0
text = "Statistics:"
autowrap_trim_flags = 0
justification_flags = 0
[node name="timings" type="HBoxContainer" parent="tree_tools" unique_id=1494080859]
layout_mode = 2
size_flags_horizontal = 2
size_flags_vertical = 4
alignment = 1
[node name="time_icon" type="TextureRect" parent="tree_tools/timings" unique_id=156277722]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
stretch_mode = 2
[node name="time_value" type="Label" parent="tree_tools/timings" unique_id=387690970]
unique_name_in_owner = true
custom_minimum_size = Vector2(64, 0)
layout_mode = 2
size_flags_horizontal = 3
text = "0ms"
horizontal_alignment = 2
vertical_alignment = 1
autowrap_trim_flags = 0
justification_flags = 0
[node name="tree_buttons" type="HBoxContainer" parent="tree_tools" unique_id=1600307316]
layout_mode = 2
size_flags_horizontal = 10
size_flags_vertical = 4
alignment = 2
[node name="VSeparator" type="VSeparator" parent="tree_tools/tree_buttons" unique_id=1191926359]
layout_mode = 2
[node name="btn_tree_sync" type="Button" parent="tree_tools/tree_buttons" unique_id=2138788372]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Run discover tests."
theme_override_styles/normal = SubResource("StyleBoxEmpty_mb3ih")
[node name="btn_tree_sort" type="MenuButton" parent="tree_tools/tree_buttons" unique_id=1452127838]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Sets tree sorting mode."
theme_override_styles/normal = SubResource("StyleBoxEmpty_wo03e")
flat = false
[node name="btn_tree_mode" type="MenuButton" parent="tree_tools/tree_buttons" unique_id=1744382439]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Sets tree presentation mode."
theme_override_styles/normal = SubResource("StyleBoxEmpty_jh28t")
flat = false
[node name="HSeparator" type="HSeparator" parent="." unique_id=1416084348]
layout_mode = 2
size_flags_vertical = 4
theme_override_constants/separation = 0
[node name="MarginContainer" type="MarginContainer" parent="." unique_id=89354949]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
[node name="status_bar" type="HFlowContainer" parent="MarginContainer" unique_id=1576624226]
layout_direction = 2
layout_mode = 2
size_flags_vertical = 2
[node name="icon_template" type="SpinBox" parent="MarginContainer/status_bar" unique_id=1487498266]
unique_name_in_owner = true
visible = false
layout_mode = 2
[node name="ERROR" type="HBoxContainer" parent="MarginContainer/status_bar" unique_id=310880909]
layout_mode = 2
tooltip_text = "Detected Errors"
[node name="value" type="LineEdit" parent="MarginContainer/status_bar/ERROR" unique_id=1630464164]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Detected Errors"
text = "0"
alignment = 2
max_length = 3
editable = false
context_menu_enabled = false
emoji_menu_enabled = false
shortcut_keys_enabled = false
middle_mouse_paste_enabled = false
selecting_enabled = false
deselect_on_focus_loss_enabled = false
drag_and_drop_selection_enabled = false
virtual_keyboard_enabled = false
[node name="icon" type="TextureRect" parent="MarginContainer/status_bar/ERROR/value" unique_id=729348405]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 4.0
offset_top = -8.0
offset_right = 20.0
offset_bottom = 8.0
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
stretch_mode = 2
[node name="buttons" type="VBoxContainer" parent="MarginContainer/status_bar/ERROR" unique_id=541942806]
layout_mode = 2
size_flags_horizontal = 0
[node name="up" type="TextureButton" parent="MarginContainer/status_bar/ERROR/buttons" unique_id=1146002542]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10
[node name="down" type="TextureButton" parent="MarginContainer/status_bar/ERROR/buttons" unique_id=1867410350]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 2
flip_v = true
[node name="FAILED" type="HBoxContainer" parent="MarginContainer/status_bar" unique_id=1390016421]
layout_mode = 2
tooltip_text = "Failed Tests"
[node name="value" type="LineEdit" parent="MarginContainer/status_bar/FAILED" unique_id=75554621]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Failed Tests"
text = "0"
alignment = 2
max_length = 3
editable = false
context_menu_enabled = false
emoji_menu_enabled = false
shortcut_keys_enabled = false
middle_mouse_paste_enabled = false
selecting_enabled = false
deselect_on_focus_loss_enabled = false
drag_and_drop_selection_enabled = false
virtual_keyboard_enabled = false
[node name="icon" type="TextureRect" parent="MarginContainer/status_bar/FAILED/value" unique_id=1889621378]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 4.0
offset_top = -8.0
offset_right = 20.0
offset_bottom = 8.0
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
stretch_mode = 2
[node name="buttons" type="VBoxContainer" parent="MarginContainer/status_bar/FAILED" unique_id=699611313]
layout_mode = 2
size_flags_horizontal = 0
[node name="up" type="TextureButton" parent="MarginContainer/status_bar/FAILED/buttons" unique_id=1774403865]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10
[node name="down" type="TextureButton" parent="MarginContainer/status_bar/FAILED/buttons" unique_id=1605438045]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 2
flip_v = true
[node name="FLAKY" type="HBoxContainer" parent="MarginContainer/status_bar" unique_id=480870974]
layout_mode = 2
tooltip_text = "Flaky Tests"
[node name="value" type="LineEdit" parent="MarginContainer/status_bar/FLAKY" unique_id=2059394293]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Flaky Tests"
text = "0"
alignment = 2
max_length = 3
editable = false
context_menu_enabled = false
emoji_menu_enabled = false
shortcut_keys_enabled = false
middle_mouse_paste_enabled = false
selecting_enabled = false
deselect_on_focus_loss_enabled = false
drag_and_drop_selection_enabled = false
virtual_keyboard_enabled = false
[node name="icon" type="TextureRect" parent="MarginContainer/status_bar/FLAKY/value" unique_id=885817973]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 4.0
offset_top = -8.0
offset_right = 20.0
offset_bottom = 8.0
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
stretch_mode = 2
[node name="buttons" type="VBoxContainer" parent="MarginContainer/status_bar/FLAKY" unique_id=968503310]
layout_mode = 2
size_flags_horizontal = 0
[node name="up" type="TextureButton" parent="MarginContainer/status_bar/FLAKY/buttons" unique_id=1127861257]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10
[node name="down" type="TextureButton" parent="MarginContainer/status_bar/FLAKY/buttons" unique_id=949128796]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 2
flip_v = true
[node name="SKIPPED" type="HBoxContainer" parent="MarginContainer/status_bar" unique_id=2053554589]
layout_mode = 2
tooltip_text = "Skipped Tests"
[node name="value" type="LineEdit" parent="MarginContainer/status_bar/SKIPPED" unique_id=1877800941]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Skipped Tests"
text = "0"
alignment = 2
max_length = 3
editable = false
context_menu_enabled = false
emoji_menu_enabled = false
shortcut_keys_enabled = false
middle_mouse_paste_enabled = false
selecting_enabled = false
deselect_on_focus_loss_enabled = false
drag_and_drop_selection_enabled = false
virtual_keyboard_enabled = false
[node name="icon" type="TextureRect" parent="MarginContainer/status_bar/SKIPPED/value" unique_id=932936779]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 4.0
offset_top = -8.0
offset_right = 20.0
offset_bottom = 8.0
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
stretch_mode = 2
[node name="buttons" type="VBoxContainer" parent="MarginContainer/status_bar/SKIPPED" unique_id=1650258492]
layout_mode = 2
size_flags_horizontal = 0
[node name="up" type="TextureButton" parent="MarginContainer/status_bar/SKIPPED/buttons" unique_id=357027687]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10
[node name="down" type="TextureButton" parent="MarginContainer/status_bar/SKIPPED/buttons" unique_id=603266459]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 2
flip_v = true
[node name="ORPHAN" type="HBoxContainer" parent="MarginContainer/status_bar" unique_id=1284157443]
layout_mode = 2
tooltip_text = "Detected Orphan Nodes"
[node name="value" type="LineEdit" parent="MarginContainer/status_bar/ORPHAN" unique_id=629163801]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Detected Orphan Nodes"
text = "0"
alignment = 2
max_length = 3
editable = false
context_menu_enabled = false
emoji_menu_enabled = false
shortcut_keys_enabled = false
middle_mouse_paste_enabled = false
selecting_enabled = false
deselect_on_focus_loss_enabled = false
drag_and_drop_selection_enabled = false
virtual_keyboard_enabled = false
[node name="icon" type="TextureRect" parent="MarginContainer/status_bar/ORPHAN/value" unique_id=2121368482]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 4.0
offset_top = -8.0
offset_right = 20.0
offset_bottom = 8.0
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
stretch_mode = 2
[node name="buttons" type="VBoxContainer" parent="MarginContainer/status_bar/ORPHAN" unique_id=433516040]
layout_mode = 2
size_flags_horizontal = 0
[node name="up" type="TextureButton" parent="MarginContainer/status_bar/ORPHAN/buttons" unique_id=159317457]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10
[node name="down" type="TextureButton" parent="MarginContainer/status_bar/ORPHAN/buttons" unique_id=1357830825]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 2
flip_v = true
[connection signal="pressed" from="tree_tools/tree_buttons/btn_tree_sync" to="." method="_on_btn_tree_sync_pressed"]
@@ -0,0 +1,104 @@
@tool
extends Control
const GdUnitInspectorTreeMainPanel := preload("res://addons/gdUnit4/src/ui/parts/GdUnitInspectorTreeMainPanel.gd")
@onready var _version_label: Control = %version
@onready var _button_wiki: Button = %help
@onready var _tool_button: Button = %tool
@onready var _button_run_overall: Button = %run_overall
@onready var _button_run: Button = %run
@onready var _button_run_debug: Button = %debug
@onready var _button_stop: Button = %stop
var inspector: GdUnitInspectorTreeMainPanel
var command_handler: GdUnitCommandHandler
func _ready() -> void:
command_handler = GdUnitCommandHandler.instance()
inspector = get_parent().get_parent().find_child("MainPanel", false, false)
if inspector == null:
push_error("Internal error, can't connect to the test inspector!")
else:
inspector.tree_item_selected.connect(_on_inspector_selected)
GdUnit4Version.init_version_label(_version_label)
GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event)
GdUnitSignals.instance().gdunit_settings_changed.connect(_on_settings_changed)
_init_buttons()
func _init_buttons() -> void:
_init_button(_button_run_overall, GdUnitCommandRunTestsOverall.ID)
_init_button(_button_run, GdUnitCommandInspectorRunTests.ID)
_init_button(_button_run_debug, GdUnitCommandInspectorDebugTests.ID)
_init_button(_button_stop, GdUnitCommandStopTestSession.ID)
_button_stop.icon = command_handler.command_icon(GdUnitCommandStopTestSession.ID)
_tool_button.icon = GdUnitUiTools.get_icon("Tools")
_button_wiki.icon = GdUnitUiTools.get_icon("HelpSearch")
# Set run buttons initial disabled
_button_run.disabled = true
_button_run_debug.disabled = true
func _init_button(button: Button, comand_id: String) -> void:
button.set_meta("GdUnitCommand", comand_id)
button.icon = command_handler.command_icon(comand_id)
button.shortcut = command_handler.command_shortcut(comand_id)
if button == _button_run_overall:
button.visible = GdUnitSettings.is_inspector_toolbar_button_show()
func _on_inspector_selected(item: TreeItem) -> void:
var button_disabled := item == null
_button_run.disabled = button_disabled
_button_run_debug.disabled = button_disabled
func _on_gdunit_event(event: GdUnitEvent) -> void:
if event.type() == GdUnitEvent.SESSION_START:
_button_run_overall.disabled = true
_button_run.disabled = true
_button_run_debug.disabled = true
_button_stop.disabled = false
return
if event.type() == GdUnitEvent.SESSION_CLOSE:
_button_run_overall.disabled = false
_button_stop.disabled = true
func _on_button_pressed(source: BaseButton) -> void:
var command_id: String = source.get_meta("GdUnitCommand")
await command_handler.command_execute(command_id)
func _on_wiki_pressed() -> void:
var status := OS.shell_open("https://godot-gdunit-labs.github.io/gdUnit4/latest")
if status != OK:
push_error("Can't open GdUnit4 documentaion page: %s" % error_string(status))
func _on_btn_tool_pressed() -> void:
var settings_dlg: Window = EditorInterface.get_base_control().find_child("GdUnitSettingsDialog", false, false)
if settings_dlg == null:
settings_dlg = preload("res://addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.tscn").instantiate()
EditorInterface.get_base_control().add_child(settings_dlg, true)
settings_dlg.popup_centered_ratio(.60)
func _on_settings_changed(property: GdUnitProperty) -> void:
# needs to wait a frame to be command handler notified first for settings changes
await get_tree().process_frame
_button_run_overall.visible = GdUnitSettings.is_inspector_toolbar_button_show()
if property.name().begins_with(GdUnitSettings.GROUP_SHORTCUT_INSPECTOR):
_button_run.shortcut = command_handler.command_shortcut(GdUnitCommandInspectorRunTests.ID)
_button_run_debug.shortcut = command_handler.command_shortcut(GdUnitCommandInspectorDebugTests.ID)
_button_run_overall.shortcut = command_handler.command_shortcut(GdUnitCommandRunTestsOverall.ID)
_button_stop.shortcut = command_handler.command_shortcut(GdUnitCommandStopTestSession.ID)
@@ -0,0 +1 @@
uid://birjse4jr7jbc
@@ -0,0 +1,150 @@
[gd_scene format=3 uid="uid://dx7xy4dgi3wwb"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorToolBar.gd" id="3"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_c7rhl"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_3erui"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_p22nw"]
[sub_resource type="InputEventKey" id="InputEventKey_4j3on"]
alt_pressed = true
pressed = true
keycode = 4194338
physical_keycode = 4194338
[sub_resource type="Shortcut" id="Shortcut_5pa04"]
events = [SubResource("InputEventKey_4j3on")]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_3lcek"]
[sub_resource type="InputEventKey" id="InputEventKey_85ykl"]
alt_pressed = true
pressed = true
keycode = 4194336
physical_keycode = 4194336
[sub_resource type="Shortcut" id="Shortcut_fpubx"]
events = [SubResource("InputEventKey_85ykl")]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ndw0i"]
[sub_resource type="InputEventKey" id="InputEventKey_1iti7"]
alt_pressed = true
pressed = true
keycode = 4194337
physical_keycode = 4194337
[sub_resource type="Shortcut" id="Shortcut_hpi24"]
events = [SubResource("InputEventKey_1iti7")]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_eoihf"]
[sub_resource type="InputEventKey" id="InputEventKey_hb3do"]
alt_pressed = true
pressed = true
keycode = 4194339
physical_keycode = 4194339
[sub_resource type="Shortcut" id="Shortcut_lm2q6"]
events = [SubResource("InputEventKey_hb3do")]
[node name="ToolBar" type="HBoxContainer" unique_id=295615556]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 32.0
grow_horizontal = 2
script = ExtResource("3")
[node name="tools" type="HBoxContainer" parent="." unique_id=753222103]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
[node name="help" type="Button" parent="tools" unique_id=1834372497]
unique_name_in_owner = true
layout_mode = 2
theme_override_styles/normal = SubResource("StyleBoxEmpty_c7rhl")
[node name="tool" type="Button" parent="tools" unique_id=144277615]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "GdUnit Settings"
theme_override_styles/normal = SubResource("StyleBoxEmpty_3erui")
[node name="controls" type="HBoxContainer" parent="." unique_id=108317981]
layout_mode = 2
size_flags_horizontal = 6
size_flags_vertical = 4
alignment = 1
[node name="VSeparator3" type="VSeparator" parent="controls" unique_id=1244151035]
layout_mode = 2
[node name="run_overall" type="Button" parent="controls" unique_id=95775836]
unique_name_in_owner = true
use_parent_material = true
layout_mode = 2
tooltip_text = "Run overall tests"
theme_override_styles/normal = SubResource("StyleBoxEmpty_p22nw")
shortcut = SubResource("Shortcut_5pa04")
metadata/GdUnitCommand = "Run Tests Overall"
[node name="run" type="Button" parent="controls" unique_id=121281977]
unique_name_in_owner = true
use_parent_material = true
layout_mode = 2
tooltip_text = "Rerun unit tests"
theme_override_styles/normal = SubResource("StyleBoxEmpty_3lcek")
disabled = true
shortcut = SubResource("Shortcut_fpubx")
metadata/GdUnitCommand = "Run Inspector Tests"
[node name="debug" type="Button" parent="controls" unique_id=1188465777]
unique_name_in_owner = true
use_parent_material = true
layout_mode = 2
tooltip_text = "Rerun unit tests (Debug)"
theme_override_styles/normal = SubResource("StyleBoxEmpty_ndw0i")
disabled = true
shortcut = SubResource("Shortcut_hpi24")
metadata/GdUnitCommand = "Debug Inspector Tests"
[node name="stop" type="Button" parent="controls" unique_id=2086070257]
unique_name_in_owner = true
use_parent_material = true
layout_mode = 2
tooltip_text = "Stops runing unit tests"
theme_override_styles/normal = SubResource("StyleBoxEmpty_eoihf")
disabled = true
shortcut = SubResource("Shortcut_lm2q6")
metadata/GdUnitCommand = "Stop Test Session"
[node name="VSeparator4" type="VSeparator" parent="controls" unique_id=1661024234]
layout_mode = 2
[node name="CenterContainer" type="HBoxContainer" parent="." unique_id=1521483443]
use_parent_material = true
layout_mode = 2
size_flags_horizontal = 10
size_flags_vertical = 4
alignment = 2
[node name="version" type="Label" parent="CenterContainer" unique_id=558200171]
unique_name_in_owner = true
auto_translate_mode = 2
use_parent_material = true
layout_mode = 2
size_flags_horizontal = 2
size_flags_vertical = 13
localize_numeral_system = false
horizontal_alignment = 1
justification_flags = 160
[connection signal="pressed" from="tools/help" to="." method="_on_wiki_pressed"]
[connection signal="pressed" from="tools/tool" to="." method="_on_btn_tool_pressed"]
[connection signal="pressed" from="controls/run_overall" to="." method="_on_button_pressed" flags=18]
[connection signal="pressed" from="controls/run" to="." method="_on_button_pressed" flags=18]
[connection signal="pressed" from="controls/debug" to="." method="_on_button_pressed" flags=18]
[connection signal="pressed" from="controls/stop" to="." method="_on_button_pressed" flags=18]
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
uid://7elllplde43b
@@ -0,0 +1,133 @@
[gd_scene format=3 uid="uid://bqfpidewtpeg0"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/GdUnitInspectorTreeMainPanel.gd" id="1"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/menu/GdUnitInspectorContextMenu.tscn" id="2_o6s0p"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/parts/GdUnitReportPanel.tscn" id="3_miuuy"]
[sub_resource type="DPITexture" id="DPITexture_njcuo"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"M4 12a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 4 4z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[sub_resource type="DPITexture" id="DPITexture_o05pk"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"M3 3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1zm4.975 0A1 1 0 0 0 7 3.998v8a1 1 0 0 0 1.625.781l5-4a1 1 0 0 0 0-1.56l-5-4A1 1 0 0 0 7.975 3z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[sub_resource type="DPITexture" id="DPITexture_njtpf"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"m8 9.669-3.536 2.583H7v2.537h2v-2.537h2.536zm0-3.314L4.464 3.772H7V1.235h2v2.537h2.536zm-7.296.73h14.591v1.831H.704z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[sub_resource type="DPITexture" id="DPITexture_eg3rq"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"m8 16-3.5-2.5H7V11h2v2.5h2.5zM8 0 4.5 2.5H7V5h2V2.5h2.5zM1 7h14v2H1z\"/></svg>
"
saturation = 2.0
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(0.83, 0.78, 0.62, 1)
}
[node name="MainPanel" type="Control" unique_id=944258025]
custom_minimum_size = Vector2(120, 240)
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1")
[node name="contextMenu" parent="." unique_id=73764904 instance=ExtResource("2_o6s0p")]
unique_name_in_owner = true
visible = false
item_0/icon = SubResource("DPITexture_njcuo")
item_1/icon = SubResource("DPITexture_o05pk")
item_2/icon = SubResource("DPITexture_njcuo")
item_4/icon = SubResource("DPITexture_njtpf")
item_5/icon = SubResource("DPITexture_eg3rq")
[node name="split" type="VSplitContainer" parent="." unique_id=1044515559]
clip_contents = true
custom_minimum_size = Vector2(0, 160)
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/autohide = 0
split_offsets = PackedInt32Array(120)
split_offset = 120
[node name="Panel" type="Panel" parent="split" unique_id=290722553]
custom_minimum_size = Vector2(0, 120)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Tree" type="Tree" parent="split/Panel" unique_id=741772884]
unique_name_in_owner = true
use_parent_material = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/icon_max_width = 16
columns = 2
allow_reselect = true
allow_rmb_select = true
hide_root = true
select_mode = 1
[node name="discover_hint" type="HBoxContainer" parent="split/Panel" unique_id=555683311]
unique_name_in_owner = true
visible = false
use_parent_material = true
layout_mode = 0
alignment = 1
[node name="spinner" type="Button" parent="split/Panel/discover_hint" unique_id=200472082]
unique_name_in_owner = true
clip_contents = true
custom_minimum_size = Vector2(64, 64)
layout_mode = 2
size_flags_stretch_ratio = 1.94
disabled = true
button_mask = 0
text = "Discover Tests"
flat = true
alignment = 2
[node name="report" parent="split" unique_id=1465857421 instance=ExtResource("3_miuuy")]
unique_name_in_owner = true
custom_minimum_size = Vector2(120, 40)
layout_mode = 2
[connection signal="item_activated" from="split/Panel/Tree" to="." method="_on_Tree_item_activated"]
[connection signal="item_mouse_selected" from="split/Panel/Tree" to="." method="_on_tree_item_mouse_selected"]
[connection signal="item_selected" from="split/Panel/Tree" to="." method="_on_Tree_item_selected"]
@@ -0,0 +1,62 @@
@tool
class_name GdUnitReportPanel
extends Panel
@onready var report_list: Node = %report_list
@onready var message_template: RichTextLabel = %message
func clear() -> void:
for child in report_list.get_children():
report_list.remove_child(child)
child.queue_free()
func show_report(reports: Array[GdUnitReport]) -> void:
clear()
for report in reports:
report_list.add_child(build_report(report))
func build_report(report: GdUnitReport) -> RichTextLabel:
var message: RichTextLabel = message_template.duplicate()
GdUnitFonts.init_fonts(message)
message.push_color(GdUnitEditorColorTheme.text_color)
message.append_text(report.message())
message.pop()
add_stack_trace(message, report.stack_trace())
message.visible = true
return message
func add_stack_trace(message: RichTextLabel, trace: GdUnitStackTrace) -> void:
if trace == null:
return
message.newline()
for frame in trace.get_frames():
message.push_indent(1)
message.push_meta(frame, RichTextLabel.META_UNDERLINE_ON_HOVER, frame._source)
message.push_color(GdUnitEditorColorTheme.text_color)
message.append_text("at ")
message.push_color(GdUnitEditorColorTheme.function_definition_color)
message.append_text(frame._function)
message.pop()
message.append_text(" in ")
message.pop()
message.push_color(GdUnitEditorColorTheme.engine_type_color)
message.append_text(frame._source.get_file())
message.append_text(" : ")
message.append_text(str(frame._line))
message.pop() # push_color
message.pop() # push_meta
message.pop() # push_indent
message.newline()
if not message.meta_clicked.is_connected(_on_meta_clicked):
message.meta_clicked.connect(_on_meta_clicked)
func _on_meta_clicked(meta: Variant) -> void:
var frame: GdUnitStackTraceElement = meta
GdUnitScriptEditorControls.edit_script(frame._source, frame._line)
@@ -0,0 +1 @@
uid://dhcy3bq74qcl0
@@ -0,0 +1,47 @@
[gd_scene format=3 uid="uid://dga8nhaxnyr53"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/parts/GdUnitReportPanel.gd" id="1_w8qy0"]
[node name="report" type="Panel" unique_id=1075065511]
clip_contents = true
custom_minimum_size = Vector2(120, 80)
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_w8qy0")
[node name="message" type="RichTextLabel" parent="." unique_id=1680360176]
unique_name_in_owner = true
auto_translate_mode = 2
visible = false
layout_mode = 0
size_flags_horizontal = 3
size_flags_vertical = 3
focus_mode = 2
mouse_filter = 1
bbcode_enabled = true
fit_content = true
autowrap_mode = 0
selection_enabled = true
[node name="ScrollContainer" type="ScrollContainer" parent="." unique_id=385317760]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_vertical = 3
[node name="report_list" type="VBoxContainer" parent="ScrollContainer" unique_id=1467163528]
unique_name_in_owner = true
clip_contents = true
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 2
theme_override_constants/separation = 2
@@ -0,0 +1,56 @@
@tool
class_name GdUnitInputCapture
extends Control
signal input_completed(input_event: InputEventKey)
var _tween: Tween
var _input_event: InputEventKey
func _ready() -> void:
reset()
self_modulate = Color.WHITE
_tween = create_tween()
@warning_ignore("return_value_discarded")
_tween.set_loops()
@warning_ignore("return_value_discarded")
_tween.tween_property(%Label, "self_modulate", Color(1, 1, 1, .8), 1.0).from_current().set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN_OUT)
func reset() -> void:
_input_event = InputEventKey.new()
func _input(event: InputEvent) -> void:
if not is_visible_in_tree():
return
if event is InputEventKey and event.is_pressed() and not event.is_echo():
var _event := event as InputEventKey
match _event.keycode:
KEY_CTRL:
_input_event.ctrl_pressed = true
KEY_SHIFT:
_input_event.shift_pressed = true
KEY_ALT:
_input_event.alt_pressed = true
KEY_META:
_input_event.meta_pressed = true
_:
_input_event.keycode = _event.keycode
_apply_input_modifiers(_event)
accept_event()
if event is InputEventKey and not event.is_pressed():
input_completed.emit(_input_event)
hide()
func _apply_input_modifiers(event: InputEvent) -> void:
if event is InputEventWithModifiers:
var _event := event as InputEventWithModifiers
_input_event.meta_pressed = _event.meta_pressed or _input_event.meta_pressed
_input_event.alt_pressed = _event.alt_pressed or _input_event.alt_pressed
_input_event.shift_pressed = _event.shift_pressed or _input_event.shift_pressed
_input_event.ctrl_pressed = _event.ctrl_pressed or _input_event.ctrl_pressed
@@ -0,0 +1 @@
uid://d3snyw5r4f13t
@@ -0,0 +1,36 @@
[gd_scene load_steps=2 format=3 uid="uid://pmnkxrhglak5"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/settings/GdUnitInputCapture.gd" id="1_gki1u"]
[node name="GdUnitInputMapper" type="Control"]
modulate = Color(0.929099, 0.929099, 0.929099, 0.936189)
top_level = true
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_gki1u")
[node name="Label" type="Label" parent="."]
unique_name_in_owner = true
self_modulate = Color(0.401913, 0.401913, 0.401913, 0.461723)
top_level = true
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -60.5
offset_top = -19.5
offset_right = 60.5
offset_bottom = 19.5
grow_horizontal = 2
grow_vertical = 2
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_font_sizes/font_size = 26
text = "Press keys for shortcut"
@@ -0,0 +1,327 @@
@tool
extends Window
const EAXAMPLE_URL := "https://github.com/MikeSchulze/gdUnit4-examples/archive/refs/heads/master.zip"
const GdUnitTools := preload ("res://addons/gdUnit4/src/core/GdUnitTools.gd")
const GdUnitUpdateClient = preload ("res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd")
@onready var _update_client: GdUnitUpdateClient = $GdUnitUpdateClient
@onready var _version_label: RichTextLabel = %version
@onready var _btn_install: Button = %btn_install_examples
@onready var _progress_bar: ProgressBar = %ProgressBar
@onready var _progress_text: Label = %progress_lbl
@onready var _properties_template: Control = $property_template
@onready var _properties_common: Control = % "common-content"
@onready var _properties_ui: Control = % "ui-content"
@onready var _properties_shortcuts: Control = % "shortcut-content"
@onready var _properties_report: Control = % "report-content"
@onready var _input_capture: GdUnitInputCapture = %GdUnitInputCapture
@onready var _property_error: Window = % "propertyError"
@onready var _tab_container: TabContainer = %Properties
@onready var _update_tab: Control = %Update
var _font_size: float
func _ready() -> void:
set_name("GdUnitSettingsDialog")
# initialize for testing
if not Engine.is_editor_hint():
GdUnitSettings.setup()
GdUnit4Version.init_version_label(_version_label)
_font_size = GdUnitFonts.init_fonts(_version_label)
setup_properties(_properties_common, GdUnitSettings.COMMON_SETTINGS)
setup_properties(_properties_ui, GdUnitSettings.UI_SETTINGS)
setup_properties(_properties_report, GdUnitSettings.REPORT_SETTINGS)
setup_properties(_properties_shortcuts, GdUnitSettings.SHORTCUT_SETTINGS)
check_for_update()
func _sort_by_key(left: GdUnitProperty, right: GdUnitProperty) -> bool:
return left.name() < right.name()
func setup_properties(properties_parent: Control, property_category: String) -> void:
# Do remove first potential previous added properties (could be happened when the dlg is opened at twice)
for child in properties_parent.get_children():
properties_parent.remove_child(child)
var category_properties := GdUnitSettings.list_settings(property_category)
# sort by key
category_properties.sort_custom(_sort_by_key)
var theme_ := Theme.new()
theme_.set_constant("h_separation", "GridContainer", 12)
var last_category := "!"
var min_size_overall := 0.0
var labels := []
var inputs := []
var info_labels := []
var grid: GridContainer = null
for p in category_properties:
var min_size_ := 0.0
var property: GdUnitProperty = p
var current_category := property.category()
if not grid or current_category != last_category:
grid = GridContainer.new()
grid.columns = 4
grid.theme = theme_
var sub_category: Control = _properties_template.get_child(3).duplicate()
var category_label: Label = sub_category.get_child(0)
category_label.text = current_category.capitalize()
sub_category.custom_minimum_size.y = _font_size + 16
properties_parent.add_child(sub_category)
properties_parent.add_child(grid)
last_category = current_category
# property name
var label: Label = _properties_template.get_child(0).duplicate()
label.text = _to_human_readable(property.name())
labels.append(label)
grid.add_child(label)
# property reset btn
var reset_btn: Button = _properties_template.get_child(1).duplicate()
reset_btn.icon = _get_btn_icon("Reload")
reset_btn.disabled = property.value() == property.default()
grid.add_child(reset_btn)
# property type specific input element
var input: Node = _create_input_element(property, reset_btn)
inputs.append(input)
grid.add_child(input)
@warning_ignore("return_value_discarded")
reset_btn.pressed.connect(_on_btn_property_reset_pressed.bind(property, input, reset_btn))
# property help text
var info: Label = _properties_template.get_child(2).duplicate()
info.text = property.help()
info_labels.append(info)
grid.add_child(info)
if min_size_overall < min_size_:
min_size_overall = min_size_
for controls: Array in [labels, inputs, info_labels]:
var _size: float = controls.map(func(c: Control) -> float: return c.size.x).max()
min_size_overall += _size
for control: Control in controls:
control.custom_minimum_size.x = _size
properties_parent.custom_minimum_size.x = min_size_overall
func _create_input_element(property: GdUnitProperty, reset_btn: Button) -> Node:
if property.is_selectable_value():
var options := OptionButton.new()
options.alignment = HORIZONTAL_ALIGNMENT_CENTER
for value in property.value_set():
options.add_item(value)
options.item_selected.connect(_on_option_selected.bind(property, reset_btn))
options.select(property.int_value())
return options
if property.type() == TYPE_BOOL:
var check_btn := CheckButton.new()
check_btn.toggled.connect(_on_property_text_changed.bind(property, reset_btn))
check_btn.button_pressed = property.value()
return check_btn
if property.type() in [TYPE_INT, TYPE_STRING]:
var input := LineEdit.new()
input.text_changed.connect(_on_property_text_changed.bind(property, reset_btn))
input.set_context_menu_enabled(false)
input.set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER)
input.set_expand_to_text_length_enabled(true)
input.text = str(property.value())
return input
if property.type() == TYPE_PACKED_INT32_ARRAY:
var key_input_button := Button.new()
var value:PackedInt32Array = property.value()
key_input_button.text = to_shortcut(value)
key_input_button.pressed.connect(_on_shortcut_change.bind(key_input_button, property, reset_btn))
return key_input_button
return Control.new()
func to_shortcut(keys: PackedInt32Array) -> String:
var input_event := InputEventKey.new()
for key in keys:
match key:
KEY_CTRL: input_event.ctrl_pressed = true
KEY_SHIFT: input_event.shift_pressed = true
KEY_ALT: input_event.alt_pressed = true
KEY_META: input_event.meta_pressed = true
_:
input_event.keycode = key as Key
return input_event.as_text()
func to_keys(input_event: InputEventKey) -> PackedInt32Array:
var keys := PackedInt32Array()
if input_event.ctrl_pressed:
keys.append(KEY_CTRL)
if input_event.shift_pressed:
keys.append(KEY_SHIFT)
if input_event.alt_pressed:
keys.append(KEY_ALT)
if input_event.meta_pressed:
keys.append(KEY_META)
keys.append(input_event.keycode)
return keys
func _to_human_readable(value: String) -> String:
return value.split("/")[-1].capitalize()
func _get_btn_icon(p_name: String) -> Texture2D:
if not Engine.is_editor_hint():
var placeholder := PlaceholderTexture2D.new()
placeholder.size = Vector2(8, 8)
return placeholder
return GdUnitUiTools.get_icon(p_name)
func _install_examples() -> void:
_init_progress(5)
update_progress("Downloading examples")
await get_tree().process_frame
var tmp_path := GdUnitFileAccess.create_temp_dir("download")
var zip_file := tmp_path + "/examples.zip"
var response: GdUnitUpdateClient.HttpResponse = await _update_client.request_zip_package(EAXAMPLE_URL, zip_file)
if response.status() != 200:
push_warning("Examples cannot be retrieved from GitHub! \n Error code: %d : %s" % [response.status(), response.response()])
update_progress("Install examples failed! Try it later again.")
await get_tree().create_timer(3).timeout
stop_progress()
return
# extract zip to tmp
update_progress("Install examples into project")
var result := GdUnitFileAccess.extract_zip(zip_file, "res://gdUnit4-examples/")
if result.is_error():
update_progress("Install examples failed! %s" % result.error_message())
await get_tree().create_timer(3).timeout
stop_progress()
return
update_progress("Refresh project")
await rescan()
await reimport("res://gdUnit4-examples/")
update_progress("Examples successfully installed")
await get_tree().create_timer(3).timeout
stop_progress()
func rescan() -> void:
await get_tree().process_frame
var fs := EditorInterface.get_resource_filesystem()
fs.scan_sources()
while fs.is_scanning():
await get_tree().create_timer(1).timeout
func reimport(path: String) -> void:
await get_tree().process_frame
var files := DirAccess.get_files_at(path)
EditorInterface.get_resource_filesystem().reimport_files(files)
for directory in DirAccess.get_directories_at(path):
reimport(directory)
func check_for_update() -> void:
if not GdUnitSettings.is_update_notification_enabled():
return
var response :GdUnitUpdateClient.HttpResponse = await _update_client.request_latest_version()
if response.status() != 200:
printerr("Latest version information cannot be retrieved from GitHub!")
printerr("Error: %s" % response.response())
return
var latest_version := _update_client.extract_latest_version(response)
if latest_version.is_greater(GdUnit4Version.current()):
var tab_index := _tab_container.get_tab_idx_from_control(_update_tab)
_tab_container.set_tab_button_icon(tab_index, GdUnitUiTools.get_icon("Notification", Color.YELLOW))
_tab_container.set_tab_tooltip(tab_index, "An new update is available.")
func _on_btn_report_bug_pressed() -> void:
@warning_ignore("return_value_discarded")
OS.shell_open("https://github.com/MikeSchulze/gdUnit4/issues/new?assignees=MikeSchulze&labels=bug&projects=projects%2F5&template=bug_report.yml&title=GD-XXX%3A+Describe+the+issue+briefly")
func _on_btn_request_feature_pressed() -> void:
@warning_ignore("return_value_discarded")
OS.shell_open("https://github.com/MikeSchulze/gdUnit4/issues/new?assignees=MikeSchulze&labels=enhancement&projects=&template=feature_request.md&title=")
func _on_btn_install_examples_pressed() -> void:
_btn_install.disabled = true
await _install_examples()
_btn_install.disabled = false
func _on_btn_close_pressed() -> void:
hide()
func _on_btn_property_reset_pressed(property: GdUnitProperty, input: Node, reset_btn: Button) -> void:
if input is CheckButton:
var is_default_pressed: bool = property.default()
(input as CheckButton).button_pressed = is_default_pressed
elif input is LineEdit:
(input as LineEdit).text = str(property.default())
# we have to update manually for text input fields because of no change event is emited
_on_property_text_changed(property.default(), property, reset_btn)
elif input is OptionButton:
(input as OptionButton).select(0)
_on_option_selected(0, property, reset_btn)
elif input is Button:
var value: PackedInt32Array = property.default()
(input as Button).text = to_shortcut(value)
_on_property_text_changed(value, property, reset_btn)
func _on_property_text_changed(new_value: Variant, property: GdUnitProperty, reset_btn: Button) -> void:
property.set_value(new_value)
reset_btn.disabled = property.value() == property.default()
var error: Variant = GdUnitSettings.update_property(property)
if error:
var label: Label = _property_error.get_child(0) as Label
label.set_text(str(error))
var control := gui_get_focus_owner()
_property_error.show()
if control != null:
_property_error.position = control.global_position + Vector2(self.position) + Vector2(40, 40)
func _on_option_selected(index: int, property: GdUnitProperty, reset_btn: Button) -> void:
property.set_value(index)
reset_btn.disabled = property.value() == property.default()
GdUnitSettings.update_property(property)
func _on_shortcut_change(input_button: Button, property: GdUnitProperty, reset_btn: Button) -> void:
_input_capture.set_custom_minimum_size(_properties_shortcuts.get_size())
_input_capture.visible = true
_input_capture.show()
_properties_shortcuts.visible = false
set_process_input(false)
_input_capture.reset()
var input_event: InputEventKey = await _input_capture.input_completed
input_button.text = input_event.as_text()
_on_property_text_changed(to_keys(input_event), property, reset_btn)
_properties_shortcuts.visible = true
set_process_input(true)
func _init_progress(max_value: int) -> void:
_progress_bar.visible = true
_progress_bar.max_value = max_value
_progress_bar.value = 0
func _progress() -> void:
_progress_bar.value += 1
func stop_progress() -> void:
_progress_bar.visible = false
func update_progress(message: String) -> void:
_progress_text.text = message
_progress_bar.value += 1
@@ -0,0 +1 @@
uid://xam8iuvt0c6u
@@ -0,0 +1,349 @@
[gd_scene load_steps=9 format=3]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/settings/GdUnitSettingsDialog.gd" id="2"]
[ext_resource type="Texture2D" path="res://addons/gdUnit4/src/ui/settings/logo.png" id="3_isfyl"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/templates/GdUnitTestSuiteTemplatePanel.tscn" id="4"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.tscn" id="4_nf72w"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn" id="5_n1jtv"]
[ext_resource type="PackedScene" path="res://addons/gdUnit4/src/ui/settings/GdUnitInputCapture.tscn" id="5_xu3j8"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/update/GdUnitUpdateClient.gd" id="8_2ggr0"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hbbq5"]
content_margin_left = 10.0
content_margin_right = 10.0
bg_color = Color(0.172549, 0.113725, 0.141176, 1)
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color(0.87451, 0.0705882, 0.160784, 1)
border_blend = true
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
shadow_color = Color(0, 0, 0, 0.756863)
shadow_size = 10
shadow_offset = Vector2(10, 10)
[node name="GdUnitSettingsDialog" type="Window"]
disable_3d = true
gui_embed_subwindows = true
title = "GdUnit4 Settings"
initial_position = 1
size = Vector2i(1400, 600)
visible = false
wrap_controls = true
exclusive = true
extend_to_title = true
script = ExtResource("2")
[node name="property_template" type="Control" parent="."]
visible = false
layout_mode = 3
anchors_preset = 0
offset_left = 4.0
offset_top = 4.0
offset_right = 4.0
offset_bottom = 4.0
size_flags_horizontal = 0
[node name="Label" type="Label" parent="property_template"]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_top = -11.5
offset_right = 1.0
offset_bottom = 11.5
grow_vertical = 2
[node name="btn_reset" type="Button" parent="property_template"]
layout_mode = 0
offset_right = 12.0
offset_bottom = 40.0
tooltip_text = "Reset to default value"
clip_text = true
[node name="info" type="Label" parent="property_template"]
clip_contents = true
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_top = -11.5
offset_right = 316.0
offset_bottom = 11.5
grow_vertical = 2
size_flags_horizontal = 3
max_lines_visible = 1
[node name="sub_category" type="Panel" parent="property_template"]
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
offset_right = -220.0
grow_horizontal = 2
size_flags_horizontal = 3
[node name="Label" type="Label" parent="property_template/sub_category"]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 4.0
offset_top = -11.5
offset_right = 5.0
offset_bottom = 11.5
grow_vertical = 2
theme_override_colors/font_color = Color(0.439216, 0.45098, 1, 1)
[node name="GdUnitUpdateClient" type="Node" parent="."]
script = ExtResource("8_2ggr0")
[node name="Panel" type="Panel" parent="."]
use_parent_material = true
clip_contents = true
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="PanelContainer" type="PanelContainer" parent="Panel"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="v" type="VBoxContainer" parent="Panel/PanelContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="Panel/PanelContainer/v"]
use_parent_material = true
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
[node name="GridContainer" type="HBoxContainer" parent="Panel/PanelContainer/v/MarginContainer"]
use_parent_material = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="PanelContainer" type="MarginContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer"]
use_parent_material = true
layout_mode = 2
size_flags_vertical = 3
[node name="Panel" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer"]
use_parent_material = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="CenterContainer" type="CenterContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel"]
use_parent_material = true
layout_mode = 2
size_flags_horizontal = 3
[node name="logo" type="TextureRect" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel/CenterContainer"]
custom_minimum_size = Vector2(120, 120)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
texture = ExtResource("3_isfyl")
expand_mode = 1
stretch_mode = 5
[node name="CenterContainer2" type="MarginContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel"]
use_parent_material = true
custom_minimum_size = Vector2(0, 30)
layout_mode = 2
size_flags_horizontal = 3
[node name="version" type="RichTextLabel" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/Panel/CenterContainer2"]
unique_name_in_owner = true
auto_translate_mode = 2
use_parent_material = true
clip_contents = false
layout_mode = 2
size_flags_horizontal = 3
localize_numeral_system = false
bbcode_enabled = true
scroll_active = false
meta_underlined = false
[node name="VBoxContainer" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer"]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
alignment = 2
[node name="btn_report_bug" type="Button" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
tooltip_text = "Press to create a bug report"
text = "Report Bug"
[node name="btn_request_feature" type="Button" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
tooltip_text = "Press to create a feature request"
text = "Request Feature"
[node name="btn_install_examples" type="Button" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
tooltip_text = "Press to install the advanced test examples"
disabled = true
text = "Install Examples"
[node name="Properties" type="TabContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
current_tab = 0
[node name="Common" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"]
layout_mode = 2
metadata/_tab_index = 0
[node name="common-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/Common"]
unique_name_in_owner = true
clip_contents = true
custom_minimum_size = Vector2(1026, 0)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Hooks" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("4_nf72w")]
visible = false
layout_mode = 2
[node name="UI" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"]
visible = false
layout_mode = 2
metadata/_tab_index = 2
[node name="ui-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/UI"]
unique_name_in_owner = true
clip_contents = true
custom_minimum_size = Vector2(741, 0)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Shortcuts" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"]
visible = false
layout_mode = 2
metadata/_tab_index = 3
[node name="shortcut-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/Shortcuts"]
unique_name_in_owner = true
clip_contents = true
custom_minimum_size = Vector2(683, 0)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Report" type="ScrollContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"]
visible = false
layout_mode = 2
metadata/_tab_index = 4
[node name="report-content" type="VBoxContainer" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/Report"]
unique_name_in_owner = true
clip_contents = true
custom_minimum_size = Vector2(667, 0)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Templates" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("4")]
visible = false
layout_mode = 2
metadata/_tab_index = 5
[node name="Update" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("5_n1jtv")]
unique_name_in_owner = true
visible = false
layout_mode = 2
metadata/_tab_index = 6
[node name="GdUnitInputCapture" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties" instance=ExtResource("5_xu3j8")]
unique_name_in_owner = true
visible = false
modulate = Color(1.54884e-09, 1.54884e-09, 1.54884e-09, 0.1)
z_index = 1
z_as_relative = false
layout_mode = 2
size_flags_horizontal = 1
size_flags_vertical = 1
[node name="propertyError" type="PopupPanel" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties"]
unique_name_in_owner = true
initial_position = 1
size = Vector2i(400, 100)
theme_override_styles/panel = SubResource("StyleBoxFlat_hbbq5")
[node name="Label" type="Label" parent="Panel/PanelContainer/v/MarginContainer/GridContainer/Properties/propertyError"]
offset_left = 10.0
offset_top = 4.0
offset_right = 390.0
offset_bottom = 96.0
theme_override_colors/font_color = Color(0.858824, 0, 0.109804, 1)
horizontal_alignment = 1
vertical_alignment = 1
[node name="MarginContainer2" type="MarginContainer" parent="Panel/PanelContainer/v"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/margin_left = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/PanelContainer/v/MarginContainer2"]
layout_mode = 2
size_flags_horizontal = 3
alignment = 2
[node name="ProgressBar" type="ProgressBar" parent="Panel/PanelContainer/v/MarginContainer2/HBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="progress_lbl" type="Label" parent="Panel/PanelContainer/v/MarginContainer2/HBoxContainer/ProgressBar"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
clip_text = true
[node name="btn_close" type="Button" parent="Panel/PanelContainer/v/MarginContainer2/HBoxContainer"]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
text = "Close"
[connection signal="close_requested" from="." to="." method="_on_btn_close_pressed"]
[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer/btn_report_bug" to="." method="_on_btn_report_bug_pressed"]
[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer/btn_request_feature" to="." method="_on_btn_request_feature_pressed"]
[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer/GridContainer/PanelContainer/VBoxContainer/btn_install_examples" to="." method="_on_btn_install_examples_pressed"]
[connection signal="pressed" from="Panel/PanelContainer/v/MarginContainer2/HBoxContainer/btn_close" to="." method="_on_btn_close_pressed"]
@@ -0,0 +1,208 @@
@tool
extends ScrollContainer
@onready var _hooks_list: VBoxContainer = %hook_list
@onready var _hook_row_template: Panel = %row_template
@onready var _hook_description: RichTextLabel = %hook_description
@onready var _btn_move_up: Button = %hook_actions/btn_move_up
@onready var _btn_move_down: Button = %hook_actions/btn_move_down
@onready var _btn_delete: Button = %hook_actions/btn_delete_hook
@onready var _select_hook_dlg: FileDialog = %select_hook_dlg
@onready var _error_msg_popup: AcceptDialog = %error_msg_popup
var _selected_row: Control = null
var selected_style := StyleBoxFlat.new()
func _ready() -> void:
selected_style.set_border_color(Color.DODGER_BLUE)
selected_style.set_border_width_all(2)
selected_style.set_corner_radius_all(4)
selected_style.set_draw_center(false)
for hook: GdUnitTestSessionHook in GdUnitTestSessionHookService.instance().enigne_hooks:
_create_hook_row(hook)
_update_focus_relations()
if _hooks_list.get_child_count() > 0:
_select_row(_hooks_list.get_child(0))
func _update_focus_relations() -> void:
var row_count := _hooks_list.get_child_count()
for hook_index in row_count:
var current_hook: Control = _hooks_list.get_child(hook_index)
var previous_hook: Control = current_hook if hook_index == 0 else _hooks_list.get_child(hook_index - 1)
var next_hook: Control = current_hook if hook_index >= row_count - 1 else _hooks_list.get_child(hook_index + 1)
current_hook.focus_neighbor_top = previous_hook.get_path()
current_hook.set_focus_previous(previous_hook.get_path())
current_hook.focus_neighbor_bottom = next_hook.get_path()
current_hook.set_focus_next(next_hook.get_path())
func _create_hook_row(hook: GdUnitTestSessionHook) -> Control:
var is_system := _is_system_hook(hook)
var panel: Panel = _hook_row_template.duplicate()
panel.visible = true
panel.set_meta("hook", hook)
panel.tooltip_text = "System hook - (Read-only)" if is_system else "User hook"
panel.focus_entered.connect(_select_row.bind(panel))
panel.gui_input.connect(func(event: InputEvent) -> void:
@warning_ignore("unsafe_property_access")
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
_select_row(panel)
panel.accept_event()
)
# Left color indicator border
var indicator: ColorRect = panel.find_child("Indicator", true, false)
indicator.color = Color(1.0, 0.76, 0.03, 1) if is_system else Color(0.26, 0.54, 0.89, 1)
# Hook name
var name_label: Label = panel.find_child("HookName", true, false)
name_label.text = hook.name
# System badge
if is_system:
var badge: Control = panel.find_child("SystemBadge", true, false)
badge.visible = true
# Enable/disable toggle
var check: CheckButton = panel.find_child("Enabled", true, false)
check.button_pressed = GdUnitTestSessionHookService.is_enabled(hook)
check.toggled.connect(func(enabled: bool) -> void:
GdUnitTestSessionHookService.instance().enable_hook(hook, enabled)
)
_hooks_list.add_child(panel)
return panel
func _select_row(row: Node) -> void:
if _selected_row == row:
return
if _selected_row != null and is_instance_valid(_selected_row):
_selected_row.remove_theme_stylebox_override("panel")
_selected_row = row
if _selected_row != null:
_selected_row.grab_focus()
_selected_row.add_theme_stylebox_override("panel", selected_style)
_update_hook_buttons()
_update_hook_description()
func _update_hook_description() -> void:
if _selected_row == null:
_hook_description.text = "[i]Select a hook to view its description[/i]"
return
_hook_description.text = _get_hook(_selected_row).description
func _update_hook_buttons() -> void:
if _selected_row == null:
_btn_move_up.disabled = true
_btn_move_down.disabled = true
_btn_delete.disabled = true
return
var hook := _get_hook(_selected_row)
if _is_system_hook(hook):
_btn_move_up.disabled = true
_btn_move_down.disabled = true
_btn_delete.disabled = true
return
var idx := _selected_row.get_index()
var count := _hooks_list.get_child_count()
var prev: Control = _hooks_list.get_child(idx - 1) if idx > 0 else null
var next: Control = _hooks_list.get_child(idx + 1) if idx + 1 < count else null
_btn_move_up.disabled = prev == null or _is_system_hook(_get_hook(prev))
_btn_move_down.disabled = next == null
_btn_delete.disabled = false
static func _get_hook(row: Control) -> GdUnitTestSessionHook:
return row.get_meta("hook")
static func _is_system_hook(hook: GdUnitTestSessionHook) -> bool:
if hook == null:
return false
return hook.get_meta("SYSTEM_HOOK", false)
func _on_btn_add_hook_pressed() -> void:
_select_hook_dlg.show()
func _on_select_hook_dlg_file_selected(path: String) -> void:
_select_hook_dlg.set_current_path(path)
_on_select_hook_dlg_confirmed()
func _on_select_hook_dlg_confirmed() -> void:
_select_hook_dlg.hide()
var result := GdUnitTestSessionHookService.instance().load_hook(_select_hook_dlg.get_current_path())
if result.is_error():
_error_msg_popup.dialog_text = result.error_message()
_error_msg_popup.show()
return
var hook: GdUnitTestSessionHook = result.value()
result = GdUnitTestSessionHookService.instance().register(hook)
if result.is_error():
_error_msg_popup.dialog_text = result.error_message()
_error_msg_popup.show()
return
var row := _create_hook_row(hook)
_update_focus_relations()
_select_row(row)
func _on_btn_delete_hook_pressed() -> void:
if _selected_row == null:
return
GdUnitTestSessionHookService.instance().unregister(_get_hook(_selected_row))
_hooks_list.remove_child(_selected_row)
_selected_row.queue_free()
_update_focus_relations()
_select_row(_hooks_list.find_next_valid_focus())
func _on_btn_move_up_pressed() -> void:
if _selected_row == null:
return
var idx := _selected_row.get_index() - 1
if idx <= 0:
return
var prev: Control = _hooks_list.get_child(idx)
_hooks_list.move_child(_selected_row, idx)
GdUnitTestSessionHookService.instance().move_before(_get_hook(_selected_row), _get_hook(prev))
_update_focus_relations()
_update_hook_buttons()
func _on_btn_move_down_pressed() -> void:
if _selected_row == null:
return
var idx := _selected_row.get_index() + 1
if idx >= _hooks_list.get_child_count():
return
var next: Control = _hooks_list.get_child(idx)
_hooks_list.move_child(_selected_row, idx)
GdUnitTestSessionHookService.instance().move_after(_get_hook(_selected_row), _get_hook(next))
_update_focus_relations()
_update_hook_buttons()
@@ -0,0 +1 @@
uid://dqwl7gtce3l53
@@ -0,0 +1,227 @@
[gd_scene format=3 uid="uid://41l7a46fol5m"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/settings/GdUnitSettingsTabHooks.gd" id="1_8yffn"]
[sub_resource type="Image" id="Image_h5sr5"]
data = {
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 255, 224, 224, 224, 255, 234, 234, 234, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 1, 225, 225, 225, 174, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 173, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 74, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 228, 228, 37, 224, 224, 224, 240, 224, 224, 224, 255, 224, 224, 224, 122, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 239, 228, 228, 228, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 200, 224, 224, 224, 255, 224, 224, 224, 172, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 1, 224, 224, 224, 173, 224, 224, 224, 255, 225, 225, 225, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 193, 234, 234, 234, 12, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 193, 224, 224, 224, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id="ImageTexture_77fm0"]
image = SubResource("Image_h5sr5")
[sub_resource type="Image" id="Image_77fm0"]
data = {
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 181, 224, 224, 224, 193, 234, 234, 234, 12, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 193, 224, 224, 224, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 200, 224, 224, 224, 255, 224, 224, 224, 173, 255, 255, 255, 1, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 1, 225, 225, 225, 174, 224, 224, 224, 255, 225, 225, 225, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 228, 228, 37, 224, 224, 224, 239, 224, 224, 224, 255, 224, 224, 224, 122, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 239, 227, 227, 227, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 74, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 224, 224, 224, 253, 224, 224, 224, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 123, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 1, 224, 224, 224, 173, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 234, 234, 12, 224, 224, 224, 255, 224, 224, 224, 255, 234, 234, 234, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id="ImageTexture_rewru"]
image = SubResource("Image_77fm0")
[sub_resource type="Image" id="Image_kppp6"]
data = {
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id="ImageTexture_manhx"]
image = SubResource("Image_kppp6")
[sub_resource type="Image" id="Image_rewru"]
data = {
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 227, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 73, 224, 224, 224, 226, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 225, 226, 226, 226, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id="ImageTexture_4h4u1"]
image = SubResource("Image_rewru")
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_h5sr5"]
content_margin_left = 4.0
content_margin_top = 2.0
content_margin_right = 4.0
content_margin_bottom = 2.0
bg_color = Color(1, 0.85490197, 0.011764706, 1)
border_width_left = 2
border_width_top = 4
border_width_right = 2
border_width_bottom = 4
border_color = Color(0.8, 0.8, 0.8, 0)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[node name="Hooks" type="ScrollContainer" unique_id=659565185]
custom_minimum_size = Vector2(400, 300)
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_8yffn")
metadata/_tab_index = 1
[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=1746177026]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="hooks_content" type="VBoxContainer" parent="HBoxContainer" unique_id=1756623882]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Panel" type="Panel" parent="HBoxContainer/hooks_content" unique_id=1467652907]
modulate = Color(0.827451, 0.827451, 0.827451, 1)
layout_mode = 2
size_flags_vertical = 3
[node name="hook_scroll" type="ScrollContainer" parent="HBoxContainer/hooks_content/Panel" unique_id=1296435931]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_vertical = 3
[node name="hook_list" type="VBoxContainer" parent="HBoxContainer/hooks_content/Panel/hook_scroll" unique_id=1329270012]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="hook_description" type="RichTextLabel" parent="HBoxContainer/hooks_content" unique_id=1554657128]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 120)
layout_mode = 2
size_flags_vertical = 2
bbcode_enabled = true
text = "<hook description>"
scroll_active = false
[node name="hook_actions" type="VBoxContainer" parent="HBoxContainer" unique_id=1441205618]
unique_name_in_owner = true
custom_minimum_size = Vector2(80, 0)
layout_mode = 2
size_flags_horizontal = 8
theme_override_constants/separation = 5
[node name="btn_move_up" type="Button" parent="HBoxContainer/hook_actions" unique_id=1909528536]
layout_mode = 2
tooltip_text = "Move hook up in priority"
disabled = true
icon = SubResource("ImageTexture_77fm0")
icon_alignment = 1
[node name="btn_move_down" type="Button" parent="HBoxContainer/hook_actions" unique_id=1385113071]
layout_mode = 2
tooltip_text = "Move hook down in priority"
disabled = true
icon = SubResource("ImageTexture_rewru")
icon_alignment = 1
[node name="btn_add_hook" type="Button" parent="HBoxContainer/hook_actions" unique_id=338115845]
layout_mode = 2
tooltip_text = "Add new hook"
icon = SubResource("ImageTexture_manhx")
icon_alignment = 1
[node name="btn_delete_hook" type="Button" parent="HBoxContainer/hook_actions" unique_id=642037387]
layout_mode = 2
tooltip_text = "Delete selected hook"
disabled = true
icon = SubResource("ImageTexture_4h4u1")
icon_alignment = 1
[node name="select_hook_dlg" type="FileDialog" parent="." unique_id=2043681690]
unique_name_in_owner = true
disable_3d = true
title = "Open a File"
initial_position = 3
current_screen = 0
ok_button_text = "Open"
file_mode = 0
filters = PackedStringArray("*.gd")
[node name="error_msg_popup" type="AcceptDialog" parent="." unique_id=1430197292]
unique_name_in_owner = true
initial_position = 3
current_screen = 0
[node name="row_template" type="Panel" parent="." unique_id=2068077019]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(0, 26)
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="row_template" unique_id=421161803]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Spacer1" type="MarginContainer" parent="row_template/HBoxContainer" unique_id=1388548361]
clip_contents = true
custom_minimum_size = Vector2(12, 0)
layout_mode = 2
size_flags_horizontal = 0
theme_override_constants/margin_left = 3
theme_override_constants/margin_top = 3
theme_override_constants/margin_bottom = 3
[node name="Indicator" type="ColorRect" parent="row_template/HBoxContainer/Spacer1" unique_id=695255812]
custom_minimum_size = Vector2(4, 0)
layout_mode = 2
color = Color(1, 1, 0, 1)
[node name="HookName" type="Label" parent="row_template/HBoxContainer" unique_id=167022167]
layout_mode = 2
size_flags_horizontal = 2
text = "<hook name>"
[node name="SystemBadge" type="PanelContainer" parent="row_template/HBoxContainer" unique_id=1220764160]
layout_mode = 2
size_flags_vertical = 4
theme_override_styles/panel = SubResource("StyleBoxFlat_h5sr5")
[node name="Label" type="Label" parent="row_template/HBoxContainer/SystemBadge" unique_id=1972968522]
layout_mode = 2
theme_override_colors/font_color = Color(0.008202022, 0.008202025, 0.008202025, 1)
theme_override_font_sizes/font_size = 10
text = "SYSTEM"
[node name="Enabled" type="CheckButton" parent="row_template/HBoxContainer" unique_id=365063095]
layout_mode = 2
size_flags_vertical = 4
tooltip_text = "Enable/Disable the Hook"
focus_mode = 0
[connection signal="pressed" from="HBoxContainer/hook_actions/btn_move_up" to="." method="_on_btn_move_up_pressed"]
[connection signal="pressed" from="HBoxContainer/hook_actions/btn_move_down" to="." method="_on_btn_move_down_pressed"]
[connection signal="pressed" from="HBoxContainer/hook_actions/btn_add_hook" to="." method="_on_btn_add_hook_pressed"]
[connection signal="pressed" from="HBoxContainer/hook_actions/btn_delete_hook" to="." method="_on_btn_delete_hook_pressed"]
[connection signal="confirmed" from="select_hook_dlg" to="." method="_on_select_hook_dlg_confirmed"]
[connection signal="file_selected" from="select_hook_dlg" to="." method="_on_select_hook_dlg_file_selected"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bsfwelcotvtg0"
path="res://.godot/imported/logo.png-deda0e4ba02a0b9e4e4a830029a5817f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/gdUnit4/src/ui/settings/logo.png"
dest_files=["res://.godot/imported/logo.png-deda0e4ba02a0b9e4e4a830029a5817f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
@@ -0,0 +1,129 @@
@tool
extends MarginContainer
@onready var _template_editor :CodeEdit = $VBoxContainer/EdiorLayout/Editor
@onready var _tags_editor :CodeEdit = $Tags/MarginContainer/TextEdit
@onready var _title_bar :Panel = $VBoxContainer/sub_category
@onready var _save_button :Button = $VBoxContainer/Panel/HBoxContainer/Save
@onready var _selected_type :OptionButton = $VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer/SelectType
@onready var _show_tags :PopupPanel = $Tags
var gd_key_words :PackedStringArray = ["extends", "class_name", "const", "var", "onready", "func", "void", "pass"]
var gdunit_key_words :PackedStringArray = ["GdUnitTestSuite", "before", "after", "before_test", "after_test"]
var _selected_template :int
func _ready() -> void:
setup_editor_colors()
setup_fonts()
setup_supported_types()
load_template(GdUnitTestSuiteTemplate.TEMPLATE_ID_GD)
setup_tags_help()
func _notification(what :int) -> void:
if what == EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED:
setup_fonts()
func setup_editor_colors() -> void:
if not Engine.is_editor_hint():
return
var background_color := get_editor_color("text_editor/theme/highlighting/background_color", Color(0.1155, 0.132, 0.1595, 1))
var text_color := get_editor_color("text_editor/theme/highlighting/text_color", Color(0.8025, 0.81, 0.8225, 1))
var selection_color := get_editor_color("text_editor/theme/highlighting/selection_color", Color(0.44, 0.73, 0.98, 0.4))
for e :CodeEdit in [_template_editor, _tags_editor]:
var editor :CodeEdit = e
editor.add_theme_color_override("background_color", background_color)
editor.add_theme_color_override("font_color", text_color)
editor.add_theme_color_override("font_readonly_color", text_color)
editor.add_theme_color_override("font_selected_color", selection_color)
setup_highlighter(editor)
func setup_highlighter(editor :CodeEdit) -> void:
var highlighter := CodeHighlighter.new()
editor.set_syntax_highlighter(highlighter)
var number_color := get_editor_color("text_editor/theme/highlighting/number_color", Color(0.63, 1, 0.88, 1))
var symbol_color := get_editor_color("text_editor/theme/highlighting/symbol_color", Color(0.67, 0.79, 1, 1))
var function_color := get_editor_color("text_editor/theme/highlighting/function_color", Color(0.34, 0.7, 1, 1))
var member_variable_color := get_editor_color("text_editor/theme/highlighting/member_variable_color", Color(0.736, 0.88, 1, 1))
var comment_color := get_editor_color("text_editor/theme/highlighting/comment_color", Color(0.8025, 0.81, 0.8225, 0.5))
var keyword_color := get_editor_color("text_editor/theme/highlighting/keyword_color", Color(1, 0.44, 0.52, 1))
var base_type_color := get_editor_color("text_editor/theme/highlighting/base_type_color", Color(0.26, 1, 0.76, 1))
var annotation_color := get_editor_color("text_editor/theme/highlighting/gdscript/annotation_color", Color(1, 0.7, 0.45, 1))
highlighter.clear_color_regions()
highlighter.clear_keyword_colors()
highlighter.add_color_region("#", "", comment_color, true)
highlighter.add_color_region("${", "}", Color.YELLOW)
highlighter.add_color_region("'", "'", Color.YELLOW)
highlighter.add_color_region("\"", "\"", Color.YELLOW)
highlighter.number_color = number_color
highlighter.symbol_color = symbol_color
highlighter.function_color = function_color
highlighter.member_variable_color = member_variable_color
highlighter.add_keyword_color("@", annotation_color)
highlighter.add_keyword_color("warning_ignore", annotation_color)
for word in gd_key_words:
highlighter.add_keyword_color(word, keyword_color)
for word in gdunit_key_words:
highlighter.add_keyword_color(word, base_type_color)
## Using this function to avoid null references to colors on inital Godot installations.
## For more details show https://github.com/MikeSchulze/gdUnit4/issues/533
func get_editor_color(property_name: String, default: Color) -> Color:
var settings := EditorInterface.get_editor_settings()
return settings.get_setting(property_name) if settings.has_setting(property_name) else default
func setup_fonts() -> void:
if _template_editor:
@warning_ignore("return_value_discarded")
GdUnitFonts.init_fonts(_template_editor)
var font_size := GdUnitFonts.init_fonts(_tags_editor)
_title_bar.size.y = font_size + 16
_title_bar.custom_minimum_size.y = font_size + 16
func setup_supported_types() -> void:
_selected_type.clear()
_selected_type.add_item("GD - GDScript", GdUnitTestSuiteTemplate.TEMPLATE_ID_GD)
_selected_type.add_item("C# - CSharpScript", GdUnitTestSuiteTemplate.TEMPLATE_ID_CS)
func setup_tags_help() -> void:
_tags_editor.set_text(GdUnitTestSuiteTemplate.load_tags(_selected_template))
func load_template(template_id :int) -> void:
_selected_template = template_id
_template_editor.set_text(GdUnitTestSuiteTemplate.load_template(template_id))
func _on_Restore_pressed() -> void:
_template_editor.set_text(GdUnitTestSuiteTemplate.default_template(_selected_template))
GdUnitTestSuiteTemplate.reset_to_default(_selected_template)
_save_button.disabled = true
func _on_Save_pressed() -> void:
GdUnitTestSuiteTemplate.save_template(_selected_template, _template_editor.get_text())
_save_button.disabled = true
func _on_Tags_pressed() -> void:
_show_tags.popup_centered_ratio(.5)
func _on_Editor_text_changed() -> void:
_save_button.disabled = false
func _on_SelectType_item_selected(index :int) -> void:
load_template(_selected_type.get_item_id(index))
setup_tags_help()
@@ -0,0 +1 @@
uid://c0ovdps4fpqqj
@@ -0,0 +1,127 @@
[gd_scene format=3 uid="uid://dte0m2endcgtu"]
[ext_resource type="Script" path="res://addons/gdUnit4/src/ui/templates/GdUnitTestSuiteTemplatePanel.gd" id="1"]
[node name="TestSuiteTemplate" type="MarginContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="sub_category" type="Panel" parent="VBoxContainer"]
custom_minimum_size = Vector2(0, 30)
layout_mode = 2
size_flags_horizontal = 3
[node name="Label" type="Label" parent="VBoxContainer/sub_category"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 4.0
offset_right = 4.0
offset_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
text = "Test Suite Template
"
[node name="EdiorLayout" type="VBoxContainer" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="Editor" type="CodeEdit" parent="VBoxContainer/EdiorLayout"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/EdiorLayout/Editor"]
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -31.0
grow_horizontal = 2
grow_vertical = 0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/EdiorLayout/Editor/MarginContainer"]
layout_mode = 2
size_flags_vertical = 8
alignment = 2
[node name="Tags" type="Button" parent="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer"]
layout_mode = 2
tooltip_text = "Shows supported tags."
text = "Supported Tags"
[node name="SelectType" type="OptionButton" parent="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer"]
layout_mode = 2
tooltip_text = "Select the script type specific template."
item_count = 2
selected = 0
popup/item_0/text = "GD - GDScript"
popup/item_0/id = 1000
popup/item_1/text = "C# - CSharpScript"
popup/item_1/id = 2000
[node name="Panel" type="MarginContainer" parent="VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/Panel"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
alignment = 2
[node name="Restore" type="Button" parent="VBoxContainer/Panel/HBoxContainer"]
layout_mode = 2
text = "Restore"
[node name="Save" type="Button" parent="VBoxContainer/Panel/HBoxContainer"]
layout_mode = 2
disabled = true
text = "Save"
[node name="Tags" type="PopupPanel" parent="."]
size = Vector2i(300, 100)
unresizable = false
content_scale_aspect = 4
[node name="MarginContainer" type="MarginContainer" parent="Tags"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 4.0
offset_top = 4.0
offset_right = -856.0
offset_bottom = -552.0
grow_horizontal = 2
grow_vertical = 2
[node name="TextEdit" type="CodeEdit" parent="Tags/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
editable = false
context_menu_enabled = false
shortcut_keys_enabled = false
virtual_keyboard_enabled = false
[connection signal="text_changed" from="VBoxContainer/EdiorLayout/Editor" to="." method="_on_Editor_text_changed"]
[connection signal="pressed" from="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer/Tags" to="." method="_on_Tags_pressed"]
[connection signal="item_selected" from="VBoxContainer/EdiorLayout/Editor/MarginContainer/HBoxContainer/SelectType" to="." method="_on_SelectType_item_selected"]
[connection signal="pressed" from="VBoxContainer/Panel/HBoxContainer/Restore" to="." method="_on_Restore_pressed"]
[connection signal="pressed" from="VBoxContainer/Panel/HBoxContainer/Save" to="." method="_on_Save_pressed"]
@@ -0,0 +1,61 @@
## Provides editor theme colors sourced from [EditorSettings].
## Add this node to the scene tree so it auto-refreshes colors when the
## editor theme changes ([constant EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED]).
@tool
class_name GdUnitEditorColorTheme
extends Node
# Literal value of EditorSettings.NOTIFICATION_EDITOR_SETTINGS_CHANGED.
# The editor classes must not be referenced by name anywhere in this script:
# they do not exist in template builds (exported games, CLI runners), where a
# direct reference fails to PARSE this script and every script depending on
# it - the runtime Engine.is_editor_hint() guard never gets a chance.
const _NOTIFICATION_EDITOR_SETTINGS_CHANGED := 10000
static var text_color := Color.WEB_GRAY
static var folder_color := Color.LIGHT_SKY_BLUE
static var function_definition_color := Color.ANTIQUE_WHITE
static var engine_type_color := Color.ANTIQUE_WHITE
static var value_color := Color.DODGER_BLUE
# test state colors
static var state_initial := Color.LIGHT_GRAY
static var state_success := Color.WEB_GREEN
static var state_warning := Color.DARK_GOLDENROD
static var state_flaky := Color.GREEN_YELLOW
static var state_failure := Color.ORANGE_RED
static var state_error := Color.DARK_RED
static var state_skipped := Color.WEB_GRAY
static var state_orphan := Color.DARK_GOLDENROD
func _ready() -> void:
setup()
func _notification(what: int) -> void:
if what == _NOTIFICATION_EDITOR_SETTINGS_CHANGED:
setup()
static func setup() -> void:
if not Engine.is_editor_hint() or not Engine.has_singleton("EditorInterface"):
return
# Resolved via the singleton registry instead of naming EditorInterface -
# see the parse-time note above; on template builds the defaults apply.
var editor_interface: Object = Engine.get_singleton("EditorInterface")
var settings: Object = editor_interface.call("get_editor_settings")
text_color = settings.call("get_setting", "text_editor/theme/highlighting/text_color")
folder_color = settings.call("get_setting", "text_editor/theme/highlighting/member_variable_color")
function_definition_color = settings.call("get_setting", "text_editor/theme/highlighting/gdscript/function_definition_color")
engine_type_color = settings.call("get_setting", "text_editor/theme/highlighting/engine_type_color")
value_color = settings.call("get_setting", "text_editor/theme/highlighting/function_color")
# init test state colors
state_initial = text_color
state_success = settings.call("get_setting", "editors/animation/onion_layers_future_color")
state_warning = settings.call("get_setting", "text_editor/theme/highlighting/comment_markers/warning_color")
state_flaky = settings.call("get_setting", "text_editor/theme/highlighting/gdscript/node_reference_color")
state_failure = settings.call("get_setting", "text_editor/theme/highlighting/comment_markers/critical_color")
state_error = settings.call("get_setting", "editors/2d/smart_snapping_line_color")
state_orphan = settings.call("get_setting", "text_editor/theme/highlighting/string_placeholder_color")
@@ -0,0 +1 @@
uid://ct34lrbm46ud5