Update GUT to version 9.1.1

This commit is contained in:
Leroy Hopson 2024-01-06 23:27:15 +13:00
parent b18726eac9
commit cea41d6567
No known key found for this signature in database
GPG key ID: D2747312A6DB51AA
65 changed files with 4178 additions and 2995 deletions

View file

@ -1,232 +1,150 @@
[gd_scene load_steps=3 format=2]
[gd_scene load_steps=3 format=3 uid="uid://bsk32dh41b4gs"]
[ext_resource path="res://addons/gut/gui/ShortcutButton.tscn" type="PackedScene" id=1]
[ext_resource path="res://addons/gut/gui/BottomPanelShortcuts.gd" type="Script" id=2]
[ext_resource type="PackedScene" uid="uid://sfb1fw8j6ufu" path="res://addons/gut/gui/ShortcutButton.tscn" id="1"]
[ext_resource type="Script" path="res://addons/gut/gui/BottomPanelShortcuts.gd" id="2"]
[node name="BottomPanelShortcuts" type="Window"]
[node name="BottomPanelShortcuts" type="Popup"]
title = "Shortcuts"
size = Vector2i(500, 350)
visible = true
anchor_right = 0.234
anchor_bottom = 0.328
offset_right = 195.384
offset_bottom = 62.2
custom_minimum_size = Vector2( 435, 305 )
exclusive = true
window_title = "GUT Shortcuts"
resizable = true
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
script = ExtResource("2")
[node name="Layout" type="VBoxContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 5.0
offset_right = -5.0
offset_bottom = 2.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TopPad" type="CenterContainer" parent="Layout"]
offset_right = 425.0
offset_bottom = 5.0
custom_minimum_size = Vector2( 0, 5 )
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="Label2" type="Label" parent="Layout"]
offset_top = 9.0
offset_right = 425.0
offset_bottom = 29.0
custom_minimum_size = Vector2( 0, 20 )
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
text = "Always Active"
align = 1
valign = 1
autowrap = true
[node name="ColorRect" type="ColorRect" parent="Layout/Label2"]
show_behind_parent = true
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0, 0, 0, 0.196078 )
__meta__ = {
"_edit_use_anchors_": false
}
color = Color(0, 0, 0, 0.196078)
[node name="CPanelButton" type="HBoxContainer" parent="Layout"]
offset_top = 33.0
offset_right = 425.0
offset_bottom = 58.0
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CPanelButton"]
offset_right = 138.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 50, 0 )
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Show/Hide GUT Panel"
valign = 1
[node name="ShortcutButton" parent="Layout/CPanelButton" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 142.0
offset_right = 425.0
offset_bottom = 25.0
[node name="ShortcutButton" parent="Layout/CPanelButton" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="GutPanelPad" type="CenterContainer" parent="Layout"]
offset_top = 62.0
offset_right = 425.0
offset_bottom = 67.0
custom_minimum_size = Vector2( 0, 5 )
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="Label" type="Label" parent="Layout"]
offset_top = 71.0
offset_right = 425.0
offset_bottom = 91.0
custom_minimum_size = Vector2( 0, 20 )
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
text = "Only Active When GUT Panel Shown"
align = 1
valign = 1
autowrap = true
[node name="ColorRect2" type="ColorRect" parent="Layout/Label"]
show_behind_parent = true
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0, 0, 0, 0.196078 )
__meta__ = {
"_edit_use_anchors_": false
}
color = Color(0, 0, 0, 0.196078)
[node name="TopPad2" type="CenterContainer" parent="Layout"]
offset_top = 95.0
offset_right = 425.0
offset_bottom = 100.0
custom_minimum_size = Vector2( 0, 5 )
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="CRunAll" type="HBoxContainer" parent="Layout"]
offset_top = 104.0
offset_right = 425.0
offset_bottom = 129.0
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunAll"]
offset_right = 50.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 50, 0 )
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run All"
valign = 1
[node name="ShortcutButton" parent="Layout/CRunAll" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 54.0
offset_right = 425.0
offset_bottom = 25.0
[node name="ShortcutButton" parent="Layout/CRunAll" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CRunCurrentScript" type="HBoxContainer" parent="Layout"]
offset_top = 133.0
offset_right = 425.0
offset_bottom = 158.0
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunCurrentScript"]
offset_right = 115.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 50, 0 )
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Script"
valign = 1
[node name="ShortcutButton" parent="Layout/CRunCurrentScript" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 119.0
offset_right = 425.0
offset_bottom = 25.0
[node name="ShortcutButton" parent="Layout/CRunCurrentScript" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CRunCurrentInner" type="HBoxContainer" parent="Layout"]
offset_top = 162.0
offset_right = 425.0
offset_bottom = 187.0
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunCurrentInner"]
offset_right = 150.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 50, 0 )
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Inner Class"
valign = 1
[node name="ShortcutButton" parent="Layout/CRunCurrentInner" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 154.0
offset_right = 425.0
offset_bottom = 25.0
[node name="ShortcutButton" parent="Layout/CRunCurrentInner" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CRunCurrentTest" type="HBoxContainer" parent="Layout"]
offset_top = 191.0
offset_right = 425.0
offset_bottom = 216.0
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunCurrentTest"]
offset_right = 106.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 50, 0 )
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Test"
valign = 1
[node name="ShortcutButton" parent="Layout/CRunCurrentTest" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 110.0
offset_right = 425.0
offset_bottom = 25.0
[node name="ShortcutButton" parent="Layout/CRunCurrentTest" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CenterContainer2" type="CenterContainer" parent="Layout"]
offset_top = 220.0
offset_right = 425.0
offset_bottom = 241.0
custom_minimum_size = Vector2( 0, 5 )
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ShiftDisclaimer" type="Label" parent="Layout"]
offset_top = 245.0
offset_right = 425.0
offset_bottom = 259.0
layout_mode = 2
text = "\"Shift\" cannot be the only modifier for a shortcut."
align = 2
autowrap = true
[node name="HBoxContainer" type="HBoxContainer" parent="Layout"]
offset_top = 263.0
offset_right = 425.0
offset_bottom = 293.0
layout_mode = 2
[node name="CenterContainer" type="CenterContainer" parent="Layout/HBoxContainer"]
offset_right = 361.0
offset_bottom = 30.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Hide" type="Button" parent="Layout/HBoxContainer"]
offset_left = 365.0
offset_right = 425.0
offset_bottom = 30.0
custom_minimum_size = Vector2( 60, 30 )
custom_minimum_size = Vector2(60, 30)
layout_mode = 2
text = "Close"
[node name="BottomPad" type="CenterContainer" parent="Layout"]
offset_top = 297.0
offset_right = 425.0
offset_bottom = 307.0
custom_minimum_size = Vector2( 0, 10 )
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
size_flags_horizontal = 3
[connection signal="pressed" from="Layout/HBoxContainer/Hide" to="." method="_on_Hide_pressed"]

View file

@ -1,28 +1,29 @@
[gd_scene load_steps=10 format=3 uid="uid://b3bostcslstem"]
[ext_resource type="Script" path="res://addons/gut/gui/GutBottomPanel.gd" id="1"]
[ext_resource type="PackedScene" path="res://addons/gut/gui/BottomPanelShortcuts.tscn" id="2"]
[ext_resource type="PackedScene" path="res://addons/gut/gui/RunAtCursor.tscn" id="3"]
[ext_resource type="Texture2D" path="res://addons/gut/gui/play.png" id="4"]
[ext_resource type="PackedScene" path="res://addons/gut/gui/RunResults.tscn" id="5"]
[ext_resource type="PackedScene" path="res://addons/gut/gui/OutputText.tscn" id="6"]
[ext_resource type="PackedScene" uid="uid://bsk32dh41b4gs" path="res://addons/gut/gui/BottomPanelShortcuts.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://0yunjxtaa8iw" path="res://addons/gut/gui/RunAtCursor.tscn" id="3"]
[ext_resource type="Texture2D" uid="uid://cr6tvdv0ve6cv" path="res://addons/gut/gui/play.png" id="4"]
[ext_resource type="PackedScene" uid="uid://4gyyn12um08h" path="res://addons/gut/gui/RunResults.tscn" id="5"]
[ext_resource type="PackedScene" uid="uid://bqmo4dj64c7yl" path="res://addons/gut/gui/OutputText.tscn" id="6"]
[sub_resource type="Shortcut" id="9"]
[sub_resource type="Image" id="Image_r56ab"]
[sub_resource type="Image" id="Image_abbh7"]
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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": "LumAlpha8",
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id="2"]
image = SubResource("Image_r56ab")
[sub_resource type="ImageTexture" id="ImageTexture_x655i"]
image = SubResource("Image_abbh7")
[node name="GutBottomPanel" type="Control"]
custom_minimum_size = Vector2(250, 250)
layout_mode = 3
anchor_left = -0.0025866
anchor_top = -0.00176575
anchor_right = 0.997413
@ -34,297 +35,206 @@ offset_bottom = 1.05945
script = ExtResource("1")
[node name="layout" type="VBoxContainer" parent="."]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
[node name="ControlBar" type="HBoxContainer" parent="layout"]
offset_right = 1023.0
offset_bottom = 31.0
layout_mode = 2
[node name="RunAll" type="Button" parent="layout/ControlBar"]
offset_right = 85.0
offset_bottom = 31.0
layout_mode = 2
size_flags_vertical = 11
hint_tooltip = "Run all test scripts in the suite."
shortcut = SubResource("9")
text = "Run All"
icon = ExtResource("4")
[node name="Label" type="Label" parent="layout/ControlBar"]
offset_left = 89.0
offset_top = 2.0
offset_right = 162.0
offset_bottom = 28.0
hint_tooltip = "When a test script is edited, buttons are displayed to
run the opened script or an Inner-Test-Class or a
single test. The buttons change based on the location
of the cursor in the file.
These buttons will remain active when editing other
items so that you can run tests without having to switch
back to the test script.
You can assign keyboard shortcuts for these buttons
using the \"shortcuts\" button in the GUT panel."
layout_mode = 2
mouse_filter = 1
text = "Current: "
[node name="RunAtCursor" parent="layout/ControlBar" instance=ExtResource("3")]
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 166.0
offset_right = 532.0
offset_bottom = 31.0
layout_mode = 2
[node name="CenterContainer2" type="CenterContainer" parent="layout/ControlBar"]
offset_left = 536.0
offset_right = 903.0
offset_bottom = 31.0
layout_mode = 2
size_flags_horizontal = 3
[node name="Sep1" type="ColorRect" parent="layout/ControlBar"]
offset_left = 907.0
offset_right = 907.0
offset_bottom = 31.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="RunResultsBtn" type="Button" parent="layout/ControlBar"]
offset_left = 911.0
offset_right = 935.0
offset_bottom = 31.0
hint_tooltip = "Show/Hide Results Tree Panel."
layout_mode = 2
toggle_mode = true
icon = SubResource("2")
button_pressed = true
icon = SubResource("ImageTexture_x655i")
[node name="OutputBtn" type="Button" parent="layout/ControlBar"]
offset_left = 939.0
offset_right = 963.0
offset_bottom = 31.0
hint_tooltip = "Show/Hide Output Panel."
layout_mode = 2
toggle_mode = true
icon = SubResource("2")
icon = SubResource("ImageTexture_x655i")
[node name="Settings" type="Button" parent="layout/ControlBar"]
offset_left = 967.0
offset_right = 991.0
offset_bottom = 31.0
hint_tooltip = "Show/Hide Settings Panel."
layout_mode = 2
toggle_mode = true
icon = SubResource("2")
button_pressed = true
icon = SubResource("ImageTexture_x655i")
[node name="Sep2" type="ColorRect" parent="layout/ControlBar"]
offset_left = 995.0
offset_right = 995.0
offset_bottom = 31.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="Shortcuts" type="Button" parent="layout/ControlBar"]
offset_left = 999.0
offset_right = 1023.0
offset_bottom = 31.0
layout_mode = 2
size_flags_vertical = 11
hint_tooltip = "Set shortcuts for GUT buttons. Shortcuts do not work when the GUT panel is not visible."
icon = SubResource("2")
icon = SubResource("ImageTexture_x655i")
[node name="RSplit" type="HSplitContainer" parent="layout"]
offset_top = 35.0
offset_right = 1023.0
offset_bottom = 599.0
size_flags_horizontal = 3
size_flags_vertical = 3
collapsed = true
[node name="sc" type="ScrollContainer" parent="layout/RSplit"]
visible = false
offset_left = 593.0
offset_right = 1093.0
offset_bottom = 555.0
size_flags_vertical = 3
[node name="Settings" type="VBoxContainer" parent="layout/RSplit/sc"]
offset_right = 500.0
offset_bottom = 555.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="CResults" type="VBoxContainer" parent="layout/RSplit"]
offset_right = 1023.0
offset_bottom = 564.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ControlBar" type="HBoxContainer" parent="layout/RSplit/CResults"]
offset_right = 1023.0
layout_mode = 2
[node name="Sep2" type="ColorRect" parent="layout/RSplit/CResults/ControlBar"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="Light3D" type="Control" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_right = 30.0
offset_bottom = 35.0
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
[node name="Passing" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_left = 34.0
offset_right = 107.0
offset_bottom = 35.0
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Passing"]
offset_right = 2.0
offset_bottom = 35.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Passing"]
offset_left = 6.0
offset_top = 10.0
offset_right = 54.0
offset_bottom = 24.0
layout_mode = 2
text = "Passing"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Passing"]
offset_left = 58.0
offset_top = 10.0
offset_right = 73.0
offset_bottom = 24.0
layout_mode = 2
text = "---"
[node name="Failing" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_left = 34.0
offset_right = 100.0
offset_bottom = 35.0
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Failing"]
offset_right = 2.0
offset_bottom = 35.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Failing"]
offset_left = 6.0
offset_top = 10.0
offset_right = 47.0
offset_bottom = 24.0
layout_mode = 2
text = "Failing"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Failing"]
offset_left = 51.0
offset_top = 10.0
offset_right = 66.0
offset_bottom = 24.0
layout_mode = 2
text = "---"
[node name="Pending" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_left = 34.0
offset_right = 110.0
offset_bottom = 35.0
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Pending"]
offset_right = 2.0
offset_bottom = 35.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Pending"]
offset_left = 6.0
offset_top = 10.0
offset_right = 57.0
offset_bottom = 24.0
layout_mode = 2
text = "Pending"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Pending"]
offset_left = 61.0
offset_top = 10.0
offset_right = 76.0
offset_bottom = 24.0
layout_mode = 2
text = "---"
[node name="Orphans" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_left = 34.0
offset_right = 110.0
offset_bottom = 35.0
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Orphans"]
offset_right = 2.0
offset_bottom = 35.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Orphans"]
offset_left = 6.0
offset_top = 10.0
offset_right = 57.0
offset_bottom = 24.0
layout_mode = 2
text = "Orphans"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Orphans"]
offset_left = 61.0
offset_top = 10.0
offset_right = 76.0
offset_bottom = 24.0
layout_mode = 2
text = "---"
[node name="Errors" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_left = 34.0
offset_right = 96.0
offset_bottom = 35.0
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Errors"]
offset_right = 2.0
offset_bottom = 35.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Errors"]
offset_left = 6.0
offset_top = 10.0
offset_right = 43.0
offset_bottom = 24.0
hint_tooltip = "The number of GUT errors generated. This does not include engine errors."
layout_mode = 2
text = "Errors"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Errors"]
offset_left = 47.0
offset_top = 10.0
offset_right = 62.0
offset_bottom = 24.0
layout_mode = 2
text = "---"
[node name="Warnings" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
offset_left = 34.0
offset_right = 118.0
offset_bottom = 35.0
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Warnings"]
offset_right = 2.0
offset_bottom = 35.0
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Warnings"]
offset_left = 6.0
offset_top = 10.0
offset_right = 65.0
offset_bottom = 24.0
layout_mode = 2
text = "Warnings"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Warnings"]
offset_left = 69.0
offset_top = 10.0
offset_right = 84.0
offset_bottom = 24.0
layout_mode = 2
text = "---"
[node name="CenterContainer" type="CenterContainer" parent="layout/RSplit/CResults/ControlBar"]
offset_right = 1023.0
layout_mode = 2
size_flags_horizontal = 3
[node name="TabBar" type="HSplitContainer" parent="layout/RSplit/CResults"]
offset_top = 4.0
offset_right = 1023.0
offset_bottom = 564.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="RunResults" parent="layout/RSplit/CResults/TabBar" instance=ExtResource("5")]
offset_right = 505.0
offset_bottom = 560.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="OutputText" parent="layout/RSplit/CResults/TabBar" instance=ExtResource("6")]
offset_left = 517.0
offset_right = 1023.0
offset_bottom = 560.0
visible = false
layout_mode = 2
[node name="sc" type="ScrollContainer" parent="layout/RSplit"]
custom_minimum_size = Vector2(500, 2.08165e-12)
layout_mode = 2
size_flags_vertical = 3
[node name="Settings" type="VBoxContainer" parent="layout/RSplit/sc"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="BottomPanelShortcuts" parent="." instance=ExtResource("2")]
visible = false

View file

@ -0,0 +1,322 @@
@tool
extends Control
const RUNNER_JSON_PATH = "res://.gut_editor_config.json"
var GutConfig = load("res://addons/gut/gut_config.gd")
var GutRunnerScene = load("res://addons/gut/gui/GutRunner.tscn")
var GutConfigGui = load("res://addons/gut/gui/gut_config_gui.gd")
var _config = GutConfig.new()
var _config_gui = null
var _gut_runner = GutRunnerScene.instantiate()
var _has_connected = false
var _tree_root: TreeItem = null
var _script_icon = load("res://addons/gut/images/Script.svg")
var _folder_icon = load("res://addons/gut/images/Folder.svg")
var _tree_scripts = {}
var _tree_directories = {}
const TREE_SCRIPT = "Script"
const TREE_DIR = "Directory"
@onready var _ctrls = {
run_tests_button = $VBox/Buttons/RunTests,
run_selected = $VBox/Buttons/RunSelected,
test_tree = $VBox/Tabs/Tests,
settings_vbox = $VBox/Tabs/SettingsScroll/Settings,
tabs = $VBox/Tabs,
bg = $Bg
}
@export var bg_color: Color = Color(.36, .36, .36):
get:
return bg_color
set(val):
bg_color = val
if is_inside_tree():
$Bg.color = bg_color
func _ready():
if Engine.is_editor_hint():
return
$Bg.color = bg_color
_ctrls.tabs.set_tab_title(0, "Tests")
_ctrls.tabs.set_tab_title(1, "Settings")
_config_gui = GutConfigGui.new(_ctrls.settings_vbox)
_ctrls.test_tree.hide_root = true
# Stop tests from kicking off when the runner is "ready" and
# prevents it from writing results file that is used by
# the panel.
_gut_runner.set_cmdln_mode(true)
add_child(_gut_runner)
# Becuase of the janky _utils psuedo-global script, we cannot
# do all this in _ready. If we do this in _ready, it generates
# a bunch of errors. The errors don't matter, but it looks bad.
call_deferred("_post_ready")
func _draw():
if Engine.is_editor_hint():
return
var gut = _gut_runner.get_gut()
if !gut.is_running():
var r = Rect2(Vector2(0, 0), get_rect().size)
draw_rect(r, Color.BLACK, false, 2)
func _post_ready():
var gut = _gut_runner.get_gut()
gut.start_run.connect(_on_gut_run_started)
gut.end_run.connect(_on_gut_run_ended)
_refresh_tree_and_settings()
func _set_meta_for_script_tree_item(item, script, test = null):
var meta = {
type = TREE_SCRIPT, script = script.path, inner_class = script.inner_class_name, test = ""
}
if test != null:
meta.test = test.name
item.set_metadata(0, meta)
func _set_meta_for_directory_tree_item(item, path, temp_item):
var meta = {type = TREE_DIR, path = path, temp_item = temp_item}
item.set_metadata(0, meta)
func _get_script_tree_item(script, parent_item):
if !_tree_scripts.has(script.path):
var item = _ctrls.test_tree.create_item(parent_item)
item.set_text(0, script.path.get_file())
item.set_icon(0, _script_icon)
_tree_scripts[script.path] = item
_set_meta_for_script_tree_item(item, script)
return _tree_scripts[script.path]
func _get_directory_tree_item(path):
var parent = _tree_root
if !_tree_directories.has(path):
var item: TreeItem = null
if parent != _tree_root:
item = parent.create_child(0)
else:
item = parent.create_child()
_tree_directories[path] = item
item.collapsed = false
item.set_text(0, path)
item.set_icon(0, _folder_icon)
item.set_icon_modulate(0, Color.ROYAL_BLUE)
# temp_item is used in calls with move_before since you must use
# move_before or move_after to reparent tree items. This ensures that
# there is an item on all directories. These are deleted later.
var temp_item = item.create_child()
temp_item.set_text(0, "<temp>")
_set_meta_for_directory_tree_item(item, path, temp_item)
return _tree_directories[path]
func _find_dir_item_to_move_before(path):
var max_matching_len = 0
var best_parent = null
# Go through all the directory items finding the one that has the longest
# path that contains our path.
for key in _tree_directories.keys():
if path != key and path.begins_with(key) and key.length() > max_matching_len:
max_matching_len = key.length()
best_parent = _tree_directories[key]
var to_return = null
if best_parent != null:
to_return = best_parent.get_metadata(0).temp_item
return to_return
func _reorder_dir_items():
var the_keys = _tree_directories.keys()
the_keys.sort()
for key in _tree_directories.keys():
var to_move = _tree_directories[key]
to_move.collapsed = false
var move_before = _find_dir_item_to_move_before(key)
if move_before != null:
to_move.move_before(move_before)
var new_text = key.substr(move_before.get_parent().get_metadata(0).path.length())
to_move.set_text(0, new_text)
func _remove_dir_temp_items():
for key in _tree_directories.keys():
var item = _tree_directories[key].get_metadata(0).temp_item
_tree_directories[key].remove_child(item)
func _add_dir_and_script_tree_items():
var tree: Tree = _ctrls.test_tree
tree.clear()
_tree_root = _ctrls.test_tree.create_item()
var scripts = _gut_runner.get_gut().get_test_collector().scripts
for script in scripts:
var dir_item = _get_directory_tree_item(script.path.get_base_dir())
var item = _get_script_tree_item(script, dir_item)
if script.inner_class_name != "":
var inner_item = tree.create_item(item)
inner_item.set_text(0, script.inner_class_name)
_set_meta_for_script_tree_item(inner_item, script)
item = inner_item
for test in script.tests:
var test_item = tree.create_item(item)
test_item.set_text(0, test.name)
_set_meta_for_script_tree_item(test_item, script, test)
func _populate_tree():
_add_dir_and_script_tree_items()
_tree_root.set_collapsed_recursive(true)
_tree_root.set_collapsed(false)
_reorder_dir_items()
_remove_dir_temp_items()
func _refresh_tree_and_settings():
if _config.options.has("panel_options"):
_config_gui.set_options(_config.options)
_config.apply_options(_gut_runner.get_gut())
_gut_runner.set_gut_config(_config)
_populate_tree()
# ---------------------------
# Events
# ---------------------------
func _on_gut_run_started():
_ctrls.run_tests_button.disabled = true
_ctrls.run_selected.visible = false
_ctrls.tabs.visible = false
_ctrls.bg.visible = false
_ctrls.run_tests_button.text = "Running"
queue_redraw()
func _on_gut_run_ended():
_ctrls.run_tests_button.disabled = false
_ctrls.run_selected.visible = true
_ctrls.tabs.visible = true
_ctrls.bg.visible = true
_ctrls.run_tests_button.text = "Run All"
queue_redraw()
func _on_run_tests_pressed():
run_all()
func _on_run_selected_pressed():
run_selected()
func _on_tests_item_activated():
run_selected()
# ---------------------------
# Public
# ---------------------------
func get_gut():
return _gut_runner.get_gut()
func get_config():
return _config
func run_all():
_config.options.selected = ""
_config.options.inner_class_name = ""
_config.options.unit_test_name = ""
run_tests()
func run_tests(options = null):
if options == null:
_config.options = _config_gui.get_options(_config.options)
else:
_config.options = options
_gut_runner.get_gut().get_test_collector().clear()
_gut_runner.set_gut_config(_config)
_gut_runner.run_tests()
func run_selected():
var sel_item = _ctrls.test_tree.get_selected()
if sel_item == null:
return
var options = _config_gui.get_options(_config.options)
var meta = sel_item.get_metadata(0)
if meta.type == TREE_SCRIPT:
options.selected = meta.script.get_file()
options.inner_class_name = meta.inner_class
options.unit_test_name = meta.test
elif meta.type == TREE_DIR:
options.dirs = [meta.path]
options.include_subdirectories = true
options.selected = ""
options.inner_class_name = ""
options.unit_test_name = ""
run_tests(options)
func load_config_file(path):
_config.load_panel_options(path)
_config.options.selected = ""
_config.options.inner_class_name = ""
_config.options.unit_test_name = ""
# ##############################################################################
# The MIT License (MIT)
# =====================
#
# Copyright (c) 2023 Tom "Butch" Wesley
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ##############################################################################

View file

@ -0,0 +1,63 @@
[gd_scene load_steps=2 format=3 uid="uid://4jb53yqktyfg"]
[ext_resource type="Script" path="res://addons/gut/gui/GutControl.gd" id="1_eprql"]
[node name="GutControl" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 295.0
offset_bottom = 419.0
script = ExtResource("1_eprql")
[node name="Bg" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.36, 0.36, 0.36, 1)
[node name="VBox" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Tabs" type="TabContainer" parent="VBox"]
layout_mode = 2
size_flags_vertical = 3
[node name="Tests" type="Tree" parent="VBox/Tabs"]
layout_mode = 2
size_flags_vertical = 3
hide_root = true
[node name="SettingsScroll" type="ScrollContainer" parent="VBox/Tabs"]
visible = false
layout_mode = 2
size_flags_vertical = 3
[node name="Settings" type="VBoxContainer" parent="VBox/Tabs/SettingsScroll"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Buttons" type="HBoxContainer" parent="VBox"]
layout_mode = 2
[node name="RunTests" type="Button" parent="VBox/Buttons"]
layout_mode = 2
size_flags_horizontal = 3
text = "Run All"
[node name="RunSelected" type="Button" parent="VBox/Buttons"]
layout_mode = 2
size_flags_horizontal = 3
text = "Run Selected"
[connection signal="item_activated" from="VBox/Tabs/Tests" to="." method="_on_tests_item_activated"]
[connection signal="pressed" from="VBox/Buttons/RunTests" to="." method="_on_run_tests_pressed"]
[connection signal="pressed" from="VBox/Buttons/RunSelected" to="." method="_on_run_selected_pressed"]

View file

@ -1,3 +1,18 @@
# ##############################################################################
# This class joins together GUT, GUT Gui, GutConfig and is the main way to
# run a test suite.
#
# This creates its own instance of gut.gd that it manages.
# Use set_gut_config to set the gut_config.gd that should be used to configure
# gut.
# This will create a GUI and wire it up and apply gut_config.gd options.
#
# Running tests:
# By default, this will run tests once this control has been added to the tree.
# You can override this by setting auto_run_tests to false prior to adding
# this to the tree. To run tests manually, call run_tests.
#
# ##############################################################################
extends Node2D
var Gut = load("res://addons/gut/gut.gd")
@ -19,6 +34,7 @@ var _cmdln_mode = false
@onready var _gut_layer = $GutLayer
@onready var _gui = $GutLayer/GutScene
# When true, tests will be kicked off in _ready.
var auto_run_tests = true
@ -34,29 +50,9 @@ func _ready():
call_deferred("run_tests")
func run_tests(show_gui = true):
func _lazy_make_gut():
if _gut == null:
get_gut()
_setup_gui(show_gui)
_gut.add_children_to = self
if _gut_config.options.gut_on_top:
_gut_layer.add_child(_gut)
else:
add_child(_gut)
if !_cmdln_mode:
_gut.end_run.connect(
_on_tests_finished.bind(
_gut_config.options.should_exit, _gut_config.options.should_exit_on_success
)
)
_gut_config.config_gut(_gut)
var run_rest_of_scripts = _gut_config.options.unit_test_name == ""
_gut.test_scripts(run_rest_of_scripts)
_gut = Gut.new()
func _setup_gui(show_gui):
@ -76,20 +72,18 @@ func _setup_gui(show_gui):
if opts.background_color != null and opts.background_color.is_valid_html_color():
_gui.set_background_color(Color(opts.background_color))
#_tester.set_modulate(Color(1.0, 1.0, 1.0, min(1.0, float(opts.opacity) / 100)))
_gui.set_opacity(min(1.0, float(opts.opacity) / 100))
# if(opts.should_maximize):
# _tester.maximize()
#if(opts.compact_mode):
# _tester.get_gui().compact_mode(true)
_gui.use_compact_mode(opts.compact_mode)
func _write_results():
var content = _gui.get_textbox().text #_gut.logger.get_gui_bbcode()
var content = _gui.get_textbox().get_parsed_text() #_gut.logger.get_gui_bbcode()
var f = FileAccess.open(RESULT_FILE, FileAccess.WRITE)
if f != null:
f.store_string(content)
f.close()
f = null # closes file
else:
push_error("Could not save bbcode, result = ", FileAccess.get_open_error())
@ -112,9 +106,33 @@ func _on_tests_finished(should_exit, should_exit_on_success):
get_tree().quit()
func run_tests(show_gui = true):
_lazy_make_gut()
_setup_gui(show_gui)
_gut.add_children_to = self
if _gut.get_parent() == null:
if _gut_config.options.gut_on_top:
_gut_layer.add_child(_gut)
else:
add_child(_gut)
if !_cmdln_mode:
_gut.end_run.connect(
_on_tests_finished.bind(
_gut_config.options.should_exit, _gut_config.options.should_exit_on_success
)
)
_gut_config.apply_options(_gut)
var run_rest_of_scripts = _gut_config.options.unit_test_name == ""
_gut.test_scripts(run_rest_of_scripts)
func get_gut():
if _gut == null:
_gut = Gut.new()
_lazy_make_gut()
return _gut
@ -124,3 +142,29 @@ func set_gut_config(which):
func set_cmdln_mode(is_it):
_cmdln_mode = is_it
# ##############################################################################
# The MIT License (MIT)
# =====================
#
# Copyright (c) 2023 Tom "Butch" Wesley
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ##############################################################################

File diff suppressed because one or more lines are too long

161
addons/gut/gui/MinGui.tscn Normal file
View file

@ -0,0 +1,161 @@
[gd_scene load_steps=5 format=3 uid="uid://cnqqdfsn80ise"]
[ext_resource type="Theme" uid="uid://cstkhwkpajvqu" path="res://addons/gut/gui/GutSceneTheme.tres" id="1_farmq"]
[ext_resource type="FontFile" uid="uid://bnh0lslf4yh87" path="res://addons/gut/fonts/CourierPrime-Regular.ttf" id="2_a2e2l"]
[ext_resource type="Script" path="res://addons/gut/gui/gut_gui.gd" id="2_eokrf"]
[ext_resource type="PackedScene" uid="uid://bvrqqgjpyouse" path="res://addons/gut/gui/ResizeHandle.tscn" id="4_xrhva"]
[node name="Min" type="Panel"]
clip_contents = true
custom_minimum_size = Vector2(280, 145)
offset_right = 280.0
offset_bottom = 145.0
theme = ExtResource("1_farmq")
script = ExtResource("2_eokrf")
[node name="MainBox" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
metadata/_edit_layout_mode = 1
[node name="TitleBar" type="Panel" parent="MainBox"]
custom_minimum_size = Vector2(0, 25)
layout_mode = 2
[node name="TitleBox" type="HBoxContainer" parent="MainBox/TitleBar"]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = 2.0
offset_bottom = 3.0
grow_horizontal = 2
grow_vertical = 2
metadata/_edit_layout_mode = 1
[node name="Spacer1" type="CenterContainer" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Title" type="Label" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
text = "Title"
[node name="Spacer2" type="CenterContainer" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="TimeLabel" type="Label" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
text = "0.000s"
[node name="Body" type="HBoxContainer" parent="MainBox"]
layout_mode = 2
size_flags_vertical = 3
[node name="LeftMargin" type="CenterContainer" parent="MainBox/Body"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="BodyRows" type="VBoxContainer" parent="MainBox/Body"]
layout_mode = 2
size_flags_horizontal = 3
[node name="ProgressBars" type="HBoxContainer" parent="MainBox/Body/BodyRows"]
layout_mode = 2
size_flags_horizontal = 3
[node name="HBoxContainer" type="HBoxContainer" parent="MainBox/Body/BodyRows/ProgressBars"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Label" type="Label" parent="MainBox/Body/BodyRows/ProgressBars/HBoxContainer"]
layout_mode = 2
text = "T:"
[node name="ProgressTest" type="ProgressBar" parent="MainBox/Body/BodyRows/ProgressBars/HBoxContainer"]
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
size_flags_horizontal = 3
value = 25.0
[node name="HBoxContainer2" type="HBoxContainer" parent="MainBox/Body/BodyRows/ProgressBars"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Label" type="Label" parent="MainBox/Body/BodyRows/ProgressBars/HBoxContainer2"]
layout_mode = 2
text = "S:"
[node name="ProgressScript" type="ProgressBar" parent="MainBox/Body/BodyRows/ProgressBars/HBoxContainer2"]
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
size_flags_horizontal = 3
value = 75.0
[node name="PathDisplay" type="VBoxContainer" parent="MainBox/Body/BodyRows"]
clip_contents = true
layout_mode = 2
size_flags_vertical = 3
[node name="Path" type="Label" parent="MainBox/Body/BodyRows/PathDisplay"]
layout_mode = 2
theme_override_fonts/font = ExtResource("2_a2e2l")
theme_override_font_sizes/font_size = 14
text = "res://test/integration/whatever"
clip_text = true
text_overrun_behavior = 3
[node name="HBoxContainer" type="HBoxContainer" parent="MainBox/Body/BodyRows/PathDisplay"]
clip_contents = true
layout_mode = 2
[node name="S3" type="CenterContainer" parent="MainBox/Body/BodyRows/PathDisplay/HBoxContainer"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="File" type="Label" parent="MainBox/Body/BodyRows/PathDisplay/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = ExtResource("2_a2e2l")
theme_override_font_sizes/font_size = 14
text = "test_this_thing.gd"
text_overrun_behavior = 3
[node name="Footer" type="HBoxContainer" parent="MainBox/Body/BodyRows"]
layout_mode = 2
[node name="HandleLeft" parent="MainBox/Body/BodyRows/Footer" node_paths=PackedStringArray("resize_control") instance=ExtResource("4_xrhva")]
layout_mode = 2
orientation = 0
resize_control = NodePath("../../../../..")
vertical_resize = false
[node name="SwitchModes" type="Button" parent="MainBox/Body/BodyRows/Footer"]
layout_mode = 2
text = "Expand"
[node name="CenterContainer" type="CenterContainer" parent="MainBox/Body/BodyRows/Footer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Continue" type="Button" parent="MainBox/Body/BodyRows/Footer"]
layout_mode = 2
text = "Continue
"
[node name="HandleRight" parent="MainBox/Body/BodyRows/Footer" node_paths=PackedStringArray("resize_control") instance=ExtResource("4_xrhva")]
layout_mode = 2
resize_control = NodePath("../../../../..")
vertical_resize = false
[node name="RightMargin" type="CenterContainer" parent="MainBox/Body"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="CenterContainer" type="CenterContainer" parent="MainBox"]
custom_minimum_size = Vector2(2.08165e-12, 2)
layout_mode = 2

View file

@ -0,0 +1,213 @@
[gd_scene load_steps=5 format=3 uid="uid://duxblir3vu8x7"]
[ext_resource type="Theme" uid="uid://cstkhwkpajvqu" path="res://addons/gut/gui/GutSceneTheme.tres" id="1_5hlsm"]
[ext_resource type="Script" path="res://addons/gut/gui/gut_gui.gd" id="2_fue6q"]
[ext_resource type="FontFile" uid="uid://bnh0lslf4yh87" path="res://addons/gut/fonts/CourierPrime-Regular.ttf" id="2_u5uc1"]
[ext_resource type="PackedScene" uid="uid://bvrqqgjpyouse" path="res://addons/gut/gui/ResizeHandle.tscn" id="4_2r8a8"]
[node name="Large" type="Panel"]
custom_minimum_size = Vector2(500, 150)
offset_right = 632.0
offset_bottom = 260.0
theme = ExtResource("1_5hlsm")
script = ExtResource("2_fue6q")
[node name="MainBox" type="VBoxContainer" parent="."]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
metadata/_edit_layout_mode = 1
[node name="TitleBar" type="Panel" parent="MainBox"]
custom_minimum_size = Vector2(0, 25)
layout_mode = 2
[node name="TitleBox" type="HBoxContainer" parent="MainBox/TitleBar"]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = 2.0
offset_bottom = 3.0
grow_horizontal = 2
grow_vertical = 2
metadata/_edit_layout_mode = 1
[node name="Spacer1" type="CenterContainer" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Title" type="Label" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
text = "Title"
[node name="Spacer2" type="CenterContainer" parent="MainBox/TitleBar/TitleBox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="TimeLabel" type="Label" parent="MainBox/TitleBar/TitleBox"]
custom_minimum_size = Vector2(90, 0)
layout_mode = 2
text = "999.999s"
[node name="HBoxContainer" type="HBoxContainer" parent="MainBox"]
layout_mode = 2
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="MainBox/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="OutputBG" type="ColorRect" parent="MainBox/HBoxContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
color = Color(0.0745098, 0.0705882, 0.0784314, 1)
metadata/_edit_layout_mode = 1
[node name="HBoxContainer" type="HBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/OutputBG"]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="S2" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/OutputBG/HBoxContainer"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="TestOutput" type="RichTextLabel" parent="MainBox/HBoxContainer/VBoxContainer/OutputBG/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
focus_mode = 2
bbcode_enabled = true
scroll_following = true
autowrap_mode = 0
selection_enabled = true
[node name="S1" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/OutputBG/HBoxContainer"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="ControlBox" type="HBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer"]
layout_mode = 2
[node name="S1" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="ProgressBars" type="VBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
custom_minimum_size = Vector2(2.08165e-12, 2.08165e-12)
layout_mode = 2
[node name="TestBox" type="HBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/ProgressBars"]
layout_mode = 2
[node name="Label" type="Label" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/ProgressBars/TestBox"]
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
size_flags_horizontal = 3
text = "Tests"
[node name="ProgressTest" type="ProgressBar" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/ProgressBars/TestBox"]
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
value = 25.0
[node name="ScriptBox" type="HBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/ProgressBars"]
layout_mode = 2
[node name="Label" type="Label" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/ProgressBars/ScriptBox"]
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
size_flags_horizontal = 3
text = "Scripts"
[node name="ProgressScript" type="ProgressBar" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/ProgressBars/ScriptBox"]
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
value = 75.0
[node name="PathDisplay" type="VBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Path" type="Label" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/PathDisplay"]
layout_mode = 2
size_flags_vertical = 6
theme_override_fonts/font = ExtResource("2_u5uc1")
theme_override_font_sizes/font_size = 14
text = "res://test/integration/whatever"
text_overrun_behavior = 3
[node name="HBoxContainer" type="HBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/PathDisplay"]
layout_mode = 2
size_flags_vertical = 3
[node name="S3" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/PathDisplay/HBoxContainer"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="File" type="Label" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/PathDisplay/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = ExtResource("2_u5uc1")
theme_override_font_sizes/font_size = 14
text = "test_this_thing.gd"
text_overrun_behavior = 3
[node name="Spacer1" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
visible = false
layout_mode = 2
size_flags_horizontal = 10
[node name="Continue" type="Button" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
layout_mode = 2
size_flags_vertical = 4
text = "Continue
"
[node name="S3" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="BottomPad" type="CenterContainer" parent="MainBox"]
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="Footer" type="HBoxContainer" parent="MainBox"]
layout_mode = 2
[node name="SidePad1" type="CenterContainer" parent="MainBox/Footer"]
custom_minimum_size = Vector2(2, 2.08165e-12)
layout_mode = 2
[node name="ResizeHandle3" parent="MainBox/Footer" node_paths=PackedStringArray("resize_control") instance=ExtResource("4_2r8a8")]
custom_minimum_size = Vector2(25, 25)
layout_mode = 2
orientation = 0
resize_control = NodePath("../../..")
[node name="SwitchModes" type="Button" parent="MainBox/Footer"]
layout_mode = 2
text = "Compact
"
[node name="CenterContainer" type="CenterContainer" parent="MainBox/Footer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="ResizeHandle2" parent="MainBox/Footer" node_paths=PackedStringArray("resize_control") instance=ExtResource("4_2r8a8")]
custom_minimum_size = Vector2(25, 25)
layout_mode = 2
resize_control = NodePath("../../..")
[node name="SidePad2" type="CenterContainer" parent="MainBox/Footer"]
custom_minimum_size = Vector2(2, 2.08165e-12)
layout_mode = 2
[node name="BottomPad2" type="CenterContainer" parent="MainBox"]
custom_minimum_size = Vector2(2.08165e-12, 2)
layout_mode = 2

View file

@ -1,91 +1,64 @@
extends VBoxContainer
@tool
extends VBoxContainer
class SearchResults:
var L = 0
var C = 0
var positions = []
var te = null
# ##############################################################################
# Keeps search results from the TextEdit
# ##############################################################################
class TextEditSearcher:
var te: TextEdit
var _last_term = ""
var _last_pos = Vector2(-1, -1)
var _ignore_caret_change = false
func _search_te(text, start_position, flags = 0):
var start_pos = start_position
if start_pos[L] < 0 or start_pos[L] > te.get_line_count():
start_pos[L] = 0
if start_pos[C] < 0:
start_pos[L] = 0
func set_text_edit(which):
te = which
te.caret_changed.connect(_on_caret_changed)
var result = te.search(text, flags, start_pos[L], start_pos[C])
if (
result.size() == 2
and result[L] == start_position[L]
and result[C] == start_position[C]
and text == _last_term
):
if flags == TextEdit.SEARCH_BACKWARDS:
result[C] -= 1
func _on_caret_changed():
if _ignore_caret_change:
_ignore_caret_change = false
else:
_last_pos = _get_caret()
func _get_caret():
return Vector2(te.get_caret_column(), te.get_caret_line())
func _set_caret_and_sel(pos, len):
te.set_caret_line(pos.y)
te.set_caret_column(pos.x)
if len > 0:
te.select(pos.y, pos.x, pos.y, pos.x + len)
func _find(term, search_flags):
var pos = _get_caret()
if term == _last_term:
if search_flags == 0:
pos = _last_pos
pos.x += 1
else:
result[C] += 1
result = _search_te(text, result, flags)
L = result.y
C = result.x
elif result.size() == 2:
te.scroll_vertical = result[L]
te.select(result[L], result[C], result[L], result[C] + text.length())
te.set_caret_column(result[C])
te.set_caret_line(result[L])
te.center_viewport_to_caret()
L = result.y
C = result.x
pos = _last_pos
pos.x -= 1
_last_term = text
te.center_viewport_to_caret()
return result
var result = te.search(term, search_flags, pos.y, pos.x)
# print('searching from ', pos, ' for "', term, '" = ', result)
if result.y != -1:
_ignore_caret_change = true
_set_caret_and_sel(result, term.length())
_last_pos = result
func _cursor_to_pos():
var to_return = [0, 0]
to_return[L] = te.get_caret_line()
to_return[C] = te.get_caret_column()
return to_return
_last_term = term
func find_next(term):
return _search_te(term, _cursor_to_pos())
_find(term, 0)
func find_prev(term):
var new_pos = _search_te(term, _cursor_to_pos(), TextEdit.SEARCH_BACKWARDS)
return new_pos
func get_next_pos():
pass
func get_prev_pos():
pass
func clear():
pass
func find_all(text):
var c_pos = [0, 0]
var found = true
var last_pos = [0, 0]
positions.clear()
while found:
c_pos = te.search(text, 0, c_pos[L], c_pos[C])
if (
c_pos.size() > 0
and (c_pos[L] > last_pos[L] or (c_pos[L] == last_pos[L] and c_pos[C] > last_pos[C]))
):
positions.append([c_pos[L], c_pos[C]])
c_pos[C] += 1
last_pos = c_pos
else:
found = false
_find(term, te.SEARCH_BACKWARDS)
# ##############################################################################
# Start OutputText control code
# ##############################################################################
@onready var _ctrls = {
output = $Output,
copy_button = $Toolbar/CopyButton,
@ -93,42 +66,83 @@ class SearchResults:
clear_button = $Toolbar/ClearButton,
word_wrap = $Toolbar/WordWrap,
show_search = $Toolbar/ShowSearch,
caret_position = $Toolbar/LblPosition,
search_bar =
{
bar = $Search,
search_term = $Search/SearchTerm,
}
}
var _sr = SearchResults.new()
var _sr = TextEditSearcher.new()
var _highlighter: CodeHighlighter
var _font_name = null
# Automatically used when running the OutputText scene from the editor. Changes
# to this method only affect test-running the control through the editor.
func _test_running_setup():
_ctrls.use_colors.text = "use colors"
_ctrls.show_search.text = "search"
_ctrls.word_wrap.text = "ww"
set_all_fonts("CourierPrime")
set_font_size(20)
set_font_size(30)
_ctrls.output.queue_redraw()
load_file("user://.gut_editor.bbcode")
await get_tree().process_frame
show_search(true)
_ctrls.output.set_caret_line(0)
_ctrls.output.scroll_vertical = 0
_ctrls.output.caret_changed.connect(_on_caret_changed)
func _ready():
_sr.te = _ctrls.output
_sr.set_text_edit(_ctrls.output)
_ctrls.use_colors.icon = get_theme_icon("RichTextEffect", "EditorIcons")
_ctrls.show_search.icon = get_theme_icon("Search", "EditorIcons")
_ctrls.word_wrap.icon = get_theme_icon("Loop", "EditorIcons")
_setup_colors()
_ctrls.use_colors.button_pressed = true
_use_highlighting(true)
if get_parent() == get_tree().root:
_test_running_setup()
func _on_caret_changed():
var txt = str(
"line:", _ctrls.output.get_caret_line(), " col:", _ctrls.output.get_caret_column()
)
_ctrls.caret_position.text = str(txt)
# ------------------
# Private
# ------------------
func _setup_colors():
_ctrls.output.clear()
# Call this after changes in colors and the like to get them to apply. reloads
# the text of the output control.
func _refresh_output():
var orig_pos = _ctrls.output.scroll_vertical
var text = _ctrls.output.text
_ctrls.output.text = text
_ctrls.output.scroll_vertical = orig_pos
func _create_highlighter(default_color = Color(1, 1, 1, 1)):
var to_return = CodeHighlighter.new()
to_return.function_color = default_color
to_return.number_color = default_color
to_return.symbol_color = default_color
to_return.member_variable_color = default_color
var keywords = [
["Failed", Color.RED],
["Passed", Color.GREEN],
@ -139,34 +153,30 @@ func _setup_colors():
]
for keyword in keywords:
if _ctrls.output.syntax_highlighter == null:
_ctrls.output.syntax_highlighter = CodeHighlighter.new()
_ctrls.output.syntax_highlighter.add_keyword_color(keyword[0], keyword[1])
to_return.add_keyword_color(keyword[0], keyword[1])
return to_return
func _setup_colors():
_ctrls.output.clear()
var f_color = null
if _ctrls.output.theme == null:
f_color = get_theme_color("font_color")
else:
f_color = _ctrls.output.theme.font_color
_ctrls.output.add_theme_color_override("font_color_readonly", f_color)
_ctrls.output.add_theme_color_override("function_color", f_color)
_ctrls.output.add_theme_color_override("member_variable_color", f_color)
_highlighter = _create_highlighter()
_ctrls.output.queue_redraw()
func _set_font(font_name, custom_name):
var rtl = _ctrls.output
if font_name == null:
rtl.set("custom_fonts/" + custom_name, null)
func _use_highlighting(should):
if should:
_ctrls.output.syntax_highlighter = _highlighter
else:
pass
# cuasing issues in 4.0
# var dyn_font = FontFile.new()
# var font_data = FontFile.new()
# font_data.font_path = 'res://addons/gut/fonts/' + font_name + '.ttf'
# font_data.antialiased = true
# dyn_font.font_data = font_data
# rtl.set('custom_fonts/' + custom_name, dyn_font)
_ctrls.output.syntax_highlighter = null
_refresh_output()
# ------------------
@ -177,7 +187,7 @@ func _on_CopyButton_pressed():
func _on_UseColors_pressed():
_ctrls.output.syntax_highlighter = _ctrls.use_colors.button_pressed
_use_highlighting(_ctrls.use_colors.button_pressed)
func _on_ClearButton_pressed():
@ -215,12 +225,16 @@ func _on_SearchTerm_text_entered(new_text):
func _on_SearchTerm_gui_input(event):
if event is InputEventKey and !event.pressed and event.scancode == KEY_ESCAPE:
if event is InputEventKey and !event.pressed and event.keycode == KEY_ESCAPE:
show_search(false)
func _on_WordWrap_pressed():
_ctrls.output.wrap_enabled = _ctrls.word_wrap.pressed
if _ctrls.word_wrap.button_pressed:
_ctrls.output.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY
else:
_ctrls.output.wrap_mode = TextEdit.LINE_WRAPPING_NONE
_ctrls.output.queue_redraw()
@ -240,40 +254,57 @@ func search(text, start_pos, highlight = true):
func copy_to_clipboard():
var selected = _ctrls.output.get_selection_text()
var selected = _ctrls.output.get_selected_text()
if selected != "":
OS.clipboard = selected
DisplayServer.clipboard_set(selected)
else:
OS.clipboard = _ctrls.output.text
DisplayServer.clipboard_set(_ctrls.output.text)
func clear():
_ctrls.output.text = ""
func _set_font(font_name, custom_name):
var rtl = _ctrls.output
if font_name == null:
rtl.add_theme_font_override(custom_name, null)
else:
var dyn_font = FontFile.new()
dyn_font.load_dynamic_font("res://addons/gut/fonts/" + font_name + ".ttf")
rtl.add_theme_font_override(custom_name, dyn_font)
func set_all_fonts(base_name):
_font_name = GutUtils.nvl(base_name, "Default")
if base_name == "Default":
_set_font(null, "font")
# _set_font(null, 'normal_font')
# _set_font(null, 'bold_font')
# _set_font(null, 'italics_font')
# _set_font(null, 'bold_italics_font')
_set_font(null, "normal_font")
_set_font(null, "bold_font")
_set_font(null, "italics_font")
_set_font(null, "bold_italics_font")
else:
_set_font(base_name + "-Regular", "font")
# _set_font(base_name + '-Regular', 'normal_font')
# _set_font(base_name + '-Bold', 'bold_font')
# _set_font(base_name + '-Italic', 'italics_font')
# _set_font(base_name + '-BoldItalic', 'bold_italics_font')
_set_font(base_name + "-Regular", "normal_font")
_set_font(base_name + "-Bold", "bold_font")
_set_font(base_name + "-Italic", "italics_font")
_set_font(base_name + "-BoldItalic", "bold_italics_font")
func set_font_size(new_size):
var rtl = _ctrls.output
if rtl.get("custom_fonts/font") != null:
rtl.get("custom_fonts/font").size = new_size
rtl.set("theme_override_font_sizes/font_size", new_size)
# rtl.add_theme_font_size_override("font", new_size)
# rtl.add_theme_font_size_override("normal_font", new_size)
# rtl.add_theme_font_size_override("bold_font", new_size)
# rtl.add_theme_font_size_override("italics_font", new_size)
# rtl.add_theme_font_size_override("bold_italics_font", new_size)
# if(rtl.get('custom_fonts/font') != null):
# rtl.get('custom_fonts/font').size = new_size
# rtl.get('custom_fonts/bold_italics_font').size = new_size
# rtl.get('custom_fonts/bold_font').size = new_size
# rtl.get('custom_fonts/italics_font').size = new_size
@ -298,7 +329,7 @@ func load_file(path):
return
var t = f.get_as_text()
f.close()
f = null # closes file
_ctrls.output.text = t
_ctrls.output.scroll_vertical = _ctrls.output.get_line_count()
_ctrls.output.set_deferred("scroll_vertical", _ctrls.output.get_line_count())

View file

@ -1,113 +1,107 @@
[gd_scene load_steps=4 format=2]
[gd_scene load_steps=5 format=3 uid="uid://bqmo4dj64c7yl"]
[ext_resource path="res://addons/gut/gui/OutputText.gd" type="Script" id=1]
[ext_resource type="Script" path="res://addons/gut/gui/OutputText.gd" id="1"]
[sub_resource type="Image" id=3]
[sub_resource type="Image" id="Image_abbh7"]
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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": "LumAlpha8",
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id=2]
flags = 4
flags = 4
image = SubResource( 3 )
size = Vector2( 16, 16 )
[sub_resource type="ImageTexture" id="ImageTexture_x655i"]
image = SubResource("Image_abbh7")
[sub_resource type="CodeHighlighter" id="CodeHighlighter_4pcgd"]
number_color = Color(1, 1, 1, 1)
symbol_color = Color(1, 1, 1, 1)
function_color = Color(1, 1, 1, 1)
member_variable_color = Color(1, 1, 1, 1)
keyword_colors = {
"ERROR": Color(1, 0, 0, 1),
"Failed": Color(1, 0, 0, 1),
"Orphans": Color(1, 1, 0, 1),
"Passed": Color(0, 1, 0, 1),
"Pending": Color(1, 1, 0, 1),
"WARNING": Color(1, 1, 0, 1)
}
[node name="OutputText" type="VBoxContainer"]
offset_right = 862.0
offset_bottom = 523.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
script = ExtResource("1")
[node name="Toolbar" type="HBoxContainer" parent="."]
offset_right = 862.0
offset_bottom = 24.0
layout_mode = 2
size_flags_horizontal = 3
[node name="ShowSearch" type="Button" parent="Toolbar"]
offset_right = 28.0
offset_bottom = 24.0
layout_mode = 2
tooltip_text = "Search"
toggle_mode = true
icon = SubResource( 2 )
icon = SubResource("ImageTexture_x655i")
[node name="UseColors" type="Button" parent="Toolbar"]
offset_left = 32.0
offset_right = 60.0
offset_bottom = 24.0
hint_tooltip = "Colorize output.
It's not the same as everywhere else (long story),
but it is better than nothing."
layout_mode = 2
tooltip_text = "Colorized Text"
toggle_mode = true
pressed = true
icon = SubResource( 2 )
button_pressed = true
icon = SubResource("ImageTexture_x655i")
[node name="WordWrap" type="Button" parent="Toolbar"]
offset_left = 64.0
offset_right = 92.0
offset_bottom = 24.0
hint_tooltip = "Word wrap"
layout_mode = 2
tooltip_text = "Word Wrap"
toggle_mode = true
icon = SubResource( 2 )
icon = SubResource("ImageTexture_x655i")
[node name="CenterContainer" type="CenterContainer" parent="Toolbar"]
offset_left = 96.0
offset_right = 743.0
offset_bottom = 24.0
layout_mode = 2
size_flags_horizontal = 3
[node name="LblPosition" type="Label" parent="Toolbar"]
layout_mode = 2
[node name="CopyButton" type="Button" parent="Toolbar"]
offset_left = 747.0
offset_right = 798.0
offset_bottom = 24.0
hint_tooltip = "Copy to clipboard"
layout_mode = 2
text = " Copy "
[node name="ClearButton" type="Button" parent="Toolbar"]
offset_left = 802.0
offset_right = 862.0
offset_bottom = 24.0
layout_mode = 2
text = " Clear "
[node name="Output" type="TextEdit" parent="."]
offset_top = 28.0
offset_right = 862.0
offset_bottom = 523.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
readonly = true
text = "Hello World
This is a bunch of text
That exists for you to see."
deselect_on_focus_loss_enabled = false
virtual_keyboard_enabled = false
middle_mouse_paste_enabled = false
highlight_all_occurrences = true
highlight_current_line = true
syntax_highlighter = true
show_line_numbers = true
smooth_scrolling = true
syntax_highlighter = SubResource("CodeHighlighter_4pcgd")
scroll_smooth = true
[node name="Search" type="HBoxContainer" parent="."]
visible = false
offset_top = 499.0
offset_right = 862.0
offset_bottom = 523.0
layout_mode = 2
[node name="SearchTerm" type="LineEdit" parent="Search"]
offset_right = 804.0
offset_bottom = 24.0
layout_mode = 2
size_flags_horizontal = 3
[node name="SearchNext" type="Button" parent="Search"]
offset_left = 808.0
offset_right = 862.0
offset_bottom = 24.0
hint_tooltip = "Find next (enter)"
layout_mode = 2
text = "Next"
[node name="SearchPrev" type="Button" parent="Search"]
offset_left = 808.0
offset_right = 820.0
offset_bottom = 20.0
hint_tooltip = "Find previous (shift + enter)"
layout_mode = 2
text = "Prev"
[connection signal="pressed" from="Toolbar/ShowSearch" to="." method="_on_ShowSearch_pressed"]

View file

@ -0,0 +1,108 @@
@tool
extends ColorRect
# #############################################################################
# Resize Handle control. Place onto a control. Set the orientation, then
# set the control that this should resize. Then you can resize the control
# by dragging this thing around. It's pretty neat.
# #############################################################################
enum ORIENTATION { LEFT, RIGHT }
@export var orientation := ORIENTATION.RIGHT:
get:
return orientation
set(val):
orientation = val
queue_redraw()
@export var resize_control: Control = null
@export var vertical_resize := true
var _line_width = .5
var _line_color = Color(.4, .4, .4)
var _active_line_color = Color(.3, .3, .3)
var _invalid_line_color = Color(1, 0, 0)
var _grab_margin = 2
var _line_space = 3
var _num_lines = 8
var _mouse_down = false
# Called when the node enters the scene tree for the first time.
func _draw():
var c = _line_color
if resize_control == null:
c = _invalid_line_color
elif _mouse_down:
c = _active_line_color
if orientation == ORIENTATION.LEFT:
_draw_resize_handle_left(c)
else:
_draw_resize_handle_right(c)
func _gui_input(event):
if resize_control == null:
return
if orientation == ORIENTATION.LEFT:
_handle_left_input(event)
else:
_handle_right_input(event)
# Draw the lines in the corner to show where you can
# drag to resize the dialog
func _draw_resize_handle_right(color):
var br = size
for i in range(_num_lines):
var start = br - Vector2(i * _line_space, 0)
var end = br - Vector2(0, i * _line_space)
draw_line(start, end, color, _line_width, true)
func _draw_resize_handle_left(color):
var bl = Vector2(0, size.y)
for i in range(_num_lines):
var start = bl + Vector2(i * _line_space, 0)
var end = bl - Vector2(0, i * _line_space)
draw_line(start, end, color, _line_width, true)
func _handle_right_input(event: InputEvent):
if event is InputEventMouseMotion:
if (
_mouse_down
and event.global_position.x > 0
and event.global_position.y < DisplayServer.window_get_size().y
):
if vertical_resize:
resize_control.size.y += event.relative.y
resize_control.size.x += event.relative.x
elif event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
_mouse_down = event.pressed
queue_redraw()
func _handle_left_input(event: InputEvent):
if event is InputEventMouseMotion:
if (
_mouse_down
and event.global_position.x > 0
and event.global_position.y < DisplayServer.window_get_size().y
):
var start_size = resize_control.size
resize_control.size.x -= event.relative.x
if resize_control.size.x != start_size.x:
resize_control.global_position.x += event.relative.x
if vertical_resize:
resize_control.size.y += event.relative.y
elif event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
_mouse_down = event.pressed
queue_redraw()

View file

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://bvrqqgjpyouse"]
[ext_resource type="Script" path="res://addons/gut/gui/ResizeHandle.gd" id="1_oi5ed"]
[node name="ResizeHandle" type="ColorRect"]
custom_minimum_size = Vector2(20, 20)
color = Color(1, 1, 1, 0)
script = ExtResource("1_oi5ed")

View file

@ -0,0 +1,360 @@
@tool
extends Control
var _show_orphans = true
var show_orphans = true:
get:
return _show_orphans
set(val):
_show_orphans = val
var _hide_passing = true
var hide_passing = true:
get:
return _hide_passing
set(val):
_hide_passing = val
var _icons = {
red = load("res://addons/gut/images/red.png"),
green = load("res://addons/gut/images/green.png"),
yellow = load("res://addons/gut/images/yellow.png"),
}
const _col_1_bg_color = Color(0, 0, 0, .1)
var _max_icon_width = 10
var _root: TreeItem
@onready var _ctrls = {tree = $Tree, lbl_overlay = $Tree/TextOverlay}
signal item_selected(script_path, inner_class, test_name, line_number)
# -------------------
# Private
# -------------------
func _ready():
_root = _ctrls.tree.create_item()
_root = _ctrls.tree.create_item()
_ctrls.tree.set_hide_root(true)
_ctrls.tree.columns = 2
_ctrls.tree.set_column_expand(0, true)
_ctrls.tree.set_column_expand(1, false)
_ctrls.tree.set_column_clip_content(0, true)
$Tree.item_selected.connect(_on_tree_item_selected)
if get_parent() == get_tree().root:
_test_running_setup()
func _test_running_setup():
load_json_file("user://.gut_editor.json")
func _on_tree_item_selected():
var item = _ctrls.tree.get_selected()
var item_meta = item.get_metadata(0)
var item_type = null
# Only select the left side of the tree item, cause I like that better.
# you can still click the right, but only the left gets highlighted.
if item.is_selected(1):
item.deselect(1)
item.select(0)
if item_meta == null:
return
else:
item_type = item_meta.type
var script_path = ""
var line = -1
var test_name = ""
var inner_class = ""
if item_type == "test":
var s_item = item.get_parent()
script_path = s_item.get_metadata(0)["path"]
inner_class = s_item.get_metadata(0)["inner_class"]
line = -1
test_name = item.get_text(0)
elif item_type == "assert":
var s_item = item.get_parent().get_parent()
script_path = s_item.get_metadata(0)["path"]
inner_class = s_item.get_metadata(0)["inner_class"]
line = _get_line_number_from_assert_msg(item.get_text(0))
test_name = item.get_parent().get_text(0)
elif item_type == "script":
script_path = item.get_metadata(0)["path"]
if item.get_parent() != _root:
inner_class = item.get_text(0)
line = -1
test_name = ""
else:
return
item_selected.emit(script_path, inner_class, test_name, line)
func _get_line_number_from_assert_msg(msg):
var line = -1
if msg.find("at line") > 0:
line = msg.split("at line")[-1].split(" ")[-1].to_int()
return line
func _get_path_and_inner_class_name_from_test_path(path):
var to_return = {path = "", inner_class = ""}
to_return.path = path
if !path.ends_with(".gd"):
var loc = path.find(".gd")
to_return.inner_class = path.split(".")[-1]
to_return.path = path.substr(0, loc + 3)
return to_return
func _find_script_item_with_path(path):
var items = _root.get_children()
var to_return = null
var idx = 0
while idx < items.size() and to_return == null:
var item = items[idx]
if item.get_metadata(0).path == path:
to_return = item
else:
idx += 1
return to_return
func _add_script_tree_item(script_path, script_json):
var path_info = _get_path_and_inner_class_name_from_test_path(script_path)
var item_text = script_path
var parent = _root
if path_info.inner_class != "":
parent = _find_script_item_with_path(path_info.path)
item_text = path_info.inner_class
if parent == null:
parent = _add_script_tree_item(path_info.path, {})
parent.get_metadata(0).inner_tests += script_json["props"]["tests"]
parent.get_metadata(0).inner_passing += script_json["props"]["tests"]
parent.get_metadata(0).inner_passing -= script_json["props"]["failures"]
parent.get_metadata(0).inner_passing -= script_json["props"]["pending"]
var total_text = str("All ", parent.get_metadata(0).inner_tests, " passed")
if parent.get_metadata(0).inner_passing != parent.get_metadata(0).inner_tests:
total_text = str(
parent.get_metadata(0).inner_passing,
"/",
parent.get_metadata(0).inner_tests,
" passed."
)
parent.set_text(1, total_text)
var item = _ctrls.tree.create_item(parent)
item.set_text(0, item_text)
var meta = {
"type": "script",
"path": path_info.path,
"inner_class": path_info.inner_class,
"json": script_json,
"inner_passing": 0,
"inner_tests": 0
}
item.set_metadata(0, meta)
item.set_custom_bg_color(1, _col_1_bg_color)
return item
func _add_assert_item(text, icon, parent_item):
# print(' * adding assert')
var assert_item = _ctrls.tree.create_item(parent_item)
assert_item.set_icon_max_width(0, _max_icon_width)
assert_item.set_text(0, text)
assert_item.set_metadata(0, {"type": "assert"})
assert_item.set_icon(0, icon)
assert_item.set_custom_bg_color(1, _col_1_bg_color)
return assert_item
func _add_test_tree_item(test_name, test_json, script_item):
# print(' * adding test ', test_name)
var no_orphans_to_show = !_show_orphans or (_show_orphans and test_json.orphans == 0)
if _hide_passing and test_json["status"] == "pass" and no_orphans_to_show:
return
var item = _ctrls.tree.create_item(script_item)
var status = test_json["status"]
var meta = {"type": "test", "json": test_json}
item.set_text(0, test_name)
item.set_text(1, status)
item.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT)
item.set_custom_bg_color(1, _col_1_bg_color)
item.set_metadata(0, meta)
item.set_icon_max_width(0, _max_icon_width)
var orphan_text = "orphans"
if test_json.orphans == 1:
orphan_text = "orphan"
orphan_text = str(test_json.orphans, " ", orphan_text)
if status == "pass" and no_orphans_to_show:
item.set_icon(0, _icons.green)
elif status == "pass" and !no_orphans_to_show:
item.set_icon(0, _icons.yellow)
item.set_text(1, orphan_text)
elif status == "fail":
item.set_icon(0, _icons.red)
else:
item.set_icon(0, _icons.yellow)
if !_hide_passing:
for passing in test_json.passing:
_add_assert_item("pass: " + passing, _icons.green, item)
for failure in test_json.failing:
_add_assert_item("fail: " + failure.replace("\n", ""), _icons.red, item)
for pending in test_json.pending:
_add_assert_item("pending: " + pending.replace("\n", ""), _icons.yellow, item)
if status != "pass" and !no_orphans_to_show:
_add_assert_item(orphan_text, _icons.yellow, item)
return item
func _add_script_to_tree(key, script_json):
var tests = script_json["tests"]
var test_keys = tests.keys()
var s_item = _add_script_tree_item(key, script_json)
var bad_count = 0
for test_key in test_keys:
var t_item = _add_test_tree_item(test_key, tests[test_key], s_item)
if tests[test_key].status != "pass":
bad_count += 1
elif t_item != null:
t_item.collapsed = true
if s_item.get_children().size() == 0:
s_item.free()
else:
var total_text = str("All ", test_keys.size(), " passed")
if bad_count == 0:
s_item.collapsed = true
else:
total_text = str(test_keys.size() - bad_count, "/", test_keys.size(), " passed")
s_item.set_text(1, total_text)
func _free_childless_scripts():
var items = _root.get_children()
for item in items:
var next_item = item.get_next()
if item.get_children().size() == 0:
item.free()
item = next_item
func _show_all_passed():
if _root.get_children().size() == 0:
add_centered_text("Everything passed!")
func _load_result_tree(j):
var scripts = j["test_scripts"]["scripts"]
var script_keys = scripts.keys()
# if we made it here, the json is valid and we did something, otherwise the
# 'nothing to see here' should be visible.
clear_centered_text()
for key in script_keys:
if scripts[key]["props"]["tests"] > 0:
_add_script_to_tree(key, scripts[key])
_free_childless_scripts()
_show_all_passed()
# -------------------
# Public
# -------------------
func load_json_file(path):
var file = FileAccess.open(path, FileAccess.READ)
var text = ""
if file != null:
text = file.get_as_text()
if text != "":
var test_json_conv = JSON.new()
var result = test_json_conv.parse(text)
if result != OK:
add_centered_text(
str(
path,
" has invalid json in it \n",
"Error ",
result,
"@",
test_json_conv.get_error_line(),
"\n",
test_json_conv.get_error_message()
)
)
return
var data = test_json_conv.get_data()
load_json_results(data)
else:
add_centered_text(str(path, " was empty or does not exist."))
func load_json_results(j):
clear()
_load_result_tree(j)
func clear():
_ctrls.tree.clear()
_root = _ctrls.tree.create_item()
func set_summary_min_width(width):
_ctrls.tree.set_column_custom_minimum_width(1, width)
func add_centered_text(t):
_ctrls.lbl_overlay.visible = true
_ctrls.lbl_overlay.text = t
func clear_centered_text():
_ctrls.lbl_overlay.visible = false
_ctrls.lbl_overlay.text = ""
func collapse_all():
set_collapsed_on_all(_root, true)
func expand_all():
set_collapsed_on_all(_root, false)
func set_collapsed_on_all(item, value):
item.set_collapsed_recursive(value)
if item == _root and value:
item.set_collapsed(false)
func get_selected():
return _ctrls.tree.get_selected()

View file

@ -0,0 +1,32 @@
[gd_scene load_steps=2 format=3 uid="uid://dls5r5f6157nq"]
[ext_resource type="Script" path="res://addons/gut/gui/ResultsTree.gd" id="1_b4uub"]
[node name="ResultsTree" type="VBoxContainer"]
custom_minimum_size = Vector2(10, 10)
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_right = -70.0
offset_bottom = -104.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_b4uub")
[node name="Tree" type="Tree" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 2
hide_root = true
[node name="TextOverlay" type="Label" parent="Tree"]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View file

@ -16,7 +16,7 @@ var _editors = null
var _cur_editor = null
var _last_line = -1
var _cur_script_path = null
var _last_info = null
var _last_info = {script = null, inner_class = null, test_method = null}
signal run_tests(what)
@ -26,6 +26,8 @@ func _ready():
_ctrls.btn_script.visible = false
_ctrls.btn_inner.visible = false
_ctrls.btn_method.visible = false
_ctrls.arrow_1.visible = false
_ctrls.arrow_2.visible = false
# ----------------
@ -34,11 +36,13 @@ func _ready():
func _set_editor(which):
_last_line = -1
if _cur_editor != null and _cur_editor.get_ref():
_cur_editor.get_ref().disconnect("cursor_changed", Callable(self, "_on_cursor_changed"))
# _cur_editor.get_ref().disconnect('cursor_changed',Callable(self,'_on_cursor_changed'))
_cur_editor.get_ref().caret_changed.disconnect(_on_cursor_changed)
if which != null:
_cur_editor = weakref(which)
which.connect("cursor_changed", Callable(self, "_on_cursor_changed"), [which])
which.caret_changed.connect(_on_cursor_changed.bind(which))
# which.connect('cursor_changed',Callable(self,'_on_cursor_changed'),[which])
_last_line = which.get_caret_line()
_last_info = _editors.get_line_info()
@ -52,12 +56,12 @@ func _update_buttons(info):
_ctrls.btn_inner.visible = info.inner_class != null
_ctrls.arrow_1.visible = info.inner_class != null
_ctrls.btn_inner.text = str(info.inner_class)
_ctrls.btn_inner.hint_tooltip = str("Run all tests in Inner-Test-Class ", info.inner_class)
_ctrls.btn_inner.tooltip_text = str("Run all tests in Inner-Test-Class ", info.inner_class)
_ctrls.btn_method.visible = info.test_method != null
_ctrls.arrow_2.visible = info.test_method != null
_ctrls.btn_method.text = str(info.test_method)
_ctrls.btn_method.hint_tooltip = str("Run test ", info.test_method)
_ctrls.btn_method.tooltip_text = str("Run test ", info.test_method)
# The button's new size won't take effect until the next frame.
# This appears to be what was causing the button to not be clickable the
@ -66,7 +70,7 @@ func _update_buttons(info):
func _update_size():
custom_minimum_size.x = _ctrls.btn_method.size.x + _ctrls.btn_method.rect_position.x
custom_minimum_size.x = _ctrls.btn_method.size.x + _ctrls.btn_method.position.x
# ----------------
@ -110,9 +114,12 @@ func set_script_text_editors(value):
func activate_for_script(path):
_ctrls.btn_script.visible = true
_ctrls.btn_script.text = path.get_file()
_ctrls.btn_script.hint_tooltip = str("Run all tests in script ", path)
_ctrls.btn_script.tooltip_text = str("Run all tests in script ", path)
_cur_script_path = path
_editors.refresh()
# We have to wait a beat for the visibility to change on
# the editors, otherwise we always get the first one.
await get_tree().process_frame
_set_editor(_editors.get_current_text_edit())
@ -145,7 +152,4 @@ func search_current_editor_for_text(txt):
var result = te.search(txt, 0, 0, 0)
var to_return = -1
if result.size() > 0:
to_return = result[TextEdit.SEARCH_RESULT_LINE]
return to_return

View file

@ -1,79 +1,64 @@
[gd_scene load_steps=4 format=2]
[gd_scene load_steps=4 format=3 uid="uid://0yunjxtaa8iw"]
[ext_resource path="res://addons/gut/gui/RunAtCursor.gd" type="Script" id=1]
[ext_resource path="res://addons/gut/gui/play.png" type="Texture2D" id=2]
[ext_resource path="res://addons/gut/gui/arrow.png" type="Texture2D" id=3]
[ext_resource type="Script" path="res://addons/gut/gui/RunAtCursor.gd" id="1"]
[ext_resource type="Texture2D" uid="uid://cr6tvdv0ve6cv" path="res://addons/gut/gui/play.png" id="2"]
[ext_resource type="Texture2D" uid="uid://6wra5rxmfsrl" path="res://addons/gut/gui/arrow.png" id="3"]
[node name="RunAtCursor" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_right = 1.0
offset_bottom = -527.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
script = ExtResource("1")
[node name="HBox" type="HBoxContainer" parent="."]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LblNoneSelected" type="Label" parent="HBox"]
offset_top = 29.0
offset_right = 50.0
offset_bottom = 43.0
layout_mode = 2
text = "<None>"
[node name="BtnRunScript" type="Button" parent="HBox"]
visible = false
offset_left = 54.0
offset_right = 140.0
offset_bottom = 73.0
layout_mode = 2
text = "<script>"
icon = ExtResource( 2 )
icon = ExtResource("2")
[node name="Arrow1" type="TextureButton" parent="HBox"]
visible = false
offset_left = 54.0
offset_right = 78.0
offset_bottom = 73.0
custom_minimum_size = Vector2( 24, 0 )
texture_normal = ExtResource( 3 )
expand = true
custom_minimum_size = Vector2(24, 0)
layout_mode = 2
texture_normal = ExtResource("3")
stretch_mode = 3
[node name="BtnRunInnerClass" type="Button" parent="HBox"]
visible = false
offset_left = 134.0
offset_right = 243.0
offset_bottom = 73.0
layout_mode = 2
text = "<inner class>"
icon = ExtResource( 2 )
icon = ExtResource("2")
[node name="Arrow2" type="TextureButton" parent="HBox"]
visible = false
offset_left = 54.0
offset_right = 78.0
offset_bottom = 73.0
custom_minimum_size = Vector2( 24, 0 )
texture_normal = ExtResource( 3 )
expand = true
custom_minimum_size = Vector2(24, 0)
layout_mode = 2
texture_normal = ExtResource("3")
stretch_mode = 3
[node name="BtnRunMethod" type="Button" parent="HBox"]
visible = false
offset_left = 247.0
offset_right = 337.0
offset_bottom = 73.0
layout_mode = 2
text = "<method>"
icon = ExtResource( 2 )
icon = ExtResource("2")
[connection signal="pressed" from="HBox/BtnRunScript" to="." method="_on_BtnRunScript_pressed"]
[connection signal="pressed" from="HBox/BtnRunInnerClass" to="." method="_on_BtnRunInnerClass_pressed"]

View file

@ -1,31 +1,14 @@
extends Control
@tool
extends Control
var _interface = null
var _utils = load("res://addons/gut/utils.gd").new()
var _hide_passing = true
var _font = null
var _font_size = null
var _root = null
var _max_icon_width = 10
var _editors = null # script_text_editor_controls.gd
var _show_orphans = true
var _output_control = null
const _col_1_bg_color = Color(0, 0, 0, .1)
var _icons = {
red = load("res://addons/gut/images/red.png"),
green = load("res://addons/gut/images/green.png"),
yellow = load("res://addons/gut/images/yellow.png"),
}
signal search_for_text(text)
@onready var _ctrls = {
tree = $VBox/Output/Scroll/Tree,
lbl_overlay = $VBox/Output/OverlayMessage,
chk_hide_passing = $VBox/Toolbar/HidePassing,
toolbar =
{
toolbar = $VBox/Toolbar,
@ -40,9 +23,36 @@ signal search_for_text(text)
}
func _ready():
var f = null
if $FontSampler.get_label_settings() == null:
f = get_theme_default_font()
else:
f = $FontSampler.get_label_settings().font
var s_size = f.get_string_size("000 of 000 passed")
_ctrls.tree.set_summary_min_width(s_size.x)
_set_toolbutton_icon(_ctrls.toolbar.collapse, "CollapseTree", "c")
_set_toolbutton_icon(_ctrls.toolbar.collapse_all, "CollapseTree", "c")
_set_toolbutton_icon(_ctrls.toolbar.expand, "ExpandTree", "e")
_set_toolbutton_icon(_ctrls.toolbar.expand_all, "ExpandTree", "e")
_set_toolbutton_icon(_ctrls.toolbar.show_script, "Script", "ss")
_set_toolbutton_icon(_ctrls.toolbar.scroll_output, "Font", "so")
_ctrls.tree.hide_passing = true
_ctrls.toolbar.hide_passing.button_pressed = false
_ctrls.tree.show_orphans = true
_ctrls.tree.item_selected.connect(_on_item_selected)
if get_parent() == get_tree().root:
_test_running_setup()
call_deferred("_update_min_width")
func _test_running_setup():
_hide_passing = true
_show_orphans = true
_ctrls.tree.hide_passing = true
_ctrls.tree.show_orphans = true
var _gut_config = load("res://addons/gut/gut_config.gd").new()
_gut_config.load_panel_options("res://.gut_editor_config.json")
set_font(
@ -50,7 +60,7 @@ func _test_running_setup():
)
_ctrls.toolbar.hide_passing.text = "[hp]"
load_json_file("user://.gut_editor.json")
_ctrls.tree.load_json_file("user://.gut_editor.json")
func _set_toolbutton_icon(btn, icon_name, text):
@ -60,51 +70,17 @@ func _set_toolbutton_icon(btn, icon_name, text):
btn.text = str("[", text, "]")
func _ready():
var f = null
if $FontSampler.get_label_settings() == null:
f = get_theme_default_font()
else:
f = $FontSampler.get_label_settings().font
var s_size = f.get_string_size("000 of 000 passed")
_root = _ctrls.tree.create_item()
_ctrls.tree.set_hide_root(true)
_ctrls.tree.columns = 2
_ctrls.tree.set_column_expand(0, true)
_ctrls.tree.set_column_expand(1, false)
_ctrls.tree.set_column_custom_minimum_width(1, s_size.x)
_set_toolbutton_icon(_ctrls.toolbar.collapse, "CollapseTree", "c")
_set_toolbutton_icon(_ctrls.toolbar.collapse_all, "CollapseTree", "c")
_set_toolbutton_icon(_ctrls.toolbar.expand, "ExpandTree", "e")
_set_toolbutton_icon(_ctrls.toolbar.expand_all, "ExpandTree", "e")
_set_toolbutton_icon(_ctrls.toolbar.show_script, "Script", "ss")
_set_toolbutton_icon(_ctrls.toolbar.scroll_output, "Font", "so")
_ctrls.toolbar.hide_passing.set(
"custom_icons/checked", get_theme_icon("GuiVisibilityHidden", "EditorIcons")
)
_ctrls.toolbar.hide_passing.set(
"custom_icons/unchecked", get_theme_icon("GuiVisibilityVisible", "EditorIcons")
)
if get_parent() == get_tree().root:
_test_running_setup()
call_deferred("_update_min_width")
func _update_min_width():
custom_minimum_size.x = _ctrls.toolbar.toolbar.size.x
func _open_file(path, line_number):
func _open_script_in_editor(path, line_number):
if _interface == null:
print("Too soon, wait a bit and try again.")
return
var r = load(path)
if line_number != -1:
if line_number != null and line_number != -1:
_interface.edit_script(r, line_number)
else:
_interface.edit_script(r)
@ -113,211 +89,6 @@ func _open_file(path, line_number):
_interface.set_main_screen_editor("Script")
func _add_script_tree_item(script_path, script_json):
var path_info = _get_path_and_inner_class_name_from_test_path(script_path)
# print('* adding script ', path_info)
var item_text = script_path
var parent = _root
if path_info.inner_class != "":
parent = _find_script_item_with_path(path_info.path)
item_text = path_info.inner_class
if parent == null:
parent = _add_script_tree_item(path_info.path, {})
var item = _ctrls.tree.create_item(parent)
item.set_text(0, item_text)
var meta = {
"type": "script",
"path": path_info.path,
"inner_class": path_info.inner_class,
"json": script_json
}
item.set_metadata(0, meta)
item.set_custom_bg_color(1, _col_1_bg_color)
return item
func _add_assert_item(text, icon, parent_item):
# print(' * adding assert')
var assert_item = _ctrls.tree.create_item(parent_item)
assert_item.set_icon_max_width(0, _max_icon_width)
assert_item.set_text(0, text)
assert_item.set_metadata(0, {"type": "assert"})
assert_item.set_icon(0, icon)
assert_item.set_custom_bg_color(1, _col_1_bg_color)
return assert_item
func _add_test_tree_item(test_name, test_json, script_item):
# print(' * adding test ', test_name)
var no_orphans_to_show = !_show_orphans or (_show_orphans and test_json.orphans == 0)
if _hide_passing and test_json["status"] == "pass" and no_orphans_to_show:
return
var item = _ctrls.tree.create_item(script_item)
var status = test_json["status"]
var meta = {"type": "test", "json": test_json}
item.set_text(0, test_name)
item.set_text(1, status)
item.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT)
item.set_custom_bg_color(1, _col_1_bg_color)
item.set_metadata(0, meta)
item.set_icon_max_width(0, _max_icon_width)
var orphan_text = "orphans"
if test_json.orphans == 1:
orphan_text = "orphan"
orphan_text = str(test_json.orphans, " ", orphan_text)
if status == "pass" and no_orphans_to_show:
item.set_icon(0, _icons.green)
elif status == "pass" and !no_orphans_to_show:
item.set_icon(0, _icons.yellow)
item.set_text(1, orphan_text)
elif status == "fail":
item.set_icon(0, _icons.red)
else:
item.set_icon(0, _icons.yellow)
if !_hide_passing:
for passing in test_json.passing:
_add_assert_item("pass: " + passing, _icons.green, item)
for failure in test_json.failing:
_add_assert_item("fail: " + failure.replace("\n", ""), _icons.red, item)
for pending in test_json.pending:
_add_assert_item("pending: " + pending.replace("\n", ""), _icons.yellow, item)
if status != "pass" and !no_orphans_to_show:
_add_assert_item(orphan_text, _icons.yellow, item)
return item
func _load_result_tree(j):
var scripts = j["test_scripts"]["scripts"]
var script_keys = scripts.keys()
# if we made it here, the json is valid and we did something, otherwise the
# 'nothing to see here' should be visible.
clear_centered_text()
var _last_script_item = null
for key in script_keys:
var tests = scripts[key]["tests"]
var test_keys = tests.keys()
var s_item = _add_script_tree_item(key, scripts[key])
var bad_count = 0
for test_key in test_keys:
var t_item = _add_test_tree_item(test_key, tests[test_key], s_item)
if tests[test_key].status != "pass":
bad_count += 1
elif t_item != null:
t_item.collapsed = true
# get_children returns the first child or null. its a dumb name.
if s_item.get_children() == null:
# var m = s_item.get_metadata(0)
# print('!! Deleting ', m.path, ' ', m.inner_class)
s_item.free()
else:
var total_text = str(test_keys.size(), " passed")
# s_item.set_text_alignment(1, s_item.ALIGN_LEFT)
if bad_count == 0:
s_item.collapsed = true
else:
total_text = str(test_keys.size() - bad_count, " of ", test_keys.size(), " passed")
s_item.set_text(1, total_text)
_free_childless_scripts()
_show_all_passed()
func _free_childless_scripts():
var items = _root.get_children()
for item in items:
var next_item = item.get_next()
if item.get_children() == null:
item.free()
item = next_item
func _find_script_item_with_path(path):
var items = _root.get_children()
var to_return = null
var idx = 0
while idx < items.size() and to_return == null:
var item = items[idx]
if item.get_metadata(0).path == path:
to_return = item
else:
idx += 1
return to_return
func _get_line_number_from_assert_msg(msg):
var line = -1
if msg.find("at line") > 0:
line = msg.split("at line")[-1].split(" ")[-1].to_int()
return line
func _get_path_and_inner_class_name_from_test_path(path):
var to_return = {path = "", inner_class = ""}
to_return.path = path
if !path.ends_with(".gd"):
var loc = path.find(".gd")
to_return.inner_class = path.split(".")[-1]
to_return.path = path.substr(0, loc + 3)
return to_return
func _handle_tree_item_select(item, force_scroll):
var item_type = item.get_metadata(0).type
var path = ""
var line = -1
var method_name = ""
var inner_class = ""
if item_type == "test":
var s_item = item.get_parent()
path = s_item.get_metadata(0)["path"]
inner_class = s_item.get_metadata(0)["inner_class"]
line = -1
method_name = item.get_text(0)
elif item_type == "assert":
var s_item = item.get_parent().get_parent()
path = s_item.get_metadata(0)["path"]
inner_class = s_item.get_metadata(0)["inner_class"]
line = _get_line_number_from_assert_msg(item.get_text(0))
method_name = item.get_parent().get_text(0)
elif item_type == "script":
path = item.get_metadata(0)["path"]
if item.get_parent() != _root:
inner_class = item.get_text(0)
line = -1
method_name = ""
else:
return
var path_info = _get_path_and_inner_class_name_from_test_path(path)
if force_scroll or _ctrls.toolbar.show_script.pressed:
_goto_code(path, line, method_name, inner_class)
if force_scroll or _ctrls.toolbar.scroll_output.pressed:
_goto_output(path, method_name, inner_class)
# starts at beginning of text edit and searches for each search term, moving
# through the text as it goes; ensuring that, when done, it found the first
# occurance of the last srting that happend after the first occurance of
@ -325,9 +96,12 @@ func _handle_tree_item_select(item, force_scroll):
# inner class that may have be a duplicate of a method name in a different
# inner class)
func _get_line_number_for_seq_search(search_strings, te):
# var te = _editors.get_current_text_edit()
if te == null:
print("No Text editor to get line number for")
return 0
var result = null
var line = Vector2i(-1, -1)
var line = Vector2i(0, 0)
var s_flags = 0
var i = 0
@ -348,7 +122,7 @@ func _goto_code(path, line, method_name = "", inner_class = ""):
print("going to ", [path, line, method_name, inner_class])
return
_open_file(path, line)
_open_script_in_editor(path, line)
if line == -1:
var search_strings = []
if inner_class != "":
@ -357,8 +131,9 @@ func _goto_code(path, line, method_name = "", inner_class = ""):
if method_name != "":
search_strings.append(method_name)
await get_tree().process_frame
line = _get_line_number_for_seq_search(search_strings, _editors.get_current_text_edit())
if line != -1:
if line != null and line != -1:
_interface.get_script_editor().goto_line(line)
@ -375,44 +150,13 @@ func _goto_output(path, method_name, inner_class):
search_strings.append(method_name)
var line = _get_line_number_for_seq_search(search_strings, _output_control.get_rich_text_edit())
if line != -1:
if line != null and line != -1:
_output_control.scroll_to_line(line)
func _show_all_passed():
if _root.get_children() == null:
add_centered_text("Everything passed!")
func _set_collapsed_on_all(item, value):
if item == _root:
var node = _root.get_children()
while node != null:
node.call_recursive("set_collapsed", value)
node = node.get_next()
else:
item.call_recursive("set_collapsed", value)
# --------------
# Events
# --------------
func _on_Tree_item_selected():
# do not force scroll
var item = _ctrls.tree.get_selected()
_handle_tree_item_select(item, false)
# it just looks better if the left is always selected.
if item.is_selected(1):
item.deselect(1)
item.select(0)
func _on_Tree_item_activated():
# force scroll
print("double clicked")
_handle_tree_item_select(_ctrls.tree.get_selected(), true)
func _on_Collapse_pressed():
collapse_selected()
@ -430,55 +174,30 @@ func _on_ExpandAll_pressed():
func _on_Hide_Passing_pressed():
_hide_passing = _ctrls.toolbar.hide_passing.button_pressed
_ctrls.tree.hide_passing = !_ctrls.toolbar.hide_passing.button_pressed
_ctrls.tree.load_json_file("user://.gut_editor.json")
func _on_item_selected(script_path, inner_class, test_name, line):
if _ctrls.toolbar.show_script.button_pressed:
_goto_code(script_path, line, test_name, inner_class)
if _ctrls.toolbar.scroll_output.button_pressed:
_goto_output(script_path, test_name, inner_class)
# --------------
# Public
# --------------
func load_json_file(path):
var text = _utils.get_file_as_text(path)
if text != "":
var test_json_conv = JSON.new()
test_json_conv.parse(text)
var result = test_json_conv.get_data()
if result.error != OK:
add_centered_text(
str(
path,
" has invalid json in it \n",
"Error ",
result.error,
"@",
result.error_line,
"\n",
result.error_string
)
)
return
load_json_results(result.result)
else:
add_centered_text(str(path, " was empty or does not exist."))
func load_json_results(j):
clear()
add_centered_text("Nothing Here")
_load_result_tree(j)
func add_centered_text(t):
_ctrls.lbl_overlay.text = t
_ctrls.tree.add_centered_text(t)
func clear_centered_text():
_ctrls.lbl_overlay.text = ""
_ctrls.tree.clear_centered_text()
func clear():
_ctrls.tree.clear()
_root = _ctrls.tree.create_item()
clear_centered_text()
@ -491,27 +210,27 @@ func set_script_text_editors(value):
func collapse_all():
_set_collapsed_on_all(_root, true)
_ctrls.tree.collapse_all()
func expand_all():
_set_collapsed_on_all(_root, false)
_ctrls.tree.expand_all()
func collapse_selected():
var item = _ctrls.tree.get_selected()
if item != null:
_set_collapsed_on_all(item, true)
_ctrls.tree.set_collapsed_on_all(item, true)
func expand_selected():
var item = _ctrls.tree.get_selected()
if item != null:
_set_collapsed_on_all(item, false)
_ctrls.tree.set_collapsed_on_all(item, false)
func set_show_orphans(should):
_show_orphans = should
_ctrls.tree.show_orphans = should
func set_font(font_name, size):
@ -531,3 +250,7 @@ func set_font(font_name, size):
func set_output_control(value):
_output_control = value
func load_json_results(j):
_ctrls.tree.load_json_results(j)

View file

@ -1,157 +1,110 @@
[gd_scene load_steps=4 format=2]
[gd_scene load_steps=5 format=3 uid="uid://4gyyn12um08h"]
[ext_resource path="res://addons/gut/gui/RunResults.gd" type="Script" id=1]
[ext_resource type="Script" path="res://addons/gut/gui/RunResults.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://dls5r5f6157nq" path="res://addons/gut/gui/ResultsTree.tscn" id="2_o808v"]
[sub_resource type="Image" id=3]
[sub_resource type="Image" id="Image_abbh7"]
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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": "LumAlpha8",
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id=2]
flags = 4
flags = 4
image = SubResource( 3 )
size = Vector2( 16, 16 )
[sub_resource type="ImageTexture" id="ImageTexture_x655i"]
image = SubResource("Image_abbh7")
[node name="RunResults" type="Control"]
offset_right = 595.0
offset_bottom = 459.0
custom_minimum_size = Vector2( 302, 0 )
script = ExtResource( 1 )
custom_minimum_size = Vector2(345, 0)
layout_mode = 3
anchors_preset = 0
offset_right = 709.0
offset_bottom = 321.0
script = ExtResource("1")
[node name="VBox" type="VBoxContainer" parent="."]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
[node name="Toolbar" type="HBoxContainer" parent="VBox"]
offset_right = 296.0
offset_bottom = 24.0
layout_mode = 2
size_flags_horizontal = 0
[node name="Expand" type="Button" parent="VBox/Toolbar"]
offset_right = 28.0
offset_bottom = 24.0
hint_tooltip = "Expand selected item and all children."
icon = SubResource( 2 )
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
[node name="Collapse" type="Button" parent="VBox/Toolbar"]
offset_left = 32.0
offset_right = 60.0
offset_bottom = 24.0
hint_tooltip = "Collapse selected item and all children."
icon = SubResource( 2 )
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
[node name="Sep" type="ColorRect" parent="VBox/Toolbar"]
offset_left = 64.0
offset_right = 66.0
offset_bottom = 24.0
custom_minimum_size = Vector2( 2, 0 )
custom_minimum_size = Vector2(2, 0)
layout_mode = 2
[node name="LblAll" type="Label" parent="VBox/Toolbar"]
offset_left = 70.0
offset_top = 5.0
offset_right = 91.0
offset_bottom = 19.0
layout_mode = 2
text = "All:"
align = 1
[node name="ExpandAll" type="Button" parent="VBox/Toolbar"]
offset_left = 95.0
offset_right = 123.0
offset_bottom = 24.0
hint_tooltip = "Expand All."
icon = SubResource( 2 )
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
[node name="CollapseAll" type="Button" parent="VBox/Toolbar"]
offset_left = 127.0
offset_right = 155.0
offset_bottom = 24.0
hint_tooltip = "Collapse all."
icon = SubResource( 2 )
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
[node name="Sep2" type="ColorRect" parent="VBox/Toolbar"]
offset_left = 159.0
offset_right = 161.0
offset_bottom = 24.0
custom_minimum_size = Vector2( 2, 0 )
custom_minimum_size = Vector2(2, 0)
layout_mode = 2
[node name="HidePassing" type="CheckBox" parent="VBox/Toolbar"]
offset_left = 165.0
offset_right = 189.0
offset_bottom = 24.0
hint_tooltip = "Show/Hide passing tests. Takes effect on next run."
layout_mode = 2
size_flags_horizontal = 4
custom_icons/checked = SubResource( 2 )
custom_icons/unchecked = SubResource( 2 )
pressed = true
__meta__ = {
"_editor_description_": ""
}
text = "Passing"
[node name="Sep3" type="ColorRect" parent="VBox/Toolbar"]
offset_left = 193.0
offset_right = 195.0
offset_bottom = 24.0
custom_minimum_size = Vector2( 2, 0 )
custom_minimum_size = Vector2(2, 0)
layout_mode = 2
[node name="LblSync" type="Label" parent="VBox/Toolbar"]
offset_left = 199.0
offset_top = 5.0
offset_right = 232.0
offset_bottom = 19.0
layout_mode = 2
text = "Sync:"
align = 1
[node name="ShowScript" type="Button" parent="VBox/Toolbar"]
offset_left = 236.0
offset_right = 264.0
offset_bottom = 24.0
hint_tooltip = "Open script and scroll to line when a tree item is clicked."
layout_mode = 2
toggle_mode = true
pressed = true
icon = SubResource( 2 )
button_pressed = true
icon = SubResource("ImageTexture_x655i")
[node name="ScrollOutput" type="Button" parent="VBox/Toolbar"]
offset_left = 268.0
offset_right = 296.0
offset_bottom = 24.0
hint_tooltip = "Scroll to related line in the output panel when tree item clicked."
layout_mode = 2
toggle_mode = true
pressed = true
icon = SubResource( 2 )
button_pressed = true
icon = SubResource("ImageTexture_x655i")
[node name="Output" type="Panel" parent="VBox"]
self_modulate = Color( 1, 1, 1, 0.541176 )
offset_top = 28.0
offset_right = 595.0
offset_bottom = 459.0
self_modulate = Color(1, 1, 1, 0.541176)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Scroll" type="ScrollContainer" parent="VBox/Output"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Tree" type="Tree" parent="VBox/Output/Scroll"]
offset_right = 595.0
offset_bottom = 431.0
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 2
hide_root = true
[node name="OverlayMessage" type="Label" parent="VBox/Output"]
anchor_right = 1.0
anchor_bottom = 1.0
align = 1
valign = 1
[node name="Tree" parent="VBox/Output/Scroll" instance=ExtResource("2_o808v")]
layout_mode = 2
[node name="FontSampler" type="Label" parent="."]
visible = false
layout_mode = 0
offset_right = 40.0
offset_bottom = 14.0
text = "000 of 000 passed"
@ -161,5 +114,3 @@ text = "000 of 000 passed"
[connection signal="pressed" from="VBox/Toolbar/ExpandAll" to="." method="_on_ExpandAll_pressed"]
[connection signal="pressed" from="VBox/Toolbar/CollapseAll" to="." method="_on_CollapseAll_pressed"]
[connection signal="pressed" from="VBox/Toolbar/HidePassing" to="." method="_on_Hide_Passing_pressed"]
[connection signal="item_activated" from="VBox/Output/Scroll/Tree" to="." method="_on_Tree_item_activated"]
[connection signal="item_selected" from="VBox/Output/Scroll/Tree" to="." method="_on_Tree_item_selected"]

View file

@ -1,4 +1,4 @@
[gd_scene format=2]
[gd_scene format=3 uid="uid://cvvvtsah38l0e"]
[node name="Settings" type="VBoxContainer"]
offset_right = 388.0

View file

@ -36,24 +36,13 @@ func _display_shortcut():
func _is_shift_only_modifier():
return (
_source_event.shift_pressed
and !(
_source_event.alt_pressed
or _source_event.command_pressed
or _source_event.ctrl_pressed
or _source_event.meta_pressed
)
and !(_source_event.alt_pressed or _source_event.ctrl_pressed or _source_event.meta_pressed)
and !_is_modifier(_source_event.keycode)
)
func _has_modifier(event):
return (
event.alt_pressed
or event.command_pressed
or event.ctrl_pressed
or event.meta_pressed
or event.shift_pressed
)
return event.alt_pressed or event.ctrl_pressed or event.meta_pressed or event.shift_pressed
func _is_modifier(keycode):

View file

@ -1,77 +1,52 @@
[gd_scene load_steps=2 format=2]
[gd_scene load_steps=2 format=3 uid="uid://sfb1fw8j6ufu"]
[ext_resource path="res://addons/gut/gui/ShortcutButton.gd" type="Script" id=1]
[ext_resource type="Script" path="res://addons/gut/gui/ShortcutButton.gd" id="1"]
[node name="ShortcutButton" type="Control"]
custom_minimum_size = Vector2(210, 30)
layout_mode = 3
anchor_right = 0.123
anchor_bottom = 0.04
offset_right = 33.048
offset_bottom = 1.0
custom_minimum_size = Vector2( 125, 25 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
offset_right = 68.304
offset_bottom = 6.08
script = ExtResource("1")
[node name="Layout" type="HBoxContainer" parent="."]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="lblShortcut" type="Label" parent="Layout"]
offset_right = 50.0
offset_bottom = 25.0
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 7
text = "<None>"
align = 2
valign = 1
horizontal_alignment = 2
[node name="CenterContainer" type="CenterContainer" parent="Layout"]
offset_left = 54.0
offset_right = 64.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 10, 0 )
custom_minimum_size = Vector2(10, 0)
layout_mode = 2
[node name="SetButton" type="Button" parent="Layout"]
offset_left = 68.0
offset_right = 128.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 60, 0 )
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
text = "Set"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="SaveButton" type="Button" parent="Layout"]
visible = false
offset_left = 82.0
offset_right = 142.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 60, 0 )
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
text = "Save"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CancelButton" type="Button" parent="Layout"]
visible = false
offset_left = 82.0
offset_right = 142.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 60, 0 )
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
text = "Cancel"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ClearButton" type="Button" parent="Layout"]
offset_left = 132.0
offset_right = 192.0
offset_bottom = 25.0
custom_minimum_size = Vector2( 60, 0 )
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
text = "Clear"
[connection signal="pressed" from="Layout/SetButton" to="." method="_on_SetButton_pressed"]

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/arrow.png-2b5b2d838b5b3467cf300ac2da1630d9.ct
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -1,4 +1,6 @@
# ------------------------------------------------------------------------------
# Choose an existing directory from res://. Dialog allows for creating a
# directory.
# ------------------------------------------------------------------------------
class DirectoryCtrl:
extends HBoxContainer
@ -9,20 +11,20 @@ class DirectoryCtrl:
set(val):
_txt_path.text = val
var _txt_path = LineEdit.new()
var _btn_dir = Button.new()
var _dialog = FileDialog.new()
var _txt_path := LineEdit.new()
var _btn_dir := Button.new()
var _dialog := FileDialog.new()
func _init():
_btn_dir.text = "..."
_btn_dir.connect("pressed", Callable(self, "_on_dir_button_pressed"))
_btn_dir.pressed.connect(_on_dir_button_pressed)
_txt_path.size_flags_horizontal = _txt_path.SIZE_EXPAND_FILL
_dialog.mode = _dialog.FILE_MODE_OPEN_DIR
_dialog.file_mode = _dialog.FILE_MODE_OPEN_DIR
_dialog.unresizable = false
_dialog.connect("dir_selected", Callable(self, "_on_selected"))
_dialog.connect("file_selected", Callable(self, "_on_selected"))
_dialog.dir_selected.connect(_on_selected)
_dialog.file_selected.connect(_on_selected)
_dialog.size = Vector2(1000, 700)
func _on_selected(path):
@ -42,12 +44,27 @@ class DirectoryCtrl:
# ------------------------------------------------------------------------------
# Choose an existing file in res://
# ------------------------------------------------------------------------------
class FileCtrl:
extends DirectoryCtrl
func _init():
_dialog.mode = _dialog.FILE_MODE_OPEN_FILE
super._init()
_dialog.file_mode = _dialog.FILE_MODE_OPEN_FILE
# ------------------------------------------------------------------------------
# Choose a save location. Can pick anywhere on file system. Will warn if you
# pick a file that already exists.
# ------------------------------------------------------------------------------
class SaveFileAnywhere:
extends DirectoryCtrl
func _init():
super._init()
_dialog.file_mode = _dialog.FILE_MODE_SAVE_FILE
_dialog.access = _dialog.ACCESS_FILESYSTEM
# ------------------------------------------------------------------------------
@ -127,6 +144,11 @@ func _init(cont):
_base_control.add_child(lbl)
func _notification(what):
if what == NOTIFICATION_PREDELETE:
_base_control.free()
# ------------------
# Private
# ------------------
@ -134,7 +156,7 @@ func _new_row(key, disp_text, value_ctrl, hint):
var ctrl = _base_control.duplicate()
var lbl = ctrl.get_child(0)
lbl.hint_tooltip = hint
lbl.tooltip_text = hint
lbl.text = disp_text
_base_container.add_child(ctrl)
@ -167,7 +189,7 @@ func _add_number(key, value, disp_text, v_min, v_max, hint = ""):
value_ctrl.max_value = v_max
_wire_select_on_focus(value_ctrl.get_line_edit())
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_select(key, value, values, disp_text, hint = ""):
@ -180,7 +202,7 @@ func _add_select(key, value, values, disp_text, hint = ""):
value_ctrl.selected = select_idx
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_value(key, value, disp_text, hint = ""):
@ -189,14 +211,14 @@ func _add_value(key, value, disp_text, hint = ""):
value_ctrl.text = value
_wire_select_on_focus(value_ctrl)
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_boolean(key, value, disp_text, hint = ""):
var value_ctrl = CheckBox.new()
value_ctrl.button_pressed = value
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_directory(key, value, disp_text, hint = ""):
@ -205,7 +227,7 @@ func _add_directory(key, value, disp_text, hint = ""):
value_ctrl.text = value
_wire_select_on_focus(value_ctrl.get_line_edit())
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_file(key, value, disp_text, hint = ""):
@ -214,7 +236,16 @@ func _add_file(key, value, disp_text, hint = ""):
value_ctrl.text = value
_wire_select_on_focus(value_ctrl.get_line_edit())
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_save_file_anywhere(key, value, disp_text, hint = ""):
var value_ctrl = SaveFileAnywhere.new()
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.text = value
_wire_select_on_focus(value_ctrl.get_line_edit())
return _new_row(key, disp_text, value_ctrl, hint)
func _add_color(key, value, disp_text, hint = ""):
@ -222,7 +253,7 @@ func _add_color(key, value, disp_text, hint = ""):
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.color = value
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
func _add_vector2(key, value, disp_text, hint = ""):
@ -232,7 +263,7 @@ func _add_vector2(key, value, disp_text, hint = ""):
_wire_select_on_focus(value_ctrl.x_spin.get_line_edit())
_wire_select_on_focus(value_ctrl.y_spin.get_line_edit())
_new_row(key, disp_text, value_ctrl, hint)
return _new_row(key, disp_text, value_ctrl, hint)
# -----------------------------
@ -242,7 +273,6 @@ func _add_vector2(key, value, disp_text, hint = ""):
# Events
# ------------------
func _wire_select_on_focus(which):
pass
which.connect("focus_entered", _on_ctrl_focus_highlight.bind(which))
which.connect("focus_exited", _on_ctrl_focus_unhighlight.bind(which))
@ -273,8 +303,7 @@ func get_config_issues():
var path = _cfg_ctrls[key].text
if path != null and path != "":
has_directory = true
var dir = DirAccess.open(".")
if !dir.dir_exists(path):
if !DirAccess.dir_exists_absolute(path):
to_return.append(str("Test directory ", path, " does not exist."))
if !has_directory:
@ -286,8 +315,23 @@ func get_config_issues():
return to_return
# --------------
# SUPER dumb but VERY fun hack to hide settings. The various _add methods will
# return what they add. If you want to hide it, just assign the result to this.
# YES, I could have just put .visible at the end, but I didn't think of that
# until just now, and this was fun, non-permanent and the .visible at the end
# isn't as obvious as hide_this =
#
# Also, we can't just skip adding the controls because other things are looking
# for them and things start to blow up if you don't add them.
var hide_this = null:
set(val):
val.visible = false
# --------------
func set_options(options):
_add_title("Settings")
_add_title("Settings") # ----------------------------------
_add_number(
"log_level",
options.log_level,
@ -321,26 +365,48 @@ func set_options(options):
"Exit on Success",
"Exit if there are no failures. Does nothing if 'Exit on Finish' is enabled."
)
var ds = _add_select(
"double_strategy",
"Script Only",
["Include Native", "Script Only"],
"Double Strategy",
(
'"Include Native" will include native methods in Doubles. "Script Only" will not. '
+ "\n"
+ "The native method override warning is disabled when creating Doubles."
+ "\n"
+ "This is the default, you can override this at the script level or when creating doubles."
)
)
_cfg_ctrls["double_strategy"].selected = GutUtils.get_enum_value(
options.double_strategy, GutUtils.DOUBLE_STRATEGY, GutUtils.DOUBLE_STRATEGY.SCRIPT_ONLY
)
_add_boolean(
"errors_cause_failure",
!options.errors_do_not_cause_failure,
"Errors cause failures.",
"When GUT generates an error (not an engine error) it causes tests to fail."
)
_add_title("Panel Output")
_add_title("Panel Output") # ----------------------------------
_add_select(
"output_font_name",
options.panel_options.font_name,
options.panel_options.output_font_name,
_avail_fonts,
"Font",
"The name of the font to use when running tests and in the output panel to the left."
)
_add_number(
"output_font_size",
options.panel_options.font_size,
options.panel_options.output_font_size,
"Font Size",
5,
100,
"The font size to use when running tests and in the output panel to the left."
)
_add_title("Runner Window")
_add_boolean(
_add_title("Runner Window") # ----------------------------------
hide_this = _add_boolean(
"gut_on_top",
options.gut_on_top,
"On Top",
@ -349,7 +415,7 @@ func set_options(options):
_add_number(
"opacity", options.opacity, "Opacity", 0, 100, "The opacity of GUT when tests are running."
)
_add_boolean(
hide_this = _add_boolean(
"should_maximize",
options.should_maximize,
"Maximize",
@ -362,7 +428,7 @@ func set_options(options):
"The runner will be in compact mode. This overrides Maximize."
)
_add_title("Runner Appearance")
_add_title("Runner Appearance") # ----------------------------------
_add_select(
"font_name",
options.font_name,
@ -378,7 +444,7 @@ func set_options(options):
100,
"The font size for text output in the Gut Runner."
)
_add_color(
hide_this = _add_color(
"font_color",
options.font_color,
"Font Color",
@ -397,7 +463,7 @@ func set_options(options):
"Disable formatting and colors used in the Runner. Does not affect panel output."
)
_add_title("Test Directories")
_add_title("Test Directories") # ----------------------------------
_add_boolean(
"include_subdirs",
options.include_subdirs,
@ -411,11 +477,11 @@ func set_options(options):
_add_directory(str("directory_", i), value, str("Directory ", i))
_add_title("XML Output")
_add_value(
_add_title("XML Output") # ----------------------------------
_add_save_file_anywhere(
"junit_xml_file",
options.junit_xml_file,
"Output Path3D",
"Output Path",
(
"Path3D and filename where GUT should create a JUnit compliant XML file. "
+ "This file will contain the results of the last test run. To avoid "
@ -429,7 +495,7 @@ func set_options(options):
"Include a timestamp in the filename so that each run gets its own xml file."
)
_add_title("Hooks")
_add_title("Hooks") # ----------------------------------
_add_file(
"pre_run_script",
options.pre_run_script,
@ -443,7 +509,7 @@ func set_options(options):
"This script will be run by GUT after all tests are run."
)
_add_title("Misc")
_add_title("Misc") # ----------------------------------
_add_value(
"prefix", options.prefix, "Script Prefix", "The filename prefix for all test scripts."
)
@ -466,7 +532,7 @@ func set_options(options):
_cfg_ctrls.paint_after.step = .05
_cfg_ctrls.paint_after.value = options.paint_after
print("paint after = ", options.paint_after)
print("GUT config loaded")
func get_options(base_opts):
@ -478,11 +544,13 @@ func get_options(base_opts):
to_return.hide_orphans = _cfg_ctrls.hide_orphans.button_pressed
to_return.should_exit = _cfg_ctrls.should_exit.button_pressed
to_return.should_exit_on_success = _cfg_ctrls.should_exit_on_success.button_pressed
to_return.double_strategy = _cfg_ctrls.double_strategy.selected
to_return.errors_do_not_cause_failure = !_cfg_ctrls.errors_cause_failure.button_pressed
#Output
to_return.panel_options.font_name = (_cfg_ctrls.output_font_name.get_item_text(
to_return.panel_options.font_name = _cfg_ctrls.output_font_name.get_item_text(
_cfg_ctrls.output_font_name.selected
))
)
to_return.panel_options.font_size = _cfg_ctrls.output_font_size.value
# Runner Appearance

238
addons/gut/gui/gut_gui.gd Normal file
View file

@ -0,0 +1,238 @@
extends Control
# ##############################################################################
# This is the decoupled GUI for gut.gd
#
# This is a "generic" interface between a GUI and gut.gd. It assumes there are
# certain controls with specific names. It will then interact with those
# controls based on signals emitted from gut.gd in order to give the user
# feedback about the progress of the test run and the results.
#
# Optional controls are marked as such in the _ctrls dictionary. The names
# of the controls can be found in _populate_ctrls.
# ##############################################################################
var _gut = null
var _ctrls = {
btn_continue = null,
path_dir = null,
path_file = null,
prog_script = null,
prog_test = null,
rtl = null, # optional
rtl_bg = null, # required if rtl exists
switch_modes = null,
time_label = null,
title = null,
title_bar = null,
}
var _title_mouse = {down = false}
var _resize_mouse = {down = false}
var _resize_left_mouse = {down = false}
signal switch_modes
var _max_position = Vector2(100, 100)
var _utils = null
func _ready():
_populate_ctrls()
_ctrls.btn_continue.visible = false
_ctrls.btn_continue.pressed.connect(_on_continue_pressed)
_ctrls.switch_modes.pressed.connect(_on_switch_modes_pressed)
_ctrls.title_bar.gui_input.connect(_on_title_bar_input)
_ctrls.prog_script.value = 0
_ctrls.prog_test.value = 0
_ctrls.path_dir.text = ""
_ctrls.path_file.text = ""
_ctrls.time_label.text = ""
_max_position = get_display_size() - Vector2(30, _ctrls.title_bar.size.y)
func _process(_delta):
if _gut != null and _gut.is_running():
set_elapsed_time(_gut.get_elapsed_time())
# ------------------
# Private
# ------------------
func get_display_size():
return get_viewport().get_visible_rect().size
func _populate_ctrls():
# Brute force, but flexible. This allows for all the controls to exist
# anywhere, and as long as they all have the right name, they will be
# found.
_ctrls.btn_continue = _get_first_child_named("Continue", self)
_ctrls.path_dir = _get_first_child_named("Path", self)
_ctrls.path_file = _get_first_child_named("File", self)
_ctrls.prog_script = _get_first_child_named("ProgressScript", self)
_ctrls.prog_test = _get_first_child_named("ProgressTest", self)
_ctrls.rtl = _get_first_child_named("TestOutput", self)
_ctrls.rtl_bg = _get_first_child_named("OutputBG", self)
_ctrls.switch_modes = _get_first_child_named("SwitchModes", self)
_ctrls.time_label = _get_first_child_named("TimeLabel", self)
_ctrls.title = _get_first_child_named("Title", self)
_ctrls.title_bar = _get_first_child_named("TitleBar", self)
func _get_first_child_named(obj_name, parent_obj):
if parent_obj == null:
return null
var kids = parent_obj.get_children()
var index = 0
var to_return = null
while index < kids.size() and to_return == null:
if str(kids[index]).find(str(obj_name, ":")) != -1:
to_return = kids[index]
else:
to_return = _get_first_child_named(obj_name, kids[index])
if to_return == null:
index += 1
return to_return
# ------------------
# Events
# ------------------
func _on_title_bar_input(event: InputEvent):
if event is InputEventMouseMotion:
if _title_mouse.down:
position += event.relative
position.x = clamp(position.x, 0, _max_position.x)
position.y = clamp(position.y, 0, _max_position.y)
elif event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
_title_mouse.down = event.pressed
func _on_continue_pressed():
_gut.end_teardown_pause()
func _on_gut_start_run():
if _ctrls.rtl != null:
_ctrls.rtl.clear()
set_num_scripts(_gut.get_test_collector().scripts.size())
func _on_gut_end_run():
_ctrls.prog_test.value = _ctrls.prog_test.max_value
_ctrls.prog_script.value = _ctrls.prog_script.max_value
func _on_gut_start_script(script_obj):
next_script(script_obj.get_full_name(), script_obj.tests.size())
func _on_gut_end_script():
pass
func _on_gut_start_test(test_name):
next_test(test_name)
func _on_gut_end_test():
pass
func _on_gut_start_pause():
pause_before_teardown()
func _on_gut_end_pause():
_ctrls.btn_continue.visible = false
func _on_switch_modes_pressed():
switch_modes.emit()
# ------------------
# Public
# ------------------
func set_num_scripts(val):
_ctrls.prog_script.value = 0
_ctrls.prog_script.max_value = val
func next_script(path, num_tests):
_ctrls.prog_script.value += 1
_ctrls.prog_test.value = 0
_ctrls.prog_test.max_value = num_tests
_ctrls.path_dir.text = path.get_base_dir()
_ctrls.path_file.text = path.get_file()
func next_test(test_name):
_ctrls.prog_test.value += 1
func pause_before_teardown():
_ctrls.btn_continue.visible = true
func set_gut(g):
if _gut == g:
return
_gut = g
g.start_run.connect(_on_gut_start_run)
g.end_run.connect(_on_gut_end_run)
g.start_script.connect(_on_gut_start_script)
g.end_script.connect(_on_gut_end_script)
g.start_test.connect(_on_gut_start_test)
g.end_test.connect(_on_gut_end_test)
g.start_pause_before_teardown.connect(_on_gut_start_pause)
g.end_pause_before_teardown.connect(_on_gut_end_pause)
func get_gut():
return _gut
func get_textbox():
return _ctrls.rtl
func set_elapsed_time(t):
_ctrls.time_label.text = str("%6.1f" % t, "s")
func set_bg_color(c):
_ctrls.rtl_bg.color = c
func set_title(text):
_ctrls.title.text = text
func to_top_left():
self.position = Vector2(5, 5)
func to_bottom_right():
var win_size = get_display_size()
self.position = win_size - Vector2(self.size) - Vector2(5, 5)
func align_right():
var win_size = get_display_size()
self.position.x = win_size.x - self.size.x - 5
self.position.y = 5
self.size.y = win_size.y - 10

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/play.png-5c90e88e8136487a183a099d67a7de24.cte
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -1,5 +1,5 @@
# Holds weakrefs to a ScriptTextEditor and related children nodes
# that might be useful. Though the TextEdit is really the only one, but
# that might be useful. Though the CodeEdit is really the only one, but
# since the tree may change, the first TextEdit under a CodeTextEditor is
# the one we use...so we hold a ref to the CodeTextEditor too.
class ScriptEditorControlRef:
@ -10,6 +10,7 @@ class ScriptEditorControlRef:
func _init(script_edit):
_script_editor = weakref(script_edit)
_populate_controls()
# print("_script_editor = ", script_edit, ' vis = ', is_visible())
func _populate_controls():
# who knows if the tree will change so get the first instance of each
@ -27,7 +28,7 @@ class ScriptEditorControlRef:
var to_return = null
while index < kids.size() and to_return == null:
if str(kids[index]).find(str("[", obj_name)) != -1:
if str(kids[index]).find(str("<", obj_name)) != -1:
to_return = kids[index]
else:
to_return = _get_first_child_named(obj_name, kids[index])
@ -79,7 +80,7 @@ func _init(script_edit):
func _is_script_editor(obj):
return str(obj).find("[ScriptTextEditor") != -1
return str(obj).find("<ScriptTextEditor") != -1
# Find the first ScriptTextEditor and then get its parent. Done this way
@ -106,14 +107,19 @@ func _populate_editors():
# easier than trying to find a place where it could be used by both.
func _get_first_child_of_type_name(obj_name, parent_obj):
if parent_obj == null:
# print('aborting search for ', obj_name, ' parent is null')
return null
var kids = parent_obj.get_children()
var index = 0
var to_return = null
var search_for = str("<", obj_name)
# print('searching for ', search_for, ' in ', parent_obj, ' kids ', kids.size())
while index < kids.size() and to_return == null:
if str(kids[index]).find(str("[", obj_name)) != -1:
var this_one = str(kids[index])
# print(search_for, ' :: ', this_one)
if this_one.find(search_for) != -1:
to_return = kids[index]
else:
to_return = _get_first_child_of_type_name(obj_name, kids[index])
@ -140,10 +146,13 @@ func _get_class_name_from_line(text):
func refresh():
if _script_editors_parent == null:
_find_script_editors_parent()
# print("script editors parent = ", _script_editors_parent)
if _script_editors_parent != null:
_populate_editors()
# print("script editor controls = ", _script_editor_controls)
func get_current_text_edit():
var cur_script_editor = null