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:
@@ -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; }
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user