From fc0521b2ca5b0764d2b651c81329b8809d48a9c9 Mon Sep 17 00:00:00 2001 From: malc Date: Thu, 23 Feb 2012 19:50:01 +0400 Subject: [PATCH] Improve keyboard link navigation somewhat --- link.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- main.ml | 41 ++++++++++++++++++++++----------------- 2 files changed, 84 insertions(+), 25 deletions(-) diff --git a/link.c b/link.c index 5e845bf..b90d587 100644 --- a/link.c +++ b/link.c @@ -137,6 +137,7 @@ struct pagedim { }; struct slink { + char *text; fz_bbox bbox; fz_link *link; }; @@ -1920,6 +1921,46 @@ static int compareslinks (const void *l, const void *r) return ls->bbox.y0 - rs->bbox.y0; } +static char *regiontext (struct page *page, fz_bbox bbox) +{ + char *buf = NULL; + fz_text_span *span; + int bufcap = 0, buflen = 0; + + ensuretext (page); + for (span = page->text; span; span = span->next) { + int i; + + for (i = 0; i < span->len; ++i) { + fz_bbox b, tb; + + tb = span->text[i].bbox; + b = fz_intersect_bbox (bbox, tb); + if (fz_is_empty_bbox (b)) { + int len; + char utf8[4]; + + len = runetochar (utf8, &span->text[i].c); + if (buflen + len + 1 >= bufcap) { + size_t size; + bufcap = bufcap + len + 1; + size = bufcap; + buf = realloc (buf, size); + if (!buf) { + err (1, "realloc %" FMT_s, size); + } + } + memcpy (buf + buflen, utf8, len); + buflen += len; + } + } + } + if (buf) { + buf[buflen] = 0; + } + return buf; +} + static void ensureslinks (struct page *page) { fz_matrix ctm; @@ -1959,6 +2000,7 @@ static void ensureslinks (struct page *page) page->slinks[i].link = link; page->slinks[i].bbox = fz_round_rect (fz_transform_rect (ctm, link->rect)); + page->slinks[i].text = regiontext (page, page->slinks[i].bbox); } qsort (page->slinks, count, slinksize, compareslinks); } @@ -2037,17 +2079,29 @@ CAMLprim value ml_findlink (value ptr_v, value dir_v) switch (dirtag) { case dir_first_visible: { - int x0, y0; + int x0, y0, dir; pos_v = Field (dir_v, 0); x0 = Int_val (Field (pos_v, 0)); y0 = Int_val (Field (pos_v, 1)); - - for (i = 0; i < page->slinkcount; i++) { - slink = &page->slinks[i]; - if (slink->bbox.y0 >= y0 && slink->bbox.x0 >= x0) { - found = slink; - break; + dir = Int_val (Field (pos_v, 2)); + + if (dir >= 0) { + for (i = 0; i < page->slinkcount; ++i) { + slink = &page->slinks[i]; + if (slink->bbox.y0 >= y0 && slink->bbox.x0 >= x0) { + found = slink; + break; + } + } + } + else { + for (i = page->slinkcount - 1; i >= 0; --i) { + slink = &page->slinks[i]; + if (slink->bbox.y0 >= y0 && slink->bbox.x0 >= x0) { + found = slink; + break; + } } } } diff --git a/main.ml b/main.ml index 1076dea..40c2ead 100644 --- a/main.ml +++ b/main.ml @@ -44,7 +44,7 @@ type link = and linkdir = | LDfirst | LDlast - | LDfirstvisible of (int * int) + | LDfirstvisible of (int * int * int) | LDleft of int | LDright of int | LDdown of int @@ -335,13 +335,16 @@ type mode = | Birdseye of (conf * leftx * pageno * pageno * anchor) | Textentry of (textentry * onleave) | View - | LinkNav of ((page * opaque * int) * (int * int * int * int)) option + | LinkNav of (linktarget * string) and onleave = leavetextentrystatus -> unit and leavetextentrystatus = | Cancel | Confirm and helpitem = string * int * action and action = | Noaction | Action of (uioh -> uioh) +and linktarget = + | Ltexact of ((page * opaque * int) * (int * int * int * int)) + | Ltgendir of int ;; let isbirdseye = function Birdseye _ -> true | _ -> false;; @@ -1475,25 +1478,25 @@ let gotoy y = conf, leftx, l.pageno, hooverpageno, anchor ) ); - | LinkNav _ -> + | LinkNav ((Ltgendir dir as lt, pattern)) -> let linknav = let rec loop = function - | [] -> None + | [] -> lt | l :: rest -> match getopaque l.pageno with | None -> loop rest | Some opaque -> let link = - findlink opaque (LDfirstvisible (l.pagex, l.pagey)) + findlink opaque (LDfirstvisible (l.pagex, l.pagey, dir)) in match link with | Lnone -> loop rest | Lfound (n, x0, y0, x1, y1) -> - Some ((l, opaque, n), (x0, y0, x1, y1)) + Ltexact ((l, opaque, n), (x0, y0, x1, y1)) in loop state.layout in - state.mode <- LinkNav linknav + state.mode <- LinkNav (linknav, pattern) | _ -> () end; preload layout; @@ -4243,7 +4246,7 @@ let viewkeyboard key mask = exit 0 | 0xff63 -> (* insert *) - state.mode <- LinkNav None; + state.mode <- LinkNav (Ltgendir 0, ""); gotoy state.y; | 0xff1b | 113 -> (* escape / q *) @@ -4651,16 +4654,16 @@ let gotounder = function | Uunexpected _ | Ulaunch _ | Unamed _ | Utext _ | Unone -> () ;; -let linknavkeyboard key mask linknav = +let linknavkeyboard key mask (linknav, pattern) = if key = 0xff63 then ( state.mode <- View; G.postRedisplay "leave linknav" ) else - begin match if state.currently = Idle then linknav else None with - | None -> viewkeyboard key mask - | Some ((l, opaque, n), _) -> + begin match linknav with + | Ltgendir _ -> viewkeyboard key mask + | Ltexact ((l, opaque, n), _) -> if key = 0xff0d then let under = getlink opaque n in @@ -4698,7 +4701,7 @@ let linknavkeyboard key mask linknav = begin match findpwl l.pageno dir with | Pwlnotfound -> () | Pwl pageno -> - state.mode <- LinkNav None; + state.mode <- LinkNav (Ltgendir dir, pattern); let y, h = getpageyh pageno in let y = if dir < 0 @@ -4709,9 +4712,9 @@ let linknavkeyboard key mask linknav = end; | Some (Lfound (m, x0, y0, x1, y1)) -> - if y0 < l.pagey || l.pagedispy + (y0 - l.pagey) > conf.winh + if y0 < l.pagey || l.pagedispy + (y1 - l.pagey) > conf.winh then ( - state.mode <- LinkNav None; + state.mode <- LinkNav ((Ltgendir 0), pattern); gotoy (state.y + (y0 - l.pagey)) ) else ( @@ -4720,7 +4723,7 @@ let linknavkeyboard key mask linknav = match findpwl l.pageno dir with | Pwlnotfound -> () | Pwl pageno -> - state.mode <- LinkNav None; + state.mode <- LinkNav ((Ltgendir dir), pattern); let y, h = getpageyh pageno in let y = if dir < 0 @@ -4731,7 +4734,9 @@ let linknavkeyboard key mask linknav = ) else let r = x0, y0, x1, y1 in - state.mode <- LinkNav (Some ((l, opaque, m), r)); + state.mode <- LinkNav ( + (Ltexact ((l, opaque, m), r)), pattern + ); G.postRedisplay "linknav up" ) | None -> @@ -4953,7 +4958,7 @@ let display () = List.iter drawpage state.layout; let rects = match state.mode with - | LinkNav (Some ((page, _, _), (x0, y0, x1, y1))) -> + | LinkNav ((Ltexact ((page, _, _), (x0, y0, x1, y1))), _) -> (page.pageno, 5, ( float x0, float y0, float x1, float y0, -- 2.11.4.GIT