mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
selection: update: don't dirty cells that don't change state
Previously when updating a selection, we would unmark *all* cells in the old selection, and then mark all cells in the new selection. This caused *all* cells to be dirtied and thus re-rendered. Avoid this, by adding a temporary state to the cells' selected state. Before unmarking the old selection, pre-mark the new selection using a temporary state. When unmarking the old selection, ignore cells in this temporary state. When marking the new selection, ignore cells in this temporary state (except clearing the temporary state).
This commit is contained in:
parent
6833abf33c
commit
457eb573c4
3 changed files with 51 additions and 22 deletions
2
render.c
2
render.c
|
|
@ -385,7 +385,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
int x = term->x_margin + col * width;
|
||||
int y = term->y_margin + row * height;
|
||||
|
||||
//bool is_selected = coord_is_selected(term, col, row);
|
||||
assert(cell->attrs.selected == 0 || cell->attrs.selected == 1);
|
||||
bool is_selected = cell->attrs.selected;
|
||||
|
||||
uint32_t _fg = 0;
|
||||
|
|
|
|||
67
selection.c
67
selection.c
|
|
@ -47,12 +47,12 @@ selection_on_row_in_view(const struct terminal *term, int row_no)
|
|||
|
||||
static void
|
||||
foreach_selected_normal(
|
||||
struct terminal *term,
|
||||
struct terminal *term, struct coord _start, struct coord _end,
|
||||
void (*cb)(struct terminal *term, struct row *row, struct cell *cell, void *data),
|
||||
void *data)
|
||||
{
|
||||
const struct coord *start = &term->selection.start;
|
||||
const struct coord *end = &term->selection.end;
|
||||
const struct coord *start = &_start;
|
||||
const struct coord *end = &_end;
|
||||
|
||||
int start_row, end_row;
|
||||
int start_col, end_col;
|
||||
|
|
@ -91,12 +91,12 @@ foreach_selected_normal(
|
|||
|
||||
static void
|
||||
foreach_selected_block(
|
||||
struct terminal *term,
|
||||
struct terminal *term, struct coord _start, struct coord _end,
|
||||
void (*cb)(struct terminal *term, struct row *row, struct cell *cell, void *data),
|
||||
void *data)
|
||||
{
|
||||
const struct coord *start = &term->selection.start;
|
||||
const struct coord *end = &term->selection.end;
|
||||
const struct coord *start = &_start;
|
||||
const struct coord *end = &_end;
|
||||
|
||||
struct coord top_left = {
|
||||
.row = min(start->row, end->row),
|
||||
|
|
@ -120,16 +120,16 @@ foreach_selected_block(
|
|||
|
||||
static void
|
||||
foreach_selected(
|
||||
struct terminal *term,
|
||||
struct terminal *term, struct coord start, struct coord end,
|
||||
void (*cb)(struct terminal *term, struct row *row, struct cell *cell, void *data),
|
||||
void *data)
|
||||
{
|
||||
switch (term->selection.kind) {
|
||||
case SELECTION_NORMAL:
|
||||
return foreach_selected_normal(term, cb, data);
|
||||
return foreach_selected_normal(term, start, end, cb, data);
|
||||
|
||||
case SELECTION_BLOCK:
|
||||
return foreach_selected_block(term, cb, data);
|
||||
return foreach_selected_block(term, start, end, cb, data);
|
||||
|
||||
case SELECTION_NONE:
|
||||
assert(false);
|
||||
|
|
@ -251,7 +251,9 @@ extract_selection(const struct terminal *term)
|
|||
.size = buf_size,
|
||||
};
|
||||
|
||||
foreach_selected((struct terminal *)term, &extract_one, &ctx);
|
||||
foreach_selected(
|
||||
(struct terminal *)term, term->selection.start, term->selection.end,
|
||||
&extract_one, &ctx);
|
||||
|
||||
if (ctx.idx == 0) {
|
||||
/* Selection of empty cells only */
|
||||
|
|
@ -300,8 +302,10 @@ static void
|
|||
unmark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||
void *data)
|
||||
{
|
||||
if (!cell->attrs.selected)
|
||||
if (cell->attrs.selected == 0 || (cell->attrs.selected & 2)) {
|
||||
/* Ignore if already deselected, or if premarked for updated selection */
|
||||
return;
|
||||
}
|
||||
|
||||
row->dirty = 1;
|
||||
cell->attrs.selected = 0;
|
||||
|
|
@ -309,11 +313,21 @@ unmark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
|||
}
|
||||
|
||||
static void
|
||||
mark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||
void *data)
|
||||
premark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||
void *data)
|
||||
{
|
||||
if (cell->attrs.selected)
|
||||
/* Tell unmark to leave this be */
|
||||
cell->attrs.selected |= 2;
|
||||
}
|
||||
|
||||
static void
|
||||
mark_selected(struct terminal *term, struct row *row, struct cell *cell,
|
||||
void *data)
|
||||
{
|
||||
if (cell->attrs.selected & 1) {
|
||||
cell->attrs.selected = 1; /* Clear the pre-mark bit */
|
||||
return;
|
||||
}
|
||||
|
||||
row->dirty = 1;
|
||||
cell->attrs.selected = 1;
|
||||
|
|
@ -334,13 +348,26 @@ selection_update(struct terminal *term, int col, int row)
|
|||
assert(term->selection.start.row != -1);
|
||||
assert(term->grid->view + row != -1);
|
||||
|
||||
if (term->selection.end.row != -1)
|
||||
foreach_selected(term, &unmark_selected, NULL);
|
||||
struct coord new_end = {col, term->grid->view + row};
|
||||
|
||||
term->selection.end = (struct coord){col, term->grid->view + row};
|
||||
/* Premark all cells that *will* be selected */
|
||||
foreach_selected(
|
||||
term, term->selection.start, new_end, &premark_selected, NULL);
|
||||
|
||||
if (term->selection.end.row != -1) {
|
||||
/* Unmark previous selection, ignoring cells that are part of
|
||||
* the new selection */
|
||||
foreach_selected(term, term->selection.start, term->selection.end,
|
||||
&unmark_selected, NULL);
|
||||
}
|
||||
|
||||
term->selection.end = new_end;
|
||||
assert(term->selection.start.row != -1 && term->selection.end.row != -1);
|
||||
foreach_selected(term, &mark_selected, NULL);
|
||||
|
||||
/* Mark new selection */
|
||||
foreach_selected(
|
||||
term, term->selection.start, term->selection.end, &mark_selected, NULL);
|
||||
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +409,9 @@ selection_cancel(struct terminal *term)
|
|||
term->selection.end.row, term->selection.end.col);
|
||||
|
||||
if (term->selection.start.row != -1 && term->selection.end.row != -1) {
|
||||
foreach_selected(term, &unmark_selected, NULL);
|
||||
foreach_selected(
|
||||
term, term->selection.start, term->selection.end,
|
||||
&unmark_selected, NULL);
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ struct attributes {
|
|||
uint32_t clean:1;
|
||||
uint32_t have_fg:1;
|
||||
uint32_t have_bg:1;
|
||||
uint32_t selected:1;
|
||||
uint32_t reserved:4;
|
||||
uint32_t selected:2;
|
||||
uint32_t reserved:3;
|
||||
uint32_t bg:24;
|
||||
};
|
||||
static_assert(sizeof(struct attributes) == 8, "bad size");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue