Implement drag scrolling in C
This commit is contained in:
parent
a27004da35
commit
4feaf13556
@ -475,6 +475,8 @@ render_cursor(Window *w, double now) {
|
||||
}
|
||||
}
|
||||
|
||||
extern bool drag_scroll(Window *);
|
||||
|
||||
static inline bool
|
||||
render(ChildMonitor *self, double now) {
|
||||
double time_since_last_render = now - last_render_at;
|
||||
@ -489,6 +491,14 @@ render(ChildMonitor *self, double now) {
|
||||
Window *w = tab->windows + i;
|
||||
#define WD w->render_data
|
||||
if (w->visible && WD.screen) {
|
||||
if (w->last_drag_scroll_at > 0) {
|
||||
if (now - w->last_drag_scroll_at >= 0.02) {
|
||||
if (drag_scroll(w)) {
|
||||
w->last_drag_scroll_at = now;
|
||||
set_maximum_wait(0.02);
|
||||
} else w->last_drag_scroll_at = 0;
|
||||
} else set_maximum_wait(now - w->last_drag_scroll_at);
|
||||
}
|
||||
draw_cells(WD.vao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen);
|
||||
if (WD.screen->start_visual_bell_at != 0) {
|
||||
double bell_left = global_state.opts.visual_bell_duration - (now - WD.screen->start_visual_bell_at);
|
||||
|
||||
@ -34,6 +34,7 @@ typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_U
|
||||
#define ERROR_PREFIX "[PARSE ERROR]"
|
||||
typedef enum MouseTrackingModes { NO_TRACKING, BUTTON_MODE, MOTION_MODE, ANY_MODE } MouseTrackingMode;
|
||||
typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL} MouseTrackingProtocol;
|
||||
typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
||||
|
||||
#define MAX_CHILDREN 256
|
||||
#define BLANK_CHAR 0
|
||||
|
||||
22
kitty/glfw.c
22
kitty/glfw.c
@ -37,7 +37,7 @@ typedef struct {
|
||||
|
||||
GLFWwindow *window;
|
||||
PyObject *framebuffer_size_callback, *char_mods_callback, *key_callback, *mouse_button_callback, *scroll_callback, *cursor_pos_callback, *window_focus_callback;
|
||||
GLFWcursor *standard_cursor, *click_cursor;
|
||||
GLFWcursor *standard_cursor, *click_cursor, *arrow_cursor;
|
||||
} WindowWrapper;
|
||||
|
||||
// callbacks {{{
|
||||
@ -111,8 +111,18 @@ window_focus_callback(GLFWwindow UNUSED *w, int focused) {
|
||||
// }}}
|
||||
|
||||
void
|
||||
set_click_cursor(bool yes) {
|
||||
glfwSetCursor(the_window->window, yes ? the_window->click_cursor : the_window->standard_cursor);
|
||||
set_mouse_cursor(MouseShape type) {
|
||||
switch(type) {
|
||||
case HAND:
|
||||
glfwSetCursor(the_window->window, the_window->click_cursor);
|
||||
break;
|
||||
case ARROW:
|
||||
glfwSetCursor(the_window->window, the_window->arrow_cursor);
|
||||
break;
|
||||
default:
|
||||
glfwSetCursor(the_window->window, the_window->standard_cursor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@ -131,8 +141,10 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
global_state.viewport_width = width; global_state.viewport_height = height;
|
||||
self->standard_cursor = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||
self->click_cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||
if (self->standard_cursor == NULL || self->click_cursor == NULL) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL; }
|
||||
set_click_cursor(false);
|
||||
self->arrow_cursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
if (self->standard_cursor == NULL || self->click_cursor == NULL || self->arrow_cursor == NULL) {
|
||||
Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL; }
|
||||
set_mouse_cursor(0);
|
||||
glfwSetFramebufferSizeCallback(self->window, framebuffer_size_callback);
|
||||
glfwSetCharModsCallback(self->window, char_mods_callback);
|
||||
glfwSetKeyCallback(self->window, key_callback);
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
#include "lineops.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
extern void set_click_cursor(bool yes);
|
||||
static bool has_click_cursor = false;
|
||||
extern void set_mouse_cursor(MouseShape);
|
||||
static MouseShape mouse_cursor_shape = BEAM;
|
||||
|
||||
#define call_boss(name, ...) { \
|
||||
PyObject *cret_ = PyObject_CallMethod(global_state.boss, #name, __VA_ARGS__); \
|
||||
@ -52,12 +52,37 @@ update_drag(bool from_button, Window *w, bool is_release) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
drag_scroll(Window *w) {
|
||||
unsigned int margin = global_state.cell_height / 2;
|
||||
double x = global_state.mouse_x, y = global_state.mouse_y;
|
||||
if (y < w->geometry.top || y > w->geometry.bottom) return false;
|
||||
if (x < w->geometry.left || x > w->geometry.right) return false;
|
||||
bool upwards = y <= w->geometry.top + margin ? true : false;
|
||||
if (upwards || y >= w->geometry.bottom - margin) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
if (screen->linebuf == screen->main_linebuf) {
|
||||
screen_history_scroll(screen, SCROLL_LINE, upwards);
|
||||
update_drag(false, w, false);
|
||||
global_state.last_mouse_activity_at = monotonic();
|
||||
if (mouse_cursor_shape != ARROW) {
|
||||
mouse_cursor_shape = ARROW;
|
||||
set_mouse_cursor(mouse_cursor_shape);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
HANDLER(handle_move_event) {
|
||||
unsigned int x, y;
|
||||
if (!cell_for_pos(w, &x, &y)) return;
|
||||
Line *line = screen_visual_line(w->render_data.screen, y);
|
||||
has_click_cursor = (line && line_url_start_at(line, x) < line->xnum) ? true : false;
|
||||
if (x == w->mouse_cell_x && y == w->mouse_cell_y) return;
|
||||
mouse_cursor_shape = (line && line_url_start_at(line, x) < line->xnum) ? HAND : BEAM;
|
||||
bool mouse_cell_changed = x != w->mouse_cell_x || y != w->mouse_cell_y ? true : false;
|
||||
w->mouse_cell_x = x; w->mouse_cell_y = y;
|
||||
Screen *screen = w->render_data.screen;
|
||||
bool handle_in_kitty = (
|
||||
@ -67,9 +92,14 @@ HANDLER(handle_move_event) {
|
||||
) ? false : true;
|
||||
if (handle_in_kitty) {
|
||||
if (screen->selection.in_progress && button == GLFW_MOUSE_BUTTON_LEFT) {
|
||||
update_drag(false, w, false);
|
||||
double now = monotonic();
|
||||
if ((now - w->last_drag_scroll_at) >= 0.02 || mouse_cell_changed) {
|
||||
update_drag(false, w, false);
|
||||
w->last_drag_scroll_at = monotonic();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!mouse_cell_changed) return;
|
||||
// TODO: Implement this
|
||||
}
|
||||
}
|
||||
@ -174,11 +204,10 @@ handle_tab_bar_mouse(int button, int UNUSED modifiers) {
|
||||
|
||||
void
|
||||
mouse_event(int button, int modifiers) {
|
||||
bool old_has_click_cursor = has_click_cursor;
|
||||
MouseShape old_cursor = mouse_cursor_shape;
|
||||
bool in_tab_bar = global_state.num_tabs > 1 && global_state.mouse_y >= global_state.viewport_height - global_state.cell_height ? true : false;
|
||||
has_click_cursor = false;
|
||||
if (in_tab_bar) {
|
||||
has_click_cursor = true;
|
||||
mouse_cursor_shape = HAND;
|
||||
handle_tab_bar_mouse(button, modifiers);
|
||||
} else {
|
||||
Tab *t = global_state.tabs + global_state.active_tab;
|
||||
@ -189,7 +218,7 @@ mouse_event(int button, int modifiers) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (has_click_cursor != old_has_click_cursor) {
|
||||
set_click_cursor(has_click_cursor);
|
||||
if (mouse_cursor_shape != old_cursor) {
|
||||
set_mouse_cursor(mouse_cursor_shape);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,6 @@
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#define SCROLL_LINE -1
|
||||
#define SCROLL_PAGE -2
|
||||
#define SCROLL_FULL -3
|
||||
|
||||
#define EXTRA_INIT PyModule_AddIntMacro(module, SCROLL_LINE); PyModule_AddIntMacro(module, SCROLL_PAGE); PyModule_AddIntMacro(module, SCROLL_FULL);
|
||||
|
||||
#include "state.h"
|
||||
@ -1371,10 +1367,8 @@ screen_selection_range_for_word(Screen *self, index_type x, index_type y, index_
|
||||
#undef is_ok
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
scroll(Screen *self, PyObject *args) {
|
||||
int amt, upwards;
|
||||
if (!PyArg_ParseTuple(args, "ip", &amt, &upwards)) return NULL;
|
||||
bool
|
||||
screen_history_scroll(Screen *self, int amt, bool upwards) {
|
||||
switch(amt) {
|
||||
case SCROLL_LINE:
|
||||
amt = 1;
|
||||
@ -1386,24 +1380,28 @@ scroll(Screen *self, PyObject *args) {
|
||||
amt = self->historybuf->count;
|
||||
break;
|
||||
default:
|
||||
if (amt < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "scroll amounts must be positive numbers");
|
||||
return NULL;
|
||||
}
|
||||
amt = MAX(0, amt);
|
||||
break;
|
||||
}
|
||||
if (!upwards) {
|
||||
amt = MIN((unsigned int)amt, self->scrolled_by);
|
||||
amt *= -1;
|
||||
}
|
||||
if (amt != 0) {
|
||||
unsigned int new_scroll = MIN(self->scrolled_by + amt, self->historybuf->count);
|
||||
if (new_scroll != self->scrolled_by) {
|
||||
self->scrolled_by = new_scroll;
|
||||
self->scroll_changed = true;
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
if (amt == 0) return false;
|
||||
unsigned int new_scroll = MIN(self->scrolled_by + amt, self->historybuf->count);
|
||||
if (new_scroll != self->scrolled_by) {
|
||||
self->scrolled_by = new_scroll;
|
||||
self->scroll_changed = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
scroll(Screen *self, PyObject *args) {
|
||||
int amt, upwards;
|
||||
if (!PyArg_ParseTuple(args, "ip", &amt, &upwards)) return NULL;
|
||||
if (screen_history_scroll(self, amt, upwards)) { Py_RETURN_TRUE; }
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } ScrollType;
|
||||
|
||||
void screen_align(Screen*);
|
||||
void screen_restore_cursor(Screen *);
|
||||
void screen_save_cursor(Screen *);
|
||||
@ -68,6 +70,7 @@ bool screen_selection_range_for_line(Screen *self, index_type y, index_type *sta
|
||||
bool screen_selection_range_for_word(Screen *self, index_type x, index_type y, index_type *start, index_type *end);
|
||||
void screen_start_selection(Screen *self, index_type x, index_type y);
|
||||
void screen_update_selection(Screen *self, index_type x, index_type y, bool ended);
|
||||
bool screen_history_scroll(Screen *self, int amt, bool upwards);
|
||||
Line* screen_visual_line(Screen *self, index_type y);
|
||||
unsigned long screen_current_char_width(Screen *self);
|
||||
#define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen);
|
||||
@ -76,4 +79,3 @@ DECLARE_CH_SCREEN_HANDLER(backspace)
|
||||
DECLARE_CH_SCREEN_HANDLER(tab)
|
||||
DECLARE_CH_SCREEN_HANDLER(linefeed)
|
||||
DECLARE_CH_SCREEN_HANDLER(carriage_return)
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ typedef struct {
|
||||
unsigned int mouse_cell_x, mouse_cell_y;
|
||||
WindowGeometry geometry;
|
||||
ClickQueue click_queue;
|
||||
double last_drag_scroll_at;
|
||||
} Window;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user