From 28c6f505311b719db9bf26e0e24f1f1892f3c984 Mon Sep 17 00:00:00 2001 From: cy384 Date: Fri, 22 Jan 2021 19:47:48 -0500 Subject: [PATCH] initial implementation of selection and copying --- ssheven-console.c | 136 +++++++++++++++++++++++++++++++++++++++++++++- ssheven-console.h | 4 +- ssheven.c | 21 ++++++- ssheven.h | 8 +++ 4 files changed, 163 insertions(+), 6 deletions(-) diff --git a/ssheven-console.c b/ssheven-console.c index 9897bec..866cf3b 100644 --- a/ssheven-console.c +++ b/ssheven-console.c @@ -15,6 +15,9 @@ #include +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + char key_to_vterm[256] = { VTERM_KEY_NONE }; void setup_key_translation(void) @@ -149,9 +152,41 @@ inline int idx2qd(VTermColor c) } } -// p is in window local coordinates -void mouse_click(Point p, bool click) +void point_to_cell(Point p, int* x, int* y) { + *x = p.h / con.cell_width; + *y = p.v / con.cell_height; + + if (*x > con.size_x) *x = con.size_x; + if (*y > con.size_y) *y = con.size_y; +} + +void damage_selection(void) +{ + // damage all rows that have part of the selection (TODO make this better) + Rect topleft = cell_rect(0, MIN(con.select_start_y, con.select_end_y), (con.win->portRect)); + Rect bottomright = cell_rect(con.size_x, MAX(con.select_start_y, con.select_end_y), (con.win->portRect)); + + UnionRect(&topleft, &bottomright, &topleft); + InvalRect(&topleft); +} + +void update_selection_end(void) +{ + Point new_mouse; + GetMouse(&new_mouse); + point_to_cell(new_mouse, &con.select_end_x, &con.select_end_y); + + damage_selection(); +} + +// p is in window local coordinates +void mouse_click(Point p, int click) +{ + static Point last_click; + + con.mouse_state = click; + if (con.mouse_mode == CLICK_SEND) { int row = p.v / con.cell_height; @@ -161,10 +196,74 @@ void mouse_click(Point p, bool click) } else if (con.mouse_mode == CLICK_SELECT) { - // TODO: implement text selection + if (click) + { + // damage the old selection so it gets wiped from the screen + damage_selection(); + + last_click = p; + point_to_cell(p, &con.select_start_x, &con.select_start_y); + point_to_cell(p, &con.select_end_x, &con.select_end_y); + update_selection_end(); + } + else + { + int a, b, c, d; + point_to_cell(last_click, &a, &b); + point_to_cell(p, &c, &d); + + // if in same cell, cancel the selection + if (a == c && b == d) + { + con.select_start_x = -1; + con.select_start_y = -1; + con.select_end_x = -1; + con.select_end_y = -1; + } + + update_selection_end(); + } } } +size_t get_selection(char** selection) +{ + int a = con.select_start_x + con.select_start_y * con.size_x; + int b = con.select_end_x + con.select_end_y * con.size_x; + + ssize_t len = MAX(a,b) - MIN(a,b) + 1; + if (len == 0) + { + *selection = NULL; + return 0; + } + + char* output = malloc(sizeof(char) * len); + + int start_row = MIN(con.select_start_y, con.select_end_y); + int start_col = MIN(con.select_start_x, con.select_end_x); + //int end_row = MAX(con.select_start_y, con.select_end_y); + //int end_col = MAX(con.select_start_x, con.select_end_x); + + VTermPos pos = {.row = 0, .col = 0}; + ScreenCell* vtsc = NULL; + + for(int i = 0; i < len; i++) + { + pos.col = (start_col + i) % con.size_x; + pos.row = (start_row + (i / con.size_x)); + + vtsc = vterm_screen_unsafe_get_cell(con.vts, pos); + output[i] = (char)vtsc->chars[0]; + } + + output[len-1] = '\0'; + + *selection = output; + + return len; +} + void draw_screen_color(Rect* r) { // get the intersection of our console region and the update region @@ -208,6 +307,32 @@ void draw_screen_color(Rect* r) ScreenCell* vtsc = NULL; VTermPos pos = {.row = 0, .col = 0}; + int i = 0; + int select_start = -1; + int select_end = -1; + + if (con.mouse_mode == CLICK_SELECT && con.mouse_state) update_selection_end(); + + if (con.mouse_mode == CLICK_SELECT && con.select_start_x != -1) + { + int a = con.select_start_x + con.select_start_y * con.size_x; + int b = con.select_end_x + con.select_end_y * con.size_x; + + if (a < b) + { + select_start = a; + select_end = b; + } + else + { + select_start = b; + select_end = a; + } + + select_start = MIN(a,b); + select_end = MAX(a,b); + } + for(pos.row = minRow; pos.row < maxRow; pos.row++) { for (pos.col = minCol; pos.col < maxCol; pos.col++) @@ -233,6 +358,11 @@ void draw_screen_color(Rect* r) { InvertRect(&cr); } + if (i < select_end && i >= select_start) + { + InvertRect(&cr); + } + i++; } } diff --git a/ssheven-console.h b/ssheven-console.h index 1695c99..1d0deb3 100644 --- a/ssheven-console.h +++ b/ssheven-console.h @@ -17,6 +17,8 @@ void printf_i(const char* c, ...); void check_cursor(void); -void mouse_click(Point p, bool click); +void mouse_click(Point p, int click); void update_console_colors(void); + +size_t get_selection(char** selection); diff --git a/ssheven.c b/ssheven.c index 565fc19..a593e06 100644 --- a/ssheven.c +++ b/ssheven.c @@ -25,7 +25,7 @@ #include // sinful globals -struct ssheven_console con = { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 1, CLICK_SELECT, NULL, NULL }; +struct ssheven_console con = { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, CLICK_SELECT, NULL, NULL }; struct ssheven_ssh_connection ssh_con = { NULL, NULL, kOTInvalidEndpointRef, NULL, NULL }; struct preferences prefs; @@ -288,6 +288,19 @@ void ssh_paste(void) DisposeHandle(buf); } +void ssh_copy(void) +{ + OSErr e = ZeroScrap(); + if (e != noErr) printf_i("Failed to ZeroScrap!"); + + char* selection = NULL; + size_t len = get_selection(&selection); + if (selection == NULL || len == 0) return; + + e = PutScrap(len, 'TEXT', selection); + if (e != noErr) printf_i("Failed to PutScrap!"); +} + int qd_color_to_menu_item(int qd_color) { switch (qd_color) @@ -417,6 +430,7 @@ int process_menu_select(int32_t result) break; case MENU_EDIT: + if (item == 4) ssh_copy(); if (item == 5) ssh_paste(); break; @@ -479,6 +493,9 @@ int handle_keypress(EventRecord* event) case 'v': ssh_paste(); break; + case 'c': + ssh_copy(); + break; default: break; } @@ -1088,7 +1105,7 @@ int main(int argc, char** argv) menu = GetMenuHandle(MENU_EDIT); DisableItem(menu, 1); DisableItem(menu, 3); - DisableItem(menu, 4); + //DisableItem(menu, 4); DisableItem(menu, 5); DisableItem(menu, 6); DisableItem(menu, 7); diff --git a/ssheven.h b/ssheven.h index 81c9ecf..75b6cc0 100644 --- a/ssheven.h +++ b/ssheven.h @@ -37,6 +37,14 @@ struct ssheven_console long int last_cursor_blink; int cursor_visible; + int select_start_x; + int select_start_y; + + int select_end_x; + int select_end_y; + + int mouse_state; // 1 for down, 0 for up + enum { CLICK_SEND, CLICK_SELECT } mouse_mode; VTerm* vterm;