├── LICENSE.md ├── README.md ├── addons └── terminal │ ├── TermStyle.gd │ ├── buffer.gd │ ├── plugin.cfg │ ├── terminal.gd │ ├── terminal.tscn │ ├── terminal_draw.gd │ ├── terminal_icon.png │ └── terminal_plugin.gd ├── demo.gd ├── demo.tscn ├── engine.cfg ├── fonts ├── UFL.txt ├── UbuntuMono-Bold.ttf ├── UbuntuMono-BoldItalic.ttf ├── UbuntuMono-Italic.ttf ├── UbuntuMono-Regular.ttf ├── Ubuntu_mono_bold.tres ├── Ubuntu_mono_italic.tres ├── Ubuntu_mono_italic_bold.tres └── Ubuntu_mono_regular.tres ├── icon.png └── icon.png.flags /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License - code 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 Daniel Lewan - TeddyDD 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | # License - fonts 14 | Fonts included in repository are from Ubuntu Mono family 15 | 16 | Fonts license is avaliable in `fonts/UFL.txt` file. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](icon.png) 2 | 3 | # Terminal for Godot 4 | 5 | This is simple terminal emulator like control for Godot engine. It might be useful for projects like 6 | 7 | - rougelikes 8 | - game about hacking/hackers 9 | - game about programming 10 | - game with ASCII graphics 11 | - game when you have to interact with computers 12 | - editor plugins 13 | - cheat/debug console 14 | - think of something yourself 15 | 16 | **Notice: This control is still under development. While It's quite usable, the API may change without warning until 1.0** 17 | 18 | ## Screenshot 19 | Screenshot of `demo.tscn` | [Gif - Input](https://66.media.tumblr.com/ef38b961962ef316956a4a343f527564/tumblr_o8atshfiyx1ujs4h9o1_540.gif) | [Gif - Font resize](https://67.media.tumblr.com/3e736bab172592e20dab24242f01aeee/tumblr_o8atshfiyx1ujs4h9o2_540.gif) | [Gif - Terminal resize](https://67.media.tumblr.com/7fef07c7d04fa20b50c880962bb2a45b/tumblr_o8atshfiyx1ujs4h9o3_540.gif) 20 | 21 | ![Screenshot of demo scene](https://cloud.githubusercontent.com/assets/4397533/15800472/28877386-2a7b-11e6-8b11-e4c2dc4003d0.png) 22 | 23 | ## Project Setup 24 | 25 | Godot Engine version >= 2.1 is required. 26 | 27 | ## Testing 28 | 29 | Todo 30 | 31 | ## How to use 32 | 33 | To install these, copy `terminal` to a folder `addons/` 34 | inside your projects, like this `addons/terminal` 35 | 36 | and then activate it in `Scene > Project Settings > Plugins` 37 | Now you can create terminal control from `Create new Node menu`. 38 | 39 | **OR** instance `terminal.tscn` somewhere in your scene. 40 | 41 | -------------------------------------------------------------------------------- /addons/terminal/TermStyle.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Reference 3 | 4 | var fg 5 | var bg 6 | var font 7 | 8 | 9 | func _init(fg=null, bg=null, font=null): 10 | self.fg = fg 11 | self.bg = bg 12 | self.font = font 13 | -------------------------------------------------------------------------------- /addons/terminal/buffer.gd: -------------------------------------------------------------------------------- 1 | extends Reference 2 | 3 | var size # size of buffer: Vector2 4 | 5 | var chars # array of chars 6 | var fgcolors # foreground (text) colors 7 | var bgcolors # background colors 8 | var fonts # font IDs 9 | 10 | var damage = [] 11 | 12 | # Create buffer of given size_c_r (Vector2D, columns, rows) and fill with default values 13 | # char by default is " " (space) 14 | func _init(size, fg, bg, character=" ", font_id=0, set_defaults=true): 15 | self.size = size 16 | # initialize arrays 17 | chars = [] 18 | fgcolors = [] 19 | bgcolors = [] 20 | fonts = [] 21 | 22 | # resize buffers 23 | var b = get_size() 24 | 25 | chars.resize(b) 26 | fgcolors.resize(b) 27 | bgcolors.resize(b) 28 | fonts.resize(b) 29 | 30 | if set_defaults: 31 | set_default(character,fg,bg, font_id) 32 | 33 | # return index for given column and row 34 | func index(x, y): 35 | return y * size.width + x 36 | 37 | # return column and row for given point 38 | func get_point(index): 39 | return Vector2(int(index) % int(size.y), int(index/size.y)) 40 | 41 | func get_size(): 42 | return size.width * size.height 43 | 44 | func transfer_from(buffer): 45 | for y in range(size.height): 46 | if y < buffer.size.height: 47 | for x in range(size.width): 48 | if x < buffer.size.width: 49 | var i = index(x,y) # new 50 | var j = buffer.index(x,y) # old 51 | # new # old 52 | chars[i] = buffer.chars[j] 53 | fgcolors[i] = buffer.fgcolors[j] 54 | bgcolors[i] = buffer.bgcolors[j] 55 | fonts[i] = buffer.fonts[j] 56 | 57 | func set_default(character, fg, bg, font_id): 58 | # set default variables 59 | for item in range( get_size() ): 60 | chars[item] = character 61 | fgcolors[item] = fg 62 | bgcolors[item] = bg 63 | fonts[item] = font_id 64 | 65 | -------------------------------------------------------------------------------- /addons/terminal/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="Terminal" 4 | description="Adds a new Terminal node in Control" 5 | author="Daniel Lewan" 6 | version="0.1" 7 | script="terminal_plugin.gd" 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /addons/terminal/terminal.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Control 3 | 4 | # export variables 5 | 6 | # default font 7 | export (DynamicFont) var dynamicFont 8 | 9 | export(Color, RGBA) var foregound_default = Color("ffffff") # default text color 10 | export(Color, RGBA) var background_default = Color("000000") setget _set_background_default # default background color 11 | 12 | 13 | # offset of characters in cells 14 | export(float) var font_x_offset = 0 15 | export(float) var font_y_offset = 0 16 | 17 | # change the size of cells 18 | # The size of the cells is calculated based on size of "W" character 19 | # These properties allow you to change the margin of characters 20 | export(float) var resize_cell_x = 1 21 | export(float) var resize_cell_y = 1 22 | 23 | 24 | # private variables 25 | # avaliable dynamic fonts - size of cell is based on biggest font 26 | # 0 is usually default font 27 | var fonts = [] 28 | 29 | 30 | var grid = Vector2() # rows and collumns 31 | var cell = Vector2() # cell size in pixels 32 | 33 | # libs 34 | var Buffer = preload("res://addons/terminal/buffer.gd") 35 | var Style = preload("res://addons/terminal/TermStyle.gd") 36 | 37 | var buffer 38 | var defaultStyle 39 | 40 | var _draw_buffer 41 | var _draw_texture 42 | 43 | # true if code is running inside editor 44 | var _editor = true 45 | 46 | var _redraw = true 47 | 48 | 49 | #################### 50 | # Public functions # 51 | #################### 52 | 53 | # call this functions and then update() to redraw changes. 54 | 55 | # return cell from mouse coordinates 56 | func get_cell(point): 57 | return Vector2(clamp(floor(point.x / cell.width), 0, grid.x - 1), 58 | clamp(floor(point.y / cell.height), 0, grid.y - 1)) 59 | 60 | # Write character in given postion using given style 61 | # any parameter can be null 62 | func write(x, y, character, style=defaultStyle): 63 | _check_bounds(x, y) 64 | assert(character.length() == 1) # this function can take only one character 65 | var i = buffer.index(x, y) 66 | buffer.damage.append(i) 67 | if character != null: 68 | buffer.chars[i] = character 69 | if style != null: 70 | if style.fg != null: 71 | buffer.fgcolors[i] = style.fg 72 | if style.bg != null: 73 | buffer.bgcolors[i] = style.bg 74 | if style.font != null: 75 | buffer.fonts[i] = style.font 76 | 77 | # Write string in given postion. fg and bg can be null. 78 | # This method use simple line wrapping. 79 | # Returns postion of last cell of string (Vector2) 80 | func write_string(x, y, string, style=defaultStyle): 81 | _check_bounds(x,y) 82 | assert(string != null) 83 | var cut = buffer.get_size() - buffer.index(x,y) 84 | if string.length() >= cut: 85 | string = string.left(cut) 86 | 87 | var cursor = Vector2(x, y) 88 | var i = buffer.index(cursor.x, cursor.y) 89 | for l in range(string.length()): 90 | buffer.damage.append(i) 91 | var c = string[l] 92 | buffer.chars[i] = c 93 | if style.fg != null: 94 | buffer.fgcolors[i] = style.fg 95 | if style.bg != null: 96 | buffer.bgcolors[i] = style.bg 97 | if style.font != null: 98 | buffer.fonts[i] = style.font 99 | # wrap lines 100 | if cursor.x >= grid.width - 1: 101 | cursor.y += 1 102 | cursor.x = 0 103 | elif cursor.y >= grid.height: 104 | cursor.y = grid.height - 1 105 | return cursor 106 | else: 107 | cursor.x += 1 108 | i += 1 109 | return cursor 110 | 111 | # draw rectangle with given parameters 112 | # character, fg and bg can be null 113 | func write_rect(rect, character=null, style=defaultStyle): 114 | _check_bounds(rect.pos.x, rect.pos.y) 115 | _check_bounds(rect.end.x, rect.end.y) 116 | 117 | for y in range(rect.size.y): 118 | for x in range(rect.size.x): 119 | var i = buffer.index(x + rect.pos.x, y + rect.pos.y) 120 | if character != null: 121 | buffer.chars[i] = character 122 | if style.fg != null: 123 | buffer.fgcolors[i] = style.fg 124 | if style.bg != null: 125 | buffer.bgcolors[i] = style.bg 126 | if style.font != null: 127 | buffer.fonts[i] = style.font 128 | buffer.damage.append(i) 129 | 130 | # Clean screen with given params 131 | func write_all(character=null, style=defaultStyle): 132 | _draw_buffer.request_full_redraw() 133 | assert(style.fg != null and style.bg != null) 134 | buffer.set_default(character, style.fg, style.bg, style.font) 135 | 136 | # add font to fonts array and calulate size 137 | # returns ID of font 138 | func add_font(f): 139 | assert(f.get_type() == "DynamicFont") 140 | fonts.append(f) 141 | _calculate_size() 142 | # return id of added font 143 | return fonts.size() - 1 144 | 145 | # resize all fonts 146 | func resize_fonts(delta): 147 | _draw_buffer.request_full_redraw() 148 | for f in fonts: 149 | f.set_size(f.get_size() + delta) 150 | 151 | func redraw_terminal(): 152 | _redraw = true 153 | 154 | ##################### 155 | # Private functions # 156 | ##################### 157 | 158 | func _ready(): 159 | # editor check 160 | _editor = get_tree().is_editor_hint() 161 | 162 | # default style 163 | defaultStyle = Style.new(foregound_default, background_default, 0) 164 | if not _editor: 165 | # add default font and calculate size 166 | defaultStyle.font = add_font(dynamicFont) 167 | assert(fonts != null) 168 | 169 | buffer = Buffer.new(grid,defaultStyle.fg, defaultStyle.bg, null, defaultStyle.font) 170 | 171 | connect("resized", self, "_on_resize") 172 | 173 | _draw_buffer = get_node("capture/draw buffer") 174 | _draw_buffer.connect("_done_rendering", self, "_render_done") 175 | 176 | _draw_buffer.mode = _draw_buffer.FULL_REDRAW 177 | _draw_buffer.update() 178 | set_process(true) 179 | 180 | func _render_done(mode): 181 | _draw_texture = get_node("capture").get_render_target_texture() 182 | update() 183 | if mode == _draw_buffer.FULL_REDRAW: 184 | buffer.damage = [] 185 | _draw_buffer.mode = _draw_buffer.DAMAGE_REDRAW 186 | 187 | 188 | func _process(delta): 189 | if _redraw: 190 | _draw_buffer.update() 191 | _redraw = false 192 | 193 | 194 | func _draw(): 195 | if _editor: 196 | draw_rect(Rect2(get_global_rect().pos - get_global_pos(), get_size()), background_default) 197 | 198 | if _draw_texture != null: 199 | draw_texture(_draw_texture, Vector2(0,0)) 200 | else: 201 | _draw_buffer.request_full_redraw() 202 | _draw_buffer.on_resize() 203 | _draw_buffer.update() 204 | 205 | 206 | # Helper function that ensures drawing in bounds of buffer 207 | func _check_bounds(x, y): 208 | assert(x >= 0 and x <= grid.x - 1) 209 | assert(y >= 0 and y <= grid.y - 1) 210 | 211 | 212 | # Calculate the grid size. Final result depens of font size 213 | func _calculate_size(): 214 | 215 | var width = get_size().width 216 | var height = get_size().height 217 | 218 | # Get size of biggest font 219 | # prevous max cell size 220 | var c = Vector2() 221 | for f in fonts: 222 | cell.width = max( int(f.get_string_size("W").width * resize_cell_x ), c.width) 223 | cell.height = max( int(f.get_height() * resize_cell_y ), c.height) 224 | # I want a copy, not reference 225 | c = cell + Vector2(0,0) 226 | 227 | grid.width = ( width - (int(width) % int(cell.width)) ) / cell.width 228 | grid.height = ( height - (int(height) % int(cell.height)) ) / cell.height 229 | 230 | # Call manually when changed font size 231 | func _on_resize(): # signal 232 | if not _editor: 233 | var old_grid = grid 234 | _calculate_size() 235 | if grid.x > 0 and grid.y > 0 and old_grid != grid: 236 | var b = Buffer.new(grid,defaultStyle.fg, defaultStyle.bg, null) 237 | b.transfer_from(buffer) 238 | buffer = b 239 | _draw_buffer.mode = _draw_buffer.RESIZE_REDRAW 240 | _draw_buffer.on_resize() 241 | redraw_terminal() 242 | 243 | 244 | # SetGet 245 | # Default Bg color - only for editor 246 | func _set_background_default(value): 247 | background_default = value 248 | if _editor: 249 | update() 250 | 251 | -------------------------------------------------------------------------------- /addons/terminal/terminal.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=1] 2 | 3 | [ext_resource path="res://addons/terminal/terminal.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/terminal/terminal_draw.gd" type="Script" id=2] 5 | 6 | [node name="Terminal" type="Control"] 7 | 8 | anchor/right = 1 9 | anchor/bottom = 1 10 | focus/ignore_mouse = false 11 | focus/stop_mouse = true 12 | size_flags/horizontal = 2 13 | size_flags/vertical = 2 14 | margin/left = 0.0 15 | margin/top = 0.0 16 | margin/right = 984.0 17 | margin/bottom = 560.0 18 | script/script = ExtResource( 1 ) 19 | dynamicFont = null 20 | foregound_default = Color( 1, 1, 1, 1 ) 21 | background_default = Color( 0, 0, 0, 1 ) 22 | font_x_offset = 0 23 | font_y_offset = 0 24 | resize_cell_x = 1 25 | resize_cell_y = 1 26 | 27 | [node name="capture" type="Viewport" parent="."] 28 | 29 | rect = Rect2( 0, 0, 40, 40 ) 30 | own_world = false 31 | world = null 32 | transparent_bg = false 33 | render_target/enabled = true 34 | render_target/v_flip = false 35 | render_target/clear_on_new_frame = false 36 | render_target/filter = false 37 | render_target/gen_mipmaps = false 38 | render_target/update_mode = 3 39 | audio_listener/enable_2d = false 40 | audio_listener/enable_3d = false 41 | physics/object_picking = false 42 | gui/disable_input = false 43 | 44 | [node name="draw buffer" type="Control" parent="capture"] 45 | 46 | focus/ignore_mouse = false 47 | focus/stop_mouse = true 48 | size_flags/horizontal = 2 49 | size_flags/vertical = 2 50 | margin/left = 0.0 51 | margin/top = 0.0 52 | margin/right = 40.0 53 | margin/bottom = 40.0 54 | script/script = ExtResource( 2 ) 55 | 56 | 57 | -------------------------------------------------------------------------------- /addons/terminal/terminal_draw.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | const FULL_REDRAW = 1 4 | const DAMAGE_REDRAW = 2 5 | const RESIZE_REDRAW = 3 6 | var mode = 1 7 | 8 | # debug 9 | var _draw_time = 0 10 | 11 | var term 12 | signal _done_rendering(mode) 13 | 14 | func _ready(): 15 | term = get_parent().get_parent() 16 | term.connect("resized", self, "on_resize") 17 | set_size(term.get_size()) 18 | 19 | 20 | func request_full_redraw(): 21 | mode = FULL_REDRAW 22 | 23 | func on_resize(): 24 | get_parent().set_rect(Rect2(Vector2(), get_size())) 25 | set_size(term.get_size()) 26 | 27 | 28 | func _draw(): 29 | var t = OS.get_ticks_msec() 30 | if term._draw_texture != null and mode == DAMAGE_REDRAW: 31 | term._draw_texture = get_parent().get_render_target_texture() 32 | draw_texture(term._draw_texture, Vector2()) 33 | on_resize() 34 | _redraw(term.buffer.damage) 35 | emit_signal("_done_rendering", DAMAGE_REDRAW) 36 | # elif term._draw_texture != null and mode == RESIZE_REDRAW: 37 | # draw_bg() 38 | # term._draw_texture = get_parent().get_render_target_texture() 39 | # draw_texture_rect_region(term._draw_texture, term.get_rect(), Rect2(Vector2(), term.get_size())) 40 | # mode = DAMAGE_REDRAW 41 | # emit_signal("_done_rendering", RESIZE_REDRAW) 42 | else: # full redraw 43 | draw_bg() 44 | _redraw(range(term.buffer.get_size())) 45 | term._draw_texture = get_parent().get_render_target_texture() 46 | emit_signal("_done_rendering", FULL_REDRAW) 47 | term.buffer.damage = [] 48 | _draw_time = (OS.get_ticks_msec() - t) 49 | 50 | 51 | func draw_bg(): 52 | draw_rect(get_rect(), term.defaultStyle.bg) 53 | 54 | func _redraw(indexes): 55 | # variables for loop 56 | var char_now 57 | var fgcolor_now 58 | var font_now 59 | var font_pos = Vector2() 60 | var bg_rect = Rect2(0,0, term.cell.width, term.cell.height) 61 | var w = term.buffer.size.width 62 | var default_font = term.defaultStyle.font 63 | var cell = term.cell 64 | var fonts = term.buffer.fonts 65 | var chars = term.buffer.chars 66 | var fg = term.buffer.fgcolors 67 | var bg = term.buffer.bgcolors 68 | var def_bg = term.defaultStyle.bg 69 | 70 | # draw letters and boxes 71 | # index 72 | var i = 0 73 | var x = 0 74 | var y = 0 75 | var size = term.buffer.size.width 76 | 77 | for i in (indexes): 78 | x = int(i) % int(size) 79 | y = int(i/size) 80 | # draw bg 81 | if bg[i] != null or bg[i] != def_bg: 82 | bg_rect.pos.x = x * cell.width 83 | bg_rect.pos.y = y * cell.height 84 | draw_rect(bg_rect, bg[i]) 85 | # draw text 86 | char_now = chars[i] 87 | if char_now != null : 88 | if char_now != " ": 89 | if not fonts[i] == null: 90 | font_now = term.fonts[fonts[i]] 91 | else: 92 | font_now = term.fonts[term.defaultStyle.font] 93 | 94 | fgcolor_now = fg[i] 95 | if fgcolor_now == null: 96 | fgcolor_now = fonts[term.defaultStyle.font] 97 | 98 | font_pos.x = (x * cell.width) + (cell.width * term.font_x_offset) 99 | font_pos.y = (y * cell.height) + font_now.get_ascent() + (cell.height * term.font_y_offset) 100 | draw_char( font_now, font_pos, char_now, "W", fgcolor_now) 101 | -------------------------------------------------------------------------------- /addons/terminal/terminal_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeddyDD/gterm/f121a79b3ddff2ff184595a47300ea0f67a87a99/addons/terminal/terminal_icon.png -------------------------------------------------------------------------------- /addons/terminal/terminal_plugin.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends EditorPlugin 3 | 4 | func _enter_tree(): 5 | # When this plugin node enters tree, add the custom type 6 | add_custom_type("Terminal","Control",preload("res://addons/terminal/terminal.gd"),preload("res://addons/terminal/terminal_icon.png")) 7 | 8 | func _exit_tree(): 9 | # When the plugin node exits the tree, remove the custom type 10 | remove_custom_type("Terminal") 11 | -------------------------------------------------------------------------------- /demo.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Panel 3 | 4 | var cursor = Vector2(0,0) 5 | var terminal 6 | var current_style 7 | 8 | # color pickers 9 | onready var fg_picker = get_node("VBoxContainer/HBoxContainer/fg_color") 10 | onready var bg_picker = get_node("VBoxContainer/HBoxContainer/bg_color") 11 | 12 | # font selector 13 | onready var font_select = get_node("VBoxContainer/HBoxContainer/font_style") 14 | 15 | var draw_mouse = false 16 | 17 | func _ready(): 18 | terminal = get_node("VBoxContainer/Terminal") 19 | # load additional fonts 20 | terminal.add_font(preload("res://fonts/Ubuntu_mono_bold.tres")) 21 | terminal.add_font(preload("res://fonts/Ubuntu_mono_italic.tres")) 22 | terminal.add_font(preload("res://fonts/Ubuntu_mono_italic_bold.tres")) 23 | terminal._on_resize() 24 | terminal.redraw_terminal() 25 | 26 | 27 | # current terminal style 28 | current_style = terminal.Style.new(fg_picker.get_color(), bg_picker.get_color(), 0) 29 | 30 | # add menu items for fonts 31 | font_select.add_item("Normal", 0) 32 | font_select.add_item("Bold", 1) 33 | font_select.add_item("Italic", 2) 34 | font_select.add_item("Bold Italic", 3) 35 | font_select.select(0) 36 | 37 | 38 | 39 | # Enter button 40 | func _on_enter_pressed(): 41 | var string = get_node("VBoxContainer/HBoxContainer/LineEdit").get_text() 42 | cursor = terminal.write_string(cursor.x, cursor.y, string, current_style) 43 | 44 | 45 | cursor.x += 1 46 | if cursor.x >= terminal.grid.x - 1: 47 | _on_new_line_pressed() 48 | 49 | # redraw terminal 50 | terminal.redraw_terminal() 51 | 52 | # When you press enter key while writing 53 | func _on_LineEdit_text_entered( text ): 54 | _on_enter_pressed() 55 | get_node("VBoxContainer/HBoxContainer/LineEdit").set_text("") 56 | 57 | func resize_font(size): 58 | terminal.resize_fonts(size) 59 | terminal._on_resize() 60 | terminal.redraw_terminal() 61 | 62 | # font+ button 63 | func _on_font_plus_pressed(): 64 | resize_font(1) 65 | 66 | # font- button 67 | func _on_font_minus_pressed(): 68 | resize_font(-1) 69 | 70 | 71 | func _on_clean_pressed(): 72 | var c = get_node("VBoxContainer/HBoxContainer/LineEdit").get_text() 73 | c = c.left(1) 74 | if c.empty(): 75 | c = " " 76 | cursor = Vector2() 77 | terminal.defaultStyle.bg = current_style.bg 78 | terminal.write_all(c, current_style) 79 | terminal.redraw_terminal() 80 | 81 | 82 | func _on_font_style_item_selected( ID ): 83 | current_style.font = ID 84 | 85 | 86 | func _on_fg_color_color_changed( color ): 87 | current_style.fg = color 88 | 89 | 90 | func _on_bg_color_color_changed( color ): 91 | current_style.bg = color 92 | 93 | 94 | func _on_new_line_pressed(): 95 | # go to begginig of next line 96 | cursor.x = 0 97 | cursor.y += 1 98 | if cursor.y >= terminal.grid.y - 1: 99 | cursor.y = 0 100 | 101 | 102 | 103 | func _on_Terminal_input_event( ev ): 104 | if ev.type == InputEvent.MOUSE_MOTION and draw_mouse: 105 | var c = terminal.get_cell(Vector2(ev.x, ev.y)) 106 | terminal.write(c.x, c.y, "#", current_style) 107 | terminal.redraw_terminal() 108 | 109 | 110 | func _on_draw_toggled( pressed ): 111 | draw_mouse = pressed 112 | 113 | 114 | func _on_Panel_resized(): 115 | if terminal != null: 116 | OS.set_window_title("Terminal: %s" % terminal.grid) 117 | 118 | # using internal apis 119 | func _on_rand_bg_pressed(): 120 | for i in range(terminal.buffer.get_size()): 121 | terminal.buffer.bgcolors[i] = Color(randf(), randf(), randf()) 122 | terminal._draw_buffer.request_full_redraw() 123 | terminal.redraw_terminal() 124 | 125 | -------------------------------------------------------------------------------- /demo.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=9 format=1] 2 | 3 | [ext_resource path="res://demo.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/terminal/terminal.tscn" type="PackedScene" id=2] 5 | [ext_resource path="res://fonts/UbuntuMono-Regular.ttf" type="DynamicFontData" id=3] 6 | [ext_resource path="res://fonts/Ubuntu_mono_regular.tres" type="DynamicFont" id=4] 7 | 8 | [sub_resource type="DynamicFontData" id=1] 9 | 10 | font_path = "res://fonts/UbuntuMono-Regular.ttf" 11 | 12 | [sub_resource type="DynamicFont" id=2] 13 | 14 | font/size = 16 15 | font/use_mipmaps = false 16 | font/use_filter = false 17 | font/font = SubResource( 1 ) 18 | 19 | [sub_resource type="Theme" id=3] 20 | 21 | default_font = SubResource( 2 ) 22 | 23 | [sub_resource type="DynamicFont" id=4] 24 | 25 | font/size = 16 26 | font/use_mipmaps = false 27 | font/use_filter = false 28 | font/font = ExtResource( 3 ) 29 | 30 | [node name="Panel" type="Panel"] 31 | 32 | anchor/right = 1 33 | anchor/bottom = 1 34 | focus/ignore_mouse = false 35 | focus/stop_mouse = true 36 | size_flags/horizontal = 2 37 | size_flags/vertical = 2 38 | theme/theme = SubResource( 3 ) 39 | margin/left = 0.0 40 | margin/top = 0.0 41 | margin/right = 0.0 42 | margin/bottom = 0.0 43 | script/script = ExtResource( 1 ) 44 | __meta__ = { "_edit_lock_":true } 45 | 46 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 47 | 48 | anchor/right = 1 49 | anchor/bottom = 1 50 | focus/ignore_mouse = false 51 | focus/stop_mouse = false 52 | size_flags/horizontal = 3 53 | size_flags/vertical = 3 54 | margin/left = 10.0 55 | margin/top = 10.0 56 | margin/right = 10.0 57 | margin/bottom = 10.0 58 | alignment = 0 59 | __meta__ = { "_edit_lock_":true } 60 | 61 | [node name="Terminal" parent="VBoxContainer" instance=ExtResource( 2 )] 62 | 63 | anchor/right = 0 64 | anchor/bottom = 0 65 | size_flags/vertical = 3 66 | margin/right = 1004.0 67 | margin/bottom = 550.0 68 | dynamicFont = SubResource( 4 ) 69 | 70 | [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] 71 | 72 | focus/ignore_mouse = false 73 | focus/stop_mouse = false 74 | size_flags/horizontal = 2 75 | size_flags/vertical = 2 76 | margin/left = 0.0 77 | margin/top = 554.0 78 | margin/right = 1004.0 79 | margin/bottom = 580.0 80 | alignment = 0 81 | 82 | [node name="font_plus" type="Button" parent="VBoxContainer/HBoxContainer"] 83 | 84 | focus/ignore_mouse = false 85 | focus/stop_mouse = true 86 | size_flags/horizontal = 2 87 | size_flags/vertical = 2 88 | margin/left = 0.0 89 | margin/top = 0.0 90 | margin/right = 60.0 91 | margin/bottom = 26.0 92 | toggle_mode = false 93 | enabled_focus_mode = 2 94 | shortcut = null 95 | text = "font +" 96 | flat = false 97 | 98 | [node name="font_minus" type="Button" parent="VBoxContainer/HBoxContainer"] 99 | 100 | focus/ignore_mouse = false 101 | focus/stop_mouse = true 102 | size_flags/horizontal = 2 103 | size_flags/vertical = 2 104 | margin/left = 64.0 105 | margin/top = 0.0 106 | margin/right = 124.0 107 | margin/bottom = 26.0 108 | toggle_mode = false 109 | enabled_focus_mode = 2 110 | shortcut = null 111 | text = "font -" 112 | flat = false 113 | 114 | [node name="LineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainer"] 115 | 116 | rect/min_size = Vector2( 200, 0 ) 117 | focus/ignore_mouse = false 118 | focus/stop_mouse = true 119 | size_flags/horizontal = 2 120 | size_flags/vertical = 2 121 | margin/left = 128.0 122 | margin/top = 0.0 123 | margin/right = 328.0 124 | margin/bottom = 26.0 125 | custom_fonts/font = ExtResource( 4 ) 126 | placeholder/alpha = 0.6 127 | focus_mode = 2 128 | caret/caret_blink = false 129 | caret/caret_blink_speed = 0.65 130 | 131 | [node name="enter" type="Button" parent="VBoxContainer/HBoxContainer"] 132 | 133 | focus/ignore_mouse = false 134 | focus/stop_mouse = true 135 | size_flags/horizontal = 2 136 | size_flags/vertical = 2 137 | margin/left = 332.0 138 | margin/top = 0.0 139 | margin/right = 384.0 140 | margin/bottom = 26.0 141 | toggle_mode = false 142 | enabled_focus_mode = 2 143 | shortcut = null 144 | text = "enter" 145 | flat = false 146 | 147 | [node name="new_line" type="Button" parent="VBoxContainer/HBoxContainer"] 148 | 149 | focus/ignore_mouse = false 150 | focus/stop_mouse = true 151 | size_flags/horizontal = 2 152 | size_flags/vertical = 2 153 | margin/left = 388.0 154 | margin/top = 0.0 155 | margin/right = 464.0 156 | margin/bottom = 26.0 157 | toggle_mode = false 158 | enabled_focus_mode = 2 159 | shortcut = null 160 | text = "new line" 161 | flat = false 162 | 163 | [node name="fg_color" type="ColorPickerButton" parent="VBoxContainer/HBoxContainer"] 164 | 165 | focus/ignore_mouse = false 166 | focus/stop_mouse = true 167 | size_flags/horizontal = 2 168 | size_flags/vertical = 2 169 | margin/left = 468.0 170 | margin/top = 0.0 171 | margin/right = 496.0 172 | margin/bottom = 26.0 173 | toggle_mode = false 174 | enabled_focus_mode = 2 175 | shortcut = null 176 | text = "fg" 177 | flat = false 178 | color = Color( 1, 1, 1, 1 ) 179 | edit_alpha = true 180 | 181 | [node name="bg_color" type="ColorPickerButton" parent="VBoxContainer/HBoxContainer"] 182 | 183 | focus/ignore_mouse = false 184 | focus/stop_mouse = true 185 | size_flags/horizontal = 2 186 | size_flags/vertical = 2 187 | margin/left = 500.0 188 | margin/top = 0.0 189 | margin/right = 528.0 190 | margin/bottom = 26.0 191 | toggle_mode = false 192 | enabled_focus_mode = 2 193 | shortcut = null 194 | text = "fg" 195 | flat = false 196 | color = Color( 0, 0, 0, 1 ) 197 | edit_alpha = true 198 | 199 | [node name="clean" type="Button" parent="VBoxContainer/HBoxContainer"] 200 | 201 | focus/ignore_mouse = false 202 | focus/stop_mouse = true 203 | size_flags/horizontal = 2 204 | size_flags/vertical = 2 205 | margin/left = 532.0 206 | margin/top = 0.0 207 | margin/right = 584.0 208 | margin/bottom = 26.0 209 | toggle_mode = false 210 | enabled_focus_mode = 2 211 | shortcut = null 212 | text = "clean" 213 | flat = false 214 | 215 | [node name="font_style" type="OptionButton" parent="VBoxContainer/HBoxContainer"] 216 | 217 | rect/min_size = Vector2( 120, 0 ) 218 | focus/ignore_mouse = false 219 | focus/stop_mouse = true 220 | size_flags/horizontal = 2 221 | size_flags/vertical = 2 222 | margin/left = 588.0 223 | margin/top = 0.0 224 | margin/right = 708.0 225 | margin/bottom = 26.0 226 | toggle_mode = false 227 | click_on_press = true 228 | enabled_focus_mode = 0 229 | shortcut = null 230 | flat = true 231 | align = 0 232 | selected = -1 233 | items = [ ] 234 | 235 | [node name="draw" type="CheckButton" parent="VBoxContainer/HBoxContainer"] 236 | 237 | focus/ignore_mouse = false 238 | focus/stop_mouse = true 239 | size_flags/horizontal = 2 240 | size_flags/vertical = 2 241 | margin/left = 712.0 242 | margin/top = 0.0 243 | margin/right = 908.0 244 | margin/bottom = 26.0 245 | toggle_mode = true 246 | enabled_focus_mode = 2 247 | shortcut = null 248 | text = "Draw with mouse" 249 | flat = false 250 | align = 0 251 | 252 | [node name="rand_bg" type="Button" parent="VBoxContainer/HBoxContainer"] 253 | 254 | focus/ignore_mouse = false 255 | focus/stop_mouse = true 256 | size_flags/horizontal = 2 257 | size_flags/vertical = 2 258 | margin/left = 912.0 259 | margin/top = 0.0 260 | margin/right = 996.0 261 | margin/bottom = 26.0 262 | toggle_mode = false 263 | enabled_focus_mode = 2 264 | shortcut = null 265 | text = "Random BG" 266 | flat = false 267 | 268 | [connection signal="resized" from="." to="." method="_on_Panel_resized"] 269 | 270 | [connection signal="input_event" from="VBoxContainer/Terminal" to="." method="_on_Terminal_input_event"] 271 | 272 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/font_plus" to="." method="_on_font_plus_pressed"] 273 | 274 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/font_minus" to="." method="_on_font_minus_pressed"] 275 | 276 | [connection signal="text_entered" from="VBoxContainer/HBoxContainer/LineEdit" to="." method="_on_LineEdit_text_entered"] 277 | 278 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/enter" to="." method="_on_enter_pressed"] 279 | 280 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/new_line" to="." method="_on_new_line_pressed"] 281 | 282 | [connection signal="color_changed" from="VBoxContainer/HBoxContainer/fg_color" to="." method="_on_fg_color_color_changed"] 283 | 284 | [connection signal="color_changed" from="VBoxContainer/HBoxContainer/bg_color" to="." method="_on_bg_color_color_changed"] 285 | 286 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/clean" to="." method="_on_clean_pressed"] 287 | 288 | [connection signal="item_selected" from="VBoxContainer/HBoxContainer/font_style" to="." method="_on_font_style_item_selected"] 289 | 290 | [connection signal="toggled" from="VBoxContainer/HBoxContainer/draw" to="." method="_on_draw_toggled"] 291 | 292 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/rand_bg" to="." method="_on_rand_bg_pressed"] 293 | 294 | 295 | -------------------------------------------------------------------------------- /engine.cfg: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | name="Terminal for Godot" 4 | main_scene="res://demo.tscn" 5 | icon="res://icon.png" 6 | -------------------------------------------------------------------------------- /fonts/UFL.txt: -------------------------------------------------------------------------------- 1 | ------------------------------- 2 | UBUNTU FONT LICENCE Version 1.0 3 | ------------------------------- 4 | 5 | PREAMBLE 6 | This licence allows the licensed fonts to be used, studied, modified and 7 | redistributed freely. The fonts, including any derivative works, can be 8 | bundled, embedded, and redistributed provided the terms of this licence 9 | are met. The fonts and derivatives, however, cannot be released under 10 | any other licence. The requirement for fonts to remain under this 11 | licence does not require any document created using the fonts or their 12 | derivatives to be published under this licence, as long as the primary 13 | purpose of the document is not to be a vehicle for the distribution of 14 | the fonts. 15 | 16 | DEFINITIONS 17 | "Font Software" refers to the set of files released by the Copyright 18 | Holder(s) under this licence and clearly marked as such. This may 19 | include source files, build scripts and documentation. 20 | 21 | "Original Version" refers to the collection of Font Software components 22 | as received under this licence. 23 | 24 | "Modified Version" refers to any derivative made by adding to, deleting, 25 | or substituting -- in part or in whole -- any of the components of the 26 | Original Version, by changing formats or by porting the Font Software to 27 | a new environment. 28 | 29 | "Copyright Holder(s)" refers to all individuals and companies who have a 30 | copyright ownership of the Font Software. 31 | 32 | "Substantially Changed" refers to Modified Versions which can be easily 33 | identified as dissimilar to the Font Software by users of the Font 34 | Software comparing the Original Version with the Modified Version. 35 | 36 | To "Propagate" a work means to do anything with it that, without 37 | permission, would make you directly or secondarily liable for 38 | infringement under applicable copyright law, except executing it on a 39 | computer or modifying a private copy. Propagation includes copying, 40 | distribution (with or without modification and with or without charging 41 | a redistribution fee), making available to the public, and in some 42 | countries other activities as well. 43 | 44 | PERMISSION & CONDITIONS 45 | This licence does not grant any rights under trademark law and all such 46 | rights are reserved. 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a 49 | copy of the Font Software, to propagate the Font Software, subject to 50 | the below conditions: 51 | 52 | 1) Each copy of the Font Software must contain the above copyright 53 | notice and this licence. These can be included either as stand-alone 54 | text files, human-readable headers or in the appropriate machine- 55 | readable metadata fields within text or binary files as long as those 56 | fields can be easily viewed by the user. 57 | 58 | 2) The font name complies with the following: 59 | (a) The Original Version must retain its name, unmodified. 60 | (b) Modified Versions which are Substantially Changed must be renamed to 61 | avoid use of the name of the Original Version or similar names entirely. 62 | (c) Modified Versions which are not Substantially Changed must be 63 | renamed to both (i) retain the name of the Original Version and (ii) add 64 | additional naming elements to distinguish the Modified Version from the 65 | Original Version. The name of such Modified Versions must be the name of 66 | the Original Version, with "derivative X" where X represents the name of 67 | the new work, appended to that name. 68 | 69 | 3) The name(s) of the Copyright Holder(s) and any contributor to the 70 | Font Software shall not be used to promote, endorse or advertise any 71 | Modified Version, except (i) as required by this licence, (ii) to 72 | acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with 73 | their explicit written permission. 74 | 75 | 4) The Font Software, modified or unmodified, in part or in whole, must 76 | be distributed entirely under this licence, and must not be distributed 77 | under any other licence. The requirement for fonts to remain under this 78 | licence does not affect any document created using the Font Software, 79 | except any version of the Font Software extracted from a document 80 | created using the Font Software may only be distributed under this 81 | licence. 82 | 83 | TERMINATION 84 | This licence becomes null and void if any of the above conditions are 85 | not met. 86 | 87 | DISCLAIMER 88 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 89 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 90 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 91 | COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 92 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 93 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 94 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 95 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER 96 | DEALINGS IN THE FONT SOFTWARE. 97 | -------------------------------------------------------------------------------- /fonts/UbuntuMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeddyDD/gterm/f121a79b3ddff2ff184595a47300ea0f67a87a99/fonts/UbuntuMono-Bold.ttf -------------------------------------------------------------------------------- /fonts/UbuntuMono-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeddyDD/gterm/f121a79b3ddff2ff184595a47300ea0f67a87a99/fonts/UbuntuMono-BoldItalic.ttf -------------------------------------------------------------------------------- /fonts/UbuntuMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeddyDD/gterm/f121a79b3ddff2ff184595a47300ea0f67a87a99/fonts/UbuntuMono-Italic.ttf -------------------------------------------------------------------------------- /fonts/UbuntuMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeddyDD/gterm/f121a79b3ddff2ff184595a47300ea0f67a87a99/fonts/UbuntuMono-Regular.ttf -------------------------------------------------------------------------------- /fonts/Ubuntu_mono_bold.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=1] 2 | 3 | [ext_resource path="res://fonts/UbuntuMono-Bold.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | 7 | font/size = 16 8 | font/font = ExtResource( 1 ) 9 | 10 | -------------------------------------------------------------------------------- /fonts/Ubuntu_mono_italic.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=1] 2 | 3 | [ext_resource path="res://fonts/UbuntuMono-Italic.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | 7 | font/size = 16 8 | font/font = ExtResource( 1 ) 9 | 10 | -------------------------------------------------------------------------------- /fonts/Ubuntu_mono_italic_bold.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=1] 2 | 3 | [ext_resource path="res://fonts/UbuntuMono-BoldItalic.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | 7 | font/size = 16 8 | font/font = ExtResource( 1 ) 9 | 10 | -------------------------------------------------------------------------------- /fonts/Ubuntu_mono_regular.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=1] 2 | 3 | [ext_resource path="res://fonts/UbuntuMono-Regular.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | 7 | font/size = 16 8 | font/font = ExtResource( 1 ) 9 | 10 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeddyDD/gterm/f121a79b3ddff2ff184595a47300ea0f67a87a99/icon.png -------------------------------------------------------------------------------- /icon.png.flags: -------------------------------------------------------------------------------- 1 | gen_mipmaps=false 2 | --------------------------------------------------------------------------------