mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-10 04:40:25 +01:00
parent
6e938f03bf
commit
bc86b92412
7 changed files with 177 additions and 100 deletions
Binary file not shown.
|
@ -1 +1 @@
|
||||||
ae254c9a4443cc28cdd000971eaf3133f690d2bd
|
0ecaef63a90e5b7cc5f1af692f4e6658886dcbcf
|
Binary file not shown.
|
@ -1,4 +1,5 @@
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <Theme.hpp>
|
#include <Theme.hpp>
|
||||||
|
|
||||||
using namespace godot;
|
using namespace godot;
|
||||||
|
@ -26,15 +27,18 @@ const uint8_t Terminal::default_color_palette[TSM_COLOR_NUM][3] = {
|
||||||
[TSM_COLOR_BACKGROUND] = {0x00, 0x00, 0x00},
|
[TSM_COLOR_BACKGROUND] = {0x00, 0x00, 0x00},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct {
|
static struct
|
||||||
|
{
|
||||||
Color col;
|
Color col;
|
||||||
bool is_set;
|
bool is_set;
|
||||||
} colours[16];
|
} colours[16];
|
||||||
|
|
||||||
static void term_output(const char *s, size_t len, void *user) {
|
static void term_output(const char *s, size_t len, void *user)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_cb(struct tsm_vte *vte, const char *u8, size_t len, void *data) {
|
static void write_cb(struct tsm_vte *vte, const char *u8, size_t len, void *data)
|
||||||
|
{
|
||||||
|
|
||||||
Terminal *term = static_cast<Terminal *>(data);
|
Terminal *term = static_cast<Terminal *>(data);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +52,8 @@ static int text_draw_cb(struct tsm_screen *con,
|
||||||
unsigned int posy,
|
unsigned int posy,
|
||||||
const struct tsm_screen_attr *attr,
|
const struct tsm_screen_attr *attr,
|
||||||
tsm_age_t age,
|
tsm_age_t age,
|
||||||
void *data) {
|
void *data)
|
||||||
|
{
|
||||||
|
|
||||||
Terminal *terminal = static_cast<Terminal *>(data);
|
Terminal *terminal = static_cast<Terminal *>(data);
|
||||||
|
|
||||||
|
@ -58,21 +63,26 @@ static int text_draw_cb(struct tsm_screen *con,
|
||||||
size_t ulen;
|
size_t ulen;
|
||||||
char buf[5] = {0};
|
char buf[5] = {0};
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0)
|
||||||
|
{
|
||||||
char *utf8 = tsm_ucs4_to_utf8_alloc(ch, len, &ulen);
|
char *utf8 = tsm_ucs4_to_utf8_alloc(ch, len, &ulen);
|
||||||
memcpy(terminal->cells[posy][posx].ch, utf8, ulen);
|
memcpy(terminal->cells[posy][posx].ch, utf8, ulen);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
terminal->cells[posy][posx] = {};
|
terminal->cells[posy][posx] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&terminal->cells[posy][posx].attr, attr, sizeof(tsm_screen_attr));
|
memcpy(&terminal->cells[posy][posx].attr, attr, sizeof(tsm_screen_attr));
|
||||||
|
|
||||||
|
if (!terminal->sleep)
|
||||||
terminal->update();
|
terminal->update();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::_register_methods() {
|
void Terminal::_register_methods()
|
||||||
|
{
|
||||||
|
|
||||||
register_method("_init", &Terminal::_init);
|
register_method("_init", &Terminal::_init);
|
||||||
register_method("_ready", &Terminal::_ready);
|
register_method("_ready", &Terminal::_ready);
|
||||||
|
@ -80,89 +90,101 @@ void Terminal::_register_methods() {
|
||||||
register_method("_draw", &Terminal::_draw);
|
register_method("_draw", &Terminal::_draw);
|
||||||
|
|
||||||
register_method("write", &Terminal::write);
|
register_method("write", &Terminal::write);
|
||||||
|
register_method("update_size", &Terminal::update_size);
|
||||||
|
|
||||||
register_property<Terminal, int>("rows", &Terminal::rows, 24);
|
//register_property<Terminal, int>("rows", &Terminal::rows, 24);
|
||||||
register_property<Terminal, int>("cols", &Terminal::cols, 80);
|
//register_property<Terminal, int>("cols", &Terminal::cols, 80);
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal::Terminal() {
|
Terminal::Terminal()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal::~Terminal() {
|
Terminal::~Terminal()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::_init() {
|
void Terminal::_init()
|
||||||
|
{
|
||||||
|
sleep = true;
|
||||||
|
|
||||||
rows = 24;
|
if (tsm_screen_new(&screen, NULL, NULL))
|
||||||
cols = 80;
|
{
|
||||||
|
|
||||||
for (int x = 0; x < rows; x++) {
|
|
||||||
Row row(cols);
|
|
||||||
|
|
||||||
for (int y = 0; y < cols; y++) {
|
|
||||||
row[y] = empty_cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
cells.push_back(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell_size = Vector2(12, 21); // TODO: Get proper cell_size based on font.
|
|
||||||
|
|
||||||
sleep = false;
|
|
||||||
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (tsm_screen_new(&screen, NULL, NULL)) {
|
|
||||||
ERR_PRINT("Error creating new tsm screen");
|
ERR_PRINT("Error creating new tsm screen");
|
||||||
}
|
}
|
||||||
tsm_screen_set_max_sb(screen, 1000); // TODO: Use config var for scrollback size.
|
tsm_screen_set_max_sb(screen, 1000); // TODO: Use config var for scrollback size.
|
||||||
|
|
||||||
if (tsm_vte_new(&vte, screen, write_cb, this, NULL, NULL)) {
|
if (tsm_vte_new(&vte, screen, write_cb, this, NULL, NULL))
|
||||||
|
{
|
||||||
ERR_PRINT("Error creating new tsm vte");
|
ERR_PRINT("Error creating new tsm vte");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the color palette */
|
|
||||||
update_color_palette();
|
update_color_palette();
|
||||||
if (tsm_vte_set_custom_palette(vte, color_palette)) {
|
if (tsm_vte_set_custom_palette(vte, color_palette))
|
||||||
|
{
|
||||||
ERR_PRINT("Error setting custom palette");
|
ERR_PRINT("Error setting custom palette");
|
||||||
}
|
}
|
||||||
if (tsm_vte_set_palette(vte, "custom")) {
|
if (tsm_vte_set_palette(vte, "custom"))
|
||||||
|
{
|
||||||
ERR_PRINT("Error setting palette");
|
ERR_PRINT("Error setting palette");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::_ready() {
|
void Terminal::_ready()
|
||||||
|
{
|
||||||
|
connect("resized", this, "update_size");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::_input(Variant event) {
|
void Terminal::_notification(int what)
|
||||||
|
{
|
||||||
|
switch (what)
|
||||||
|
{
|
||||||
|
case NOTIFICATION_RESIZED:
|
||||||
|
Godot::print("resized!");
|
||||||
|
update_size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::_draw() {
|
void Terminal::_input(Variant event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::_draw()
|
||||||
|
{
|
||||||
if (sleep)
|
if (sleep)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Draw the background */
|
/* Draw the background */
|
||||||
|
draw_rect(get_rect(), get_color("Background", "Terminal"));
|
||||||
|
|
||||||
|
/* Draw the cell backgrounds */
|
||||||
|
|
||||||
// Draw the background first so subsequent rows don't overlap
|
// Draw the background first so subsequent rows don't overlap
|
||||||
// foreground characters such as y that may extend below the baseline.
|
// foreground characters such as y that may extend below the baseline.
|
||||||
for (int row = 0; row < rows; row++) {
|
for (int row = 0; row < rows; row++)
|
||||||
for (int col = 0; col < cols; col++) {
|
{
|
||||||
|
for (int col = 0; col < cols; col++)
|
||||||
|
{
|
||||||
draw_background(row, col, get_cell_colors(row, col).first);
|
draw_background(row, col, get_cell_colors(row, col).first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw the foreground */
|
/* Draw the cell foregrounds */
|
||||||
|
|
||||||
for (int row = 0; row < rows; row++) {
|
for (int row = 0; row < rows; row++)
|
||||||
for (int col = 0; col < cols; col++) {
|
{
|
||||||
|
for (int col = 0; col < cols; col++)
|
||||||
|
{
|
||||||
draw_foreground(row, col, get_cell_colors(row, col).second);
|
draw_foreground(row, col, get_cell_colors(row, col).second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::update_color_palette() {
|
void Terminal::update_color_palette()
|
||||||
|
{
|
||||||
// Start with a copy of the default color palette
|
// Start with a copy of the default color palette
|
||||||
memcpy(color_palette, Terminal::default_color_palette, sizeof(Terminal::default_color_palette));
|
memcpy(color_palette, Terminal::default_color_palette, sizeof(Terminal::default_color_palette));
|
||||||
|
|
||||||
|
@ -199,7 +221,8 @@ void Terminal::update_color_palette() {
|
||||||
set_pallete_color(TSM_COLOR_FOREGROUND, "Foreground");
|
set_pallete_color(TSM_COLOR_FOREGROUND, "Foreground");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::draw_background(int row, int col, Color bgcolor) {
|
void Terminal::draw_background(int row, int col, Color bgcolor)
|
||||||
|
{
|
||||||
|
|
||||||
/* Draw the background */
|
/* Draw the background */
|
||||||
Vector2 background_pos = Vector2(col * cell_size.x, row * cell_size.y);
|
Vector2 background_pos = Vector2(col * cell_size.x, row * cell_size.y);
|
||||||
|
@ -207,7 +230,8 @@ void Terminal::draw_background(int row, int col, Color bgcolor) {
|
||||||
draw_rect(background_rect, bgcolor);
|
draw_rect(background_rect, bgcolor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::draw_foreground(int row, int col, Color fgcolor) {
|
void Terminal::draw_foreground(int row, int col, Color fgcolor)
|
||||||
|
{
|
||||||
|
|
||||||
struct cell cell = cells[row][col];
|
struct cell cell = cells[row][col];
|
||||||
|
|
||||||
|
@ -215,13 +239,20 @@ void Terminal::draw_foreground(int row, int col, Color fgcolor) {
|
||||||
|
|
||||||
Ref<Font> fontref = get_font("");
|
Ref<Font> fontref = get_font("");
|
||||||
|
|
||||||
if (cell.attr.bold && cell.attr.italic) {
|
if (cell.attr.bold && cell.attr.italic)
|
||||||
|
{
|
||||||
fontref = get_font("Bold Italic", "Terminal");
|
fontref = get_font("Bold Italic", "Terminal");
|
||||||
} else if (cell.attr.bold) {
|
}
|
||||||
|
else if (cell.attr.bold)
|
||||||
|
{
|
||||||
fontref = get_font("Bold", "Terminal");
|
fontref = get_font("Bold", "Terminal");
|
||||||
} else if (cell.attr.italic) {
|
}
|
||||||
|
else if (cell.attr.italic)
|
||||||
|
{
|
||||||
fontref = get_font("Italic", "Terminal");
|
fontref = get_font("Italic", "Terminal");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fontref = get_font("Regular", "Terminal");
|
fontref = get_font("Regular", "Terminal");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +272,8 @@ void Terminal::draw_foreground(int row, int col, Color fgcolor) {
|
||||||
draw_string(fontref, foreground_pos, "_", fgcolor);
|
draw_string(fontref, foreground_pos, "_", fgcolor);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Color, Color> Terminal::get_cell_colors(int row, int col) {
|
std::pair<Color, Color> Terminal::get_cell_colors(int row, int col)
|
||||||
|
{
|
||||||
struct cell cell = cells[row][col];
|
struct cell cell = cells[row][col];
|
||||||
Color fgcol, bgcol;
|
Color fgcol, bgcol;
|
||||||
float fr = 1, fg = 1, fb = 1, br = 0, bg = 0, bb = 0;
|
float fr = 1, fg = 1, fb = 1, br = 0, bg = 0, bb = 0;
|
||||||
|
@ -249,30 +281,38 @@ std::pair<Color, Color> Terminal::get_cell_colors(int row, int col) {
|
||||||
|
|
||||||
/* Get foreground color */
|
/* Get foreground color */
|
||||||
|
|
||||||
if (cell.attr.fccode && palette.count(cell.attr.fccode)) {
|
if (cell.attr.fccode && palette.count(cell.attr.fccode))
|
||||||
|
{
|
||||||
fgcol = palette[cell.attr.fccode];
|
fgcol = palette[cell.attr.fccode];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fr = (float)cell.attr.fr / 255.0;
|
fr = (float)cell.attr.fr / 255.0;
|
||||||
fg = (float)cell.attr.fg / 255.0;
|
fg = (float)cell.attr.fg / 255.0;
|
||||||
fb = (float)cell.attr.fb / 255.0;
|
fb = (float)cell.attr.fb / 255.0;
|
||||||
fgcol = Color(fr, fg, fb);
|
fgcol = Color(fr, fg, fb);
|
||||||
|
|
||||||
if (cell.attr.fccode) {
|
if (cell.attr.fccode)
|
||||||
|
{
|
||||||
palette.insert(std::pair<int, Color>(cell.attr.fccode, Color(fr, fg, fb)));
|
palette.insert(std::pair<int, Color>(cell.attr.fccode, Color(fr, fg, fb)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get background color */
|
/* Get background color */
|
||||||
|
|
||||||
if (cell.attr.bccode && palette.count(cell.attr.bccode)) {
|
if (cell.attr.bccode && palette.count(cell.attr.bccode))
|
||||||
|
{
|
||||||
bgcol = palette[cell.attr.bccode];
|
bgcol = palette[cell.attr.bccode];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
br = (float)cell.attr.br / 255.0;
|
br = (float)cell.attr.br / 255.0;
|
||||||
bg = (float)cell.attr.bg / 255.0;
|
bg = (float)cell.attr.bg / 255.0;
|
||||||
bb = (float)cell.attr.bb / 255.0;
|
bb = (float)cell.attr.bb / 255.0;
|
||||||
bgcol = Color(br, bg, bb);
|
bgcol = Color(br, bg, bb);
|
||||||
|
|
||||||
if (cell.attr.bccode) {
|
if (cell.attr.bccode)
|
||||||
|
{
|
||||||
palette.insert(std::pair<int, Color>(cell.attr.bccode, Color(br, bg, bb)));
|
palette.insert(std::pair<int, Color>(cell.attr.bccode, Color(br, bg, bb)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,8 +323,40 @@ std::pair<Color, Color> Terminal::get_cell_colors(int row, int col) {
|
||||||
return std::make_pair(bgcol, fgcol);
|
return std::make_pair(bgcol, fgcol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::write(PoolByteArray data) {
|
// Recalculates the cell_size and number of cols/rows based on font size and the Control's rect_size
|
||||||
|
void Terminal::update_size()
|
||||||
|
{
|
||||||
|
sleep = true;
|
||||||
|
|
||||||
|
cell_size = get_font("Regular", "Terminal").ptr()->get_string_size("W");
|
||||||
|
|
||||||
|
rows = std::max(2, (int)floor(get_rect().size.y / cell_size.y));
|
||||||
|
cols = std::max(1, (int)floor(get_rect().size.x / cell_size.x));
|
||||||
|
|
||||||
|
Godot::print(String("resized_rows: {0}, resized_cols: {1}").format(Array::make(rows, cols)));
|
||||||
|
|
||||||
|
cells = {};
|
||||||
|
|
||||||
|
for (int x = 0; x < rows; x++)
|
||||||
|
{
|
||||||
|
Row row(cols);
|
||||||
|
|
||||||
|
for (int y = 0; y < cols; y++)
|
||||||
|
{
|
||||||
|
row[y] = empty_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
cells.push_back(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
tsm_screen_resize(screen, cols, rows);
|
||||||
|
|
||||||
|
sleep = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::write(PoolByteArray data)
|
||||||
|
{
|
||||||
tsm_vte_input(vte, (char *)data.read().ptr(), data.size());
|
tsm_vte_input(vte, (char *)data.read().ptr(), data.size());
|
||||||
framebuffer_age = tsm_screen_draw(screen, text_draw_cb, this);
|
framebuffer_age = tsm_screen_draw(screen, text_draw_cb, this);
|
||||||
}
|
}
|
|
@ -8,13 +8,16 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace godot {
|
namespace godot
|
||||||
|
{
|
||||||
|
|
||||||
class Terminal : public Control {
|
class Terminal : public Control
|
||||||
|
{
|
||||||
GODOT_CLASS(Terminal, Control)
|
GODOT_CLASS(Terminal, Control)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct cell {
|
struct cell
|
||||||
|
{
|
||||||
char ch[5];
|
char ch[5];
|
||||||
struct tsm_screen_attr attr;
|
struct tsm_screen_attr attr;
|
||||||
} empty_cell = {ch : {0, 0, 0, 0, 0}, attr : {}};
|
} empty_cell = {ch : {0, 0, 0, 0, 0}, attr : {}};
|
||||||
|
@ -35,6 +38,8 @@ private:
|
||||||
Vector2 cell_size;
|
Vector2 cell_size;
|
||||||
std::map<int, Color> palette = {};
|
std::map<int, Color> palette = {};
|
||||||
|
|
||||||
|
void update_size();
|
||||||
|
|
||||||
void update_color_palette();
|
void update_color_palette();
|
||||||
std::pair<Color, Color> get_cell_colors(int row, int col);
|
std::pair<Color, Color> get_cell_colors(int row, int col);
|
||||||
void draw_background(int row, int col, Color bgcol);
|
void draw_background(int row, int col, Color bgcol);
|
||||||
|
@ -48,6 +53,7 @@ public:
|
||||||
|
|
||||||
void _init();
|
void _init();
|
||||||
void _ready();
|
void _ready();
|
||||||
|
void _notification(int what);
|
||||||
void _input(Variant event);
|
void _input(Variant event);
|
||||||
void _draw();
|
void _draw();
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -6,6 +6,8 @@
|
||||||
[ext_resource path="res://examples/terminal/container.gd" type="Script" id=4]
|
[ext_resource path="res://examples/terminal/container.gd" type="Script" id=4]
|
||||||
|
|
||||||
[node name="Container" type="Container"]
|
[node name="Container" type="Container"]
|
||||||
|
margin_right = 40.0
|
||||||
|
margin_bottom = 40.0
|
||||||
script = ExtResource( 4 )
|
script = ExtResource( 4 )
|
||||||
__meta__ = {
|
__meta__ = {
|
||||||
"_edit_use_anchors_": false
|
"_edit_use_anchors_": false
|
||||||
|
@ -16,9 +18,6 @@ margin_right = 40.0
|
||||||
margin_bottom = 40.0
|
margin_bottom = 40.0
|
||||||
theme = ExtResource( 2 )
|
theme = ExtResource( 2 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
__meta__ = {
|
|
||||||
"_edit_use_anchors_": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[node name="Pseudoterminal" type="Node" parent="."]
|
[node name="Pseudoterminal" type="Node" parent="."]
|
||||||
script = ExtResource( 3 )
|
script = ExtResource( 3 )
|
||||||
|
|
Loading…
Reference in a new issue