2021-07-08 15:10:34 +02:00
|
|
|
# Copyright (c) 2021, Leroy Hopson (MIT License).
|
|
|
|
#
|
|
|
|
# This file contains snippets of code derived from Godot's TextEdit node.
|
|
|
|
# These snippets are copyright of their authors and released under the MIT license:
|
|
|
|
# - Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur (MIT License).
|
|
|
|
# - Copyright (c) 2014-2021 Godot Engine contributors (MIT License).
|
2021-06-19 15:57:05 +02:00
|
|
|
tool
|
|
|
|
extends Control
|
|
|
|
|
|
|
|
const DefaultTheme = preload("../../themes/default.tres")
|
|
|
|
|
|
|
|
signal data_sent(data)
|
|
|
|
signal key_pressed(data, event)
|
|
|
|
signal size_changed(new_size)
|
2021-07-03 16:57:19 +02:00
|
|
|
signal bell
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
enum UpdateMode {
|
|
|
|
DISABLED,
|
|
|
|
AUTO,
|
|
|
|
ALL,
|
|
|
|
ALL_NEXT_FRAME,
|
|
|
|
}
|
|
|
|
|
|
|
|
export (UpdateMode) var update_mode = UpdateMode.AUTO setget set_update_mode
|
|
|
|
|
2021-07-02 19:04:34 +02:00
|
|
|
var cols = 2
|
|
|
|
var rows = 2
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
var _viewport: Viewport = preload("./viewport.tscn").instance()
|
|
|
|
var _native_terminal: Control = _viewport.get_node("Terminal")
|
|
|
|
var _screen := TextureRect.new()
|
|
|
|
var _visibility_notifier := VisibilityNotifier2D.new()
|
2021-07-02 19:04:34 +02:00
|
|
|
var _dirty := false
|
|
|
|
|
|
|
|
var buffer := StreamPeerBuffer.new()
|
|
|
|
|
|
|
|
var times = 0
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
func set_update_mode(value):
|
|
|
|
update_mode = value
|
|
|
|
_native_terminal.update_mode = value
|
|
|
|
|
|
|
|
|
|
|
|
func get_rows() -> int:
|
2021-07-02 19:04:34 +02:00
|
|
|
return 0
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
func get_cols() -> int:
|
2021-07-02 19:04:34 +02:00
|
|
|
return 0
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
func write(data) -> void:
|
|
|
|
assert(data is String or data is PoolByteArray)
|
2021-07-02 19:04:34 +02:00
|
|
|
|
|
|
|
# FIXME: This will occasionally cause a "Resumed function after yield, but class instance is gone" error after freeing the Terminal instance.
|
|
|
|
# However, this yield is necessary to ensure the terminal state machines framebuffer is up to date when we make all the draw_* calls.
|
|
|
|
yield(VisualServer, "frame_pre_draw")
|
|
|
|
|
|
|
|
_native_terminal.write(data if data is String else data.get_string_from_utf8())
|
|
|
|
_native_terminal.update()
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
|
|
if theme:
|
|
|
|
_native_terminal.theme = theme
|
|
|
|
|
|
|
|
_native_terminal.update_mode = update_mode
|
|
|
|
_native_terminal.connect("data_sent", self, "_on_data_sent")
|
|
|
|
_native_terminal.connect("key_pressed", self, "_on_key_pressed")
|
|
|
|
_native_terminal.connect("size_changed", self, "_on_size_changed")
|
2021-07-03 16:57:19 +02:00
|
|
|
_native_terminal.connect("bell", self, "_on_bell")
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
_viewport.size = rect_size
|
|
|
|
_viewport.render_target_update_mode = Viewport.UPDATE_ALWAYS
|
|
|
|
|
|
|
|
_screen.set_anchors_preset(PRESET_WIDE)
|
|
|
|
_screen.texture = _viewport.get_texture()
|
|
|
|
|
|
|
|
_visibility_notifier.connect("screen_entered", self, "_refresh")
|
|
|
|
|
|
|
|
add_child(_viewport)
|
|
|
|
add_child(_screen)
|
|
|
|
add_child(_visibility_notifier)
|
|
|
|
|
|
|
|
_refresh()
|
|
|
|
|
|
|
|
|
|
|
|
func _refresh():
|
|
|
|
if update_mode == UpdateMode.AUTO:
|
|
|
|
_native_terminal.update_mode = UpdateMode.ALL_NEXT_FRAME
|
|
|
|
|
|
|
|
|
|
|
|
func _gui_input(event):
|
|
|
|
_native_terminal._gui_input(event)
|
2021-07-08 15:10:34 +02:00
|
|
|
_handle_mouse_wheel(event)
|
|
|
|
|
|
|
|
|
|
|
|
func _handle_mouse_wheel(event: InputEventMouseButton):
|
|
|
|
if not event or not event.is_pressed():
|
|
|
|
return
|
|
|
|
|
|
|
|
if event.button_index == BUTTON_WHEEL_UP:
|
|
|
|
if event.alt:
|
|
|
|
# Scroll 5 times as fast as normal (like TextEdit).
|
|
|
|
_native_terminal.sb_up(15 * event.factor)
|
|
|
|
else:
|
|
|
|
# Scroll 3 lines.
|
|
|
|
_native_terminal.sb_up(3 * event.factor)
|
|
|
|
|
|
|
|
if event.button_index == BUTTON_WHEEL_DOWN:
|
|
|
|
if event.alt:
|
|
|
|
# Scroll 5 times as fast as normal (like TextEdit).
|
|
|
|
_native_terminal.sb_down(15 * event.factor)
|
|
|
|
else:
|
|
|
|
# Scroll 3 lines.
|
|
|
|
_native_terminal.sb_down(3 * event.factor)
|
2021-06-19 15:57:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
func _notification(what: int) -> void:
|
|
|
|
match what:
|
|
|
|
NOTIFICATION_RESIZED:
|
|
|
|
_viewport.size = rect_size
|
|
|
|
_visibility_notifier.rect = get_rect()
|
|
|
|
_refresh()
|
|
|
|
NOTIFICATION_THEME_CHANGED:
|
|
|
|
_native_terminal.theme = theme
|
|
|
|
_refresh()
|
|
|
|
|
|
|
|
|
|
|
|
func _on_data_sent(data: PoolByteArray):
|
|
|
|
emit_signal("data_sent", data)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_key_pressed(data: String, event: InputEventKey):
|
|
|
|
emit_signal("key_pressed", data, event)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_size_changed(new_size: Vector2):
|
2021-07-02 19:04:34 +02:00
|
|
|
cols = new_size.x
|
|
|
|
rows = new_size.y
|
2021-06-19 15:57:05 +02:00
|
|
|
emit_signal("size_changed", new_size)
|
2021-07-02 19:04:34 +02:00
|
|
|
|
|
|
|
|
2021-07-03 16:57:19 +02:00
|
|
|
func _on_bell():
|
|
|
|
emit_signal("bell")
|
|
|
|
|
|
|
|
|
2021-07-02 19:04:34 +02:00
|
|
|
func _set_size_warning(value):
|
|
|
|
if value:
|
|
|
|
push_warning(
|
|
|
|
"Terminal cols and rows are read only and determined by the font and rect sizes."
|
|
|
|
)
|