aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ui_compositor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ui_compositor.c')
-rw-r--r--src/nvim/ui_compositor.c113
1 files changed, 86 insertions, 27 deletions
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index c7ba0306e4..e52ba437ee 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -17,6 +17,7 @@
#include "nvim/ui.h"
#include "nvim/highlight.h"
#include "nvim/memory.h"
+#include "nvim/popupmnu.h"
#include "nvim/ui_compositor.h"
#include "nvim/ugrid.h"
#include "nvim/screen.h"
@@ -55,7 +56,6 @@ void ui_comp_init(void)
compositor->rgb = true;
compositor->grid_resize = ui_comp_grid_resize;
- compositor->grid_clear = ui_comp_grid_clear;
compositor->grid_scroll = ui_comp_grid_scroll;
compositor->grid_cursor_goto = ui_comp_grid_cursor_goto;
compositor->raw_line = ui_comp_raw_line;
@@ -107,10 +107,12 @@ bool ui_comp_should_draw(void)
/// TODO(bfredl): later on the compositor should just use win_float_pos events,
/// though that will require slight event order adjustment: emit the win_pos
/// events in the beginning of update_screen(0), rather than in ui_flush()
-bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width)
+bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
+ bool valid, bool on_top)
{
+ bool moved;
if (grid->comp_index != 0) {
- bool moved = (row != grid->comp_row) || (col != grid->comp_col);
+ moved = (row != grid->comp_row) || (col != grid->comp_col);
if (ui_comp_should_draw()) {
// Redraw the area covered by the old position, and is not covered
// by the new position. Disable the grid so that compose_area() will not
@@ -134,21 +136,41 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width)
}
grid->comp_row = row;
grid->comp_col = col;
- return moved;
- }
+ } else {
+ moved = true;
#ifndef NDEBUG
- for (size_t i = 0; i < kv_size(layers); i++) {
- if (kv_A(layers, i) == grid) {
- assert(false);
+ for (size_t i = 0; i < kv_size(layers); i++) {
+ if (kv_A(layers, i) == grid) {
+ assert(false);
+ }
}
- }
#endif
- // not found: new grid
- kv_push(layers, grid);
- grid->comp_row = row;
- grid->comp_col = col;
- grid->comp_index = kv_size(layers)-1;
- return true;
+
+ size_t insert_at = kv_size(layers);
+ if (kv_A(layers, insert_at-1) == &pum_grid) {
+ insert_at--;
+ }
+ if (insert_at > 1 && !on_top) {
+ insert_at--;
+ }
+ // not found: new grid
+ kv_push(layers, grid);
+ if (insert_at < kv_size(layers)-1) {
+ for (size_t i = kv_size(layers)-1; i > insert_at; i--) {
+ kv_A(layers, i) = kv_A(layers, i-i);
+ }
+ kv_A(layers, insert_at) = grid;
+ }
+
+ grid->comp_row = row;
+ grid->comp_col = col;
+ grid->comp_index = insert_at;
+ }
+ if (moved && valid && ui_comp_should_draw()) {
+ compose_area(grid->comp_row, grid->comp_row+grid->Rows,
+ grid->comp_col, grid->comp_col+grid->Columns);
+ }
+ return moved;
}
void ui_comp_remove_grid(ScreenGrid *grid)
@@ -194,6 +216,26 @@ bool ui_comp_set_grid(handle_T handle)
return false;
}
+static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
+{
+ size_t old_index = grid->comp_index;
+ for (size_t i = old_index; i < new_index; i++) {
+ kv_A(layers, i) = kv_A(layers, i+1);
+ kv_A(layers, i)->comp_index = i;
+ }
+ kv_A(layers, new_index) = grid;
+ grid->comp_index = new_index;
+ for (size_t i = old_index; i < new_index; i++) {
+ ScreenGrid *grid2 = kv_A(layers, i);
+ int startcol = MAX(grid->comp_col, grid2->comp_col);
+ int endcol = MIN(grid->comp_col+grid->Columns,
+ grid2->comp_col+grid2->Columns);
+ compose_area(MAX(grid->comp_row, grid2->comp_row),
+ MIN(grid->comp_row+grid->Rows, grid2->comp_row+grid2->Rows),
+ startcol, endcol);
+ }
+}
+
static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
Integer r, Integer c)
{
@@ -203,6 +245,18 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
int cursor_row = curgrid->comp_row+(int)r;
int cursor_col = curgrid->comp_col+(int)c;
+ // TODO(bfredl): maybe not the best time to do this, for efficiency we
+ // should configure all grids before entering win_update()
+ if (curgrid != &default_grid) {
+ size_t new_index = kv_size(layers)-1;
+ if (kv_A(layers, new_index) == &pum_grid) {
+ new_index--;
+ }
+ if (curgrid->comp_index < new_index) {
+ ui_comp_raise_grid(curgrid, new_index);
+ }
+ }
+
if (cursor_col >= default_grid.Columns || cursor_row >= default_grid.Rows) {
// TODO(bfredl): this happens with 'writedelay', refactor?
// abort();
@@ -211,6 +265,18 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
ui_composed_call_grid_cursor_goto(1, cursor_row, cursor_col);
}
+ScreenGrid *ui_comp_mouse_focus(int row, int col)
+{
+ // TODO(bfredl): click "through" unfocusable grids?
+ for (ssize_t i = (ssize_t)kv_size(layers)-1; i > 0; i--) {
+ ScreenGrid *grid = kv_A(layers, i);
+ if (row >= grid->comp_row && row < grid->comp_row+grid->Rows
+ && col >= grid->comp_col && col < grid->comp_col+grid->Columns) {
+ return grid;
+ }
+ }
+ return NULL;
+}
/// Baseline implementation. This is always correct, but we can sometimes
/// do something more efficient (where efficiency means smaller deltas to
@@ -260,7 +326,7 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
// 'pumblend'
- if (grid != &default_grid && p_pb) {
+ if (grid == &pum_grid && p_pb) {
for (int i = col-(int)startcol; i < until-startcol; i++) {
bool thru = strequal((char *)linebuf[i], " "); // negative space
attrbuf[i] = (sattr_T)hl_blend_attrs(bg_attrs[i], attrbuf[i], thru);
@@ -348,7 +414,8 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
assert(row < default_grid.Rows);
assert(clearcol <= default_grid.Columns);
if (flags & kLineFlagInvalid
- || kv_size(layers) > (p_pb ? 1 : curgrid->comp_index+1)) {
+ || kv_size(layers) > curgrid->comp_index+1
+ || (p_pb && curgrid == &pum_grid)) {
compose_line(row, startcol, clearcol, flags);
} else {
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
@@ -359,17 +426,9 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
/// The screen is invalid and will soon be cleared
///
/// Don't redraw floats until screen is cleared
-void ui_comp_invalidate_screen(void)
-{
- valid_screen = false;
-}
-
-static void ui_comp_grid_clear(UI *ui, Integer grid)
+void ui_comp_set_screen_valid(bool valid)
{
- // By design, only first grid uses clearing.
- assert(grid == 1);
- ui_composed_call_grid_clear(1);
- valid_screen = true;
+ valid_screen = valid;
}
// TODO(bfredl): These events are somewhat of a hack. multiline messages