Allow double-click and triple-click + drag to extend selections word at a time or line at a time. Fixes #400

This commit is contained in:
Kovid Goyal
2018-03-26 16:48:28 +05:30
parent 09710425ab
commit 90cc785b55
3 changed files with 38 additions and 24 deletions

View File

@@ -23,7 +23,6 @@ typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
#define MOTION_INDICATOR (1 << 5)
#define EXTRA_BUTTON_INDICATOR (1 << 6)
static int last_multi_clicks = 0;
static inline unsigned int
button_map(int button) {
@@ -121,10 +120,9 @@ update_drag(bool from_button, Window *w, bool is_release, int modifiers) {
Screen *screen = w->render_data.screen;
if (from_button) {
if (is_release) screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, true);
else screen_start_selection(screen, w->mouse_cell_x, w->mouse_cell_y, modifiers == (int)OPT(rectangle_select_modifiers));
else screen_start_selection(screen, w->mouse_cell_x, w->mouse_cell_y, modifiers == (int)OPT(rectangle_select_modifiers), EXTEND_CELL);
} else if (screen->selection.in_progress) {
screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, false);
call_boss(set_primary_selection, NULL);
}
}
@@ -155,12 +153,8 @@ drag_scroll(Window *w, OSWindow *frame) {
static inline void
extend_selection(Window *w) {
Screen *screen = w->render_data.screen;
index_type start, end;
if (screen_has_selection(screen)) {
bool found_selectable_word = screen_selection_range_for_word(screen, w->mouse_cell_x, w->mouse_cell_y, &start, &end);
if (last_multi_clicks >= 2 && found_selectable_word) screen_update_selection(screen, end, w->mouse_cell_y, true);
else screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, false);
call_boss(set_primary_selection, NULL);
screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, false);
}
}
@@ -237,20 +231,22 @@ multi_click(Window *w, unsigned int count) {
Screen *screen = w->render_data.screen;
index_type start, end;
bool found_selection = false;
SelectionExtendMode mode = EXTEND_CELL;
switch(count) {
case 2:
found_selection = screen_selection_range_for_word(screen, w->mouse_cell_x, w->mouse_cell_y, &start, &end);
mode = EXTEND_WORD;
break;
case 3:
found_selection = screen_selection_range_for_line(screen, w->mouse_cell_y, &start, &end);
mode = EXTEND_LINE;
break;
default:
break;
}
if (found_selection) {
screen_start_selection(screen, start, w->mouse_cell_y, false);
screen_update_selection(screen, end, w->mouse_cell_y, true);
call_boss(set_primary_selection, NULL);
screen_start_selection(screen, start, w->mouse_cell_y, false, mode);
screen_update_selection(screen, end, w->mouse_cell_y, false);
}
}
@@ -263,11 +259,9 @@ HANDLER(add_click) {
q->length++;
// Now dispatch the multi-click if any
if (q->length > 2 && N(1).at - N(3).at <= 2 * OPT(click_interval)) {
last_multi_clicks = 3;
multi_click(w, 3);
q->length = 0;
} else if (q->length > 1 && N(1).at - N(2).at <= OPT(click_interval)) {
last_multi_clicks = 2;
multi_click(w, 2);
}
#undef N
@@ -297,14 +291,9 @@ HANDLER(handle_button_event) {
switch(button) {
case GLFW_MOUSE_BUTTON_LEFT:
update_drag(true, w, is_release, modifiers);
last_multi_clicks = 0;
if (is_release) {
if (modifiers == (int)OPT(open_url_modifiers)) {
open_url(w);
} else {
if (is_release) add_click(w, button, modifiers, window_idx);
}
}
if (modifiers == (int)OPT(open_url_modifiers)) open_url(w);
} else add_click(w, button, modifiers, window_idx);
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
if (is_release && !modifiers) { call_boss(paste_from_selection, NULL); return; }

View File

@@ -1626,9 +1626,17 @@ WRAP0(carriage_return)
WRAP2(resize, 1, 1)
WRAP2(set_margins, 1, 1)
WRAP2(rescale_images, 1, 1)
WRAP2B(start_selection)
WRAP2B(update_selection)
static PyObject*
start_selection(Screen *self, PyObject *args) {
unsigned int x, y;
int rectangle_select = 0, extend_mode = EXTEND_CELL;
if (!PyArg_ParseTuple(args, "II|pp", &x, &y, &rectangle_select, &extend_mode)) return NULL;
screen_start_selection(self, x, y, rectangle_select, extend_mode);
Py_RETURN_NONE;
}
static PyObject*
change_scrollback_size(Screen *self, PyObject *args) {
unsigned int count = 1;
@@ -1733,10 +1741,10 @@ screen_is_selection_dirty(Screen *self) {
}
void
screen_start_selection(Screen *self, index_type x, index_type y, bool rectangle_select) {
screen_start_selection(Screen *self, index_type x, index_type y, bool rectangle_select, SelectionExtendMode extend_mode) {
#define A(attr, val) self->selection.attr = val;
A(start_x, x); A(end_x, x); A(start_y, y); A(end_y, y); A(start_scrolled_by, self->scrolled_by); A(end_scrolled_by, self->scrolled_by);
A(in_progress, true); A(rectangle_select, rectangle_select);
A(in_progress, true); A(rectangle_select, rectangle_select); A(extend_mode, extend_mode);
#undef A
}
@@ -1751,6 +1759,20 @@ void
screen_update_selection(Screen *self, index_type x, index_type y, bool ended) {
self->selection.end_x = x; self->selection.end_y = y; self->selection.end_scrolled_by = self->scrolled_by;
if (ended) self->selection.in_progress = false;
index_type start, end;
bool found = false;
switch(self->selection.extend_mode) {
case EXTEND_WORD:
found = screen_selection_range_for_word(self, x, y, &start, &end);
break;
case EXTEND_LINE:
found = screen_selection_range_for_line(self, y, &start, &end);
break;
case EXTEND_CELL:
break;
}
if (found) self->selection.end_x = end;
call_boss(set_primary_selection, NULL);
}
static PyObject*

View File

@@ -22,9 +22,12 @@ typedef struct {
unsigned int x, y;
} SelectionBoundary;
typedef enum SelectionExtendModes { EXTEND_CELL, EXTEND_WORD, EXTEND_LINE } SelectionExtendMode;
typedef struct {
unsigned int start_x, start_y, start_scrolled_by, end_x, end_y, end_scrolled_by;
bool in_progress, rectangle_select;
SelectionExtendMode extend_mode;
} Selection;
#define SAVEPOINTS_SZ 256
@@ -156,7 +159,7 @@ void screen_update_cell_data(Screen *self, void *address, size_t sz);
bool screen_is_cursor_visible(Screen *self);
bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end);
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, bool);
void screen_start_selection(Screen *self, index_type x, index_type y, bool, SelectionExtendMode);
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);