mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-25 02:30:27 +01:00
Further progress towards Godot 4.0 support
- Primary example scenes (menu, terminal, and asciicast) working but still a lot of warning/error messages and some regressions. - Editor integrated terminal works, but still a lot of warning/error messages and some regressions. - Added support for "blink" display attribute. - Removed GDScript terminal code. Terminal node is now purely a GDExtension. So is LibuvUtils. - GUT tests not working yet. - Still a lot of things to fix. - So far, only built for and manually tested on Linux x86_64.
This commit is contained in:
parent
aad8e39dae
commit
ad7f97e493
30 changed files with 1385 additions and 1459 deletions
|
@ -1,5 +1,5 @@
|
|||
@tool
|
||||
extends "../../terminal.gd"
|
||||
extends Terminal
|
||||
|
||||
signal exited(exit_code, signum)
|
||||
|
||||
|
@ -14,46 +14,43 @@ func _set_terminal_colors(color_map: Dictionary) -> void:
|
|||
for key in color_map.keys():
|
||||
var val: String = color_map[key]
|
||||
var color: Color = editor_settings.get_setting("text_editor/highlighting/%s" % val)
|
||||
theme.set_color(key, "Terminal", color)
|
||||
add_theme_color_override(key, color)
|
||||
|
||||
|
||||
func _ready():
|
||||
if not editor_settings:
|
||||
return
|
||||
|
||||
theme = Theme.new()
|
||||
|
||||
# Get colors from TextEdit theme. Created using the default (Adaptive) theme
|
||||
# for reference, but will probably cause strange results if using another theme
|
||||
# better to use a dedicated terminal theme, rather than relying on this.
|
||||
_set_terminal_colors(
|
||||
{
|
||||
"black": "caret_background_color",
|
||||
"red": "keyword_color",
|
||||
"green": "gdscript/node_path_color",
|
||||
"yellow": "string_color",
|
||||
"blue": "function_color",
|
||||
"magenta": "symbol_color",
|
||||
"cyan": "gdscript/function_definition_color",
|
||||
"white": "text_color",
|
||||
"bright_black": "comment_color",
|
||||
"bright_red": "breakpoint_color",
|
||||
"bright_green": "base_type_color",
|
||||
"bright_yellow": "search_result_color",
|
||||
"bright_blue": "member_variable_color",
|
||||
"bright_magenta": "code_folding_color",
|
||||
"bright_cyan": "user_type_color",
|
||||
"bright_white": "text_selected_color",
|
||||
"background": "background_color",
|
||||
"foreground": "caret_color",
|
||||
"ansi_0_color": "completion_background_color",
|
||||
"ansi_1_color": "keyword_color",
|
||||
"ansi_2_color": "gdscript/node_path_color",
|
||||
"ansi_3_color": "string_color",
|
||||
"ansi_4_color": "function_color",
|
||||
"ansi_5_color": "symbol_color",
|
||||
"ansi_6_color": "gdscript/function_definition_color",
|
||||
"ansi_7_color": "text_color",
|
||||
"ansi_8_color": "comment_color",
|
||||
"ansi_9_color": "breakpoint_color",
|
||||
"ansi_10_color": "base_type_color",
|
||||
"ansi_11_color": "search_result_color",
|
||||
"ansi_12_color": "member_variable_color",
|
||||
"ansi_13_color": "code_folding_color",
|
||||
"ansi_14_color": "user_type_color",
|
||||
"ansi_15_color": "text_selected_color",
|
||||
"background_color": "background_color",
|
||||
"foreground_color": "caret_color",
|
||||
}
|
||||
)
|
||||
_native_terminal._update_theme()
|
||||
|
||||
|
||||
func _input(event):
|
||||
if has_focus() and event is InputEventKey and event.is_pressed():
|
||||
if event.control and event.scancode in [KEY_PAGEUP, KEY_PAGEDOWN]:
|
||||
if event.ctrl_pressed and event.scancode in [KEY_PAGEUP, KEY_PAGEDOWN]:
|
||||
# Handled by switch tabs shortcut.
|
||||
return
|
||||
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://bkcyv0w3setep"]
|
||||
|
||||
[ext_resource path="res://addons/godot_xterm/editor_plugins/terminal/editor_terminal.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_xterm/pty.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/godot_xterm/themes/default.tres" type="Theme" id=3]
|
||||
[ext_resource type="Script" path="res://addons/godot_xterm/editor_plugins/terminal/editor_terminal.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://addons/godot_xterm/pty.gd" id="2"]
|
||||
[ext_resource type="Theme" uid="uid://c3ep6rm56qjeb" path="res://addons/godot_xterm/themes/default.tres" id="3"]
|
||||
|
||||
[node name="Terminal" type="Control"]
|
||||
[node name="Terminal" type="Terminal"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
focus_mode = 1
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
theme = ExtResource( 3 )
|
||||
script = ExtResource( 1 )
|
||||
focus_mode = 1
|
||||
theme = ExtResource("3")
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="PTY" type="Node" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
script = ExtResource("2")
|
||||
terminal_path = NodePath("..")
|
||||
env = {
|
||||
"COLORTERM": "truecolor",
|
||||
"TERM": "xterm-256color"
|
||||
}
|
||||
|
||||
[node name="Bell" type="AudioStreamPlayer" parent="."]
|
||||
|
||||
[connection signal="bell" from="." to="Bell" method="play"]
|
||||
[connection signal="exited" from="PTY" to="." method="_on_PTY_exited"]
|
||||
|
|
|
@ -28,9 +28,9 @@ var editor_plugin: EditorPlugin
|
|||
var editor_interface: EditorInterface
|
||||
|
||||
@onready var editor_settings: EditorSettings = editor_interface.get_editor_settings()
|
||||
@onready var tabs: TabBar = $VBoxContainer/TabbarContainer/TabBar
|
||||
@onready var tabs: TabBar = $VBoxContainer/TabbarContainer/Tabs
|
||||
@onready var tabbar_container: HBoxContainer = $VBoxContainer/TabbarContainer
|
||||
@onready var add_button: Button = $VBoxContainer/TabbarContainer/TabBar/AddButton
|
||||
@onready var add_button: Button = $VBoxContainer/TabbarContainer/AddButton
|
||||
@onready var tab_container: TabContainer = $VBoxContainer/TabContainer
|
||||
@onready var terminal_popup_menu: PopupMenu = $VBoxContainer/TerminalPopupMenu
|
||||
|
||||
|
@ -39,7 +39,7 @@ var editor_interface: EditorInterface
|
|||
@onready var size_label: Label = $SizeLabel
|
||||
@onready var size_label_timer: Timer = $SizeLabel/SizeLabelTimer
|
||||
|
||||
@onready var ready := true
|
||||
@onready var is_ready := true
|
||||
|
||||
var _theme := Theme.new()
|
||||
var _settings: TerminalSettings
|
||||
|
@ -47,7 +47,9 @@ var _tab_container_min_size
|
|||
|
||||
|
||||
func _ready():
|
||||
tab_container.add_theme_stylebox_override("panel", get_stylebox("background", "EditorStyles"))
|
||||
tab_container.add_theme_stylebox_override(
|
||||
"panel", get_theme_stylebox("background", "EditorStyles")
|
||||
)
|
||||
_update_settings()
|
||||
|
||||
|
||||
|
@ -55,18 +57,6 @@ func _load_or_create_settings() -> void:
|
|||
# Use only default settings for now, until settings are properly defined
|
||||
# and documented.
|
||||
_settings = TerminalSettings.new()
|
||||
return
|
||||
|
||||
var dir := Directory.new()
|
||||
|
||||
if not dir.dir_exists(SETTINGS_FILE_PATH.get_base_dir()):
|
||||
dir.make_dir(SETTINGS_FILE_PATH.get_base_dir())
|
||||
|
||||
if not dir.file_exists(SETTINGS_FILE_PATH):
|
||||
var settings := TerminalSettings.new()
|
||||
ResourceSaver.save(SETTINGS_FILE_PATH, settings)
|
||||
|
||||
_settings = load(SETTINGS_FILE_PATH)
|
||||
|
||||
|
||||
func _update_settings() -> void:
|
||||
|
@ -76,36 +66,37 @@ func _update_settings() -> void:
|
|||
if editor_interface.has_method("get_editor_scale"):
|
||||
editor_scale = editor_interface.get_editor_scale()
|
||||
|
||||
minimum_size = Vector2(0, tabbar_container.size.y + 182) * editor_scale
|
||||
custom_minimum_size = Vector2(0, tabbar_container.size.y + 182) * editor_scale
|
||||
size.y = 415
|
||||
|
||||
tabs.tab_close_display_policy = TabBar.CLOSE_BUTTON_SHOW_ALWAYS
|
||||
|
||||
# Update shortcuts.
|
||||
if _settings.new_terminal_shortcut:
|
||||
terminal_popup_menu.set_item_shortcut(
|
||||
TerminalPopupMenuOptions.NEW_TERMINAL, _settings.new_terminal_shortcut, true
|
||||
)
|
||||
if _settings.kill_terminal_shortcut:
|
||||
terminal_popup_menu.set_item_shortcut(
|
||||
TerminalPopupMenuOptions.KILL_TERMINAL, _settings.kill_terminal_shortcut, false
|
||||
)
|
||||
if _settings.copy_shortcut:
|
||||
terminal_popup_menu.set_item_shortcut(
|
||||
TerminalPopupMenuOptions.COPY, _settings.copy_shortcut, false
|
||||
)
|
||||
if _settings.paste_shortcut:
|
||||
terminal_popup_menu.set_item_shortcut(
|
||||
TerminalPopupMenuOptions.PASTE, _settings.paste_shortcut, false
|
||||
)
|
||||
#FIXME
|
||||
# # Update shortcuts.
|
||||
# if _settings.new_terminal_shortcut:
|
||||
# terminal_popup_menu.set_item_shortcut(
|
||||
# TerminalPopupMenuOptions.NEW_TERMINAL, _settings.new_terminal_shortcut, true
|
||||
# )
|
||||
# if _settings.kill_terminal_shortcut:
|
||||
# terminal_popup_menu.set_item_shortcut(
|
||||
# TerminalPopupMenuOptions.KILL_TERMINAL, _settings.kill_terminal_shortcut, false
|
||||
# )
|
||||
# if _settings.copy_shortcut:
|
||||
# terminal_popup_menu.set_item_shortcut(
|
||||
# TerminalPopupMenuOptions.COPY, _settings.copy_shortcut, false
|
||||
# )
|
||||
# if _settings.paste_shortcut:
|
||||
# terminal_popup_menu.set_item_shortcut(
|
||||
# TerminalPopupMenuOptions.PASTE, _settings.paste_shortcut, false
|
||||
# )
|
||||
|
||||
_update_terminal_tabs()
|
||||
|
||||
|
||||
func _update_terminal_tabs():
|
||||
# Wait a couple of frames to allow everything to resize before updating.
|
||||
await get_tree().idle_frame
|
||||
await get_tree().idle_frame
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
|
||||
if tabs.get_offset_buttons_visible():
|
||||
# Move add button to fixed position on the tabbar.
|
||||
|
@ -116,7 +107,7 @@ func _update_terminal_tabs():
|
|||
tabbar_container.move_child(add_button, 0)
|
||||
else:
|
||||
# Move add button after last tab.
|
||||
if add_button.get_parent() == tabbar_container:
|
||||
if tabs.tab_count > 0 and add_button.get_parent() == tabbar_container:
|
||||
tabbar_container.remove_child(add_button)
|
||||
tabs.add_child(add_button)
|
||||
var last_tab := Rect2()
|
||||
|
@ -125,6 +116,9 @@ func _update_terminal_tabs():
|
|||
add_button.position = Vector2(
|
||||
last_tab.position.x + last_tab.size.x + 3, last_tab.position.y
|
||||
)
|
||||
if tabs.tab_count == 0 and add_button.get_parent() == tabs:
|
||||
tabs.remove_child(add_button)
|
||||
tabbar_container.add_child(add_button)
|
||||
|
||||
# Make sure we still own the button, so it gets saved with our scene.
|
||||
add_button.owner = self
|
||||
|
@ -135,9 +129,9 @@ func _on_AddButton_pressed():
|
|||
var terminal := EditorTerminal.instantiate()
|
||||
tabs.add_tab(shell.get_file())
|
||||
terminal.editor_settings = editor_settings
|
||||
terminal.set_anchors_preset(PRESET_WIDE)
|
||||
terminal.connect("gui_input",Callable(self,"_on_TabContainer_gui_input"))
|
||||
terminal.connect("exited",Callable(self,"_on_Terminal_exited").bind(terminal))
|
||||
terminal.set_anchors_preset(PRESET_BOTTOM_WIDE)
|
||||
terminal.connect("gui_input", Callable(self, "_on_TabContainer_gui_input"))
|
||||
terminal.connect("exited", Callable(self, "_on_Terminal_exited").bind(terminal))
|
||||
tab_container.add_child(terminal)
|
||||
terminal.pty.fork(shell)
|
||||
terminal.grab_focus()
|
||||
|
@ -163,7 +157,7 @@ func _on_Tabs_tab_close(tab_index):
|
|||
|
||||
|
||||
func _notification(what):
|
||||
if not ready:
|
||||
if not is_ready:
|
||||
return
|
||||
|
||||
match what:
|
||||
|
@ -181,46 +175,53 @@ func _input(event: InputEvent) -> void:
|
|||
return
|
||||
|
||||
# Global shortcut to open new terminal and make terminal panel visible.
|
||||
if _settings.new_terminal_shortcut and _settings.new_terminal_shortcut.shortcut:
|
||||
if event.is_match(_settings.new_terminal_shortcut.shortcut):
|
||||
get_tree().set_input_as_handled()
|
||||
editor_plugin.make_bottom_panel_item_visible(self)
|
||||
_on_AddButton_pressed()
|
||||
# FIXME
|
||||
# if _settings.new_terminal_shortcut and _settings.new_terminal_shortcut.shortcut:
|
||||
# if event.is_match(_settings.new_terminal_shortcut.shortcut):
|
||||
# get_tree().set_input_as_handled()
|
||||
# editor_plugin.make_bottom_panel_item_visible(self)
|
||||
# _on_AddButton_pressed()
|
||||
|
||||
# Non-global shortcuts, only applied if terminal is active and focused.
|
||||
if (
|
||||
tabs.get_tab_count() > 0 and tab_container.get_child(tabs.current_tab).has_focus()
|
||||
or terminal_popup_menu.has_focus()
|
||||
):
|
||||
pass
|
||||
# Kill terminal.
|
||||
if _settings.kill_terminal_shortcut and _settings.kill_terminal_shortcut.shortcut:
|
||||
if event.is_match(_settings.kill_terminal_shortcut.shortcut):
|
||||
get_tree().set_input_as_handled()
|
||||
_on_TerminalPopupMenu_id_pressed(TerminalPopupMenuOptions.KILL_TERMINAL)
|
||||
# FIXME shortcut
|
||||
|
||||
# Copy.
|
||||
if _settings.copy_shortcut and _settings.copy_shortcut.shortcut:
|
||||
if event.is_match(_settings.copy_shortcut.shortcut):
|
||||
get_tree().set_input_as_handled()
|
||||
_on_TerminalPopupMenu_id_pressed(TerminalPopupMenuOptions.COPY)
|
||||
|
||||
# Paste.
|
||||
if _settings.paste_shortcut and _settings.paste_shortcut.shortcut:
|
||||
if event.is_match(_settings.paste_shortcut.shortcut):
|
||||
get_tree().set_input_as_handled()
|
||||
_on_TerminalPopupMenu_id_pressed(TerminalPopupMenuOptions.PASTE)
|
||||
# if _settings.kill_terminal_shortcut and _settings.kill_terminal_shortcut.shortcut:
|
||||
# if event.is_match(_settings.kill_terminal_shortcut.shortcut):
|
||||
# get_tree().set_input_as_handled()
|
||||
# _on_TerminalPopupMenu_id_pressed(TerminalPopupMenuOptions.KILL_TERMINAL)
|
||||
|
||||
# Next tab.
|
||||
if _settings.next_tab_shortcut and _settings.next_tab_shortcut.shortcut:
|
||||
if event.is_match(_settings.next_tab_shortcut.shortcut):
|
||||
get_tree().set_input_as_handled()
|
||||
tabs.current_tab = min(tabs.current_tab + 1, tabs.get_tab_count() - 1)
|
||||
# Copy.
|
||||
#FIXME
|
||||
# if _settings.copy_shortcut and _settings.copy_shortcut.shortcut:
|
||||
# if event.is_match(_settings.copy_shortcut.shortcut):
|
||||
# get_tree().set_input_as_handled()
|
||||
# _on_TerminalPopupMenu_id_pressed(TerminalPopupMenuOptions.COPY)
|
||||
|
||||
# Previous tab.
|
||||
if _settings.previous_tab_shortcut and _settings.previous_tab_shortcut.shortcut:
|
||||
if event.is_match(_settings.previous_tab_shortcut.shortcut):
|
||||
get_tree().set_input_as_handled()
|
||||
tabs.current_tab = max(tabs.current_tab - 1, 0)
|
||||
# Paste.
|
||||
#FIXME
|
||||
# if _settings.paste_shortcut and _settings.paste_shortcut.shortcut:
|
||||
# if event.is_match(_settings.paste_shortcut.shortcut):
|
||||
# get_tree().set_input_as_handled()
|
||||
# _on_TerminalPopupMenu_id_pressed(TerminalPopupMenuOptions.PASTE)
|
||||
#
|
||||
# # Next tab.
|
||||
# if _settings.next_tab_shortcut and _settings.next_tab_shortcut.shortcut:
|
||||
# if event.is_match(_settings.next_tab_shortcut.shortcut):
|
||||
# get_tree().set_input_as_handled()
|
||||
# tabs.current_tab = min(tabs.current_tab + 1, tabs.get_tab_count() - 1)
|
||||
#
|
||||
# # Previous tab.
|
||||
# if _settings.previous_tab_shortcut and _settings.previous_tab_shortcut.shortcut:
|
||||
# if event.is_match(_settings.previous_tab_shortcut.shortcut):
|
||||
# get_tree().set_input_as_handled()
|
||||
# tabs.current_tab = max(tabs.current_tab - 1, 0)
|
||||
|
||||
|
||||
func _on_TabContainer_gui_input(event):
|
||||
|
@ -238,15 +239,15 @@ func _on_TerminalPopupMenu_id_pressed(id):
|
|||
var terminal = tab_container.get_child(tab_container.current_tab)
|
||||
match id:
|
||||
TerminalPopupMenuOptions.COPY:
|
||||
OS.clipboard = terminal.copy_selection()
|
||||
DisplayServer.clipboard_set(terminal.copy_selection())
|
||||
TerminalPopupMenuOptions.PASTE:
|
||||
for i in OS.clipboard.length():
|
||||
for i in DisplayServer.clipboard_get().length():
|
||||
var event = InputEventKey.new()
|
||||
event.unicode = ord(OS.clipboard[i])
|
||||
event.unicode = DisplayServer.clipboard_get().unicode_at(i)
|
||||
event.button_pressed = true
|
||||
terminal._gui_input(event)
|
||||
TerminalPopupMenuOptions.COPY_ALL:
|
||||
OS.clipboard = terminal.copy_all()
|
||||
DisplayServer.clipboard_set(terminal.copy_all())
|
||||
TerminalPopupMenuOptions.CLEAR:
|
||||
terminal.clear()
|
||||
TerminalPopupMenuOptions.KILL_TERMINAL:
|
||||
|
|
|
@ -1,119 +1,93 @@
|
|||
[gd_scene load_steps=7 format=2]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://cbxovnvw5o4mo"]
|
||||
|
||||
[ext_resource path="res://addons/godot_xterm/editor_plugins/terminal/terminal_panel.gd" type="Script" id=1]
|
||||
[ext_resource type="Script" path="res://addons/godot_xterm/editor_plugins/terminal/terminal_panel.gd" id="1"]
|
||||
|
||||
[sub_resource type="Image" id=6]
|
||||
[sub_resource type="Image" id="Image_x7bb3"]
|
||||
data = {
|
||||
"data": PackedByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=2]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 6 )
|
||||
size = Vector2( 16, 16 )
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id=3]
|
||||
texture = SubResource( 2 )
|
||||
region_rect = Rect2( 0, 0, 16, 16 )
|
||||
offset_left = 2.0
|
||||
offset_right = 2.0
|
||||
offset_top = 2.0
|
||||
offset_bottom = 2.0
|
||||
|
||||
[sub_resource type="Image" id=7]
|
||||
data = {
|
||||
"data": PackedByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "RGBA8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=5]
|
||||
flags = 0
|
||||
flags = 0
|
||||
image = SubResource( 7 )
|
||||
size = Vector2( 16, 16 )
|
||||
[sub_resource type="ImageTexture" id="ImageTexture_e8boo"]
|
||||
image = SubResource("Image_x7bb3")
|
||||
|
||||
[node name="Panel" type="Panel"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -3.0
|
||||
minimum_size = Vector2( 0, 34 )
|
||||
custom_styles/panel = SubResource( 3 )
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
offset_bottom = 3.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
minimum_size = Vector2( 0, 24 )
|
||||
custom_constants/separation = 0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="TabbarContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TabBar" type="TabBar" parent="VBoxContainer/TabbarContainer"]
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
tab_alignment = 0
|
||||
tab_close_display_policy = 1
|
||||
[node name="Tabs" type="TabBar" parent="VBoxContainer/TabbarContainer"]
|
||||
layout_mode = 2
|
||||
clip_tabs = false
|
||||
drag_to_rearrange_enabled = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="AddButton" type="Button" parent="VBoxContainer/TabbarContainer/TabBar"]
|
||||
offset_left = 3.0
|
||||
offset_right = 31.0
|
||||
offset_bottom = 24.0
|
||||
[node name="AddButton" type="Button" parent="VBoxContainer/TabbarContainer"]
|
||||
layout_mode = 2
|
||||
tooltip_text = "Add a new scene."
|
||||
icon = SubResource( 5 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
icon = SubResource("ImageTexture_e8boo")
|
||||
|
||||
[node name="PopupMenu" type="PopupMenu" parent="VBoxContainer/TabbarContainer"]
|
||||
offset_left = 906.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 88.0
|
||||
items = [ "Kill", null, 0, false, false, 0, 0, null, "", false, "Kill Others", null, 0, false, false, 1, 0, null, "", false, "Kill to the Right", null, 0, false, false, 2, 0, null, "", false, "Kill All", null, 0, false, false, 3, 0, null, "", false ]
|
||||
item_count = 4
|
||||
item_0/text = "Kill"
|
||||
item_0/id = 0
|
||||
item_1/text = "Kill Others"
|
||||
item_1/id = 1
|
||||
item_2/text = "Kill to the Right"
|
||||
item_2/id = 2
|
||||
item_3/text = "Kill All"
|
||||
item_3/id = 3
|
||||
|
||||
[node name="TabContainer" type="TabContainer" parent="VBoxContainer"]
|
||||
offset_top = 24.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 603.0
|
||||
clip_contents = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
custom_constants/top_margin = 0
|
||||
custom_constants/side_margin = 0
|
||||
custom_styles/panel = SubResource( 3 )
|
||||
tabs_visible = false
|
||||
|
||||
[node name="TerminalPopupMenu" type="PopupMenu" parent="VBoxContainer"]
|
||||
offset_right = 193.0
|
||||
offset_bottom = 160.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
items = [ "New Terminal", null, 0, false, false, 0, 0, null, "", false, "", null, 0, false, true, 1, 0, null, "", true, "Copy", null, 0, false, false, 2, 0, null, "", false, "Paste", null, 0, false, false, 3, 0, null, "", false, "Copy All", null, 0, false, false, 4, 0, null, "", false, "", null, 0, false, false, 5, 0, null, "", true, "Clear", null, 0, false, false, 6, 0, null, "", false, "Kill Terminal", null, 0, false, false, 7, 0, null, "", false ]
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
size = Vector2i(136, 178)
|
||||
item_count = 8
|
||||
item_0/text = "New Terminal"
|
||||
item_0/id = 0
|
||||
item_1/text = ""
|
||||
item_1/id = 1
|
||||
item_1/disabled = true
|
||||
item_1/separator = true
|
||||
item_2/text = "Copy"
|
||||
item_2/id = 2
|
||||
item_3/text = "Paste"
|
||||
item_3/id = 3
|
||||
item_4/text = "Copy All"
|
||||
item_4/id = 4
|
||||
item_5/text = ""
|
||||
item_5/id = 5
|
||||
item_5/separator = true
|
||||
item_6/text = "Clear"
|
||||
item_6/id = 6
|
||||
item_7/text = "Kill Terminal"
|
||||
item_7/id = 7
|
||||
|
||||
[node name="SizeLabel" type="Label" parent="."]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
|
@ -122,15 +96,15 @@ offset_left = -52.0
|
|||
offset_top = -15.5
|
||||
offset_right = 52.0
|
||||
offset_bottom = 15.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "Size: %d rows; %d cols
|
||||
(%d x %d)"
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Panel" type="Panel" parent="SizeLabel"]
|
||||
show_behind_parent = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -5.0
|
||||
|
@ -139,17 +113,13 @@ offset_right = 5.0
|
|||
offset_bottom = 5.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="SizeLabelTimer" type="Timer" parent="SizeLabel"]
|
||||
|
||||
[connection signal="resized" from="." to="." method="_on_Panel_resized"]
|
||||
[connection signal="reposition_active_tab_request" from="VBoxContainer/TabbarContainer/TabBar" to="." method="_on_Tabs_reposition_active_tab_request"]
|
||||
[connection signal="tab_changed" from="VBoxContainer/TabbarContainer/TabBar" to="." method="_on_Tabs_tab_changed"]
|
||||
[connection signal="tab_closed" from="VBoxContainer/TabbarContainer/TabBar" to="." method="_on_Tabs_tab_close"]
|
||||
[connection signal="pressed" from="VBoxContainer/TabbarContainer/TabBar/AddButton" to="." method="_on_AddButton_pressed"]
|
||||
[connection signal="tab_changed" from="VBoxContainer/TabbarContainer/Tabs" to="." method="_on_Tabs_tab_changed"]
|
||||
[connection signal="tab_close_pressed" from="VBoxContainer/TabbarContainer/Tabs" to="." method="_on_Tabs_tab_close"]
|
||||
[connection signal="pressed" from="VBoxContainer/TabbarContainer/AddButton" to="." method="_on_AddButton_pressed"]
|
||||
[connection signal="gui_input" from="VBoxContainer/TabContainer" to="." method="_on_TabContainer_gui_input"]
|
||||
[connection signal="id_pressed" from="VBoxContainer/TerminalPopupMenu" to="." method="_on_TerminalPopupMenu_id_pressed"]
|
||||
[connection signal="timeout" from="SizeLabel/SizeLabelTimer" to="." method="_on_SizeLabelTimer_timeout"]
|
||||
|
|
|
@ -39,8 +39,9 @@ func _import(source_file, save_path, options, r_platform_variant, r_gen_files):
|
|||
return err
|
||||
|
||||
var theme: Theme = XrdbTheme.new()
|
||||
theme.set_font("regular", "Terminal", preload("../themes/fonts/regular.tres"))
|
||||
for font in ["bold", "italic", "bold_italic"]:
|
||||
theme.set_font_size("font_size", "Terminal", 14)
|
||||
theme.set_font("normal_font", "Terminal", preload("../themes/fonts/regular.tres"))
|
||||
for font in ["bold_font", "italic_font", "bold_italic_font"]:
|
||||
theme.set_font(font, "Terminal", null)
|
||||
|
||||
var word_regex = RegEx.new()
|
||||
|
@ -77,37 +78,37 @@ func _import(source_file, save_path, options, r_platform_variant, r_gen_files):
|
|||
|
||||
match name:
|
||||
"color0", "ansi_0_color":
|
||||
theme.set_color("black", "Terminal", color)
|
||||
theme.set_color("ansi_0_color", "Terminal", color)
|
||||
"color1", "ansi_1_color":
|
||||
theme.set_color("red", "Terminal", color)
|
||||
theme.set_color("ansi_1_color", "Terminal", color)
|
||||
"color2", "ansi_2_color":
|
||||
theme.set_color("green", "Terminal", color)
|
||||
theme.set_color("ansi_2_color", "Terminal", color)
|
||||
"color3", "ansi_3_color":
|
||||
theme.set_color("yellow", "Terminal", color)
|
||||
theme.set_color("ansi_3_color", "Terminal", color)
|
||||
"color4", "ansi_4_color":
|
||||
theme.set_color("blue", "Terminal", color)
|
||||
theme.set_color("ansi_4_color", "Terminal", color)
|
||||
"color5", "ansi_5_color":
|
||||
theme.set_color("magenta", "Terminal", color)
|
||||
theme.set_color("ansi_5_color", "Terminal", color)
|
||||
"color6", "ansi_6_color":
|
||||
theme.set_color("cyan", "Terminal", color)
|
||||
theme.set_color("ansi_6_color", "Terminal", color)
|
||||
"color7", "ansi_7_color":
|
||||
theme.set_color("white", "Terminal", color)
|
||||
theme.set_color("ansi_7_color", "Terminal", color)
|
||||
"color8", "ansi_8_color":
|
||||
theme.set_color("bright_black", "Terminal", color)
|
||||
theme.set_color("ansi_8_color", "Terminal", color)
|
||||
"color9", "ansi_9_color":
|
||||
theme.set_color("bright_red", "Terminal", color)
|
||||
theme.set_color("ansi_9_color", "Terminal", color)
|
||||
"color10", "ansi_10_color":
|
||||
theme.set_color("bright_green", "Terminal", color)
|
||||
theme.set_color("ansi_10_color", "Terminal", color)
|
||||
"color11", "ansi_11_color":
|
||||
theme.set_color("bright_yellow", "Terminal", color)
|
||||
theme.set_color("ansi_11_color", "Terminal", color)
|
||||
"color12", "ansi_12_color":
|
||||
theme.set_color("bright_blue", "Terminal", color)
|
||||
theme.set_color("ansi_12_color", "Terminal", color)
|
||||
"color13", "ansi_13_color":
|
||||
theme.set_color("bright_magenta", "Terminal", color)
|
||||
theme.set_color("ansi_13_color", "Terminal", color)
|
||||
"color14", "ansi_14_color":
|
||||
theme.set_color("bright_cyan", "Terminal", color)
|
||||
theme.set_color("ansi_14_color", "Terminal", color)
|
||||
"color15", "ansi_15_color":
|
||||
theme.set_color("bright_white", "Terminal", color)
|
||||
theme.set_color("ansi_15_color", "Terminal", color)
|
||||
"foreground", "foreground_color":
|
||||
theme.set_color("foreground", "Terminal", color)
|
||||
"background", "background_color":
|
||||
|
|
|
@ -277,6 +277,7 @@ env.Append(LIBS=[
|
|||
|
||||
sources = []
|
||||
sources.append('src/register_types.cpp')
|
||||
sources.append('src/constants.cpp')
|
||||
sources.append('src/terminal.cpp')
|
||||
|
||||
|
||||
|
|
211
addons/godot_xterm/native/src/constants.cpp
Normal file
211
addons/godot_xterm/native/src/constants.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
#include "terminal.h"
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
const std::map<const char *, const char *> Terminal::FONTS = {
|
||||
{"normal_font", "res://addons/godot_xterm/fonts/normal.ttf"},
|
||||
{"bold_font", "res://addons/godot_xterm/fonts/bold.ttf"},
|
||||
{"italics_font", "res://addons/godot_xterm/fonts/italics.ttf"},
|
||||
{"bold_italics_font", "res://addons/godot_xterm/fonts/bold_italics.ttf"},
|
||||
};
|
||||
|
||||
// TODO: Ensure it is default Xterm dark theme.
|
||||
const Terminal::ColorMap Terminal::COLORS = {
|
||||
{"ansi_0_color", {"#000000", TSM_COLOR_BLACK}},
|
||||
{"ansi_1_color", {"#CD0000", TSM_COLOR_RED}},
|
||||
{"ansi_2_color", {"#00CD00", TSM_COLOR_GREEN}},
|
||||
{"ansi_3_color", {"#CDCD00", TSM_COLOR_YELLOW}},
|
||||
{"ansi_4_color", {"#0000EE", TSM_COLOR_BLUE}},
|
||||
{"ansi_5_color", {"#CD00CD", TSM_COLOR_MAGENTA}},
|
||||
{"ansi_6_color", {"#00CDCD", TSM_COLOR_CYAN}},
|
||||
{"ansi_7_color", {"#E5E5E5", TSM_COLOR_LIGHT_GREY}},
|
||||
{"ansi_8_color", {"#7F7F7F", TSM_COLOR_DARK_GREY}},
|
||||
{"ansi_9_color", {"#FF0000", TSM_COLOR_LIGHT_RED}},
|
||||
{"ansi_10_color", {"#00FF00", TSM_COLOR_LIGHT_GREEN}},
|
||||
{"ansi_11_color", {"#FFFF00", TSM_COLOR_LIGHT_YELLOW}},
|
||||
{"ansi_12_color", {"#0000FC", TSM_COLOR_LIGHT_BLUE}},
|
||||
{"ansi_13_color", {"#FF00FF", TSM_COLOR_LIGHT_MAGENTA}},
|
||||
{"ansi_14_color", {"#00FFFF", TSM_COLOR_LIGHT_CYAN}},
|
||||
{"ansi_15_color", {"#FFFFFF", TSM_COLOR_WHITE}},
|
||||
{"foreground_color", {"#FFFFFF", TSM_COLOR_FOREGROUND}},
|
||||
{"background_color", {"#000000", TSM_COLOR_BACKGROUND}},
|
||||
};
|
||||
|
||||
const Terminal::KeyMap Terminal::KEY_MAP = {
|
||||
// Godot does not have seperate scancodes for keypad keys when NumLock is
|
||||
// off. We can check the unicode value to determine whether it is off and
|
||||
// set the appropriate scancode. Based on the patch which adds support for
|
||||
// this to TextEdit/LineEdit:
|
||||
// https://github.com/godotengine/godot/pull/3269/files
|
||||
{{KEY_KP_0, '0'}, XKB_KEY_KP_0},
|
||||
{{KEY_KP_0, '\0'}, XKB_KEY_KP_Insert},
|
||||
{{KEY_KP_1, '1'}, XKB_KEY_KP_1},
|
||||
{{KEY_KP_1, '\0'}, XKB_KEY_KP_End},
|
||||
{{KEY_KP_2, '2'}, XKB_KEY_KP_2},
|
||||
{{KEY_KP_2, '\0'}, XKB_KEY_KP_Down},
|
||||
{{KEY_KP_3, '3'}, XKB_KEY_KP_3},
|
||||
{{KEY_KP_3, '\0'}, XKB_KEY_KP_Page_Down},
|
||||
{{KEY_KP_4, '4'}, XKB_KEY_KP_4},
|
||||
{{KEY_KP_4, '\0'}, XKB_KEY_KP_Left},
|
||||
{{KEY_KP_5, '5'}, XKB_KEY_KP_5},
|
||||
{{KEY_KP_5, '\0'}, XKB_KEY_KP_Begin},
|
||||
{{KEY_KP_6, '6'}, XKB_KEY_KP_6},
|
||||
{{KEY_KP_6, '\0'}, XKB_KEY_KP_Right},
|
||||
{{KEY_KP_7, '7'}, XKB_KEY_KP_7},
|
||||
{{KEY_KP_7, '\0'}, XKB_KEY_KP_Home},
|
||||
{{KEY_KP_8, '8'}, XKB_KEY_KP_8},
|
||||
{{KEY_KP_8, '\0'}, XKB_KEY_KP_Up},
|
||||
{{KEY_KP_9, '9'}, XKB_KEY_KP_9},
|
||||
{{KEY_KP_9, '\0'}, XKB_KEY_KP_Page_Up},
|
||||
{{KEY_KP_PERIOD, '.'}, XKB_KEY_KP_Decimal},
|
||||
{{KEY_KP_PERIOD, '\0'}, XKB_KEY_KP_Delete},
|
||||
{{KEY_KP_DIVIDE, '/'}, XKB_KEY_KP_Divide},
|
||||
{{KEY_KP_MULTIPLY, '*'}, XKB_KEY_KP_Multiply},
|
||||
{{KEY_KP_SUBTRACT, '-'}, XKB_KEY_KP_Subtract},
|
||||
{{KEY_KP_ADD, '+'}, XKB_KEY_KP_Add},
|
||||
{{KEY_KP_ENTER, '\0'}, XKB_KEY_KP_Enter},
|
||||
//{{ , }, XKB_KEY_KP_Equal},
|
||||
//{{ , }, XKB_KEY_KP_Separator},
|
||||
//{{ , }, XKB_KEY_KP_Tab},
|
||||
//{{ , }, XKB_KEY_KP_F1},
|
||||
//{{ , }, XKB_KEY_KP_F2},
|
||||
//{{ , }, XKB_KEY_KP_F3},
|
||||
//{{ , }, XKB_KEY_KP_F4},
|
||||
|
||||
// Godot scancodes do not distinguish between uppercase and lowercase
|
||||
// letters, so we can check the unicode value to determine this.
|
||||
{{KEY_A, 'a'}, XKB_KEY_a},
|
||||
{{KEY_A, 'A'}, XKB_KEY_A},
|
||||
{{KEY_B, 'b'}, XKB_KEY_b},
|
||||
{{KEY_B, 'B'}, XKB_KEY_B},
|
||||
{{KEY_C, 'c'}, XKB_KEY_c},
|
||||
{{KEY_C, 'C'}, XKB_KEY_C},
|
||||
{{KEY_D, 'd'}, XKB_KEY_d},
|
||||
{{KEY_D, 'D'}, XKB_KEY_D},
|
||||
{{KEY_E, 'e'}, XKB_KEY_e},
|
||||
{{KEY_E, 'E'}, XKB_KEY_E},
|
||||
{{KEY_F, 'f'}, XKB_KEY_f},
|
||||
{{KEY_F, 'F'}, XKB_KEY_F},
|
||||
{{KEY_G, 'g'}, XKB_KEY_g},
|
||||
{{KEY_G, 'G'}, XKB_KEY_G},
|
||||
{{KEY_H, 'h'}, XKB_KEY_h},
|
||||
{{KEY_H, 'H'}, XKB_KEY_H},
|
||||
{{KEY_I, 'i'}, XKB_KEY_i},
|
||||
{{KEY_I, 'I'}, XKB_KEY_I},
|
||||
{{KEY_J, 'j'}, XKB_KEY_j},
|
||||
{{KEY_J, 'J'}, XKB_KEY_J},
|
||||
{{KEY_K, 'k'}, XKB_KEY_k},
|
||||
{{KEY_K, 'K'}, XKB_KEY_K},
|
||||
{{KEY_L, 'l'}, XKB_KEY_l},
|
||||
{{KEY_L, 'L'}, XKB_KEY_L},
|
||||
{{KEY_M, 'm'}, XKB_KEY_m},
|
||||
{{KEY_M, 'M'}, XKB_KEY_M},
|
||||
{{KEY_N, 'n'}, XKB_KEY_n},
|
||||
{{KEY_N, 'N'}, XKB_KEY_N},
|
||||
{{KEY_O, 'o'}, XKB_KEY_o},
|
||||
{{KEY_O, 'O'}, XKB_KEY_O},
|
||||
{{KEY_P, 'p'}, XKB_KEY_p},
|
||||
{{KEY_P, 'P'}, XKB_KEY_P},
|
||||
{{KEY_Q, 'q'}, XKB_KEY_q},
|
||||
{{KEY_Q, 'Q'}, XKB_KEY_Q},
|
||||
{{KEY_R, 'r'}, XKB_KEY_r},
|
||||
{{KEY_R, 'R'}, XKB_KEY_R},
|
||||
{{KEY_S, 's'}, XKB_KEY_s},
|
||||
{{KEY_S, 'S'}, XKB_KEY_S},
|
||||
{{KEY_T, 't'}, XKB_KEY_t},
|
||||
{{KEY_T, 'T'}, XKB_KEY_T},
|
||||
{{KEY_U, 'u'}, XKB_KEY_u},
|
||||
{{KEY_U, 'U'}, XKB_KEY_U},
|
||||
{{KEY_V, 'v'}, XKB_KEY_v},
|
||||
{{KEY_V, 'V'}, XKB_KEY_V},
|
||||
{{KEY_W, 'w'}, XKB_KEY_w},
|
||||
{{KEY_W, 'W'}, XKB_KEY_W},
|
||||
{{KEY_X, 'x'}, XKB_KEY_x},
|
||||
{{KEY_X, 'X'}, XKB_KEY_X},
|
||||
{{KEY_Y, 'y'}, XKB_KEY_y},
|
||||
{{KEY_Y, 'Y'}, XKB_KEY_Y},
|
||||
{{KEY_Z, 'z'}, XKB_KEY_z},
|
||||
{{KEY_Z, 'Z'}, XKB_KEY_Z},
|
||||
|
||||
{{KEY_0, '0'}, XKB_KEY_0},
|
||||
{{KEY_1, '1'}, XKB_KEY_1},
|
||||
{{KEY_2, '2'}, XKB_KEY_2},
|
||||
{{KEY_3, '3'}, XKB_KEY_3},
|
||||
{{KEY_4, '4'}, XKB_KEY_4},
|
||||
{{KEY_5, '5'}, XKB_KEY_5},
|
||||
{{KEY_6, '6'}, XKB_KEY_6},
|
||||
{{KEY_7, '7'}, XKB_KEY_7},
|
||||
{{KEY_8, '8'}, XKB_KEY_8},
|
||||
{{KEY_9, '9'}, XKB_KEY_9},
|
||||
|
||||
{{KEY_BRACKETLEFT, '['}, XKB_KEY_bracketleft},
|
||||
{{KEY_BRACKETLEFT, ']'}, XKB_KEY_bracketright},
|
||||
{{KEY_BRACELEFT, '{'}, XKB_KEY_braceleft},
|
||||
{{KEY_BRACERIGHT, '}'}, XKB_KEY_braceright},
|
||||
|
||||
{{KEY_BACKSLASH, '\\'}, XKB_KEY_backslash},
|
||||
{{KEY_BAR, '|'}, XKB_KEY_bar},
|
||||
{{KEY_QUOTELEFT, '`'}, XKB_KEY_grave},
|
||||
{{KEY_ASCIITILDE, '~'}, XKB_KEY_asciitilde},
|
||||
{{KEY_SLASH, '/'}, XKB_KEY_slash},
|
||||
{{KEY_QUESTION, '?'}, XKB_KEY_question},
|
||||
|
||||
{{KEY_HOME, '\0'}, XKB_KEY_Home},
|
||||
{{KEY_BACKSPACE, '\0'}, XKB_KEY_BackSpace},
|
||||
{{KEY_BACKTAB, '\0'}, XKB_KEY_ISO_Left_Tab},
|
||||
{{KEY_CLEAR, '\0'}, XKB_KEY_Clear},
|
||||
{{KEY_PAUSE, '\0'}, XKB_KEY_Pause},
|
||||
{{KEY_SCROLLLOCK, '\0'}, XKB_KEY_Scroll_Lock},
|
||||
{{KEY_SYSREQ, '\0'}, XKB_KEY_Sys_Req},
|
||||
{{KEY_ESCAPE, '\0'}, XKB_KEY_Escape},
|
||||
{{KEY_ENTER, '\0'}, XKB_KEY_Return},
|
||||
{{KEY_INSERT, '\0'}, XKB_KEY_Insert},
|
||||
{{KEY_DELETE, '\0'}, XKB_KEY_Delete},
|
||||
{{KEY_PAGEUP, '\0'}, XKB_KEY_Page_Up},
|
||||
{{KEY_PAGEDOWN, '\0'}, XKB_KEY_Page_Down},
|
||||
{{KEY_UP, '\0'}, XKB_KEY_Up},
|
||||
{{KEY_DOWN, '\0'}, XKB_KEY_Down},
|
||||
{{KEY_RIGHT, '\0'}, XKB_KEY_Right},
|
||||
{{KEY_LEFT, '\0'}, XKB_KEY_Left},
|
||||
{{KEY_TAB, '\0'}, XKB_KEY_Tab},
|
||||
//{{ , }, XKB_KEY_Linefeed},
|
||||
//{{ , }, XKB_KEY_Find},
|
||||
//{{ , }, XKB_KEY_Select},
|
||||
|
||||
{{KEY_F1, '\0'}, XKB_KEY_F1},
|
||||
{{KEY_F2, '\0'}, XKB_KEY_F2},
|
||||
{{KEY_F3, '\0'}, XKB_KEY_F3},
|
||||
{{KEY_F4, '\0'}, XKB_KEY_F4},
|
||||
{{KEY_F5, '\0'}, XKB_KEY_F5},
|
||||
{{KEY_F6, '\0'}, XKB_KEY_F6},
|
||||
{{KEY_F7, '\0'}, XKB_KEY_F7},
|
||||
{{KEY_F8, '\0'}, XKB_KEY_F8},
|
||||
{{KEY_F9, '\0'}, XKB_KEY_F9},
|
||||
{{KEY_F10, '\0'}, XKB_KEY_F10},
|
||||
{{KEY_F11, '\0'}, XKB_KEY_F11},
|
||||
{{KEY_F12, '\0'}, XKB_KEY_F12},
|
||||
{{KEY_F13, '\0'}, XKB_KEY_F13},
|
||||
{{KEY_F14, '\0'}, XKB_KEY_F14},
|
||||
{{KEY_F15, '\0'}, XKB_KEY_F15},
|
||||
{{KEY_F16, '\0'}, XKB_KEY_F16},
|
||||
{{KEY_F17, '\0'}, XKB_KEY_F17},
|
||||
{{KEY_F18, '\0'}, XKB_KEY_F18},
|
||||
{{KEY_F19, '\0'}, XKB_KEY_F19},
|
||||
{{KEY_F20, '\0'}, XKB_KEY_F20},
|
||||
{{KEY_F21, '\0'}, XKB_KEY_F21},
|
||||
{{KEY_F22, '\0'}, XKB_KEY_F22},
|
||||
{{KEY_F23, '\0'}, XKB_KEY_F23},
|
||||
{{KEY_F24, '\0'}, XKB_KEY_F24},
|
||||
{{KEY_F25, '\0'}, XKB_KEY_F25},
|
||||
{{KEY_F26, '\0'}, XKB_KEY_F26},
|
||||
{{KEY_F27, '\0'}, XKB_KEY_F27},
|
||||
{{KEY_F28, '\0'}, XKB_KEY_F28},
|
||||
{{KEY_F29, '\0'}, XKB_KEY_F29},
|
||||
{{KEY_F30, '\0'}, XKB_KEY_F30},
|
||||
{{KEY_F31, '\0'}, XKB_KEY_F31},
|
||||
{{KEY_F32, '\0'}, XKB_KEY_F32},
|
||||
{{KEY_F33, '\0'}, XKB_KEY_F33},
|
||||
{{KEY_F34, '\0'}, XKB_KEY_F34},
|
||||
{{KEY_F35, '\0'}, XKB_KEY_F35},
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2021-2022 Leroy Hopson <godot-xterm@leroy.geek.nz>
|
||||
// SPDX-FileCopyrightText: 2021-2023 Leroy Hopson <godot-xterm@leroy.geek.nz>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "libuv_utils.h"
|
||||
|
@ -8,11 +8,15 @@
|
|||
using namespace godot;
|
||||
|
||||
void LibuvUtils::_bind_methods() {
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("get_os_environ"), &LibuvUtils::get_os_environ);
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("get_os_release"), &LibuvUtils::get_os_release);
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("get_cwd"), &LibuvUtils::get_cwd);
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("get_os_environ"),
|
||||
&LibuvUtils::get_os_environ);
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("get_os_release"),
|
||||
&LibuvUtils::get_os_release);
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("get_cwd"),
|
||||
&LibuvUtils::get_cwd);
|
||||
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("kill", "pid", "signum"), &LibuvUtils::kill);
|
||||
ClassDB::bind_static_method("LibuvUtils", D_METHOD("kill", "pid", "signum"),
|
||||
&LibuvUtils::kill);
|
||||
}
|
||||
|
||||
LibuvUtils::LibuvUtils() {}
|
||||
|
@ -108,14 +112,14 @@ Error LibuvUtils::translate_uv_errno(int uv_err) {
|
|||
case UV_ENOENT: // no such file or directory
|
||||
return ERR_FILE_NOT_FOUND;
|
||||
|
||||
case UV_EAI_BADFLAGS: // bad ai_flags value
|
||||
case UV_EAI_BADHINTS: // invalid value for hints
|
||||
case UV_EFAULT: // bad address in system call argument
|
||||
case UV_EFTYPE: // inappropriate file type or format
|
||||
case UV_EINVAL: // invalid argument
|
||||
case UV_ENOTTY: // inappropriate ioctl for device
|
||||
case UV_EPROTOTYPE: // protocol wrong type for socket
|
||||
return ERR_INVALID_PARAMETER; // Parameter passed is invalid
|
||||
case UV_EAI_BADFLAGS: // bad ai_flags value
|
||||
case UV_EAI_BADHINTS: // invalid value for hints
|
||||
case UV_EFAULT: // bad address in system call argument
|
||||
case UV_EFTYPE: // inappropriate file type or format
|
||||
case UV_EINVAL: // invalid argument
|
||||
case UV_ENOTTY: // inappropriate ioctl for device
|
||||
case UV_EPROTOTYPE: // protocol wrong type for socket
|
||||
return ERR_INVALID_PARAMETER; // Parameter passed is invalid
|
||||
|
||||
case UV_ENOSYS: // function not implemented
|
||||
return ERR_METHOD_NOT_FOUND;
|
||||
|
@ -123,12 +127,12 @@ Error LibuvUtils::translate_uv_errno(int uv_err) {
|
|||
case UV_EAI_MEMORY: // out of memory
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
|
||||
case UV_E2BIG: // argument list too long
|
||||
case UV_EFBIG: // file too large
|
||||
case UV_EMSGSIZE: // message too long
|
||||
case UV_ENAMETOOLONG: // name too long
|
||||
case UV_EOVERFLOW: // value too large for defined data type
|
||||
case UV_ERANGE: // result too large
|
||||
case UV_E2BIG: // argument list too long
|
||||
case UV_EFBIG: // file too large
|
||||
case UV_EMSGSIZE: // message too long
|
||||
case UV_ENAMETOOLONG: // name too long
|
||||
case UV_EOVERFLOW: // value too large for defined data type
|
||||
case UV_ERANGE: // result too large
|
||||
return ERR_PARAMETER_RANGE_ERROR; // Parameter given out of range
|
||||
|
||||
case UV_ETIMEDOUT:
|
||||
|
@ -139,19 +143,19 @@ Error LibuvUtils::translate_uv_errno(int uv_err) {
|
|||
case UV_EXDEV: // cross-device link not permitted
|
||||
return ERR_UNAUTHORIZED;
|
||||
|
||||
case UV_EADDRNOTAVAIL: // address not available
|
||||
case UV_EAFNOSUPPORT: // address family not supported
|
||||
case UV_EAGAIN: // resource temporarily unavailable
|
||||
case UV_EAI_ADDRFAMILY: // address family not supported
|
||||
case UV_EAI_FAMILY: // ai_family not supported
|
||||
case UV_EAI_SERVICE: // service not available for socket type
|
||||
case UV_EAI_SOCKTYPE: // socket type not supported
|
||||
case UV_ENOPROTOOPT: // protocol not available
|
||||
case UV_ENOTSUP: // operation not supported on socket
|
||||
case UV_EPROTONOSUPPORT: // protocol not supported
|
||||
case UV_ESOCKTNOSUPPORT: // socket type not supported
|
||||
return ERR_UNAVAILABLE; // What is requested is
|
||||
// unsupported/unavailable
|
||||
case UV_EADDRNOTAVAIL: // address not available
|
||||
case UV_EAFNOSUPPORT: // address family not supported
|
||||
case UV_EAGAIN: // resource temporarily unavailable
|
||||
case UV_EAI_ADDRFAMILY: // address family not supported
|
||||
case UV_EAI_FAMILY: // ai_family not supported
|
||||
case UV_EAI_SERVICE: // service not available for socket type
|
||||
case UV_EAI_SOCKTYPE: // socket type not supported
|
||||
case UV_ENOPROTOOPT: // protocol not available
|
||||
case UV_ENOTSUP: // operation not supported on socket
|
||||
case UV_EPROTONOSUPPORT: // protocol not supported
|
||||
case UV_ESOCKTNOSUPPORT: // socket type not supported
|
||||
return ERR_UNAVAILABLE; // What is requested is
|
||||
// unsupported/unavailable
|
||||
|
||||
case UV_EAI_NODATA: // no address
|
||||
case UV_EDESTADDRREQ: // destination address required
|
||||
|
@ -191,6 +195,6 @@ Error LibuvUtils::translate_uv_errno(int uv_err) {
|
|||
case UV_ESPIPE: // invalid seek
|
||||
case UV_UNKNOWN: // unknown error
|
||||
default:
|
||||
return FAILED; // Generic fail error
|
||||
return FAILED; // Generic fail error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
// Copyright (c) 2021, Leroy Hopson (MIT License).
|
||||
// SPDX-FileCopyrightText: 2021-2023 Leroy Hopson <godot-xterm@leroy.geek.nz>
|
||||
// SDPX-License-Identifier: MIT
|
||||
|
||||
#include "pipe.h"
|
||||
#include "libuv_utils.h"
|
||||
#include <godot_cpp/variant/dictionary.hpp>
|
||||
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/classes/input_event_key.hpp>
|
||||
#include <godot_cpp/classes/os.hpp>
|
||||
#include <godot_cpp/classes/resource_loader.hpp>
|
||||
#include <godot_cpp/classes/theme.hpp>
|
||||
#include <godot_cpp/classes/timer.hpp>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
#ifndef ULONG
|
||||
#define ULONG size_t
|
||||
|
@ -22,15 +11,16 @@
|
|||
using namespace godot;
|
||||
|
||||
void Pipe::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_init"), &Pipe::_init);
|
||||
ClassDB::bind_method(D_METHOD("_init"), &Pipe::_init);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("poll"), &Pipe::_poll_connection);
|
||||
ClassDB::bind_method(D_METHOD("open"), &Pipe::open);
|
||||
ClassDB::bind_method(D_METHOD("open", "fd", "ipc"), &Pipe::open);
|
||||
ClassDB::bind_method(D_METHOD("write"), &Pipe::write);
|
||||
ClassDB::bind_method(D_METHOD("get_status"), &Pipe::get_status);
|
||||
ClassDB::bind_method(D_METHOD("close"), &Pipe::close);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data")));
|
||||
ADD_SIGNAL(MethodInfo("data_received",
|
||||
PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data")));
|
||||
}
|
||||
|
||||
Pipe::Pipe() {}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright (c) 2022, Leroy Hopson (MIT License).
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
|
@ -25,9 +23,9 @@ using namespace godot;
|
|||
|
||||
void initialize_godot_xterm_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ClassDB::register_class<Terminal>();
|
||||
#if !defined(_PTY_DISABLED)
|
||||
ClassDB::register_class<Pipe>();
|
||||
|
@ -36,25 +34,30 @@ void initialize_godot_xterm_module(ModuleInitializationLevel p_level) {
|
|||
ClassDB::register_class<PTYUnix>();
|
||||
#endif
|
||||
#if defined(__WIN32)
|
||||
//ClassDB::register_class<ConPTY>();
|
||||
// ClassDB::register_class<ConPTY>();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void uninitialize_godot_xterm_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
// Initialization
|
||||
GDExtensionBool GDE_EXPORT godot_xterm_library_init(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||
godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
|
||||
// Initialization
|
||||
GDExtensionBool GDE_EXPORT
|
||||
godot_xterm_library_init(const GDExtensionInterface *p_interface,
|
||||
GDExtensionClassLibraryPtr p_library,
|
||||
GDExtensionInitialization *r_initialization) {
|
||||
godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library,
|
||||
r_initialization);
|
||||
|
||||
init_obj.register_initializer(initialize_godot_xterm_module);
|
||||
init_obj.register_terminator(uninitialize_godot_xterm_module);
|
||||
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||
init_obj.register_initializer(initialize_godot_xterm_module);
|
||||
init_obj.register_terminator(uninitialize_godot_xterm_module);
|
||||
init_obj.set_minimum_library_initialization_level(
|
||||
MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||
|
||||
return init_obj.init();
|
||||
return init_obj.init();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,93 +1,165 @@
|
|||
// SPDX-FileCopyrightText: 2021-2022 Leroy Hopson <godot-xterm@leroy.geek.nz>
|
||||
// SPDX-FileCopyrightText: 2021-2023 Leroy Hopson <godot-xterm@leroy.geek.nz>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef TERMINAL_H
|
||||
#define TERMINAL_H
|
||||
#ifndef GODOT_XTERM_TERMINAL_H
|
||||
#define GODOT_XTERM_TERMINAL_H
|
||||
|
||||
#include <godot_cpp/classes/control.hpp>
|
||||
#include <godot_cpp/classes/font.hpp>
|
||||
#include <godot_cpp/classes/input_event.hpp>
|
||||
#include <godot_cpp/classes/input_event_key.hpp>
|
||||
#include <godot_cpp/classes/input_event_mouse.hpp>
|
||||
#include <godot_cpp/classes/input_event_mouse_button.hpp>
|
||||
#include <godot_cpp/classes/sub_viewport.hpp>
|
||||
#include <godot_cpp/classes/texture_rect.hpp>
|
||||
#include <godot_cpp/classes/timer.hpp>
|
||||
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||
#include <libtsm.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace godot {
|
||||
using namespace godot;
|
||||
|
||||
class Terminal : public Control {
|
||||
GDCLASS(Terminal, Control)
|
||||
|
||||
public:
|
||||
Ref<InputEventKey> input_event_key;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
tsm_screen *screen;
|
||||
tsm_vte *vte;
|
||||
|
||||
private:
|
||||
static const uint8_t default_color_palette[TSM_COLOR_NUM][3];
|
||||
|
||||
static std::map<std::pair<int64_t, int64_t>, int> _key_list;
|
||||
static void _populate_key_list();
|
||||
static uint32_t mapkey(std::pair<int64_t, int64_t> key);
|
||||
|
||||
std::map<int, Color> palette = {};
|
||||
std::map<String, Ref<Font>> fontmap = {};
|
||||
|
||||
void update_size();
|
||||
void update_theme();
|
||||
|
||||
public:
|
||||
std::pair<Color, Color> get_cell_colors(const tsm_screen_attr *attr);
|
||||
void draw_background(int row, int col, Color bgcol, int width);
|
||||
void draw_foreground(int row, int col, char *ch, const tsm_screen_attr *attr,
|
||||
Color fgcol);
|
||||
|
||||
public:
|
||||
Terminal();
|
||||
~Terminal();
|
||||
|
||||
void _ready();
|
||||
void _notification(int what);
|
||||
void _gui_input(Variant event);
|
||||
void _draw();
|
||||
|
||||
void write(PackedByteArray data);
|
||||
|
||||
void sb_up(int num);
|
||||
void sb_down(int num);
|
||||
void sb_reset();
|
||||
void clear_sb();
|
||||
|
||||
void start_selection(Vector2 position);
|
||||
void select_to_pointer(Vector2 position);
|
||||
void reset_selection();
|
||||
String copy_selection();
|
||||
String copy_all();
|
||||
|
||||
enum UpdateMode {
|
||||
DISABLED,
|
||||
AUTO,
|
||||
ALL,
|
||||
ALL_NEXT_FRAME,
|
||||
};
|
||||
int update_mode = UpdateMode::AUTO;
|
||||
int get_update_mode();
|
||||
void set_update_mode(int update_mode);
|
||||
|
||||
static const UpdateMode UPDATE_MODE_DISABLED = UpdateMode::DISABLED;
|
||||
static const UpdateMode UPDATE_MODE_AUTO = UpdateMode::AUTO;
|
||||
static const UpdateMode UPDATE_MODE_ALL = UpdateMode::ALL;
|
||||
static const UpdateMode UPDATE_MODE_ALL_NEXT_FRAME =
|
||||
UpdateMode::ALL_NEXT_FRAME;
|
||||
|
||||
bool copy_on_selection = false;
|
||||
void set_copy_on_selection(bool value);
|
||||
bool get_copy_on_selection();
|
||||
|
||||
UpdateMode update_mode = UPDATE_MODE_AUTO;
|
||||
void set_update_mode(UpdateMode value);
|
||||
UpdateMode get_update_mode();
|
||||
|
||||
double bell_cooldown = 0.1f;
|
||||
void set_bell_cooldown(double value);
|
||||
double get_bell_cooldown();
|
||||
|
||||
bool bell_muted = false;
|
||||
void set_bell_muted(bool value);
|
||||
bool get_bell_muted();
|
||||
|
||||
bool blink_enabled = true;
|
||||
void set_blink_enabled(bool value);
|
||||
bool get_blink_enabled();
|
||||
|
||||
double blink_time_on = 0.6;
|
||||
void set_blink_time_on(double value);
|
||||
double get_blink_time_on();
|
||||
|
||||
double blink_time_off = 0.3;
|
||||
void set_blink_time_off(double value);
|
||||
double get_blink_time_off();
|
||||
|
||||
void clear();
|
||||
String copy_all();
|
||||
String copy_selection();
|
||||
int get_cols();
|
||||
int get_rows();
|
||||
void write(Variant data);
|
||||
|
||||
void _gui_input(Ref<InputEvent> event);
|
||||
void _notification(int what);
|
||||
|
||||
void _flush();
|
||||
void _on_back_buffer_draw();
|
||||
void _on_selection_held();
|
||||
void _toggle_blink();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
struct ColorDef {
|
||||
const char *default_color;
|
||||
tsm_vte_color tsm_color;
|
||||
};
|
||||
|
||||
struct ThemeCache {
|
||||
int font_size = 0;
|
||||
std::map<String, Ref<Font>> fonts = std::map<String, Ref<Font>>{};
|
||||
std::map<String, Color> colors = std::map<String, Color>{};
|
||||
} theme_cache;
|
||||
|
||||
typedef std::map<const char *, ColorDef> ColorMap;
|
||||
typedef std::pair<Color, Color> ColorPair;
|
||||
typedef std::map<const char *, const char *> FontMap;
|
||||
typedef std::map<std::pair<Key, char32_t>, uint32_t> KeyMap;
|
||||
|
||||
static const KeyMap KEY_MAP;
|
||||
static const ColorMap COLORS;
|
||||
static const FontMap FONTS;
|
||||
|
||||
enum SelectionMode { NONE, POINTER };
|
||||
|
||||
Control *back_buffer = new Control();
|
||||
SubViewport *sub_viewport = new SubViewport();
|
||||
TextureRect *front_buffer = new TextureRect();
|
||||
|
||||
Timer *bell_timer = new Timer();
|
||||
Timer *blink_timer = new Timer();
|
||||
Timer *selection_timer = new Timer();
|
||||
|
||||
tsm_screen *screen;
|
||||
tsm_vte *vte;
|
||||
|
||||
Array write_buffer = Array();
|
||||
|
||||
int cols = 80;
|
||||
int rows = 24;
|
||||
|
||||
// Whether blinking characters are visible. Not whether blinking is enabled
|
||||
// which is determined by `blink_enabled`.
|
||||
bool blink_on = true;
|
||||
|
||||
Vector2 cell_size = Vector2(0, 0);
|
||||
Vector2 get_cell_size();
|
||||
int rows = 24;
|
||||
int get_rows();
|
||||
int cols = 80;
|
||||
int get_cols();
|
||||
|
||||
uint8_t color_palette[TSM_COLOR_NUM][3];
|
||||
std::map<int, Color> palette = {};
|
||||
|
||||
tsm_age_t framebuffer_age;
|
||||
};
|
||||
} // namespace godot
|
||||
|
||||
#endif // TERMINAL_H
|
||||
Ref<InputEventKey> last_input_event_key;
|
||||
|
||||
bool selecting = false;
|
||||
SelectionMode selection_mode = SelectionMode::NONE;
|
||||
|
||||
static void _bell_cb(tsm_vte *vte, void *data);
|
||||
static int _text_draw_cb(tsm_screen *con, uint64_t id, const uint32_t *ch,
|
||||
size_t len, unsigned int width, unsigned int col,
|
||||
unsigned int row, const tsm_screen_attr *attr,
|
||||
tsm_age_t age, void *data);
|
||||
static void _write_cb(tsm_vte *vte, const char *u8, size_t len, void *data);
|
||||
|
||||
void _draw_background(int row, int col, Color bgcol, int width);
|
||||
void _draw_foreground(int row, int col, char *ch, const tsm_screen_attr *attr,
|
||||
Color fgcol);
|
||||
ColorPair _get_cell_colors(const tsm_screen_attr *attr);
|
||||
|
||||
void _handle_key_input(Ref<InputEventKey> event);
|
||||
void _handle_mouse_wheel(Ref<InputEventMouseButton> event);
|
||||
void _handle_selection(Ref<InputEventMouse> event);
|
||||
void _recalculate_size();
|
||||
void _refresh();
|
||||
void _update_theme_item_cache();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Terminal, UpdateMode);
|
||||
|
||||
#endif // GODOT_XTERM_TERMINAL_H
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
# Copyright (c) 2021, Leroy Hopson (MIT License)
|
||||
|
||||
@tool
|
||||
extends Object
|
||||
# Wrapper around libuv utility functions.
|
||||
# GDNative does not currently support registering static functions so we fake it.
|
||||
# Only the static functions of this class should be called.
|
||||
|
||||
|
||||
static func get_os_environ() -> Dictionary:
|
||||
# While Godot has OS.get_environment(), I could see a way to get all environent
|
||||
# variables, other than by OS.execute() which would require to much platform
|
||||
# specific code. Easier to use libuv's utility function.
|
||||
return LibuvUtils.get_os_environ()
|
||||
|
||||
|
||||
static func get_cwd() -> String:
|
||||
# Use uv_cwd() rather than Directory.get_current_dir() because the latter
|
||||
# defaults to res:// even if starting godot from a different directory.
|
||||
return LibuvUtils.new().get_cwd()
|
||||
|
||||
|
||||
static func get_windows_build_number() -> int:
|
||||
assert(OS.get_name() == "Windows") #,"This function is only supported checked Windows.")
|
||||
var release: String = LibuvUtils.new().get_os_release()
|
||||
assert(false) #,"Not implemented.")
|
||||
return 0
|
||||
|
||||
|
||||
static func kill(pid: int, signum: int):
|
||||
if pid > 1:
|
||||
return LibuvUtils.new().kill(pid, signum)
|
||||
|
||||
|
||||
static func new():
|
||||
assert(false) #,"Abstract sealed (i.e. static) class should not be instantiated.")
|
|
@ -64,7 +64,10 @@ var _exit_cb: Callable
|
|||
# Writes data to the socket.
|
||||
# data: The data to write.
|
||||
func write(data) -> void:
|
||||
assert(data is PackedByteArray or data is String, "Invalid type for argument 'data'. Should be of type PackedByteArray or String")
|
||||
var correct_type: bool = data is PackedByteArray or data is String
|
||||
var err_message := "Invalid type for argument 'data'. Should be of type PackedByteArray or String"
|
||||
assert(correct_type, err_message)
|
||||
|
||||
if _pipe:
|
||||
_pipe.write(data if data is PackedByteArray else data.to_utf8_buffer())
|
||||
|
||||
|
@ -88,7 +91,7 @@ func _parse_env(env: Dictionary = {}) -> PackedStringArray:
|
|||
for key in keys:
|
||||
var value = env[key]
|
||||
var valid = key is String and value is String
|
||||
assert(valid) #,"Env key/value pairs must be of type String/String.")
|
||||
assert(valid) #,"Env key/value pairs must be of type String/String.")
|
||||
|
||||
if not valid:
|
||||
push_warning("Skipping invalid env key/value pair.")
|
||||
|
@ -129,9 +132,23 @@ func fork(
|
|||
_exit_cb = Callable(self, "on_exit")
|
||||
|
||||
# Actual fork.
|
||||
var result = PTYUnix.new().fork(
|
||||
# VERY IMPORTANT: The second argument must be 0, otherwise will get an ENOTSOCK error after connecting our pipe to the fd.
|
||||
file, 0, args, parsed_env, cwd, cols, rows, uid, gid, utf8, _exit_cb
|
||||
var result = (
|
||||
PTYUnix
|
||||
. new()
|
||||
. fork(
|
||||
# VERY IMPORTANT: The second argument must be 0, otherwise will get an ENOTSOCK error after connecting our pipe to the fd.
|
||||
file,
|
||||
0,
|
||||
args,
|
||||
parsed_env,
|
||||
cwd,
|
||||
cols,
|
||||
rows,
|
||||
uid,
|
||||
gid,
|
||||
utf8,
|
||||
_exit_cb
|
||||
)
|
||||
)
|
||||
|
||||
if result[0] != OK:
|
||||
|
@ -146,10 +163,10 @@ func fork(
|
|||
_pid = result[1].pid
|
||||
|
||||
_pipe = Pipe.new()
|
||||
_pipe.open(_fd, true) # FIXME: _pipe.open(_fd) should be sufficient but requires two args.
|
||||
_pipe.open(_fd, false)
|
||||
|
||||
# Must connect to signal AFTER opening, otherwise we will get error ENOTSOCK.
|
||||
_pipe.connect("data_received",Callable(self,"_on_pipe_data_received"))
|
||||
_pipe.connect("data_received", Callable(self, "_on_pipe_data_received"))
|
||||
|
||||
return OK
|
||||
|
||||
|
@ -159,7 +176,7 @@ func open(cols: int = DEFAULT_COLS, rows: int = DEFAULT_ROWS) -> Array:
|
|||
|
||||
|
||||
func _exit_tree():
|
||||
_exit_cb = null
|
||||
_exit_cb = Callable()
|
||||
if _pid > 1:
|
||||
LibuvUtils.kill(_pid, IPCSignal.SIGHUP)
|
||||
if _pipe:
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
@tool
|
||||
extends SubViewport
|
|
@ -1,23 +0,0 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://c62updkby54f3"]
|
||||
|
||||
[sub_resource type="GDScript" id="GDScript_d8lvm"]
|
||||
script/source = "@tool
|
||||
extends SubViewport
|
||||
"
|
||||
|
||||
[node name="SubViewport" type="SubViewport"]
|
||||
transparent_bg = true
|
||||
handle_input_locally = false
|
||||
gui_snap_controls_to_pixels = false
|
||||
size = Vector2i(2, 2)
|
||||
render_target_clear_mode = 1
|
||||
script = SubResource("GDScript_d8lvm")
|
||||
|
||||
[node name="Terminal" type="Terminal" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = -2.0
|
||||
offset_bottom = -2.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
|
@ -1,7 +1,7 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
var pty_supported := OS.get_name() in ["X11", "Server", "OSX"]
|
||||
var pty_supported := OS.get_name() in ["Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD", "macOS"]
|
||||
var asciicast_import_plugin
|
||||
var xrdb_import_plugin
|
||||
var terminal_panel: Control
|
||||
|
@ -17,18 +17,16 @@ func _enter_tree():
|
|||
var asciicast_script = preload("./resources/asciicast.gd")
|
||||
add_custom_type("Asciicast", "Animation", asciicast_script, null)
|
||||
|
||||
var terminal_script = preload("./terminal.gd")
|
||||
var terminal_icon = load(
|
||||
"%s/nodes/terminal/terminal_icon.svg" % get_script().resource_path.get_base_dir()
|
||||
)
|
||||
add_custom_type("Terminal", "Control", terminal_script, terminal_icon)
|
||||
|
||||
if pty_supported:
|
||||
var base_dir = get_script().resource_path.get_base_dir()
|
||||
var pty_icon = load("%s/nodes/pty/pty_icon.svg" % base_dir)
|
||||
var pty_script
|
||||
match OS.get_name():
|
||||
"X11", "Server", "OSX":
|
||||
"Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD", "macOS":
|
||||
pty_script = load("%s/pty.gd" % base_dir)
|
||||
add_custom_type("PTY", "Node", pty_script, pty_icon)
|
||||
terminal_panel = preload("./editor_plugins/terminal/terminal_panel.tscn").instantiate()
|
||||
|
@ -45,7 +43,6 @@ func _exit_tree():
|
|||
xrdb_import_plugin = null
|
||||
|
||||
remove_custom_type("Asciicast")
|
||||
remove_custom_type("Terminal")
|
||||
|
||||
if pty_supported:
|
||||
remove_custom_type("PTY")
|
||||
|
|
|
@ -6,10 +6,9 @@
|
|||
@tool
|
||||
extends Node
|
||||
|
||||
const _LibuvUtils := preload("./nodes/pty/libuv_utils.gd")
|
||||
var _LibuvUtils := LibuvUtils
|
||||
const _PTYNative := preload("./nodes/pty/pty_native.gd")
|
||||
const _PTYUnix := preload("./nodes/pty/unix/pty_unix.gd")
|
||||
const _Terminal := preload("./terminal.gd")
|
||||
|
||||
const DEFAULT_NAME := "xterm-256color"
|
||||
const DEFAULT_COLS := 80
|
||||
|
@ -23,30 +22,26 @@ const IPCSignal = _PTYUnix.IPCSignal
|
|||
signal data_received(data)
|
||||
signal exited(exit_code, signum)
|
||||
|
||||
@export var terminal_path: NodePath = NodePath() :
|
||||
@export var terminal_path: NodePath = NodePath():
|
||||
get:
|
||||
return terminal_path
|
||||
set(value):
|
||||
terminal_path = value
|
||||
_set_terminal(get_node_or_null(terminal_path))
|
||||
|
||||
var _terminal: _Terminal = null :
|
||||
get:
|
||||
return _terminal # TODOConverter40 Non existent get function
|
||||
set(mod_value):
|
||||
mod_value # TODOConverter40 Copy here content of _set_terminal
|
||||
var _terminal
|
||||
|
||||
# The column size in characters.
|
||||
@export var cols: int = DEFAULT_COLS :
|
||||
@export var cols: int = DEFAULT_COLS:
|
||||
get:
|
||||
return cols # TODOConverter40 Copy here content of get_cols
|
||||
return cols # TODOConverter40 Copy here content of get_cols
|
||||
set(mod_value):
|
||||
mod_value # TODOConverter40 Copy here content of set_cols
|
||||
|
||||
# The row size in characters.
|
||||
@export var rows: int = DEFAULT_ROWS :
|
||||
@export var rows: int = DEFAULT_ROWS:
|
||||
get:
|
||||
return rows # TODOConverter40 Copy here content of get_rows
|
||||
return rows # TODOConverter40 Copy here content of get_rows
|
||||
set(mod_value):
|
||||
mod_value # TODOConverter40 Copy here content of set_rows
|
||||
|
||||
|
@ -66,13 +61,13 @@ var _pty_native: _PTYNative
|
|||
func _init():
|
||||
var os_name := OS.get_name()
|
||||
match os_name:
|
||||
"X11", "Server", "OSX":
|
||||
"Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD", "macOS":
|
||||
_pty_native = _PTYUnix.new()
|
||||
_:
|
||||
push_error("PTY is not support on current platform (%s)." % os_name)
|
||||
push_error("PTY is not supported on the current platform (%s)." % os_name)
|
||||
|
||||
_pty_native.connect("data_received",Callable(self,"_on_pty_native_data_received"))
|
||||
_pty_native.connect("exited",Callable(self,"_on_pty_native_exited"))
|
||||
_pty_native.connect("data_received", Callable(self, "_on_pty_native_data_received"))
|
||||
_pty_native.connect("exited", Callable(self, "_on_pty_native_exited"))
|
||||
|
||||
add_child(_pty_native)
|
||||
|
||||
|
@ -96,31 +91,31 @@ func set_rows(value: int):
|
|||
|
||||
func get_rows() -> int:
|
||||
return _rows
|
||||
|
||||
|
||||
func _set_terminal(value: _Terminal):
|
||||
|
||||
func _set_terminal(value):
|
||||
if _terminal == value:
|
||||
return
|
||||
|
||||
# Disconect the current terminal, if any.
|
||||
if _terminal:
|
||||
disconnect("data_received",Callable(_terminal,"write"))
|
||||
_terminal.disconnect("data_sent",Callable(self,"write"))
|
||||
_terminal.disconnect("size_changed",Callable(self,"resizev"))
|
||||
if _terminal != null:
|
||||
disconnect("data_received", Callable(_terminal, "write"))
|
||||
_terminal.disconnect("data_sent", Callable(self, "write"))
|
||||
_terminal.disconnect("size_changed", Callable(self, "resizev"))
|
||||
|
||||
_terminal = value
|
||||
|
||||
if not _terminal:
|
||||
if _terminal == null:
|
||||
return
|
||||
|
||||
# Connect the new terminal.
|
||||
resize(_terminal.get_cols(), _terminal.get_rows())
|
||||
if not _terminal.is_connected("size_changed",Callable(self,"resizev")):
|
||||
_terminal.connect("size_changed",Callable(self,"resizev"))
|
||||
if not _terminal.is_connected("data_sent",Callable(self,"write")):
|
||||
_terminal.connect("data_sent",Callable(self,"write"))
|
||||
if not is_connected("data_received",Callable(_terminal,"write")):
|
||||
connect("data_received",Callable(_terminal,"write"))
|
||||
if not _terminal.is_connected("size_changed", Callable(self, "resizev")):
|
||||
_terminal.connect("size_changed", Callable(self, "resizev"))
|
||||
if not _terminal.is_connected("data_sent", Callable(self, "write")):
|
||||
_terminal.connect("data_sent", Callable(self, "write"))
|
||||
if not is_connected("data_received", Callable(_terminal, "write")):
|
||||
connect("data_received", Callable(_terminal, "write"))
|
||||
|
||||
|
||||
# Writes data to the socket.
|
||||
|
@ -159,7 +154,7 @@ func _notification(what: int):
|
|||
match what:
|
||||
NOTIFICATION_PARENTED:
|
||||
var parent = get_parent()
|
||||
if parent is _Terminal:
|
||||
if parent is Terminal:
|
||||
self.terminal_path = get_path_to(parent)
|
||||
|
||||
|
||||
|
|
|
@ -1,291 +0,0 @@
|
|||
# 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).
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
signal data_sent(data)
|
||||
signal key_pressed(data, event)
|
||||
signal size_changed(new_size)
|
||||
signal bell
|
||||
|
||||
enum UpdateMode {
|
||||
DISABLED,
|
||||
AUTO,
|
||||
ALL,
|
||||
ALL_NEXT_FRAME,
|
||||
}
|
||||
|
||||
enum SelectionMode {
|
||||
NONE,
|
||||
POINTER,
|
||||
}
|
||||
|
||||
@export var update_mode: UpdateMode = UpdateMode.AUTO :
|
||||
get:
|
||||
return update_mode # TODOConverter40 Non existent get function
|
||||
set(p_update_mode):
|
||||
set_update_mode(p_update_mode)
|
||||
|
||||
# If true, text in the terminal will be copied to the clipboard when selected.
|
||||
@export var copy_on_selection: bool
|
||||
|
||||
# Bell
|
||||
# If muted, the "bell" signal will not be emitted when the bell "\u0007" character
|
||||
# is written to the terminal.
|
||||
@export var bell_muted := false
|
||||
# Amount of time in seconds that must pass before emitting a new "bell" signal.
|
||||
# This can be useful in cases where the bell character is being written too
|
||||
# frequently such as `while true; do echo -e "\a"; done`.
|
||||
@export var bell_cooldown: float = 0.1
|
||||
|
||||
@export var blink_on_time: float = 0.6
|
||||
@export var blink_off_time: float = 0.3
|
||||
|
||||
var _cols := 2
|
||||
var _rows := 2
|
||||
|
||||
var _default_theme: Theme = preload("./themes/default.tres")
|
||||
var _viewport: SubViewport = preload("./nodes/terminal/viewport.tscn").instantiate()
|
||||
var _native_terminal: Control = _viewport.get_node("Terminal")
|
||||
var _screen := TextureRect.new()
|
||||
|
||||
var _bell_timer := Timer.new()
|
||||
|
||||
var _selecting := false
|
||||
var _selecting_mode: int = SelectionMode.NONE
|
||||
var _selection_timer := Timer.new()
|
||||
|
||||
var _buffer := []
|
||||
|
||||
|
||||
func set_update_mode(value):
|
||||
update_mode = value
|
||||
_native_terminal.update_mode = value
|
||||
|
||||
|
||||
func get_cols() -> int:
|
||||
return _cols
|
||||
|
||||
|
||||
func get_rows() -> int:
|
||||
return _rows
|
||||
|
||||
|
||||
func write(data) -> void:
|
||||
# "Invalid type for argument 'data'. Should be of type PackedByteArray or String."
|
||||
assert(data is PackedByteArray or data is String)
|
||||
|
||||
# Will be cleared when _flush() is called after RenderingServer emits the "frame_pre_draw" signal.
|
||||
_buffer.push_back(data)
|
||||
|
||||
# Ensure redraw is requested if terminal is visible.
|
||||
if visible:
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _flush():
|
||||
for data in _buffer:
|
||||
_native_terminal.write(data if data is PackedByteArray else data.to_utf8_buffer())
|
||||
_native_terminal.queue_redraw()
|
||||
_buffer.clear()
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
var initial_size = _native_terminal.size
|
||||
_native_terminal.size.y = _native_terminal.cell_size.y
|
||||
_native_terminal.clear_sb()
|
||||
_native_terminal.size = initial_size
|
||||
|
||||
|
||||
func copy_selection() -> String:
|
||||
return _native_terminal.copy_selection()
|
||||
|
||||
|
||||
func copy_all() -> String:
|
||||
return _native_terminal.copy_all()
|
||||
|
||||
|
||||
func _ready():
|
||||
_update_theme()
|
||||
|
||||
_native_terminal.update_mode = update_mode
|
||||
_native_terminal.connect("data_sent",Callable(self,"_on_data_sent"))
|
||||
_native_terminal.connect("key_pressed",Callable(self,"_on_key_pressed"))
|
||||
_native_terminal.connect("size_changed",Callable(self,"_on_size_changed"))
|
||||
|
||||
_viewport.size = size
|
||||
_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||||
|
||||
_screen.set_anchors_preset(PRESET_VCENTER_WIDE)
|
||||
_screen.texture = _viewport.get_texture()
|
||||
|
||||
_native_terminal.connect("bell",Callable(self,"_on_bell"))
|
||||
_bell_timer.one_shot = true
|
||||
add_child(_bell_timer)
|
||||
|
||||
_selection_timer.wait_time = 0.05
|
||||
_selection_timer.connect("timeout",Callable(self,"_on_selection_held"))
|
||||
|
||||
add_child(_viewport)
|
||||
add_child(_screen)
|
||||
add_child(_selection_timer)
|
||||
|
||||
_refresh()
|
||||
|
||||
# Ensure the terminal state machine's framebuffer is up to date before
|
||||
# we make all the draw_* calls caused by writing. We need to use signals
|
||||
# here rather than yield otherwise we will sometimes get a "Resumed
|
||||
# function after yield but class instance is gone" error.
|
||||
RenderingServer.connect("frame_pre_draw",Callable(self,"_flush"))
|
||||
|
||||
|
||||
func _update_theme():
|
||||
# Themes are not propagated through the SubViewport, so in order for theme
|
||||
# inheritance to work we can pass through the theme variables manually.
|
||||
for color in _default_theme.get_color_list("Terminal"):
|
||||
var c: Color
|
||||
if has_theme_color(color, "Terminal"):
|
||||
c = get_theme_color(color, "Terminal")
|
||||
else:
|
||||
c = _default_theme.get_color(color, "Terminal")
|
||||
_native_terminal.add_theme_color_override(color, c)
|
||||
for font in _default_theme.get_font_list("Terminal"):
|
||||
var f: Font
|
||||
if has_theme_font(font, "Terminal"):
|
||||
f = get_theme_font(font, "Terminal")
|
||||
elif has_theme_font("regular", "Terminal"):
|
||||
f = get_theme_font("regular", "Terminal")
|
||||
else:
|
||||
if _default_theme.has_theme_font(font, "Terminal"):
|
||||
f = _default_theme.get_font(font, "Terminal")
|
||||
else:
|
||||
f = _default_theme.get_font(font, "regular")
|
||||
_native_terminal.add_theme_font_override(font, f)
|
||||
_native_terminal._update_theme()
|
||||
_native_terminal._update_size()
|
||||
|
||||
|
||||
func _refresh():
|
||||
_screen.queue_redraw()
|
||||
if update_mode == UpdateMode.AUTO:
|
||||
_native_terminal.update_mode = UpdateMode.ALL_NEXT_FRAME
|
||||
|
||||
|
||||
func _gui_input(event):
|
||||
_native_terminal.__gui_input(event) # FIXME: use _gui_input rather than __gui_input.
|
||||
|
||||
if event is InputEventKey and event.pressed:
|
||||
# Return to bottom of scrollback buffer if we scrolled up. Ignore modifier
|
||||
# keys pressed in isolation or if Ctrl+Shift modifier keys are pressed.
|
||||
if (
|
||||
not event.keycode in [KEY_ALT, KEY_SHIFT, KEY_CTRL, KEY_META, KEY_MASK_CMD_OR_CTRL]
|
||||
and not (event.ctrl_pressed and event.shift_pressed)
|
||||
):
|
||||
_native_terminal.sb_reset()
|
||||
|
||||
# Prevent focus changing to other inputs when pressing Tab or Arrow keys.
|
||||
if event.keycode in [KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN, KEY_TAB]:
|
||||
accept_event()
|
||||
|
||||
# FIXME
|
||||
#_handle_mouse_wheel(event)
|
||||
#_handle_selection(event)
|
||||
|
||||
|
||||
func _handle_mouse_wheel(event: InputEventMouseButton):
|
||||
if not event or not event.is_pressed():
|
||||
return
|
||||
|
||||
if event.button_index == MOUSE_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 == MOUSE_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)
|
||||
|
||||
|
||||
func _handle_selection(event: InputEventMouse):
|
||||
if event is InputEventMouseButton:
|
||||
if not event or not event.is_pressed() or not event.button_index == MOUSE_BUTTON_LEFT:
|
||||
return
|
||||
|
||||
if _selecting:
|
||||
_selecting = false
|
||||
_selecting_mode = SelectionMode.NONE
|
||||
_native_terminal.reset_selection()
|
||||
|
||||
# Single-click select pointer.
|
||||
_selecting = false
|
||||
_selecting_mode = SelectionMode.POINTER
|
||||
|
||||
elif event is InputEventMouseMotion:
|
||||
if (
|
||||
event.button_mask & MOUSE_BUTTON_MASK_LEFT
|
||||
and _selecting_mode != SelectionMode.NONE
|
||||
and not _selecting
|
||||
):
|
||||
_selecting = true
|
||||
_native_terminal.start_selection(_mouse_to_cell(event.position))
|
||||
_selection_timer.start()
|
||||
|
||||
|
||||
func _on_selection_held() -> void:
|
||||
if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) or _selecting_mode == SelectionMode.NONE:
|
||||
if copy_on_selection:
|
||||
var selection = _native_terminal.copy_selection()
|
||||
# TODO:godot4
|
||||
# OS.set_clipboard(selection)
|
||||
_selection_timer.stop()
|
||||
return
|
||||
|
||||
var position: Vector2 = _mouse_to_cell(get_local_mouse_position())
|
||||
_native_terminal.select_to_pointer(position)
|
||||
_selection_timer.start()
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
match what:
|
||||
NOTIFICATION_RESIZED:
|
||||
_viewport.size = size
|
||||
_refresh()
|
||||
NOTIFICATION_THEME_CHANGED:
|
||||
_update_theme()
|
||||
_refresh()
|
||||
|
||||
|
||||
func _on_data_sent(data: PackedByteArray):
|
||||
emit_signal("data_sent", data)
|
||||
|
||||
|
||||
func _on_key_pressed(data: PackedByteArray, event: InputEventKey):
|
||||
emit_signal("key_pressed", data.get_string_from_utf8(), event)
|
||||
|
||||
|
||||
func _on_size_changed(new_size: Vector2):
|
||||
_cols = new_size.x
|
||||
_rows = new_size.y
|
||||
emit_signal("size_changed", new_size)
|
||||
|
||||
|
||||
func _on_bell():
|
||||
if not bell_muted and (bell_cooldown == 0 or _bell_timer.time_left == 0):
|
||||
emit_signal("bell")
|
||||
if bell_cooldown > 0:
|
||||
_bell_timer.start(bell_cooldown)
|
||||
|
||||
|
||||
func _mouse_to_cell(pos: Vector2) -> Vector2:
|
||||
return Vector2(pos / _native_terminal.cell_size)
|
|
@ -1,8 +1,23 @@
|
|||
[gd_resource type="FontFile" load_steps=2 format=2]
|
||||
[gd_resource type="FontFile" load_steps=2 format=3 uid="uid://dhmyegcx24dpo"]
|
||||
|
||||
[ext_resource path="res://addons/godot_xterm/themes/fonts/hack/hack_regular-3.003.ttf" type="FontFile" id=4]
|
||||
[ext_resource type="FontFile" uid="uid://edo5q2qxos3u" path="res://addons/godot_xterm/themes/fonts/hack/hack_regular-3.003.ttf" id="4"]
|
||||
|
||||
[resource]
|
||||
size = 14
|
||||
extra_spacing_bottom = 1
|
||||
font_data = ExtResource( 4 )
|
||||
fallbacks = [ExtResource("4")]
|
||||
face_index = null
|
||||
embolden = null
|
||||
transform = null
|
||||
cache/0/16/0/ascent = 0.0
|
||||
cache/0/16/0/descent = 0.0
|
||||
cache/0/16/0/underline_position = 0.0
|
||||
cache/0/16/0/underline_thickness = 0.0
|
||||
cache/0/16/0/scale = 1.0
|
||||
cache/0/16/0/kerning_overrides/16/0 = Vector2(0, 0)
|
||||
cache/0/16/0/kerning_overrides/14/0 = Vector2(0, 0)
|
||||
cache/0/14/0/ascent = 0.0
|
||||
cache/0/14/0/descent = 0.0
|
||||
cache/0/14/0/underline_position = 0.0
|
||||
cache/0/14/0/underline_thickness = 0.0
|
||||
cache/0/14/0/scale = 1.0
|
||||
cache/0/14/0/kerning_overrides/16/0 = Vector2(0, 0)
|
||||
cache/0/14/0/kerning_overrides/14/0 = Vector2(0, 0)
|
||||
|
|
|
@ -1,19 +1,26 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://did1ipako11pd"]
|
||||
|
||||
[ext_resource path="res://addons/godot_xterm/terminal.gd" type="Script" id=1]
|
||||
[ext_resource path="res://examples/asciicast/example.cast" type="Animation" id=6]
|
||||
[ext_resource type="Theme" uid="uid://b7vd50tw2g1nl" path="res://themes/default.tres" id="1_nsh8i"]
|
||||
[ext_resource type="Animation" uid="uid://dcgqvylq0648u" path="res://examples/asciicast/example.cast" id="2_3048a"]
|
||||
|
||||
[node name="Terminal" type="Control"]
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_02l7k"]
|
||||
_data = {
|
||||
"example": ExtResource("2_3048a")
|
||||
}
|
||||
|
||||
[node name="Terminal" type="Terminal"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
focus_mode = 1
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
theme = ExtResource("1_nsh8i")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
autoplay = "example"
|
||||
playback_speed = 2.0
|
||||
method_call_mode = 1
|
||||
anims/example = ExtResource( 6 )
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_02l7k")
|
||||
}
|
||||
|
|
|
@ -42,11 +42,11 @@ var offset: int
|
|||
|
||||
|
||||
func _ready():
|
||||
if not $Terminal.is_connected("key_pressed",Callable(self,"_on_Terminal_key_pressed")):
|
||||
if not $Terminal.is_connected("key_pressed", Callable(self, "_on_Terminal_key_pressed")):
|
||||
# warning-ignore:return_value_discarded
|
||||
$Terminal.connect("key_pressed",Callable(self,"_on_Terminal_key_pressed"))
|
||||
$Terminal.connect("key_pressed", Callable(self, "_on_Terminal_key_pressed"))
|
||||
# warning-ignore:return_value_discarded
|
||||
$Terminal.connect("size_changed",Callable(self,"draw_all"))
|
||||
$Terminal.connect("size_changed", Callable(self, "draw_all"))
|
||||
$Terminal.grab_focus()
|
||||
draw_all()
|
||||
|
||||
|
@ -134,7 +134,10 @@ func _on_Terminal_key_pressed(data: String, event: InputEventKey) -> void:
|
|||
"Asciicast":
|
||||
var scene = item.scene.instantiate()
|
||||
var animation_player: AnimationPlayer = scene.get_node("AnimationPlayer")
|
||||
scene.connect("key_pressed",Callable(self,"_on_Asciicast_key_pressed").bind(animation_player))
|
||||
scene.connect(
|
||||
"key_pressed",
|
||||
Callable(self, "_on_Asciicast_key_pressed").bind(animation_player)
|
||||
)
|
||||
add_child(scene)
|
||||
scene.grab_focus()
|
||||
await animation_player.animation_finished
|
||||
|
@ -163,7 +166,7 @@ func _on_Terminal_key_pressed(data: String, event: InputEventKey) -> void:
|
|||
pass
|
||||
# FIXME
|
||||
#if OS.has_feature("JavaScript"):
|
||||
#JavaScript.eval("window.history.back() || window.close()")
|
||||
#JavaScript.eval("window.history.back() || window.close()")
|
||||
#get_tree().quit()
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://brjrtf5fpptw8"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot_xterm/terminal.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://examples/menu/menu.gd" id="2"]
|
||||
[ext_resource type="Theme" uid="uid://b7vd50tw2g1nl" path="res://themes/default.tres" id="2_o1653"]
|
||||
|
||||
[node name="Menu" type="Control"]
|
||||
layout_mode = 3
|
||||
|
@ -12,13 +12,11 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
script = ExtResource("2")
|
||||
|
||||
[node name="Terminal" type="Control" parent="."]
|
||||
[node name="Terminal" type="Terminal" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
focus_mode = 1
|
||||
script = ExtResource("1")
|
||||
copy_on_selection = false
|
||||
theme = ExtResource("2_o1653")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
[gd_scene load_steps=6 format=2]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://ddebdj001o1m5"]
|
||||
|
||||
[ext_resource path="res://examples/menu/menu.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://themes/retro_green.tres" type="Theme" id=2]
|
||||
[ext_resource type="PackedScene" uid="uid://brjrtf5fpptw8" path="res://examples/menu/menu.tscn" id="1"]
|
||||
[ext_resource type="Theme" uid="uid://blh56m1gdieyu" path="res://themes/retro_green.tres" id="2"]
|
||||
|
||||
[sub_resource type="Shader" id=1]
|
||||
[sub_resource type="Shader" id="1"]
|
||||
code = "/*
|
||||
Shader from Godot Shaders - the free shader library.
|
||||
godotshaders.com/shader/VHS-and-CRT-monitor-effect
|
||||
|
@ -234,31 +234,31 @@ void fragment()
|
|||
COLOR = text;
|
||||
}"
|
||||
|
||||
[sub_resource type="ShaderMaterial" id=2]
|
||||
shader = SubResource( 1 )
|
||||
shader_param/overlay = true
|
||||
shader_param/scanlines_opacity = 0.4
|
||||
shader_param/scanlines_width = 0.25
|
||||
shader_param/grille_opacity = 0.3
|
||||
shader_param/resolution = Vector2( 768, 240 )
|
||||
shader_param/pixelate = false
|
||||
shader_param/roll = true
|
||||
shader_param/roll_speed = 8.0
|
||||
shader_param/roll_size = 15.0
|
||||
shader_param/roll_variation = 1.8
|
||||
shader_param/distort_intensity = 0.05
|
||||
shader_param/noise_opacity = 0.4
|
||||
shader_param/noise_speed = 5.0
|
||||
shader_param/static_noise_intensity = 0.06
|
||||
shader_param/aberration = 0.0
|
||||
shader_param/brightness = 2.5
|
||||
shader_param/discolor = true
|
||||
shader_param/warp_amount = 1.0
|
||||
shader_param/clip_warp = false
|
||||
shader_param/vignette_intensity = 0.4
|
||||
shader_param/vignette_opacity = 0.5
|
||||
[sub_resource type="ShaderMaterial" id="2"]
|
||||
shader = SubResource("1")
|
||||
shader_parameter/overlay = true
|
||||
shader_parameter/scanlines_opacity = 0.4
|
||||
shader_parameter/scanlines_width = 0.25
|
||||
shader_parameter/grille_opacity = 0.3
|
||||
shader_parameter/resolution = Vector2(768, 240)
|
||||
shader_parameter/pixelate = false
|
||||
shader_parameter/roll = true
|
||||
shader_parameter/roll_speed = 8.0
|
||||
shader_parameter/roll_size = 15.0
|
||||
shader_parameter/roll_variation = 1.8
|
||||
shader_parameter/distort_intensity = 0.05
|
||||
shader_parameter/noise_opacity = 0.4
|
||||
shader_parameter/noise_speed = 5.0
|
||||
shader_parameter/static_noise_intensity = 0.06
|
||||
shader_parameter/aberration = 0.0
|
||||
shader_parameter/brightness = 2.5
|
||||
shader_parameter/discolor = true
|
||||
shader_parameter/warp_amount = 1.0
|
||||
shader_parameter/clip_warp = false
|
||||
shader_parameter/vignette_intensity = 0.4
|
||||
shader_parameter/vignette_opacity = 0.5
|
||||
|
||||
[sub_resource type="Environment" id=3]
|
||||
[sub_resource type="Environment" id="3"]
|
||||
background_mode = 4
|
||||
glow_enabled = true
|
||||
glow_intensity = 1.0
|
||||
|
@ -266,36 +266,39 @@ glow_strength = 1.15
|
|||
glow_blend_mode = 0
|
||||
|
||||
[node name="RetroTerm" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
theme = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("2")
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
show_behind_parent = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color( 0.156863, 0.156863, 0.156863, 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0.156863, 0.156863, 0.156863, 1)
|
||||
|
||||
[node name="Menu" parent="." instance=ExtResource( 1 )]
|
||||
[node name="Menu" parent="." instance=ExtResource("1")]
|
||||
layout_mode = 1
|
||||
offset_left = 30.0
|
||||
offset_top = 30.0
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="CanvasLayer"]
|
||||
modulate = Color( 0, 1, 0.4, 1 )
|
||||
material = SubResource( 2 )
|
||||
modulate = Color(0, 1, 0.4, 1)
|
||||
material = SubResource("2")
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource( 3 )
|
||||
environment = SubResource("3")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
extends "res://addons/godot_xterm/terminal.gd"
|
||||
extends Terminal
|
||||
|
||||
@export var exec_path: String := "bash"
|
||||
@export var socat_path: String := "socat" # E.g. /usr/bin/socat
|
||||
@export var port: int := 2023
|
||||
@export var verbose: bool := false
|
||||
@export var exec_path := "bash"
|
||||
@export var socat_path := "socat" # E.g. /usr/bin/socat
|
||||
@export var port := 2023
|
||||
@export var verbose := false
|
||||
|
||||
var _timeout = 30
|
||||
var _pid: int
|
||||
|
@ -15,7 +15,7 @@ func _ready():
|
|||
args.append("tcp-l:%d,reuseaddr,fork" % port)
|
||||
args.append("exec:%s,pty,setsid,setpgid,stderr,ctty" % exec_path)
|
||||
|
||||
_pid = OS.execute(socat_path, args, false)
|
||||
_pid = OS.create_process(socat_path, args)
|
||||
|
||||
|
||||
func _process(delta):
|
||||
|
@ -25,7 +25,7 @@ func _process(delta):
|
|||
if _timeout < 1:
|
||||
_error("Timeout: could not connect to socat")
|
||||
|
||||
if not _stream.is_connected_to_host():
|
||||
if _stream.get_connected_host().is_empty():
|
||||
if _stream.connect_to_host("127.0.0.1", port) != OK:
|
||||
_error("Could not connect to socat")
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bc5o6m6ty0ejn"]
|
||||
|
||||
[ext_resource path="res://examples/socat_terminal/socat_terminal.gd" type="Script" id=1]
|
||||
[ext_resource type="Script" path="res://examples/socat_terminal/socat_terminal.gd" id="1"]
|
||||
|
||||
[node name="Terminal" type="Control"]
|
||||
[node name="Terminal" type="Terminal"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
focus_mode = 2
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[connection signal="data_sent" from="." to="." method="_on_Terminal_data_sent"]
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends "res://addons/godot_xterm/terminal.gd"
|
||||
extends Terminal
|
||||
|
||||
@onready var pty = $PTY
|
||||
|
||||
|
|
|
@ -1,28 +1,24 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://cysad55lwtnc6"]
|
||||
|
||||
[ext_resource path="res://themes/audio/bell.wav" type="AudioStream" id=1]
|
||||
[ext_resource path="res://addons/godot_xterm/pty.gd" type="Script" id=2]
|
||||
[ext_resource path="res://examples/terminal/terminal.gd" type="Script" id=3]
|
||||
[ext_resource type="AudioStream" uid="uid://n0hqjfxltbm0" path="res://themes/audio/bell.wav" id="1"]
|
||||
[ext_resource type="Theme" uid="uid://0gk8swmcldbg" path="res://addons/godot_xterm/themes/default.tres" id="1_uci3c"]
|
||||
[ext_resource type="Script" path="res://addons/godot_xterm/pty.gd" id="2"]
|
||||
[ext_resource type="Script" path="res://examples/terminal/terminal.gd" id="3"]
|
||||
|
||||
[node name="Terminal" type="Control"]
|
||||
[node name="Terminal" type="Terminal"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
focus_mode = 2
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
copy_on_selection = true
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_uci3c")
|
||||
script = ExtResource("3")
|
||||
|
||||
[node name="PTY" type="Node" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
script = ExtResource("2")
|
||||
terminal_path = NodePath("..")
|
||||
env = {
|
||||
"COLORTERM": "truecolor",
|
||||
"TERM": "xterm-256color"
|
||||
}
|
||||
|
||||
[node name="Bell" type="AudioStreamPlayer" parent="."]
|
||||
stream = ExtResource( 1 )
|
||||
stream = ExtResource("1")
|
||||
|
||||
[connection signal="bell" from="." to="Bell" method="play"]
|
||||
|
|
|
@ -41,6 +41,10 @@ config/icon="res://docs/media/icon.png"
|
|||
|
||||
window/vsync/use_vsync=false
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/godot_xterm/plugin.cfg")
|
||||
|
||||
[rendering]
|
||||
|
||||
quality/driver/driver_name="GLES2"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[ext_resource type="Script" path="res://addons/godot_xterm/resources/xrdb_theme.gd" id="1"]
|
||||
[ext_resource type="FontFile" uid="uid://edo5q2qxos3u" path="res://addons/godot_xterm/themes/fonts/hack/hack_regular-3.003.ttf" id="2"]
|
||||
|
||||
[sub_resource type="FontFile" id="1"]
|
||||
[sub_resource type="FontFile" id="FontFile_tdf0u"]
|
||||
fallbacks = [ExtResource("2")]
|
||||
face_index = null
|
||||
embolden = null
|
||||
|
@ -39,5 +39,5 @@ Terminal/font_sizes/font_size = 14
|
|||
Terminal/fonts/bold_font = null
|
||||
Terminal/fonts/bold_italics_font = null
|
||||
Terminal/fonts/italics_font = null
|
||||
Terminal/fonts/normal_font = SubResource("1")
|
||||
Terminal/fonts/normal_font = SubResource("FontFile_tdf0u")
|
||||
script = ExtResource("1")
|
||||
|
|
Loading…
Reference in a new issue