render: implement cursor styles 'bar' and 'underline'

This commit is contained in:
Daniel Eklöf 2019-07-22 20:07:34 +02:00
parent 10be7c37ba
commit ed5df194b8
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 94 additions and 49 deletions

2
csi.c
View file

@ -937,13 +937,11 @@ csi_dispatch(struct terminal *term, uint8_t final)
case 3: /* blinking underline */
case 4: /* steady underline */
term->cursor_style = CURSOR_UNDERLINE;
LOG_WARN("unimplemented: cursor style: underline");
break;
case 5: /* blinking bar */
case 6: /* steady bar */
term->cursor_style = CURSOR_BAR;
LOG_WARN("unimplemented: cursor style: bar");
break;
}

141
render.c
View file

@ -70,15 +70,50 @@ gseq_flush(struct terminal *term, struct buffer *buf)
}
static void
render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
int col, int row, bool has_cursor)
draw_underline(const struct terminal *term, struct buffer *buf,
const struct font *font, struct rgb color, double x, double y)
{
double width = term->cell_width;
double height = term->cell_height;
double x = col * width;
double y = row * height;
//const struct font *font = attrs_to_font(term, &cell->attrs);
double baseline = y + term->fextents.height - term->fextents.descent;
double width = font->underline.thickness;
double y_under = baseline - font->underline.position - width / 2.;
bool is_selected = false;
cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b);
cairo_set_line_width(buf->cairo, width);
cairo_move_to(buf->cairo, x, round(y_under) + 0.5);
cairo_rel_line_to(buf->cairo, term->cell_width, 0);
cairo_stroke(buf->cairo);
}
static void
draw_bar(const struct terminal *term, struct buffer *buf, struct rgb color,
double x, double y)
{
cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b);
cairo_set_line_width(buf->cairo, 1.0);
cairo_move_to(buf->cairo, x + 0.5, y);
cairo_rel_line_to(buf->cairo, 0, term->cell_height);
cairo_stroke(buf->cairo);
}
static void
draw_strikeout(const struct terminal *term, struct buffer *buf,
const struct font *font, struct rgb color, double x, double y)
{
double baseline = y + term->fextents.height - term->fextents.descent;
double width = font->strikeout.thickness;
double y_strike = baseline - font->strikeout.position - width / 2.;
cairo_set_source_rgb(buf->cairo, color.r, color.g, color.b);
cairo_set_line_width(buf->cairo, width);
cairo_move_to(buf->cairo, x, round(y_strike) + 0.5);
cairo_rel_line_to(buf->cairo, term->cell_width, 0);
cairo_stroke(buf->cairo);
}
static bool
coord_is_selected(const struct terminal *term, int col, int row)
{
if (term->selection.start.col != -1 && term->selection.end.col != -1) {
const struct coord *start = &term->selection.start;
const struct coord *end = &term->selection.end;
@ -92,18 +127,50 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
assert(start->row <= end->row);
if (start->row == end->row) {
is_selected
= term->grid->view + row == start->row && col >= start->col && col <= end->col;
return (term->grid->view + row == start->row &&
col >= start->col &&
col <= end->col);
} else {
if (term->grid->view + row == start->row)
is_selected = col >= start->col;
return col >= start->col;
else if (term->grid->view + row == end->row)
is_selected = col <= end->col;
return col <= end->col;
else
is_selected = term->grid->view + row >= start->row && term->grid->view + row <= end->row;
return (term->grid->view + row >= start->row &&
term->grid->view + row <= end->row);
}
}
return false;
}
static void
arm_blink_timer(struct terminal *term)
{
LOG_DBG("arming blink timer");
struct itimerspec alarm = {
.it_value = {.tv_sec = 0, .tv_nsec = 500 * 1000000},
.it_interval = {.tv_sec = 0, .tv_nsec = 500 * 1000000},
};
if (timerfd_settime(term->blink.fd, 0, &alarm, NULL) < 0)
LOG_ERRNO("failed to arm blink timer");
else
term->blink.active = true;
}
static void
render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
int col, int row, bool has_cursor)
{
double width = term->cell_width;
double height = term->cell_height;
double x = col * width;
double y = row * height;
bool block_cursor = has_cursor && term->cursor_style == CURSOR_BLOCK;
bool is_selected = coord_is_selected(term, col, row);
uint32_t _fg = cell->attrs.foreground >> 31
? cell->attrs.foreground
: !term->reverse ? term->colors.fg : term->colors.bg;
@ -112,7 +179,7 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
: !term->reverse ? term->colors.bg : term->colors.fg;
/* If *one* is set, we reverse */
if (has_cursor ^ cell->attrs.reverse ^ is_selected) {
if (block_cursor ^ cell->attrs.reverse ^ is_selected) {
uint32_t swap = _fg;
_fg = _bg;
_bg = swap;
@ -132,49 +199,29 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell,
cairo_rectangle(buf->cairo, x, y, width, height);
cairo_fill(buf->cairo);
/* Non-block cursors */
if (has_cursor) {
if (term->cursor_style == CURSOR_BAR)
draw_bar(term, buf, fg, x, y);
else if (term->cursor_style == CURSOR_UNDERLINE)
draw_underline(
term, buf, attrs_to_font(term, &cell->attrs), fg, x, y);
}
if (cell->attrs.blink && !term->blink.active) {
/* First cell we see that has blink set - arm blink timer */
LOG_DBG("arming blink timer");
struct itimerspec alarm = {
.it_value = {.tv_sec = 0, .tv_nsec = 500 * 1000000},
.it_interval = {.tv_sec = 0, .tv_nsec = 500 * 1000000},
};
if (timerfd_settime(term->blink.fd, 0, &alarm, NULL) < 0)
LOG_ERRNO("failed to arm blink timer");
else
term->blink.active = true;
arm_blink_timer(term);
}
if (cell->c[0] == '\0' || cell->attrs.conceal)
return;
/* Underline */
if (cell->attrs.underline) {
const struct font *font = attrs_to_font(term, &cell->attrs);
double baseline = y + term->fextents.height - term->fextents.descent;
double width = font->underline.thickness;
double y_under = baseline - font->underline.position - width / 2.;
if (cell->attrs.underline)
draw_underline(term, buf, attrs_to_font(term, &cell->attrs), fg, x, y);
cairo_set_source_rgb(buf->cairo, fg.r, fg.g, fg.b);
cairo_set_line_width(buf->cairo, width);
cairo_move_to(buf->cairo, x, round(y_under) + 0.5);
cairo_rel_line_to(buf->cairo, term->cell_width, 0);
cairo_stroke(buf->cairo);
}
if (cell->attrs.strikethrough) {
const struct font *font = attrs_to_font(term, &cell->attrs);
double baseline = y + term->fextents.height - term->fextents.descent;
double width = font->strikeout.thickness;
double y_strike = baseline - font->strikeout.position - width / 2.;
cairo_set_source_rgb(buf->cairo, fg.r, fg.g, fg.b);
cairo_set_line_width(buf->cairo, width);
cairo_move_to(buf->cairo, x, round(y_strike) + 0.5);
cairo_rel_line_to(buf->cairo, term->cell_width, 0);
cairo_stroke(buf->cairo);
}
if (cell->attrs.strikethrough)
draw_strikeout(term, buf, attrs_to_font(term, &cell->attrs), fg, x, y);
/*
* cairo_show_glyphs() apparently works *much* faster when