mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-25 01:40:19 -05:00
mouse scrolling and selection
This commit is contained in:
parent
a163484f25
commit
5fc55b8fbd
7 changed files with 147 additions and 66 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include "selection.h"
|
||||
#include "terminal.h"
|
||||
#include "url-mode.h"
|
||||
#include "vimode.h"
|
||||
#include "util.h"
|
||||
|
||||
void
|
||||
|
|
@ -47,6 +48,7 @@ cmd_scrollback_up(struct terminal *term, int rows)
|
|||
|
||||
selection_view_up(term, new_view);
|
||||
term->grid->view = new_view;
|
||||
vimode_view_up(term, 0);
|
||||
|
||||
if (rows < term->rows) {
|
||||
term_damage_scroll(
|
||||
|
|
@ -101,6 +103,7 @@ cmd_scrollback_down(struct terminal *term, int rows)
|
|||
|
||||
selection_view_down(term, new_view);
|
||||
term->grid->view = new_view;
|
||||
vimode_view_down(term, 0);
|
||||
|
||||
if (rows < term->rows) {
|
||||
term_damage_scroll(
|
||||
|
|
|
|||
101
input.c
101
input.c
|
|
@ -501,11 +501,17 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
term_theme_toggle(term);
|
||||
return true;
|
||||
|
||||
case BIND_ACTION_SELECT_BEGIN:
|
||||
selection_start(
|
||||
term, (struct coord){.row = seat->mouse.row, .col = seat->mouse.col}, SELECTION_CHAR_WISE, false);
|
||||
case BIND_ACTION_SELECT_BEGIN: {
|
||||
struct coord const point = {.row = seat->mouse.row, .col = seat->mouse.col};
|
||||
selection_start(term, point, SELECTION_CHAR_WISE, false);
|
||||
// TODO (kociap): Single click causes selection to start
|
||||
// instead of just repositioning the cursor.
|
||||
vimode_mouse_selection_begin(term, point, VI_MODE_VISUAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO (kociap): Add vimode selection to the remaining selection
|
||||
// bindings.
|
||||
case BIND_ACTION_SELECT_BEGIN_BLOCK:
|
||||
selection_start(
|
||||
term, (struct coord){.row = seat->mouse.row, .col = seat->mouse.col}, SELECTION_BLOCK, false);
|
||||
|
|
@ -2566,6 +2572,8 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|||
break;
|
||||
|
||||
case TERM_SURF_GRID:
|
||||
// TODO (kociap): unsure what this does and when it
|
||||
// triggers.
|
||||
selection_finalize(seat, old_moused, seat->pointer.serial);
|
||||
break;
|
||||
|
||||
|
|
@ -2721,7 +2729,7 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
xassert(seat->mouse.row >= 0 && seat->mouse.row < term->rows);
|
||||
|
||||
/* Cursor has moved to a different cell since last time */
|
||||
bool cursor_is_on_new_cell
|
||||
const bool cursor_is_on_new_cell
|
||||
= old_col != seat->mouse.col || old_row != seat->mouse.row;
|
||||
|
||||
if (cursor_is_on_new_cell) {
|
||||
|
|
@ -2746,47 +2754,49 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
if (auto_scroll_direction == SELECTION_SCROLL_NOT)
|
||||
selection_stop_scroll_timer(term);
|
||||
|
||||
/* Update selection */
|
||||
if (!term->vimode.active) {
|
||||
if (auto_scroll_direction != SELECTION_SCROLL_NOT) {
|
||||
/*
|
||||
* Start 'selection auto-scrolling'
|
||||
*
|
||||
* The speed of the scrolling is proportional to the
|
||||
* distance between the mouse and the grid; the
|
||||
* further away the mouse is, the faster we scroll.
|
||||
*
|
||||
* Note that the speed is measured in 'intervals (in
|
||||
* ns) between each timed scroll of a single line'.
|
||||
*
|
||||
* Thus, the further away the mouse is, the smaller
|
||||
* interval value we use.
|
||||
*/
|
||||
if (auto_scroll_direction != SELECTION_SCROLL_NOT) {
|
||||
/*
|
||||
* Start 'selection auto-scrolling'
|
||||
*
|
||||
* The speed of the scrolling is proportional to the
|
||||
* distance between the mouse and the grid; the
|
||||
* further away the mouse is, the faster we scroll.
|
||||
*
|
||||
* Note that the speed is measured in 'intervals (in
|
||||
* ns) between each timed scroll of a single line'.
|
||||
*
|
||||
* Thus, the further away the mouse is, the smaller
|
||||
* interval value we use.
|
||||
*/
|
||||
|
||||
int distance = auto_scroll_direction == SELECTION_SCROLL_UP
|
||||
? term->margins.top - y
|
||||
: y - (term->height - term->margins.bottom);
|
||||
int distance = auto_scroll_direction == SELECTION_SCROLL_UP
|
||||
? term->margins.top - y
|
||||
: y - (term->height - term->margins.bottom);
|
||||
|
||||
xassert(distance > 0);
|
||||
int divisor
|
||||
= distance * term->conf->scrollback.multiplier / term->scale;
|
||||
xassert(distance > 0);
|
||||
int divisor
|
||||
= distance * term->conf->scrollback.multiplier / term->scale;
|
||||
|
||||
selection_start_scroll_timer(
|
||||
term, 400000000 / (divisor > 0 ? divisor : 1),
|
||||
auto_scroll_direction, seat->mouse.col);
|
||||
}
|
||||
|
||||
if (term->selection.ongoing &&
|
||||
(cursor_is_on_new_cell ||
|
||||
(term->selection.coords.end.row < 0 &&
|
||||
seat->mouse.x >= term->margins.left &&
|
||||
seat->mouse.x < term->width - term->margins.right &&
|
||||
seat->mouse.y >= term->margins.top &&
|
||||
seat->mouse.y < term->height - term->margins.bottom)))
|
||||
{
|
||||
selection_update(term, (struct coord){.row = seat->mouse.row, .col = seat->mouse.col});
|
||||
}
|
||||
selection_start_scroll_timer(
|
||||
term, 400000000 / (divisor > 0 ? divisor : 1),
|
||||
auto_scroll_direction, seat->mouse.col);
|
||||
}
|
||||
const bool mouse_in_bounds =
|
||||
seat->mouse.x >= term->margins.left &&
|
||||
seat->mouse.x < term->width - term->margins.right &&
|
||||
seat->mouse.y >= term->margins.top &&
|
||||
seat->mouse.y < term->height - term->margins.bottom;
|
||||
const bool selection_ongoing =
|
||||
(!term->vimode.active && term->selection.ongoing) ||
|
||||
term->vimode.selection.mouse_button_pressed;
|
||||
if (selection_ongoing && (cursor_is_on_new_cell ||
|
||||
(term->selection.coords.end.row < 0 && mouse_in_bounds))) {
|
||||
struct coord point = {.row = seat->mouse.row,
|
||||
.col = seat->mouse.col};
|
||||
selection_update(term, point);
|
||||
vimode_mouse_move(term, point);
|
||||
}
|
||||
|
||||
|
||||
/* Send mouse event to client application */
|
||||
if (!term_mouse_grabbed(term, seat) &&
|
||||
|
|
@ -3210,9 +3220,6 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|||
break;
|
||||
|
||||
case TERM_SURF_GRID: {
|
||||
// TODO (kociap): unsure whether mouse should cancel vimode
|
||||
// or work in tandem.
|
||||
vimode_cancel(term);
|
||||
urls_reset(term);
|
||||
|
||||
bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0;
|
||||
|
|
@ -3248,7 +3255,11 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|||
}
|
||||
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
selection_finalize(seat, term, serial);
|
||||
if (!term->vimode.active) {
|
||||
selection_finalize(seat, term, serial);
|
||||
} else {
|
||||
vimode_mouse_selection_end(term);
|
||||
}
|
||||
|
||||
if (send_to_client && !term_mouse_grabbed(term, seat)) {
|
||||
term_mouse_up(
|
||||
|
|
|
|||
|
|
@ -741,7 +741,7 @@ selection_start(struct terminal *term, struct coord const start,
|
|||
kind == SELECTION_WORD_WISE ? "word-wise" :
|
||||
kind == SELECTION_LINE_WISE ? "line-wise" :
|
||||
kind == SELECTION_BLOCK ? "block" : "<unknown>",
|
||||
row, col);
|
||||
start.row, start.col);
|
||||
|
||||
term->selection.kind = kind;
|
||||
term->selection.ongoing = true;
|
||||
|
|
|
|||
|
|
@ -3094,6 +3094,7 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
|||
|
||||
/* Cancel selections that cannot be scrolled */
|
||||
if (unlikely(term->selection.coords.end.row >= 0)) {
|
||||
// TODO (kociap): selection cancelled on scroll.
|
||||
/*
|
||||
* Selection is (partly) inside either the top or bottom
|
||||
* scrolling regions, or on (at least one) of the lines
|
||||
|
|
|
|||
|
|
@ -634,6 +634,7 @@ struct terminal {
|
|||
struct coord cursor;
|
||||
|
||||
struct {
|
||||
bool mouse_button_pressed;
|
||||
struct coord start;
|
||||
} selection;
|
||||
|
||||
|
|
|
|||
72
vimode.c
72
vimode.c
|
|
@ -460,6 +460,32 @@ void vimode_cancel(struct terminal *term)
|
|||
render_refresh(term);
|
||||
}
|
||||
|
||||
void vimode_view_up(struct terminal *term, int const delta)
|
||||
{
|
||||
if (!term->vimode.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
damage_cursor_cell(term);
|
||||
term->vimode.cursor.row += delta;
|
||||
clip_cursor_to_view(term);
|
||||
update_selection(term);
|
||||
update_highlights(term);
|
||||
}
|
||||
|
||||
void vimode_view_down(struct terminal *const term, int const delta)
|
||||
{
|
||||
if (!term->vimode.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
damage_cursor_cell(term);
|
||||
term->vimode.cursor.row -= delta;
|
||||
clip_cursor_to_view(term);
|
||||
update_selection(term);
|
||||
update_highlights(term);
|
||||
}
|
||||
|
||||
static ssize_t matches_cell(const struct terminal *term,
|
||||
const struct cell *cell, char32_t const *const buf,
|
||||
size_t const len, size_t search_ofs)
|
||||
|
|
@ -819,19 +845,6 @@ void vimode_search_add_chars(struct terminal *term, const char *src,
|
|||
on_search_string_updated(term);
|
||||
}
|
||||
|
||||
void vimode_view_down(struct terminal *const term, int const delta)
|
||||
{
|
||||
if (!term->vimode.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("VIMODE VIEW DOWN [delta=%d]", delta);
|
||||
damage_cursor_cell(term);
|
||||
term->vimode.cursor.row -= delta;
|
||||
clip_cursor_to_view(term);
|
||||
update_highlights(term);
|
||||
}
|
||||
|
||||
enum c32_class {
|
||||
CLASS_BLANK,
|
||||
CLASS_PUNCTUATION,
|
||||
|
|
@ -1738,3 +1751,36 @@ void vimode_input(struct seat *seat, struct terminal *term,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vimode_mouse_selection_begin(struct terminal *const term,
|
||||
struct coord const point,
|
||||
enum vi_mode const vmode)
|
||||
{
|
||||
if (term->vimode.active == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_mode_visual(vmode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
term->vimode.selection.mouse_button_pressed = true;
|
||||
term->vimode.selection.start = point;
|
||||
term->vimode.mode = vmode;
|
||||
damage_cursor_cell(term);
|
||||
term->vimode.cursor = cursor_from_view_relative(term, point);
|
||||
damage_cursor_cell(term);
|
||||
}
|
||||
|
||||
void vimode_mouse_selection_end(struct terminal *const term)
|
||||
{
|
||||
term->vimode.selection.mouse_button_pressed = false;
|
||||
}
|
||||
|
||||
void vimode_mouse_move(struct terminal *const term, struct coord const point)
|
||||
{
|
||||
damage_cursor_cell(term);
|
||||
term->vimode.cursor = cursor_from_view_relative(term, point);
|
||||
damage_cursor_cell(term);
|
||||
update_selection(term);
|
||||
}
|
||||
|
|
|
|||
33
vimode.h
33
vimode.h
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
void vimode_begin(struct terminal *term);
|
||||
|
||||
/* vimode_search_begin
|
||||
*
|
||||
* Enter search mode directly without needing to interact with the
|
||||
* vimode first. Enters vimode as well.
|
||||
*/
|
||||
// vimode_search_begin
|
||||
//
|
||||
// Enter search mode directly without needing to interact with the
|
||||
// vimode first. Enters vimode as well.
|
||||
//
|
||||
void vimode_search_begin(struct terminal *term);
|
||||
|
||||
void vimode_cancel(struct terminal *term);
|
||||
|
|
@ -20,6 +20,27 @@ void vimode_input(struct seat *seat, struct terminal *term,
|
|||
xkb_keysym_t sym, xkb_mod_mask_t mods,
|
||||
xkb_mod_mask_t consumed, const xkb_keysym_t *raw_syms,
|
||||
size_t raw_count, uint32_t serial);
|
||||
|
||||
// vimode_mouse_selection_begin
|
||||
//
|
||||
// Enter visual selection mode guided by a mouse. The position of the
|
||||
// vimode cursor is updated to match the position of the mouse.
|
||||
//
|
||||
// Does nothing if vimode is not active.
|
||||
//
|
||||
// Parameters:
|
||||
// point - view-relative position of the mouse.
|
||||
// vmode - the visual mode to be started. If a non-visual mode is
|
||||
// passed, the function does nothing.
|
||||
//
|
||||
void vimode_mouse_selection_begin(struct terminal *term, struct coord point,
|
||||
enum vi_mode vmode);
|
||||
void vimode_mouse_selection_end(struct terminal *term);
|
||||
void vimode_mouse_move(struct terminal *term, struct coord point);
|
||||
|
||||
void vimode_view_up(struct terminal *term, int new_view);
|
||||
void vimode_view_down(struct terminal *term, int new_view);
|
||||
|
||||
void vimode_search_add_chars(struct terminal *term, const char *text,
|
||||
size_t len);
|
||||
|
||||
|
|
@ -34,5 +55,3 @@ struct search_match_iterator search_matches_new_iter(struct terminal *term,
|
|||
char32_t const *const buf,
|
||||
size_t const len);
|
||||
struct range search_matches_next(struct search_match_iterator *iter);
|
||||
|
||||
void vimode_view_down(struct terminal *term, int delta);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue