Files
fnaf-gameshow-fangame/Assets/Scripts/UI/terminal/terminal_controls.gd

268 lines
7.7 KiB
GDScript

extends Node
class_name TerminalControls
@onready var historyContainer = $MarginContainer/ScrollContainer/VBoxContainer
@onready var caret = $MarginContainer/ScrollContainer/VBoxContainer/Label/Caret
@onready var blink_timer = $MarginContainer/ScrollContainer/VBoxContainer/Label/CaretTimer
@export var terminalLine: RichTextLabel
var command: String
var directory: String = "~/"
var fileSystem: Dictionary = {
"documents": {
"special": {
"notes.txt": "test",
"secrets": {
"password.txt": "123"
}
}
},
"bin": {
"sh": "binary data",
}
}
func _ready() -> void:
terminalLine.text = "user@work "+ directory + " "
blink_timer.start()
Help()
UpdateCaretPos()
# --- Caret Blinking Logic ---
func _on_caret_timer_timeout() -> void:
caret.visible = !caret.visible
func reset_blink() -> void:
caret.visible = true
blink_timer.start() # Resets the countdown
# --- Input Handling ---
func InputChar(input) -> void:
if input == null:
return
else:
command = input
terminalLine.text += command
UpdateCaretPos()
await get_tree().create_timer(.01).timeout
reset_blink()
func InputDelChar() -> void:
if terminalLine.text.length() > ("user@work " + directory).length() + 1:
terminalLine.text = terminalLine.text.left(-1)
UpdateCaretPos()
await get_tree().create_timer(.01).timeout
reset_blink()
func EnterCommand() -> void:
var fullText = terminalLine.text
var userInput = fullText.trim_prefix("user@work " + directory).strip_edges()
var parts = userInput.to_lower().split(" ")
if historyContainer.get_child_count() <24:
CreateHistoryEntry(fullText)
match parts[0]:
"ls", "list":
var currentDirData
if parts.size() > 1:
currentDirData = GetDirAtPath(directory + parts[1])
else:
currentDirData = GetDirAtPath(directory)
if currentDirData is Dictionary:
var list = ""
for key in currentDirData.keys():
list += key + " "
CreateHistoryEntry(list)
else:
CreateHistoryEntry("error: Directory not found")
"cd", "changedirectory":
if parts.size() > 1:
var targetPath = parts[1]
var newDir = ResolvePath(directory, targetPath)
if GetDirAtPath(newDir) != null:
directory = newDir
else:
CreateHistoryEntry("cd: no such directory: " + targetPath)
else:
directory = "~/"
"cat", "view":
if parts.size() > 1:
RetrieveData(parts[1])
else:
CreateHistoryEntry("usage: cat [filename]")
"clear", "cls":
for child in historyContainer.get_children():
if child != terminalLine:
child.queue_free()
"help":
Help()
"":
pass
_:
CreateHistoryEntry("Command not found: " + userInput)
terminalLine.text = "user@work "+ directory + " "
UpdateCaretPos()
GetBottomScroll()
# --- History and FileSystem Helpers ---
func CreateHistoryEntry(content: String) -> void:
# var label = Label.new()
# label.text = content
# label.label_settings = LabelSettings.new()
# label.label_settings.font_size = 42
# label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
# label.custom_minimum_size = Vector2(1400, 0)
#
#if terminalLine.text.length() > 200:
#for child in historyContainer.get_children():
#if child != terminalLine:
#child.queue_free()
# historyContainer.add_child(label)
# historyContainer.move_child(label, historyContainer.get_child_count() - 2)
var rtl = RichTextLabel.new()
rtl.bbcode_enabled = true
rtl.fit_content = true # Important for VBoxContainer
rtl.text = content
rtl.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
rtl.custom_minimum_size = Vector2(1400, 0)
rtl.add_theme_font_size_override("normal_font_size", 42)
# Optional: Set a theme or font override here
# rtl.add_theme_font_size_override("normal_font_size", 42)
historyContainer.add_child(rtl)
# Moves the entry above the input line
historyContainer.move_child(rtl, historyContainer.get_child_count() - 2)
func ResolvePath(current: String, target: String) -> String:
if target.begins_with("~/"):
return target if target.ends_with("/") else target + "/"
if target == "..":
if current == "~/": return "~/"
var parts = current.trim_suffix("/").rsplit("/", true, 1)
return parts[0] + "/"
var joined = current + target
return joined if joined.ends_with("/") else joined + "/"
func GetDirAtPath(path: String):
if path == "~/" or path == "": return fileSystem
var cleanPath = path.trim_prefix("~/").trim_suffix("/")
var folders = cleanPath.split("/")
var current = fileSystem
for folder in folders:
if folder == "": continue
if current is Dictionary and current.has(folder):
if current[folder] is Dictionary:
current = current[folder]
else:
# We hit a file, not a directory
return null
else:
return null
return current
func RetrieveData(inputPath: String):
var targetFileName: String
var targetDirData: Dictionary
if "/" in inputPath:
var pathParts = inputPath.rsplit("/", true, 1)
var dirPath = pathParts[0]
targetFileName = pathParts[1]
var resolvedDirPath = ResolvePath(directory, dirPath)
var result = GetDirAtPath(resolvedDirPath)
if result is Dictionary:
targetDirData = result
else:
CreateHistoryEntry("cat: " + dirPath + ": No such directory")
return
else:
targetFileName = inputPath
targetDirData = GetDirAtPath(directory)
if targetDirData.has(targetFileName):
var content = targetDirData[targetFileName]
if content is Dictionary:
CreateHistoryEntry("cat: " + targetFileName + ": Is a directory")
else:
CreateHistoryEntry(str(content))
else:
CreateHistoryEntry("cat: " + targetFileName + ": No such file or directory")
func Help(commandName: String = "default"):
match commandName:
"default": CreateHistoryEntry("--- AVAILABLE COMMANDS ---
ls (or list) [folder] : List all files and directories/folders
cd [folder] : Change directory (use '..' to go up a directory/folder)
cat (or view) [file] : Read the contents of a file
clear (or cls) : Clear the terminal screen
help : Show this menu
-------------------------")
func ScrollUp():
#var scroll: ScrollContainer = $MarginContainer/ScrollContainer
#await get_tree().create_timer(.0001).timeout
#scroll.set_deferred("scroll_vertical", scroll.get_v_scroll_bar().value - 10 )
#call_deferred("ScrollUp")
var scrolli: RichTextLabel = $MarginContainer/ScrollContainer/VBoxContainer/Label
var scroll = scrolli.get_v_scroll_bar()
var tween: = create_tween()
tween.tween_property(scroll, "value", scroll.value - (scroll.page - scroll.page * 0.1), 0.1)
get_tree().get_root().set_input_as_handled()
func ScrollDown():
var scroll: ScrollContainer = $MarginContainer/ScrollContainer
await get_tree().create_timer(.0001).timeout
scroll.set_deferred("scroll_vertical", scroll.get_v_scroll_bar().value + 10 )
call_deferred("ScrollDown")
func GetBottomScroll():
var scroll: ScrollContainer = $MarginContainer/ScrollContainer
var scrollMax: float = scroll.get_v_scroll_bar().max_value
await get_tree().create_timer(.01).timeout
scroll.set_deferred("scroll_vertical", scrollMax)
#scroll.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_SHOW_NEVER
call_deferred("GetBottomScroll")
func UpdateCaretPos():
await get_tree().create_timer(.01).timeout
var font = terminalLine.get_theme_font("normal_font")
var font_size = terminalLine.get_theme_font_size("normal_font_size")
var visible_text = terminalLine.get_parsed_text()
var lines = visible_text.split("\n")
var last_line = lines[-1]
var char_rectY = terminalLine.get_content_height()
var text_line = TextLine.new()
text_line.width = terminalLine.size.x
text_line.flags = TextServer.JUSTIFICATION_NONE
text_line.alignment = HORIZONTAL_ALIGNMENT_LEFT
text_line.add_string(last_line, font, font_size)
caret.position.x = text_line.get_line_width()
caret.position.y = char_rectY - 50
pass