Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(term): make cursor hollow when un-focused #98

Merged
merged 1 commit into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions addons/godot_xterm/editor_plugins/terminal/editor_terminal.gd
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ func _ready():
if not editor_settings:
return

add_theme_stylebox_override("normal", get_theme_stylebox("normal", "Tree"))
add_theme_stylebox_override("focus", get_theme_stylebox("focus", "Tree"))

# 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.
Expand Down
28 changes: 18 additions & 10 deletions addons/godot_xterm/native/src/terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ void Terminal::_notification(int what)
case NOTIFICATION_FOCUS_ENTER:
case NOTIFICATION_FOCUS_EXIT:
{
set_shader_parameters("has_focus", has_focus());
refresh();
break;
}
Expand Down Expand Up @@ -275,6 +276,9 @@ int Terminal::_draw_cb(struct tsm_screen *con,
attr_flags |= AttrFlag::INVERSE;
if (attr->blink)
attr_flags |= AttrFlag::BLINK;
if (term->cursor_position.x == posx && term->cursor_position.y == posy) {
attr_flags |= AttrFlag::CURSOR;
}

// Collect colors.
Color fgcol = std::min(attr->fccode, (int8_t)TSM_COLOR_FOREGROUND) >= 0
Expand Down Expand Up @@ -471,22 +475,26 @@ void Terminal::update_sizes(bool force)
attr_image = Image::create(std::max(cols, 1u), std::max(rows, 1u), false, Image::FORMAT_L8);
attr_texture->set_image(attr_image);

update_shader_parameters(back_material);
update_shader_parameters(fore_material);
set_shader_parameters();

if (force || prev_cols != cols || prev_rows != rows)
emit_signal("size_changed", Vector2i(cols, rows));

refresh();
}

void Terminal::update_shader_parameters(Ref<ShaderMaterial> material)
void Terminal::set_shader_parameters(const String &param, const Variant &value)
{
material->set_shader_parameter("cols", cols);
material->set_shader_parameter("rows", rows);
material->set_shader_parameter("size", size);
material->set_shader_parameter("cell_size", cell_size);
material->set_shader_parameter("grid_size", Vector2(cols * cell_size.x, rows * cell_size.y));
if (param.is_empty()) {
set_shader_parameters("cols", cols);
set_shader_parameters("rows", rows);
set_shader_parameters("size", size);
set_shader_parameters("cell_size", cell_size);
set_shader_parameters("grid_size", Vector2(cols * cell_size.x, rows * cell_size.y));
} else {
back_material->set_shader_parameter(param, value);
fore_material->set_shader_parameter(param, value);
}
}

void Terminal::initialize_rendering() {
Expand Down Expand Up @@ -614,6 +622,7 @@ void Terminal::draw_screen() {
}

rs->canvas_item_clear(char_canvas_item);
cursor_position = tsm_screen_get_flags(screen) & TSM_SCREEN_HIDE_CURSOR ? Vector2i(-1, -1) : get_cursor_pos();
framebuffer_age = tsm_screen_draw(screen, Terminal::_draw_cb, this);
attr_texture->update(attr_image);
back_texture->update(back_image);
Expand Down Expand Up @@ -752,8 +761,7 @@ void Terminal::set_inverse_mode(const int mode) {
inverse_mode = static_cast<InverseMode>(mode);

bool inverse_enabled = inverse_mode == InverseMode::INVERSE_MODE_INVERT;
back_material->set_shader_parameter("inverse_enabled", inverse_enabled);
fore_material->set_shader_parameter("inverse_enabled", inverse_enabled);
set_shader_parameters("inverse_enabled", inverse_enabled);

refresh();
}
Expand Down
4 changes: 3 additions & 1 deletion addons/godot_xterm/native/src/terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace godot
{
INVERSE = 1 << 0,
BLINK = 1 << 1,
CURSOR = 1 << 2,
};

enum InverseMode {
Expand Down Expand Up @@ -130,6 +131,7 @@ namespace godot
double font_offset;
Vector2 size;
Vector2 cell_size;
Vector2i cursor_position;

Ref<Image> attr_image;
Ref<ImageTexture> attr_texture;
Expand Down Expand Up @@ -157,7 +159,7 @@ namespace godot
void initialize_rendering();
void update_theme();
void update_sizes(bool force = false);
void update_shader_parameters(Ref<ShaderMaterial> material);
void set_shader_parameters(const String &name = "", const Variant &value = nullptr);
bool redraw_requested = false;
void _on_frame_post_draw();
void draw_screen();
Expand Down
27 changes: 21 additions & 6 deletions addons/godot_xterm/shaders/common.gdshaderinc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define FLAG_INVERSE 1 << 0
#define FLAG_BLINK 1 << 1
#define FLAG_CURSOR 1 << 2

#define transparent vec4(0)

Expand All @@ -14,6 +15,7 @@ uniform vec2 grid_size;

uniform sampler2D attributes;
uniform bool inverse_enabled = true;
uniform bool has_focus = false;

#ifdef BACKGROUND
uniform vec4 background_color;
Expand Down Expand Up @@ -48,17 +50,21 @@ void fragment() {
color = texture(TEXTURE, UV);
#endif

if (has_attribute(sample_uv, FLAG_INVERSE) && inverse_enabled) {
bool unfocused_cursor = !has_focus && has_attribute(sample_uv, FLAG_CURSOR);

#ifdef BACKGROUND
if (has_attribute(sample_uv, FLAG_INVERSE) && inverse_enabled) {
vec4 bg_color = textureLod(screen_texture, SCREEN_UV, 0.0);
vec4 target_color;
target_color.a = color.a + (1.0 - color.a) * bg_color.a;
target_color.rgb = 1.0 / target_color.a * (color.a * color.rgb + (1.0 - color.a) * bg_color.a * bg_color.rgb);
#else
vec4 target_color = color;
#endif
color = vec4(1.0 - target_color.rgb, target_color.a);
}
#else
if (has_attribute(sample_uv, FLAG_INVERSE) && inverse_enabled && !unfocused_cursor) {
color.rgb = vec3(1.0 - color.rgb);
}
#endif

#ifdef FOREGROUND
if (has_attribute(sample_uv, FLAG_BLINK)) {
Expand All @@ -70,9 +76,18 @@ void fragment() {
}
#endif

#if defined(FOREGROUND) || defined(BACKGROUND)
COLOR = color;
#ifdef BACKGROUND
if (unfocused_cursor) {
// Draw hollow cursor when not focused.
bool isBorderX = (UV.x * size.x - float(cell_x) * cell_size.x) < 1.0 || (float(cell_x + 1) * cell_size.x - UV.x * size.x) < 1.0;
bool isBorderY = (UV.y * size.y - float(cell_y) * cell_size.y) < 1.0 || (float(cell_y + 1) * cell_size.y - UV.y * size.y) < 1.0;
if (!isBorderX && !isBorderY) {
color = transparent;
}
}
#endif

COLOR = color;
} else { // Outside the grid.
COLOR = transparent;
}
Expand Down
Binary file modified test/visual_regression/baseline/default_theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual_regression/baseline/emoji.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual_regression/baseline/empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/visual_regression/baseline/empty_focused.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/visual_regression/baseline/hollow_cursor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual_regression/baseline/solid_invert_selection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual_regression/baseline/solid_swap_selection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual_regression/baseline/transparency.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/visual_regression/baseline/transparent_invert_selection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions test/visual_regression/test_visual_regression.gd
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ class TestVisualRegression:
await wait_frames(30)
assert_match("empty")

func test_empty_focused():
subject.grab_focus()
await wait_frames(30)
assert_match("empty_focused")

func test_hollow_cursor():
subject.write("W\b")
await wait_frames(30)
assert_match("hollow_cursor")

func test_default_theme():
# Print every background color.
for i in range(8):
Expand Down
Loading