upgrade gut

This commit is contained in:
anyreso 2026-02-19 03:14:22 -05:00
parent 6e724f67fe
commit 82aeebfd35
201 changed files with 8547 additions and 3871 deletions

View file

@ -1,139 +0,0 @@
@tool
extends Window
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
var default_path = GutEditorGlobals.editor_shortcuts_path
@onready var _ctrls = {
run_all = $Layout/CRunAll/ShortcutButton,
run_current_script = $Layout/CRunCurrentScript/ShortcutButton,
run_current_inner = $Layout/CRunCurrentInner/ShortcutButton,
run_current_test = $Layout/CRunCurrentTest/ShortcutButton,
panel_button = $Layout/CPanelButton/ShortcutButton,
}
var _user_prefs = GutEditorGlobals.user_prefs
func _ready():
for key in _ctrls:
var sc_button = _ctrls[key]
sc_button.connect('start_edit', _on_edit_start.bind(sc_button))
sc_button.connect('end_edit', _on_edit_end)
# show dialog when running scene from editor.
if(get_parent() == get_tree().root):
popup_centered()
func _cancel_all():
_ctrls.run_all.cancel()
_ctrls.run_current_script.cancel()
_ctrls.run_current_inner.cancel()
_ctrls.run_current_test.cancel()
_ctrls.panel_button.cancel()
# ------------
# Events
# ------------
func _on_Hide_pressed():
hide()
func _on_edit_start(which):
for key in _ctrls:
var sc_button = _ctrls[key]
if(sc_button != which):
sc_button.disable_set(true)
sc_button.disable_clear(true)
func _on_edit_end():
for key in _ctrls:
var sc_button = _ctrls[key]
sc_button.disable_set(false)
sc_button.disable_clear(false)
func _on_popup_hide():
_cancel_all()
# ------------
# Public
# ------------
func get_run_all():
return _ctrls.run_all.get_shortcut()
func get_run_current_script():
return _ctrls.run_current_script.get_shortcut()
func get_run_current_inner():
return _ctrls.run_current_inner.get_shortcut()
func get_run_current_test():
return _ctrls.run_current_test.get_shortcut()
func get_panel_button():
return _ctrls.panel_button.get_shortcut()
func _set_pref_value(pref, button):
pref.value = {shortcut = button.get_shortcut().events}
func save_shortcuts():
save_shortcuts_to_file(default_path)
func save_shortcuts_to_editor_settings():
_set_pref_value(_user_prefs.shortcut_run_all, _ctrls.run_all)
_set_pref_value(_user_prefs.shortcut_run_current_script, _ctrls.run_current_script)
_set_pref_value(_user_prefs.shortcut_run_current_inner, _ctrls.run_current_inner)
_set_pref_value(_user_prefs.shortcut_run_current_test, _ctrls.run_current_test)
_set_pref_value(_user_prefs.shortcut_panel_button, _ctrls.panel_button)
_user_prefs.save_it()
func save_shortcuts_to_file(path):
var f = ConfigFile.new()
f.set_value('main', 'run_all', _ctrls.run_all.get_shortcut())
f.set_value('main', 'run_current_script', _ctrls.run_current_script.get_shortcut())
f.set_value('main', 'run_current_inner', _ctrls.run_current_inner.get_shortcut())
f.set_value('main', 'run_current_test', _ctrls.run_current_test.get_shortcut())
f.set_value('main', 'panel_button', _ctrls.panel_button.get_shortcut())
f.save(path)
func _load_shortcut_from_pref(user_pref):
var to_return = Shortcut.new()
# value with be _user_prefs.EMPTY which is a string when the value
# has not been set.
if(typeof(user_pref.value) == TYPE_DICTIONARY):
to_return.events.append(user_pref.value.shortcut[0])
# to_return = user_pref.value
return to_return
func load_shortcuts():
load_shortcuts_from_file(default_path)
func load_shortcuts_from_editor_settings():
var empty = Shortcut.new()
_ctrls.run_all.set_shortcut(_load_shortcut_from_pref(_user_prefs.shortcut_run_all))
_ctrls.run_current_script.set_shortcut(_load_shortcut_from_pref(_user_prefs.shortcut_run_current_script))
_ctrls.run_current_inner.set_shortcut(_load_shortcut_from_pref(_user_prefs.shortcut_run_current_inner))
_ctrls.run_current_test.set_shortcut(_load_shortcut_from_pref(_user_prefs.shortcut_run_current_test))
_ctrls.panel_button.set_shortcut(_load_shortcut_from_pref(_user_prefs.shortcut_panel_button))
func load_shortcuts_from_file(path):
var f = ConfigFile.new()
var empty = Shortcut.new()
f.load(path)
_ctrls.run_all.set_shortcut(f.get_value('main', 'run_all', empty))
_ctrls.run_current_script.set_shortcut(f.get_value('main', 'run_current_script', empty))
_ctrls.run_current_inner.set_shortcut(f.get_value('main', 'run_current_inner', empty))
_ctrls.run_current_test.set_shortcut(f.get_value('main', 'run_current_test', empty))
_ctrls.panel_button.set_shortcut(f.get_value('main', 'panel_button', empty))

View file

@ -1 +0,0 @@
uid://dsmt384dwo7em

View file

@ -1,153 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://bsk32dh41b4gs"]
[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="Popup"]
title = "Shortcuts"
size = Vector2i(500, 350)
visible = true
exclusive = true
unresizable = false
borderless = 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
[node name="TopPad" type="CenterContainer" parent="Layout"]
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="Label2" type="Label" parent="Layout"]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
text = "Always Active"
[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)
[node name="CPanelButton" type="HBoxContainer" parent="Layout"]
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CPanelButton"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Show/Hide GUT Panel"
[node name="ShortcutButton" parent="Layout/CPanelButton" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="GutPanelPad" type="CenterContainer" parent="Layout"]
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="Label" type="Label" parent="Layout"]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
text = "Only Active When GUT Panel Shown"
[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)
[node name="TopPad2" type="CenterContainer" parent="Layout"]
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="CRunAll" type="HBoxContainer" parent="Layout"]
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunAll"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run All"
[node name="ShortcutButton" parent="Layout/CRunAll" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CRunCurrentScript" type="HBoxContainer" parent="Layout"]
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunCurrentScript"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Script"
[node name="ShortcutButton" parent="Layout/CRunCurrentScript" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CRunCurrentInner" type="HBoxContainer" parent="Layout"]
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunCurrentInner"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Inner Class"
[node name="ShortcutButton" parent="Layout/CRunCurrentInner" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CRunCurrentTest" type="HBoxContainer" parent="Layout"]
layout_mode = 2
[node name="Label" type="Label" parent="Layout/CRunCurrentTest"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Test"
[node name="ShortcutButton" parent="Layout/CRunCurrentTest" instance=ExtResource("1")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CenterContainer2" type="CenterContainer" parent="Layout"]
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ShiftDisclaimer" type="Label" parent="Layout"]
layout_mode = 2
text = "\"Shift\" cannot be the only modifier for a shortcut."
[node name="HBoxContainer" type="HBoxContainer" parent="Layout"]
layout_mode = 2
[node name="CenterContainer" type="CenterContainer" parent="Layout/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Hide" type="Button" parent="Layout/HBoxContainer"]
custom_minimum_size = Vector2(60, 30)
layout_mode = 2
text = "Close"
[node name="BottomPad" type="CenterContainer" parent="Layout"]
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
size_flags_horizontal = 3
[connection signal="popup_hide" from="." to="." method="_on_popup_hide"]
[connection signal="pressed" from="Layout/HBoxContainer/Hide" to="." method="_on_Hide_pressed"]

View file

@ -0,0 +1,13 @@
[gd_resource type="Theme" format=3 uid="uid://dssgvu257o1si"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_u716c"]
bg_color = Color(0.43137255, 0.8784314, 0.6156863, 0.5254902)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ht2pf"]
bg_color = Color(0, 0.44705883, 0.23921569, 1)
[resource]
Button/colors/font_hover_pressed_color = Color(1, 1, 1, 1)
Button/colors/font_pressed_color = Color(1, 1, 1, 1)
Button/styles/hover = SubResource("StyleBoxFlat_u716c")
Button/styles/pressed = SubResource("StyleBoxFlat_ht2pf")

View file

@ -2,53 +2,75 @@
extends Control
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
var TestScript = load('res://addons/gut/test.gd')
var GutConfigGui = load('res://addons/gut/gui/gut_config_gui.gd')
var ScriptTextEditors = load('res://addons/gut/gui/script_text_editor_controls.gd')
var AboutWindow = load("res://addons/gut/gui/about.tscn")
var _interface = null;
var _is_running = false;
var _is_running = false :
set(val):
_is_running = val
_disable_run_buttons(_is_running)
var _gut_config = load('res://addons/gut/gut_config.gd').new()
var _gut_config_gui = null
var _gut_plugin = null
var _light_color = Color(0, 0, 0, .5)
var _light_color = Color(0, 0, 0, .5) :
set(val):
_light_color = val
if(is_inside_tree()):
_ctrls.light.queue_redraw()
var _panel_button = null
var _last_selected_path = null
var _user_prefs = null
var _shell_out_panel = null
var menu_manager = null :
set(val):
menu_manager = val
if(val != null):
_apply_shortcuts()
menu_manager.toggle_windowed.connect(_on_toggle_windowed)
menu_manager.about.connect(show_about)
menu_manager.run_all.connect(_run_all)
menu_manager.show_gut.connect(_on_show_gut)
@onready var _ctrls = {
output = $layout/RSplit/CResults/TabBar/OutputText.get_rich_text_edit(),
output_ctrl = $layout/RSplit/CResults/TabBar/OutputText,
about = %ExtraButtons/About,
light = %StatusIndicator,
output_button = %ExtraButtons/OutputBtn,
run_button = $layout/ControlBar/RunAll,
shortcuts_button = $layout/ControlBar/Shortcuts,
settings_button = $layout/ControlBar/Settings,
run_results_button = $layout/ControlBar/RunResultsBtn,
output_button = $layout/ControlBar/OutputBtn,
settings = $layout/RSplit/sc/Settings,
shortcut_dialog = $BottomPanelShortcuts,
light = $layout/RSplit/CResults/ControlBar/Light3D,
results = {
bar = $layout/RSplit/CResults/ControlBar,
passing = $layout/RSplit/CResults/ControlBar/Passing/value,
failing = $layout/RSplit/CResults/ControlBar/Failing/value,
pending = $layout/RSplit/CResults/ControlBar/Pending/value,
errors = $layout/RSplit/CResults/ControlBar/Errors/value,
warnings = $layout/RSplit/CResults/ControlBar/Warnings/value,
orphans = $layout/RSplit/CResults/ControlBar/Orphans/value
},
run_externally_dialog = $ShellOutOptions,
run_mode = %ExtraButtons/RunMode,
run_at_cursor = $layout/ControlBar/RunAtCursor,
run_results = $layout/RSplit/CResults/TabBar/RunResults
run_results_button = %ExtraButtons/RunResultsBtn,
settings = $layout/RSplit/sc/Settings,
settings_button = %ExtraButtons/Settings,
shortcut_dialog = $ShortcutDialog,
shortcuts_button = %ExtraButtons/Shortcuts,
results = {
bar = $layout/ControlBar2,
errors = %errors_value,
failing = %failing_value,
orphans = %orphans_value,
passing = %passing_value,
pending = %pending_value,
warnings = %warnings_value,
},
}
func _init():
pass
@onready var results_v_split = %VSplitResults
@onready var results_h_split = %HSplitResults
@onready var results_tree = %RunResults
@onready var results_text = %OutputText
@onready var make_floating_btn = %MakeFloating
func _ready():
if(get_parent() is SubViewport):
return
GutEditorGlobals.create_temp_directory()
_user_prefs = GutEditorGlobals.user_prefs
@ -59,45 +81,75 @@ func _ready():
_gut_config.load_options(GutEditorGlobals.editor_run_gut_config_path)
_gut_config_gui.set_options(_gut_config.options)
_apply_options_to_controls()
_ctrls.shortcuts_button.icon = get_theme_icon('Shortcut', 'EditorIcons')
_ctrls.settings_button.icon = get_theme_icon('Tools', 'EditorIcons')
_ctrls.run_results_button.icon = get_theme_icon('AnimationTrackGroup', 'EditorIcons') # Tree
_ctrls.output_button.icon = get_theme_icon('Font', 'EditorIcons')
make_floating_btn.icon = get_theme_icon("MakeFloating", 'EditorIcons')
make_floating_btn.text = ''
_ctrls.about.icon = get_theme_icon('Info', 'EditorIcons')
_ctrls.about.text = ''
_ctrls.run_mode.icon = get_theme_icon("ViewportSpeed", 'EditorIcons')
_ctrls.run_results.set_output_control(_ctrls.output_ctrl)
results_tree.set_output_control(results_text)
var check_import = load('res://addons/gut/images/red.png')
var check_import = load('res://addons/gut/images/HSplitContainer.svg')
if(check_import == null):
_ctrls.run_results.add_centered_text("GUT got some new images that are not imported yet. Please restart Godot.")
results_tree.add_centered_text("GUT got some new images that are not imported yet. Please restart Godot.")
print('GUT got some new images that are not imported yet. Please restart Godot.')
else:
_ctrls.run_results.add_centered_text("Let's run some tests!")
results_tree.add_centered_text("Let's run some tests!")
_ctrls.run_externally_dialog.load_from_file()
_apply_options_to_controls()
results_vert_layout()
func _apply_options_to_controls():
hide_settings(_user_prefs.hide_settings.value)
hide_result_tree(_user_prefs.hide_result_tree.value)
hide_output_text(_user_prefs.hide_output_text.value)
_ctrls.run_results.set_show_orphans(!_gut_config.options.hide_orphans)
func _process(delta):
func _process(_delta):
if(_is_running):
if(!_interface.is_playing_scene()):
if(_ctrls.run_externally_dialog.should_run_externally()):
if(!is_instance_valid(_shell_out_panel)):
_is_running = false
show_me()
elif(!_interface.is_playing_scene()):
_is_running = false
_ctrls.output_ctrl.add_text("\ndone")
results_text.add_text("\ndone")
load_result_output()
_gut_plugin.make_bottom_panel_item_visible(self)
show_me()
# ---------------
# Private
# ---------------
func _apply_options_to_controls():
hide_settings(_user_prefs.hide_settings.value)
hide_result_tree(_user_prefs.hide_result_tree.value)
hide_output_text(_user_prefs.hide_output_text.value)
results_tree.set_show_orphans(!_gut_config.options.hide_orphans)
var shell_dialog_size = _user_prefs.run_externally_options_dialog_size.value
func load_shortcuts():
_ctrls.shortcut_dialog.load_shortcuts()
_apply_shortcuts()
if(shell_dialog_size != Vector2i(-1, -1)):
_ctrls.run_externally_dialog.size = Vector2i(shell_dialog_size)
if(_user_prefs.shortcuts_dialog_size.value != Vector2i(-1, -1)):
_ctrls.shortcut_dialog.size = _user_prefs.shortcuts_dialog_size.value
var mode_ind = 'Ed'
if(_ctrls.run_externally_dialog.run_mode == _ctrls.run_externally_dialog.RUN_MODE_BLOCKING):
mode_ind = 'ExB'
elif(_ctrls.run_externally_dialog.run_mode == _ctrls.run_externally_dialog.RUN_MODE_NON_BLOCKING):
mode_ind = 'ExN'
_ctrls.run_mode.text = mode_ind
_ctrls.run_at_cursor.apply_gut_config(_gut_config)
func _disable_run_buttons(should):
_ctrls.run_button.disabled = should
_ctrls.run_at_cursor.disabled = should
func _is_test_script(script):
@ -109,22 +161,31 @@ func _is_test_script(script):
func _show_errors(errs):
_ctrls.output_ctrl.clear()
results_text.clear()
var text = "Cannot run tests, you have a configuration error:\n"
for e in errs:
text += str('* ', e, "\n")
text += "Check your settings ----->"
_ctrls.output_ctrl.add_text(text)
results_text.add_text(text)
hide_output_text(false)
hide_settings(false)
func _save_config():
func _save_user_prefs():
_user_prefs.hide_settings.value = !_ctrls.settings_button.button_pressed
_user_prefs.hide_result_tree.value = !_ctrls.run_results_button.button_pressed
_user_prefs.hide_output_text.value = !_ctrls.output_button.button_pressed
_user_prefs.shortcuts_dialog_size.value = _ctrls.shortcut_dialog.size
_user_prefs.run_externally.value = _ctrls.run_externally_dialog.run_mode != _ctrls.run_externally_dialog.RUN_MODE_EDITOR
_user_prefs.run_externally_options_dialog_size.value = _ctrls.run_externally_dialog.size
_user_prefs.save_it()
func _save_config():
_save_user_prefs()
_gut_config.options = _gut_config_gui.get_options(_gut_config.options)
var w_result = _gut_config.write_options(GutEditorGlobals.editor_run_gut_config_path)
if(w_result != OK):
@ -133,8 +194,25 @@ func _save_config():
_gut_config_gui.mark_saved()
func _run_externally():
_shell_out_panel = GutUtils.RunExternallyScene.instantiate()
_shell_out_panel.bottom_panel = self
_shell_out_panel.blocking_mode = _ctrls.run_externally_dialog.run_mode
_shell_out_panel.additional_arguments = _ctrls.run_externally_dialog.get_additional_arguments_array()
add_child(_shell_out_panel)
_shell_out_panel.run_tests()
func _run_tests():
show_me()
if(_is_running):
push_error("GUT: Cannot run tests, tests are already running.")
return
clear_results()
GutEditorGlobals.create_temp_directory()
_light_color = Color.BLUE
var issues = _gut_config_gui.get_config_issues()
if(issues.size() > 0):
@ -142,29 +220,43 @@ func _run_tests():
return
write_file(GutEditorGlobals.editor_run_bbcode_results_path, 'Run in progress')
write_file(GutEditorGlobals.editor_run_json_results_path, '')
_save_config()
_apply_options_to_controls()
_ctrls.output_ctrl.clear()
_ctrls.run_results.clear()
_ctrls.run_results.add_centered_text('Running...')
results_text.clear()
results_tree.clear()
results_tree.add_centered_text('Running...')
_interface.play_custom_scene('res://addons/gut/gui/run_from_editor.tscn')
_is_running = true
_ctrls.output_ctrl.add_text('Running...')
results_text.add_text('Running...')
if(_ctrls.run_externally_dialog.should_run_externally()):
_gut_plugin.make_bottom_panel_item_visible(self)
_run_externally()
else:
_interface.play_custom_scene('res://addons/gut/gui/run_from_editor.tscn')
func _apply_shortcuts():
_ctrls.run_button.shortcut = _ctrls.shortcut_dialog.get_run_all()
if(menu_manager != null):
menu_manager.apply_gut_shortcuts(_ctrls.shortcut_dialog)
_ctrls.run_button.shortcut = \
_ctrls.shortcut_dialog.scbtn_run_all.get_shortcut()
_ctrls.run_at_cursor.get_script_button().shortcut = \
_ctrls.shortcut_dialog.get_run_current_script()
_ctrls.shortcut_dialog.scbtn_run_current_script.get_shortcut()
_ctrls.run_at_cursor.get_inner_button().shortcut = \
_ctrls.shortcut_dialog.get_run_current_inner()
_ctrls.shortcut_dialog.scbtn_run_current_inner.get_shortcut()
_ctrls.run_at_cursor.get_test_button().shortcut = \
_ctrls.shortcut_dialog.get_run_current_test()
_panel_button.shortcut = _ctrls.shortcut_dialog.get_panel_button()
_ctrls.shortcut_dialog.scbtn_run_current_test.get_shortcut()
# Took this out because it seems to break using the shortcut when docked.
# Though it does allow the shortcut to work when windowed. Shortcuts
# are weird.
# make_floating_btn.shortcut = \
# _ctrls.shortcut_dialog.scbtn_windowed.get_shortcut()
if(get_parent() is EditorDock):
get_parent().dock_shortcut = _ctrls.shortcut_dialog.scbtn_panel.get_shortcut()
func _run_all():
@ -187,11 +279,6 @@ func _on_Light_draw():
l.draw_circle(Vector2(l.size.x / 2, l.size.y / 2), l.size.x / 2, _light_color)
func _on_editor_script_changed(script):
if(script):
set_current_script(script)
func _on_RunAll_pressed():
_run_all()
@ -199,14 +286,17 @@ func _on_RunAll_pressed():
func _on_Shortcuts_pressed():
_ctrls.shortcut_dialog.popup_centered()
func _on_bottom_panel_shortcuts_visibility_changed():
func _on_sortcut_dialog_confirmed() -> void:
_apply_shortcuts()
_ctrls.shortcut_dialog.save_shortcuts()
_save_user_prefs()
func _on_RunAtCursor_run_tests(what):
_gut_config.options.selected = what.script
_gut_config.options.inner_class = what.inner_class
_gut_config.options.unit_test_name = what.test_method
_gut_config.options.unit_test_name = what.method
_run_tests()
@ -231,11 +321,51 @@ func _on_RunResultsBtn_pressed():
func _on_UseColors_pressed():
pass
func _on_shell_out_options_confirmed() -> void:
_ctrls.run_externally_dialog.save_to_file()
_save_user_prefs()
_apply_options_to_controls()
func _on_run_mode_pressed() -> void:
_ctrls.run_externally_dialog.popup_centered()
func _on_toggle_windowed():
_gut_plugin.toggle_windowed()
func _on_to_window_pressed() -> void:
_gut_plugin.toggle_windowed()
func _on_show_gut() -> void:
show_hide()
func _on_about_pressed() -> void:
show_about()
func _on_horiz_layout_pressed() -> void:
results_horiz_layout()
func _on_vert_layout_pressed() -> void:
results_vert_layout()
# ---------------
# Public
# ---------------
func load_shortcuts():
_ctrls.shortcut_dialog.load_shortcuts()
_apply_shortcuts()
func hide_result_tree(should):
_ctrls.run_results.visible = !should
results_tree.visible = !should
_ctrls.run_results_button.button_pressed = !should
@ -255,69 +385,84 @@ func hide_settings(should):
func hide_output_text(should):
$layout/RSplit/CResults/TabBar/OutputText.visible = !should
results_text.visible = !should
_ctrls.output_button.button_pressed = !should
func load_result_output():
_ctrls.output_ctrl.load_file(GutEditorGlobals.editor_run_bbcode_results_path)
func clear_results():
_light_color = Color(0, 0, 0, .5)
_ctrls.results.passing.text = "0"
_ctrls.results.passing.get_parent().visible = false
_ctrls.results.failing.text = "0"
_ctrls.results.failing.get_parent().visible = false
_ctrls.results.pending.text = "0"
_ctrls.results.pending.get_parent().visible = false
_ctrls.results.errors.text = "0"
_ctrls.results.errors.get_parent().visible = false
_ctrls.results.warnings.text = "0"
_ctrls.results.warnings.get_parent().visible = false
_ctrls.results.orphans.text = "0"
_ctrls.results.orphans.get_parent().visible = false
func load_result_json():
var summary = get_file_as_text(GutEditorGlobals.editor_run_json_results_path)
var test_json_conv = JSON.new()
if (test_json_conv.parse(summary) != OK):
return
var results = test_json_conv.get_data()
_ctrls.run_results.load_json_results(results)
results_tree.load_json_results(results)
var summary_json = results['test_scripts']['props']
_ctrls.results.passing.text = str(summary_json.passing)
_ctrls.results.passing.text = str(int(summary_json.passing))
_ctrls.results.passing.get_parent().visible = true
_ctrls.results.failing.text = str(summary_json.failures)
_ctrls.results.failing.text = str(int(summary_json.failures))
_ctrls.results.failing.get_parent().visible = true
_ctrls.results.pending.text = str(summary_json.pending)
_ctrls.results.pending.text = str(int(summary_json.pending) + int(summary_json.risky))
_ctrls.results.pending.get_parent().visible = _ctrls.results.pending.text != '0'
_ctrls.results.errors.text = str(summary_json.errors)
_ctrls.results.errors.text = str(int(summary_json.errors))
_ctrls.results.errors.get_parent().visible = _ctrls.results.errors.text != '0'
_ctrls.results.warnings.text = str(summary_json.warnings)
_ctrls.results.warnings.text = str(int(summary_json.warnings))
_ctrls.results.warnings.get_parent().visible = _ctrls.results.warnings.text != '0'
_ctrls.results.orphans.text = str(summary_json.orphans)
_ctrls.results.orphans.text = str(int(summary_json.orphans))
_ctrls.results.orphans.get_parent().visible = _ctrls.results.orphans.text != '0' and !_gut_config.options.hide_orphans
if(summary_json.tests == 0):
_light_color = Color(1, 0, 0, .75)
elif(summary_json.failures != 0):
_light_color = Color(1, 0, 0, .75)
elif(summary_json.pending != 0):
elif(summary_json.pending != 0 or summary_json.risky != 0):
_light_color = Color(1, 1, 0, .75)
else:
_light_color = Color(0, 1, 0, .75)
_ctrls.light.visible = true
_ctrls.light.queue_redraw()
func set_current_script(script):
if(script):
if(_is_test_script(script)):
var file = script.resource_path.get_file()
_last_selected_path = script.resource_path.get_file()
_ctrls.run_at_cursor.activate_for_script(script.resource_path)
func load_result_text():
results_text.load_file(GutEditorGlobals.editor_run_bbcode_results_path)
func load_result_output():
load_result_text()
load_result_json()
func set_interface(value):
_interface = value
_interface.get_script_editor().connect("editor_script_changed",Callable(self,'_on_editor_script_changed'))
var ste = ScriptTextEditors.new(_interface.get_script_editor())
_ctrls.run_results.set_interface(_interface)
_ctrls.run_results.set_script_text_editors(ste)
_ctrls.run_at_cursor.set_script_text_editors(ste)
set_current_script(_interface.get_script_editor().get_current_script())
results_tree.set_interface(_interface)
func set_plugin(value):
@ -327,9 +472,7 @@ func set_plugin(value):
func set_panel_button(value):
_panel_button = value
# ------------------------------------------------------------------------------
# Write a file.
# ------------------------------------------------------------------------------
func write_file(path, content):
var f = FileAccess.open(path, FileAccess.WRITE)
if(f != null):
@ -339,9 +482,6 @@ func write_file(path, content):
return FileAccess.get_open_error()
# ------------------------------------------------------------------------------
# Returns the text of a file or an empty string if the file could not be opened.
# ------------------------------------------------------------------------------
func get_file_as_text(path):
var to_return = ''
var f = FileAccess.open(path, FileAccess.READ)
@ -351,11 +491,66 @@ func get_file_as_text(path):
return to_return
# ------------------------------------------------------------------------------
# return if_null if value is null otherwise return value
# ------------------------------------------------------------------------------
func nvl(value, if_null):
if(value == null):
return if_null
func get_text_output_control():
return results_text
func add_output_text(text):
results_text.add_text(text)
func show_about():
var about = AboutWindow.instantiate()
add_child(about)
about.popup_centered()
about.confirmed.connect(about.queue_free)
func show_me():
get_parent().make_visible()
func show_hide():
if(owner is Window):
if(owner.has_focus()):
var win_to_focus_on = EditorInterface.get_editor_main_screen().get_parent()
while(win_to_focus_on != null and win_to_focus_on is not Window):
win_to_focus_on = win_to_focus_on.get_parent()
if(win_to_focus_on != null):
win_to_focus_on.grab_focus()
else:
owner.grab_focus()
else:
return value
pass
# We don't have to do anything when we are docked because the GUT
# bottom panel has the shortcut and it does the toggling all on its
# own.
func get_shortcut_dialog():
return _ctrls.shortcut_dialog
func results_vert_layout():
if(results_tree.get_parent() != results_v_split):
results_tree.reparent(results_v_split)
results_text.reparent(results_v_split)
results_v_split.visible = true
results_h_split.visible = false
func results_horiz_layout():
if(results_tree.get_parent() != results_h_split):
results_tree.reparent(results_h_split)
results_text.reparent(results_h_split)
results_v_split.visible = false
results_h_split.visible = true
func show_layout_buttons(should):
%HorizLayout.visible = should
%VertLayout.visible = should
func get_panel_shortcut():
_ctrls.shortcut_dialog.scbtn_panel.get_shortcut()

View file

@ -1 +1 @@
uid://b84o6yt8c0i3p
uid://dtvnb0xatk0my

View file

@ -1,27 +1,21 @@
[gd_scene load_steps=10 format=3 uid="uid://b3bostcslstem"]
[gd_scene format=3 uid="uid://b3bostcslstem"]
[ext_resource type="Script" path="res://addons/gut/gui/GutBottomPanel.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://bsk32dh41b4gs" path="res://addons/gut/gui/BottomPanelShortcuts.tscn" id="2"]
[ext_resource type="Script" uid="uid://dtvnb0xatk0my" path="res://addons/gut/gui/GutBottomPanel.gd" id="1"]
[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="Texture2D" uid="uid://bvo0uao7deu0q" path="res://addons/gut/icon.png" id="4_xv2r3"]
[ext_resource type="PackedScene" uid="uid://4gyyn12um08h" path="res://addons/gut/gui/RunResults.tscn" id="5"]
[ext_resource type="Texture2D" uid="uid://ljc2viafngwd" path="res://addons/gut/images/HSplitContainer.svg" id="5_qdqpf"]
[ext_resource type="PackedScene" uid="uid://bqmo4dj64c7yl" path="res://addons/gut/gui/OutputText.tscn" id="6"]
[ext_resource type="Texture2D" uid="uid://bhew20crsywxr" path="res://addons/gut/images/VSplitContainer.svg" id="6_ot46d"]
[ext_resource type="PackedScene" uid="uid://dj5ve0bq7xa5j" path="res://addons/gut/gui/ShortcutDialog.tscn" id="7_srqj5"]
[ext_resource type="PackedScene" uid="uid://ckv5eh8xyrwbk" path="res://addons/gut/gui/ShellOutOptions.tscn" id="7_xv2r3"]
[sub_resource type="Shortcut" id="9"]
[sub_resource type="Image" id="Image_4maas"]
data = {
"data": PackedByteArray(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, 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, 94, 94, 127, 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, 94, 94, 127, 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, 94, 94, 127, 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, 255, 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, 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, 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, 94, 94, 54, 255, 94, 94, 57, 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, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 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, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 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, 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, 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="ButtonGroup" id="ButtonGroup_bskl7"]
[sub_resource type="ImageTexture" id="ImageTexture_umaha"]
image = SubResource("Image_4maas")
[node name="GutBottomPanel" type="Control"]
[node name="GutBottomPanel" type="Control" unique_id=1136630421]
custom_minimum_size = Vector2(250, 250)
layout_mode = 3
anchor_left = -0.0025866
@ -34,217 +28,292 @@ offset_right = 2.64862
offset_bottom = 1.05945
script = ExtResource("1")
[node name="layout" type="VBoxContainer" parent="."]
[node name="layout" type="VBoxContainer" parent="." unique_id=790416054]
layout_mode = 0
anchor_right = 1.0
anchor_bottom = 1.0
[node name="ControlBar" type="HBoxContainer" parent="layout"]
[node name="ControlBar" type="HBoxContainer" parent="layout" unique_id=672788595]
layout_mode = 2
[node name="RunAll" type="Button" parent="layout/ControlBar"]
[node name="RunAll" type="Button" parent="layout/ControlBar" unique_id=678231332]
layout_mode = 2
size_flags_vertical = 11
shortcut = SubResource("9")
text = "Run All"
icon = ExtResource("4")
[node name="Label" type="Label" parent="layout/ControlBar"]
layout_mode = 2
mouse_filter = 1
text = "Current: "
[node name="RunAtCursor" parent="layout/ControlBar" instance=ExtResource("3")]
[node name="Sep3" type="ColorRect" parent="layout/ControlBar" unique_id=1600176902]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="CenterContainer2" type="CenterContainer" parent="layout/ControlBar"]
[node name="RunAtCursor" parent="layout/ControlBar" unique_id=1603612118 instance=ExtResource("3")]
custom_minimum_size = Vector2(237, 0)
layout_mode = 2
[node name="CenterContainer2" type="CenterContainer" parent="layout/ControlBar" unique_id=269691286]
layout_mode = 2
size_flags_horizontal = 3
[node name="Sep1" type="ColorRect" parent="layout/ControlBar"]
[node name="MakeFloating" type="Button" parent="layout/ControlBar" unique_id=1273743620]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Move the GUT panel to a window."
icon = ExtResource("4_xv2r3")
flat = true
[node name="HorizLayout" type="Button" parent="layout/ControlBar" unique_id=679134345]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
toggle_mode = true
button_pressed = true
button_group = SubResource("ButtonGroup_bskl7")
icon = ExtResource("5_qdqpf")
icon_alignment = 1
[node name="VertLayout" type="Button" parent="layout/ControlBar" unique_id=1762257478]
unique_name_in_owner = true
layout_mode = 2
toggle_mode = true
button_group = SubResource("ButtonGroup_bskl7")
icon = ExtResource("6_ot46d")
[node name="ControlBar2" type="HBoxContainer" parent="layout" unique_id=920578685]
layout_mode = 2
[node name="Sep2" type="ColorRect" parent="layout/ControlBar2" unique_id=781273927]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
color = Color(1, 1, 1, 0)
[node name="StatusIndicator" type="Control" parent="layout/ControlBar2" unique_id=173224142]
unique_name_in_owner = true
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
[node name="Passing" type="HBoxContainer" parent="layout/ControlBar2" unique_id=2110519605]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/ControlBar2/Passing" unique_id=164849935]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="RunResultsBtn" type="Button" parent="layout/ControlBar"]
[node name="label" type="Label" parent="layout/ControlBar2/Passing" unique_id=1437040616]
layout_mode = 2
toggle_mode = true
icon = SubResource("ImageTexture_umaha")
text = "Pass"
[node name="OutputBtn" type="Button" parent="layout/ControlBar"]
[node name="passing_value" type="Label" parent="layout/ControlBar2/Passing" unique_id=551548364]
unique_name_in_owner = true
layout_mode = 2
toggle_mode = true
icon = SubResource("ImageTexture_umaha")
text = "---"
[node name="Settings" type="Button" parent="layout/ControlBar"]
[node name="Failing" type="HBoxContainer" parent="layout/ControlBar2" unique_id=1824266070]
visible = false
layout_mode = 2
toggle_mode = true
icon = SubResource("ImageTexture_umaha")
[node name="Sep2" type="ColorRect" parent="layout/ControlBar"]
[node name="Sep" type="ColorRect" parent="layout/ControlBar2/Failing" unique_id=1239759559]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="Shortcuts" type="Button" parent="layout/ControlBar"]
[node name="label" type="Label" parent="layout/ControlBar2/Failing" unique_id=1956836855]
layout_mode = 2
text = "Fail"
[node name="failing_value" type="Label" parent="layout/ControlBar2/Failing" unique_id=636519064]
unique_name_in_owner = true
layout_mode = 2
text = "---"
[node name="Pending" type="HBoxContainer" parent="layout/ControlBar2" unique_id=1121510368]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/ControlBar2/Pending" unique_id=896038473]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/ControlBar2/Pending" unique_id=1642849369]
layout_mode = 2
text = "Risky"
[node name="pending_value" type="Label" parent="layout/ControlBar2/Pending" unique_id=162567404]
unique_name_in_owner = true
layout_mode = 2
text = "---"
[node name="Orphans" type="HBoxContainer" parent="layout/ControlBar2" unique_id=2040966734]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/ControlBar2/Orphans" unique_id=153606264]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/ControlBar2/Orphans" unique_id=1507291727]
layout_mode = 2
text = "Orphans"
[node name="orphans_value" type="Label" parent="layout/ControlBar2/Orphans" unique_id=235887326]
unique_name_in_owner = true
layout_mode = 2
text = "---"
[node name="Errors" type="HBoxContainer" parent="layout/ControlBar2" unique_id=1697483051]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/ControlBar2/Errors" unique_id=411797244]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/ControlBar2/Errors" unique_id=299959536]
layout_mode = 2
text = "Errors"
[node name="errors_value" type="Label" parent="layout/ControlBar2/Errors" unique_id=1340004517]
unique_name_in_owner = true
layout_mode = 2
text = "---"
[node name="Warnings" type="HBoxContainer" parent="layout/ControlBar2" unique_id=1097631959]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/ControlBar2/Warnings" unique_id=763793318]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/ControlBar2/Warnings" unique_id=272711725]
layout_mode = 2
text = "Warnings"
[node name="warnings_value" type="Label" parent="layout/ControlBar2/Warnings" unique_id=868414665]
unique_name_in_owner = true
layout_mode = 2
text = "---"
[node name="CenterContainer" type="CenterContainer" parent="layout/ControlBar2" unique_id=1705687195]
layout_mode = 2
size_flags_horizontal = 3
[node name="ExtraButtons" type="HBoxContainer" parent="layout/ControlBar2" unique_id=1132817721]
unique_name_in_owner = true
layout_mode = 2
[node name="Sep1" type="ColorRect" parent="layout/ControlBar2/ExtraButtons" unique_id=601143834]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="RunMode" type="Button" parent="layout/ControlBar2/ExtraButtons" unique_id=1469737845]
layout_mode = 2
tooltip_text = "Run Mode. Run tests through the editor or externally in a different process."
text = "ExN"
icon = ExtResource("4_xv2r3")
[node name="Sep2" type="ColorRect" parent="layout/ControlBar2/ExtraButtons" unique_id=710471274]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="RunResultsBtn" type="Button" parent="layout/ControlBar2/ExtraButtons" unique_id=385339391]
layout_mode = 2
tooltip_text = "Show/Hide Result Tree"
toggle_mode = true
button_pressed = true
icon = ExtResource("4_xv2r3")
[node name="OutputBtn" type="Button" parent="layout/ControlBar2/ExtraButtons" unique_id=1461861149]
layout_mode = 2
tooltip_text = "Show/Hide Text Output"
toggle_mode = true
button_pressed = true
icon = ExtResource("4_xv2r3")
[node name="Settings" type="Button" parent="layout/ControlBar2/ExtraButtons" unique_id=1063789901]
layout_mode = 2
tooltip_text = "GUT Settings"
toggle_mode = true
button_pressed = true
icon = ExtResource("4_xv2r3")
[node name="Sep3" type="ColorRect" parent="layout/ControlBar2/ExtraButtons" unique_id=650070116]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="Shortcuts" type="Button" parent="layout/ControlBar2/ExtraButtons" unique_id=545241830]
layout_mode = 2
size_flags_vertical = 11
icon = SubResource("ImageTexture_umaha")
tooltip_text = "GUT Shortcuts"
icon = ExtResource("4_xv2r3")
[node name="RSplit" type="HSplitContainer" parent="layout"]
[node name="About" type="Button" parent="layout/ControlBar2/ExtraButtons" unique_id=1763800911]
layout_mode = 2
tooltip_text = "About"
text = "A"
[node name="RSplit" type="HSplitContainer" parent="layout" unique_id=153697410]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
collapsed = true
[node name="sc" type="ScrollContainer" parent="layout/RSplit"]
[node name="CResults" type="VBoxContainer" parent="layout/RSplit" unique_id=124140650]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="HSplitResults" type="HSplitContainer" parent="layout/RSplit/CResults" unique_id=241208440]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="RunResults" parent="layout/RSplit/CResults/HSplitResults" unique_id=1277406275 instance=ExtResource("5")]
unique_name_in_owner = true
custom_minimum_size = Vector2(255, 255)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="OutputText" parent="layout/RSplit/CResults/HSplitResults" unique_id=1658148044 instance=ExtResource("6")]
unique_name_in_owner = true
layout_mode = 2
[node name="VSplitResults" type="VSplitContainer" parent="layout/RSplit/CResults" unique_id=394710781]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_vertical = 3
[node name="sc" type="ScrollContainer" parent="layout/RSplit" unique_id=978940325]
custom_minimum_size = Vector2(500, 2.08165e-12)
layout_mode = 2
size_flags_vertical = 3
[node name="Settings" type="VBoxContainer" parent="layout/RSplit/sc"]
[node name="Settings" type="VBoxContainer" parent="layout/RSplit/sc" unique_id=1724913756]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="CResults" type="VBoxContainer" parent="layout/RSplit"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ControlBar" type="HBoxContainer" parent="layout/RSplit/CResults"]
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"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
[node name="Passing" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
[node name="ShortcutDialog" parent="." unique_id=1224532527 instance=ExtResource("7_srqj5")]
size = Vector2i(1512, 1571)
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Passing"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Passing"]
layout_mode = 2
text = "Passing"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Passing"]
layout_mode = 2
text = "---"
[node name="Failing" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Failing"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Failing"]
layout_mode = 2
text = "Failing"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Failing"]
layout_mode = 2
text = "---"
[node name="Pending" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Pending"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Pending"]
layout_mode = 2
text = "Pending"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Pending"]
layout_mode = 2
text = "---"
[node name="Orphans" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Orphans"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Orphans"]
layout_mode = 2
text = "Orphans"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Orphans"]
layout_mode = 2
text = "---"
[node name="Errors" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Errors"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Errors"]
layout_mode = 2
text = "Errors"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Errors"]
layout_mode = 2
text = "---"
[node name="Warnings" type="HBoxContainer" parent="layout/RSplit/CResults/ControlBar"]
visible = false
layout_mode = 2
[node name="Sep" type="ColorRect" parent="layout/RSplit/CResults/ControlBar/Warnings"]
custom_minimum_size = Vector2(1, 2.08165e-12)
layout_mode = 2
[node name="label" type="Label" parent="layout/RSplit/CResults/ControlBar/Warnings"]
layout_mode = 2
text = "Warnings"
[node name="value" type="Label" parent="layout/RSplit/CResults/ControlBar/Warnings"]
layout_mode = 2
text = "---"
[node name="CenterContainer" type="CenterContainer" parent="layout/RSplit/CResults/ControlBar"]
layout_mode = 2
size_flags_horizontal = 3
[node name="TabBar" type="HSplitContainer" parent="layout/RSplit/CResults"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="RunResults" parent="layout/RSplit/CResults/TabBar" instance=ExtResource("5")]
visible = false
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="OutputText" parent="layout/RSplit/CResults/TabBar" instance=ExtResource("6")]
visible = false
layout_mode = 2
[node name="BottomPanelShortcuts" parent="." instance=ExtResource("2")]
[node name="ShellOutOptions" parent="." unique_id=1974075127 instance=ExtResource("7_xv2r3")]
size = Vector2i(1300, 1336)
visible = false
[connection signal="pressed" from="layout/ControlBar/RunAll" to="." method="_on_RunAll_pressed"]
[connection signal="run_tests" from="layout/ControlBar/RunAtCursor" to="." method="_on_RunAtCursor_run_tests"]
[connection signal="pressed" from="layout/ControlBar/RunResultsBtn" to="." method="_on_RunResultsBtn_pressed"]
[connection signal="pressed" from="layout/ControlBar/OutputBtn" to="." method="_on_OutputBtn_pressed"]
[connection signal="pressed" from="layout/ControlBar/Settings" to="." method="_on_Settings_pressed"]
[connection signal="pressed" from="layout/ControlBar/Shortcuts" to="." method="_on_Shortcuts_pressed"]
[connection signal="draw" from="layout/RSplit/CResults/ControlBar/Light3D" to="." method="_on_Light_draw"]
[connection signal="visibility_changed" from="BottomPanelShortcuts" to="." method="_on_bottom_panel_shortcuts_visibility_changed"]
[connection signal="pressed" from="layout/ControlBar/MakeFloating" to="." method="_on_to_window_pressed"]
[connection signal="pressed" from="layout/ControlBar/HorizLayout" to="." method="_on_horiz_layout_pressed"]
[connection signal="pressed" from="layout/ControlBar/VertLayout" to="." method="_on_vert_layout_pressed"]
[connection signal="draw" from="layout/ControlBar2/StatusIndicator" to="." method="_on_Light_draw"]
[connection signal="pressed" from="layout/ControlBar2/ExtraButtons/RunMode" to="." method="_on_run_mode_pressed"]
[connection signal="pressed" from="layout/ControlBar2/ExtraButtons/RunResultsBtn" to="." method="_on_RunResultsBtn_pressed"]
[connection signal="pressed" from="layout/ControlBar2/ExtraButtons/OutputBtn" to="." method="_on_OutputBtn_pressed"]
[connection signal="pressed" from="layout/ControlBar2/ExtraButtons/Settings" to="." method="_on_Settings_pressed"]
[connection signal="pressed" from="layout/ControlBar2/ExtraButtons/Shortcuts" to="." method="_on_Shortcuts_pressed"]
[connection signal="pressed" from="layout/ControlBar2/ExtraButtons/About" to="." method="_on_about_pressed"]
[connection signal="confirmed" from="ShortcutDialog" to="." method="_on_sortcut_dialog_confirmed"]
[connection signal="confirmed" from="ShellOutOptions" to="." method="_on_shell_out_options_confirmed"]

View file

@ -9,8 +9,7 @@ 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 _gut_runner = null
var _tree_root : TreeItem = null
var _script_icon = load('res://addons/gut/images/Script.svg')
@ -43,6 +42,7 @@ func _ready():
if Engine.is_editor_hint():
return
_gut_runner = GutRunnerScene.instantiate()
$Bg.color = bg_color
_ctrls.tabs.set_tab_title(0, 'Tests')
_ctrls.tabs.set_tab_title(1, 'Settings')
@ -260,6 +260,10 @@ func run_tests(options = null):
_config.options = _config_gui.get_options(_config.options)
else:
_config.options = options
# We ar running from within the game, so we should not exit, ever.
_config.options.should_exit_on_success = false
_config.options.should_exit = false
_gut_runner.get_gut().get_test_collector().clear()
_gut_runner.set_gut_config(_config)

View file

@ -1 +1 @@
uid://dxbu5m7ovktb8
uid://cqlvpwidawld6

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://4jb53yqktyfg"]
[ext_resource type="Script" path="res://addons/gut/gui/GutControl.gd" id="1_eprql"]
[ext_resource type="Script" uid="uid://cqlvpwidawld6" path="res://addons/gut/gui/GutControl.gd" id="1_eprql"]
[node name="GutControl" type="Control"]
layout_mode = 3

View file

@ -0,0 +1,36 @@
[gd_scene load_steps=4 format=3 uid="uid://bjkn8mhx2fmt1"]
[ext_resource type="Script" uid="uid://b8lvgepb64m8t" path="res://addons/gut/gui/gut_logo.gd" id="1_ba6lh"]
[ext_resource type="Texture2D" uid="uid://dyxbmyvpkkcvs" path="res://addons/gut/images/GutIconV2_base.png" id="2_ba6lh"]
[ext_resource type="Texture2D" uid="uid://dx0yxxn5q7doc" path="res://addons/gut/images/eyey.png" id="3_rc8fb"]
[node name="Logo" type="Node2D"]
script = ExtResource("1_ba6lh")
[node name="BaseLogo" type="Sprite2D" parent="."]
scale = Vector2(0.5, 0.5)
texture = ExtResource("2_ba6lh")
[node name="LeftEye" type="Sprite2D" parent="BaseLogo"]
visible = false
position = Vector2(-238, 16)
texture = ExtResource("3_rc8fb")
[node name="RightEye" type="Sprite2D" parent="BaseLogo"]
visible = false
position = Vector2(239, 16)
texture = ExtResource("3_rc8fb")
[node name="ResetTimer" type="Timer" parent="."]
wait_time = 5.0
one_shot = true
[node name="FaceButton" type="Button" parent="."]
modulate = Color(1, 1, 1, 0)
offset_left = -141.0
offset_top = -113.0
offset_right = 140.0
offset_bottom = 175.0
[connection signal="timeout" from="ResetTimer" to="." method="_on_reset_timer_timeout"]
[connection signal="pressed" from="FaceButton" to="." method="_on_face_button_pressed"]

View file

@ -28,12 +28,15 @@ var result_json_path = null
var lgr = GutUtils.get_logger()
var gut_config = null
var error_tracker = GutUtils.get_error_tracker()
var _hid_gut = null;
# Lazy loaded gut instance. Settable for testing purposes.
var gut = _hid_gut :
get:
if(_hid_gut == null):
_hid_gut = Gut.new()
_hid_gut = Gut.new(lgr)
_hid_gut.error_tracker = error_tracker
return _hid_gut
set(val):
_hid_gut = val
@ -94,7 +97,8 @@ func _write_results_for_gut_panel():
func _handle_quit(should_exit, should_exit_on_success, override_exit_code=EXIT_OK):
var quitting_time = should_exit or \
(should_exit_on_success and gut.get_fail_count() == 0)
(should_exit_on_success and gut.get_fail_count() == 0) or \
GutUtils.is_headless()
if(!quitting_time):
if(should_exit_on_success):
@ -122,6 +126,8 @@ func _end_run(override_exit_code=EXIT_OK):
if(_ran_from_editor):
_write_results_for_gut_panel()
GutErrorTracker.deregister_logger(error_tracker)
_handle_quit(gut_config.options.should_exit,
gut_config.options.should_exit_on_success,
override_exit_code)
@ -157,7 +163,9 @@ func run_tests(show_gui=true):
_setup_gui(show_gui)
if(gut_config.options.dirs.size() + gut_config.options.tests.size() == 0):
var err_text = "You do not have any directories configured, so GUT doesn't know where to find the tests. Tell GUT where to find the tests and GUT shall run the tests."
var err_text = "You do not have any directories configured, so GUT " + \
"doesn't know where to find the tests. Tell GUT where to find the " + \
"tests and GUT shall run the tests."
lgr.error(err_text)
push_error(err_text)
_end_run(EXIT_ERROR)
@ -178,11 +186,15 @@ func run_tests(show_gui=true):
else:
add_child(gut)
gut.end_run.connect(_on_tests_finished)
if(!gut.end_run.is_connected(_on_tests_finished)):
gut.end_run.connect(_on_tests_finished)
gut_config.apply_options(gut)
var run_rest_of_scripts = gut_config.options.unit_test_name == ''
if GutUtils.is_headless():
gut._ignore_pause_before_teardown = true
var run_rest_of_scripts = gut_config.options.unit_test_name == ''
GutErrorTracker.register_logger(error_tracker)
gut.test_scripts(run_rest_of_scripts)
@ -199,6 +211,7 @@ func quit(exit_code):
# Sometimes quitting takes a few seconds. This gives some indicator
# of what is going on.
_gui.set_title("Exiting")
await get_tree().process_frame
lgr.info(str('Exiting with code ', exit_code))

View file

@ -1 +1 @@
uid://bayjc3x1exeie
uid://eg8k46gd42a4

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://bqy3ikt6vu4b5"]
[ext_resource type="Script" path="res://addons/gut/gui/GutRunner.gd" id="1"]
[ext_resource type="Script" uid="uid://eg8k46gd42a4" path="res://addons/gut/gui/GutRunner.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://m28heqtswbuq" path="res://addons/gut/GutScene.tscn" id="2_6ruxb"]
[node name="GutRunner" type="Node2D"]

View file

@ -2,7 +2,7 @@
[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="Script" uid="uid://blvhsbnsvfyow" 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"]

View file

@ -1,7 +1,7 @@
[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="Script" uid="uid://blvhsbnsvfyow" 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"]
@ -158,17 +158,19 @@ 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
[node name="Buttons" type="VBoxContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
layout_mode = 2
size_flags_horizontal = 10
[node name="Continue" type="Button" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
[node name="Continue" type="Button" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/Buttons"]
layout_mode = 2
size_flags_vertical = 4
text = "Continue
"
[node name="WordWrap" type="CheckButton" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox/Buttons"]
layout_mode = 2
text = "Word Wrap"
[node name="S3" type="CenterContainer" parent="MainBox/HBoxContainer/VBoxContainer/ControlBox"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2

View file

@ -89,6 +89,18 @@ var _user_prefs = GutEditorGlobals.user_prefs
var _font_name_pctrl = null
var _font_size_pctrl = null
var keywords = [
['Failed', Color.RED],
['Passed', Color.GREEN],
['Pending', Color.YELLOW],
['Risky', Color.YELLOW],
['Orphans', Color.YELLOW],
['WARNING', Color.YELLOW],
['ERROR', Color.RED],
['ExpectedError', Color.LIGHT_BLUE],
]
# 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():
@ -110,6 +122,9 @@ func _test_running_setup():
func _ready():
if(get_parent() is SubViewport):
return
_sr.set_text_edit(_ctrls.output)
_ctrls.use_colors.icon = get_theme_icon('RichTextEffect', 'EditorIcons')
_ctrls.show_search.icon = get_theme_icon('Search', 'EditorIcons')
@ -127,7 +142,7 @@ func _ready():
func _add_other_ctrls():
var fname = 'CourierNew'
var fname = GutUtils.gut_fonts.DEFAULT_CUSTOM_FONT_NAME
if(_user_prefs != null):
fname = _user_prefs.output_font_name.value
_font_name_pctrl = PanelControls.SelectControl.new('Font', fname, GutUtils.avail_fonts,
@ -170,15 +185,6 @@ func _create_highlighter(default_color=Color(1, 1, 1, 1)):
to_return.symbol_color = default_color
to_return.member_variable_color = default_color
var keywords = [
['Failed', Color.RED],
['Passed', Color.GREEN],
['Pending', Color.YELLOW],
['Orphans', Color.YELLOW],
['WARNING', Color.YELLOW],
['ERROR', Color.RED]
]
for keyword in keywords:
to_return.add_keyword_color(keyword[0], keyword[1])
@ -187,13 +193,6 @@ func _create_highlighter(default_color=Color(1, 1, 1, 1)):
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
_highlighter = _create_highlighter()
_ctrls.output.queue_redraw()
@ -300,31 +299,19 @@ func clear():
_ctrls.output.text = ''
func _set_font(font_name, custom_name):
var rtl = _ctrls.output
if(font_name == null):
rtl.remove_theme_font_override(custom_name)
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_font(custom_name, theme_font_name):
var font = GutUtils.gut_fonts.get_font_for_theme_font_name(theme_font_name, custom_name)
_ctrls.output.add_theme_font_override(theme_font_name, 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')
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, 'font')
_set_font(base_name, 'normal_font')
_set_font(base_name, 'bold_font')
_set_font(base_name, 'italics_font')
_set_font(base_name, 'bold_italics_font')
func set_font_size(new_size):

View file

@ -1 +1 @@
uid://ccdonk2lpn1d1
uid://cax5phqs8acmu

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
uid://dp618d4ofjpv1
uid://duf6rfdqr6yoc

View file

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

View file

@ -1,5 +1,5 @@
@tool
extends Control
extends Tree
var _show_orphans = true
var show_orphans = true :
@ -18,83 +18,55 @@ var _icons = {
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)
@export var script_entry_color : Color = Color(0, 0, 0, .2) :
set(val):
if(val != null):
script_entry_color = val
@export var column_0_color : Color = Color(1, 1, 1, 0) :
set(val):
if(val != null):
column_0_color = val
@export var column_1_color : Color = Color(0, 0, 0, .2):
set(val):
if(val != null):
column_1_color = val
var _max_icon_width = 10
var _root : TreeItem
@onready var _ctrls = {
tree = $Tree,
lbl_overlay = $Tree/TextOverlay
}
@onready var lbl_overlay = $TextOverlay
signal selected(script_path, inner_class, test_name, line_number)
func _debug_ready():
hide_passing = false
load_json_file('user://gut_temp_directory/gut_editor.json')
func _ready():
_root = create_item()
set_hide_root(true)
columns = 2
set_column_expand(0, true)
set_column_expand_ratio(0, 5)
set_column_expand_ratio(1, 1)
set_column_expand(1, true)
item_selected.connect(_on_tree_item_selected)
if(get_parent() == get_tree().root):
_debug_ready()
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):
@ -142,17 +114,7 @@ func _add_script_tree_item(script_path, script_json):
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)
var item = create_item(parent)
item.set_text(0, item_text)
var meta = {
"type":"script",
@ -163,51 +125,46 @@ func _add_script_tree_item(script_path, script_json):
"inner_tests":0
}
item.set_metadata(0, meta)
item.set_custom_bg_color(1, _col_1_bg_color)
item.set_custom_bg_color(0, script_entry_color)
item.set_custom_bg_color(1, script_entry_color)
return item
func _add_assert_item(text, icon, parent_item):
# print(' * adding assert')
var assert_item = _ctrls.tree.create_item(parent_item)
var assert_item = 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)
assert_item.set_custom_bg_color(0, column_0_color)
assert_item.set_custom_bg_color(1, column_1_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)
var no_orphans_to_show = !_show_orphans or (_show_orphans and test_json.orphan_count == 0)
if(_hide_passing and test_json['status'] == 'pass' and no_orphans_to_show):
return
var item = _ctrls.tree.create_item(script_item)
var item = 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_custom_bg_color(1, column_1_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)
item.set_custom_bg_color(0, column_0_color)
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:
@ -223,8 +180,18 @@ func _add_test_tree_item(test_name, test_json, script_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)
var orphan_text = 'orphans'
if(test_json.orphan_count == 1):
orphan_text = 'orphan'
orphan_text = str(int(test_json.orphan_count), ' ', orphan_text)
if(!no_orphans_to_show):
var orphan_item = _add_assert_item(orphan_text, _icons.yellow, item)
for o in test_json.orphans:
var orphan_entry = create_item(orphan_item)
orphan_entry.set_text(0, o)
orphan_entry.set_custom_bg_color(0, column_0_color)
orphan_entry.set_custom_bg_color(1, column_1_color)
return item
@ -243,13 +210,17 @@ func _add_script_to_tree(key, script_json):
t_item.collapsed = true
if(s_item.get_children().size() == 0):
s_item.free()
if(script_json.props.skipped):
_add_assert_item("Skipped", _icons.yellow, s_item)
s_item.set_text(1, "Skipped")
else:
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')
total_text = str(int(test_keys.size() - bad_count), '/', int(test_keys.size()), ' passed')
s_item.set_text(1, total_text)
@ -276,15 +247,60 @@ func _load_result_tree(j):
var add_count = 0
for key in script_keys:
if(scripts[key]['props']['tests'] > 0):
add_count += 1
_add_script_to_tree(key, scripts[key])
add_count += 1
_add_script_to_tree(key, scripts[key])
_free_childless_scripts()
if(add_count == 0):
add_centered_text('Nothing was run')
else:
_show_all_passed()
# -------------------
# Events
# -------------------
func _on_tree_item_selected():
var item = 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
selected.emit(script_path, inner_class, test_name, line)
# -------------------
@ -313,26 +329,29 @@ func load_json_file(path):
func load_json_results(j):
clear()
if(_root == null):
_root = create_item()
_load_result_tree(j)
func clear():
_ctrls.tree.clear()
_root = _ctrls.tree.create_item()
#func clear():
#clear()
#_root = create_item()
func set_summary_min_width(width):
_ctrls.tree.set_column_custom_minimum_width(1, width)
set_column_custom_minimum_width(1, width)
func add_centered_text(t):
_ctrls.lbl_overlay.visible = true
_ctrls.lbl_overlay.text = t
lbl_overlay.visible = true
lbl_overlay.text = t
func clear_centered_text():
_ctrls.lbl_overlay.visible = false
_ctrls.lbl_overlay.text = ''
lbl_overlay.visible = false
lbl_overlay.text = ''
func collapse_all():
@ -347,7 +366,3 @@ 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

@ -1 +1 @@
uid://dmfojusal8t8m
uid://dehdhn78qv5tr

View file

@ -1,9 +1,28 @@
[gd_scene load_steps=2 format=3 uid="uid://dls5r5f6157nq"]
[ext_resource type="Script" path="res://addons/gut/gui/ResultsTree.gd" id="1_b4uub"]
[ext_resource type="Script" uid="uid://dehdhn78qv5tr" path="res://addons/gut/gui/ResultsTree.gd" id="1_b4uub"]
[node name="ResultsTree" type="VBoxContainer"]
[node name="ResultsTree" type="Tree"]
offset_right = 1082.0
offset_bottom = 544.0
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 2
hide_root = true
script = ExtResource("1_b4uub")
[node name="TextOverlay" type="Label" parent="."]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="ResultsTree" type="VBoxContainer" parent="."]
custom_minimum_size = Vector2(10, 10)
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
@ -13,20 +32,3 @@ 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

@ -1,8 +1,7 @@
@tool
extends Control
var ScriptTextEditors = load('res://addons/gut/gui/script_text_editor_controls.gd')
var EditorCaretContextNotifier = load('res://addons/gut/editor_caret_context_notifier.gd')
@onready var _ctrls = {
btn_script = $HBox/BtnRunScript,
@ -13,16 +12,33 @@ var ScriptTextEditors = load('res://addons/gut/gui/script_text_editor_controls.g
arrow_2 = $HBox/Arrow2
}
var _editors = null
var _cur_editor = null
var _last_line = -1
var _cur_script_path = null
var _caret_notifier = null
var _last_info = {
script = null,
inner_class = null,
test_method = null
method = null
}
var disabled = false :
set(val):
disabled = val
if(is_inside_tree()):
_ctrls.btn_script.disabled = val
_ctrls.btn_inner.disabled = val
_ctrls.btn_method.disabled = val
var method_prefix = 'test_'
var inner_class_prefix = 'Test'
var menu_manager = null :
set(val):
menu_manager = val
menu_manager.run_script.connect(_on_BtnRunScript_pressed)
menu_manager.run_at_cursor.connect(run_at_cursor)
menu_manager.rerun.connect(rerun)
menu_manager.run_inner_class.connect(_on_BtnRunInnerClass_pressed)
menu_manager.run_test.connect(_on_BtnRunMethod_pressed)
_update_buttons(_last_info)
signal run_tests(what)
@ -35,95 +51,103 @@ func _ready():
_ctrls.arrow_1.visible = false
_ctrls.arrow_2.visible = false
# ----------------
# Private
# ----------------
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().caret_changed.disconnect(_on_cursor_changed)
_caret_notifier = EditorCaretContextNotifier.new()
add_child(_caret_notifier)
_caret_notifier.it_changed.connect(_on_caret_notifer_changed)
if(which != null):
_cur_editor = weakref(which)
which.caret_changed.connect(_on_cursor_changed.bind(which))
# which.connect('cursor_changed',Callable(self,'_on_cursor_changed'),[which])
disabled = disabled
_last_line = which.get_caret_line()
_last_info = _editors.get_line_info()
func _on_caret_notifer_changed(data):
if(data.is_test_script):
_last_info = data
_update_buttons(_last_info)
# ----------------
# Private
# ----------------
func _update_buttons(info):
_ctrls.lbl_none.visible = _cur_script_path == null
_ctrls.btn_script.visible = _cur_script_path != null
_ctrls.lbl_none.visible = false
_ctrls.btn_script.visible = info.script != null
if(info.script != null and info.is_test_script):
_ctrls.btn_script.text = info.script.resource_path.get_file()
_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.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.tooltip_text = str("Run test ", info.test_method)
var is_test_method = info.method != null and info.method.begins_with(method_prefix)
_ctrls.btn_method.visible = is_test_method
_ctrls.arrow_2.visible = is_test_method
if(is_test_method):
_ctrls.btn_method.text = str(info.method)
_ctrls.btn_method.tooltip_text = str("Run test ", info.method)
if(menu_manager != null):
menu_manager.disable_menu("run_script", info.script == null)
menu_manager.disable_menu("run_inner_class", info.inner_class == null)
menu_manager.disable_menu("run_at_cursor", info.script == null)
menu_manager.disable_menu("run_test", is_test_method)
menu_manager.disable_menu("rerun", _last_run_info == {})
# 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
# first time.
call_deferred("_update_size")
_update_size.call_deferred()
func _update_size():
custom_minimum_size.x = _ctrls.btn_method.size.x + _ctrls.btn_method.position.x
var _last_run_info = {}
func _emit_run_tests(info):
_last_run_info = info.duplicate()
run_tests.emit(info)
# ----------------
# Events
# ----------------
func _on_cursor_changed(which):
if(which.get_caret_line() != _last_line):
_last_line = which.get_caret_line()
_last_info = _editors.get_line_info()
_update_buttons(_last_info)
func _on_BtnRunScript_pressed():
var info = _last_info.duplicate()
info.script = _cur_script_path.get_file()
info.script = info.script.resource_path.get_file()
info.inner_class = null
info.test_method = null
emit_signal("run_tests", info)
info.method = null
_emit_run_tests(info)
func _on_BtnRunInnerClass_pressed():
var info = _last_info.duplicate()
info.script = _cur_script_path.get_file()
info.test_method = null
emit_signal("run_tests", info)
info.script = info.script.resource_path.get_file()
info.method = null
_emit_run_tests(info)
func _on_BtnRunMethod_pressed():
var info = _last_info.duplicate()
info.script = _cur_script_path.get_file()
emit_signal("run_tests", info)
info.script = info.script.resource_path.get_file()
_emit_run_tests(info)
# ----------------
# Public
# ----------------
func set_script_text_editors(value):
_editors = value
func rerun():
if(_last_run_info != {}):
_emit_run_tests(_last_run_info)
func activate_for_script(path):
_ctrls.btn_script.visible = true
_ctrls.btn_script.text = path.get_file()
_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())
func run_at_cursor():
if(_ctrls.btn_method.visible):
_on_BtnRunMethod_pressed()
elif(_ctrls.btn_inner.visible):
_on_BtnRunInnerClass_pressed()
elif(_ctrls.btn_script.visible):
_on_BtnRunScript_pressed()
else:
print("nothing selected")
func get_script_button():
@ -138,21 +162,10 @@ func get_test_button():
return _ctrls.btn_method
# not used, thought was configurable but it's just the script prefix
func set_method_prefix(value):
_editors.set_method_prefix(value)
# not used, thought was configurable but it's just the script prefix
func set_inner_class_prefix(value):
_editors.set_inner_class_prefix(value)
_caret_notifier.inner_class_prefix = value
# Mashed this function in here b/c it has _editors. Probably should be
# somewhere else (possibly in script_text_editor_controls).
func search_current_editor_for_text(txt):
var te = _editors.get_current_text_edit()
var result = te.search(txt, 0, 0, 0)
var to_return = -1
return to_return
func apply_gut_config(gut_config):
_caret_notifier.script_prefix = gut_config.options.prefix
_caret_notifier.script_suffix = gut_config.options.suffix

View file

@ -1 +1 @@
uid://417tmtcbran2
uid://c4gmgdl1xwflw

View file

@ -1,10 +1,10 @@
[gd_scene load_steps=4 format=3 uid="uid://0yunjxtaa8iw"]
[gd_scene load_steps=3 format=3 uid="uid://0yunjxtaa8iw"]
[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="Script" uid="uid://c4gmgdl1xwflw" path="res://addons/gut/gui/RunAtCursor.gd" id="1"]
[ext_resource type="Texture2D" uid="uid://6wra5rxmfsrl" path="res://addons/gut/gui/arrow.png" id="3"]
[node name="RunAtCursor" type="Control"]
custom_minimum_size = Vector2(510, 0)
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
@ -25,40 +25,35 @@ size_flags_horizontal = 3
size_flags_vertical = 3
[node name="LblNoneSelected" type="Label" parent="HBox"]
visible = false
layout_mode = 2
text = "<None>"
[node name="BtnRunScript" type="Button" parent="HBox"]
visible = false
layout_mode = 2
text = "<script>"
icon = ExtResource("2")
text = "test_test.gd"
[node name="Arrow1" type="TextureButton" parent="HBox"]
visible = false
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
layout_mode = 2
text = "<inner class>"
icon = ExtResource("2")
tooltip_text = "Run all tests in Inner-Test-Class TestAssertNe"
text = "TestAssertNe"
[node name="Arrow2" type="TextureButton" parent="HBox"]
visible = false
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
layout_mode = 2
text = "<method>"
icon = ExtResource("2")
tooltip_text = "Run test test_fails_with_integers_equal"
text = "test_fails_with_integers_equal"
[connection signal="pressed" from="HBox/BtnRunScript" to="." method="_on_BtnRunScript_pressed"]
[connection signal="pressed" from="HBox/BtnRunInnerClass" to="." method="_on_BtnRunInnerClass_pressed"]

View file

@ -0,0 +1,216 @@
@tool
extends Control
# I'm probably going to put this back in later and I don't want to create it
# again. Yeah, yeah, yeah.
# class DotsAnimator:
# var text = ''
# var dot = '.'
# var max_dots = 3
# var dot_delay = .5
# var _anim_text = ''
# var _elapsed_time = 0.0
# var _cur_dots = 0
# func get_animated_text():
# return _anim_text
# func add_time(delta):
# _elapsed_time += delta
# if(_elapsed_time > dot_delay):
# _elapsed_time = 0
# _cur_dots += 1
# if(_cur_dots > max_dots):
# _cur_dots = 0
# _anim_text = text.rpad(text.length() + _cur_dots, dot)
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
@onready var btn_kill_it = $BgControl/VBox/Kill
@onready var bg_control = $BgControl
var _pipe_results = {}
var _debug_mode = false
var _std_thread : Thread
var _escape_regex : RegEx = RegEx.new()
var _text_buffer = ''
var bottom_panel = null :
set(val):
bottom_panel = val
bottom_panel.resized.connect(_on_bottom_panel_resized)
var blocking_mode = "Blocking"
var additional_arguments = []
var remove_escape_characters = true
@export var bg_color = Color.WHITE:
set(val):
bg_color = val
if(is_inside_tree()):
bg_control.get("theme_override_styles/panel").bg_color = bg_color
func _debug_ready():
_debug_mode = true
additional_arguments = ['-gselect', 'test_awaiter.gd', '-gconfig', 'res://.gutconfig.json'] # '-gunit_test_name', 'test_can_clear_spies'
blocking_mode = "NonBlocking"
run_tests()
func _ready():
_escape_regex.compile("\\x1b\\[[0-9;]*m")
btn_kill_it.visible = false
if(get_parent() == get_tree().root):
_debug_ready.call_deferred()
bg_color = bg_color
func _process(_delta: float) -> void:
if(_pipe_results != {}):
if(!OS.is_process_running(_pipe_results.pid)):
_end_non_blocking()
# ----------
# Private
# ----------
func _center_me():
position = get_parent().size / 2.0 - size / 2.0
func _output_text(text, should_scroll = true):
if(_debug_mode):
print(text)
else:
if(remove_escape_characters):
text = _escape_regex.sub(text, '', true)
if(bottom_panel != null):
bottom_panel.add_output_text(text)
if(should_scroll):
_scroll_output_pane(-1)
else:
_text_buffer += text
func _scroll_output_pane(line):
if(!_debug_mode and bottom_panel != null):
var txt_ctrl = bottom_panel.get_text_output_control().get_rich_text_edit()
if(line == -1):
line = txt_ctrl.get_line_count()
txt_ctrl.scroll_vertical = line
func _add_arguments_to_output():
if(additional_arguments.size() != 0):
_output_text(
str("Run Mode arguments: ", ' '.join(additional_arguments), "\n\n")
)
func _load_json():
if(_debug_mode):
pass # could load file and print it if we want.
elif(bottom_panel != null):
bottom_panel.load_result_json()
func _run_blocking(options):
btn_kill_it.visible = false
var output = []
await get_tree().create_timer(.1).timeout
OS.execute(OS.get_executable_path(), options, output, true)
_output_text(output[0])
_add_arguments_to_output()
_scroll_output_pane(-1)
_load_json()
queue_free()
func _read_non_blocking_stdio():
while(OS.is_process_running(_pipe_results.pid)):
while(_pipe_results.stderr.get_length() > 0):
_output_text(_pipe_results.stderr.get_line() + "\n")
while(_pipe_results.stdio.get_length() > 0):
_output_text(_pipe_results.stdio.get_line() + "\n")
# without this, things start to lock up.
await get_tree().process_frame
func _run_non_blocking(options):
_pipe_results = OS.execute_with_pipe(OS.get_executable_path(), options, false)
_std_thread = Thread.new()
_std_thread.start(_read_non_blocking_stdio)
btn_kill_it.visible = true
func _end_non_blocking():
_add_arguments_to_output()
_scroll_output_pane(-1)
_load_json()
_pipe_results = {}
_std_thread.wait_to_finish()
_std_thread = null
queue_free()
if(_debug_mode):
get_tree().quit()
# ----------------
# Events
# ----------------
func _on_kill_pressed() -> void:
if(_pipe_results != {} and OS.is_process_running(_pipe_results.pid)):
OS.kill(_pipe_results.pid)
btn_kill_it.visible = false
func _on_color_rect_gui_input(event: InputEvent) -> void:
if(event is InputEventMouseMotion):
if(event.button_mask == MOUSE_BUTTON_MASK_LEFT):
position += event.relative
func _on_bottom_panel_resized():
_center_me()
# ----------------
# Public
# ----------------
func run_tests():
_center_me()
var options = ["-s", "res://addons/gut/gut_cmdln.gd", "-graie", "-gdisable_colors",
"-gconfig", GutEditorGlobals.editor_run_gut_config_path]
options.append_array(additional_arguments)
if(blocking_mode == 'Blocking'):
_run_blocking(options)
else:
_run_non_blocking(options)
func get_godot_help():
_text_buffer = ''
var options = ["--help", "--headless"]
await _run_blocking(options)
return _text_buffer
func get_gut_help():
_text_buffer = ''
var options = ["-s", "res://addons/gut/gut_cmdln.gd", "-gh", "--headless"]
await _run_blocking(options)
return _text_buffer

View file

@ -0,0 +1 @@
uid://bi8pg352un4om

View file

@ -0,0 +1,65 @@
[gd_scene load_steps=3 format=3 uid="uid://cftcb0e6g7tu1"]
[ext_resource type="Script" uid="uid://bi8pg352un4om" path="res://addons/gut/gui/RunExternally.gd" id="1_lrqqi"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_haowt"]
bg_color = Color(0.025935074, 0.17817128, 0.30283752, 1)
corner_radius_top_left = 20
corner_radius_top_right = 20
corner_radius_bottom_right = 20
corner_radius_bottom_left = 20
shadow_size = 5
shadow_offset = Vector2(7, 7)
[node name="DoShellOut" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 774.0
offset_bottom = 260.0
script = ExtResource("1_lrqqi")
bg_color = Color(0.025935074, 0.17817128, 0.30283752, 1)
[node name="BgControl" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_haowt")
[node name="VBox" type="VBoxContainer" parent="BgControl"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Spacer" type="CenterContainer" parent="BgControl/VBox"]
layout_mode = 2
size_flags_vertical = 3
[node name="Title" type="Label" parent="BgControl/VBox"]
layout_mode = 2
text = "Running Tests"
horizontal_alignment = 1
[node name="Spacer2" type="CenterContainer" parent="BgControl/VBox"]
visible = false
layout_mode = 2
size_flags_vertical = 3
[node name="Kill" type="Button" parent="BgControl/VBox"]
visible = false
custom_minimum_size = Vector2(200, 50)
layout_mode = 2
size_flags_horizontal = 4
text = "Stop"
[node name="Spacer3" type="CenterContainer" parent="BgControl/VBox"]
layout_mode = 2
size_flags_vertical = 3
[connection signal="gui_input" from="BgControl" to="." method="_on_color_rect_gui_input"]
[connection signal="pressed" from="BgControl/VBox/Kill" to="." method="_on_kill_pressed"]

View file

@ -4,9 +4,6 @@ extends Control
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
var _interface = null
var _font = null
var _font_size = null
var _editors = null # script_text_editor_controls.gd
var _output_control = null
@onready var _ctrls = {
@ -24,6 +21,9 @@ var _output_control = null
}
func _ready():
if(get_parent() is SubViewport):
return
var f = null
if ($FontSampler.get_label_settings() == null) :
f = get_theme_default_font()
@ -42,7 +42,7 @@ func _ready():
_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)
_ctrls.tree.selected.connect(_on_item_selected)
if(get_parent() == get_tree().root):
_test_running_setup()
@ -127,7 +127,8 @@ func _goto_code(path, line, method_name='', inner_class =''):
search_strings.append(method_name)
await get_tree().process_frame
line = _get_line_number_for_seq_search(search_strings, _editors.get_current_text_edit())
line = _get_line_number_for_seq_search(search_strings,
_interface.get_script_editor().get_current_editor().get_base_editor())
if(line != null and line != -1):
_interface.get_script_editor().goto_line(line)
@ -204,10 +205,6 @@ func set_interface(which):
_interface = which
func set_script_text_editors(value):
_editors = value
func collapse_all():
_ctrls.tree.collapse_all()

View file

@ -1 +1 @@
uid://d1ntrij87eoco
uid://chnko3073tkcv

View file

@ -1,20 +1,9 @@
[gd_scene load_steps=5 format=3 uid="uid://4gyyn12um08h"]
[gd_scene load_steps=4 format=3 uid="uid://4gyyn12um08h"]
[ext_resource type="Script" path="res://addons/gut/gui/RunResults.gd" id="1"]
[ext_resource type="Script" uid="uid://chnko3073tkcv" path="res://addons/gut/gui/RunResults.gd" id="1"]
[ext_resource type="Texture2D" uid="uid://bvo0uao7deu0q" path="res://addons/gut/icon.png" id="2_1k8e0"]
[ext_resource type="PackedScene" uid="uid://dls5r5f6157nq" path="res://addons/gut/gui/ResultsTree.tscn" id="2_o808v"]
[sub_resource type="Image" id="Image_abbh7"]
data = {
"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="ImageTexture_x655i"]
image = SubResource("Image_abbh7")
[node name="RunResults" type="Control"]
custom_minimum_size = Vector2(345, 0)
layout_mode = 3
@ -33,28 +22,32 @@ layout_mode = 2
size_flags_horizontal = 0
[node name="Expand" type="Button" parent="VBox/Toolbar"]
visible = false
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
icon = ExtResource("2_1k8e0")
[node name="Collapse" type="Button" parent="VBox/Toolbar"]
visible = false
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
icon = ExtResource("2_1k8e0")
[node name="Sep" type="ColorRect" parent="VBox/Toolbar"]
visible = false
custom_minimum_size = Vector2(2, 0)
layout_mode = 2
[node name="LblAll" type="Label" parent="VBox/Toolbar"]
visible = false
layout_mode = 2
text = "All:"
[node name="ExpandAll" type="Button" parent="VBox/Toolbar"]
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
icon = ExtResource("2_1k8e0")
[node name="CollapseAll" type="Button" parent="VBox/Toolbar"]
layout_mode = 2
icon = SubResource("ImageTexture_x655i")
icon = ExtResource("2_1k8e0")
[node name="Sep2" type="ColorRect" parent="VBox/Toolbar"]
custom_minimum_size = Vector2(2, 0)
@ -77,13 +70,13 @@ text = "Sync:"
layout_mode = 2
toggle_mode = true
button_pressed = true
icon = SubResource("ImageTexture_x655i")
icon = ExtResource("2_1k8e0")
[node name="ScrollOutput" type="Button" parent="VBox/Toolbar"]
layout_mode = 2
toggle_mode = true
button_pressed = true
icon = SubResource("ImageTexture_x655i")
icon = ExtResource("2_1k8e0")
[node name="Output" type="Panel" parent="VBox"]
self_modulate = Color(1, 1, 1, 0.541176)

View file

@ -0,0 +1,321 @@
@tool
extends ConfirmationDialog
const RUN_MODE_EDITOR = 'Editor'
const RUN_MODE_BLOCKING = 'Blocking'
const RUN_MODE_NON_BLOCKING = 'NonBlocking'
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
@onready var _bad_arg_dialog = $AcceptDialog
@onready var _main_container = $ScrollContainer/VBoxContainer
var _blurb_style_box = StyleBoxEmpty.new()
var _opt_maker_setup = false
var _arg_vbox : VBoxContainer = null
var _my_ok_button : Button = null
# Run mode button stuff
var _run_mode_theme = load('res://addons/gut/gui/EditorRadioButton.tres')
var _button_group = ButtonGroup.new()
var _btn_in_editor : Button = null
var _btn_blocking : Button = null
var _btn_non_blocking : Button = null
var _txt_additional_arguments = null
var _btn_godot_help = null
var _btn_gut_help = null
var opt_maker = null
var default_path = GutEditorGlobals.run_externally_options_path
# I like this. It holds values loaded/saved which makes for an easy
# reset mechanism. Hit OK; values get written to this object (not the file
# system). Hit Cancel; values are reloaded from this object. Call the
# save/load methods to interact with the file system.
#
# Downside: If the keys/sections in the config file change, this ends up
# preserving old data. So you gotta find a way to clean it out
# somehow.
# Downside solved: Clear the config file at the start of the save method.
var _config_file = ConfigFile.new()
var _run_mode = RUN_MODE_EDITOR
var run_mode = _run_mode:
set(val):
_run_mode = val
if(is_inside_tree()):
_btn_in_editor.button_pressed = _run_mode == RUN_MODE_EDITOR
if(_btn_in_editor.button_pressed):
_btn_in_editor.pressed.emit()
_btn_blocking.button_pressed = _run_mode == RUN_MODE_BLOCKING
if(_btn_blocking.button_pressed):
_btn_blocking.pressed.emit()
_btn_non_blocking.button_pressed = _run_mode == RUN_MODE_NON_BLOCKING
if(_btn_non_blocking.button_pressed):
_btn_non_blocking.pressed.emit()
get():
return _run_mode
var additional_arguments = '' :
get():
if(_opt_maker_setup):
return opt_maker.controls.additional_arguments.value
else:
return additional_arguments
func _debug_ready():
popup_centered()
default_path = GutEditorGlobals.temp_directory.path_join('test_external_run_options.cfg')
exclusive = false
var save_btn = Button.new()
save_btn.text = 'save'
save_btn.pressed.connect(func():
save_to_file()
print(_config_file.encode_to_text()))
save_btn.position = Vector2(100, 20)
save_btn.size = Vector2(100, 100)
get_tree().root.add_child(save_btn)
var load_btn = Button.new()
load_btn.text = 'load'
load_btn.pressed.connect(func():
load_from_file()
print(_config_file.encode_to_text()))
load_btn.position = Vector2(100, 130)
load_btn.size = Vector2(100, 100)
get_tree().root.add_child(load_btn)
var show_btn = Button.new()
show_btn.text = 'Show'
show_btn.pressed.connect(popup_centered)
show_btn.position = Vector2(100, 250)
show_btn.size = Vector2(100, 100)
get_tree().root.add_child(show_btn)
func _ready():
opt_maker = GutUtils.OptionMaker.new(_main_container)
_add_controls()
if(get_parent() == get_tree().root):
_debug_ready.call_deferred()
_my_ok_button = Button.new()
_my_ok_button.text = 'OK'
_my_ok_button.pressed.connect(_validate_and_confirm)
get_ok_button().add_sibling(_my_ok_button)
get_ok_button().modulate.a = 0.0
get_ok_button().text = ''
get_ok_button().disabled = true
canceled.connect(reset)
_button_group.pressed.connect(_on_mode_button_pressed)
run_mode = run_mode
func _validate_and_confirm():
if(validate_arguments()):
_save_to_config_file(_config_file)
confirmed.emit()
hide()
else:
var dlg_text = str("Invalid arguments. The following cannot be used:\n",
' '.join(_invalid_args))
if(run_mode == RUN_MODE_BLOCKING):
dlg_text += str("\nThese cannot be used with blocking mode:\n",
' '.join(_invalid_blocking_args))
_bad_arg_dialog.dialog_text = dlg_text
_bad_arg_dialog.popup_centered()
func _on_mode_button_pressed(which):
if(which == _btn_in_editor):
_arg_vbox.modulate.a = .3
else:
_arg_vbox.modulate.a = 1.0
_txt_additional_arguments.value_ctrl.editable = which != _btn_in_editor
if(which == _btn_in_editor):
_run_mode = RUN_MODE_EDITOR
elif(which == _btn_blocking):
_run_mode = RUN_MODE_BLOCKING
elif(which == _btn_non_blocking):
_run_mode = RUN_MODE_NON_BLOCKING
func _add_run_mode_button(text, desc_label, description):
var btn = Button.new()
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
btn.toggle_mode = true
btn.text = text
btn.button_group = _button_group
btn.theme = _run_mode_theme
btn.pressed.connect(func(): desc_label.text = str('[b]', text, "[/b]\n", description))
return btn
func _add_blurb(text):
var ctrl = opt_maker.add_blurb(text)
ctrl.set("theme_override_styles/normal", _blurb_style_box)
return ctrl
func _add_title(text):
var ctrl = opt_maker.add_title(text)
ctrl.get_child(0).horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
return ctrl
func _add_controls():
_add_title("Run Modes")
_add_blurb(
"Choose how GUT will launch tests. Normally you just run them through the editor, but now " +
"you can run them externally. This is an experimental feature. It has been tested on Mac " +
"and Windows. Your results may vary. Feedback welcome at [url]https://github.com/bitwes/Gut/issues[/url].\n ")
var button_desc_box = HBoxContainer.new()
var button_box = VBoxContainer.new()
var button_desc = RichTextLabel.new()
button_desc.fit_content = true
button_desc.bbcode_enabled = true
button_desc.size_flags_horizontal = Control.SIZE_EXPAND_FILL
button_desc.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_main_container.add_child(button_desc_box)
button_desc_box.add_child(button_box)
button_desc_box.add_child(button_desc)
_btn_in_editor = _add_run_mode_button("In Editor (default)", button_desc,
"This is the default. Runs through the editor. When an error occurs " +
"the debugger is invoked. [b]print[/b] output " +
"appears in the Output panel and errors show up in the Debugger panel.")
button_box.add_child(_btn_in_editor)
_btn_blocking = _add_run_mode_button("Externally - Blocking", button_desc,
"Debugger is not enabled, and cannot be enabled. All output (print, errors, warnings, etc) " +
"appears in the GUT panel, and [b]not[/b] the Output or Debugger panels. \n" +
"The Editor cannot be used while tests are running. If you are trying to test for errors, this " +
"mode provides the best output.")
button_box.add_child(_btn_blocking)
_btn_non_blocking = _add_run_mode_button("Externally - NonBlocking", button_desc,
"Debugger is not enabled, and cannot be enabled. All output (print, errors, warnings, etc) " +
"appears in the GUT panel, and [b]not[/b] the Output or Debugger panels. \n" +
"Test output is streamed to the GUT panel. The editor is not blocked, but can be less " +
"responsive when there is a lot of output. This is the only mode that supports the --headless argument." )
button_box.add_child(_btn_non_blocking)
_add_title("Command Line Arguments")
_arg_vbox = VBoxContainer.new()
_main_container.add_child(_arg_vbox)
opt_maker.base_container = _arg_vbox
_txt_additional_arguments = opt_maker.add_value("additional_arguments", additional_arguments, '', '')
_txt_additional_arguments.value_ctrl.placeholder_text = "Put your arguments here. Ex: --verbose -glog 0"
_txt_additional_arguments.value_ctrl.select_all_on_focus = false
_add_blurb(
"Supply any command line options for GUT and/or Godot when running externally. You cannot use " +
"spaces in values. See the Godot and GUT documentation for valid arguments. GUT arguments " +
"specified here take precedence over your config.")
_add_blurb("[b]Be Careful[/b] There are plenty of argument combinations that may make this " +
"act wrong/odd/bad/horrible. Some arguments you might [i]want[/i] " +
"to use but [b]shouldn't[/b] are checked for, but not that many. Choose your arguments carefully (generally good advice).")
opt_maker.base_container = _main_container
_add_title("Display CLI Help")
_add_blurb("You can use these buttons to get a list of valid GUT and Godot options. They print the CLI help text for each to the [b]Output Panel[/b].")
_btn_godot_help = Button.new()
_btn_godot_help.text = "Print Godot CLI Help"
_main_container.add_child(_btn_godot_help)
_btn_godot_help.pressed.connect(func():
await _show_help("get_godot_help"))
_btn_gut_help = Button.new()
_btn_gut_help.text = "Print GUT CLI Help"
_main_container.add_child(_btn_gut_help)
_btn_gut_help.pressed.connect(func():
await _show_help("get_gut_help"))
_opt_maker_setup = true
func _show_help(help_method_name):
_btn_godot_help.disabled = true
_btn_gut_help.disabled = true
var re = GutUtils.RunExternallyScene.instantiate()
add_child(re)
re.visible = false
var text = await re.call(help_method_name)
print(text)
re.queue_free()
_btn_godot_help.disabled = false
_btn_gut_help.disabled = false
if(GutEditorGlobals.gut_plugin != null):
GutEditorGlobals.gut_plugin.show_output_panel()
func _save_to_config_file(f : ConfigFile):
f.clear()
f.set_value('main', 'run_mode', run_mode)
f.set_value('main', 'additional_arguments', opt_maker.controls.additional_arguments.value)
func save_to_file(path = default_path):
_save_to_config_file(_config_file)
_config_file.save(path)
func _load_from_config_file(f):
run_mode = f.get_value('main', 'run_mode', RUN_MODE_EDITOR)
opt_maker.controls.additional_arguments.value = \
f.get_value('main', 'additional_arguments', '')
func load_from_file(path = default_path):
_config_file.load(path)
_load_from_config_file(_config_file)
func reset():
_load_from_config_file(_config_file)
func get_additional_arguments_array():
return additional_arguments.split(" ", false)
func should_run_externally():
return run_mode != RUN_MODE_EDITOR
var _invalid_args = [
'-d', '--debug',
'-s', '--script',
'-e', '--editor'
]
var _invalid_blocking_args = [
'--headless'
]
func validate_arguments():
var arg_array = get_additional_arguments_array()
var i = 0
var invalid_found = false
while i < _invalid_args.size() and !invalid_found:
if(arg_array.has(_invalid_args[i])):
invalid_found = true
i += 1
if(run_mode == RUN_MODE_BLOCKING):
i = 0
while i < _invalid_blocking_args.size() and !invalid_found:
if(arg_array.has(_invalid_blocking_args[i])):
invalid_found = true
i += 1
return !invalid_found
func get_godot_help():
return ''

View file

@ -0,0 +1 @@
uid://c64u22kybimgi

View file

@ -0,0 +1,34 @@
[gd_scene load_steps=2 format=3 uid="uid://ckv5eh8xyrwbk"]
[ext_resource type="Script" uid="uid://c64u22kybimgi" path="res://addons/gut/gui/ShellOutOptions.gd" id="1_ht2pf"]
[node name="ShellOutOptions" type="ConfirmationDialog"]
oversampling_override = 1.0
title = "GUT Run Mode (Experimental)"
position = Vector2i(0, 36)
size = Vector2i(516, 557)
visible = true
script = ExtResource("1_ht2pf")
[node name="ScrollContainer" type="ScrollContainer" parent="."]
custom_minimum_size = Vector2(500, 500)
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 8.0
offset_top = 8.0
offset_right = -8.0
offset_bottom = -49.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="AcceptDialog" type="AcceptDialog" parent="."]
oversampling_override = 1.0
size = Vector2i(399, 106)
dialog_text = "Invalid arguments. The following cannot be used:
-d --debug -s --script"

View file

@ -120,6 +120,8 @@ func get_shortcut():
to_return.events.append(_source_event)
return to_return
func get_input_event():
return _source_event
func set_shortcut(sc):
if(sc == null or sc.events == null || sc.events.size() <= 0):

View file

@ -1 +1 @@
uid://byhinwdh4mxic
uid://k6hvvpekp0xw

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://sfb1fw8j6ufu"]
[ext_resource type="Script" path="res://addons/gut/gui/ShortcutButton.gd" id="1"]
[ext_resource type="Script" uid="uid://k6hvvpekp0xw" path="res://addons/gut/gui/ShortcutButton.gd" id="1"]
[node name="ShortcutButton" type="Control"]
custom_minimum_size = Vector2(210, 30)

View file

@ -0,0 +1,120 @@
@tool
extends ConfirmationDialog
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
var default_path = GutEditorGlobals.editor_shortcuts_path
@onready var scbtn_run_all = $Scroll/Layout/CRunAll/ShortcutButton
@onready var scbtn_run_current_script = $Scroll/Layout/CRunCurrentScript/ShortcutButton
@onready var scbtn_run_current_inner = $Scroll/Layout/CRunCurrentInner/ShortcutButton
@onready var scbtn_run_current_test = $Scroll/Layout/CRunCurrentTest/ShortcutButton
@onready var scbtn_run_at_cursor = $Scroll/Layout/CRunAtCursor/ShortcutButton
@onready var scbtn_rerun = $Scroll/Layout/CRerun/ShortcutButton
@onready var scbtn_panel = $Scroll/Layout/CPanelButton/ShortcutButton
@onready var scbtn_windowed = $Scroll/Layout/CToggleWindowed/ShortcutButton
@onready var all_buttons = [
scbtn_run_all, scbtn_run_current_script, scbtn_run_current_inner,
scbtn_run_current_test, scbtn_run_at_cursor, scbtn_rerun,
scbtn_panel, scbtn_windowed
]
func _debug_ready():
popup_centered()
var btn = Button.new()
btn.text = "show"
get_tree().root.add_child(btn)
btn.pressed.connect(popup)
btn.position = Vector2(100, 100)
btn.size = Vector2(100, 100)
size_changed.connect(func(): title = str(size))
func _ready():
for scbtn in all_buttons:
scbtn.connect('start_edit', _on_edit_start.bind(scbtn))
scbtn.connect('end_edit', _on_edit_end)
canceled.connect(_on_cancel)
# Sizing this window on different monitors, especially compared to what it
# looks like if you just run this project is annoying. This is what I came
# up with after getting annoyed. You probably won't be looking at this
# very often so it's fine...until it isn't.
size = Vector2(DisplayServer.screen_get_size()) * Vector2(.5, .8)
if(get_parent() == get_tree().root):
_debug_ready.call_deferred()
func _cancel_all():
for scbtn in all_buttons:
scbtn.cancel()
# ------------
# Events
# ------------
func _on_cancel():
_cancel_all()
load_shortcuts()
func _on_edit_start(which):
for scbtn in all_buttons:
if(scbtn != which):
scbtn.disable_set(true)
scbtn.disable_clear(true)
func _on_edit_end():
for scbtn in all_buttons:
scbtn.disable_set(false)
scbtn.disable_clear(false)
# ------------
# Public
# ------------
func save_shortcuts():
save_shortcuts_to_file(default_path)
func save_shortcuts_to_file(path):
var f = ConfigFile.new()
f.set_value('main', 'panel_button', scbtn_panel.get_shortcut())
f.set_value('main', 'rerun', scbtn_rerun.get_shortcut())
f.set_value('main', 'run_all', scbtn_run_all.get_shortcut())
f.set_value('main', 'run_at_cursor', scbtn_run_at_cursor.get_shortcut())
f.set_value('main', 'run_current_inner', scbtn_run_current_inner.get_shortcut())
f.set_value('main', 'run_current_script', scbtn_run_current_script.get_shortcut())
f.set_value('main', 'run_current_test', scbtn_run_current_test.get_shortcut())
# f.set_value('main', 'toggle_windowed', scbtn_windowed.get_shortcut())
f.save(path)
func load_shortcuts():
load_shortcuts_from_file(default_path)
func load_shortcuts_from_file(path):
var f = ConfigFile.new()
# as long as this shortcut is never modified, this is fine, otherwise
# each thing should get its own default instead.
var empty = Shortcut.new()
f.load(path)
scbtn_panel.set_shortcut(f.get_value('main', 'panel_button', empty))
scbtn_rerun.set_shortcut(f.get_value('main', 'rerun', empty))
scbtn_run_all.set_shortcut(f.get_value('main', 'run_all', empty))
scbtn_run_at_cursor.set_shortcut(f.get_value('main', 'run_at_cursor', empty))
scbtn_run_current_inner.set_shortcut(f.get_value('main', 'run_current_inner', empty))
scbtn_run_current_script.set_shortcut(f.get_value('main', 'run_current_script', empty))
scbtn_run_current_test.set_shortcut(f.get_value('main', 'run_current_test', empty))
# scbtn_windowed.set_shortcut(f.get_value('main', 'toggle_windowed', empty))

View file

@ -0,0 +1 @@
uid://dc5jgemxslgvl

View file

@ -0,0 +1,209 @@
[gd_scene format=3 uid="uid://dj5ve0bq7xa5j"]
[ext_resource type="Script" uid="uid://dc5jgemxslgvl" path="res://addons/gut/gui/ShortcutDialog.gd" id="1_qq8qn"]
[ext_resource type="PackedScene" uid="uid://sfb1fw8j6ufu" path="res://addons/gut/gui/ShortcutButton.tscn" id="2_i3wie"]
[node name="ShortcutDialog" type="ConfirmationDialog" unique_id=1776753623]
oversampling_override = 1.0
title = "GUT Shortcuts"
position = Vector2i(0, 36)
size = Vector2i(1920, 1728)
visible = true
script = ExtResource("1_qq8qn")
[node name="Scroll" type="ScrollContainer" parent="." unique_id=1914806303]
offset_left = 8.0
offset_top = 8.0
offset_right = 1912.0
offset_bottom = 1679.0
[node name="Layout" type="VBoxContainer" parent="Scroll" unique_id=501181924]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ShortcutDescription" type="RichTextLabel" parent="Scroll/Layout" unique_id=945401700]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "Shortcuts for:
- Buttons in Panel
- Project->Tools->GUT menu items
Shortcuts that only apply to menus are labeled."
fit_content = true
scroll_active = false
[node name="TopPad" type="CenterContainer" parent="Scroll/Layout" unique_id=1405248155]
custom_minimum_size = Vector2(0, 5)
layout_mode = 2
[node name="CPanelButton" type="HBoxContainer" parent="Scroll/Layout" unique_id=1970478925]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CPanelButton" unique_id=1534644867]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Show/Hide GUT"
[node name="ShortcutButton" parent="Scroll/Layout/CPanelButton" unique_id=2131329924 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription2" type="RichTextLabel" parent="Scroll/Layout" unique_id=2145896902]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Show/hide the gut panel or move focus to/away from the GUT window.
[/i]"
fit_content = true
scroll_active = false
[node name="CRunAll" type="HBoxContainer" parent="Scroll/Layout" unique_id=1158078093]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CRunAll" unique_id=1066237403]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run All"
[node name="ShortcutButton" parent="Scroll/Layout/CRunAll" unique_id=738525032 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription3" type="RichTextLabel" parent="Scroll/Layout" unique_id=140757094]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Run the entire test suite.[/i]"
fit_content = true
scroll_active = false
[node name="CRunCurrentScript" type="HBoxContainer" parent="Scroll/Layout" unique_id=736016343]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CRunCurrentScript" unique_id=950095716]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Script"
[node name="ShortcutButton" parent="Scroll/Layout/CRunCurrentScript" unique_id=983079158 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription4" type="RichTextLabel" parent="Scroll/Layout" unique_id=1806489359]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Run all tests in the currently selected script.[/i]"
fit_content = true
scroll_active = false
[node name="CRunCurrentInner" type="HBoxContainer" parent="Scroll/Layout" unique_id=2095658353]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CRunCurrentInner" unique_id=1492835813]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Inner Class"
[node name="ShortcutButton" parent="Scroll/Layout/CRunCurrentInner" unique_id=1400542413 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription5" type="RichTextLabel" parent="Scroll/Layout" unique_id=1669546632]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Run only the currently selected inner test class if one is selected.[/i]"
fit_content = true
scroll_active = false
[node name="CRunCurrentTest" type="HBoxContainer" parent="Scroll/Layout" unique_id=641427686]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CRunCurrentTest" unique_id=879088006]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run Current Test"
[node name="ShortcutButton" parent="Scroll/Layout/CRunCurrentTest" unique_id=1073304800 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription6" type="RichTextLabel" parent="Scroll/Layout" unique_id=164300543]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Run only the currently selected test, if one is selected[/i]"
fit_content = true
scroll_active = false
[node name="CRunAtCursor" type="HBoxContainer" parent="Scroll/Layout" unique_id=1201163993]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CRunAtCursor" unique_id=1748949401]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Run At Cursor (menu only)"
[node name="ShortcutButton" parent="Scroll/Layout/CRunAtCursor" unique_id=282512521 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription7" type="RichTextLabel" parent="Scroll/Layout" unique_id=1040671512]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Run the most specific test/inner class/script based on where the cursor is.[/i]"
fit_content = true
scroll_active = false
[node name="CRerun" type="HBoxContainer" parent="Scroll/Layout" unique_id=1620841467]
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CRerun" unique_id=1644131487]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Rerun (menu only)"
[node name="ShortcutButton" parent="Scroll/Layout/CRerun" unique_id=782836241 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription8" type="RichTextLabel" parent="Scroll/Layout" unique_id=520952349]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Rerun the test(s) that were last run."
fit_content = true
scroll_active = false
[node name="CToggleWindowed" type="HBoxContainer" parent="Scroll/Layout" unique_id=1521839247]
visible = false
layout_mode = 2
[node name="Label" type="Label" parent="Scroll/Layout/CToggleWindowed" unique_id=728639840]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
size_flags_vertical = 7
text = "Toggle Windowed"
[node name="ShortcutButton" parent="Scroll/Layout/CToggleWindowed" unique_id=603114021 instance=ExtResource("2_i3wie")]
layout_mode = 2
size_flags_horizontal = 3
[node name="ShortcutDescription9" type="RichTextLabel" parent="Scroll/Layout" unique_id=747035069]
visible = false
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
bbcode_enabled = true
text = "[i]Toggle GUT in the bottom panel or a separate window.[/i]"
fit_content = true
scroll_active = false

125
addons/gut/gui/about.gd Normal file
View file

@ -0,0 +1,125 @@
@tool
extends AcceptDialog
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
var _bbcode = \
"""
[center]GUT {gut_version}[/center]
[center][b]GUT Links[/b]
{gut_link_table}[/center]
[center][b]VSCode Extension Links[/b]
{vscode_link_table}[/center]
[center]You can support GUT development at
{donate_link}
Thanks for using GUT!
[/center]
"""
var _gut_links = [
[&"Documentation", &"https://gut.readthedocs.io"],
[&"What's New", &"https://github.com/bitwes/Gut/releases/tag/v{gut_version}"],
[&"Repo", &"https://github.com/bitwes/gut"],
[&"Report Bugs", &"https://github.com/bitwes/gut/issues"]
]
var _vscode_links = [
["Repo", "https://github.com/bitwes/gut-extension"],
["Market Place", "https://marketplace.visualstudio.com/items?itemName=bitwes.gut-extension"]
]
var _donate_link = "https://buymeacoffee.com/bitwes"
@onready var _logo = $Logo
func _ready():
if(get_parent() is SubViewport):
return
_vert_center_logo()
$Logo.disabled = true
$HBox/Scroll/RichTextLabel.text = _make_text()
func _color_link(link_text):
return str("[color=ROYAL_BLUE]", link_text, "[/color]")
func _link_table(entries):
var text = ''
for entry in entries:
text += str("[cell][right]", entry[0], "[/right][/cell]")
var link = str("[url]", entry[1], "[/url]")
if(entry[1].length() > 60):
link = str("[url=", entry[1], "]", entry[1].substr(0, 50), "...[/url]")
text += str("[cell][left]", _color_link(link), "[/left][/cell]\n")
return str('[table=2]', text, '[/table]')
func _make_text():
var gut_link_table = _link_table(_gut_links)
var vscode_link_table = _link_table(_vscode_links)
var text = _bbcode.format({
"gut_link_table":gut_link_table,
"vscode_link_table":vscode_link_table,
"donate_link":_color_link(str('[url]', _donate_link, '[/url]')),
"gut_version":GutUtils.version_numbers.gut_version,
})
return text
func _vert_center_logo():
_logo.position.y = size.y / 2.0
# -----------
# Events
# -----------
func _on_rich_text_label_meta_clicked(meta: Variant) -> void:
OS.shell_open(str(meta))
func _on_mouse_entered() -> void:
pass#_logo.active = true
func _on_mouse_exited() -> void:
pass#_logo.active = false
var _odd_ball_eyes_l = 1.1
var _odd_ball_eyes_r = .7
func _on_rich_text_label_meta_hover_started(meta: Variant) -> void:
if(meta == _gut_links[0][1]):
_logo.set_eye_color(Color.RED)
elif(meta.find("releases/tag/") > 0):
_logo.set_eye_color(Color.GREEN)
elif(meta == _gut_links[2][1]):
_logo.set_eye_color(Color.PURPLE)
elif(meta == _gut_links[3][1]):
_logo.set_eye_scale(1.2)
elif(meta == _vscode_links[0][1]):
_logo.set_eye_scale(.5, .5)
elif(meta == _vscode_links[1][1]):
_logo.set_eye_scale(_odd_ball_eyes_l, _odd_ball_eyes_r)
var temp = _odd_ball_eyes_l
_odd_ball_eyes_l = _odd_ball_eyes_r
_odd_ball_eyes_r = temp
elif(meta == _donate_link):
_logo.active = false
func _on_rich_text_label_meta_hover_ended(meta: Variant) -> void:
if(meta == _donate_link):
_logo.active = true
func _on_logo_pressed() -> void:
_logo.disabled = !_logo.disabled

View file

@ -0,0 +1 @@
uid://g7qu8ihdt3pd

56
addons/gut/gui/about.tscn Normal file
View file

@ -0,0 +1,56 @@
[gd_scene load_steps=5 format=3 uid="uid://dqbkylpsatcqm"]
[ext_resource type="Script" uid="uid://g7qu8ihdt3pd" path="res://addons/gut/gui/about.gd" id="1_bg86c"]
[ext_resource type="PackedScene" uid="uid://bjkn8mhx2fmt1" path="res://addons/gut/gui/GutLogo.tscn" id="3_kpic4"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q8rky"]
bg_color = Color(0, 0, 0, 0.49803922)
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kpic4"]
[node name="About" type="AcceptDialog"]
oversampling_override = 1.0
title = "About GUT"
position = Vector2i(0, 36)
size = Vector2i(1500, 800)
visible = true
min_size = Vector2i(800, 800)
script = ExtResource("1_bg86c")
[node name="HBox" type="HBoxContainer" parent="."]
offset_left = 8.0
offset_top = 8.0
offset_right = 1492.0
offset_bottom = 751.0
alignment = 1
[node name="MakeRoomForLogo" type="CenterContainer" parent="HBox"]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
[node name="Scroll" type="ScrollContainer" parent="HBox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="RichTextLabel" type="RichTextLabel" parent="HBox/Scroll"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_styles/normal = SubResource("StyleBoxFlat_q8rky")
theme_override_styles/focus = SubResource("StyleBoxEmpty_kpic4")
bbcode_enabled = true
fit_content = true
[node name="Logo" parent="." instance=ExtResource("3_kpic4")]
modulate = Color(0.74509805, 0.74509805, 0.74509805, 1)
position = Vector2(151, 265)
scale = Vector2(0.8, 0.8)
active = true
disabled = true
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]
[connection signal="meta_clicked" from="HBox/Scroll/RichTextLabel" to="." method="_on_rich_text_label_meta_clicked"]
[connection signal="meta_hover_ended" from="HBox/Scroll/RichTextLabel" to="." method="_on_rich_text_label_meta_hover_ended"]
[connection signal="meta_hover_started" from="HBox/Scroll/RichTextLabel" to="." method="_on_rich_text_label_meta_hover_started"]
[connection signal="pressed" from="Logo" to="." method="_on_logo_pressed"]

View file

@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/arrow.png-2b5b2d838b5b3467cf300ac2da1630d9.ct
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -25,6 +27,10 @@ mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -11,9 +11,10 @@ static var editor_run_gut_config_path = 'gut_editor_config.json':
get: return temp_directory.path_join(editor_run_gut_config_path)
# Should this print a message or something instead? Probably, but then I'd
# be repeating even more code than if this was just a constant. So I didn't,
# even though I wanted to put make the message a easter eggish fun message.
# even though I wanted to make the message a easter eggish fun message.
# I didn't, so this dumb comment will have to serve as the easter eggish fun.
set(v): pass
set(v):
print("Be sure to document your code. Never trust comments.")
static var editor_run_bbcode_results_path = 'gut_editor.bbcode':
@ -30,6 +31,9 @@ static var editor_shortcuts_path = 'gut_editor_shortcuts.cfg' :
get: return temp_directory.path_join(editor_shortcuts_path)
set(v): pass
static var run_externally_options_path = 'gut_editor_run_externally.cfg' :
get: return temp_directory.path_join(run_externally_options_path)
set(v): pass
static var _user_prefs = null
static var user_prefs = _user_prefs :
@ -38,10 +42,27 @@ static var user_prefs = _user_prefs :
# editor.
get:
if(_user_prefs == null and Engine.is_editor_hint()):
_user_prefs = GutUserPreferences.new(EditorInterface.get_editor_settings())
# This is sometimes used when not in the editor. Avoid parser error
# for EditorInterface.
_user_prefs = GutUserPreferences.new(GutUtils.get_editor_interface().get_editor_settings())
return _user_prefs
static var gut_plugin = null
static func create_temp_directory():
DirAccess.make_dir_recursive_absolute(temp_directory)
static func is_being_edited_in_editor(which):
if(!Engine.is_editor_hint()):
return false
var trav = which
var is_scene_root = false
var editor_root = which.get_tree().edited_scene_root
while(trav != null and !is_scene_root):
is_scene_root = editor_root == trav
if(!is_scene_root):
trav = trav.get_parent()
return is_scene_root

View file

@ -1 +1 @@
uid://b0cay8uv6i2kn
uid://cbi00ubn046c2

View file

@ -3,105 +3,33 @@ var GutConfig = load('res://addons/gut/gut_config.gd')
const DIRS_TO_LIST = 6
var _base_container = null
# All the various PanelControls indexed by thier gut_config keys.
var _cfg_ctrls = {}
# specific titles that we need to do stuff with
var _titles = {
dirs = null
}
# All titles so we can free them when we want.
var _all_titles = []
var _cfg_ctrls = {}
var opt_maker = null
func _init(cont):
_base_container = cont
func _add_title(text):
var row = PanelControls.BaseGutPanelControl.new(text, text)
_base_container.add_child(row)
row.connect('draw', _on_title_cell_draw.bind(row))
_all_titles.append(row)
return row
func _add_ctrl(key, ctrl):
_cfg_ctrls[key] = ctrl
_base_container.add_child(ctrl)
func _add_number(key, value, disp_text, v_min, v_max, hint=''):
var ctrl = PanelControls.NumberControl.new(disp_text, value, v_min, v_max, hint)
_add_ctrl(key, ctrl)
return ctrl
func _add_select(key, value, values, disp_text, hint=''):
var ctrl = PanelControls.SelectControl.new(disp_text, value, values, hint)
_add_ctrl(key, ctrl)
return ctrl
func _add_value(key, value, disp_text, hint=''):
var ctrl = PanelControls.StringControl.new(disp_text, value, hint)
_add_ctrl(key, ctrl)
return ctrl
func _add_boolean(key, value, disp_text, hint=''):
var ctrl = PanelControls.BooleanControl.new(disp_text, value, hint)
_add_ctrl(key, ctrl)
return ctrl
func _add_directory(key, value, disp_text, hint=''):
var ctrl = PanelControls.DirectoryControl.new(disp_text, value, hint)
_add_ctrl(key, ctrl)
ctrl.dialog.title = disp_text
return ctrl
func _add_file(key, value, disp_text, hint=''):
var ctrl = PanelControls.DirectoryControl.new(disp_text, value, hint)
_add_ctrl(key, ctrl)
ctrl.dialog.file_mode = ctrl.dialog.FILE_MODE_OPEN_FILE
ctrl.dialog.title = disp_text
return ctrl
func _add_save_file_anywhere(key, value, disp_text, hint=''):
var ctrl = PanelControls.DirectoryControl.new(disp_text, value, hint)
_add_ctrl(key, ctrl)
ctrl.dialog.file_mode = ctrl.dialog.FILE_MODE_SAVE_FILE
ctrl.dialog.access = ctrl.dialog.ACCESS_FILESYSTEM
ctrl.dialog.title = disp_text
return ctrl
func _add_color(key, value, disp_text, hint=''):
var ctrl = PanelControls.ColorControl.new(disp_text, value, hint)
_add_ctrl(key, ctrl)
return ctrl
opt_maker = GutUtils.OptionMaker.new(cont)
_cfg_ctrls = opt_maker.controls
# _base_container = cont
func _add_save_load():
var ctrl = PanelControls.SaveLoadControl.new('Config', '', '')
_base_container.add_child(ctrl)
ctrl.save_path_chosen.connect(_on_save_path_chosen)
ctrl.load_path_chosen.connect(_on_load_path_chosen)
_cfg_ctrls['save_load'] = ctrl
#_cfg_ctrls['save_load'] = ctrl
opt_maker.add_ctrl('save_load', ctrl)
return ctrl
# ------------------
# Events
# ------------------
func _on_title_cell_draw(which):
which.draw_rect(Rect2(Vector2(0, 0), which.size), Color(0, 0, 0, .15))
func _on_save_path_chosen(path):
save_file(path)
@ -145,15 +73,7 @@ func get_config_issues():
func clear():
for key in _cfg_ctrls:
_cfg_ctrls[key].free()
_cfg_ctrls.clear()
for entry in _all_titles:
entry.free()
_all_titles.clear()
opt_maker.clear()
func save_file(path):
@ -191,54 +111,65 @@ func set_options(opts):
# _add_title('Save/Load')
_add_save_load()
_add_title("Settings")
_add_number("log_level", options.log_level, "Log Level", 0, 3,
opt_maker.add_title("Settings")
opt_maker.add_number("log_level", options.log_level, "Log Level", 0, 3,
"Detail level for log messages.\n" + \
"\t0: Errors and failures only.\n" + \
"\t1: Adds all test names + warnings + info\n" + \
"\t2: Shows all asserts\n" + \
"\t3: Adds more stuff probably, maybe not.")
_add_boolean('ignore_pause', options.ignore_pause, 'Ignore Pause',
opt_maker.add_float("wait_log_delay", options.wait_log_delay, "Wait Log Delay", 0.1, 0.0, 999.1,
"How long to wait before displaying 'Awaiting' messages.")
opt_maker.add_boolean('ignore_pause', options.ignore_pause, 'Ignore Pause',
"Ignore calls to pause_before_teardown")
_add_boolean('hide_orphans', options.hide_orphans, 'Hide Orphans',
opt_maker.add_boolean('hide_orphans', options.hide_orphans, 'Hide Orphans',
'Do not display orphan counts in output.')
_add_boolean('should_exit', options.should_exit, 'Exit on Finish',
opt_maker.add_boolean('should_exit', options.should_exit, 'Exit on Finish',
"Exit when tests finished.")
_add_boolean('should_exit_on_success', options.should_exit_on_success, 'Exit on Success',
opt_maker.add_boolean('should_exit_on_success', options.should_exit_on_success, 'Exit on Success',
"Exit if there are no failures. Does nothing if 'Exit on Finish' is enabled.")
_add_select('double_strategy', 'Script Only', ['Include Native', 'Script Only'], 'Double Strategy',
opt_maker.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.value = 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('Runner Appearance')
hide_this = _add_boolean("gut_on_top", options.gut_on_top, "On Top",
opt_maker.add_title("Fail Error Types")
opt_maker.add_boolean("error_tracking", !options.no_error_tracking, 'Track Errors',
"Enable/Disable GUT's ability to detect engine and push errors.")
opt_maker.add_boolean('engine_errors_cause_failure', options.failure_error_types.has(GutConfig.FAIL_ERROR_TYPE_ENGINE),
'Engine', 'Any script/engine error that occurs during a test will cause the test to fail.')
opt_maker.add_boolean('push_error_errors_cause_failure', options.failure_error_types.has(GutConfig.FAIL_ERROR_TYPE_PUSH_ERROR),
'Push', 'Any error generated by a call to push_error that occurs during a test will cause the test to fail.')
opt_maker.add_boolean('gut_errors_cause_failure', options.failure_error_types.has(GutConfig.FAIL_ERROR_TYPE_GUT),
'GUT', 'Any internal GUT error that occurs while a test is running will cause it to fail..')
opt_maker.add_title('Runner Appearance')
hide_this = opt_maker.add_boolean("gut_on_top", options.gut_on_top, "On Top",
"The GUT Runner appears above children added during tests.")
_add_number('opacity', options.opacity, 'Opacity', 0, 100,
opt_maker.add_number('opacity', options.opacity, 'Opacity', 0, 100,
"The opacity of GUT when tests are running.")
hide_this = _add_boolean('should_maximize', options.should_maximize, 'Maximize',
hide_this = opt_maker.add_boolean('should_maximize', options.should_maximize, 'Maximize',
"Maximize GUT when tests are being run.")
_add_boolean('compact_mode', options.compact_mode, 'Compact Mode',
opt_maker.add_boolean('compact_mode', options.compact_mode, 'Compact Mode',
'The runner will be in compact mode. This overrides Maximize.')
_add_select('font_name', options.font_name, GutUtils.avail_fonts, 'Font',
opt_maker.add_select('font_name', options.font_name, GutUtils.avail_fonts, 'Font',
"The font to use for text output in the Gut Runner.")
_add_number('font_size', options.font_size, 'Font Size', 5, 100,
opt_maker.add_number('font_size', options.font_size, 'Font Size', 5, 100,
"The font size for text output in the Gut Runner.")
hide_this = _add_color('font_color', options.font_color, 'Font Color',
hide_this = opt_maker.add_color('font_color', options.font_color, 'Font Color',
"The font color for text output in the Gut Runner.")
_add_color('background_color', options.background_color, 'Background Color',
opt_maker.add_color('background_color', options.background_color, 'Background Color',
"The background color for text output in the Gut Runner.")
_add_boolean('disable_colors', options.disable_colors, 'Disable Formatting',
opt_maker.add_boolean('disable_colors', options.disable_colors, 'Disable Formatting',
'Disable formatting and colors used in the Runner. Does not affect panel output.')
_titles.dirs = _add_title('Test Directories')
_add_boolean('include_subdirs', options.include_subdirs, 'Include Subdirs',
_titles.dirs = opt_maker.add_title('Test Directories')
opt_maker.add_boolean('include_subdirs', options.include_subdirs, 'Include Subdirs',
"Include subdirectories of the directories configured below.")
var dirs_to_load = options.configured_dirs
@ -250,40 +181,35 @@ func set_options(opts):
if(dirs_to_load.size() > i):
value = dirs_to_load[i]
var test_dir = _add_directory(str('directory_', i), value, str(i))
var test_dir = opt_maker.add_directory(str('directory_', i), value, str(i))
test_dir.enabled_button.visible = true
test_dir.enabled_button.button_pressed = options.dirs.has(value)
_add_title("XML Output")
_add_save_file_anywhere("junit_xml_file", options.junit_xml_file, "Output Path",
"Path3D and filename where GUT should create a JUnit compliant XML file. " +
opt_maker.add_title("XML Output")
opt_maker.add_save_file_anywhere("junit_xml_file", options.junit_xml_file, "Output Path",
"Path and filename where GUT should create a JUnit compliant XML file. " +
"This file will contain the results of the last test run. To avoid " +
"overriding the file use Include Timestamp.")
_add_boolean("junit_xml_timestamp", options.junit_xml_timestamp, "Include Timestamp",
opt_maker.add_boolean("junit_xml_timestamp", options.junit_xml_timestamp, "Include Timestamp",
"Include a timestamp in the filename so that each run gets its own xml file.")
_add_title('Hooks')
_add_file('pre_run_script', options.pre_run_script, 'Pre-Run Hook',
opt_maker.add_title('Hooks')
opt_maker.add_file('pre_run_script', options.pre_run_script, 'Pre-Run Hook',
'This script will be run by GUT before any tests are run.')
_add_file('post_run_script', options.post_run_script, 'Post-Run Hook',
opt_maker.add_file('post_run_script', options.post_run_script, 'Post-Run Hook',
'This script will be run by GUT after all tests are run.')
_add_title('Misc')
_add_value('prefix', options.prefix, 'Script Prefix',
opt_maker.add_title('Misc')
opt_maker.add_value('prefix', options.prefix, 'Script Prefix',
"The filename prefix for all test scripts.")
_add_value('suffix', options.suffix, 'Script Suffix',
opt_maker.add_value('suffix', options.suffix, 'Script Suffix',
"Script suffix, including .gd extension. For example '_foo.gd'.")
_add_number('paint_after', options.paint_after, 'Paint After', 0.0, 1.0,
opt_maker.add_float('paint_after', options.paint_after, 'Paint After', .05, 0.0, 1.0,
"How long GUT will wait before pausing for 1 frame to paint the screen. 0 is never.")
# since _add_number doesn't set step property, it will default to a step of
# 1 and cast values to int. Give it a .5 step and re-set the value.
_cfg_ctrls.paint_after.value_ctrl.step = .05
_cfg_ctrls.paint_after.value = options.paint_after
func get_options(base_opts):
@ -291,13 +217,12 @@ func get_options(base_opts):
# Settings
to_return.log_level = _cfg_ctrls.log_level.value
to_return.wait_log_delay = _cfg_ctrls.wait_log_delay.value
to_return.ignore_pause = _cfg_ctrls.ignore_pause.value
to_return.hide_orphans = _cfg_ctrls.hide_orphans.value
to_return.should_exit = _cfg_ctrls.should_exit.value
to_return.should_exit_on_success = _cfg_ctrls.should_exit_on_success.value
to_return.double_strategy = _cfg_ctrls.double_strategy.value
to_return.errors_do_not_cause_failure = !_cfg_ctrls.errors_cause_failure.value
# Runner Appearance
to_return.font_name = _cfg_ctrls.font_name.text
@ -311,6 +236,17 @@ func get_options(base_opts):
to_return.gut_on_top = _cfg_ctrls.gut_on_top.value
to_return.paint_after = _cfg_ctrls.paint_after.value
# Fail Error Types
to_return.no_error_tracking = !_cfg_ctrls.error_tracking
var fail_error_types = []
if(_cfg_ctrls.engine_errors_cause_failure.value):
fail_error_types.append(GutConfig.FAIL_ERROR_TYPE_ENGINE)
if(_cfg_ctrls.push_error_errors_cause_failure.value):
fail_error_types.append(GutConfig.FAIL_ERROR_TYPE_PUSH_ERROR)
if(_cfg_ctrls.gut_errors_cause_failure.value):
fail_error_types.append(GutConfig.FAIL_ERROR_TYPE_GUT)
to_return.failure_error_types = fail_error_types
# Directories
to_return.include_subdirs = _cfg_ctrls.include_subdirs.value

View file

@ -1 +1 @@
uid://xlv525p30gpr
uid://chosc1tvfaduq

View file

@ -0,0 +1,37 @@
extends EditorDock
var _panel : Control = null
var _current_layout = -1
func _update_layout(layout):
_current_layout = layout
if(_panel != null):
if(layout == DOCK_LAYOUT_FLOATING):
_windowed_mode()
else:
_dock_mode()
# -------------
# Private
# -------------
func _windowed_mode():
_panel.show_layout_buttons(true)
func _dock_mode():
_panel.results_horiz_layout()
_panel.show_layout_buttons(false)
# -------------
# Public
# -------------
func add_bottom_panel(gut_bottom_panel):
_panel = gut_bottom_panel
# Make floating button not supported right now
add_child(_panel)
_panel.make_floating_btn.visible = false
_update_layout(_current_layout)

View file

@ -0,0 +1 @@
uid://cmj50k82tckur

View file

@ -24,6 +24,7 @@ var _ctrls = {
time_label = null,
title = null,
title_bar = null,
tgl_word_wrap = null, # optional
}
var _title_mouse = {
@ -42,6 +43,8 @@ func _ready():
_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)
if(_ctrls.tgl_word_wrap != null):
_ctrls.tgl_word_wrap.toggled.connect(_on_word_wrap_toggled)
_ctrls.prog_script.value = 0
_ctrls.prog_test.value = 0
@ -79,6 +82,7 @@ func _populate_ctrls():
_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)
_ctrls.tgl_word_wrap = _get_first_child_named("WordWrap", self)
func _get_first_child_named(obj_name, parent_obj):
@ -96,7 +100,7 @@ func _get_first_child_named(obj_name, parent_obj):
to_return = _get_first_child_named(obj_name, kids[index])
if(to_return == null):
index += 1
return to_return
@ -157,6 +161,9 @@ func _on_gut_end_pause():
func _on_switch_modes_pressed():
switch_modes.emit()
func _on_word_wrap_toggled(toggled):
_ctrls.rtl.autowrap_mode = toggled
# ------------------
# Public
# ------------------

View file

@ -1 +1 @@
uid://xsm23flin7t3
uid://blvhsbnsvfyow

225
addons/gut/gui/gut_logo.gd Normal file
View file

@ -0,0 +1,225 @@
@tool
extends Node2D
class Eyeball:
extends Node2D
var _should_draw_laser = false
var _laser_end_pos = Vector2.ZERO
var _laser_timer : Timer = null
var _color_tween : Tween
var _size_tween : Tween
var sprite : Sprite2D = null
var default_position = Vector2(0, 0)
var move_radius = 25
var move_center = Vector2(0, 0)
var default_color = Color(0.31, 0.31, 0.31)
var _color = default_color :
set(val):
_color = val
queue_redraw()
var color = _color :
set(val):
_start_color_tween(_color, val)
get(): return _color
var default_size = 70
var _size = default_size :
set(val):
_size = val
queue_redraw()
var size = _size :
set(val):
_start_size_tween(_size, val)
get(): return _size
func _init(node):
sprite = node
default_position = sprite.position
move_center = sprite.position
# hijack the original sprite, because I want to draw it here but keep
# the original in the scene for layout.
position = sprite.position
sprite.get_parent().add_child(self)
sprite.visible = false
func _ready():
_laser_timer = Timer.new()
_laser_timer.wait_time = .1
_laser_timer.one_shot = true
add_child(_laser_timer)
_laser_timer.timeout.connect(func(): _should_draw_laser = false)
func _process(_delta):
if(_should_draw_laser):
queue_redraw()
func _start_color_tween(old_color, new_color):
if(_color_tween != null and _color_tween.is_running()):
_color_tween.kill()
_color_tween = create_tween()
_color_tween.tween_property(self, '_color', new_color, .3).from(old_color)
_color_tween.play()
func _start_size_tween(old_size, new_size):
if(_size_tween != null and _size_tween.is_running()):
_size_tween.kill()
_size_tween = create_tween()
_size_tween.tween_property(self, '_size', new_size, .3).from(old_size)
_size_tween.play()
var _laser_size = 20.0
func _draw() -> void:
draw_circle(Vector2.ZERO, size, color, true, -1, true)
if(_should_draw_laser):
var end_pos = (_laser_end_pos - global_position) * 2
var laser_size = _laser_size * (float(size)/float(default_size))
draw_line(Vector2.ZERO, end_pos, color, laser_size)
draw_line(Vector2.ZERO, end_pos, Color(1, 1, 1, .5), laser_size * .8)
# There's a bug in here where the eye shakes like crazy. It's a feature
# now. Don't fix it.
func look_at_local_position(local_pos):
var dir = position.direction_to(local_pos)
var dist = position.distance_to(local_pos)
position = move_center + (dir * min(dist, move_radius))
position.x = clamp(position.x, move_center.x - move_radius, move_center.x + move_radius)
position.y = clamp(position.y, move_center.y - move_radius, move_center.y + move_radius)
func reset():
color = default_color
size = default_size
func eye_laser(global_pos):
_should_draw_laser = true
_laser_end_pos = global_pos
_laser_timer.start()
func _stop_laser():
_should_draw_laser = false
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
# Active means it's actively doing stuff. When this is not active the eyes
# won't follow, but you can still make the sizes change by calling methods on
# this.
@export var active = false :
set(val):
active = val
if(!active and is_inside_tree()):
left_eye.position = left_eye.default_position
right_eye.position = right_eye.default_position
# When disabled, this will reset to default and you can't make it do anything.
@export var disabled = false :
set(val):
disabled = val
if(disabled and is_inside_tree()):
left_eye.position = left_eye.default_position
right_eye.position = right_eye.default_position
left_eye.reset()
right_eye.reset()
modulate = Color.GRAY
$BaseLogo.texture = _no_shine
else:
$BaseLogo.texture = _normal
modulate = Color.WHITE
@onready var _reset_timer = $ResetTimer
@onready var _face_button = $FaceButton
@onready var left_eye : Eyeball = Eyeball.new($BaseLogo/LeftEye)
@onready var right_eye : Eyeball = Eyeball.new($BaseLogo/RightEye)
var _no_shine = load("res://addons/gut/images/GutIconV2_no_shine.png")
var _normal = load("res://addons/gut/images/GutIconV2_base.png")
var _is_in_edited_scene = false
signal pressed
func _debug_ready():
position = Vector2(500, 500)
active = true
func _ready():
_is_in_edited_scene = GutEditorGlobals.is_being_edited_in_editor(self)
if(get_parent() == get_tree().root):
_debug_ready()
disabled = disabled
active = active
left_eye.move_center.x -= 20
right_eye.move_center.x += 10
_face_button.modulate.a = 0.0
func _process(_delta):
if(active and !disabled and !_is_in_edited_scene):
left_eye.look_at_local_position(get_local_mouse_position())
right_eye.look_at_local_position(get_local_mouse_position())
# ----------------
# Events
# ----------------
func _on_reset_timer_timeout() -> void:
left_eye.reset()
right_eye.reset()
func _on_face_button_pressed() -> void:
pressed.emit()
# ----------------
# Public
# ----------------
func set_eye_scale(left, right=left):
if(disabled or _is_in_edited_scene):
return
left_eye.size = left_eye.default_size * left
right_eye.size = right_eye.default_size * right
_reset_timer.start()
func reset_eye_size():
if(disabled or _is_in_edited_scene):
return
left_eye.size = left_eye.default_size
right_eye.size = right_eye.default_size
func set_eye_color(left, right=left):
if(disabled or _is_in_edited_scene):
return
left_eye.color = left
right_eye.color = right
_reset_timer.start()
func reset_eye_color():
if(disabled or _is_in_edited_scene):
return
left_eye.color = left_eye.default_color
right_eye.color = right_eye.default_color
# I removed the eye lasers because they aren't ready yet. I've already spent
# too much time on this logo. It's great, I love it...but it's been long
# enough. This gives me, or someone else, something to do later.
#func eye_lasers(global_pos):
#left_eye.eye_laser(global_pos)
#right_eye.eye_laser(global_pos)

View file

@ -0,0 +1 @@
uid://b8lvgepb64m8t

View file

@ -37,12 +37,11 @@ var hide_result_tree = null
var hide_output_text = null
var hide_settings = null
var use_colors = null # ? might be output panel
# var shortcut_run_all = null
# var shortcut_run_current_script = null
# var shortcut_run_current_inner = null
# var shortcut_run_current_test = null
# var shortcut_panel_button = null
var run_externally = null
var run_externally_options_dialog_size = null
var shortcuts_dialog_size = null
var gut_window_size = null
var gut_window_on_top = null
func _init(editor_settings):
@ -52,12 +51,12 @@ func _init(editor_settings):
hide_output_text = GutEditorPref.new('hide_output_text', false, editor_settings)
hide_settings = GutEditorPref.new('hide_settings', false, editor_settings)
use_colors = GutEditorPref.new('use_colors', true, editor_settings)
run_externally = GutEditorPref.new('run_externally', false, editor_settings)
run_externally_options_dialog_size = GutEditorPref.new('run_externally_options_dialog_size', Vector2i(-1, -1), editor_settings)
shortcuts_dialog_size = GutEditorPref.new('shortcuts_dialog_size', Vector2i(-1, -1), editor_settings)
gut_window_size = GutEditorPref.new('editor_window_size', Vector2i(-1, -1), editor_settings)
gut_window_on_top = GutEditorPref.new('editor_window_on_top', false, editor_settings)
# shortcut_run_all = GutEditorPref.new('shortcut_run_all', EMPTY, editor_settings)
# shortcut_run_current_script = GutEditorPref.new('shortcut_run_current_script', EMPTY, editor_settings)
# shortcut_run_current_inner = GutEditorPref.new('shortcut_run_current_inner', EMPTY, editor_settings)
# shortcut_run_current_test = GutEditorPref.new('shortcut_run_current_test', EMPTY, editor_settings)
# shortcut_panel_button = GutEditorPref.new('shortcut_panel_button', EMPTY, editor_settings)
func save_it():
for prop in get_property_list():
@ -77,4 +76,4 @@ func erase_all():
for prop in get_property_list():
var val = get(prop.name)
if(val is GutEditorPref):
val.erase()
val.erase()

View file

@ -1 +1 @@
uid://3n0bh8lrcprr
uid://dsndkn6whyiov

View file

@ -0,0 +1,124 @@
var PanelControls = load("res://addons/gut/gui/panel_controls.gd")
# All titles so we can free them when we want.
var _all_titles = []
var base_container = null
# All the various PanelControls indexed by thier keys.
var controls = {}
func _init(cont):
base_container = cont
func add_title(text):
var row = PanelControls.BaseGutPanelControl.new(text, text)
base_container.add_child(row)
row.connect('draw', _on_title_cell_draw.bind(row))
_all_titles.append(row)
return row
func add_ctrl(key, ctrl):
controls[key] = ctrl
base_container.add_child(ctrl)
func add_number(key, value, disp_text, v_min, v_max, hint=''):
var ctrl = PanelControls.NumberControl.new(disp_text, value, v_min, v_max, hint)
add_ctrl(key, ctrl)
return ctrl
func add_float(key, value, disp_text, step, v_min, v_max, hint=''):
var ctrl = PanelControls.FloatControl.new(disp_text, value, step, v_min, v_max, hint)
add_ctrl(key, ctrl)
return ctrl
func add_select(key, value, values, disp_text, hint=''):
var ctrl = PanelControls.SelectControl.new(disp_text, value, values, hint)
add_ctrl(key, ctrl)
return ctrl
func add_value(key, value, disp_text, hint=''):
var ctrl = PanelControls.StringControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
func add_multiline_text(key, value, disp_text, hint=''):
var ctrl = PanelControls.MultiLineStringControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
func add_boolean(key, value, disp_text, hint=''):
var ctrl = PanelControls.BooleanControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
func add_directory(key, value, disp_text, hint=''):
var ctrl = PanelControls.DirectoryControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
ctrl.dialog.title = disp_text
return ctrl
func add_file(key, value, disp_text, hint=''):
var ctrl = PanelControls.DirectoryControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
ctrl.dialog.file_mode = ctrl.dialog.FILE_MODE_OPEN_FILE
ctrl.dialog.title = disp_text
return ctrl
func add_save_file_anywhere(key, value, disp_text, hint=''):
var ctrl = PanelControls.DirectoryControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
ctrl.dialog.file_mode = ctrl.dialog.FILE_MODE_SAVE_FILE
ctrl.dialog.access = ctrl.dialog.ACCESS_FILESYSTEM
ctrl.dialog.title = disp_text
return ctrl
func add_color(key, value, disp_text, hint=''):
var ctrl = PanelControls.ColorControl.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
var _blurbs = 0
func add_blurb(text):
var ctrl = RichTextLabel.new()
ctrl.fit_content = true
ctrl.bbcode_enabled = true
ctrl.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
ctrl.text = text
add_ctrl(str("blurb_", _blurbs), ctrl)
return ctrl
# ------------------
# Events
# ------------------
func _on_title_cell_draw(which):
which.draw_rect(Rect2(Vector2(0, 0), which.size), Color(0, 0, 0, .15))
# ------------------
# Public
# ------------------
func clear():
for key in controls:
controls[key].free()
controls.clear()
for entry in _all_titles:
entry.free()
_all_titles.clear()

View file

@ -0,0 +1 @@
uid://bjahqsqo645sf

View file

@ -78,6 +78,17 @@ class NumberControl:
value_ctrl.value = val
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
class FloatControl:
extends NumberControl
func _init(title, val, step, v_min, v_max, hint=""):
super._init(title, val, v_min, v_max, hint)
value_ctrl.step = step
value_ctrl.value = val
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
class StringControl:
@ -93,6 +104,38 @@ class StringControl:
value_ctrl.text_changed.connect(_on_text_changed)
value_ctrl.select_all_on_focus = true
add_child(value_ctrl)
if(title == ''):
label.visible = false
func _on_text_changed(new_value):
changed.emit()
func get_value():
return value_ctrl.text
func set_value(val):
value_ctrl.text = val
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
class MultiLineStringControl:
extends BaseGutPanelControl
var value_ctrl = TextEdit.new()
func _init(title, val, hint=""):
super._init(title, val, hint)
var vbox = VBoxContainer.new()
vbox.size_flags_horizontal = SIZE_EXPAND_FILL
add_child(vbox)
label.reparent(vbox)
value_ctrl.size_flags_horizontal = value_ctrl.SIZE_EXPAND_FILL
value_ctrl.text = val
value_ctrl.text_changed.connect(_on_text_changed)
value_ctrl.scroll_fit_content_height = true
vbox.add_child(value_ctrl)
func _on_text_changed(new_value):
changed.emit()

View file

@ -1 +1 @@
uid://48ebclaq0ewd
uid://db54jy04d8w7p

View file

@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/play.png-5c90e88e8136487a183a099d67a7de24.cte
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
@ -25,6 +27,10 @@ mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false

View file

@ -16,4 +16,3 @@ func _ready() -> void:
var runner : Node = load("res://addons/gut/gui/GutRunner.tscn").instantiate()
add_child(runner)
runner.run_from_editor()
GutLoader.restore_ignore_addons()

View file

@ -1 +1 @@
uid://dkqis5sjx5mb4
uid://bwf2iuidqfkpl

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://bgj3fm5d8yvjw"]
[ext_resource type="Script" path="res://addons/gut/gui/run_from_editor.gd" id="1_53pap"]
[ext_resource type="Script" uid="uid://bwf2iuidqfkpl" path="res://addons/gut/gui/run_from_editor.gd" id="1_53pap"]
[node name="RunFromEditor" type="Node2D"]
script = ExtResource("1_53pap")

View file

@ -1,239 +0,0 @@
# Holds weakrefs to a ScriptTextEditor and related children nodes
# 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:
var _text_edit = null
var _script_editor = null
var _code_editor = null
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
# type of control we care about. Chances are there won't be more than
# one of these in the future, but their position in the tree may change.
_code_editor = weakref(_get_first_child_named('CodeTextEditor', _script_editor.get_ref()))
_text_edit = weakref(_get_first_child_named("CodeEdit", _code_editor.get_ref()))
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
func get_script_text_edit():
return _script_editor.get_ref()
func get_text_edit():
# ScriptTextEditors that are loaded when the project is opened
# do not have their children populated yet. So if we may have to
# _populate_controls again if we don't have one.
if(_text_edit == null):
_populate_controls()
return _text_edit.get_ref()
func get_script_editor():
return _script_editor
func is_visible():
var to_return = false
if(_script_editor.get_ref()):
to_return = _script_editor.get_ref().visible
return to_return
# ##############################################################################
#
# ##############################################################################
# Used to make searching for the controls easier and faster.
var _script_editors_parent = null
# reference the ScriptEditor instance
var _script_editor = null
# Array of ScriptEditorControlRef containing all the opened ScriptTextEditors
# and related controls at the time of the last refresh.
var _script_editor_controls = []
var _method_prefix = 'test_'
var _inner_class_prefix = 'Test'
func _init(script_edit):
_script_editor = script_edit
refresh()
func _is_script_editor(obj):
return str(obj).find('<ScriptTextEditor') != -1
# Find the first ScriptTextEditor and then get its parent. Done this way
# because who knows if the parent object will change. This is somewhat
# future proofed.
func _find_script_editors_parent():
var _first_editor = _get_first_child_of_type_name("ScriptTextEditor", _script_editor)
if(_first_editor != null):
_script_editors_parent = _first_editor.get_parent()
func _populate_editors():
if(_script_editors_parent == null):
return
_script_editor_controls.clear()
for child in _script_editors_parent.get_children():
if(_is_script_editor(child)):
var ref = ScriptEditorControlRef.new(child)
_script_editor_controls.append(ref)
# Yes, this is the same as the one above but with a different name. This was
# 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):
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])
if(to_return == null):
index += 1
return to_return
func _get_func_name_from_line(text):
text = text.strip_edges()
var left = text.split("(")[0]
var func_name = left.split(" ")[1]
return func_name
func _get_class_name_from_line(text):
text = text.strip_edges()
var right = text.split(" ")[1]
var the_name = right.rstrip(":")
return the_name
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
var idx = 0
while(idx < _script_editor_controls.size() and cur_script_editor == null):
if(_script_editor_controls[idx].is_visible()):
cur_script_editor = _script_editor_controls[idx]
else:
idx += 1
var to_return = null
if(cur_script_editor != null):
to_return = cur_script_editor.get_text_edit()
return to_return
func get_script_editor_controls():
var to_return = []
for ctrl_ref in _script_editor_controls:
to_return.append(ctrl_ref.get_script_text_edit())
return to_return
func get_line_info():
var editor = get_current_text_edit()
if(editor == null):
return
var info = {
script = null,
inner_class = null,
test_method = null
}
var line = editor.get_caret_line()
var done_func = false
var done_inner = false
while(line > 0 and (!done_func or !done_inner)):
if(editor.can_fold_line(line)):
var text = editor.get_line(line)
var strip_text = text.strip_edges(true, false) # only left
if(!done_func and strip_text.begins_with("func ")):
var func_name = _get_func_name_from_line(text)
if(func_name.begins_with(_method_prefix)):
info.test_method = func_name
done_func = true
# If the func line is left justified then there won't be any
# inner classes above it.
if(strip_text == text):
done_inner = true
if(!done_inner and strip_text.begins_with("class")):
var inner_name = _get_class_name_from_line(text)
if(inner_name.begins_with(_inner_class_prefix)):
info.inner_class = inner_name
done_inner = true
# if we found an inner class then we are already past
# any test the cursor could be in.
done_func = true
line -= 1
return info
func get_method_prefix():
return _method_prefix
func set_method_prefix(method_prefix):
_method_prefix = method_prefix
func get_inner_class_prefix():
return _inner_class_prefix
func set_inner_class_prefix(inner_class_prefix):
_inner_class_prefix = inner_class_prefix

View file

@ -1 +0,0 @@
uid://dsc4xxr52mh52