mirror of
https://codeberg.org/sunder/sunder.git
synced 2026-03-12 13:20:32 +00:00
upgrade gut
This commit is contained in:
parent
6e724f67fe
commit
82aeebfd35
201 changed files with 8547 additions and 3871 deletions
|
|
@ -91,9 +91,11 @@ func _set_font(rtl, font_name, custom_name):
|
|||
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)
|
||||
var font_path = 'res://addons/gut/fonts/' + font_name + '.ttf'
|
||||
if(FileAccess.file_exists(font_path)):
|
||||
var dyn_font = FontFile.new()
|
||||
dyn_font.load_dynamic_font('res://addons/gut/fonts/' + font_name + '.ttf')
|
||||
rtl.add_theme_font_override(custom_name, dyn_font)
|
||||
|
||||
|
||||
func _set_all_fonts_in_rtl(rtl, base_name):
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://bnydli77wadhj
|
||||
uid://bw7tukh738kw1
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://m28heqtswbuq"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/gut/GutScene.gd" id="1_b4m8y"]
|
||||
[ext_resource type="Script" uid="uid://bw7tukh738kw1" path="res://addons/gut/GutScene.gd" id="1_b4m8y"]
|
||||
[ext_resource type="PackedScene" uid="uid://duxblir3vu8x7" path="res://addons/gut/gui/NormalGui.tscn" id="2_j6ywb"]
|
||||
[ext_resource type="PackedScene" uid="uid://cnqqdfsn80ise" path="res://addons/gut/gui/MinGui.tscn" id="3_3glw1"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://d08awoq0h05xb
|
||||
uid://x51wilphva3d
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://bsm7wtt1gie4v"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/gut/UserFileViewer.gd" id="1"]
|
||||
[ext_resource type="Script" uid="uid://x51wilphva3d" path="res://addons/gut/UserFileViewer.gd" id="1"]
|
||||
|
||||
[node name="UserFileViewer" type="Window"]
|
||||
exclusive = true
|
||||
|
|
|
|||
|
|
@ -30,28 +30,57 @@
|
|||
# ##############################################################################
|
||||
var _to_free = []
|
||||
var _to_queue_free = []
|
||||
var _ref_counted_doubles = []
|
||||
var _all_instance_ids = []
|
||||
|
||||
|
||||
func _add_instance_id(thing):
|
||||
if(thing.has_method("get_instance_id")):
|
||||
_all_instance_ids.append(thing.get_instance_id())
|
||||
|
||||
|
||||
func add_free(thing):
|
||||
if(typeof(thing) == TYPE_OBJECT):
|
||||
_add_instance_id(thing)
|
||||
if(!thing is RefCounted):
|
||||
_to_free.append(thing)
|
||||
elif(GutUtils.is_double(thing)):
|
||||
_ref_counted_doubles.append(thing)
|
||||
|
||||
|
||||
func add_queue_free(thing):
|
||||
_to_queue_free.append(thing)
|
||||
if(typeof(thing) == TYPE_OBJECT):
|
||||
_add_instance_id(thing)
|
||||
_to_queue_free.append(thing)
|
||||
|
||||
|
||||
func get_queue_free_count():
|
||||
return _to_queue_free.size()
|
||||
|
||||
|
||||
func get_free_count():
|
||||
return _to_free.size()
|
||||
|
||||
|
||||
func free_all():
|
||||
for i in range(_to_free.size()):
|
||||
if(is_instance_valid(_to_free[i])):
|
||||
_to_free[i].free()
|
||||
for node in _to_free:
|
||||
if(is_instance_valid(node)):
|
||||
if(GutUtils.is_double(node)):
|
||||
node.__gutdbl_done()
|
||||
node.free()
|
||||
_to_free.clear()
|
||||
|
||||
for i in range(_to_queue_free.size()):
|
||||
if(is_instance_valid(_to_queue_free[i])):
|
||||
_to_queue_free[i].queue_free()
|
||||
_to_queue_free.clear()
|
||||
|
||||
for ref_dbl in _ref_counted_doubles:
|
||||
ref_dbl.__gutdbl_done()
|
||||
_ref_counted_doubles.clear()
|
||||
|
||||
_all_instance_ids.clear()
|
||||
|
||||
|
||||
func has_instance_id(id):
|
||||
return _all_instance_ids.has(id)
|
||||
|
|
@ -1 +1 @@
|
|||
uid://bfrf3uq3hieco
|
||||
uid://bxjfriqxgwe0r
|
||||
|
|
|
|||
|
|
@ -1,60 +1,126 @@
|
|||
extends Node
|
||||
|
||||
class AwaitLogger:
|
||||
var _time_waited = 0.0
|
||||
var logger = GutUtils.get_logger()
|
||||
var waiting_on = "nothing"
|
||||
var logged_initial_message = false
|
||||
var wait_log_delay := 1.0
|
||||
var disabled = false
|
||||
|
||||
func waited(x):
|
||||
_time_waited += x
|
||||
if(!logged_initial_message and _time_waited >= wait_log_delay):
|
||||
log_it()
|
||||
logged_initial_message = true
|
||||
|
||||
|
||||
func reset():
|
||||
_time_waited = 0.0
|
||||
logged_initial_message = false
|
||||
|
||||
|
||||
func log_it():
|
||||
if(!disabled):
|
||||
var msg = str("--- Awaiting ", waiting_on, " ---")
|
||||
logger.wait_msg(msg)
|
||||
|
||||
|
||||
|
||||
|
||||
signal timeout
|
||||
signal wait_started
|
||||
|
||||
var await_logger = AwaitLogger.new()
|
||||
var _wait_time := 0.0
|
||||
var _wait_frames := 0
|
||||
var _wait_process_frames := 0
|
||||
var _wait_physics_frames := 0
|
||||
var _signal_to_wait_on = null
|
||||
|
||||
var _predicate_function_waiting_to_be_true = null
|
||||
var _predicate_method = null
|
||||
var _waiting_for_predicate_to_be = null
|
||||
|
||||
var _predicate_time_between := 0.0
|
||||
var _predicate_time_between_elpased := 0.0
|
||||
|
||||
var _elapsed_time := 0.0
|
||||
var _elapsed_frames := 0
|
||||
|
||||
var _did_last_wait_timeout = false
|
||||
var did_last_wait_timeout = false :
|
||||
get: return _did_last_wait_timeout
|
||||
set(val): push_error("Cannot set did_last_wait_timeout")
|
||||
|
||||
var _elapsed_time := 0.0
|
||||
var _elapsed_frames := 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
get_tree().process_frame.connect(_on_tree_process_frame)
|
||||
get_tree().physics_frame.connect(_on_tree_physics_frame)
|
||||
|
||||
|
||||
func _on_tree_process_frame():
|
||||
# Count frames here instead of in _process so that tree order never
|
||||
# makes a difference and the count/signaling happens outside of
|
||||
# _process being called.
|
||||
if(_wait_process_frames > 0):
|
||||
_elapsed_frames += 1
|
||||
if(_elapsed_frames > _wait_process_frames):
|
||||
_end_wait()
|
||||
|
||||
|
||||
func _on_tree_physics_frame():
|
||||
# Count frames here instead of in _physics_process so that tree order never
|
||||
# makes a difference and the count/signaling happens outside of
|
||||
# _physics_process being called.
|
||||
if(_wait_physics_frames != 0):
|
||||
_elapsed_frames += 1
|
||||
if(_elapsed_frames > _wait_physics_frames):
|
||||
_end_wait()
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if(is_waiting()):
|
||||
await_logger.waited(delta)
|
||||
|
||||
if(_wait_time != 0.0):
|
||||
_elapsed_time += delta
|
||||
if(_elapsed_time >= _wait_time):
|
||||
_end_wait()
|
||||
|
||||
if(_wait_frames != 0):
|
||||
_elapsed_frames += 1
|
||||
if(_elapsed_frames >= _wait_frames):
|
||||
_end_wait()
|
||||
|
||||
if(_predicate_function_waiting_to_be_true != null):
|
||||
if(_predicate_method != null):
|
||||
_predicate_time_between_elpased += delta
|
||||
if(_predicate_time_between_elpased >= _predicate_time_between):
|
||||
_predicate_time_between_elpased = 0.0
|
||||
var result = _predicate_function_waiting_to_be_true.call()
|
||||
if(typeof(result) == TYPE_BOOL and result):
|
||||
_end_wait()
|
||||
var result = _predicate_method.call()
|
||||
if(_waiting_for_predicate_to_be == false):
|
||||
if(typeof(result) != TYPE_BOOL or result != true):
|
||||
_end_wait()
|
||||
else:
|
||||
if(typeof(result) == TYPE_BOOL and result == _waiting_for_predicate_to_be):
|
||||
_end_wait()
|
||||
|
||||
|
||||
func _end_wait():
|
||||
await_logger.reset()
|
||||
# Check for time before checking for frames so that the extra frames added
|
||||
# when waiting on a signal do not cause a false negative for timing out.
|
||||
if(_wait_time > 0):
|
||||
_did_last_wait_timeout = _elapsed_time >= _wait_time
|
||||
elif(_wait_frames > 0):
|
||||
_did_last_wait_timeout = _elapsed_frames >= _wait_frames
|
||||
elif(_wait_physics_frames > 0):
|
||||
_did_last_wait_timeout = _elapsed_frames >= _wait_physics_frames
|
||||
elif(_wait_process_frames > 0):
|
||||
_did_last_wait_timeout = _elapsed_frames >= _wait_process_frames
|
||||
|
||||
if(_signal_to_wait_on != null and _signal_to_wait_on.is_connected(_signal_callback)):
|
||||
if(_signal_to_wait_on != null and \
|
||||
is_instance_valid(_signal_to_wait_on.get_object()) and \
|
||||
_signal_to_wait_on.is_connected(_signal_callback)):
|
||||
_signal_to_wait_on.disconnect(_signal_callback)
|
||||
|
||||
_wait_process_frames = 0
|
||||
_wait_time = 0.0
|
||||
_wait_frames = 0
|
||||
_wait_physics_frames = 0
|
||||
_signal_to_wait_on = null
|
||||
_predicate_function_waiting_to_be_true = null
|
||||
_predicate_method = null
|
||||
_elapsed_time = 0.0
|
||||
_elapsed_frames = 0
|
||||
timeout.emit()
|
||||
|
|
@ -68,23 +134,34 @@ func _signal_callback(
|
|||
|
||||
_signal_to_wait_on.disconnect(_signal_callback)
|
||||
# DO NOT _end_wait here. For other parts of the test to get the signal that
|
||||
# was waited on, we have to wait for a couple more frames. For example, the
|
||||
# was waited on, we have to wait for another frames. For example, the
|
||||
# signal_watcher doesn't get the signal in time if we don't do this.
|
||||
_wait_frames = 2
|
||||
_wait_process_frames = 1
|
||||
|
||||
func wait_seconds(x):
|
||||
|
||||
func wait_seconds(x, msg=''):
|
||||
await_logger.waiting_on = str(x, " seconds ", msg)
|
||||
_did_last_wait_timeout = false
|
||||
_wait_time = x
|
||||
wait_started.emit()
|
||||
|
||||
|
||||
func wait_frames(x):
|
||||
func wait_process_frames(x, msg=''):
|
||||
await_logger.waiting_on = str(x, " idle frames ", msg)
|
||||
_did_last_wait_timeout = false
|
||||
_wait_frames = x
|
||||
_wait_process_frames = x
|
||||
wait_started.emit()
|
||||
|
||||
|
||||
func wait_for_signal(the_signal, max_time):
|
||||
func wait_physics_frames(x, msg=''):
|
||||
await_logger.waiting_on = str(x, " physics frames ", msg)
|
||||
_did_last_wait_timeout = false
|
||||
_wait_physics_frames = x
|
||||
wait_started.emit()
|
||||
|
||||
|
||||
func wait_for_signal(the_signal : Signal, max_time, msg=''):
|
||||
await_logger.waiting_on = str("signal ", the_signal.get_name(), " or ", max_time, "s ", msg)
|
||||
_did_last_wait_timeout = false
|
||||
the_signal.connect(_signal_callback)
|
||||
_signal_to_wait_on = the_signal
|
||||
|
|
@ -92,14 +169,33 @@ func wait_for_signal(the_signal, max_time):
|
|||
wait_started.emit()
|
||||
|
||||
|
||||
func wait_until(predicate_function: Callable, max_time, time_between_calls:=0.0):
|
||||
func wait_until(predicate_function: Callable, max_time, time_between_calls:=0.0, msg=''):
|
||||
await_logger.waiting_on = str("callable to return TRUE or ", max_time, "s. ", msg)
|
||||
_predicate_time_between = time_between_calls
|
||||
_predicate_function_waiting_to_be_true = predicate_function
|
||||
_predicate_method = predicate_function
|
||||
_wait_time = max_time
|
||||
|
||||
_waiting_for_predicate_to_be = true
|
||||
_predicate_time_between_elpased = 0.0
|
||||
_did_last_wait_timeout = false
|
||||
|
||||
wait_started.emit()
|
||||
|
||||
|
||||
func wait_while(predicate_function: Callable, max_time, time_between_calls:=0.0, msg=''):
|
||||
await_logger.waiting_on = str("callable to return FALSE or ", max_time, "s. ", msg)
|
||||
_predicate_time_between = time_between_calls
|
||||
_predicate_method = predicate_function
|
||||
_wait_time = max_time
|
||||
|
||||
_waiting_for_predicate_to_be = false
|
||||
_predicate_time_between_elpased = 0.0
|
||||
_did_last_wait_timeout = false
|
||||
|
||||
wait_started.emit()
|
||||
|
||||
|
||||
func is_waiting():
|
||||
return _wait_time != 0.0 || _wait_frames != 0
|
||||
return _wait_time != 0.0 || \
|
||||
_wait_physics_frames != 0 || \
|
||||
_wait_process_frames != 0
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://psark8vrstly
|
||||
uid://ccu4ww35edtdi
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://cfqihvbcwhtkg
|
||||
uid://1pauyfnd1cre
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ Options whose values are lists/arrays can be specified multiple times:
|
|||
-gdir c,d
|
||||
-gdir e
|
||||
# results in -gdir equaling [a, b, c, d, e]
|
||||
|
||||
To not use an empty value instead of a default value, specifiy the option with
|
||||
an immediate "=":
|
||||
-gconfig=
|
||||
"""
|
||||
opts.add_heading("Test Config:")
|
||||
opts.add('-gdir', options.dirs, 'List of directories to search for test scripts in.')
|
||||
|
|
@ -125,6 +129,8 @@ Options whose values are lists/arrays can be specified multiple times:
|
|||
opts.add('-gexit', false, 'Exit after running tests. If not specified you have to manually close the window.')
|
||||
opts.add('-gexit_on_success', false, 'Only exit if zero tests fail.')
|
||||
opts.add('-gignore_pause', false, 'Ignores any calls to pause_before_teardown.')
|
||||
opts.add('-gno_error_tracking', false, 'Disable error tracking.')
|
||||
opts.add('-gfailure_error_types', options.failure_error_types, 'Error types that will cause tests to fail if the are encountered during the execution of a test. Default "[default]"')
|
||||
|
||||
opts.add_heading("Display Settings:")
|
||||
opts.add('-glog', options.log_level, 'Log level [0-3]. Default [default]')
|
||||
|
|
@ -138,6 +144,7 @@ Options whose values are lists/arrays can be specified multiple times:
|
|||
opts.add('-gbackground_color', options.background_color, 'Background color as an html color, default "[default]"')
|
||||
opts.add('-gfont_color',options.font_color, 'Font color as an html color, default "[default]"')
|
||||
opts.add('-gpaint_after', options.paint_after, 'Delay before GUT will add a 1 frame pause to paint the screen/GUI. default [default]')
|
||||
opts.add('-gwait_log_delay', options.wait_log_delay, 'Delay before GUT will print a message to indicate a test is awaiting one of the wait_* methods. Default [default]')
|
||||
|
||||
opts.add_heading("Result Export:")
|
||||
opts.add('-gjunit_xml_file', options.junit_xml_file, 'Export results of run to this file in the Junit XML format.')
|
||||
|
|
@ -148,16 +155,22 @@ Options whose values are lists/arrays can be specified multiple times:
|
|||
opts.add('-gpo', false, 'Print option values from all sources and the value used.')
|
||||
opts.add('-gprint_gutconfig_sample', false, 'Print out json that can be used to make a gutconfig file.')
|
||||
|
||||
# run as in editor, for shelling out purposes through Editor.
|
||||
var o = opts.add('-graie', false, 'do not use')
|
||||
o.show_in_help = false
|
||||
return opts
|
||||
|
||||
|
||||
# Parses options, applying them to the _tester or setting values
|
||||
# in the options struct.
|
||||
func extract_command_line_options(from, to):
|
||||
to.compact_mode = from.get_value_or_null('-gcompact_mode')
|
||||
to.config_file = from.get_value_or_null('-gconfig')
|
||||
to.dirs = from.get_value_or_null('-gdir')
|
||||
to.disable_colors = from.get_value_or_null('-gdisable_colors')
|
||||
to.double_strategy = from.get_value_or_null('-gdouble_strategy')
|
||||
to.errors_do_not_cause_failure = from.get_value_or_null('-gerrors_do_not_cause_failure')
|
||||
to.hide_orphans = from.get_value_or_null('-ghide_orphans')
|
||||
to.ignore_pause = from.get_value_or_null('-gignore_pause')
|
||||
to.include_subdirs = from.get_value_or_null('-ginclude_subdirs')
|
||||
to.inner_class = from.get_value_or_null('-ginner_class')
|
||||
|
|
@ -170,22 +183,24 @@ func extract_command_line_options(from, to):
|
|||
to.should_exit = from.get_value_or_null('-gexit')
|
||||
to.should_exit_on_success = from.get_value_or_null('-gexit_on_success')
|
||||
to.should_maximize = from.get_value_or_null('-gmaximize')
|
||||
to.compact_mode = from.get_value_or_null('-gcompact_mode')
|
||||
to.hide_orphans = from.get_value_or_null('-ghide_orphans')
|
||||
to.suffix = from.get_value_or_null('-gsuffix')
|
||||
to.errors_do_not_cause_failure = from.get_value_or_null('-gerrors_do_not_cause_failure')
|
||||
to.tests = from.get_value_or_null('-gtest')
|
||||
to.unit_test_name = from.get_value_or_null('-gunit_test_name')
|
||||
to.wait_log_delay = from.get_value_or_null('-gwait_log_delay')
|
||||
|
||||
to.font_size = from.get_value_or_null('-gfont_size')
|
||||
to.font_name = from.get_value_or_null('-gfont_name')
|
||||
to.background_color = from.get_value_or_null('-gbackground_color')
|
||||
to.font_color = from.get_value_or_null('-gfont_color')
|
||||
to.font_name = from.get_value_or_null('-gfont_name')
|
||||
to.font_size = from.get_value_or_null('-gfont_size')
|
||||
to.paint_after = from.get_value_or_null('-gpaint_after')
|
||||
|
||||
to.junit_xml_file = from.get_value_or_null('-gjunit_xml_file')
|
||||
to.junit_xml_timestamp = from.get_value_or_null('-gjunit_xml_timestamp')
|
||||
|
||||
to.failure_error_types = from.get_value_or_null('-gfailure_error_types')
|
||||
to.no_error_tracking = from.get_value_or_null('-gno_error_tracking')
|
||||
to.raie = from.get_value_or_null('-graie')
|
||||
|
||||
|
||||
|
||||
func _print_gutconfigs(values):
|
||||
|
|
@ -217,7 +232,10 @@ func _run_tests(opt_resolver):
|
|||
runner.set_gut_config(_gut_config)
|
||||
get_tree().root.add_child(runner)
|
||||
|
||||
runner.run_tests()
|
||||
if(opt_resolver.cmd_opts.raie):
|
||||
runner.run_from_editor()
|
||||
else:
|
||||
runner.run_tests()
|
||||
|
||||
|
||||
# parse options and run Gut
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://ddx1kavbbraby
|
||||
uid://bhuudqinp4bth
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
## created Option instance. See that class above for more info. You can use
|
||||
## the returned instance to get values, or use get_value/get_value_or_null.
|
||||
## add("--name", "default", "Description goes here")
|
||||
## add_required("--name", "default", "Description goes here")
|
||||
## add(["--name", "--aliases"], "default", "Description goes here")
|
||||
## add_required(["--name", "--aliases"], "default", "Description goes here")
|
||||
## add_positional("--name", "default", "Description goes here")
|
||||
## add_positional_required("--name", "default", "Description goes here")
|
||||
##
|
||||
|
|
@ -153,6 +154,8 @@ class Option:
|
|||
var default = null
|
||||
var description = ''
|
||||
var required = false
|
||||
var aliases: Array[String] = []
|
||||
var show_in_help = true
|
||||
|
||||
|
||||
func _init(name,default_value,desc=''):
|
||||
|
|
@ -162,12 +165,51 @@ class Option:
|
|||
_value = default
|
||||
|
||||
|
||||
func to_s(min_space=0):
|
||||
func wrap_text(text, left_indent, max_length, wiggle_room=15):
|
||||
var line_indent = str("\n", " ".repeat(left_indent + 1))
|
||||
var wrapped = ''
|
||||
var position = 0
|
||||
var split_length = max_length
|
||||
while(position < text.length()):
|
||||
if(position > 0):
|
||||
wrapped += line_indent
|
||||
|
||||
var split_by = split_length
|
||||
if(position + split_by + wiggle_room >= text.length()):
|
||||
split_by = text.length() - position
|
||||
else:
|
||||
var min_space = text.rfind(' ', position + split_length)
|
||||
var max_space = text.find(' ', position + split_length)
|
||||
if(max_space <= position + split_length + wiggle_room):
|
||||
split_by = max_space - position
|
||||
else:
|
||||
split_by = min_space - position
|
||||
|
||||
wrapped += text.substr(position, split_by).lstrip(' ')
|
||||
|
||||
if(position == 0):
|
||||
split_length = max_length - left_indent
|
||||
|
||||
position += split_by
|
||||
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
|
||||
func to_s(min_space=0, wrap_length=100):
|
||||
var line_indent = str("\n", " ".repeat(min_space + 1))
|
||||
var subbed_desc = description
|
||||
if not aliases.is_empty():
|
||||
subbed_desc += "\naliases: " + ", ".join(aliases)
|
||||
subbed_desc = subbed_desc.replace('[default]', str(default))
|
||||
subbed_desc = subbed_desc.replace("\n", line_indent)
|
||||
return str(option_name.rpad(min_space), ' ', subbed_desc)
|
||||
|
||||
var final = str(option_name.rpad(min_space), ' ', subbed_desc)
|
||||
if(wrap_length != -1):
|
||||
final = wrap_text(final, min_space, wrap_length)
|
||||
|
||||
return final
|
||||
|
||||
|
||||
func has_been_set():
|
||||
|
|
@ -196,7 +238,7 @@ class Options:
|
|||
var default_heading = OptionHeading.new()
|
||||
var script_option = Option.new('-s', '?', 'script option provided by Godot')
|
||||
|
||||
var _options_by_name = {}
|
||||
var _options_by_name = {"--script": script_option, "-s": script_option}
|
||||
var _options_by_heading = [default_heading]
|
||||
var _cur_heading = default_heading
|
||||
|
||||
|
|
@ -208,11 +250,16 @@ class Options:
|
|||
_options_by_heading.append(heading)
|
||||
|
||||
|
||||
func add(option):
|
||||
func add(option, aliases=null):
|
||||
options.append(option)
|
||||
_options_by_name[option.option_name] = option
|
||||
_cur_heading.options.append(option)
|
||||
|
||||
if aliases != null:
|
||||
for a in aliases:
|
||||
_options_by_name[a] = option
|
||||
option.aliases.assign(aliases)
|
||||
|
||||
|
||||
func add_positional(option):
|
||||
positional.append(option)
|
||||
|
|
@ -221,9 +268,7 @@ class Options:
|
|||
|
||||
func get_by_name(option_name):
|
||||
var found_param = null
|
||||
if(option_name == script_option.option_name):
|
||||
found_param = script_option
|
||||
elif(_options_by_name.has(option_name)):
|
||||
if(_options_by_name.has(option_name)):
|
||||
found_param = _options_by_name[option_name]
|
||||
|
||||
return found_param
|
||||
|
|
@ -240,8 +285,8 @@ class Options:
|
|||
if(heading != default_heading):
|
||||
text += str("\n", heading.display, "\n")
|
||||
for option in heading.options:
|
||||
text += str(' ', option.to_s(longest + 2).replace("\n", "\n "), "\n")
|
||||
|
||||
if(option.show_in_help):
|
||||
text += str(' ', option.to_s(longest + 2).replace("\n", "\n "), "\n")
|
||||
|
||||
return text
|
||||
|
||||
|
|
@ -296,19 +341,28 @@ class Options:
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# optarse
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
var options = Options.new()
|
||||
var banner = ''
|
||||
var option_name_prefix = '-'
|
||||
## @ignore
|
||||
var options := Options.new()
|
||||
## Set the banner property to any text you want to appear before the usage and
|
||||
## options sections when printing the options help.
|
||||
var banner := ''
|
||||
## optparse uses option_name_prefix to differentiate between option names and
|
||||
## values. Any argument that starts with this value will be treated as an
|
||||
## argument name. The default is "-". Set this before calling parse if you want
|
||||
## to change it.
|
||||
var option_name_prefix := '-'
|
||||
## @ignore
|
||||
var unused = []
|
||||
## @ignore
|
||||
var parsed_args = []
|
||||
var values = {}
|
||||
## @ignore
|
||||
var values: Dictionary = {}
|
||||
|
||||
|
||||
func _populate_values_dictionary():
|
||||
for entry in options.options:
|
||||
|
|
@ -320,7 +374,6 @@ func _populate_values_dictionary():
|
|||
values[value_key] = entry.value
|
||||
|
||||
|
||||
|
||||
func _convert_value_to_array(raw_value):
|
||||
var split = raw_value.split(',')
|
||||
# This is what an empty set looks like from the command line. If we do
|
||||
|
|
@ -330,7 +383,6 @@ func _convert_value_to_array(raw_value):
|
|||
split = []
|
||||
return split
|
||||
|
||||
|
||||
# REMEMBER raw_value not used for bools.
|
||||
func _set_option_value(option, raw_value):
|
||||
var t = typeof(option.default)
|
||||
|
|
@ -403,30 +455,87 @@ func _parse_command_line_arguments(args):
|
|||
return parsed_opts
|
||||
|
||||
|
||||
func is_option(arg):
|
||||
## Test if something is an existing argument. If [code]str(arg)[/code] begins
|
||||
## with the [member option_name_prefix], it will considered true,
|
||||
## otherwise it will be considered false.
|
||||
func is_option(arg) -> bool:
|
||||
return str(arg).begins_with(option_name_prefix)
|
||||
|
||||
|
||||
func add(op_name, default, desc):
|
||||
var new_op = null
|
||||
## Adds a command line option.
|
||||
## If [param op_names] is a String, this is set as the argument's name.
|
||||
## If [param op_names] is an Array of Strings, all elements of the array
|
||||
## will be aliases for the same argument and will be treated as such during
|
||||
## parsing.
|
||||
## [param default] is the default value the option will be set to if it is not
|
||||
## explicitly set during parsing.
|
||||
## [param desc] is a human readable text description of the option.
|
||||
## If the option is successfully added, the Option object will be returned.
|
||||
## If the option is not successfully added (e.g. a name collision with another
|
||||
## option occurs), an error message will be printed and [code]null[/code]
|
||||
## will be returned.
|
||||
func add(op_names, default, desc: String) -> Option:
|
||||
var op_name: String
|
||||
var aliases: Array[String] = []
|
||||
var new_op: Option = null
|
||||
|
||||
if(typeof(op_names) == TYPE_STRING):
|
||||
op_name = op_names
|
||||
else:
|
||||
op_name = op_names[0]
|
||||
aliases.assign(op_names.slice(1))
|
||||
|
||||
var bad_alias: int = aliases.map(
|
||||
func (a: String) -> bool: return options.get_by_name(a) != null
|
||||
).find(true)
|
||||
|
||||
if(options.get_by_name(op_name) != null):
|
||||
push_error(str('Option [', op_name, '] already exists.'))
|
||||
elif bad_alias != -1:
|
||||
push_error(str('Option [', aliases[bad_alias], '] already exists.'))
|
||||
else:
|
||||
new_op = Option.new(op_name, default, desc)
|
||||
options.add(new_op)
|
||||
options.add(new_op, aliases)
|
||||
|
||||
return new_op
|
||||
|
||||
|
||||
func add_required(op_name, default, desc):
|
||||
var op = add(op_name, default, desc)
|
||||
## Adds a required command line option.
|
||||
## Required options that have not been set may be collected after parsing
|
||||
## by calling [method get_missing_required_options].
|
||||
## If [param op_names] is a String, this is set as the argument's name.
|
||||
## If [param op_names] is an Array of Strings, all elements of the array
|
||||
## will be aliases for the same argument and will be treated as such during
|
||||
## parsing.
|
||||
## [param default] is the default value the option will be set to if it is not
|
||||
## explicitly set during parsing.
|
||||
## [param desc] is a human readable text description of the option.
|
||||
## If the option is successfully added, the Option object will be returned.
|
||||
## If the option is not successfully added (e.g. a name collision with another
|
||||
## option occurs), an error message will be printed and [code]null[/code]
|
||||
## will be returned.
|
||||
func add_required(op_names, default, desc: String) -> Option:
|
||||
var op := add(op_names, default, desc)
|
||||
if(op != null):
|
||||
op.required = true
|
||||
return op
|
||||
|
||||
|
||||
func add_positional(op_name, default, desc):
|
||||
## Adds a positional command line option.
|
||||
## Positional options are parsed by their position in the list of arguments
|
||||
## are are not assigned by name by the user.
|
||||
## If [param op_name] is a String, this is set as the argument's name.
|
||||
## If [param op_name] is an Array of Strings, all elements of the array
|
||||
## will be aliases for the same argument and will be treated as such during
|
||||
## parsing.
|
||||
## [param default] is the default value the option will be set to if it is not
|
||||
## explicitly set during parsing.
|
||||
## [param desc] is a human readable text description of the option.
|
||||
## If the option is successfully added, the Option object will be returned.
|
||||
## If the option is not successfully added (e.g. a name collision with another
|
||||
## option occurs), an error message will be printed and [code]null[/code]
|
||||
## will be returned.
|
||||
func add_positional(op_name, default, desc: String) -> Option:
|
||||
var new_op = null
|
||||
if(options.get_by_name(op_name) != null):
|
||||
push_error(str('Positional option [', op_name, '] already exists.'))
|
||||
|
|
@ -436,35 +545,64 @@ func add_positional(op_name, default, desc):
|
|||
return new_op
|
||||
|
||||
|
||||
func add_positional_required(op_name, default, desc):
|
||||
## Adds a required positional command line option.
|
||||
## If [param op_name] is a String, this is set as the argument's name.
|
||||
## Required options that have not been set may be collected after parsing
|
||||
## by calling [method get_missing_required_options].
|
||||
## Positional options are parsed by their position in the list of arguments
|
||||
## are are not assigned by name by the user.
|
||||
## If [param op_name] is an Array of Strings, all elements of the array
|
||||
## will be aliases for the same argument and will be treated as such during
|
||||
## parsing.
|
||||
## [param default] is the default value the option will be set to if it is not
|
||||
## explicitly set during parsing.
|
||||
## [param desc] is a human readable text description of the option.
|
||||
## If the option is successfully added, the Option object will be returned.
|
||||
## If the option is not successfully added (e.g. a name collision with another
|
||||
## option occurs), an error message will be printed and [code]null[/code]
|
||||
## will be returned.
|
||||
func add_positional_required(op_name, default, desc: String) -> Option:
|
||||
var op = add_positional(op_name, default, desc)
|
||||
if(op != null):
|
||||
op.required = true
|
||||
return op
|
||||
|
||||
|
||||
func add_heading(display_text):
|
||||
## Headings are used to separate logical groups of command line options
|
||||
## when printing out options from the help menu.
|
||||
## Headings are printed out between option descriptions in the order
|
||||
## that [method add_heading] was called.
|
||||
func add_heading(display_text: String) -> void:
|
||||
options.add_heading(display_text)
|
||||
|
||||
|
||||
func get_value(name):
|
||||
var found_param = options.get_by_name(name)
|
||||
## Gets the value assigned to an option after parsing.
|
||||
## [param name] can be the name of the option or an alias of it.
|
||||
## [param name] specifies the option whose value you wish to query.
|
||||
## If the option exists, the value assigned to it during parsing is returned.
|
||||
## Otherwise, an error message is printed and [code]null[/code] is returned.
|
||||
func get_value(name: String):
|
||||
var found_param: Option = options.get_by_name(name)
|
||||
|
||||
if(found_param != null):
|
||||
return found_param.value
|
||||
else:
|
||||
print("COULD NOT FIND OPTION " + name)
|
||||
push_error("COULD NOT FIND OPTION " + name)
|
||||
return null
|
||||
|
||||
|
||||
# This will return null instead of the default value if an option has not been
|
||||
# specified. This can be useful when providing an order of precedence to your
|
||||
# values. For example if
|
||||
# default value < config file < command line
|
||||
# then you do not want to get the default value for a command line option or it
|
||||
# will overwrite the value in a config file.
|
||||
func get_value_or_null(name):
|
||||
var found_param = options.get_by_name(name)
|
||||
## Gets the value assigned to an option after parsing,
|
||||
## returning null if the option was not assigned instead of its default value.
|
||||
## [param name] specifies the option whose value you wish to query.
|
||||
## This can be useful when providing an order of precedence to your values.
|
||||
## For example if
|
||||
## [codeblock]
|
||||
## default value < config file < command line
|
||||
## [/codeblock]
|
||||
## then you do not want to get the default value for a command line option or
|
||||
## it will overwrite the value in a config file.
|
||||
func get_value_or_null(name: String):
|
||||
var found_param: Option = options.get_by_name(name)
|
||||
|
||||
if(found_param != null and found_param.has_been_set()):
|
||||
return found_param.value
|
||||
|
|
@ -472,10 +610,11 @@ func get_value_or_null(name):
|
|||
return null
|
||||
|
||||
|
||||
func get_help():
|
||||
var sep = '---------------------------------------------------------'
|
||||
## Returns the help text for all defined options.
|
||||
func get_help() -> String:
|
||||
var sep := '---------------------------------------------------------'
|
||||
|
||||
var text = str(sep, "\n", banner, "\n\n")
|
||||
var text := str(sep, "\n", banner, "\n\n")
|
||||
text += "Usage\n-----------\n"
|
||||
text += " " + options.get_usage_text() + "\n\n"
|
||||
text += "\nOptions\n-----------\n"
|
||||
|
|
@ -484,11 +623,18 @@ func get_help():
|
|||
return text
|
||||
|
||||
|
||||
func print_help():
|
||||
## Prints out the help text for all defined options.
|
||||
func print_help() -> void:
|
||||
print(get_help())
|
||||
|
||||
|
||||
func parse(cli_args=null):
|
||||
## Parses a string for all options that have been set in this optparse.
|
||||
## if [param cli_args] is passed as a String, then it is parsed.
|
||||
## Otherwise if [param cli_args] is null,
|
||||
## aruments passed to the Godot engine at startup are parsed.
|
||||
## See the explanation at the top of addons/gut/cli/optparse.gd to understand
|
||||
## which arguments this will have access to.
|
||||
func parse(cli_args=null) -> void:
|
||||
parsed_args = cli_args
|
||||
|
||||
if(parsed_args == null):
|
||||
|
|
@ -499,7 +645,9 @@ func parse(cli_args=null):
|
|||
_populate_values_dictionary()
|
||||
|
||||
|
||||
func get_missing_required_options():
|
||||
## Get all options that were required and were not set during parsing.
|
||||
## The return value is an Array of Options.
|
||||
func get_missing_required_options() -> Array:
|
||||
return options.get_missing_required_options()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://bt37la38fetnn
|
||||
uid://c8m4fojwln6bq
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ func _init(logger=null):
|
|||
|
||||
|
||||
func get_new():
|
||||
return load_script().new()
|
||||
var inst = load_script().new()
|
||||
inst.collected_script = self
|
||||
return inst
|
||||
|
||||
|
||||
func load_script():
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://ckts04qa5iehe
|
||||
uid://bjjcnr1oqvag6
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ var orphans = 0
|
|||
|
||||
var was_run = false
|
||||
|
||||
var collected_script : WeakRef = null
|
||||
|
||||
|
||||
func did_pass():
|
||||
return is_passing()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://cdsm0ov7xq73d
|
||||
uid://cl854f1m26a2a
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://73ft8c27puxf
|
||||
uid://bohry7fhscy7y
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://d81wg1ecbtxu
|
||||
uid://cow1xqmqqvn4e
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://0m6qaxiiiwwq
|
||||
uid://ch2km05phxacd
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ enum {
|
|||
|
||||
var _strutils = GutUtils.Strutils.new()
|
||||
var _compare = GutUtils.Comparator.new()
|
||||
var DiffTool = load('res://addons/gut/diff_tool.gd')
|
||||
|
||||
var _value_1 = null
|
||||
var _value_2 = null
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://epp6hsk6gg3t
|
||||
uid://beoxokvl1hjs8
|
||||
|
|
|
|||
22
addons/gut/double_templates/double_data_template.txt
Normal file
22
addons/gut/double_templates/double_data_template.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
var __gutdbl_values = {
|
||||
thepath = '{path}',
|
||||
subpath = '{subpath}',
|
||||
stubber = {stubber_id},
|
||||
spy = {spy_id},
|
||||
gut = {gut_id},
|
||||
singleton_name = '{singleton_name}',
|
||||
singleton = {singleton_id},
|
||||
is_partial = {is_partial},
|
||||
doubled_methods = {doubled_methods},
|
||||
}
|
||||
var __gutdbl = load('res://addons/gut/double_tools.gd').new(self)
|
||||
|
||||
# Here so other things can check for a method to know if this is a double.
|
||||
func __gutdbl_check_method__():
|
||||
pass
|
||||
|
||||
# Cleanup called by GUT after tests have finished. Important for RefCounted
|
||||
# objects. Nodes are freed, and won't have this method called on them.
|
||||
func __gutdbl_done():
|
||||
__gutdbl = null
|
||||
__gutdbl_values.clear()
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
{func_decleration}
|
||||
{vararg_warning}__gutdbl.spy_on('{method_name}', {param_array})
|
||||
if(__gutdbl == null):
|
||||
return
|
||||
|
||||
__gutdbl.spy_on('{method_name}', {param_array})
|
||||
if(__gutdbl.is_stubbed_to_call_super('{method_name}', {param_array})):
|
||||
return {super_call}
|
||||
{super_call}
|
||||
else:
|
||||
return await __gutdbl.handle_other_stubs('{method_name}', {param_array})
|
||||
|
|
|
|||
|
|
@ -3,29 +3,10 @@
|
|||
# ##############################################################################
|
||||
{extends}
|
||||
|
||||
{constants}
|
||||
|
||||
{properties}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# GUT stuff
|
||||
# ------------------------------------------------------------------------------
|
||||
var __gutdbl_values = {
|
||||
double = self,
|
||||
thepath = '{path}',
|
||||
subpath = '{subpath}',
|
||||
stubber = {stubber_id},
|
||||
spy = {spy_id},
|
||||
gut = {gut_id},
|
||||
from_singleton = '{singleton_name}',
|
||||
is_partial = {is_partial},
|
||||
doubled_methods = {doubled_methods},
|
||||
}
|
||||
var __gutdbl = load('res://addons/gut/double_tools.gd').new(__gutdbl_values)
|
||||
|
||||
# Here so other things can check for a method to know if this is a double.
|
||||
func __gutdbl_check_method__():
|
||||
pass
|
||||
{double_data}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Doubled Methods
|
||||
|
|
|
|||
16
addons/gut/double_templates/singleton_template.txt
Normal file
16
addons/gut/double_templates/singleton_template.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{extends}
|
||||
|
||||
{constants}
|
||||
|
||||
{signals}
|
||||
|
||||
{properties}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# GUT stuff
|
||||
# ------------------------------------------------------------------------------
|
||||
{double_data}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Doubled Methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
@ -1,77 +1,83 @@
|
|||
var thepath = ''
|
||||
var subpath = ''
|
||||
var stubber = null
|
||||
var spy = null
|
||||
var gut = null
|
||||
var from_singleton = null
|
||||
var singleton_name = null
|
||||
var is_partial = null
|
||||
var double = null
|
||||
|
||||
var double_ref : WeakRef = null
|
||||
var stubber_ref : WeakRef = null
|
||||
var spy_ref : WeakRef = null
|
||||
var gut_ref : WeakRef = null
|
||||
var singleton_ref : WeakRef = null
|
||||
var __gutdbl_values = {}
|
||||
|
||||
const NO_DEFAULT_VALUE = '!__gut__no__default__value__!'
|
||||
func _init(values=null):
|
||||
if(values != null):
|
||||
double = values.double
|
||||
func _init(double = null):
|
||||
if(double != null):
|
||||
var values = double.__gutdbl_values
|
||||
__gutdbl_values = double.__gutdbl_values
|
||||
double_ref = weakref(double)
|
||||
thepath = values.thepath
|
||||
subpath = values.subpath
|
||||
stubber = from_id(values.stubber)
|
||||
spy = from_id(values.spy)
|
||||
gut = from_id(values.gut)
|
||||
from_singleton = values.from_singleton
|
||||
stubber_ref = weakref_from_id(values.stubber)
|
||||
spy_ref = weakref_from_id(values.spy)
|
||||
gut_ref = weakref_from_id(values.gut)
|
||||
singleton_ref = weakref_from_id(values.singleton)
|
||||
singleton_name = values.singleton_name
|
||||
is_partial = values.is_partial
|
||||
|
||||
if(gut != null):
|
||||
gut.get_autofree().add_free(double)
|
||||
if(gut_ref.get_ref() != null):
|
||||
gut_ref.get_ref().get_autofree().add_free(double_ref.get_ref())
|
||||
|
||||
|
||||
func _get_stubbed_method_to_call(method_name, called_with):
|
||||
var method = stubber.get_call_this(double, method_name, called_with)
|
||||
var method = stubber_ref.get_ref().get_call_this(double_ref.get_ref(), method_name, called_with)
|
||||
if(method != null):
|
||||
method = method.bindv(called_with)
|
||||
return method
|
||||
return method
|
||||
|
||||
|
||||
func from_id(inst_id):
|
||||
func weakref_from_id(inst_id):
|
||||
if(inst_id == -1):
|
||||
return null
|
||||
return weakref(null)
|
||||
else:
|
||||
return instance_from_id(inst_id)
|
||||
return weakref(instance_from_id(inst_id))
|
||||
|
||||
|
||||
func is_stubbed_to_call_super(method_name, called_with):
|
||||
if(stubber != null):
|
||||
return stubber.should_call_super(double, method_name, called_with)
|
||||
if(stubber_ref.get_ref() != null):
|
||||
return stubber_ref.get_ref().should_call_super(double_ref.get_ref(), method_name, called_with)
|
||||
else:
|
||||
return false
|
||||
|
||||
|
||||
func handle_other_stubs(method_name, called_with):
|
||||
if(stubber == null):
|
||||
if(stubber_ref.get_ref() == null):
|
||||
return
|
||||
|
||||
var method = _get_stubbed_method_to_call(method_name, called_with)
|
||||
if(method != null):
|
||||
return await method.call()
|
||||
else:
|
||||
return stubber.get_return(double, method_name, called_with)
|
||||
return stubber_ref.get_ref().get_return(double_ref.get_ref(), method_name, called_with)
|
||||
|
||||
|
||||
func spy_on(method_name, called_with):
|
||||
if(spy != null):
|
||||
spy.add_call(double, method_name, called_with)
|
||||
if(spy_ref.get_ref() != null):
|
||||
spy_ref.get_ref().add_call(double_ref.get_ref(), method_name, called_with)
|
||||
|
||||
|
||||
func default_val(method_name, p_index, default_val=NO_DEFAULT_VALUE):
|
||||
if(stubber != null):
|
||||
return stubber.get_default_value(double, method_name, p_index)
|
||||
else:
|
||||
func default_val(method_name, p_index):
|
||||
if(stubber_ref.get_ref() == null):
|
||||
return null
|
||||
else:
|
||||
var result = stubber_ref.get_ref().get_default_value(double_ref.get_ref(), method_name, p_index)
|
||||
return result
|
||||
|
||||
|
||||
func vararg_warning():
|
||||
if(gut != null):
|
||||
gut.get_logger().warn(
|
||||
"This method contains a vararg argument and the paramter count was not stubbed. " + \
|
||||
"GUT adds extra parameters to this method which should fill most needs. " + \
|
||||
"It is recommended that you stub param_count for this object's class to ensure " + \
|
||||
"that there are not any parameter count mismatch errors.")
|
||||
func get_singleton():
|
||||
var to_return = singleton_ref.get_ref()
|
||||
if(to_return == null):
|
||||
push_error("Trying to get a singleton reference on a non-singleton double: ",
|
||||
__gutdbl_values.singleton_name, "/", __gutdbl_values.singleton)
|
||||
return to_return
|
||||
|
|
@ -1 +1 @@
|
|||
uid://bs61eaaw6d85b
|
||||
uid://tr4khoco1hef
|
||||
|
|
|
|||
|
|
@ -1,47 +1,13 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
# A stroke of genius if I do say so. This allows for doubling a scene without
|
||||
# having to write any files. By overloading the "instantiate" method we can
|
||||
# make whatever we want.
|
||||
# ------------------------------------------------------------------------------
|
||||
class PackedSceneDouble:
|
||||
extends PackedScene
|
||||
var _script = null
|
||||
var _scene = null
|
||||
|
||||
func set_script_obj(obj):
|
||||
_script = obj
|
||||
|
||||
@warning_ignore("native_method_override")
|
||||
func instantiate(edit_state=0):
|
||||
var inst = _scene.instantiate(edit_state)
|
||||
var export_props = []
|
||||
var script_export_flag = (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE)
|
||||
|
||||
if(_script != null):
|
||||
if(inst.get_script() != null):
|
||||
# Get all the exported props and values so we can set them again
|
||||
for prop in inst.get_property_list():
|
||||
var is_export = prop.usage & (script_export_flag) == script_export_flag
|
||||
if(is_export):
|
||||
export_props.append([prop.name, inst.get(prop.name)])
|
||||
|
||||
inst.set_script(_script)
|
||||
for exported_value in export_props:
|
||||
inst.set(exported_value[0], exported_value[1])
|
||||
|
||||
return inst
|
||||
|
||||
func load_scene(path):
|
||||
_scene = load(path)
|
||||
extends RefCounted
|
||||
|
||||
|
||||
static var _base_script_text = GutUtils.get_file_as_text('res://addons/gut/double_templates/script_template.txt')
|
||||
static var _singleton_script_text = GutUtils.get_file_as_text('res://addons/gut/double_templates/singleton_template.txt')
|
||||
static var _double_data_text = GutUtils.get_file_as_text('res://addons/gut/double_templates/double_data_template.txt')
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# START Doubler
|
||||
# ------------------------------------------------------------------------------
|
||||
var _base_script_text = GutUtils.get_file_as_text('res://addons/gut/double_templates/script_template.txt')
|
||||
var _script_collector = GutUtils.ScriptCollector.new()
|
||||
var _singleton_parser = GutUtils.SingletonParser.new()
|
||||
|
||||
# used by tests for debugging purposes.
|
||||
var print_source = false
|
||||
var inner_class_registry = GutUtils.InnerClassRegistry.new()
|
||||
|
|
@ -83,7 +49,6 @@ func set_strategy(strategy):
|
|||
else:
|
||||
_lgr.error(str('doubler.gd: invalid double strategy ', strategy))
|
||||
|
||||
|
||||
var _method_maker = GutUtils.MethodMaker.new()
|
||||
func get_method_maker():
|
||||
return _method_maker
|
||||
|
|
@ -92,6 +57,7 @@ var _ignored_methods = GutUtils.OneToMany.new()
|
|||
func get_ignored_methods():
|
||||
return _ignored_methods
|
||||
|
||||
|
||||
# ###############
|
||||
# Private
|
||||
# ###############
|
||||
|
|
@ -100,6 +66,11 @@ func _init(strategy=GutUtils.DOUBLE_STRATEGY.SCRIPT_ONLY):
|
|||
_strategy = strategy
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if(what == NOTIFICATION_PREDELETE):
|
||||
if(_stubber != null):
|
||||
_stubber.clear()
|
||||
|
||||
func _get_indented_line(indents, text):
|
||||
var to_return = ''
|
||||
for _i in range(indents):
|
||||
|
|
@ -111,8 +82,13 @@ func _stub_to_call_super(parsed, method_name):
|
|||
if(!parsed.get_method(method_name).is_eligible_for_doubling()):
|
||||
return
|
||||
|
||||
var params = GutUtils.StubParams.new(parsed.script_path, method_name, parsed.subpath)
|
||||
var params = null
|
||||
if(parsed.is_native):
|
||||
params = GutUtils.StubParams.new(parsed._native_class, method_name, parsed.subpath)
|
||||
else:
|
||||
params = GutUtils.StubParams.new(parsed.script_path, method_name, parsed.subpath)
|
||||
params.to_call_super()
|
||||
params.is_script_default = true
|
||||
_stubber.add_stub(params)
|
||||
|
||||
|
||||
|
|
@ -134,27 +110,63 @@ func _get_base_script_text(parsed, override_path, partial, included_methods):
|
|||
gut_id = _gut.get_instance_id()
|
||||
|
||||
var extends_text = parsed.get_extends_text()
|
||||
|
||||
var values = {
|
||||
# Top sections
|
||||
"extends":extends_text,
|
||||
"constants":'',#obj_info.get_constants_text(),
|
||||
"properties":'',#obj_info.get_properties_text(),
|
||||
|
||||
# metadata values
|
||||
var double_data_values = {
|
||||
"path":path,
|
||||
"subpath":GutUtils.nvl(parsed.subpath, ''),
|
||||
"stubber_id":stubber_id,
|
||||
"spy_id":spy_id,
|
||||
"gut_id":gut_id,
|
||||
"singleton_name":'',#GutUtils.nvl(obj_info.get_singleton_name(), ''),
|
||||
"singleton_name":'',
|
||||
"singleton_id":-1,
|
||||
"is_partial":partial,
|
||||
"doubled_methods":included_methods,
|
||||
}
|
||||
|
||||
var values = {
|
||||
"extends":extends_text,
|
||||
"double_data":_double_data_text.format(double_data_values),
|
||||
}
|
||||
|
||||
return _base_script_text.format(values)
|
||||
|
||||
|
||||
func _get_singleton_text(parsed, included_methods, is_partial):
|
||||
var stubber_id = -1
|
||||
if(_stubber != null):
|
||||
stubber_id = _stubber.get_instance_id()
|
||||
|
||||
var spy_id = -1
|
||||
if(_spy != null):
|
||||
spy_id = _spy.get_instance_id()
|
||||
|
||||
var gut_id = -1
|
||||
if(_gut != null):
|
||||
gut_id = _gut.get_instance_id()
|
||||
|
||||
var double_data_values = {
|
||||
"path":'',
|
||||
"subpath":'',
|
||||
"stubber_id":stubber_id,
|
||||
"spy_id":spy_id,
|
||||
"gut_id":gut_id,
|
||||
"singleton_name":parsed.singleton_name,
|
||||
"singleton_id":parsed.singleton_id,
|
||||
"is_partial":is_partial,
|
||||
"doubled_methods":included_methods,
|
||||
}
|
||||
|
||||
var values = {
|
||||
"extends":"extends RefCounted",
|
||||
"double_data":_double_data_text.format(double_data_values),
|
||||
"signals":parsed.get_all_signal_text(),
|
||||
"constants":parsed.get_all_constants_text(),
|
||||
"properties":parsed.get_all_properties_text()
|
||||
}
|
||||
|
||||
var src = _singleton_script_text.format(values)
|
||||
return src
|
||||
|
||||
|
||||
func _is_method_eligible_for_doubling(parsed_script, parsed_method):
|
||||
return !parsed_method.is_accessor() and \
|
||||
parsed_method.is_eligible_for_doubling() and \
|
||||
|
|
@ -177,66 +189,89 @@ func _create_script_no_warnings(src):
|
|||
|
||||
|
||||
func _create_double(parsed, strategy, override_path, partial):
|
||||
var path = ""
|
||||
|
||||
path = parsed.script_path
|
||||
var dbl_src = ""
|
||||
var included_methods = []
|
||||
|
||||
for method in parsed.get_local_methods():
|
||||
if(_is_method_eligible_for_doubling(parsed, method)):
|
||||
included_methods.append(method.meta.name)
|
||||
var mthd = parsed.get_local_method(method.meta.name)
|
||||
if(parsed.is_native):
|
||||
dbl_src += _get_func_text(method.meta, parsed.resource)
|
||||
else:
|
||||
dbl_src += _get_func_text(method.meta, path)
|
||||
dbl_src += _get_func_text(method.meta)
|
||||
|
||||
if(strategy == GutUtils.DOUBLE_STRATEGY.INCLUDE_NATIVE):
|
||||
for method in parsed.get_super_methods():
|
||||
if(_is_method_eligible_for_doubling(parsed, method)):
|
||||
included_methods.append(method.meta.name)
|
||||
_stub_to_call_super(parsed, method.meta.name)
|
||||
if(parsed.is_native):
|
||||
dbl_src += _get_func_text(method.meta, parsed.resource)
|
||||
else:
|
||||
dbl_src += _get_func_text(method.meta, path)
|
||||
dbl_src += _get_func_text(method.meta)
|
||||
|
||||
var base_script = _get_base_script_text(parsed, override_path, partial, included_methods)
|
||||
dbl_src = base_script + "\n\n" + dbl_src
|
||||
|
||||
|
||||
if(print_source):
|
||||
print(GutUtils.add_line_numbers(dbl_src))
|
||||
var to_print :String = GutUtils.add_line_numbers(dbl_src)
|
||||
to_print = to_print.rstrip("\n")
|
||||
_lgr.log(str(to_print))
|
||||
|
||||
var DblClass = _create_script_no_warnings(dbl_src)
|
||||
if(_stubber != null):
|
||||
_stub_method_default_values(DblClass, parsed, strategy)
|
||||
_stub_method_default_values(parsed)
|
||||
|
||||
if(print_source):
|
||||
_lgr.log(str(" path | ", DblClass.resource_path, "\n"))
|
||||
|
||||
return DblClass
|
||||
|
||||
|
||||
func _stub_method_default_values(which, parsed, strategy):
|
||||
func _create_singleton_double(singleton, is_partial):
|
||||
var parsed = _singleton_parser.parse(singleton)
|
||||
var dbl_src = _get_singleton_text(parsed, parsed.methods_by_name.keys(), is_partial)
|
||||
|
||||
for key in parsed.methods_by_name:
|
||||
if(!_ignored_methods.has(singleton, key)):
|
||||
dbl_src += _method_maker.get_function_text(parsed.methods_by_name[key], singleton) + "\n"
|
||||
|
||||
if(print_source):
|
||||
var to_print :String = GutUtils.add_line_numbers(dbl_src)
|
||||
to_print = to_print.rstrip("\n")
|
||||
_lgr.log(str(to_print))
|
||||
|
||||
var DblClass = GutUtils.create_script_from_source(dbl_src)
|
||||
if(_stubber != null):
|
||||
for key in parsed.methods_by_name:
|
||||
var meta = parsed.methods_by_name[key]
|
||||
if(meta != {} and !meta.flags & METHOD_FLAG_VARARG):
|
||||
_stubber.stub_defaults_from_meta(singleton, meta)
|
||||
|
||||
return DblClass
|
||||
|
||||
|
||||
func _stub_method_default_values(parsed):
|
||||
for method in parsed.get_local_methods():
|
||||
if(method.is_eligible_for_doubling() and !_ignored_methods.has(parsed.resource, method.meta.name)):
|
||||
_stubber.stub_defaults_from_meta(parsed.script_path, method.meta)
|
||||
|
||||
|
||||
|
||||
func _double_scene_and_script(scene, strategy, partial):
|
||||
var to_return = PackedSceneDouble.new()
|
||||
to_return.load_scene(scene.get_path())
|
||||
|
||||
var dbl_bundle = scene._bundled.duplicate(true)
|
||||
var script_obj = GutUtils.get_scene_script_object(scene)
|
||||
# I'm not sure if the script object for the root node of a packed scene is
|
||||
# always the first entry in "variants" so this tries to find it.
|
||||
var script_index = dbl_bundle["variants"].find(script_obj)
|
||||
var script_dbl = null
|
||||
|
||||
if(script_obj != null):
|
||||
var script_dbl = null
|
||||
if(partial):
|
||||
script_dbl = _partial_double(script_obj, strategy, scene.get_path())
|
||||
else:
|
||||
script_dbl = _double(script_obj, strategy, scene.get_path())
|
||||
to_return.set_script_obj(script_dbl)
|
||||
|
||||
return to_return
|
||||
if(script_index != -1):
|
||||
dbl_bundle["variants"][script_index] = script_dbl
|
||||
|
||||
var doubled_scene = PackedScene.new()
|
||||
doubled_scene._set_bundled_scene(dbl_bundle)
|
||||
|
||||
return doubled_scene
|
||||
|
||||
|
||||
func _get_inst_id_ref_str(inst):
|
||||
|
|
@ -246,14 +281,8 @@ func _get_inst_id_ref_str(inst):
|
|||
return ref_str
|
||||
|
||||
|
||||
func _get_func_text(method_hash, path):
|
||||
var override_count = null;
|
||||
if(_stubber != null):
|
||||
override_count = _stubber.get_parameter_count(path, method_hash.name)
|
||||
|
||||
var text = _method_maker.get_function_text(method_hash, override_count) + "\n"
|
||||
|
||||
return text
|
||||
func _get_func_text(method_hash):
|
||||
return _method_maker.get_function_text(method_hash) + "\n"
|
||||
|
||||
|
||||
func _parse_script(obj):
|
||||
|
|
@ -291,6 +320,7 @@ func _partial_double(obj, strategy, override_path=null):
|
|||
func double(obj, strategy=_strategy):
|
||||
return _double(obj, strategy)
|
||||
|
||||
|
||||
func partial_double(obj, strategy=_strategy):
|
||||
return _partial_double(obj, strategy)
|
||||
|
||||
|
|
@ -299,6 +329,7 @@ func partial_double(obj, strategy=_strategy):
|
|||
func double_scene(scene, strategy=_strategy):
|
||||
return _double_scene_and_script(scene, strategy, false)
|
||||
|
||||
|
||||
func partial_double_scene(scene, strategy=_strategy):
|
||||
return _double_scene_and_script(scene, strategy, true)
|
||||
|
||||
|
|
@ -306,6 +337,7 @@ func partial_double_scene(scene, strategy=_strategy):
|
|||
func double_gdnative(which):
|
||||
return _double(which, GutUtils.DOUBLE_STRATEGY.INCLUDE_NATIVE)
|
||||
|
||||
|
||||
func partial_double_gdnative(which):
|
||||
return _partial_double(which, GutUtils.DOUBLE_STRATEGY.INCLUDE_NATIVE)
|
||||
|
||||
|
|
@ -320,11 +352,20 @@ func partial_double_inner(parent, inner, strategy=_strategy):
|
|||
return _create_double(parsed, strategy, null, true)
|
||||
|
||||
|
||||
func double_singleton(obj):
|
||||
return _create_singleton_double(obj, false)
|
||||
|
||||
|
||||
func partial_double_singleton(obj):
|
||||
return _create_singleton_double(obj, true)
|
||||
|
||||
|
||||
func add_ignored_method(obj, method_name):
|
||||
_ignored_methods.add(obj, method_name)
|
||||
|
||||
|
||||
|
||||
|
||||
# ##############################################################################
|
||||
#(G)odot (U)nit (T)est class
|
||||
#
|
||||
|
|
@ -352,4 +393,4 @@ func add_ignored_method(obj, method_name):
|
|||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
# ##############################################################################
|
||||
# ##############################################################################
|
||||
|
|
@ -1 +1 @@
|
|||
uid://dw6wqc1uj6j0r
|
||||
uid://cpy013l0wqwmg
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dc5bkpm84twcu
|
||||
uid://cnbjsrik0p5uf
|
||||
|
|
|
|||
212
addons/gut/editor_caret_context_notifier.gd
Normal file
212
addons/gut/editor_caret_context_notifier.gd
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
@tool
|
||||
extends Node
|
||||
# ##############################################################################
|
||||
#
|
||||
# Watches script editors and emits a signal whenever the method, inner class,
|
||||
# or script changes based on cursor position and other stuff.
|
||||
#
|
||||
# Basically, whenever this thing's signal is emitted, then the RunAtCursor
|
||||
# buttons should be updated to match the data passed to the signal.
|
||||
# ##############################################################################
|
||||
# In the editor, whenever a script is opened you get these new things that
|
||||
# hang off of EditorInterface.get_script_editor()
|
||||
# * ScriptEditorBase
|
||||
# * CodeEdit
|
||||
# ##############################################################################
|
||||
|
||||
|
||||
var _last_info : Dictionary = {}
|
||||
var _last_line = -1
|
||||
# This is the control that holds all the individual editors.
|
||||
var _current_script_editor : ScriptEditor = null
|
||||
# Reference to the GDScript for the last script we were notified about.
|
||||
var _current_script = null
|
||||
var _current_script_is_test_script = false
|
||||
var _current_editor_base : ScriptEditorBase = null
|
||||
var _current_editor : CodeEdit = null
|
||||
# Quick lookup of editors based on the current script.
|
||||
var _editors_for_scripts : Dictionary= {}
|
||||
|
||||
|
||||
# In order to keep the data that comes back from the emitted signal way more
|
||||
# usable, we have to know what GUT looks for for an inner-test-class prefix.
|
||||
# If we didn't do this, then this thing would have to return all the inner
|
||||
# classes and then we'd have to determine if we were in an inner-test-class
|
||||
# outside of here by traversing all the classes returned. It makes this thing
|
||||
# less generic and know too much, but this is probably already too generic as
|
||||
# it is.
|
||||
var inner_class_prefix = "Test"
|
||||
var method_prefix = "test_"
|
||||
var script_prefix = "test_"
|
||||
var script_suffix = ".gd"
|
||||
|
||||
|
||||
# Based on cursor and open editors, this will be emitted. You do what you
|
||||
# want with it.
|
||||
signal it_changed(change_data)
|
||||
|
||||
|
||||
func _ready():
|
||||
# This will not change, and should not change, over the course of a session.
|
||||
_current_script_editor = EditorInterface.get_script_editor()
|
||||
_current_script_editor.editor_script_changed.connect(_on_editor_script_changed)
|
||||
_current_script_editor.script_close.connect(_on_editor_script_close)
|
||||
|
||||
|
||||
func _handle_caret_location(which):
|
||||
var current_line = which.get_caret_line(0) + 1
|
||||
if(_last_line != current_line):
|
||||
_last_line = current_line
|
||||
|
||||
if(_current_script_is_test_script):
|
||||
var new_info = _make_info(which, _current_script, _current_script_is_test_script)
|
||||
if(_last_info != new_info):
|
||||
_last_info = new_info
|
||||
it_changed.emit(_last_info.duplicate())
|
||||
|
||||
|
||||
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 _make_info(editor, script, test_script_flag):
|
||||
if(editor == null):
|
||||
return
|
||||
|
||||
var info = {
|
||||
script = script,
|
||||
inner_class = null,
|
||||
method = null,
|
||||
is_test_script = test_script_flag
|
||||
}
|
||||
|
||||
var start_line = editor.get_caret_line()
|
||||
var line = start_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 ")):
|
||||
info.method = _get_func_name_from_line(text)
|
||||
done_func = true
|
||||
# If the func line is left justified then there won't be any
|
||||
# inner classes above it.
|
||||
if(editor.get_indent_level(line) == 0):
|
||||
done_inner = true
|
||||
|
||||
if(!done_inner and strip_text.begins_with("class")):
|
||||
var inner_name = _get_class_name_from_line(text)
|
||||
# See note about inner_class_prefix, this knows too much, but
|
||||
# if it was to know less it would insanely more difficult
|
||||
# everywhere.
|
||||
if(inner_name.begins_with(inner_class_prefix)):
|
||||
info.inner_class = inner_name
|
||||
done_inner = true
|
||||
done_func = true
|
||||
line -= 1
|
||||
|
||||
# print('parsed lines: ', start_line - line, '(', info.inner_class, ':', info.method, ')')
|
||||
return info
|
||||
# -------------
|
||||
# Events
|
||||
# -------------
|
||||
|
||||
# Fired whenever the script changes. This does not fire for help files. If
|
||||
# you click a help file and then back to the same file, then this will fire
|
||||
# for the same script
|
||||
#
|
||||
# This does fire for some non-script files such as .cfg, .json and .md files,
|
||||
# but the passed in value will be null.
|
||||
#
|
||||
# This can fire multiple times for the same script when a script is opened.
|
||||
func _on_editor_script_changed(script):
|
||||
if(script == null):
|
||||
return
|
||||
_last_line = -1
|
||||
_current_script = script
|
||||
_current_editor_base = _current_script_editor.get_current_editor()
|
||||
if(_current_editor_base.get_base_editor() is CodeEdit):
|
||||
_current_editor = _current_editor_base.get_base_editor()
|
||||
if(!_current_editor.caret_changed.is_connected(_on_caret_changed)):
|
||||
_current_editor.caret_changed.connect(_on_caret_changed.bind(_current_editor))
|
||||
else:
|
||||
_current_editor = null
|
||||
_editors_for_scripts[script] = _current_editor
|
||||
_current_script_is_test_script = is_test_script(_current_script)
|
||||
|
||||
_handle_caret_location(_current_editor)
|
||||
|
||||
|
||||
func _on_editor_script_close(script):
|
||||
var script_editor = _editors_for_scripts.get(script, null)
|
||||
if(script_editor != null):
|
||||
if(script_editor.caret_changed.is_connected(_on_caret_changed)):
|
||||
script_editor.caret_changed.disconnect(_on_caret_changed)
|
||||
_editors_for_scripts.erase(script)
|
||||
|
||||
|
||||
func _on_caret_changed(which):
|
||||
# Sometimes this is fired for editors that are not the current. I could
|
||||
# make this fire by saving a file in an external editor. I was unable to
|
||||
# get useful data out when it wasn't the current editor so I'm only doing
|
||||
# anything when it is the current editor.
|
||||
if(which == _current_editor):
|
||||
_handle_caret_location(which)
|
||||
|
||||
|
||||
func _could_be_test_script(script):
|
||||
return script.resource_path.get_file().begins_with(script_prefix) and \
|
||||
script.resource_path.get_file().ends_with(script_suffix)
|
||||
|
||||
# -------------
|
||||
# Public
|
||||
# -------------
|
||||
var _scripts_that_have_been_warned_about = []
|
||||
var _we_have_warned_enough = false
|
||||
var _max_warnings = 5
|
||||
func is_test_script(script):
|
||||
var base = script.get_base_script()
|
||||
if(base == null and script.get_script_method_list().size() == 0 and _could_be_test_script(script)):
|
||||
if(OS.is_stdout_verbose() or (!_scripts_that_have_been_warned_about.has(script.resource_path) and !_we_have_warned_enough)):
|
||||
_scripts_that_have_been_warned_about.append(script.resource_path)
|
||||
push_warning(str('[GUT] Treating ', script.resource_path, " as test script: ",
|
||||
"GUT was not able to retrieve information about this script. If this is ",
|
||||
"a new script you can ignore this warning. Otherwise, this may ",
|
||||
"have to do with having VSCode open. Restarting Godot sometimes helps. See ",
|
||||
"https://github.com/bitwes/Gut/issues/754"))
|
||||
if(!OS.is_stdout_verbose() and _scripts_that_have_been_warned_about.size() >= _max_warnings):
|
||||
print("[GUT] Disabling warning.")
|
||||
_we_have_warned_enough = true
|
||||
|
||||
# We can't know if this is a test script. It's more usable if we
|
||||
# assume this is a test script.
|
||||
return true
|
||||
else:
|
||||
while(base and base.resource_path != 'res://addons/gut/test.gd'):
|
||||
base = base.get_base_script()
|
||||
return base != null
|
||||
|
||||
|
||||
func get_info():
|
||||
return _last_info.duplicate()
|
||||
|
||||
|
||||
func log_values():
|
||||
print("---------------------------------------------------------------")
|
||||
print("script ", _current_script)
|
||||
print("script_editor ", _current_script_editor)
|
||||
print("editor_base ", _current_editor_base)
|
||||
print("editor ", _current_editor)
|
||||
1
addons/gut/editor_caret_context_notifier.gd.uid
Normal file
1
addons/gut/editor_caret_context_notifier.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c110s7a32x4su
|
||||
192
addons/gut/error_tracker.gd
Normal file
192
addons/gut/error_tracker.gd
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
extends Logger
|
||||
class_name GutErrorTracker
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Static methods wrap around add/remove logger to make disabling the logger
|
||||
# easier and to help avoid misusing add/remove in tests. If GUT needs to
|
||||
# add/remove a logger then this is how it should do it.
|
||||
# ------------------------------------------------------------------------------
|
||||
static var registered_loggers := {}
|
||||
static var register_loggers = true
|
||||
|
||||
static func register_logger(which):
|
||||
if(register_loggers and !registered_loggers.has(which)):
|
||||
OS.add_logger(which)
|
||||
registered_loggers[which] = get_stack()
|
||||
|
||||
|
||||
static func deregister_logger(which):
|
||||
if(registered_loggers.has(which)):
|
||||
OS.remove_logger(which)
|
||||
registered_loggers.erase(which)
|
||||
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# GutErrorTracker
|
||||
# ------------------------------------------------------------------------------
|
||||
var _current_test_id = GutUtils.NO_TEST
|
||||
var _mutex = Mutex.new()
|
||||
|
||||
var errors = GutUtils.OneToMany.new()
|
||||
|
||||
var treat_gut_errors_as : GutUtils.TREAT_AS = GutUtils.TREAT_AS.FAILURE
|
||||
var treat_engine_errors_as : GutUtils.TREAT_AS = GutUtils.TREAT_AS.FAILURE
|
||||
var treat_push_error_as : GutUtils.TREAT_AS = GutUtils.TREAT_AS.FAILURE
|
||||
var disabled = false
|
||||
|
||||
|
||||
# ----------------
|
||||
#region Private
|
||||
# ----------------
|
||||
|
||||
func _get_stack_data(current_test_name):
|
||||
var test_entry = {}
|
||||
var stackTrace = get_stack()
|
||||
|
||||
if(stackTrace!=null):
|
||||
var index = 0
|
||||
while(index < stackTrace.size() and test_entry == {}):
|
||||
var line = stackTrace[index]
|
||||
var function = line.get("function")
|
||||
if function == current_test_name:
|
||||
test_entry = stackTrace[index]
|
||||
else:
|
||||
index += 1
|
||||
|
||||
for i in range(index):
|
||||
stackTrace.remove_at(0)
|
||||
|
||||
return {
|
||||
"test_entry" = test_entry,
|
||||
"full_stack" = stackTrace
|
||||
}
|
||||
|
||||
|
||||
func _is_error_failable(error : GutTrackedError):
|
||||
var is_it = false
|
||||
if(error.handled == false):
|
||||
if(error.is_gut_error()):
|
||||
is_it = treat_gut_errors_as == GutUtils.TREAT_AS.FAILURE
|
||||
elif(error.is_push_error()):
|
||||
is_it = treat_push_error_as == GutUtils.TREAT_AS.FAILURE
|
||||
elif(error.is_engine_error()):
|
||||
is_it = treat_engine_errors_as == GutUtils.TREAT_AS.FAILURE
|
||||
return is_it
|
||||
|
||||
# ----------------
|
||||
#endregion
|
||||
#region Godot's Logger Overrides
|
||||
# ----------------
|
||||
|
||||
# Godot's Logger virtual method for errors
|
||||
func _log_error(function: String, file: String, line: int,
|
||||
code: String, rationale: String, editor_notify: bool,
|
||||
error_type: int, script_backtraces: Array[ScriptBacktrace]) -> void:
|
||||
add_error(function, file, line,
|
||||
code, rationale, editor_notify,
|
||||
error_type, script_backtraces)
|
||||
|
||||
# Godot's Logger virtual method for any output?
|
||||
# func _log_message(message: String, error: bool) -> void:
|
||||
# pass
|
||||
|
||||
# ----------------
|
||||
#endregion
|
||||
#region Public
|
||||
# ----------------
|
||||
|
||||
func start_test(test_id):
|
||||
_current_test_id = test_id
|
||||
|
||||
|
||||
func end_test():
|
||||
_current_test_id = GutUtils.NO_TEST
|
||||
|
||||
|
||||
func did_test_error(test_id=_current_test_id):
|
||||
return errors.size(test_id) > 0
|
||||
|
||||
|
||||
func get_current_test_errors():
|
||||
return errors.items.get(_current_test_id, [])
|
||||
|
||||
|
||||
# This should look through all the errors for a test and see if a failure
|
||||
# should happen based off of flags.
|
||||
func should_test_fail_from_errors(test_id = _current_test_id):
|
||||
var to_return = false
|
||||
if(errors.items.has(test_id)):
|
||||
var errs = errors.items[test_id]
|
||||
var index = 0
|
||||
while(index < errs.size() and !to_return):
|
||||
var error = errs[index]
|
||||
to_return = _is_error_failable(error)
|
||||
index += 1
|
||||
return to_return
|
||||
|
||||
|
||||
func get_errors_for_test(test_id=_current_test_id):
|
||||
var to_return = []
|
||||
if(errors.items.has(test_id)):
|
||||
to_return = errors.items[test_id].duplicate()
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
# Returns emtpy string or text for errors that occurred during the test that
|
||||
# should cause failure based on this class' flags.
|
||||
func get_fail_text_for_errors(test_id=_current_test_id) -> String:
|
||||
var error_texts = []
|
||||
|
||||
if(errors.items.has(test_id)):
|
||||
for error in errors.items[test_id]:
|
||||
if(_is_error_failable(error)):
|
||||
error_texts.append(str('<', error.get_error_type_name(), '>', error.code))
|
||||
|
||||
var to_return = ""
|
||||
for i in error_texts.size():
|
||||
if(to_return != ""):
|
||||
to_return += "\n"
|
||||
to_return += str("[", i + 1, "] ", error_texts[i])
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func add_gut_error(text) -> GutTrackedError:
|
||||
if(_current_test_id != GutUtils.NO_TEST):
|
||||
var data = _get_stack_data(_current_test_id)
|
||||
if(data.test_entry != {}):
|
||||
return add_error(_current_test_id, data.test_entry.source, data.test_entry.line,
|
||||
text, '', false,
|
||||
GutUtils.GUT_ERROR_TYPE, data.full_stack)
|
||||
|
||||
return add_error(_current_test_id, "unknown", -1,
|
||||
text, '', false,
|
||||
GutUtils.GUT_ERROR_TYPE, get_stack())
|
||||
|
||||
|
||||
func add_error(function: String, file: String, line: int,
|
||||
code: String, rationale: String, editor_notify: bool,
|
||||
error_type: int, script_backtraces: Array) -> GutTrackedError:
|
||||
if(disabled):
|
||||
return
|
||||
|
||||
_mutex.lock()
|
||||
|
||||
var err := GutTrackedError.new()
|
||||
err.backtrace = script_backtraces
|
||||
err.code = code
|
||||
err.rationale = rationale
|
||||
err.error_type = error_type
|
||||
err.editor_notify = editor_notify
|
||||
err.file = file
|
||||
err.function = function
|
||||
err.line = line
|
||||
|
||||
errors.add(_current_test_id, err)
|
||||
|
||||
_mutex.unlock()
|
||||
|
||||
return err
|
||||
1
addons/gut/error_tracker.gd.uid
Normal file
1
addons/gut/error_tracker.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://35kxgqotjmlu
|
||||
6
addons/gut/get_editor_interface.gd
Normal file
6
addons/gut/get_editor_interface.gd
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# This file is here so we can load it only when we are in the editor so that
|
||||
# other places do not have to have "EditorInterface" in them, which causes a
|
||||
# parser error when loaded outside of the editor. The things we have to do in
|
||||
# order to test things is annoying.
|
||||
func get_it():
|
||||
return EditorInterface
|
||||
1
addons/gut/get_editor_interface.gd.uid
Normal file
1
addons/gut/get_editor_interface.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://fgn2xo217kg1
|
||||
48
addons/gut/godot_singletons.gd
Normal file
48
addons/gut/godot_singletons.gd
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
# This file is auto-generated as part of the release process. GUT maintainers
|
||||
# should not change this file manually.
|
||||
static var class_ref = [
|
||||
AudioServer,
|
||||
CameraServer,
|
||||
ClassDB,
|
||||
DisplayServer,
|
||||
# excluded: EditorInterface,
|
||||
Engine,
|
||||
EngineDebugger,
|
||||
GDExtensionManager,
|
||||
Geometry2D,
|
||||
Geometry3D,
|
||||
IP,
|
||||
Input,
|
||||
InputMap,
|
||||
JavaClassWrapper,
|
||||
JavaScriptBridge,
|
||||
Marshalls,
|
||||
NativeMenu,
|
||||
NavigationMeshGenerator,
|
||||
NavigationServer2D,
|
||||
NavigationServer2DManager,
|
||||
NavigationServer3D,
|
||||
NavigationServer3DManager,
|
||||
OS,
|
||||
Performance,
|
||||
PhysicsServer2D,
|
||||
PhysicsServer2DManager,
|
||||
PhysicsServer3D,
|
||||
PhysicsServer3DManager,
|
||||
ProjectSettings,
|
||||
RenderingServer,
|
||||
ResourceLoader,
|
||||
ResourceSaver,
|
||||
ResourceUID,
|
||||
TextServerManager,
|
||||
ThemeDB,
|
||||
Time,
|
||||
TranslationServer,
|
||||
WorkerThreadPool,
|
||||
XRServer
|
||||
]
|
||||
static var names = []
|
||||
static func _static_init():
|
||||
for entry in class_ref:
|
||||
names.append(entry.get_class())
|
||||
1
addons/gut/godot_singletons.gd.uid
Normal file
1
addons/gut/godot_singletons.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cjkrqx36xfcbw
|
||||
|
|
@ -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))
|
||||
|
|
@ -1 +0,0 @@
|
|||
uid://dsmt384dwo7em
|
||||
|
|
@ -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"]
|
||||
13
addons/gut/gui/EditorRadioButton.tres
Normal file
13
addons/gut/gui/EditorRadioButton.tres
Normal 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")
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://b84o6yt8c0i3p
|
||||
uid://dtvnb0xatk0my
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dxbu5m7ovktb8
|
||||
uid://cqlvpwidawld6
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
36
addons/gut/gui/GutLogo.tscn
Normal file
36
addons/gut/gui/GutLogo.tscn
Normal 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"]
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://bayjc3x1exeie
|
||||
uid://eg8k46gd42a4
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://ccdonk2lpn1d1
|
||||
uid://cax5phqs8acmu
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
uid://dp618d4ofjpv1
|
||||
uid://duf6rfdqr6yoc
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dmfojusal8t8m
|
||||
uid://dehdhn78qv5tr
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://417tmtcbran2
|
||||
uid://c4gmgdl1xwflw
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
216
addons/gut/gui/RunExternally.gd
Normal file
216
addons/gut/gui/RunExternally.gd
Normal 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
|
||||
1
addons/gut/gui/RunExternally.gd.uid
Normal file
1
addons/gut/gui/RunExternally.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bi8pg352un4om
|
||||
65
addons/gut/gui/RunExternally.tscn
Normal file
65
addons/gut/gui/RunExternally.tscn
Normal 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"]
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://d1ntrij87eoco
|
||||
uid://chnko3073tkcv
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
321
addons/gut/gui/ShellOutOptions.gd
Normal file
321
addons/gut/gui/ShellOutOptions.gd
Normal 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 ''
|
||||
1
addons/gut/gui/ShellOutOptions.gd.uid
Normal file
1
addons/gut/gui/ShellOutOptions.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c64u22kybimgi
|
||||
34
addons/gut/gui/ShellOutOptions.tscn
Normal file
34
addons/gut/gui/ShellOutOptions.tscn
Normal 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"
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://byhinwdh4mxic
|
||||
uid://k6hvvpekp0xw
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
120
addons/gut/gui/ShortcutDialog.gd
Normal file
120
addons/gut/gui/ShortcutDialog.gd
Normal 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))
|
||||
1
addons/gut/gui/ShortcutDialog.gd.uid
Normal file
1
addons/gut/gui/ShortcutDialog.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dc5jgemxslgvl
|
||||
209
addons/gut/gui/ShortcutDialog.tscn
Normal file
209
addons/gut/gui/ShortcutDialog.tscn
Normal 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
125
addons/gut/gui/about.gd
Normal 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
|
||||
1
addons/gut/gui/about.gd.uid
Normal file
1
addons/gut/gui/about.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://g7qu8ihdt3pd
|
||||
56
addons/gut/gui/about.tscn
Normal file
56
addons/gut/gui/about.tscn
Normal 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"]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://b0cay8uv6i2kn
|
||||
uid://cbi00ubn046c2
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://xlv525p30gpr
|
||||
uid://chosc1tvfaduq
|
||||
|
|
|
|||
37
addons/gut/gui/gut_dock.gd
Normal file
37
addons/gut/gui/gut_dock.gd
Normal 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)
|
||||
1
addons/gut/gui/gut_dock.gd.uid
Normal file
1
addons/gut/gui/gut_dock.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cmj50k82tckur
|
||||
|
|
@ -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
|
||||
# ------------------
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://xsm23flin7t3
|
||||
uid://blvhsbnsvfyow
|
||||
|
|
|
|||
225
addons/gut/gui/gut_logo.gd
Normal file
225
addons/gut/gui/gut_logo.gd
Normal 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)
|
||||
1
addons/gut/gui/gut_logo.gd.uid
Normal file
1
addons/gut/gui/gut_logo.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b8lvgepb64m8t
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://3n0bh8lrcprr
|
||||
uid://dsndkn6whyiov
|
||||
|
|
|
|||
124
addons/gut/gui/option_maker.gd
Normal file
124
addons/gut/gui/option_maker.gd
Normal 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()
|
||||
1
addons/gut/gui/option_maker.gd.uid
Normal file
1
addons/gut/gui/option_maker.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bjahqsqo645sf
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue