From 0b47830838a3155b88e622cf9725b19df107d4a7 Mon Sep 17 00:00:00 2001 From: malc Date: Thu, 1 Mar 2012 23:59:47 +0400 Subject: [PATCH] Go to link (F) --- KEYS | 1 + link.c | 241 +++++++++++++++++++++++++++++++++++++++++----------------------- main.ml | 136 +++++++++++++++++++++++++----------- 3 files changed, 251 insertions(+), 127 deletions(-) diff --git a/KEYS b/KEYS index aee87bc..53af52c 100644 --- a/KEYS +++ b/KEYS @@ -23,6 +23,7 @@ n - repeat last search (forward) p, N - .................. (backward) g, G - go to first/last page t - align top of the screen with the top of the page +F - go to numbered link space - go to the next page delete - go to the previous page insert - toggle link navigation mode diff --git a/link.c b/link.c index e0477ed..68899ed 100644 --- a/link.c +++ b/link.c @@ -161,6 +161,7 @@ struct page { } u; fz_display_list *dlist; int slinkcount; + int slinkindexbase; struct slink *slinks; struct mark { int i; @@ -1657,6 +1658,8 @@ static void showsel (struct page *page, int ox, int oy) glDisable (GL_BLEND); } +#include "glfont.c" + static void highlightlinks (struct page *page, int xoff, int yoff) { fz_matrix ctm; @@ -1721,6 +1724,122 @@ static void highlightlinks (struct page *page, int xoff, int yoff) glDisable (GL_LINE_STIPPLE); } +static int compareslinks (const void *l, const void *r) +{ + struct slink const *ls = l; + struct slink const *rs = r; + if (ls->bbox.y0 == rs->bbox.y0) { + return rs->bbox.x0 - rs->bbox.x0; + } + return ls->bbox.y0 - rs->bbox.y0; +} + +static void droptext (struct page *page) +{ + if (page->text) { + fz_free_text_span (state.ctx, page->text); + page->fmark.i = -1; + page->lmark.i = -1; + page->fmark.span = NULL; + page->lmark.span = NULL; + page->text = NULL; + } +} + +static void dropslinks (struct page *page) +{ + if (page->slinks) { + free (page->slinks); + page->slinks = NULL; + page->slinkcount = 0; + } +} + +static void ensureslinks (struct page *page) +{ + fz_matrix ctm; + int i, count = 0; + size_t slinksize = sizeof (*page->slinks); + fz_link *link, *links; + + if (state.gen != page->gen) { + droptext (page); + dropslinks (page); + page->gen = state.gen; + } + if (page->slinks) return; + + switch (page->type) { + case DPDF: + links = page->u.pdfpage->links; + ctm = fz_concat (trimctm (page->u.pdfpage, page->pdimno), + state.pagedims[page->pdimno].ctm); + break; + + case DXPS: + links = page->u.xpspage->links; + ctm = state.pagedims[page->pdimno].ctm; + break; + + default: + return; + } + + for (link = links; link; link = link->next) { + count++; + } + if (count > 0) { + page->slinkcount = count; + page->slinks = calloc (count, slinksize); + if (!page->slinks) { + err (1, "realloc slinks %d", count); + } + + for (i = 0, link = links; link; ++i, link = link->next) { + page->slinks[i].link = link; + page->slinks[i].bbox = + fz_round_rect (fz_transform_rect (ctm, link->rect)); + } + qsort (page->slinks, count, slinksize, compareslinks); + } +} + +static void highlightslinks (struct page *page, int xoff, int yoff, int noff) +{ + int i; + char buf[40]; + struct slink *slink; + double x0, y0, x1, y1, w; + + ensureslinks (page); + glColor3ub (0xc3, 0xb0, 0x91); + for (i = 0; i < page->slinkcount; ++i) { + slink = &page->slinks[i]; + + snprintf (buf, sizeof (buf), "%d", i + noff); + x0 = slink->bbox.x0 + xoff - 5; + y1 = slink->bbox.y0 + yoff - 5; + y0 = y1 + 22; + w = measure_string (state.face, 12, buf); + x1 = x0 + w + 10; + glRectd (x0, y0, x1, y1); + } + + glEnable (GL_BLEND); + glEnable (GL_TEXTURE_2D); + glColor3ub (0, 0, 0); + for (i = 0; i < page->slinkcount; ++i) { + slink = &page->slinks[i]; + + snprintf (buf, sizeof (buf), "%d", i + noff); + x0 = slink->bbox.x0 + xoff; + y0 = slink->bbox.y0 + yoff + 12; + draw_string (state.face, 12, x0, y0, buf); + } + glDisable (GL_TEXTURE_2D); + glDisable (GL_BLEND); +} + static void uploadslice (struct tile *tile, struct slice *slice) { int offset; @@ -1838,24 +1957,32 @@ CAMLprim value ml_drawtile (value args_v, value ptr_v) } CAMLprim value ml_postprocess (value ptr_v, value hlinks_v, - value xoff_v, value yoff_v) + value xoff_v, value yoff_v, + value noff_v) { - CAMLparam4 (ptr_v, hlinks_v, xoff_v, yoff_v); + CAMLparam5 (ptr_v, hlinks_v, xoff_v, yoff_v, noff_v); int xoff = Int_val (xoff_v); int yoff = Int_val (yoff_v); + int noff = Int_val (noff_v); char *s = String_val (ptr_v); + int hlmask = Int_val (hlinks_v); struct page *page = parse_pointer ("ml_postprocess", s); - if (Bool_val (hlinks_v)) highlightlinks (page, xoff, yoff); - + if (hlmask & 1) highlightlinks (page, xoff, yoff); if (trylock ("ml_postprocess")) { + noff = 0; goto done; } + page->slinkindexbase = noff; + if (hlmask & 2) { + highlightslinks (page, xoff, yoff, noff); + noff = page->slinkcount; + } showsel (page, xoff, yoff); unlock ("ml_postprocess"); done: - CAMLreturn (Val_unit); + CAMLreturn (Val_int (noff)); } static fz_link *getlink (struct page *page, int x, int y) @@ -1895,27 +2022,6 @@ static fz_link *getlink (struct page *page, int x, int y) return NULL; } -static void droptext (struct page *page) -{ - if (page->text) { - fz_free_text_span (state.ctx, page->text); - page->fmark.i = -1; - page->lmark.i = -1; - page->fmark.span = NULL; - page->lmark.span = NULL; - page->text = NULL; - } -} - -static void dropslinks (struct page *page) -{ - if (page->slinks) { - free (page->slinks); - page->slinks = NULL; - page->slinkcount = 0; - } -} - static void ensuretext (struct page *page) { if (state.gen != page->gen) { @@ -1936,65 +2042,6 @@ static void ensuretext (struct page *page) } } -static int compareslinks (const void *l, const void *r) -{ - struct slink const *ls = l; - struct slink const *rs = r; - if (ls->bbox.y0 == rs->bbox.y0) { - return rs->bbox.x0 - rs->bbox.x0; - } - return ls->bbox.y0 - rs->bbox.y0; -} - -static void ensureslinks (struct page *page) -{ - fz_matrix ctm; - int i, count = 0; - size_t slinksize = sizeof (*page->slinks); - fz_link *link, *links; - - if (state.gen != page->gen) { - droptext (page); - dropslinks (page); - page->gen = state.gen; - } - if (page->slinks) return; - - switch (page->type) { - case DPDF: - links = page->u.pdfpage->links; - ctm = fz_concat (trimctm (page->u.pdfpage, page->pdimno), - state.pagedims[page->pdimno].ctm); - break; - - case DXPS: - links = page->u.xpspage->links; - ctm = state.pagedims[page->pdimno].ctm; - break; - - default: - return; - } - - for (link = links; link; link = link->next) { - count++; - } - if (count > 0) { - page->slinkcount = count; - page->slinks = calloc (count, slinksize); - if (!page->slinks) { - err (1, "realloc slinks %d", count); - } - - for (i = 0, link = links; link; ++i, link = link->next) { - page->slinks[i].link = link; - page->slinks[i].bbox = - fz_round_rect (fz_transform_rect (ctm, link->rect)); - } - qsort (page->slinks, count, slinksize, compareslinks); - } -} - CAMLprim value ml_find_page_with_links (value start_page_v, value dir_v) { CAMLparam2 (start_page_v, dir_v); @@ -2251,6 +2298,28 @@ CAMLprim value ml_getlink (value ptr_v, value n_v) CAMLreturn (ret_v); } +CAMLprim value ml_getlink2 (value ptr_v, value n_v) +{ + CAMLparam2 (ptr_v, n_v); + CAMLlocal3 (ret_v, tup_v, str_v); + int linkno; + fz_link *link; + struct page *page; + struct pagedim *pdim; + char *s = String_val (ptr_v); + + ret_v = Val_int (0); + page = parse_pointer ("ml_getlink2", s); + ensureslinks (page); + linkno = Int_val (n_v) - page->slinkindexbase; + if (linkno >= 0 && linkno < page->slinkcount) { + pdim = &state.pagedims[page->pdimno]; + link = page->slinks[linkno].link; + LINKTOVAL; + } + CAMLreturn (ret_v); +} + CAMLprim value ml_getlinkrect (value ptr_v, value n_v) { CAMLparam2 (ptr_v, n_v); @@ -2638,8 +2707,6 @@ CAMLprim value ml_zoom_for_height (value winw_v, value winh_v, value dw_v) CAMLreturn (ret_v); } -#include "glfont.c" - CAMLprim value ml_draw_string (value pt_v, value x_v, value y_v, value string_v) { CAMLparam4 (pt_v, x_v, y_v, string_v); diff --git a/main.ml b/main.ml index 5740294..234dd61 100644 --- a/main.ml +++ b/main.ml @@ -83,7 +83,8 @@ external zoomforh : int -> int -> int -> float = "ml_zoom_for_height";; external drawstr : int -> int -> int -> string -> float = "ml_draw_string";; external measurestr : int -> string -> float = "ml_measure_string";; external getmaxw : unit -> float = "ml_getmaxw";; -external postprocess : opaque -> bool -> int -> int -> unit = "ml_postprocess";; +external postprocess : opaque -> int -> int -> int -> int -> int = + "ml_postprocess";; external pagebbox : opaque -> (int * int * int * int) = "ml_getpagebox";; external platform : unit -> platform = "ml_platform";; external setaalevel : int -> unit = "ml_setaalevel";; @@ -91,6 +92,7 @@ external realloctexts : int -> bool = "ml_realloctexts";; external cloexec : Unix.file_descr -> unit = "ml_cloexec";; external findlink : opaque -> linkdir -> link = "ml_findlink";; external getlink : opaque -> int -> under = "ml_getlink";; +external getlink2 : opaque -> int -> under = "ml_getlink2";; external getlinkrect : opaque -> int -> irect = "ml_getlinkrect";; external findpwl: int -> int -> pagewithlinks = "ml_find_page_with_links" @@ -426,6 +428,7 @@ type state = ; mutable redisplay : bool ; mutable mpos : mpos ; mutable keystate : keystate + ; mutable glinks : bool } and hists = { pat : string circbuf @@ -663,6 +666,7 @@ let state = ; redisplay = true ; mpos = (-1, -1) ; keystate = KSnone + ; glinks = false } ;; @@ -4318,6 +4322,41 @@ let setautoscrollspeed step goingdown = state.autoscroll <- Some astep; ;; +let gotounder = function + | Ulinkgoto (pageno, top) -> + if pageno >= 0 + then ( + addnav (); + gotopage1 pageno top; + ) + + | Ulinkuri s -> + gotouri s + + | Uremote (filename, pageno) -> + let path = + if Sys.file_exists filename + then filename + else + let dir = Filename.dirname state.path in + let path = Filename.concat dir filename in + if Sys.file_exists path + then path + else "" + in + if String.length path > 0 + then ( + let anchor = getanchor () in + let ranchor = state.path, state.password, anchor in + state.anchor <- (pageno, 0.0); + state.ranchors <- ranchor :: state.ranchors; + opendoc path ""; + ) + else showtext '!' ("Could not find " ^ filename) + + | Uunexpected _ | Ulaunch _ | Unamed _ | Utext _ | Unone -> () +;; + let viewkeyboard key mask = let enttext te = let mode = state.mode in @@ -4455,6 +4494,48 @@ let viewkeyboard key mask = state.text <- "highlightlinks " ^ if conf.hlinks then "on" else "off"; G.postRedisplay "toggle highlightlinks"; + | 70 -> (* F *) + state.glinks <- true; + let ondone s = + let n = + try int_of_string s with exc -> + state.text <- Printf.sprintf "bad integer `%s': %s" + s (Printexc.to_string exc); + -1 + in + if n >= 0 + then ( + let rec loop = function + | [] -> () + | l :: rest -> + match getopaque l.pageno with + | None -> loop rest + | Some opaque -> + match getlink2 opaque n with + | Unone -> loop rest + | under -> + addnav (); + cbput state.hists.pag s; + gotounder under; + in + loop state.layout; + ) + in + let onkey text key = + match Char.unsafe_chr key with + | 'g' -> TEdone text + | _ -> intentry text key + in + let mode = state.mode in + state.mode <- Textentry ( + (":", "", Some (onhist state.hists.pag), onkey, ondone), + fun _ -> + state.glinks <- false; + state.mode <- mode + ); + state.text <- ""; + G.postRedisplay "view:enttext" + | 97 -> (* a *) begin match state.autoscroll with | Some step -> @@ -4709,41 +4790,6 @@ let viewkeyboard key mask = vlog "huh? %s" (Wsi.keyname key) ;; -let gotounder = function - | Ulinkgoto (pageno, top) -> - if pageno >= 0 - then ( - addnav (); - gotopage1 pageno top; - ) - - | Ulinkuri s -> - gotouri s - - | Uremote (filename, pageno) -> - let path = - if Sys.file_exists filename - then filename - else - let dir = Filename.dirname state.path in - let path = Filename.concat dir filename in - if Sys.file_exists path - then path - else "" - in - if String.length path > 0 - then ( - let anchor = getanchor () in - let ranchor = state.path, state.password, anchor in - state.anchor <- (pageno, 0.0); - state.ranchors <- ranchor :: state.ranchors; - opendoc path ""; - ) - else showtext '!' ("Could not find " ^ filename) - - | Uunexpected _ | Ulaunch _ | Unamed _ | Utext _ | Unone -> () -;; - let linknavkeyboard key mask linknav = let getpage pageno = let rec loop = function @@ -4943,7 +4989,7 @@ let birdseyekeyboard key mask | _ -> viewkeyboard key mask ;; -let drawpage l = +let drawpage l linkindexbase = let color = match state.mode with | Textentry _ -> scalecolor 0.4 @@ -4965,9 +5011,13 @@ let drawpage l = then let x = l.pagedispx - l.pagex and y = l.pagedispy - l.pagey in - postprocess opaque conf.hlinks x y; + let hlmask = (if conf.hlinks then 1 else 0) + + (if state.glinks && not (isbirdseye state.mode) then 2 else 0) + in + postprocess opaque hlmask x y linkindexbase; + else 0 - | _ -> () + | _ -> 0 end; ;; @@ -5052,7 +5102,13 @@ let showrects rects = let display () = GlClear.color (scalecolor2 conf.bgcolor); GlClear.clear [`color]; - List.iter drawpage state.layout; + let rec loop linkindexbase = function + | l :: rest -> + let linkindexbase = linkindexbase + drawpage l linkindexbase in + loop linkindexbase rest + | [] -> () + in + loop 0 state.layout; let rects = match state.mode with | LinkNav (Ltexact (pageno, linkno)) -> -- 2.11.4.GIT