?? link.c
字號:
/* Links viewing/manipulation handling *//* $Id: link.c,v 1.309.2.6 2005/05/01 21:00:42 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#include "elinks.h"#include "bfu/listmenu.h"#include "bfu/menu.h"#include "dialogs/menu.h"#include "dialogs/status.h"#include "document/document.h"#include "document/forms.h"#include "document/html/parser.h"#include "document/html/renderer.h"#include "document/options.h"#include "document/view.h"#include "ecmascript/ecmascript.h"#include "intl/gettext/libintl.h"#include "protocol/uri.h"#include "sched/session.h"#include "sched/task.h"#include "terminal/color.h"#include "terminal/draw.h"#include "terminal/kbd.h"#include "terminal/screen.h"#include "terminal/tab.h"#include "terminal/terminal.h"#include "util/conv.h"#include "util/error.h"#include "util/memory.h"#include "util/object.h"#include "util/string.h"#include "viewer/text/form.h"#include "viewer/text/link.h"#include "viewer/text/search.h"#include "viewer/text/textarea.h"#include "viewer/text/view.h"#include "viewer/text/vs.h"/* Perhaps some of these would be more fun to have in viewer/common/, dunno. * --pasky */static intcurrent_link_evhook(struct document_view *doc_view, enum script_event_hook_type type){#ifdef CONFIG_ECMASCRIPT struct link *link; struct script_event_hook *evhook; assert(doc_view && doc_view->vs); link = get_current_link(doc_view); if (!link) return -1; if (!link->event_hooks) return -1; if (!doc_view->vs->ecmascript) return -1; foreach (evhook, *link->event_hooks) { struct string src = INIT_STRING(evhook->src, strlen(evhook->src)); if (evhook->type != type) continue; /* TODO: Some even handlers return a bool. */ if (!ecmascript_eval_boolback(doc_view->vs->ecmascript, &src)) return 0; } return 1;#else return -1;#endif}#define current_link_hover(dv) \do { \ current_link_evhook(dv, SEVHOOK_ONMOUSEOVER); \ current_link_evhook(dv, SEVHOOK_ONHOVER); \ current_link_evhook(dv, SEVHOOK_ONFOCUS); \} while (0)#define current_link_blur(dv) \do { \ current_link_evhook(dv, SEVHOOK_ONMOUSEOUT); \ current_link_evhook(dv, SEVHOOK_ONBLUR); \} while (0)voidset_link(struct document_view *doc_view){ assert(doc_view); if_assert_failed return; if (current_link_is_visible(doc_view)) return; find_link_page_down(doc_view);}static inline intget_link_cursor_offset(struct document_view *doc_view, struct link *link){ struct form_control *fc; struct form_state *fs; switch (link->type) { case LINK_CHECKBOX: return 1; case LINK_BUTTON: return 2; case LINK_FIELD: fc = get_link_form_control(link); fs = find_form_state(doc_view, fc); return fs ? fs->state - fs->vpos : 0; case LINK_AREA: fc = get_link_form_control(link); fs = find_form_state(doc_view, fc); return fs ? area_cursor(fc, fs) : 0; case LINK_HYPERTEXT: case LINK_MAP: case LINK_SELECT: return 0; } return 0;}/* Allocate doc_view->link_bg with enough space to save the colour * and attributes of each point of the given link plus one byte * for the template character. Initialise that template character * with the colour and attributes appropriate for an active link. */static inline struct screen_char *init_link_drawing(struct document_view *doc_view, struct link *link, int invert){ struct document_options *doc_opts; struct screen_char *template; enum color_flags color_flags; enum color_mode color_mode; struct color_pair colors; /* Allocate an extra background char to work on here. */ doc_view->link_bg = mem_alloc((1 + link->npoints) * sizeof(*doc_view->link_bg)); if (!doc_view->link_bg) return NULL; doc_view->link_bg_n = link->npoints; /* Setup the template char. */ template = &doc_view->link_bg[link->npoints].c; template->attr = SCREEN_ATTR_STANDOUT; /* For the color mode options we use the options set for the document. * But for the active link options we prefer to use the global * global_doc_opts since it is kept up to date by an option change * hook. However if it is not available fall back to use the options * from the viewed document. */ doc_opts = &doc_view->document->options; color_flags = (doc_opts->color_flags | COLOR_DECREASE_LIGHTNESS); color_mode = doc_opts->color_mode; if (global_doc_opts) doc_opts = global_doc_opts; if (doc_opts->underline_active_link) template->attr |= SCREEN_ATTR_UNDERLINE; if (doc_opts->bold_active_link) template->attr |= SCREEN_ATTR_BOLD; if (doc_opts->color_active_link) { colors.foreground = doc_opts->active_link_fg; colors.background = doc_opts->active_link_bg; } else { colors.foreground = link->color.foreground; colors.background = link->color.background; } if (doc_opts->invert_active_link && invert) { swap_values(color_t, colors.foreground, colors.background); /* Highlight text-input form-fields correctly if contrast * correction is needed. */ if (link_is_textinput(link)) { /* Make sure to use the options belonging to the * current document when checking for fg and bg color * usage. */ doc_opts = &doc_view->document->options; /* Are we fallen angels who didn't want to believe that * nothing /is/ nothing and so were born to lose our * loved ones and dear friends one by one and finally * our own life, to see it proved? --Kerouac */ /* Wipe out all default correction for 16 color mode */ color_flags = (color_flags & ~COLOR_INCREASE_CONTRAST); /* Make contrast correction invert things properly */ color_flags |= COLOR_ENSURE_INVERTED_CONTRAST; } } set_term_color(template, &colors, color_flags, color_mode); return template;}/* Save the current link's colours and attributes to doc_view->link_bg * and give it the appropriate colour and attributes for an active link. */voiddraw_current_link(struct session *ses, struct document_view *doc_view){ struct terminal *term = ses->tab->term; struct screen_char *template; struct link *link; int cursor_offset; int xpos, ypos; int i; assert(term && doc_view && doc_view->vs); if_assert_failed return; assert(ses->tab == get_current_tab(term)); if_assert_failed return; assertm(!doc_view->link_bg, "link background not empty"); if_assert_failed mem_free(doc_view->link_bg); link = get_current_link(doc_view); if (!link) return; i = !link_is_textinput(link) || ses->insert_mode == INSERT_MODE_OFF; template = init_link_drawing(doc_view, link, i); if (!template) return; xpos = doc_view->box.x - doc_view->vs->x; ypos = doc_view->box.y - doc_view->vs->y; if (ses->insert_mode == INSERT_MODE_OFF && ses->navigate_mode == NAVIGATE_CURSOR_ROUTING) { /* If we are navigating using cursor routing and not editing a * text-input form-field never set the cursor. */ cursor_offset = -1; } else { cursor_offset = get_link_cursor_offset(doc_view, link); } for (i = 0; i < link->npoints; i++) { int x = link->points[i].x + xpos; int y = link->points[i].y + ypos; struct screen_char *co; if (!is_in_box(&doc_view->box, x, y)) { doc_view->link_bg[i].x = -1; doc_view->link_bg[i].y = -1; continue; } doc_view->link_bg[i].x = x; doc_view->link_bg[i].y = y; co = get_char(term, x, y); copy_screen_chars(&doc_view->link_bg[i].c, co, 1); if (i == cursor_offset) { int blockable = (!link_is_textinput(link) && co->color != template->color); set_cursor(term, x, y, blockable); set_window_ptr(ses->tab, x, y); } template->data = co->data; copy_screen_chars(co, template, 1); set_screen_dirty(term->screen, y, y); }}voidfree_link(struct document_view *doc_view){ assert(doc_view); if_assert_failed return; mem_free_set(&doc_view->link_bg, NULL); doc_view->link_bg_n = 0;}/* Restore the colours and attributes that the active link had * before it was selected. */voidclear_link(struct terminal *term, struct document_view *doc_view){ assert(term && doc_view); if_assert_failed return; if (doc_view->link_bg) { struct link_bg *link_bg = doc_view->link_bg; int i; for (i = doc_view->link_bg_n - 1; i >= 0; i--) { struct link_bg *bgchar = &link_bg[i]; if (bgchar->x != -1 && bgchar->y != -1) { struct terminal_screen *screen = term->screen; struct screen_char *co; co = get_char(term, bgchar->x, bgchar->y); copy_screen_chars(co, &bgchar->c, 1); set_screen_dirty(screen, bgchar->y, bgchar->y); } } free_link(doc_view); }}struct link *get_first_link(struct document_view *doc_view){ struct link *link, *undef; struct document *document; int height; int i; assert(doc_view && doc_view->document); if_assert_failed return NULL; document = doc_view->document; if (!document->lines1) return NULL; height = doc_view->vs->y + doc_view->box.height; link = undef = document->links + document->nlinks; for (i = int_max(0, doc_view->vs->y); i < int_min(height, document->height); i++) { if (document->lines1[i] && document->lines1[i] < link) link = document->lines1[i]; } return (link == undef) ? NULL : link;}struct link *get_last_link(struct document_view *doc_view){ struct link *link = NULL; struct document *document; int height; int i; assert(doc_view && doc_view->document); if_assert_failed return NULL; document = doc_view->document; if (!document->lines2) return NULL; height = doc_view->vs->y + doc_view->box.height; for (i = int_max(0, doc_view->vs->y); i < int_min(height, document->height); i++) if (document->lines2[i] > link) link = document->lines2[i]; return link;}static inline intlink_in_view_x(struct document_view *doc_view, struct link *link){ int i, dx, width; assert(doc_view && link); if_assert_failed return 0; dx = doc_view->vs->x; width = doc_view->box.width; for (i = 0; i < link->npoints; i++) { int x = link->points[i].x - dx; if (x >= 0 && x < width) return 1; } return 0;}intlink_in_view_y(struct document_view *doc_view, struct link *link){ int i, dy, height; assert(doc_view && link); if_assert_failed return 0; dy = doc_view->vs->y; height = doc_view->box.height; for (i = 0; i < link->npoints; i++) { int y = link->points[i].y - dy; if (y >= 0 && y < height) return 1; } return 0;}intlink_in_view(struct document_view *doc_view, struct link *link){ assert(doc_view && link); if_assert_failed return 0; return link_in_view_y(doc_view, link) && link_in_view_x(doc_view, link);}intcurrent_link_is_visible(struct document_view *doc_view){ struct link *link;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -