2023-01-07 20:26:17 +01:00
|
|
|
@tool
|
2024-01-06 11:27:15 +01:00
|
|
|
extends VBoxContainer
|
2023-01-07 20:26:17 +01:00
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
# ##############################################################################
|
|
|
|
# Keeps search results from the TextEdit
|
|
|
|
# ##############################################################################
|
|
|
|
class TextEditSearcher:
|
|
|
|
var te: TextEdit
|
2023-01-20 23:34:39 +01:00
|
|
|
var _last_term = ""
|
2024-01-06 11:27:15 +01:00
|
|
|
var _last_pos = Vector2(-1, -1)
|
|
|
|
var _ignore_caret_change = false
|
|
|
|
|
|
|
|
func set_text_edit(which):
|
|
|
|
te = which
|
|
|
|
te.caret_changed.connect(_on_caret_changed)
|
|
|
|
|
|
|
|
func _on_caret_changed():
|
|
|
|
if _ignore_caret_change:
|
|
|
|
_ignore_caret_change = false
|
|
|
|
else:
|
|
|
|
_last_pos = _get_caret()
|
|
|
|
|
|
|
|
func _get_caret():
|
|
|
|
return Vector2(te.get_caret_column(), te.get_caret_line())
|
|
|
|
|
|
|
|
func _set_caret_and_sel(pos, len):
|
|
|
|
te.set_caret_line(pos.y)
|
|
|
|
te.set_caret_column(pos.x)
|
|
|
|
if len > 0:
|
|
|
|
te.select(pos.y, pos.x, pos.y, pos.x + len)
|
|
|
|
|
|
|
|
func _find(term, search_flags):
|
|
|
|
var pos = _get_caret()
|
|
|
|
if term == _last_term:
|
|
|
|
if search_flags == 0:
|
|
|
|
pos = _last_pos
|
|
|
|
pos.x += 1
|
2023-01-07 20:26:17 +01:00
|
|
|
else:
|
2024-01-06 11:27:15 +01:00
|
|
|
pos = _last_pos
|
|
|
|
pos.x -= 1
|
|
|
|
|
|
|
|
var result = te.search(term, search_flags, pos.y, pos.x)
|
|
|
|
# print('searching from ', pos, ' for "', term, '" = ', result)
|
|
|
|
if result.y != -1:
|
|
|
|
_ignore_caret_change = true
|
|
|
|
_set_caret_and_sel(result, term.length())
|
|
|
|
_last_pos = result
|
|
|
|
|
|
|
|
_last_term = term
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
func find_next(term):
|
2024-01-06 11:27:15 +01:00
|
|
|
_find(term, 0)
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
func find_prev(term):
|
2024-01-06 11:27:15 +01:00
|
|
|
_find(term, te.SEARCH_BACKWARDS)
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
# ##############################################################################
|
|
|
|
# Start OutputText control code
|
|
|
|
# ##############################################################################
|
2023-01-07 20:26:17 +01:00
|
|
|
@onready var _ctrls = {
|
|
|
|
output = $Output,
|
|
|
|
copy_button = $Toolbar/CopyButton,
|
|
|
|
use_colors = $Toolbar/UseColors,
|
|
|
|
clear_button = $Toolbar/ClearButton,
|
|
|
|
word_wrap = $Toolbar/WordWrap,
|
|
|
|
show_search = $Toolbar/ShowSearch,
|
2024-01-06 11:27:15 +01:00
|
|
|
caret_position = $Toolbar/LblPosition,
|
2023-01-20 23:34:39 +01:00
|
|
|
search_bar =
|
|
|
|
{
|
2023-01-07 20:26:17 +01:00
|
|
|
bar = $Search,
|
|
|
|
search_term = $Search/SearchTerm,
|
|
|
|
}
|
|
|
|
}
|
2024-01-06 11:27:15 +01:00
|
|
|
|
|
|
|
var _sr = TextEditSearcher.new()
|
|
|
|
var _highlighter: CodeHighlighter
|
|
|
|
var _font_name = null
|
2023-01-07 20:26:17 +01:00
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
# Automatically used when running the OutputText scene from the editor. Changes
|
|
|
|
# to this method only affect test-running the control through the editor.
|
2023-01-07 20:26:17 +01:00
|
|
|
func _test_running_setup():
|
2023-01-20 23:34:39 +01:00
|
|
|
_ctrls.use_colors.text = "use colors"
|
|
|
|
_ctrls.show_search.text = "search"
|
|
|
|
_ctrls.word_wrap.text = "ww"
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
set_all_fonts("CourierPrime")
|
2024-01-06 11:27:15 +01:00
|
|
|
set_font_size(30)
|
2023-01-07 20:26:17 +01:00
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
_ctrls.output.queue_redraw()
|
2023-01-20 23:34:39 +01:00
|
|
|
load_file("user://.gut_editor.bbcode")
|
2024-01-06 11:27:15 +01:00
|
|
|
await get_tree().process_frame
|
|
|
|
|
|
|
|
show_search(true)
|
|
|
|
_ctrls.output.set_caret_line(0)
|
|
|
|
_ctrls.output.scroll_vertical = 0
|
|
|
|
_ctrls.output.caret_changed.connect(_on_caret_changed)
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
func _ready():
|
2024-01-06 11:27:15 +01:00
|
|
|
_sr.set_text_edit(_ctrls.output)
|
2023-01-20 23:34:39 +01:00
|
|
|
_ctrls.use_colors.icon = get_theme_icon("RichTextEffect", "EditorIcons")
|
|
|
|
_ctrls.show_search.icon = get_theme_icon("Search", "EditorIcons")
|
|
|
|
_ctrls.word_wrap.icon = get_theme_icon("Loop", "EditorIcons")
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
_setup_colors()
|
2024-01-06 11:27:15 +01:00
|
|
|
_ctrls.use_colors.button_pressed = true
|
|
|
|
_use_highlighting(true)
|
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
if get_parent() == get_tree().root:
|
2023-01-07 20:26:17 +01:00
|
|
|
_test_running_setup()
|
|
|
|
|
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
func _on_caret_changed():
|
|
|
|
var txt = str(
|
|
|
|
"line:", _ctrls.output.get_caret_line(), " col:", _ctrls.output.get_caret_column()
|
|
|
|
)
|
|
|
|
_ctrls.caret_position.text = str(txt)
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
# ------------------
|
|
|
|
# Private
|
|
|
|
# ------------------
|
2024-01-06 11:27:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
# Call this after changes in colors and the like to get them to apply. reloads
|
|
|
|
# the text of the output control.
|
|
|
|
func _refresh_output():
|
|
|
|
var orig_pos = _ctrls.output.scroll_vertical
|
|
|
|
var text = _ctrls.output.text
|
|
|
|
|
|
|
|
_ctrls.output.text = text
|
|
|
|
_ctrls.output.scroll_vertical = orig_pos
|
|
|
|
|
|
|
|
|
|
|
|
func _create_highlighter(default_color = Color(1, 1, 1, 1)):
|
|
|
|
var to_return = CodeHighlighter.new()
|
|
|
|
|
|
|
|
to_return.function_color = default_color
|
|
|
|
to_return.number_color = default_color
|
|
|
|
to_return.symbol_color = default_color
|
|
|
|
to_return.member_variable_color = default_color
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
var keywords = [
|
2023-01-20 23:34:39 +01:00
|
|
|
["Failed", Color.RED],
|
|
|
|
["Passed", Color.GREEN],
|
|
|
|
["Pending", Color.YELLOW],
|
|
|
|
["Orphans", Color.YELLOW],
|
|
|
|
["WARNING", Color.YELLOW],
|
|
|
|
["ERROR", Color.RED]
|
2023-01-07 20:26:17 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
for keyword in keywords:
|
2024-01-06 11:27:15 +01:00
|
|
|
to_return.add_keyword_color(keyword[0], keyword[1])
|
|
|
|
|
|
|
|
return to_return
|
|
|
|
|
|
|
|
|
|
|
|
func _setup_colors():
|
|
|
|
_ctrls.output.clear()
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
var f_color = null
|
2023-01-20 23:34:39 +01:00
|
|
|
if _ctrls.output.theme == null:
|
2023-01-07 20:26:17 +01:00
|
|
|
f_color = get_theme_color("font_color")
|
2023-01-20 23:34:39 +01:00
|
|
|
else:
|
2023-01-07 20:26:17 +01:00
|
|
|
f_color = _ctrls.output.theme.font_color
|
2024-01-06 11:27:15 +01:00
|
|
|
|
|
|
|
_highlighter = _create_highlighter()
|
2023-01-07 20:26:17 +01:00
|
|
|
_ctrls.output.queue_redraw()
|
|
|
|
|
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
func _use_highlighting(should):
|
|
|
|
if should:
|
|
|
|
_ctrls.output.syntax_highlighter = _highlighter
|
2023-01-07 20:26:17 +01:00
|
|
|
else:
|
2024-01-06 11:27:15 +01:00
|
|
|
_ctrls.output.syntax_highlighter = null
|
|
|
|
_refresh_output()
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
# ------------------
|
|
|
|
# Events
|
|
|
|
# ------------------
|
|
|
|
func _on_CopyButton_pressed():
|
|
|
|
copy_to_clipboard()
|
|
|
|
|
|
|
|
|
|
|
|
func _on_UseColors_pressed():
|
2024-01-06 11:27:15 +01:00
|
|
|
_use_highlighting(_ctrls.use_colors.button_pressed)
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
func _on_ClearButton_pressed():
|
|
|
|
clear()
|
|
|
|
|
|
|
|
|
|
|
|
func _on_ShowSearch_pressed():
|
|
|
|
show_search(_ctrls.show_search.button_pressed)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_SearchTerm_focus_entered():
|
2023-01-20 23:34:39 +01:00
|
|
|
_ctrls.search_bar.search_term.call_deferred("select_all")
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
func _on_SearchNext_pressed():
|
|
|
|
_sr.find_next(_ctrls.search_bar.search_term.text)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_SearchPrev_pressed():
|
|
|
|
_sr.find_prev(_ctrls.search_bar.search_term.text)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_SearchTerm_text_changed(new_text):
|
2023-01-20 23:34:39 +01:00
|
|
|
if new_text == "":
|
2023-01-07 20:26:17 +01:00
|
|
|
_ctrls.output.deselect()
|
|
|
|
else:
|
|
|
|
_sr.find_next(new_text)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_SearchTerm_text_entered(new_text):
|
2023-01-20 23:34:39 +01:00
|
|
|
if Input.is_physical_key_pressed(KEY_SHIFT):
|
2023-01-07 20:26:17 +01:00
|
|
|
_sr.find_prev(new_text)
|
|
|
|
else:
|
|
|
|
_sr.find_next(new_text)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_SearchTerm_gui_input(event):
|
2024-01-06 11:27:15 +01:00
|
|
|
if event is InputEventKey and !event.pressed and event.keycode == KEY_ESCAPE:
|
2023-01-07 20:26:17 +01:00
|
|
|
show_search(false)
|
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func _on_WordWrap_pressed():
|
2024-01-06 11:27:15 +01:00
|
|
|
if _ctrls.word_wrap.button_pressed:
|
|
|
|
_ctrls.output.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY
|
|
|
|
else:
|
|
|
|
_ctrls.output.wrap_mode = TextEdit.LINE_WRAPPING_NONE
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
_ctrls.output.queue_redraw()
|
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
# ------------------
|
|
|
|
# Public
|
|
|
|
# ------------------
|
|
|
|
func show_search(should):
|
|
|
|
_ctrls.search_bar.bar.visible = should
|
2023-01-20 23:34:39 +01:00
|
|
|
if should:
|
2023-01-07 20:26:17 +01:00
|
|
|
_ctrls.search_bar.search_term.grab_focus()
|
|
|
|
_ctrls.search_bar.search_term.select_all()
|
|
|
|
_ctrls.show_search.button_pressed = should
|
|
|
|
|
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
func search(text, start_pos, highlight = true):
|
2023-01-07 20:26:17 +01:00
|
|
|
return _sr.find_next(text)
|
|
|
|
|
|
|
|
|
|
|
|
func copy_to_clipboard():
|
2024-01-06 11:27:15 +01:00
|
|
|
var selected = _ctrls.output.get_selected_text()
|
2023-01-20 23:34:39 +01:00
|
|
|
if selected != "":
|
2024-01-06 11:27:15 +01:00
|
|
|
DisplayServer.clipboard_set(selected)
|
2023-01-07 20:26:17 +01:00
|
|
|
else:
|
2024-01-06 11:27:15 +01:00
|
|
|
DisplayServer.clipboard_set(_ctrls.output.text)
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
func clear():
|
2023-01-20 23:34:39 +01:00
|
|
|
_ctrls.output.text = ""
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
func _set_font(font_name, custom_name):
|
|
|
|
var rtl = _ctrls.output
|
|
|
|
if font_name == null:
|
|
|
|
rtl.add_theme_font_override(custom_name, null)
|
|
|
|
else:
|
|
|
|
var dyn_font = FontFile.new()
|
|
|
|
dyn_font.load_dynamic_font("res://addons/gut/fonts/" + font_name + ".ttf")
|
|
|
|
rtl.add_theme_font_override(custom_name, dyn_font)
|
|
|
|
|
|
|
|
|
2023-01-07 20:26:17 +01:00
|
|
|
func set_all_fonts(base_name):
|
2024-01-06 11:27:15 +01:00
|
|
|
_font_name = GutUtils.nvl(base_name, "Default")
|
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
if base_name == "Default":
|
|
|
|
_set_font(null, "font")
|
2024-01-06 11:27:15 +01:00
|
|
|
_set_font(null, "normal_font")
|
|
|
|
_set_font(null, "bold_font")
|
|
|
|
_set_font(null, "italics_font")
|
|
|
|
_set_font(null, "bold_italics_font")
|
2023-01-07 20:26:17 +01:00
|
|
|
else:
|
2023-01-20 23:34:39 +01:00
|
|
|
_set_font(base_name + "-Regular", "font")
|
2024-01-06 11:27:15 +01:00
|
|
|
_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")
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
func set_font_size(new_size):
|
|
|
|
var rtl = _ctrls.output
|
2024-01-06 11:27:15 +01:00
|
|
|
rtl.set("theme_override_font_sizes/font_size", new_size)
|
|
|
|
|
2023-01-20 23:34:39 +01:00
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
# rtl.add_theme_font_size_override("font", new_size)
|
|
|
|
# rtl.add_theme_font_size_override("normal_font", new_size)
|
|
|
|
# rtl.add_theme_font_size_override("bold_font", new_size)
|
|
|
|
# rtl.add_theme_font_size_override("italics_font", new_size)
|
|
|
|
# rtl.add_theme_font_size_override("bold_italics_font", new_size)
|
2023-01-20 23:34:39 +01:00
|
|
|
|
2024-01-06 11:27:15 +01:00
|
|
|
# if(rtl.get('custom_fonts/font') != null):
|
|
|
|
# rtl.get('custom_fonts/font').size = new_size
|
2023-01-07 20:26:17 +01:00
|
|
|
# rtl.get('custom_fonts/bold_italics_font').size = new_size
|
|
|
|
# rtl.get('custom_fonts/bold_font').size = new_size
|
|
|
|
# rtl.get('custom_fonts/italics_font').size = new_size
|
|
|
|
# rtl.get('custom_fonts/normal_font').size = new_size
|
|
|
|
|
|
|
|
|
|
|
|
func set_use_colors(value):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
func get_use_colors():
|
2023-01-20 23:34:39 +01:00
|
|
|
return false
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
func get_rich_text_edit():
|
|
|
|
return _ctrls.output
|
|
|
|
|
|
|
|
|
|
|
|
func load_file(path):
|
|
|
|
var f = FileAccess.open(path, FileAccess.READ)
|
2023-01-20 23:34:39 +01:00
|
|
|
if f == null:
|
2023-01-07 20:26:17 +01:00
|
|
|
return
|
|
|
|
|
|
|
|
var t = f.get_as_text()
|
2024-01-06 11:27:15 +01:00
|
|
|
f = null # closes file
|
2023-01-07 20:26:17 +01:00
|
|
|
_ctrls.output.text = t
|
|
|
|
_ctrls.output.scroll_vertical = _ctrls.output.get_line_count()
|
2023-01-20 23:34:39 +01:00
|
|
|
_ctrls.output.set_deferred("scroll_vertical", _ctrls.output.get_line_count())
|
2023-01-07 20:26:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
func add_text(text):
|
2023-01-20 23:34:39 +01:00
|
|
|
if is_inside_tree():
|
2023-01-07 20:26:17 +01:00
|
|
|
_ctrls.output.text += text
|
|
|
|
|
|
|
|
|
|
|
|
func scroll_to_line(line):
|
|
|
|
_ctrls.output.scroll_vertical = line
|
|
|
|
_ctrls.output.set_caret_line(line)
|