From 6a960a9fb9382a2d571862ea5bc78f3c155c476b Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Sat, 1 Aug 2020 23:25:21 +0200 Subject: [PATCH] [viewer] New action mark-clipboard. Refs #10 Possibility to mark rectangle for clipboard. User may bind keys to move-cursor-up, move-cursor-down, move-cursor-left, move-cursor-right and mark-clipboard. mark-clipboard is tristate. First triggerred, it remembers left top corner of rectangle. Now you can move cursor. Second time triggerred, remembers right bottom corner of rectangle. Third time, it clears selection. The copy-clipboard action was changed. Now if the clipboard rectangle is marked, it copies this rectangle. If not, the current link. --- src/config/actions-main.inc | 3 +- src/config/options.inc | 3 + src/document/document.h | 9 ++ src/viewer/action.c | 6 +- src/viewer/text/draw.c | 31 +++++++ src/viewer/text/view.c | 164 +++++++++++++++++++++++++++++++++++- src/viewer/text/view.h | 4 + 7 files changed, 217 insertions(+), 3 deletions(-) diff --git a/src/config/actions-main.inc b/src/config/actions-main.inc index 56a754f92..5eed37aed 100644 --- a/src/config/actions-main.inc +++ b/src/config/actions-main.inc @@ -16,7 +16,7 @@ ACTION_(MAIN, "cache-manager", CACHE_MANAGER, N__("Open cache manager"), 0), ACTION_(MAIN, "cache-minimize", CACHE_MINIMIZE, N__("Free unused cache entries"), 0), ACTION_(MAIN, "cookie-manager", COOKIE_MANAGER, N__("Open cookie manager"), 0), ACTION_(MAIN, "cookies-load", COOKIES_LOAD, N__("Reload cookies file"), ACTION_RESTRICT_ANONYMOUS), -ACTION_(MAIN, "copy-clipboard", COPY_CLIPBOARD, N__("Copy text to clipboard"), ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION | ACTION_JUMP_TO_LINK | ACTION_REQUIRE_LINK), +ACTION_(MAIN, "copy-clipboard", COPY_CLIPBOARD, N__("Copy text to clipboard"), ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION), ACTION_(MAIN, "document-info", DOCUMENT_INFO, N__("Show information about the current page"), ACTION_JUMP_TO_LINK), ACTION_(MAIN, "download-manager", DOWNLOAD_MANAGER, N__("Open download manager"), 0), ACTION_(MAIN, "exmode", EXMODE, N__("Enter ex-mode (command line)"), 0), @@ -51,6 +51,7 @@ ACTION_(MAIN, "link-info", LINK_INFO, N__("Show information about current link") ACTION_(MAIN, "link-menu", LINK_MENU, N__("Open the link context menu"), ACTION_REQUIRE_VIEW_STATE | ACTION_JUMP_TO_LINK | ACTION_REQUIRE_LINK), ACTION_(MAIN, "link-form-menu", LINK_FORM_MENU, N__("Open the form fields menu"), ACTION_REQUIRE_VIEW_STATE | ACTION_JUMP_TO_LINK | ACTION_REQUIRE_LINK | ACTION_REQUIRE_FORM), ACTION_(MAIN, "lua-console", LUA_CONSOLE, N__("Open a Lua console"), ACTION_RESTRICT_ANONYMOUS), +ACTION_(MAIN, "mark-clipboard", MARK_CLIPBOARD, N__("Mark a corner of the clipboard rectangle"), ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION), ACTION_(MAIN, "mark-goto", MARK_GOTO, N__("Go at a specified mark"), ACTION_REQUIRE_VIEW_STATE), ACTION_(MAIN, "mark-set", MARK_SET, N__("Set a mark"), ACTION_REQUIRE_VIEW_STATE), ACTION_(MAIN, "menu", MENU, N__("Activate the menu"), 0), diff --git a/src/config/options.inc b/src/config/options.inc index 4a0c86589..5840fcf48 100644 --- a/src/config/options.inc +++ b/src/config/options.inc @@ -1284,6 +1284,9 @@ static union option_info config_options_info[] = { "separator", "brown", "white", "gray", "white", N_("Tab separator colors.")), + INIT_OPT_COLORS("", N_("Clipboard"), + "clipboard", "lime", "green", "white", "green", + N_("Clipboard highlight colors.")), INIT_OPT_COLORS("", N_("Searched strings"), "searched", "black", "lime", "black", "white", diff --git a/src/document/document.h b/src/document/document.h index b19f2464a..5d9da9178 100644 --- a/src/document/document.h +++ b/src/document/document.h @@ -42,6 +42,12 @@ enum cp_status { CP_STATUS_IGNORED }; +/** Clipboard state */ +enum clipboard_status { + CLIPBOARD_NONE, + CLIPBOARD_FIRST_POINT, + CLIPBOARD_SECOND_POINT +}; struct point { int x, y; @@ -265,6 +271,9 @@ struct document { enum cp_status cp_status; unsigned int links_sorted:1; /**< whether links are already sorted */ + + struct el_box clipboard_box; + enum clipboard_status clipboard_status; }; #define document_has_frames(document_) ((document_) && (document_)->frame_desc) diff --git a/src/viewer/action.c b/src/viewer/action.c index 7c8d268f1..734f81668 100644 --- a/src/viewer/action.c +++ b/src/viewer/action.c @@ -166,7 +166,7 @@ do_action(struct session *ses, enum main_action action_id, int verbose) break; case ACT_MAIN_COPY_CLIPBOARD: - status = copy_current_link_to_clipboard(ses, doc_view, 0); + status = copy_to_clipboard(ses, doc_view); break; case ACT_MAIN_DOCUMENT_INFO: @@ -317,6 +317,10 @@ do_action(struct session *ses, enum main_action action_id, int verbose) #endif break; + case ACT_MAIN_MARK_CLIPBOARD: + status = mark_clipboard(ses, doc_view); + break; + case ACT_MAIN_MARK_SET: #ifdef CONFIG_MARKS ses->kbdprefix.mark = KP_MARK_SET; diff --git a/src/viewer/text/draw.c b/src/viewer/text/draw.c index a38a0426f..cd251ddb8 100644 --- a/src/viewer/text/draw.c +++ b/src/viewer/text/draw.c @@ -165,6 +165,36 @@ draw_frame_lines(struct terminal *term, struct frameset_desc *frameset_desc, } } +static void +draw_clipboard(struct terminal *term, struct document_view *doc_view) +{ + struct document *document = doc_view->document; + struct color_pair *color; + int starty, startx, endy, endx, x, y, xoffset, yoffset; + + assert(term && doc_view); + if_assert_failed return; + + if (!document->clipboard_box.height || !document->clipboard_box.width) { + return; + } + + color = get_bfu_color(term, "clipboard"); + xoffset = doc_view->box.x - doc_view->vs->x; + yoffset = doc_view->box.y - doc_view->vs->y; + + starty = int_max(0, document->clipboard_box.y + yoffset); + endy = int_min(doc_view->box.height, document->clipboard_box.y + document->clipboard_box.height + yoffset); + startx = int_max(0, document->clipboard_box.x + xoffset); + endx = int_min(doc_view->box.width, document->clipboard_box.x + document->clipboard_box.width + xoffset); + + for (y = starty; y <= endy; ++y) { + for (x = startx; x <= endx; ++x) { + draw_char_color(term, x, y, color); + } + } +} + static void draw_view_status(struct session *ses, struct document_view *doc_view, int active) { @@ -173,6 +203,7 @@ draw_view_status(struct session *ses, struct document_view *doc_view, int active draw_forms(term, doc_view); if (active) { draw_searched(term, doc_view); + draw_clipboard(term, doc_view); draw_current_link(ses, doc_view); } } diff --git a/src/viewer/text/view.c b/src/viewer/text/view.c index b3affe08e..5160d8378 100644 --- a/src/viewer/text/view.c +++ b/src/viewer/text/view.c @@ -60,6 +60,8 @@ #include "viewer/text/view.h" #include "viewer/text/vs.h" +static enum frame_event_status move_clipboard_pos(struct session *ses, struct document_view *view, enum frame_event_status status); + void detach_formatted(struct document_view *doc_view) { @@ -602,15 +604,18 @@ move_cursor(struct session *ses, struct document_view *doc_view, int x, int y) return status; } + static enum frame_event_status move_cursor_rel_count(struct session *ses, struct document_view *view, int rx, int ry, int count) { + enum frame_event_status status; int x, y; x = ses->tab->x + rx*count; y = ses->tab->y + ry*count; - return move_cursor(ses, view, x, y); + status = move_cursor(ses, view, x, y); + return move_clipboard_pos(ses, view, status); } static enum frame_event_status @@ -949,6 +954,152 @@ move_cursor_line_start(struct session *ses, struct document_view *doc_view) return move_cursor_rel(ses, doc_view, -x, 0); } +static enum frame_event_status +move_clipboard_pos(struct session *ses, struct document_view *view, enum frame_event_status status) +{ + struct document *document = view->document; + int xoffset, yoffset, x, y; + + if (!document || document->clipboard_status != CLIPBOARD_FIRST_POINT) { + return status; + } + + xoffset = view->vs->x - view->box.x; + yoffset = view->vs->y - view->box.y; + x = ses->tab->x + xoffset; + y = ses->tab->y + yoffset; + + if (document->clipboard_box.x == x && document->clipboard_box.y == y) { + return status; + } + + if (document->clipboard_box.x > x || document->clipboard_box.y > y) { + return status; + } + + document->clipboard_box.height = y - document->clipboard_box.y; + document->clipboard_box.width = x - document->clipboard_box.x; + + return FRAME_EVENT_REFRESH; +} + +static enum frame_event_status +copy_to_clipboard2(struct document_view *doc_view) +{ + struct document *document = doc_view->document; + struct string data; + int starty, endy, startx, y; + int utf8; + + if (!document->clipboard_box.height || !document->clipboard_box.width) { + return FRAME_EVENT_OK; + } + + if (!init_string(&data)) { + return FRAME_EVENT_OK; + } + + starty = document->clipboard_box.y; + endy = int_min(document->clipboard_box.y + document->clipboard_box.height, document->height - 1); + startx = document->clipboard_box.x; + utf8 = document->options.utf8; + + for (y = starty; y <= endy; y++) { + int endx = int_min(document->clipboard_box.x + document->clipboard_box.width, document->data[y].length); + int x; + + for (x = startx; x < endx; x++) { +#ifdef CONFIG_UTF8 + unicode_val_T c; +#else + unsigned char c; +#endif + c = document->data[y].chars[x].data; + +#ifdef CONFIG_UTF8 + if (utf8 && c == UCS_NO_CHAR) { + /* This is the second cell of + * a double-cell character. */ + continue; + } +#endif + +#ifdef CONFIG_UTF8 + if (utf8) { + if (!isscreensafe_ucs(c)) c = ' '; + } else { + if (!isscreensafe(c)) c = ' '; + } +#else + if (!isscreensafe(c)) c = ' '; +#endif + +#ifdef CONFIG_UTF8 + if (utf8) { + add_to_string(&data, encode_utf8(c)); + } else { + add_char_to_string(&data, c); + } +#else + add_char_to_string(&data, c); +#endif + } + add_char_to_string(&data, '\n'); + } + + set_clipboard_text(data.source); + done_string(&data); + + return FRAME_EVENT_OK; + +} + +enum frame_event_status +mark_clipboard(struct session *ses, struct document_view *doc_view) +{ + struct document *document = doc_view->document; + + int xoffset = doc_view->vs->x - doc_view->box.x; + int yoffset = doc_view->vs->y - doc_view->box.y; + int x = ses->tab->x + xoffset; + int y = ses->tab->y + yoffset; + + switch (document->clipboard_status) + { + case CLIPBOARD_NONE: + document->clipboard_box.x = x; + document->clipboard_box.y = y; + document->clipboard_box.height = 0; + document->clipboard_box.width = 0; + document->clipboard_status = CLIPBOARD_FIRST_POINT; + + return FRAME_EVENT_OK; + + case CLIPBOARD_FIRST_POINT: + if (document->clipboard_box.x == x && document->clipboard_box.y == y) { + return FRAME_EVENT_OK; + } + if (document->clipboard_box.x > x || document->clipboard_box.y > y) { + return FRAME_EVENT_OK; + } + document->clipboard_box.height = y - document->clipboard_box.y; + document->clipboard_box.width = x - document->clipboard_box.x; + document->clipboard_status = CLIPBOARD_SECOND_POINT; + + return FRAME_EVENT_REFRESH; + + case CLIPBOARD_SECOND_POINT: + document->clipboard_box.x = 0; + document->clipboard_box.y = 0; + document->clipboard_box.height = 0; + document->clipboard_box.width = 0; + document->clipboard_status = CLIPBOARD_NONE; + + return FRAME_EVENT_REFRESH; + } + return FRAME_EVENT_OK; +} + enum frame_event_status copy_current_link_to_clipboard(struct session *ses, struct document_view *doc_view, @@ -975,6 +1126,17 @@ copy_current_link_to_clipboard(struct session *ses, return FRAME_EVENT_OK; } +enum frame_event_status +copy_to_clipboard(struct session *ses, struct document_view *doc_view) +{ + if (doc_view && doc_view->document + && doc_view->document->clipboard_box.height + && doc_view->document->clipboard_box.width) { + return copy_to_clipboard2(doc_view); + } + + return copy_current_link_to_clipboard(ses, doc_view, 0); +} int try_jump_to_link_number(struct session *ses, struct document_view *doc_view) diff --git a/src/viewer/text/view.h b/src/viewer/text/view.h index c598608bf..5934b15b8 100644 --- a/src/viewer/text/view.h +++ b/src/viewer/text/view.h @@ -76,6 +76,10 @@ enum frame_event_status copy_current_link_to_clipboard(struct session *ses, struct document_view *doc_view, int xxx); +enum frame_event_status copy_to_clipboard(struct session *ses, struct document_view *doc_view); + +enum frame_event_status mark_clipboard(struct session *ses, struct document_view *doc_view); + /** If the user has provided a numeric prefix, jump to the link * with that number as its index. */ int try_jump_to_link_number(struct session *ses,