6 external init
: Unix.file_descr
-> initparams
-> unit = "ml_init";;
7 external seltext
: opaque
-> (int * int * int * int) -> unit = "ml_seltext";;
8 external hassel
: opaque
-> bool = "ml_hassel";;
9 external copysel
: Unix.file_descr
-> opaque
-> unit = "ml_copysel";;
10 external getpdimrect
: int -> float array
= "ml_getpdimrect";;
11 external whatsunder
: opaque
-> int -> int -> under
= "ml_whatsunder";;
12 external markunder
: opaque
-> int -> int -> mark
-> bool = "ml_markunder";;
13 external clearmark
: opaque
-> unit = "ml_clearmark";;
14 external zoomforh
: int -> int -> int -> int -> float = "ml_zoom_for_height";;
15 external getmaxw
: unit -> float = "ml_getmaxw";;
16 external drawstr
: int -> int -> int -> string -> float = "ml_draw_string";;
17 external measurestr
: int -> string -> float = "ml_measure_string";;
18 external postprocess
:
19 opaque
-> int -> int -> int -> (int * string * int) -> int
21 external pagebbox
: opaque
-> (int * int * int * int) = "ml_getpagebox";;
22 external setaalevel
: int -> unit = "ml_setaalevel";;
23 external realloctexts
: int -> bool = "ml_realloctexts";;
24 external findlink
: opaque
-> linkdir
-> link
= "ml_findlink";;
25 external getlink
: opaque
-> int -> under
= "ml_getlink";;
26 external getlinkrect
: opaque
-> int -> irect
= "ml_getlinkrect";;
27 external getlinkcount
: opaque
-> int = "ml_getlinkcount";;
28 external findpwl
: int -> int -> pagewithlinks
= "ml_find_page_with_links";;
29 external getpbo
: width
-> height
-> colorspace
-> opaque
= "ml_getpbo";;
30 external freepbo
: opaque
-> unit = "ml_freepbo";;
31 external unmappbo
: opaque
-> unit = "ml_unmappbo";;
32 external bousable
: unit -> bool = "ml_bo_usable";;
33 external unproject
: opaque
-> int -> int -> (int * int) option
35 external project
: opaque
-> int -> int -> float -> float -> (float * float)
37 external drawtile
: tileparams
-> opaque
-> unit = "ml_drawtile";;
38 external rectofblock
: opaque
-> int -> int -> float array
option
40 external begintiles
: unit -> unit = "ml_begintiles";;
41 external endtiles
: unit -> unit = "ml_endtiles";;
42 external addannot
: opaque
-> int -> int -> string -> unit = "ml_addannot";;
43 external modannot
: opaque
-> slinkindex
-> string -> unit = "ml_modannot";;
44 external delannot
: opaque
-> slinkindex
-> unit = "ml_delannot";;
45 external hasunsavedchanges
: unit -> bool = "ml_hasunsavedchanges";;
46 external savedoc
: string -> unit = "ml_savedoc";;
47 external getannotcontents
: opaque
-> slinkindex
-> string
48 = "ml_getannotcontents";;
49 external drawprect
: opaque
-> int -> int -> float array
-> unit
51 external wcmd
: Unix.file_descr
-> bytes
-> int -> unit = "ml_wcmd";;
52 external rcmd
: Unix.file_descr
-> string = "ml_rcmd";;
53 external uritolocation
: string -> (pageno
* float * float)
54 = "ml_uritolocation";;
55 external isexternallink
: string -> bool = "ml_isexternallink";;
57 let selfexec = ref E.s
;;
58 let opengl_has_pbo = ref false;;
60 let drawstring size x y s
=
62 Gl.enable `texture_2d
;
63 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
64 ignore
(drawstr size x y s
);
66 Gl.disable `texture_2d
;
69 let drawstring1 size x y s
=
73 let drawstring2 size x y fmt
=
74 Printf.kprintf
(drawstring size
(x
+1) (y
+size
+1)) fmt
78 dolog
"l %d dim=%d {" l
.pageno l
.pagedimno
;
79 dolog
" WxH %dx%d" l
.pagew l
.pageh
;
80 dolog
" vWxH %dx%d" l
.pagevw l
.pagevh
;
81 dolog
" pagex,y %d,%d" l
.pagex l
.pagey
;
82 dolog
" dispx,y %d,%d" l
.pagedispx l
.pagedispy
;
83 dolog
" column %d" l
.pagecol
;
87 let debugrect (x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
) =
89 dolog
" x0,y0=(% f, % f)" x0 y0
;
90 dolog
" x1,y1=(% f, % f)" x1 y1
;
91 dolog
" x2,y2=(% f, % f)" x2 y2
;
92 dolog
" x3,y3=(% f, % f)" x3 y3
;
96 let isbirdseye = function
98 | Textentry _
| View
| LinkNav _
-> false
101 let istextentry = function
102 | Textentry _
-> true
103 | Birdseye _
| View
| LinkNav _
-> false
106 let wtmode = ref false;;
107 let cxack = ref false;;
109 let pgscale h
= truncate
(float h
*. conf
.pgscale);;
112 if state
.uioh#alwaysscrolly
|| ((conf
.scrollb
land scrollbhv
!= 0)
113 && (state
.w
> state
.winw
))
119 if state
.uioh#alwaysscrolly
|| ((conf
.scrollb
land scrollbvv
!= 0)
120 && (state
.maxy
> state
.winh
))
128 else x
> state
.winw
- vscrollw ()
132 fstate
.fontsize
<- n
;
133 fstate
.wwidth
<- measurestr fstate
.fontsize
"w";
134 fstate
.maxrows
<- (state
.winh
- fstate
.fontsize
- 1) / (fstate
.fontsize
+ 1);
140 else Printf.kprintf ignore fmt
144 if emptystr conf
.pathlauncher
145 then dolog
"%s" state
.path
147 let command = Str.global_replace percentsre state
.path conf
.pathlauncher
in
148 match spawn
command [] with
151 dolog
"failed to execute `%s': %s" command @@ exntos exn
157 let postRedisplay who
=
158 vlog "redisplay for [%S]" who
;
159 state
.redisplay
<- true;
163 let getopaque pageno
=
164 try Some
(Hashtbl.find state
.pagemap
(pageno
, state
.gen
))
165 with Not_found
-> None
168 let pagetranslatepoint l x y
=
169 let dy = y
- l
.pagedispy
in
170 let y = dy + l
.pagey
in
171 let dx = x
- l
.pagedispx
in
172 let x = dx + l
.pagex
in
176 let onppundermouse g
x y d
=
179 begin match getopaque l
.pageno
with
181 let x0 = l
.pagedispx
in
182 let x1 = x0 + l
.pagevw
in
183 let y0 = l
.pagedispy
in
184 let y1 = y0 + l
.pagevh
in
185 if y >= y0 && y <= y1 && x >= x0 && x <= x1
187 let px, py
= pagetranslatepoint l
x y in
188 match g opaque l
px py
with
201 let g opaque l
px py
=
204 match rectofblock opaque
px py
with
205 | Some
[|x0;x1;y0;y1|] ->
206 let rect = (x0, y0, x1, y0, x1, y1, x0, y1) in
207 let color = (0.0, 0.0, 1.0 /. (l
.pageno
mod 3 |> float), 0.5) in
208 state
.rects
<- [l
.pageno
, color, rect];
209 G.postRedisplay "getunder";
212 let under = whatsunder opaque
px py
in
213 if under = Unone
then None
else Some
under
215 onppundermouse g x y Unone
220 match unproject opaque
x y with
221 | Some
(x, y) -> Some
(Some
(opaque
, l
.pageno
, x, y))
224 onppundermouse g x y None
;
228 state
.text
<- Printf.sprintf
"%c%s" c s
;
229 G.postRedisplay "showtext";
233 Format.ksprintf
(fun s
-> showtext '
!' s
) fmt
;
236 let pipesel opaque cmd
=
239 match Unix.pipe
() with
240 | (exception exn
) -> dolog
"pipesel cannot create pipe: %S" @@ exntos exn
;
242 let doclose what fd
=
243 Ne.clo fd
(fun msg
-> dolog
"%s close failed: %s" what msg
)
246 try spawn cmd
[r
, 0; w
, -1]
248 dolog
"cannot execute %S: %s" cmd
@@ exntos exn
;
254 G.postRedisplay "pipesel";
256 else doclose "pipesel pipe/w" w
;
257 doclose "pipesel pipe/r" r
;
261 let g opaque l
px py
=
262 if markunder opaque
px py conf
.paxmark
265 match getopaque l
.pageno
with
267 | Some opaque
-> pipesel opaque conf
.paxcmd
272 G.postRedisplay "paxunder";
273 if conf
.paxmark
= Mark_page
276 match getopaque l
.pageno
with
278 | Some opaque
-> clearmark opaque
) state
.layout
;
279 state
.roam
<- onppundermouse g x y (fun () -> impmsg "whoopsie daisy");
283 match Unix.pipe
() with
284 | (exception exn
) -> impmsg "pipe failed: %s" @@ exntos exn
287 Ne.clo fd
(fun msg
-> impmsg "failed to close %s: %s" cap msg
)
290 try spawn conf
.selcmd
[r
, 0; w
, -1]
292 impmsg "failed to execute %s: %s" conf
.selcmd
@@ exntos exn
;
298 let l = String.length s
in
299 let bytes = Bytes.unsafe_of_string s
in
300 let n = tempfailureretry
(Unix.write w
bytes 0) l in
302 then impmsg "failed to write %d characters to sel pipe, wrote %d"
305 impmsg "failed to write to sel pipe: %s" @@ exntos exn
308 clo "selstring pipe/r" r
;
309 clo "selstring pipe/w" w
;
312 let undertext = function
315 | Utext s
-> "font: " ^ s
316 | Uannotation
(opaque
, slinkindex
) ->
317 "annotation: " ^ getannotcontents opaque slinkindex
320 let updateunder x y =
321 match getunder x y with
322 | Unone
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
324 if conf
.underinfo
then showtext 'u'
("ri: " ^ uri
);
325 Wsi.setcursor
Wsi.CURSOR_INFO
327 if conf
.underinfo
then showtext '
f'
("ont: " ^ s
);
328 Wsi.setcursor
Wsi.CURSOR_TEXT
330 if conf
.underinfo
then showtext 'a'
"nnotation";
331 Wsi.setcursor
Wsi.CURSOR_INFO
334 let showlinktype under =
335 if conf
.underinfo
&& under != Unone
336 then showtext ' '
@@ undertext under
339 let intentry_with_suffix text key
=
341 if key
>= 32 && key
< 127
343 let c = Char.chr key
in
348 | 'k'
| 'm'
| '
g'
| 'K'
| 'M'
| 'G'
->
349 addchar
text @@ asciilower
c
351 state
.text <- Printf.sprintf
"invalid key (%d, `%c')" key
c;
354 state
.text <- Printf.sprintf
"invalid key %d" key
;
362 let b = Buffer.create
16 in
365 let b = Buffer.to_bytes
b in
366 wcmd state
.ss
b @@ Bytes.length
b
370 let nogeomcmds cmds
=
372 | s
, [] -> emptystr s
376 let layoutN ((columns
, coverA
, coverB
), b) x y sw sh
=
377 let rec fold accu
n =
378 if n = Array.length
b
381 let pdimno, dx, vy
, (_
, w
, h
, xoff
) = b.(n) in
384 || n = state
.pagecount
- coverB
385 || (n - coverA
) mod columns
= columns
- 1)
391 let pagey = max
0 (y - vy
) in
392 let pagedispy = if pagey > 0 then 0 else vy
- y in
393 let pagedispx, pagex
=
395 if n = coverA
- 1 || n = state
.pagecount
- coverB
396 then x + (sw
- w
) / 2
404 let vw = sw
- pagedispx in
405 let pw = w
- pagex
in
408 let pagevh = min
(h
- pagey) (sh
- pagedispy) in
409 if pagevw > 0 && pagevh > 0
420 ; pagedispx = pagedispx
421 ; pagedispy = pagedispy
433 if Array.length
b = 0
435 else List.rev
(fold [] (page_of_y
y))
438 let layoutS (columns
, b) x y sw sh
=
439 let rec fold accu n =
440 if n = Array.length
b
443 let pdimno, px, vy
, (_
, pagew
, pageh
, xoff
) = b.(n) in
451 let pagey = max
0 (y - vy
) in
452 let pagedispy = if pagey > 0 then 0 else vy
- y in
453 let pagedispx, pagex
=
467 let pagecolw = pagew
/columns
in
470 then pagedispx + ((sw
- pagecolw) / 2)
474 let vw = sw
- pagedispx in
475 let pw = pagew
- pagex
in
478 let pagevw = min
pagevw pagecolw in
479 let pagevh = min
(pageh
- pagey) (sh
- pagedispy) in
480 if pagevw > 0 && pagevh > 0
491 ; pagedispx = pagedispx
492 ; pagedispy = pagedispy
493 ; pagecol
= n mod columns
507 let layout x y sw sh
=
508 if nogeomcmds state
.geomcmds
510 match conf
.columns
with
511 | Csingle
b -> layoutN ((1, 0, 0), b) x y sw sh
512 | Cmulti
c -> layoutN c x y sw sh
513 | Csplit s
-> layoutS s
x y sw sh
518 let y = state
.y + incr
in
520 let y = min
y (state
.maxy
- (if conf
.maxhfit
then state
.winh
else 0)) in
525 let tilex = l.pagex
mod conf
.tilew
in
526 let tiley = l.pagey mod conf
.tileh
in
528 let col = l.pagex
/ conf
.tilew
in
529 let row = l.pagey / conf
.tileh
in
531 let rec rowloop row y0 dispy h
=
535 let dh = conf
.tileh
- y0 in
537 let rec colloop col x0 dispx w
=
541 let dw = conf
.tilew
- x0 in
543 f col row dispx dispy
x0 y0 dw dh;
544 colloop (col+1) 0 (dispx
+dw) (w
-dw)
547 colloop col tilex l.pagedispx l.pagevw;
548 rowloop (row+1) 0 (dispy
+dh) (h
-dh)
551 if l.pagevw > 0 && l.pagevh > 0
552 then rowloop row tiley l.pagedispy l.pagevh;
555 let gettileopaque l col row =
557 l.pageno
, state
.gen
, conf
.colorspace
, conf
.angle
, l.pagew
, l.pageh
, col, row
559 try Some
(Hashtbl.find state
.tilemap
key)
560 with Not_found
-> None
563 let puttileopaque l col row gen colorspace angle opaque size elapsed
=
564 let key = l.pageno
, gen
, colorspace
, angle
, l.pagew
, l.pageh
, col, row in
565 Hashtbl.add state
.tilemap
key (opaque
, size
, elapsed
)
568 let filledrect2 x0 y0 x1 y1 x2 y2 x3 y3
=
569 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x1; y1; x2
; y2
; x3
; y3
|];
570 GlArray.vertex `two state
.vraw
;
571 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
574 let filledrect1 x0 y0 x1 y1 = filledrect2 x0 y0 x0 y1 x1 y0 x1 y1;;
576 let filledrect x0 y0 x1 y1 =
577 GlArray.disable `texture_coord
;
578 filledrect1 x0 y0 x1 y1;
579 GlArray.enable `texture_coord
;
582 let linerect x0 y0 x1 y1 =
583 GlArray.disable `texture_coord
;
584 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x0; y1; x1; y1; x1; y0 |];
585 GlArray.vertex `two state
.vraw
;
586 GlArray.draw_arrays `line_loop ~first
:0 ~count
:4;
587 GlArray.enable `texture_coord
;
590 let drawtiles l color =
593 let f col row x y tilex tiley w h
=
594 match gettileopaque l col row with
595 | Some
(opaque
, _
, t
) ->
596 let params = x, y, w
, h
, tilex, tiley in
598 then GlTex.env
(`mode `blend
);
599 drawtile
params opaque
;
601 then GlTex.env
(`mode `modulate
);
605 let s = Printf.sprintf
609 let w = measurestr fstate
.fontsize
s in
610 GlDraw.color (0.0, 0.0, 0.0);
611 filledrect (float (x-2))
614 (float (y + fstate
.fontsize
+ 2));
616 drawstring fstate
.fontsize
x (y + fstate
.fontsize
- 1) s;
623 let lw = state
.winw
- x in
626 let lh = state
.winh
- y in
630 then GlTex.env
(`mode `blend
);
631 begin match state
.checkerstexid
with
633 Gl.enable `texture_2d
;
634 GlTex.bind_texture ~target
:`texture_2d id
;
638 and y1 = float (y+h
) in
640 let tw = float w /. 16.0
641 and th
= float h
/. 16.0 in
642 let tx0 = float tilex /. 16.0
643 and ty0
= float tiley /. 16.0 in
645 and ty1
= ty0
+. th
in
646 Raw.sets_float state
.vraw ~pos
:0
647 [| x0; y0; x0; y1; x1; y0; x1; y1 |];
648 Raw.sets_float state
.traw ~pos
:0
649 [| tx0; ty0
; tx0; ty1
; tx1; ty0
; tx1; ty1
|];
650 GlArray.vertex `two state
.vraw
;
651 GlArray.tex_coord `two state
.traw
;
652 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
653 Gl.disable `texture_2d
;
656 GlDraw.color (1.0, 1.0, 1.0);
657 filledrect (float x) (float y) (float (x+w)) (float (y+h
));
660 then GlTex.env
(`mode `modulate
);
661 if w > 128 && h
> fstate
.fontsize
+ 10
663 let c = if conf
.invert
then 1.0 else 0.0 in
664 GlDraw.color (c, c, c);
667 then (col*conf
.tilew
, row*conf
.tileh
)
670 drawstring2 fstate
.fontsize
x y "Loading %d [%d,%d]" l.pageno
c r
;
679 let pagevisible layout n = List.exists
(fun l -> l.pageno
= n) layout;;
681 let tilevisible1 l x y =
683 and ax1
= l.pagex
+ l.pagevw
685 and ay1
= l.pagey + l.pagevh in
689 let bx1 = min
(bx0 + conf
.tilew
) l.pagew
690 and by1
= min
(by0
+ conf
.tileh
) l.pageh
in
692 let rx0 = max
ax0 bx0
693 and ry0
= max ay0 by0
694 and rx1
= min ax1
bx1
695 and ry1
= min ay1 by1
in
697 let nonemptyintersection = rx1
> rx0 && ry1
> ry0
in
701 let tilevisible layout n x y =
702 let rec findpageinlayout m
= function
703 | l :: rest
when l.pageno
= n ->
704 tilevisible1 l x y || (
705 match conf
.columns
with
706 | Csplit
(c, _
) when c > m
-> findpageinlayout (m
+1) rest
711 | _
:: rest
-> findpageinlayout 0 rest
714 findpageinlayout 0 layout;
717 let tileready l x y =
718 tilevisible1 l x y &&
719 gettileopaque l (x/conf
.tilew
) (y/conf
.tileh
) != None
722 let tilepage n p
layout =
723 let rec loop = function
727 let f col row _ _ _ _ _ _
=
728 if state
.currently
= Idle
730 match gettileopaque l col row with
733 let x = col*conf
.tilew
734 and y = row*conf
.tileh
in
736 let w = l.pagew
- x in
740 let h = l.pageh
- y in
745 then getpbo
w h conf
.colorspace
748 wcmd "tile %s %d %d %d %d %s"
749 (~
> p
) x y w h (~
> pbo);
752 l, p
, conf
.colorspace
, conf
.angle
,
753 state
.gen
, col, row, conf
.tilew
, conf
.tileh
762 if nogeomcmds state
.geomcmds
766 let preloadlayout x y sw sh
=
767 let y = if y < sh
then 0 else y - sh
in
768 let x = min
0 (x + sw
) in
776 if state
.currently
!= Idle
781 begin match getopaque l.pageno
with
783 wcmd "page %d %d" l.pageno
l.pagedimno
;
784 state
.currently
<- Loading
(l, state
.gen
);
786 tilepage l.pageno opaque pages
;
791 if nogeomcmds state
.geomcmds
797 if conf
.preload && state
.currently
= Idle
798 then load (preloadlayout state
.x state
.y state
.winw state
.winh
);
801 let layoutready layout =
802 let rec fold all ls
=
805 let seen = ref false in
806 let allvisible = ref true in
807 let foo col row _ _ _ _ _ _
=
809 allvisible := !allvisible &&
810 begin match gettileopaque l col row with
816 fold (!seen && !allvisible) rest
819 let alltilesvisible = fold true layout in
824 let y = bound
y 0 state
.maxy
in
825 let y, layout, proceed
=
826 match conf
.maxwait
with
827 | Some time
when state
.ghyll
== noghyll
->
828 begin match state
.throttle
with
830 let layout = layout x y state
.winw state
.winh
in
831 let ready = layoutready layout in
835 state
.throttle
<- Some
(layout, y, now
());
837 else G.postRedisplay "gotoxy showall (None)";
839 | Some
(_
, _
, started
) ->
840 let dt = now
() -. started
in
843 state
.throttle
<- None
;
844 let layout = layout x y state
.winw state
.winh
in
846 G.postRedisplay "maxwait";
853 let layout = layout x y state
.winw state
.winh
in
854 if not
!wtmode || layoutready layout
855 then G.postRedisplay "gotoxy ready";
862 state
.layout <- layout;
863 begin match state
.mode
with
866 | Ltexact
(pageno
, linkno
) ->
867 let rec loop = function
869 state
.lnava
<- Some
(pageno
, linkno
);
870 state
.mode
<- LinkNav
(Ltgendir
0)
871 | l :: _
when l.pageno
= pageno
->
872 begin match getopaque pageno
with
873 | None
-> state
.mode
<- LinkNav
(Ltnotready
(pageno
, 0))
875 let x0, y0, x1, y1 = getlinkrect opaque linkno
in
876 if not
(x0 >= l.pagex
&& x1 <= l.pagex
+ l.pagevw
877 && y0 >= l.pagey && y1 <= l.pagey + l.pagevh)
878 then state
.mode
<- LinkNav
(Ltgendir
0)
880 | _
:: rest
-> loop rest
883 | Ltnotready _
| Ltgendir _
-> ()
889 begin match state
.mode
with
890 | Birdseye
(conf
, leftx
, pageno
, hooverpageno
, anchor
) ->
891 if not
(pagevisible layout pageno
)
893 match state
.layout with
896 state
.mode
<- Birdseye
(
897 conf
, leftx
, l.pageno
, hooverpageno
, anchor
902 | Ltnotready
(_
, dir
)
905 let rec loop = function
908 match getopaque l.pageno
with
909 | None
-> Ltnotready
(l.pageno
, dir
)
914 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
916 if dir
> 0 then LDfirst
else LDlast
922 | Lnotfound
-> loop rest
924 showlinktype (getlink opaque
n);
925 Ltexact
(l.pageno
, n)
929 state
.mode
<- LinkNav
linknav
937 state
.ghyll
<- noghyll
;
940 let mx, my
= state
.mpos
in
945 let conttiling pageno opaque
=
946 tilepage pageno opaque
948 then preloadlayout state
.x state
.y state
.winw state
.winh
952 let gotoxy_and_clear_text x y =
953 if not conf
.verbose
then state
.text <- E.s;
957 let getanchory (n, top
, dtop
) =
958 let y, h = getpageyh
n in
961 let ips = calcips
h in
962 y + truncate
(top
*.float h -. dtop
*.float ips) + ips;
964 y + truncate
(top
*.float h -. dtop
*.float conf
.interpagespace
)
967 let gotoanchor anchor
=
968 gotoxy state
.x (getanchory anchor
);
972 cbput state
.hists
.nav
(getanchor
());
976 let anchor = cbgetc state
.hists
.nav dir
in
980 let gotoghyll1 single
y =
982 (* http://devmaster.net/forums/topic/9796-ease-in-ease-out-algorithm/ *)
984 let s x = 3.0*.x**2.0 -. 2.0*.x**3.0 in
986 then s (float f /. float a
)
989 then 1.0 -. s ((float (f-b) /. float (n-b)))
995 let ins = float a
*. 0.5
996 and outs
= float (n-b) *. 0.5 in
998 ins +. outs
+. float ones
1000 let rec set nab
y sy
=
1001 let (_N
, _A
, _B
), y =
1004 let scl = if y > sy
then 2 else -2 in
1005 let _N, _
, _
= nab
in
1006 (_N,0,_N), y+conf
.scrollstep
*scl
1008 let sum = summa
_N _A _B
in
1009 let dy = float (y - sy
) in
1013 then state
.ghyll
<- noghyll
1016 let s = scroll n _N _A _B
in
1017 let y1 = y1 +. ((s *. dy) /. sum) in
1018 gotoxy_and_clear_text state
.x (truncate
y1);
1019 state
.ghyll
<- gf (n+1) y1;
1023 | Some
y'
when single
-> set nab
y' state
.y
1024 | Some
y'
-> set (_N/2, 1, 1) y' state
.y
1026 gf 0 (float state
.y)
1029 match conf
.ghyllscroll
with
1030 | Some nab
when not conf
.presentation
->
1031 if state
.ghyll
== noghyll
1032 then set nab
y state
.y
1033 else state
.ghyll
(Some
y)
1035 gotoxy_and_clear_text state
.x y
1038 let gotoghyll = gotoghyll1 false;;
1040 let gotopage n top
=
1041 let y, h = getpageyh
n in
1042 let y = y + (truncate
(top
*. float h)) in
1046 let gotopage1 n top
=
1047 let y = getpagey
n in
1052 let invalidate s f =
1053 state
.redisplay
<- false;
1058 match state
.geomcmds
with
1059 | ps
, [] when emptystr ps
->
1061 state
.geomcmds
<- s, [];
1064 state
.geomcmds
<- ps
, [s, f];
1066 | ps
, (s'
, _
) :: rest
when s'
= s ->
1067 state
.geomcmds
<- ps
, ((s, f) :: rest
);
1070 state
.geomcmds
<- ps
, ((s, f) :: cmds
);
1074 Hashtbl.iter
(fun _ opaque
->
1075 wcmd "freepage %s" (~
> opaque
);
1077 Hashtbl.clear state
.pagemap
;
1081 if not
(Queue.is_empty state
.tilelru
)
1083 Queue.iter
(fun (k
, p
, s) ->
1084 wcmd "freetile %s" (~
> p
);
1085 state
.memused
<- state
.memused
- s;
1086 Hashtbl.remove state
.tilemap k
;
1088 state
.uioh#infochanged Memused
;
1089 Queue.clear state
.tilelru
;
1095 let h = truncate
(float h*.conf
.zoom
) in
1096 let d = conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0) in
1100 let opendoc path password
=
1102 state
.password
<- password
;
1103 state
.gen
<- state
.gen
+ 1;
1104 state
.docinfo
<- [];
1105 state
.outlines
<- [||];
1108 setaalevel conf
.aalevel
;
1110 if emptystr state
.origin
1114 Wsi.settitle
("llpp " ^
(mbtoutf8
(Filename.basename
titlepath)));
1115 wcmd "open %d %d %d %s\000%s\000%s\000"
1116 (btod
!wtmode) (btod
!cxack) (btod conf
.usedoccss
)
1117 path password conf
.css
;
1118 invalidate "reqlayout"
1120 wcmd "reqlayout %d %d %d %s\000"
1121 conf
.angle
(FMTE.to_int conf
.fitmodel
)
1122 (stateh state
.winh
) state
.nameddest
1125 let sl = keystostrlist conf
in
1127 function | [] -> accu
1128 | s :: rest
-> loop ((s, 0, Noaction
) :: accu) rest
1129 in makehelp
() @ (("", 0, Noaction
) :: loop [] sl) |> Array.of_list
1133 state
.anchor <- getanchor
();
1134 opendoc state
.path state
.password
;
1138 let c = c *. conf
.colorscale
in
1142 let scalecolor2 (r
, g, b) =
1143 (r
*. conf
.colorscale
, g *. conf
.colorscale
, b *. conf
.colorscale
);
1146 let docolumns columns
=
1149 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1150 let rec loop pageno
pdimno pdim
y ph pdims
=
1151 if pageno
= state
.pagecount
1154 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1156 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1157 pdimno+1, pdim
, rest
1161 let x = max
0 (((state
.winw
- w) / 2) - xoff
) in
1163 y + (if conf
.presentation
1164 then (if pageno
= 0 then calcips
h else calcips ph
+ calcips
h)
1165 else (if pageno
= 0 then 0 else conf
.interpagespace
)
1168 a.(pageno
) <- (pdimno, x, y, pdim
);
1169 loop (pageno
+1) pdimno pdim
(y + h) h pdims
1171 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 state
.pdims
;
1172 conf
.columns
<- Csingle
a;
1174 | Cmulti
((columns
, coverA
, coverB
), _
) ->
1175 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1176 let rec loop pageno
pdimno pdim
x y rowh pdims
=
1178 if m
= pageno
then () else
1179 let (pdimno, x, y, ((_
, _
, h, _
) as pdim
)) = a.(m
) in
1182 let y = y + (rowh
- h) / 2 in
1183 a.(m
) <- (pdimno, x, y, pdim
);
1187 if pageno
= state
.pagecount
1188 then fixrow (((pageno
- 1) / columns
) * columns
)
1190 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1192 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1193 pdimno+1, pdim
, rest
1198 if pageno
= coverA
- 1 || pageno
= state
.pagecount
- coverB
1200 let x = (state
.winw
- w) / 2 in
1202 if conf
.presentation
then calcips
h else conf
.interpagespace
in
1203 x, y + ips + rowh
, h
1206 if (pageno
- coverA
) mod columns
= 0
1208 let x = max
0 (state
.winw
- state
.w) / 2 in
1210 if conf
.presentation
1212 let ips = calcips
h in
1213 y + (if pageno
= 0 then 0 else calcips rowh
+ ips)
1215 y + (if pageno
= 0 then 0 else conf
.interpagespace
)
1219 else x, y, max rowh
h
1223 if pageno
> 1 && (pageno
- coverA
) mod columns
= 0
1226 if pageno
= columns
&& conf
.presentation
1228 let ips = calcips rowh
in
1229 for i
= 0 to pred columns
1231 let (pdimno, x, y, pdim
) = a.(i
) in
1232 a.(i
) <- (pdimno, x, y+ips, pdim
)
1238 fixrow (pageno
- columns
);
1243 a.(pageno
) <- (pdimno, x, y, pdim
);
1244 let x = x + w + xoff
*2 + conf
.interpagespace
in
1245 loop (pageno
+1) pdimno pdim
x y rowh' pdims
1247 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 0 state
.pdims
;
1248 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), a);
1251 let a = Array.make
(state
.pagecount
*c) (-1, -1, -1, (-1, -1, -1, -1)) in
1252 let rec loop pageno
pdimno pdim
y pdims
=
1253 if pageno
= state
.pagecount
1256 let pdimno, ((_
, w, h, _
) as pdim
), pdims
=
1258 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1259 pdimno+1, pdim
, rest
1264 let rec loop1 n x y =
1265 if n = c then y else (
1266 a.(pageno
*c + n) <- (pdimno, x, y, pdim
);
1267 loop1 (n+1) (x+cw) (y + h + conf
.interpagespace
)
1270 let y = loop1 0 0 y in
1271 loop (pageno
+1) pdimno pdim
y pdims
1273 loop 0 ~
-1 (-1,-1,-1,-1) 0 state
.pdims
;
1274 conf
.columns
<- Csplit
(c, a);
1278 docolumns conf
.columns
;
1279 state
.maxy
<- calcheight
();
1280 if state
.reprf
== noreprf
1282 match state
.mode
with
1283 | Birdseye
(_
, _
, pageno
, _
, _
) ->
1284 let y, h = getpageyh pageno
in
1285 let top = (state
.winh
- h) / 2 in
1286 gotoxy state
.x (max
0 (y - top))
1290 let y = getanchory state
.anchor in
1291 let y = min
y (state
.maxy
- state
.winh
) in
1296 state
.reprf
<- noreprf
;
1300 let reshape ?
(firsttime
=false) w h =
1301 GlDraw.viewport ~
x:0 ~
y:0 ~
w ~
h;
1302 if not firsttime
&& nogeomcmds state
.geomcmds
1303 then state
.anchor <- getanchor
();
1306 let w = truncate
(float w *. conf
.zoom
) in
1309 setfontsize fstate
.fontsize
;
1310 GlMat.mode `modelview
;
1311 GlMat.load_identity
();
1313 GlMat.mode `projection
;
1314 GlMat.load_identity
();
1315 GlMat.rotate ~
x:1.0 ~angle
:180.0 ();
1316 GlMat.translate ~
x:~
-.1.0 ~
y:~
-.1.0 ();
1317 GlMat.scale3
(2.0 /. float state
.winw
, 2.0 /. float state
.winh
, 1.0);
1322 else float state
.x /. float state
.w
1324 invalidate "geometry"
1328 then state
.x <- truncate
(relx *. float w);
1330 match conf
.columns
with
1332 | Cmulti
((c, _
, _
), _
) -> (w - (c-1)*conf
.interpagespace
) / c
1333 | Csplit
(c, _
) -> w * c
1335 wcmd "geometry %d %d %d"
1336 w (stateh h) (FMTE.to_int conf
.fitmodel
)
1341 let len = String.length state
.text in
1342 let x0 = if conf
.leftscroll
then vscrollw () else 0 in
1345 match state
.mode
with
1346 | Textentry _
| View
| LinkNav _
->
1347 let h, _
, _
= state
.uioh#scrollpw
in
1352 filledrect x (float (state
.winh
- (fstate
.fontsize
+ 4) - hscrollh))
1353 (x+.w) (float (state
.winh
- hscrollh))
1356 let w = float (state
.winw
- 1 - vscrollw ()) in
1357 if state
.progress
>= 0.0 && state
.progress
< 1.0
1359 GlDraw.color (0.3, 0.3, 0.3);
1360 let w1 = w *. state
.progress
in
1362 GlDraw.color (0.0, 0.0, 0.0);
1363 rect (float x0+.w1) (float x0+.w-.w1)
1366 GlDraw.color (0.0, 0.0, 0.0);
1370 GlDraw.color (1.0, 1.0, 1.0);
1373 (if conf
.leftscroll
then x0 + 2 else x0 + if len > 0 then 8 else 2)
1374 (state
.winh
- hscrollh - 5) s;
1377 match state
.mode
with
1378 | Textentry
((prefix
, text, _
, _
, _
, _
), _
) ->
1382 Printf.sprintf
"%s%s_ [%s]" prefix
text state
.text
1384 Printf.sprintf
"%s%s_" prefix
text
1390 | LinkNav _
-> state
.text
1395 if not
(istextentry state
.mode
) && state
.uioh#eformsgs
1397 let s1 = "(press 'e' to review error messasges)" in
1398 if nonemptystr
s then s ^
" " ^
s1 else s1
1408 let len = Queue.length state
.tilelru
in
1410 match state
.throttle
with
1413 then preloadlayout state
.x state
.y state
.winw state
.winh
1415 | Some
(layout, _
, _
) ->
1419 if state
.memused
<= conf
.memlimit
1424 let (k
, p
, s) as lruitem
= Queue.pop state
.tilelru
in
1425 let n, gen
, colorspace
, angle
, pagew
, pageh
, col, row = k
in
1426 let (_
, pw, ph
, _
) = getpagedim
n in
1428 && colorspace
= conf
.colorspace
1429 && angle
= conf
.angle
1433 let x = col*conf
.tilew
1434 and y = row*conf
.tileh
in
1435 tilevisible (Lazy.force_val
layout) n x y
1437 then Queue.push lruitem state
.tilelru
1440 wcmd "freetile %s" (~
> p
);
1441 state
.memused
<- state
.memused
- s;
1442 state
.uioh#infochanged Memused
;
1443 Hashtbl.remove state
.tilemap k
;
1451 let onpagerect pageno
f =
1453 match conf
.columns
with
1454 | Cmulti
(_
, b) -> b
1456 | Csplit
(_
, b) -> b
1458 if pageno
>= 0 && pageno
< Array.length
b
1460 let (_
, _
, _
, (_
, w, h, _
)) = b.(pageno
) in
1464 let gotopagexy1 wtmode pageno
x y =
1465 let _,w1,h1
,leftx
= getpagedim pageno
in
1466 let top = y /. (float h1
) in
1467 let left = x /. (float w1) in
1468 let py, w, h = getpageywh pageno
in
1469 let wh = state
.winh
in
1470 let x = left *. (float w) in
1471 let x = leftx
+ state
.x + truncate
x in
1473 if x < 0 || x >= state
.winw
1477 let pdy = truncate
(top *. float h) in
1478 let y'
= py + pdy in
1479 let dy = y'
- state
.y in
1481 if x != state
.x || not
(dy > 0 && dy < wh)
1483 if conf
.presentation
1485 if abs
(py - y'
) > wh
1492 if state
.x != sx || state
.y != sy
1497 let ww = state
.winw
in
1499 and qy
= pdy / wh in
1501 and y = py + qy
* wh in
1502 let x = if -x + ww > w1 then -(w1-ww) else x
1503 and y'
= if y + wh > state
.maxy
then state
.maxy
- wh else y in
1505 if conf
.presentation
1507 if abs
(py - y'
) > wh
1516 gotoxy_and_clear_text x y;
1518 else gotoxy_and_clear_text state
.x state
.y;
1521 let gotopagexy wtmode pageno
x y =
1522 match state
.mode
with
1523 | Birdseye
_ -> gotopage pageno
0.0
1526 | LinkNav
_ -> gotopagexy1 wtmode pageno
x y
1529 let getpassword () =
1530 let passcmd = getenvwithdef
"LLPP_ASKPASS" conf
.passcmd in
1535 impmsg "error getting password: %s" s;
1536 dolog
"%s" s) passcmd;
1539 let pgoto opaque pageno
x y =
1540 let pdimno = getpdimno pageno
in
1541 let x, y = project opaque pageno
pdimno x y in
1542 gotopagexy false pageno
x y;
1546 (* dolog "%S" cmds; *)
1547 let spl = splitatchar cmds ' '
in
1549 try Scanf.sscanf
s fmt
f
1551 dolog
"error processing '%S': %s" cmds
@@ exntos exn
;
1554 let addoutline outline
=
1555 match state
.currently
with
1556 | Outlining outlines
->
1557 state
.currently
<- Outlining
(outline
:: outlines
)
1558 | Idle
-> state
.currently
<- Outlining
[outline
]
1561 dolog
"invalid outlining state";
1562 logcurrently state
.currently
1567 state
.uioh#infochanged Pdim
;
1569 | "clearrects", "" ->
1570 state
.rects
<- state
.rects1
;
1571 G.postRedisplay "clearrects";
1573 | "continue", args
->
1574 let n = scan args
"%u" (fun n -> n) in
1575 state
.pagecount
<- n;
1576 begin match state
.currently
with
1578 state
.currently
<- Idle
;
1579 state
.outlines
<- Array.of_list
(List.rev
l)
1585 let cur, cmds
= state
.geomcmds
in
1587 then failwith
"umpossible";
1589 begin match List.rev cmds
with
1591 state
.geomcmds
<- E.s, [];
1592 state
.throttle
<- None
;
1596 state
.geomcmds
<- s, List.rev rest
;
1598 if conf
.maxwait
= None
&& not
!wtmode
1599 then G.postRedisplay "continue";
1606 then showtext ' ' args
1609 Buffer.add_string state
.errmsgs args
;
1610 state
.newerrmsgs
<- true;
1611 G.postRedisplay "error message"
1613 | "progress", args
->
1614 let progress, text =
1617 f, String.sub args pos
(String.length args
- pos
))
1620 state
.progress <- progress;
1621 G.postRedisplay "progress"
1623 | "firstmatch", args
->
1624 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1625 scan args
"%u %d %f %f %f %f %f %f %f %f"
1626 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1627 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1629 let y = (getpagey
pageno) + truncate
y0 in
1637 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1638 state
.rects1
<- [pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)]
1641 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1642 scan args
"%u %d %f %f %f %f %f %f %f %f"
1643 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1644 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1646 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1648 (pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) :: state
.rects1
1651 let pageopaques, t
= scan args
"%s %f" (fun p t
-> p
, t
) in
1652 let pageopaque = ~
< pageopaques in
1653 begin match state
.currently
with
1654 | Loading
(l, gen
) ->
1655 vlog "page %d took %f sec" l.pageno t
;
1656 Hashtbl.replace state
.pagemap
(l.pageno, gen
) pageopaque;
1657 begin match state
.throttle
with
1659 let preloadedpages =
1661 then preloadlayout state
.x state
.y state
.winw state
.winh
1666 List.fold_left
(fun s l -> IntSet.add
l.pageno s)
1667 IntSet.empty
preloadedpages
1670 Hashtbl.fold (fun ((pageno, _) as key) opaque
accu ->
1671 if not
(IntSet.mem
pageno set)
1673 wcmd "freepage %s" (~
> opaque
);
1679 List.iter
(Hashtbl.remove state
.pagemap
) evictedpages;
1682 state
.currently
<- Idle
;
1685 tilepage l.pageno pageopaque state
.layout;
1687 load preloadedpages;
1688 let visible = pagevisible state
.layout l.pageno in
1691 match state
.mode
with
1692 | LinkNav
(Ltnotready
(pageno, dir
)) ->
1693 if pageno = l.pageno
1698 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
1700 if dir
> 0 then LDfirst
else LDlast
1703 findlink
pageopaque ld
1708 showlinktype (getlink
pageopaque n);
1709 state
.mode
<- LinkNav
(Ltexact
(l.pageno, n))
1711 | LinkNav
(Ltgendir
_)
1712 | LinkNav
(Ltexact
_)
1718 if visible && layoutready state
.layout
1720 G.postRedisplay "page";
1724 | Some
(layout, _, _) ->
1725 state
.currently
<- Idle
;
1726 tilepage l.pageno pageopaque layout;
1733 dolog
"Inconsistent loading state";
1734 logcurrently state
.currently
;
1739 let (x, y, opaques
, size
, t
) =
1740 scan args
"%u %u %s %u %f"
1741 (fun x y p size t
-> (x, y, p
, size
, t
))
1743 let opaque = ~
< opaques
in
1744 begin match state
.currently
with
1745 | Tiling
(l, pageopaque, cs
, angle
, gen
, col, row, tilew
, tileh
) ->
1746 vlog "tile %d [%d,%d] took %f sec" l.pageno col row t
;
1749 if tilew
!= conf
.tilew
|| tileh
!= conf
.tileh
1751 wcmd "freetile %s" (~
> opaque);
1752 state
.currently
<- Idle
;
1756 puttileopaque l col row gen cs angle
opaque size t
;
1757 state
.memused
<- state
.memused
+ size
;
1758 state
.uioh#infochanged Memused
;
1760 Queue.push
((l.pageno, gen
, cs
, angle
, l.pagew
, l.pageh
, col, row),
1761 opaque, size
) state
.tilelru
;
1764 match state
.throttle
with
1765 | None
-> state
.layout
1766 | Some
(layout, _, _) -> layout
1769 state
.currently
<- Idle
;
1771 && conf
.colorspace
= cs
1772 && conf
.angle
= angle
1773 && tilevisible layout l.pageno x y
1774 then conttiling l.pageno pageopaque;
1776 begin match state
.throttle
with
1778 preload state
.layout;
1780 && conf
.colorspace
= cs
1781 && conf
.angle
= angle
1782 && tilevisible state
.layout l.pageno x y
1783 && (not
!wtmode || layoutready state
.layout)
1784 then G.postRedisplay "tile nothrottle";
1786 | Some
(layout, y, _) ->
1787 let ready = layoutready layout in
1791 state
.layout <- layout;
1792 state
.throttle
<- None
;
1793 G.postRedisplay "throttle";
1802 dolog
"Inconsistent tiling state";
1803 logcurrently state
.currently
;
1808 let (n, w, h, _) as pdim
=
1809 scan args
"%u %u %u %u" (fun n w h x -> n, w, h, x)
1812 match conf
.fitmodel
with
1814 | FitPage
| FitProportional
->
1815 match conf
.columns
with
1816 | Csplit
_ -> (n, w, h, 0)
1817 | Csingle
_ | Cmulti
_ -> pdim
1819 state
.pdims
<- pdim :: state
.pdims
;
1820 state
.uioh#infochanged Pdim
1823 let (l, n, t
, h, pos
) =
1824 scan args
"%u %u %d %u %n"
1825 (fun l n t
h pos
-> l, n, t
, h, pos
)
1827 let s = String.sub args pos
(String.length args
- pos
) in
1828 addoutline (s, l, Oanchor
(n, float t
/. float h, 0.0))
1831 let (l, len, pos
) = scan args
"%u %u %n" (fun l len pos
-> l, len, pos
) in
1832 let s = String.sub args pos
len in
1833 let pos2 = pos
+ len + 1 in
1834 let uri = String.sub args
pos2 (String.length args
- pos2) in
1835 addoutline (s, l, Ouri
uri)
1838 let (l, pos
) = scan args
"%u %n" (fun l pos
-> l, pos
) in
1839 let s = String.sub args pos
(String.length args
- pos
) in
1840 addoutline (s, l, Onone
)
1844 scan args
"%u %d %d" (fun n l t
-> n, l, t
)
1846 state
.reprf
<- (fun () -> gotopagexy !wtmode n (float l) (float t
))
1849 let pos = nindex args '
\t'
in
1853 if substratis args
0 "Title"
1855 let s = String.sub args
(pos+1) @@ String.length args
- pos - 1 in
1860 if substratis args
0 "CreationDate"
1862 if String.length args
>= pos + 7
1863 && args
.[pos+1] = 'D'
&& args
.[pos+2] = '
:'
1865 let b = Buffer.create
18 in
1866 Buffer.add_string
b "CreationDate\t";
1869 Buffer.add_substring
b args
(pos+p
+1) l;
1870 Buffer.add_char
b c;
1871 with exn
-> Buffer.add_string
b @@ exntos exn
1879 Buffer.add_char
b '
['
;
1880 Buffer.add_substring
b args
(pos+1)
1881 (String.length args
- pos - 1);
1882 Buffer.add_char
b '
]'
;
1889 state
.docinfo
<- (1, s) :: state
.docinfo
1892 state
.docinfo
<- List.rev state
.docinfo
;
1893 state
.uioh#infochanged Docinfo
1897 then Wsi.settitle
"Wrong password";
1898 let password = getpassword () in
1899 if emptystr
password
1900 then error
"document is password protected"
1901 else opendoc state
.path
password
1904 error
"unknown cmd `%S'" cmds
1909 let action = function
1910 | HCprev
-> cbget cb ~
-1
1911 | HCnext
-> cbget cb
1
1912 | HCfirst
-> cbget cb ~
-(cb
.rc)
1913 | HClast
-> cbget cb
(cb
.len - 1 - cb
.rc)
1914 and cancel
() = cb
.rc <- rc
1918 let search pattern forward
=
1919 match conf
.columns
with
1920 | Csplit
_ -> impmsg "searching does not work properly in split columns mode"
1923 if nonemptystr pattern
1926 match state
.layout with
1929 l.pageno, (l.pagey + if forward
then 0 else 0*l.pagevh)
1931 wcmd "search %d %d %d %d,%s\000"
1932 (btod conf
.icase
) pn py (btod forward
) pattern
;
1935 let intentry text key =
1937 if key >= 32 && key < 127
1939 let c = Char.chr
key in
1941 | '
0'
.. '
9'
-> addchar
text c
1943 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key c;
1946 state
.text <- Printf.sprintf
"invalid key (%d)" key;
1957 let l = String.length
s in
1958 let rec loop pos n =
1962 let m = Char.code
s.[pos] - (if pos = 0 && l > 1 then 96 else 97) in
1963 loop (pos+1) (n*26 + m)
1966 let rec loop n = function
1969 match getopaque l.pageno with
1970 | None
-> loop n rest
1972 let m = getlinkcount
opaque in
1975 let under = getlink
opaque n in
1978 else loop (n-m) rest
1980 loop n state
.layout;
1984 let linknentry text key =
1985 if key >= 32 && key < 127
1987 let text = addchar
text (Char.chr
key) in
1988 linknact (fun under -> state
.text <- undertext under) text;
1991 state
.text <- Printf.sprintf
"invalid key %d" key;
1996 let textentry text key =
1997 if Wsi.isspecialkey
key
1999 else TEcont
(text ^ toutf8
key)
2002 let reqlayout angle fitmodel
=
2003 match state
.throttle
with
2005 if nogeomcmds state
.geomcmds
2006 then state
.anchor <- getanchor
();
2007 conf
.angle
<- angle
mod 360;
2010 match state
.mode
with
2011 | LinkNav
_ -> state
.mode
<- View
2016 conf
.fitmodel
<- fitmodel
;
2020 wcmd "reqlayout %d %d %d"
2021 conf
.angle
(FMTE.to_int conf
.fitmodel
) (stateh state
.winh
)
2026 let settrim trimmargins trimfuzz
=
2027 if nogeomcmds state
.geomcmds
2028 then state
.anchor <- getanchor
();
2029 conf
.trimmargins
<- trimmargins
;
2030 conf
.trimfuzz
<- trimfuzz
;
2031 let x0, y0, x1, y1 = trimfuzz
in
2033 "settrim" (fun () ->
2034 wcmd "settrim %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1);
2039 match state
.throttle
with
2041 let zoom = max
0.0001 zoom in
2042 if zoom <> conf
.zoom
2044 state
.prevzoom
<- (conf
.zoom, state
.x);
2046 reshape state
.winw state
.winh
;
2047 state
.text <- Printf.sprintf
"zoom is now %-5.2f" (zoom *. 100.0);
2050 | Some
(layout, y, started
) ->
2052 match conf
.maxwait
with
2056 let dt = now
() -. started
in
2064 let pivotzoom ?
(vw=min state
.w state
.winw
)
2065 ?
(vh
=min
(state
.maxy
-state
.y) state
.winh
)
2066 ?
(x=vw/2) ?
(y=vh
/2) zoom =
2067 let w = float state
.w /. zoom in
2068 let hw = w /. 2.0 in
2069 let ratio = float vh
/. float vw in
2070 let hh = hw *. ratio in
2071 let x0 = if zoom < 1.0 then 0.0 else float x -. hw in
2072 let y0 = float y -. hh in
2073 gotoxy (state
.x - truncate
x0) (state
.y + truncate
y0);
2077 let pivotzoom ?
vw ?vh ?
x ?
y zoom =
2078 if nogeomcmds state
.geomcmds
then pivotzoom ?
vw ?vh ?
x ?
y zoom
2081 let setcolumns mode columns coverA coverB
=
2082 state
.prevcolumns
<- Some
(conf
.columns
, conf
.zoom);
2086 then impmsg "split mode doesn't work in bird's eye"
2088 conf
.columns
<- Csplit
(-columns
, E.a);
2096 conf
.columns
<- Csingle
E.a;
2101 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), E.a);
2105 reshape state
.winw state
.winh
;
2108 let resetmstate () =
2109 state
.mstate
<- Mnone
;
2110 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
2113 let enterbirdseye () =
2114 let zoom = float conf
.thumbw
/. float state
.winw
in
2115 let birdseyepageno =
2116 let cy = state
.winh
/ 2 in
2120 let rec fold best
= function
2123 let d = cy - (l.pagedispy + l.pagevh/2)
2124 and dbest
= cy - (best
.pagedispy + best
.pagevh/2) in
2125 if abs
d < abs dbest
2134 { conf
with zoom = conf
.zoom },
2135 state
.x, birdseyepageno, -1, getanchor
()
2139 conf
.presentation
<- false;
2140 conf
.interpagespace
<- 10;
2141 conf
.hlinks
<- false;
2142 conf
.fitmodel
<- FitPage
;
2144 conf
.maxwait
<- None
;
2146 match conf
.beyecolumns
with
2149 Cmulti
((c, 0, 0), E.a)
2150 | None
-> Csingle
E.a
2154 state
.text <- Printf.sprintf
"birds eye mode on (zoom %3.1f%%)"
2159 reshape state
.winw state
.winh
;
2162 let leavebirdseye (c, leftx
, pageno, _, anchor) goback
=
2164 conf
.zoom <- c.zoom;
2165 conf
.presentation
<- c.presentation
;
2166 conf
.interpagespace
<- c.interpagespace
;
2167 conf
.maxwait
<- c.maxwait
;
2168 conf
.hlinks
<- c.hlinks
;
2169 conf
.fitmodel
<- c.fitmodel
;
2170 conf
.beyecolumns
<- (
2171 match conf
.columns
with
2172 | Cmulti
((c, _, _), _) -> Some
c
2174 | Csplit
_ -> failwith
"leaving bird's eye split mode"
2177 match c.columns
with
2178 | Cmulti
(c, _) -> Cmulti
(c, E.a)
2179 | Csingle
_ -> Csingle
E.a
2180 | Csplit
(c, _) -> Csplit
(c, E.a)
2184 state
.text <- Printf.sprintf
"birds eye mode off (zoom %3.1f%%)"
2187 reshape state
.winw state
.winh
;
2188 state
.anchor <- if goback
then anchor else (pageno, 0.0, 1.0);
2192 let togglebirdseye () =
2193 match state
.mode
with
2194 | Birdseye vals
-> leavebirdseye vals
true
2195 | View
-> enterbirdseye ()
2196 | Textentry
_ | LinkNav
_ -> ()
2199 let upbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2200 let pageno = max
0 (pageno - incr
) in
2201 let rec loop = function
2202 | [] -> gotopage1 pageno 0
2203 | l :: _ when l.pageno = pageno ->
2204 if l.pagedispy >= 0 && l.pagey = 0
2205 then G.postRedisplay "upbirdseye"
2206 else gotopage1 pageno 0
2207 | _ :: rest
-> loop rest
2211 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor)
2214 let downbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2215 let pageno = min
(state
.pagecount
- 1) (pageno + incr
) in
2216 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor);
2217 let rec loop = function
2219 let y, h = getpageyh
pageno in
2220 let dy = (y - state
.y) - (state
.winh
- h - conf
.interpagespace
) in
2221 gotoxy state
.x (clamp dy)
2222 | l :: _ when l.pageno = pageno ->
2223 if l.pagevh != l.pageh
2224 then gotoxy state
.x (clamp (l.pageh
- l.pagevh + conf
.interpagespace
))
2225 else G.postRedisplay "downbirdseye"
2226 | _ :: rest
-> loop rest
2232 let optentry mode
_ key =
2233 let btos b = if b then "on" else "off" in
2234 if key >= 32 && key < 127
2236 let c = Char.chr
key in
2240 try conf
.scrollstep
<- int_of_string
s with exn
->
2241 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2243 TEswitch
("scroll step: ", E.s, None
, intentry, ondone, true)
2248 conf
.autoscrollstep
<- boundastep state
.winh
(int_of_string
s);
2249 if state
.autoscroll
<> None
2250 then state
.autoscroll
<- Some conf
.autoscrollstep
2252 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2254 TEswitch
("auto scroll step: ", E.s, None
, intentry, ondone, true)
2259 let n, a, b = multicolumns_of_string
s in
2260 setcolumns mode
n a b;
2262 state
.text <- Printf.sprintf
"bad columns `%s': %s" s @@ exntos exn
2264 TEswitch
("columns: ", E.s, None
, textentry, ondone, true)
2269 let zoom = float (int_of_string
s) /. 100.0 in
2272 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2274 TEswitch
("zoom: ", E.s, None
, intentry, ondone, true)
2279 conf
.thumbw
<- bound
(int_of_string
s) 2 4096;
2281 Printf.sprintf
"thumbnail width is set to %d" conf
.thumbw
;
2282 begin match mode
with
2284 leavebirdseye beye
false;
2291 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2293 TEswitch
("thumbnail width: ", E.s, None
, intentry, ondone, true)
2297 match int_of_string
s with
2298 | angle
-> reqlayout angle conf
.fitmodel
2301 Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2303 TEswitch
("rotation: ", E.s, None
, intentry, ondone, true)
2306 conf
.icase
<- not conf
.icase
;
2307 TEdone
("case insensitive search " ^
(btos conf
.icase
))
2310 conf
.preload <- not conf
.preload;
2311 gotoxy state
.x state
.y;
2312 TEdone
("preload " ^
(btos conf
.preload))
2315 conf
.verbose
<- not conf
.verbose
;
2316 TEdone
("verbose " ^
(btos conf
.verbose
))
2319 conf
.debug
<- not conf
.debug
;
2320 TEdone
("debug " ^
(btos conf
.debug
))
2323 conf
.maxhfit
<- not conf
.maxhfit
;
2324 state
.maxy
<- calcheight
();
2325 TEdone
("maxhfit " ^
(btos conf
.maxhfit
))
2328 conf
.crophack
<- not conf
.crophack
;
2329 TEdone
("crophack " ^
btos conf
.crophack
)
2333 match conf
.maxwait
with
2335 conf
.maxwait
<- Some infinity
;
2336 "always wait for page to complete"
2338 conf
.maxwait
<- None
;
2339 "show placeholder if page is not ready"
2344 conf
.underinfo
<- not conf
.underinfo
;
2345 TEdone
("underinfo " ^
btos conf
.underinfo
)
2348 conf
.savebmarks
<- not conf
.savebmarks
;
2349 TEdone
("persistent bookmarks " ^
btos conf
.savebmarks
)
2355 match state
.layout with
2360 conf
.interpagespace
<- int_of_string
s;
2361 docolumns conf
.columns
;
2362 state
.maxy
<- calcheight
();
2363 let y = getpagey
pageno in
2364 gotoxy state
.x (y + py)
2367 Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2369 TEswitch
("vertical margin: ", E.s, None
, intentry, ondone, true)
2373 match conf
.fitmodel
with
2374 | FitProportional
-> FitWidth
2375 | FitWidth
| FitPage
-> FitProportional
2377 reqlayout conf
.angle
fm;
2378 TEdone
("proportional display " ^
btos (fm == FitProportional
))
2381 settrim (not conf
.trimmargins
) conf
.trimfuzz
;
2382 TEdone
("trim margins " ^
btos conf
.trimmargins
)
2385 conf
.invert
<- not conf
.invert
;
2386 TEdone
("invert colors " ^
btos conf
.invert
)
2390 cbput state
.hists
.sel
s;
2393 TEswitch
("selection command: ", E.s, Some
(onhist state
.hists
.sel
),
2394 textentry, ondone, true)
2398 then conf
.pax
<- Some
(ref (0.0, 0, 0))
2399 else conf
.pax
<- None
;
2400 TEdone
("PAX " ^
btos (conf
.pax
!= None
))
2403 state
.text <- Printf.sprintf
"bad option %d `%c'" key c;
2409 class type lvsource
=
2411 method getitemcount
: int
2412 method getitem
: int -> (string * int)
2413 method hasaction
: int -> bool
2421 method getactive
: int
2422 method getfirst
: int
2424 method getminfo
: (int * int) array
2427 class virtual lvsourcebase
= object
2428 val mutable m_active
= 0
2429 val mutable m_first
= 0
2430 val mutable m_pan
= 0
2431 method getactive
= m_active
2432 method getfirst
= m_first
2433 method getpan
= m_pan
2434 method getminfo
: (int * int) array
= E.a
2437 let textentrykeyboard
2438 key _mask
((c, text, opthist
, onkey
, ondone, cancelonempty
), onleave
) =
2440 let key = Wsi.keypadtodigitkey
key in
2442 state
.mode
<- Textentry
(te
, onleave
);
2444 G.postRedisplay "textentrykeyboard enttext";
2446 let histaction cmd
=
2449 | Some
(action, _) ->
2452 (c, action cmd
, opthist
, onkey
, ondone, cancelonempty
), onleave
2454 G.postRedisplay "textentry histaction"
2458 if emptystr
text && cancelonempty
2461 G.postRedisplay "textentrykeyboard after cancel";
2464 let s = withoutlastutf8
text in
2465 enttext (c, s, opthist
, onkey
, ondone, cancelonempty
)
2467 | @enter
| @kpenter
->
2470 G.postRedisplay "textentrykeyboard after confirm"
2472 | @up
| @kpup
-> histaction HCprev
2473 | @down
| @kpdown
-> histaction HCnext
2474 | @home
| @kphome
-> histaction HCfirst
2475 | @jend
| @kpend
-> histaction HClast
2480 begin match opthist
with
2482 | Some
(_, onhistcancel
) -> onhistcancel
()
2486 G.postRedisplay "textentrykeyboard after cancel2"
2489 enttext (c, E.s, opthist
, onkey
, ondone, cancelonempty
)
2492 | @delete
| @kpdelete
-> ()
2494 | _ when key != 0 && not
(Wsi.isspecialkey
key) ->
2495 begin match onkey
text key with
2499 G.postRedisplay "textentrykeyboard after confirm2";
2502 enttext (c, text, opthist
, onkey
, ondone, cancelonempty
);
2506 G.postRedisplay "textentrykeyboard after cancel3"
2509 state
.mode
<- Textentry
(te
, onleave
);
2510 G.postRedisplay "textentrykeyboard switch";
2514 vlog "unhandled key %s" (Wsi.keyname
key)
2517 let firstof first active
=
2518 if first
> active
|| abs
(first
- active
) > fstate
.maxrows
- 1
2519 then max
0 (active
- (fstate
.maxrows
/2))
2523 let calcfirst first active
=
2526 let rows = active
- first
in
2527 if rows > fstate
.maxrows
then active
- fstate
.maxrows
else first
2531 let scrollph y maxy
=
2532 let sh = float (maxy
+ state
.winh
) /. float state
.winh
in
2533 let sh = float state
.winh
/. sh in
2534 let sh = max
sh (float conf
.scrollh
) in
2536 let percent = float y /. float maxy
in
2537 let position = (float state
.winh
-. sh) *. percent in
2540 if position +. sh > float state
.winh
2541 then float state
.winh
-. sh
2547 let adderrmsg src msg
=
2548 Buffer.add_string state
.errmsgs msg
;
2549 state
.newerrmsgs
<- true;
2553 let adderrfmt src fmt
=
2554 Format.ksprintf
(fun s -> adderrmsg src
s) fmt
;
2557 let coe s = (s :> uioh
);;
2559 class listview ~zebra ~helpmode ~
(source
:lvsource
) ~trusted ~modehash
=
2561 val m_pan
= source#getpan
2562 val m_first
= source#getfirst
2563 val m_active
= source#getactive
2565 val m_prev_uioh
= state
.uioh
2567 method private elemunder
y =
2571 let n = y / (fstate
.fontsize
+1) in
2572 if m_first
+ n < source#getitemcount
2574 if source#hasaction
(m_first
+ n)
2575 then Some
(m_first
+ n)
2582 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
2583 GlDraw.color (0., 0., 0.) ~alpha
:0.85;
2584 filledrect 0. 0. (float state
.winw
) (float state
.winh
);
2585 GlDraw.color (1., 1., 1.);
2586 Gl.enable `texture_2d
;
2587 let fs = fstate
.fontsize
in
2589 let hw = state
.winw
/3 in
2590 let ww = fstate
.wwidth
in
2591 let tabw = 17.0*.ww in
2592 let itemcount = source#getitemcount
in
2593 let minfo = source#getminfo
in
2597 GlMat.translate ~
x:(float conf
.scrollbw
) ();
2599 let x0 = 0.0 and x1 = float (state
.winw
- conf
.scrollbw
- 1) in
2601 if (row - m_first
) > fstate
.maxrows
2604 if row >= 0 && row < itemcount
2606 let (s, level
) = source#getitem
row in
2607 let y = (row - m_first
) * nfs in
2608 let x = 5.0 +. (float (level
+ m_pan
)) *. ww in
2611 (let c = if row land 1 = 0 then 1.0 else 0.92 in (c,c,c));
2615 Gl.disable `texture_2d
;
2616 let alpha = if source#hasaction
row then 0.9 else 0.3 in
2617 GlDraw.color (1., 1., 1.) ~
alpha;
2618 linerect (x0 +. 1.) (float (y + 1)) (x1) (float (y + fs + 3));
2619 Gl.enable `texture_2d
;
2622 if zebra
&& row land 1 = 1
2626 GlDraw.color (c,c,c);
2627 let drawtabularstring s =
2629 let x'
= truncate
(x0 +. x) in
2630 let pos = nindex
s '
\000'
in
2632 then drawstring1 fs x'
(y+nfs) s
2634 let s1 = String.sub s 0 pos
2635 and s2
= String.sub s (pos+1) (String.length
s - pos - 1) in
2640 let s'
= withoutlastutf8
s in
2641 let s = s' ^
"@Uellipsis" in
2642 let w = measurestr
fs s in
2643 if float x'
+. w +. ww < float (hw + x'
)
2648 if float x'
+. ww +. measurestr
fs s1 > float (hw + x'
)
2652 ignore
(drawstring1 fs x'
(y+nfs) s1);
2653 drawstring1 fs (hw + x'
) (y+nfs) s2
2657 let x = if helpmode
&& row > 0 then x +. ww else x in
2658 let tabpos = nindex
s '
\t'
in
2661 let len = String.length
s - tabpos - 1 in
2662 let s1 = String.sub s 0 tabpos
2663 and s2
= String.sub s (tabpos + 1) len in
2664 let nx = drawstr x s1 in
2666 let x = x +. (max
tabw sw) in
2669 let len = String.length
s - 2 in
2670 if len > 0 && s.[0] = '
\xc2'
&& s.[1] = '
\xb7'
2672 let s = String.sub s 2 len in
2673 let x = if not helpmode
then x +. ww else x in
2674 GlDraw.color (1.2, 1.2, 1.2);
2675 let vinc = drawstring1 (fs+fs/4)
2676 (truncate
(x -. ww)) (y+nfs) s in
2677 GlDraw.color (1., 1., 1.);
2678 vinc +. (float fs *. 0.8)
2684 ignore
(drawtabularstring s);
2690 GlDraw.color (1.0, 1.0, 1.0) ~
alpha:0.5;
2693 if (row - m_first
) > fstate
.maxrows
2696 if row >= 0 && row < itemcount
2698 let (s, level
) = source#getitem
row in
2699 let pos0 = nindex
s '
\000'
in
2700 let y = (row - m_first
) * nfs in
2701 let x = float (level
+ m_pan
) *. ww in
2702 let (first
, last
) = minfo.(row) in
2704 if pos0 > 0 && first
> pos0
2705 then String.sub s (pos0+1) (first
-pos0-1)
2706 else String.sub s 0 first
2708 let suffix = String.sub s first
(last
- first
) in
2709 let w1 = measurestr fstate
.fontsize
prefix in
2710 let w2 = measurestr fstate
.fontsize
suffix in
2711 let x = x +. if conf
.leftscroll
then xadj else 5.0 in
2712 let x = if pos0 > 0 && first
> pos0 then x +. float hw else x in
2714 and y0 = float (y+2) in
2716 and y1 = float (y+fs+3) in
2717 filledrect x0 y0 x1 y1;
2722 Gl.disable `texture_2d
;
2723 if Array.length
minfo > 0 then loop m_first
;
2728 method updownlevel incr
=
2729 let len = source#getitemcount
in
2731 if m_active
>= 0 && m_active
< len
2732 then snd
(source#getitem m_active
)
2736 if i
= len then i
-1 else if i
= -1 then 0 else
2737 let _, l = source#getitem i
in
2738 if l != curlevel then i
else flow (i
+incr
)
2740 let active = flow m_active
in
2741 let first = calcfirst m_first
active in
2742 G.postRedisplay "outline updownlevel";
2743 {< m_active
= active; m_first
= first >}
2745 method private key1
key mask
=
2746 let set1 active first qsearch
=
2747 coe {< m_active
= active; m_first
= first; m_qsearch
= qsearch
>}
2749 let search active pattern incr
=
2750 let active = if active = -1 then m_first
else active in
2753 if n >= 0 && n < source#getitemcount
2755 let s, _ = source#getitem
n in
2756 match Str.search_forward re
s 0 with
2757 | (exception Not_found
) -> loop (n + incr
)
2764 let qpat = Str.quote pattern
in
2765 match Str.regexp_case_fold
qpat with
2768 adderrfmt "listview key1" "regexp_case_fold for `%S' failed: %S\n"
2769 qpat @@ Printexc.to_string exn
;
2772 let itemcount = source#getitemcount
in
2773 let find start incr
=
2775 if i
= -1 || i
= itemcount
2778 if source#hasaction i
2780 else find (i
+ incr
)
2785 let set active first =
2786 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2788 coe {< m_active
= active; m_first
= first; m_qsearch
= E.s >}
2791 let isvisible first n = n >= first && n - first <= fstate
.maxrows
in
2793 let incr1 = if incr
> 0 then 1 else -1 in
2794 if isvisible m_first m_active
2797 let next = m_active
+ incr
in
2799 if next < 0 || next >= itemcount
2801 else find next incr1
2803 if abs
(m_active
- next) > fstate
.maxrows
2809 let first = m_first
+ incr
in
2810 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2812 let next = m_active
+ incr
in
2813 let next = bound
next 0 (itemcount - 1) in
2820 if isvisible first next
2827 let first = min
next m_first
in
2829 if abs
(next - first) > fstate
.maxrows
2835 let first = m_first
+ incr
in
2836 let first = bound
first 0 (itemcount - 1) in
2838 let next = m_active
+ incr
in
2839 let next = bound
next 0 (itemcount - 1) in
2840 let next = find next incr1 in
2842 if next = -1 || abs
(m_active
- first) > fstate
.maxrows
2844 let active = if m_active
= -1 then next else m_active
in
2849 if isvisible first active
2855 G.postRedisplay "listview navigate";
2859 | (@r
|@s) when Wsi.withctrl mask
->
2860 let incr = if key = @r
then -1 else 1 in
2862 match search (m_active
+ incr) m_qsearch
incr with
2864 state
.text <- m_qsearch ^
" [not found]";
2867 state
.text <- m_qsearch
;
2868 active, firstof m_first
active
2870 G.postRedisplay "listview ctrl-r/s";
2871 set1 active first m_qsearch
;
2873 | @insert
when Wsi.withctrl mask
->
2874 if m_active
>= 0 && m_active
< source#getitemcount
2876 let s, _ = source#getitem m_active
in
2882 if emptystr m_qsearch
2885 let qsearch = withoutlastutf8 m_qsearch
in
2889 G.postRedisplay "listview empty qsearch";
2890 set1 m_active m_first
E.s;
2894 match search m_active
qsearch ~
-1 with
2896 state
.text <- qsearch ^
" [not found]";
2899 state
.text <- qsearch;
2900 active, firstof m_first
active
2902 G.postRedisplay "listview backspace qsearch";
2903 set1 active first qsearch
2906 | key when (key != 0 && not
(Wsi.isspecialkey
key)) ->
2907 let pattern = m_qsearch ^ toutf8
key in
2909 match search m_active
pattern 1 with
2911 state
.text <- pattern ^
" [not found]";
2914 state
.text <- pattern;
2915 active, firstof m_first
active
2917 G.postRedisplay "listview qsearch add";
2918 set1 active first pattern;
2922 if emptystr m_qsearch
2924 G.postRedisplay "list view escape";
2925 let mx, my
= state
.mpos
in
2929 source#exit ~uioh
:(coe self
)
2930 ~cancel
:true ~
active:m_active ~
first:m_first ~pan
:m_pan
2932 | None
-> m_prev_uioh
2937 G.postRedisplay "list view kill qsearch";
2938 coe {< m_qsearch
= E.s >}
2941 | @enter
| @kpenter
->
2943 let self = {< m_qsearch
= E.s >} in
2945 G.postRedisplay "listview enter";
2946 if m_active
>= 0 && m_active
< source#getitemcount
2948 source#exit ~uioh
:(coe self) ~cancel
:false
2949 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2952 source#exit ~uioh
:(coe self) ~cancel
:true
2953 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2956 begin match opt with
2957 | None
-> m_prev_uioh
2961 | @delete
| @kpdelete
->
2964 | @up
| @kpup
-> navigate ~
-1
2965 | @down
| @kpdown
-> navigate 1
2966 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows
)
2967 | @next | @kpnext
-> navigate fstate
.maxrows
2969 | @right
| @kpright
->
2971 G.postRedisplay "listview right";
2972 coe {< m_pan
= m_pan
- 1 >}
2974 | @left | @kpleft
->
2976 G.postRedisplay "listview left";
2977 coe {< m_pan
= m_pan
+ 1 >}
2979 | @home
| @kphome
->
2980 let active = find 0 1 in
2981 G.postRedisplay "listview home";
2985 let first = max
0 (itemcount - fstate
.maxrows
) in
2986 let active = find (itemcount - 1) ~
-1 in
2987 G.postRedisplay "listview end";
2990 | key when (key = 0 || Wsi.isspecialkey
key) ->
2994 dolog
"listview unknown key %#x" key; coe self
2996 method key key mask
=
2997 match state
.mode
with
2998 | Textentry te
-> textentrykeyboard key mask te
; coe self
3001 | LinkNav
_ -> self#key1
key mask
3003 method button button down
x y _ =
3006 | 1 when vscrollhit x ->
3007 G.postRedisplay "listview scroll";
3010 let _, position, sh = self#
scrollph in
3011 if y > truncate
position && y < truncate
(position +. sh)
3013 state
.mstate
<- Mscrolly
;
3017 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3018 let first = truncate
(s *. float source#getitemcount
) in
3019 let first = min source#getitemcount
first in
3020 Some
(coe {< m_first
= first; m_active
= first >})
3022 state
.mstate
<- Mnone
;
3026 begin match self#elemunder
y with
3028 G.postRedisplay "listview click";
3029 source#exit ~uioh
:(coe {< m_active
= n >})
3030 ~cancel
:false ~
active:n ~
first:m_first ~pan
:m_pan
3034 | n when (n == 4 || n == 5) && not down
->
3035 let len = source#getitemcount
in
3037 if n = 5 && m_first
+ fstate
.maxrows
>= len
3041 let first = m_first
+ (if n == 4 then -1 else 1) in
3042 bound
first 0 (len - 1)
3044 G.postRedisplay "listview wheel";
3045 Some
(coe {< m_first
= first >})
3046 | n when (n = 6 || n = 7) && not down
->
3047 let inc = if n = 7 then -1 else 1 in
3048 G.postRedisplay "listview hwheel";
3049 Some
(coe {< m_pan
= m_pan
+ inc >})
3054 | None
-> m_prev_uioh
3057 method multiclick
_ x y = self#button
1 true x y
3060 match state
.mstate
with
3062 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3063 let first = truncate
(s *. float source#getitemcount
) in
3064 let first = min source#getitemcount
first in
3065 G.postRedisplay "listview motion";
3066 coe {< m_first
= first; m_active
= first >}
3074 method pmotion
x y =
3075 if x < state
.winw
- conf
.scrollbw
3078 match self#elemunder
y with
3079 | None
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
; m_active
3080 | Some
n -> Wsi.setcursor
Wsi.CURSOR_INFO
; n
3084 then (G.postRedisplay "listview pmotion"; {< m_active
= n >})
3089 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
3093 method infochanged
_ = ()
3095 method scrollpw
= (0, 0.0, 0.0)
3097 let nfs = fstate
.fontsize
+ 1 in
3098 let y = m_first
* nfs in
3099 let itemcount = source#getitemcount
in
3100 let maxi = max
0 (itemcount - fstate
.maxrows
) in
3101 let maxy = maxi * nfs in
3102 let p, h = scrollph y maxy in
3105 method modehash
= modehash
3106 method eformsgs
= false
3107 method alwaysscrolly
= true
3110 class outlinelistview ~zebra ~source
=
3111 let settext autonarrow
s =
3114 let ss = source#statestr
in
3118 else "{" ^
ss ^
"} [" ^
s ^
"]"
3119 else state
.text <- s
3125 ~source
:(source
:> lvsource
)
3127 ~modehash
:(findkeyhash conf
"outline")
3130 val m_autonarrow
= false
3132 method! key key mask
=
3134 if emptystr state
.text
3136 else fstate
.maxrows - 2
3138 let calcfirst first active =
3141 let rows = active - first in
3142 if rows > maxrows then active - maxrows else first
3146 let active = m_active
+ incr in
3147 let active = bound
active 0 (source#getitemcount
- 1) in
3148 let first = calcfirst m_first
active in
3149 G.postRedisplay "outline navigate";
3150 coe {< m_active
= active; m_first
= first >}
3152 let navscroll first =
3154 let dist = m_active
- first in
3160 else first + maxrows
3163 G.postRedisplay "outline navscroll";
3164 coe {< m_first
= first; m_active
= active >}
3166 let ctrl = Wsi.withctrl mask
in
3171 then (source#denarrow
; E.s)
3173 let pattern = source#renarrow
in
3174 if nonemptystr m_qsearch
3175 then (source#narrow m_qsearch
; m_qsearch
)
3179 settext (not m_autonarrow
) text;
3180 G.postRedisplay "toggle auto narrowing";
3181 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= not m_autonarrow
>}
3183 | @slash
when emptystr m_qsearch
&& not m_autonarrow
->
3185 G.postRedisplay "toggle auto narrowing";
3186 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= true >}
3189 source#narrow m_qsearch
;
3191 then source#add_narrow_pattern m_qsearch
;
3192 G.postRedisplay "outline ctrl-n";
3193 coe {< m_first
= 0; m_active
= 0 >}
3196 let active = source#calcactive
(getanchor
()) in
3197 let first = firstof m_first
active in
3198 G.postRedisplay "outline ctrl-s";
3199 coe {< m_first
= first; m_active
= active >}
3202 G.postRedisplay "outline ctrl-u";
3203 if m_autonarrow
&& nonemptystr m_qsearch
3205 ignore
(source#renarrow
);
3206 settext m_autonarrow
E.s;
3207 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3210 source#del_narrow_pattern
;
3211 let pattern = source#renarrow
in
3213 if emptystr
pattern then E.s else "Narrowed to " ^
pattern
3215 settext m_autonarrow
text;
3216 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3220 let first = max
0 (m_active
- (fstate
.maxrows / 2)) in
3221 G.postRedisplay "outline ctrl-l";
3222 coe {< m_first
= first >}
3224 | @tab
when m_autonarrow
->
3225 if nonemptystr m_qsearch
3227 G.postRedisplay "outline list view tab";
3228 source#add_narrow_pattern m_qsearch
;
3230 coe {< m_qsearch
= E.s >}
3234 | @escape
when m_autonarrow
->
3235 if nonemptystr m_qsearch
3236 then source#add_narrow_pattern m_qsearch
;
3239 | @enter
| @kpenter
when m_autonarrow
->
3240 if nonemptystr m_qsearch
3241 then source#add_narrow_pattern m_qsearch
;
3244 | key when m_autonarrow
&& (not
(Wsi.isspecialkey
key)) ->
3245 let pattern = m_qsearch ^ toutf8
key in
3246 G.postRedisplay "outlinelistview autonarrow add";
3247 source#narrow
pattern;
3248 settext true pattern;
3249 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3251 | key when m_autonarrow
&& key = @backspace
->
3252 if emptystr m_qsearch
3255 let pattern = withoutlastutf8 m_qsearch
in
3256 G.postRedisplay "outlinelistview autonarrow backspace";
3257 ignore
(source#renarrow
);
3258 source#narrow
pattern;
3259 settext true pattern;
3260 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3262 | @up
| @kpup
when ctrl ->
3263 navscroll (max
0 (m_first
- 1))
3265 | @down
| @kpdown
when ctrl ->
3266 navscroll (min
(source#getitemcount
- 1) (m_first
+ 1))
3268 | @up
| @kpup
-> navigate ~
-1
3269 | @down
| @kpdown
-> navigate 1
3270 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows)
3271 | @next | @kpnext
-> navigate fstate
.maxrows
3273 | @right
| @kpright
->
3277 G.postRedisplay "outline ctrl right";
3278 {< m_pan
= m_pan
+ 1 >}
3280 else self#updownlevel
1
3284 | @left | @kpleft
->
3288 G.postRedisplay "outline ctrl left";
3289 {< m_pan
= m_pan
- 1 >}
3291 else self#updownlevel ~
-1
3295 | @home
| @kphome
->
3296 G.postRedisplay "outline home";
3297 coe {< m_first
= 0; m_active
= 0 >}
3300 let active = source#getitemcount
- 1 in
3301 let first = max
0 (active - fstate
.maxrows) in
3302 G.postRedisplay "outline end";
3303 coe {< m_active
= active; m_first
= first >}
3305 | _ -> super#
key key mask
3308 let genhistoutlines () =
3310 |> List.sort
(fun (_, c1
, _, _, _, _) (_, c2
, _, _, _, _) ->
3311 compare c2
.lastvisit c1
.lastvisit
)
3313 (fun ((path
, c, _, _, _, origin
) as hist
) ->
3314 let path = if nonemptystr origin
then origin
else path in
3315 let base = mbtoutf8
@@ Filename.basename
path in
3316 (base ^
"\000" ^
c.title
, 1, Ohistory hist
)
3321 let gotohist (path, c, bookmarks
, x, anchor, origin
) =
3322 Config.save
leavebirdseye;
3323 state
.anchor <- anchor;
3324 state
.bookmarks
<- bookmarks
;
3325 state
.origin
<- origin
;
3328 let x0, y0, x1, y1 = conf
.trimfuzz
in
3329 wcmd "trimset %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1;
3330 reshape ~firsttime
:true state
.winw state
.winh
;
3331 opendoc path origin
;
3335 let makecheckers () =
3336 (* Based on lablGL-1.04/LablGlut/examples/lablGL/checker.ml which had
3338 converted by Issac Trotts. July 25, 2002 *)
3339 let image = GlPix.create `ubyte ~format
:`luminance ~width
:2 ~height
:2 in
3340 Raw.sets_string
(GlPix.to_raw
image) ~
pos:0 "\255\200\200\255";
3341 let id = GlTex.gen_texture
() in
3342 GlTex.bind_texture ~target
:`texture_2d
id;
3343 GlPix.store
(`unpack_alignment
1);
3344 GlTex.image2d
image;
3345 List.iter
(GlTex.parameter ~target
:`texture_2d
)
3346 [ `mag_filter `nearest
; `min_filter `nearest
];
3350 let setcheckers enabled
=
3351 match state
.checkerstexid
with
3353 if enabled
then state
.checkerstexid
<- Some
(makecheckers ())
3355 | Some checkerstexid
->
3358 GlTex.delete_texture checkerstexid
;
3359 state
.checkerstexid
<- None
;
3363 let describe_location () =
3364 let fn = page_of_y state
.y in
3365 let ln = page_of_y
(state
.y + state
.winh
- 1) in
3366 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
3370 else (100. *. (float state
.y /. float maxy))
3374 Printf.sprintf
"page %d of %d [%.2f%%]"
3375 (fn+1) state
.pagecount
percent
3378 "pages %d-%d of %d [%.2f%%]"
3379 (fn+1) (ln+1) state
.pagecount
percent
3382 let setpresentationmode v
=
3383 let n = page_of_y state
.y in
3384 state
.anchor <- (n, 0.0, 1.0);
3385 conf
.presentation
<- v
;
3386 if conf
.fitmodel
= FitPage
3387 then reqlayout conf
.angle conf
.fitmodel
;
3391 let setbgcol (r
, g, b) =
3393 let r = r *. 255.0 |> truncate
3394 and g = g *. 255.0 |> truncate
3395 and b = b *. 255.0 |> truncate
in
3396 r lsl 16 |> (lor) (g lsl 8) |> (lor) b
3398 Wsi.setwinbgcol
col;
3402 let btos b = if b then "@Uradical" else E.s in
3403 let showextended = ref false in
3404 let leave mode
_ = state
.mode
<- mode
in
3407 val mutable m_l
= []
3408 val mutable m_a
= E.a
3409 val mutable m_prev_uioh
= nouioh
3410 val mutable m_prev_mode
= View
3412 inherit lvsourcebase
3414 method reset prev_mode prev_uioh
=
3415 m_a
<- Array.of_list
(List.rev m_l
);
3417 m_prev_mode
<- prev_mode
;
3418 m_prev_uioh
<- prev_uioh
;
3420 method int name get
set =
3426 try set (int_of_string
s)
3428 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3432 let te = name ^
": ", E.s, None
, intentry, ondone, true in
3433 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3437 method int_with_suffix name get
set =
3439 (name
, `intws get
, 1,
3443 try set (int_of_string_with_suffix
s)
3445 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3450 name ^
": ", E.s, None
, intentry_with_suffix, ondone, true
3452 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3456 method bool ?
(offset
=1) ?
(btos=btos) name get
set =
3458 (name
, `
bool (btos, get
), offset
, Action
(
3465 method color name get
set =
3467 (name
, `
color get
, 1,
3470 let invalid = (nan
, nan
, nan
) in
3473 try color_of_string
s
3475 state
.text <- Printf.sprintf
"bad color `%s': %s"
3482 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3483 state
.text <- color_to_string
(get
());
3484 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3488 method string name get
set =
3490 (name
, `
string get
, 1,
3493 let ondone s = set s in
3494 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3495 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3499 method colorspace name get
set =
3501 (name
, `
string get
, 1,
3506 inherit lvsourcebase
3509 m_active
<- CSTE.to_int conf
.colorspace
;
3512 method getitemcount
=
3513 Array.length
CSTE.names
3516 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3517 ignore
(uioh
, first, pan
);
3518 if not cancel
then set active;
3520 method hasaction
_ = true
3524 let modehash = findkeyhash conf
"info" in
3525 coe (new listview ~zebra
:false ~helpmode
:false
3526 ~
source ~trusted
:true ~
modehash)
3529 method paxmark name get
set =
3531 (name
, `
string get
, 1,
3536 inherit lvsourcebase
3539 m_active
<- MTE.to_int conf
.paxmark
;
3542 method getitemcount
= Array.length
MTE.names
3543 method getitem
n = (MTE.names
.(n), 0)
3544 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3545 ignore
(uioh
, first, pan
);
3546 if not cancel
then set active;
3548 method hasaction
_ = true
3552 let modehash = findkeyhash conf
"info" in
3553 coe (new listview ~zebra
:false ~helpmode
:false
3554 ~
source ~trusted
:true ~
modehash)
3557 method fitmodel name get
set =
3559 (name
, `
string get
, 1,
3564 inherit lvsourcebase
3567 m_active
<- FMTE.to_int conf
.fitmodel
;
3570 method getitemcount
= Array.length
FMTE.names
3571 method getitem
n = (FMTE.names
.(n), 0)
3572 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3573 ignore
(uioh
, first, pan
);
3574 if not cancel
then set active;
3576 method hasaction
_ = true
3580 let modehash = findkeyhash conf
"info" in
3581 coe (new listview ~zebra
:false ~helpmode
:false
3582 ~
source ~trusted
:true ~
modehash)
3585 method caption
s offset
=
3586 m_l
<- (s, `empty
, offset
, Noaction
) :: m_l
3588 method caption2
s f offset
=
3589 m_l
<- (s, `
string f, offset
, Noaction
) :: m_l
3591 method getitemcount
= Array.length m_a
3594 let tostr = function
3595 | `
int f -> string_of_int
(f ())
3596 | `intws
f -> string_with_suffix_of_int
(f ())
3598 | `
color f -> color_to_string
(f ())
3599 | `
bool (btos, f) -> btos (f ())
3602 let name, t
, offset
, _ = m_a
.(n) in
3603 ((let s = tostr t
in
3605 then Printf.sprintf
"%s\t%s" name s
3609 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3614 match m_a
.(active) with
3615 | _, _, _, Action
f -> f uioh
3616 | _, _, _, Noaction
-> uioh
3627 method hasaction
n =
3629 | _, _, _, Action
_ -> true
3630 | _, _, _, Noaction
-> false
3632 initializer m_active
<- 1
3635 let rec fillsrc prevmode prevuioh
=
3636 let sep () = src#caption
E.s 0 in
3637 let colorp name get
set =
3639 (fun () -> color_to_string
(get
()))
3642 let c = color_of_string
v in
3646 Printf.sprintf
"bad color `%s': %s" v @@ exntos exn
3649 let oldmode = state
.mode
in
3650 let birdseye = isbirdseye state
.mode
in
3652 src#caption
(if birdseye then "Setup (Bird's eye)" else "Setup") 0;
3654 src#
bool "presentation mode"
3655 (fun () -> conf
.presentation
)
3656 (fun v -> setpresentationmode v);
3658 src#
bool "ignore case in searches"
3659 (fun () -> conf
.icase
)
3660 (fun v -> conf
.icase
<- v);
3663 (fun () -> conf
.preload)
3664 (fun v -> conf
.preload <- v);
3666 src#
bool "highlight links"
3667 (fun () -> conf
.hlinks
)
3668 (fun v -> conf
.hlinks
<- v);
3670 src#
bool "under info"
3671 (fun () -> conf
.underinfo
)
3672 (fun v -> conf
.underinfo
<- v);
3674 src#
bool "persistent bookmarks"
3675 (fun () -> conf
.savebmarks
)
3676 (fun v -> conf
.savebmarks
<- v);
3678 src#fitmodel
"fit model"
3679 (fun () -> FMTE.to_string conf
.fitmodel
)
3680 (fun v -> reqlayout conf
.angle
(FMTE.of_int
v));
3682 src#
bool "trim margins"
3683 (fun () -> conf
.trimmargins
)
3684 (fun v -> settrim v conf
.trimfuzz
; fillsrc prevmode prevuioh
);
3686 src#
bool "persistent location"
3687 (fun () -> conf
.jumpback
)
3688 (fun v -> conf
.jumpback
<- v);
3691 src#
int "inter-page space"
3692 (fun () -> conf
.interpagespace
)
3694 conf
.interpagespace
<- n;
3695 docolumns conf
.columns
;
3697 match state
.layout with
3702 state
.maxy <- calcheight
();
3703 let y = getpagey
pageno in
3704 gotoxy state
.x (y + py)
3708 (fun () -> conf
.pagebias
)
3709 (fun v -> conf
.pagebias
<- v);
3711 src#
int "scroll step"
3712 (fun () -> conf
.scrollstep
)
3713 (fun n -> conf
.scrollstep
<- n);
3715 src#
int "horizontal scroll step"
3716 (fun () -> conf
.hscrollstep
)
3717 (fun v -> conf
.hscrollstep
<- v);
3719 src#
int "auto scroll step"
3721 match state
.autoscroll
with
3723 | _ -> conf
.autoscrollstep
)
3725 let n = boundastep state
.winh
n in
3726 if state
.autoscroll
<> None
3727 then state
.autoscroll
<- Some
n;
3728 conf
.autoscrollstep
<- n);
3731 (fun () -> truncate
(conf
.zoom *. 100.))
3732 (fun v -> pivotzoom ((float v) /. 100.));
3735 (fun () -> conf
.angle
)
3736 (fun v -> reqlayout v conf
.fitmodel
);
3738 src#
int "scroll bar width"
3739 (fun () -> conf
.scrollbw
)
3742 reshape state
.winw state
.winh
;
3745 src#
int "scroll handle height"
3746 (fun () -> conf
.scrollh
)
3747 (fun v -> conf
.scrollh
<- v;);
3749 src#
int "thumbnail width"
3750 (fun () -> conf
.thumbw
)
3752 conf
.thumbw
<- min
4096 v;
3755 leavebirdseye beye
false;
3762 let mode = state
.mode in
3763 src#
string "columns"
3765 match conf
.columns
with
3767 | Cmulti
(multi
, _) -> multicolumns_to_string multi
3768 | Csplit
(count
, _) -> "-" ^ string_of_int count
3771 let n, a, b = multicolumns_of_string
v in
3772 setcolumns mode n a b);
3775 src#caption
"Pixmap cache" 0;
3776 src#int_with_suffix
"size (advisory)"
3777 (fun () -> conf
.memlimit
)
3778 (fun v -> conf
.memlimit
<- v);
3782 Printf.sprintf
"%s bytes, %d tiles"
3783 (string_with_suffix_of_int state
.memused
)
3784 (Hashtbl.length state
.tilemap
)) 1;
3787 src#caption
"Layout" 0;
3788 src#caption2
"Dimension"
3790 Printf.sprintf
"%dx%d (virtual %dx%d)"
3791 state
.winw state
.winh
3796 src#caption2
"Position" (fun () ->
3797 Printf.sprintf
"%dx%d" state
.x state
.y
3800 src#caption2
"Position" (fun () -> describe_location ()) 1
3804 src#
bool ~offset
:0 ~
btos:(fun v -> if v then "(on)" else "(off)")
3805 "Save these parameters as global defaults at exit"
3806 (fun () -> conf
.bedefault
)
3807 (fun v -> conf
.bedefault
<- v)
3811 let btos b = if b then "@Ulguillemet" else "@Urguillemet" in
3812 src#
bool ~offset
:0 ~
btos "Extended parameters"
3813 (fun () -> !showextended)
3814 (fun v -> showextended := v; fillsrc prevmode prevuioh
);
3818 (fun () -> conf
.checkers
)
3819 (fun v -> conf
.checkers
<- v; setcheckers v);
3820 src#
bool "update cursor"
3821 (fun () -> conf
.updatecurs
)
3822 (fun v -> conf
.updatecurs
<- v);
3823 src#
bool "scroll-bar on the left"
3824 (fun () -> conf
.leftscroll
)
3825 (fun v -> conf
.leftscroll
<- v);
3827 (fun () -> conf
.verbose
)
3828 (fun v -> conf
.verbose
<- v);
3829 src#
bool "invert colors"
3830 (fun () -> conf
.invert
)
3831 (fun v -> conf
.invert
<- v);
3833 (fun () -> conf
.maxhfit
)
3834 (fun v -> conf
.maxhfit
<- v);
3836 (fun () -> conf
.pax
!= None
)
3839 then conf
.pax
<- Some
(ref (now
(), 0, 0))
3840 else conf
.pax
<- None
);
3841 src#
string "uri launcher"
3842 (fun () -> conf
.urilauncher
)
3843 (fun v -> conf
.urilauncher
<- v);
3844 src#
string "path launcher"
3845 (fun () -> conf
.pathlauncher
)
3846 (fun v -> conf
.pathlauncher
<- v);
3847 src#
string "tile size"
3848 (fun () -> Printf.sprintf
"%dx%d" conf
.tilew conf
.tileh
)
3851 let w, h = Scanf.sscanf
v "%dx%d" (fun w h -> w, h) in
3852 conf
.tilew
<- max
64 w;
3853 conf
.tileh
<- max
64 h;
3856 state
.text <- Printf.sprintf
"bad tile size `%s': %s"
3859 src#
int "texture count"
3860 (fun () -> conf
.texcount
)
3863 then conf
.texcount
<- v
3864 else impmsg "failed to set texture count please retry later"
3866 src#
int "slice height"
3867 (fun () -> conf
.sliceheight
)
3869 conf
.sliceheight
<- v;
3870 wcmd "sliceh %d" conf
.sliceheight
;
3872 src#
int "anti-aliasing level"
3873 (fun () -> conf
.aalevel
)
3875 conf
.aalevel
<- bound
v 0 8;
3876 state
.anchor <- getanchor
();
3877 opendoc state
.path state
.password;
3879 src#
string "page scroll scaling factor"
3880 (fun () -> string_of_float conf
.pgscale)
3883 let s = float_of_string
v in
3886 state
.text <- Printf.sprintf
3887 "bad page scroll scaling factor `%s': %s" v
3891 src#
int "ui font size"
3892 (fun () -> fstate
.fontsize
)
3893 (fun v -> setfontsize (bound
v 5 100));
3894 src#
int "hint font size"
3895 (fun () -> conf
.hfsize
)
3896 (fun v -> conf
.hfsize
<- bound
v 5 100);
3897 colorp "background color"
3898 (fun () -> conf
.bgcolor
)
3899 (fun v -> conf
.bgcolor
<- v; setbgcol v);
3900 src#
bool "crop hack"
3901 (fun () -> conf
.crophack
)
3902 (fun v -> conf
.crophack
<- v);
3903 src#
string "trim fuzz"
3904 (fun () -> irect_to_string conf
.trimfuzz
)
3907 conf
.trimfuzz
<- irect_of_string
v;
3909 then settrim true conf
.trimfuzz
;
3911 state
.text <- Printf.sprintf
"bad irect `%s': %s" v
3914 src#
string "throttle"
3916 match conf
.maxwait
with
3917 | None
-> "show place holder if page is not ready"
3920 then "wait for page to fully render"
3922 "wait " ^ string_of_float
time
3923 ^
" seconds before showing placeholder"
3927 let f = float_of_string
v in
3929 then conf
.maxwait
<- None
3930 else conf
.maxwait
<- Some
f
3932 state
.text <- Printf.sprintf
"bad time `%s': %s" v
3935 src#
string "ghyll scroll"
3937 match conf
.ghyllscroll
with
3939 | Some nab
-> ghyllscroll_to_string nab
3942 try conf
.ghyllscroll
<- ghyllscroll_of_string
v
3945 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v msg
3947 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v
3950 src#
string "selection command"
3951 (fun () -> conf
.selcmd
)
3952 (fun v -> conf
.selcmd
<- v);
3953 src#
string "synctex command"
3954 (fun () -> conf
.stcmd
)
3955 (fun v -> conf
.stcmd
<- v);
3956 src#
string "pax command"
3957 (fun () -> conf
.paxcmd
)
3958 (fun v -> conf
.paxcmd
<- v);
3959 src#
string "ask password command"
3960 (fun () -> conf
.passcmd)
3961 (fun v -> conf
.passcmd <- v);
3962 src#
string "save path command"
3963 (fun () -> conf
.savecmd
)
3964 (fun v -> conf
.savecmd
<- v);
3965 src#colorspace
"color space"
3966 (fun () -> CSTE.to_string conf
.colorspace
)
3968 conf
.colorspace
<- CSTE.of_int
v;
3972 src#paxmark
"pax mark method"
3973 (fun () -> MTE.to_string conf
.paxmark
)
3974 (fun v -> conf
.paxmark
<- MTE.of_int
v);
3975 if bousable
() && !opengl_has_pbo
3978 (fun () -> conf
.usepbo
)
3979 (fun v -> conf
.usepbo
<- v);
3980 src#
bool "mouse wheel scrolls pages"
3981 (fun () -> conf
.wheelbypage
)
3982 (fun v -> conf
.wheelbypage
<- v);
3983 src#
bool "open remote links in a new instance"
3984 (fun () -> conf
.riani
)
3985 (fun v -> conf
.riani
<- v);
3986 src#
bool "edit annotations inline"
3987 (fun () -> conf
.annotinline
)
3988 (fun v -> conf
.annotinline
<- v);
3989 src#
bool "coarse positioning in presentation mode"
3990 (fun () -> conf
.coarseprespos
)
3991 (fun v -> conf
.coarseprespos
<- v);
3992 src#
bool "use document css"
3993 (fun () -> conf
.usedoccss
)
3995 conf
.usedoccss
<- v;
3996 state
.anchor <- getanchor
();
3997 opendoc state
.path state
.password;
4002 src#caption
"Document" 0;
4003 List.iter
(fun (_, s) -> src#caption
s 1) state
.docinfo
;
4004 src#caption2
"Pages"
4005 (fun () -> string_of_int state
.pagecount
) 1;
4006 src#caption2
"Dimensions"
4007 (fun () -> string_of_int
(List.length state
.pdims
)) 1;
4008 if nonemptystr conf
.css
4009 then src#caption2
"CSS" (fun () -> conf
.css
) 1;
4013 src#caption
"Trimmed margins" 0;
4014 src#caption2
"Dimensions"
4015 (fun () -> string_of_int
(List.length state
.pdims
)) 1;
4019 src#caption
"OpenGL" 0;
4020 src#caption
(Printf.sprintf
"Vendor\t%s" (GlMisc.get_string `vendor
)) 1;
4021 src#caption
(Printf.sprintf
"Renderer\t%s" (GlMisc.get_string `renderer
)) 1;
4024 src#caption
"Location" 0;
4025 if nonemptystr state
.origin
4026 then src#caption
("Orign\t" ^ mbtoutf8 state
.origin
) 1;
4027 src#caption
("Path\t" ^ mbtoutf8 state
.path) 1;
4029 src#reset prevmode prevuioh
;
4034 let prevmode = state
.mode
4035 and prevuioh
= state
.uioh in
4036 fillsrc prevmode prevuioh
;
4037 let source = (src :> lvsource
) in
4038 let modehash = findkeyhash conf
"info" in
4041 inherit listview ~zebra
:false ~helpmode
:false
4042 ~
source ~trusted
:true ~
modehash as super
4043 val mutable m_prevmemused
= 0
4044 method! infochanged
= function
4046 if m_prevmemused
!= state
.memused
4048 m_prevmemused
<- state
.memused
;
4049 G.postRedisplay "memusedchanged";
4051 | Pdim
-> G.postRedisplay "pdimchanged"
4052 | Docinfo
-> fillsrc prevmode prevuioh
4054 method! key key mask
=
4055 if not
(Wsi.withctrl mask
)
4058 | @left | @kpleft
-> coe (self#updownlevel ~
-1)
4059 | @right
| @kpright
-> coe (self#updownlevel
1)
4060 | _ -> super#
key key mask
4061 else super#
key key mask
4063 G.postRedisplay "info";
4069 inherit lvsourcebase
4070 method getitemcount
= Array.length state
.help
4072 let s, l, _ = state
.help
.(n) in
4075 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4079 match state
.help
.(active) with
4080 | _, _, Action
f -> Some
(f uioh)
4081 | _, _, Noaction
-> Some
uioh
4090 method hasaction
n =
4091 match state
.help
.(n) with
4092 | _, _, Action
_ -> true
4093 | _, _, Noaction
-> false
4099 let modehash = findkeyhash conf
"help" in
4101 state
.uioh <- coe (new listview
4102 ~zebra
:false ~helpmode
:true
4103 ~
source ~trusted
:true ~
modehash);
4104 G.postRedisplay "help";
4110 inherit lvsourcebase
4111 val mutable m_items
= E.a
4113 method getitemcount
= 1 + Array.length m_items
4118 else m_items
.(n-1), 0
4120 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4125 then Buffer.clear state
.errmsgs
;
4132 method hasaction
n =
4136 state
.newerrmsgs
<- false;
4137 let l = Str.split newlinere
(Buffer.contents state
.errmsgs
) in
4138 m_items
<- Array.of_list
l
4147 let source = (msgsource :> lvsource
) in
4148 let modehash = findkeyhash conf
"listview" in
4151 inherit listview ~zebra
:false ~helpmode
:false
4152 ~
source ~trusted
:false ~
modehash as super
4155 then msgsource#reset
;
4158 G.postRedisplay "msgs";
4162 let editor = getenvwithdef
"EDITOR" E.s in
4166 let tmppath = Filename.temp_file
"llpp" "note" in
4169 let oc = open_out
tmppath in
4173 let execstr = editor ^
" " ^
tmppath in
4175 match spawn
execstr [] with
4176 | (exception exn
) ->
4177 impmsg "spawn(%S) failed: %s" execstr @@ exntos exn
;
4180 match Unix.waitpid
[] pid with
4181 | (exception exn
) ->
4182 impmsg "waitpid(%d) failed: %s" pid @@ exntos exn
;
4186 | Unix.WEXITED
0 -> filecontents
tmppath
4188 impmsg "editor process(%s) exited abnormally: %d" execstr n;
4190 | Unix.WSIGNALED
n ->
4191 impmsg "editor process(%s) was killed by signal %d" execstr n;
4193 | Unix.WSTOPPED
n ->
4194 impmsg "editor(%s) process was stopped by signal %d" execstr n;
4197 match Unix.unlink
tmppath with
4198 | (exception exn
) ->
4199 impmsg "failed to ulink %S: %s" tmppath @@ exntos exn
;
4204 let enterannotmode opaque slinkindex
=
4207 inherit lvsourcebase
4208 val mutable m_text
= E.s
4209 val mutable m_items
= E.a
4211 method getitemcount
= Array.length m_items
4214 let label, _func
= m_items
.(n) in
4217 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4218 ignore
(uioh, first, pan
);
4221 let _label, func
= m_items
.(active) in
4226 method hasaction
n = nonemptystr
@@ fst m_items
.(n)
4229 let rec split accu b i
=
4231 if p = String.length
s
4232 then (String.sub s b (p-b), unit) :: accu
4234 if (i
> 70 && s.[p] = ' '
) || s.[p] = '
\r'
|| s.[p] = '
\n'
4236 let ss = if i
= 0 then E.s else String.sub s b i
in
4237 split ((ss, unit)::accu) (p+1) 0
4242 wcmd "freepage %s" (~
> opaque);
4244 Hashtbl.fold (fun key opaque'
accu ->
4245 if opaque'
= opaque'
4246 then key :: accu else accu) state
.pagemap
[]
4248 List.iter
(Hashtbl.remove state
.pagemap
) keys;
4250 gotoxy state
.x state
.y
4253 delannot
opaque slinkindex
;
4256 let edit inline
() =
4261 modannot
opaque slinkindex
s;
4267 let mode = state
.mode in
4270 ("annotation: ", m_text
, None
, textentry, update, true),
4271 fun _ -> state
.mode <- mode);
4275 let s = getusertext m_text
in
4280 ( "[Copy]", fun () -> selstring m_text
)
4281 :: ("[Delete]", dele)
4282 :: ("[Edit]", edit conf
.annotinline
)
4284 :: split [] 0 0 |> List.rev
|> Array.of_list
4291 let s = getannotcontents
opaque slinkindex
in
4294 let source = (msgsource :> lvsource
) in
4295 let modehash = findkeyhash conf
"listview" in
4296 state
.uioh <- coe (object
4297 inherit listview ~zebra
:false ~helpmode
:false
4298 ~
source ~trusted
:false ~
modehash
4300 G.postRedisplay "enterannotmode";
4303 let gotoremote spec
=
4304 let filename, dest
= splitatchar spec '#'
in
4305 let getpath filename =
4307 if nonemptystr
filename
4309 if Filename.is_relative
filename
4311 let dir = Filename.dirname state
.path in
4313 if Filename.is_implicit
dir
4314 then Filename.concat
(Sys.getcwd
()) dir
4317 Filename.concat
dir filename
4321 if Sys.file_exists
path
4325 let path = getpath filename in
4329 let cmd = Lazy.force_val lcmd
in
4330 match spawn
cmd with
4332 | (exception exn
) ->
4333 dolog
"failed to execute `%s': %s" cmd @@ exntos exn
4335 let anchor = getanchor
() in
4336 let ranchor = state
.path, state
.password, anchor, state
.origin
in
4337 state
.origin
<- E.s;
4338 state
.ranchors
<- ranchor :: state
.ranchors
;
4341 if substratis spec
0 "page="
4343 match Scanf.sscanf spec
"page=%d" (fun n -> n) with
4345 state
.anchor <- (pageno, 0.0, 0.0);
4346 dospawn @@ lazy (Printf.sprintf
"%s -page %d %S" !selfexec pageno path);
4348 adderrfmt "error parsing remote destination" "page: %s" @@ exntos exn
4350 state
.nameddest
<- dest
;
4351 dospawn @@ lazy (!selfexec ^
" " ^
path ^
" -dest " ^ dest
)
4355 let gotounder = function
4356 | Ulinkuri
s when isexternallink
s ->
4357 if substratis
s 0 "file://"
4358 then gotoremote @@ String.sub s 7 (String.length
s - 7)
4361 let pageno, x, y = uritolocation
s in
4363 gotopagexy !wtmode pageno x y
4364 | Utext
_ | Unone
-> ()
4365 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
4368 let gotooutline (_, _, kind
) =
4372 let (pageno, y, _) = anchor in
4374 (if conf
.presentation
then (pageno, y, 1.0) else anchor)
4378 | Ouri
uri -> gotounder (Ulinkuri
uri)
4379 | Olaunch _cmd
-> failwith
"gotounder (Ulaunch cmd)"
4380 | Oremote _remote
-> failwith
"gotounder (Uremote remote)"
4381 | Ohistory hist
-> gotohist hist
4382 | Oremotedest _remotedest
-> failwith
"gotounder (Uremotedest remotedest)"
4385 class outlinesoucebase fetchoutlines
= object (self)
4386 inherit lvsourcebase
4387 val mutable m_items
= E.a
4388 val mutable m_minfo
= E.a
4389 val mutable m_orig_items
= E.a
4390 val mutable m_orig_minfo
= E.a
4391 val mutable m_narrow_patterns
= []
4392 val mutable m_gen
= -1
4394 method getitemcount
= Array.length m_items
4397 let s, n, _ = m_items
.(n) in
4400 method exit ~
(uioh:uioh) ~cancel ~
active ~
(first:int) ~pan
:
4402 ignore
(uioh, first);
4404 if m_narrow_patterns
= []
4405 then m_orig_items
, m_orig_minfo
4406 else m_items
, m_minfo
4413 gotooutline m_items
.(active);
4421 method hasaction
(_:int) = true
4424 if Array.length m_items
!= Array.length m_orig_items
4427 match m_narrow_patterns
with
4429 | many
-> String.concat
"@Uellipsis" (List.rev many
)
4431 "Narrowed to " ^
s ^
" (ctrl-u to restore)"
4435 match m_narrow_patterns
with
4438 | head
:: _ -> "@Uellipsis" ^ head
4440 method narrow
pattern =
4441 match Str.regexp_case_fold
pattern with
4442 | (exception _) -> ()
4444 let rec loop accu minfo n =
4447 m_items
<- Array.of_list
accu;
4448 m_minfo
<- Array.of_list
minfo;
4451 let (s, _, _) as o = m_items
.(n) in
4453 match Str.search_forward re
s 0 with
4454 | (exception Not_found
) -> accu, minfo
4455 | first -> o :: accu, (first, Str.match_end
()) :: minfo
4457 loop accu minfo (n-1)
4459 loop [] [] (Array.length m_items
- 1)
4461 method! getminfo
= m_minfo
4464 m_orig_items
<- fetchoutlines
();
4465 m_minfo
<- m_orig_minfo
;
4466 m_items
<- m_orig_items
4468 method add_narrow_pattern
pattern =
4469 m_narrow_patterns
<- pattern :: m_narrow_patterns
4471 method del_narrow_pattern
=
4472 match m_narrow_patterns
with
4473 | _ :: rest
-> m_narrow_patterns
<- rest
4478 match m_narrow_patterns
with
4479 | pattern :: [] -> self#narrow
pattern; pattern
4481 List.fold_left
(fun accu pattern ->
4482 self#narrow
pattern;
4483 pattern ^
"@Uellipsis" ^
accu) E.s list
4485 method calcactive
(_:anchor) = 0
4487 method reset
anchor items =
4488 if state
.gen
!= m_gen
4490 m_orig_items
<- items;
4492 m_narrow_patterns
<- [];
4494 m_orig_minfo
<- E.a;
4498 if items != m_orig_items
4500 m_orig_items
<- items;
4501 if m_narrow_patterns
== []
4502 then m_items
<- items;
4505 let active = self#calcactive
anchor in
4507 m_first
<- firstof m_first
active
4511 let outlinesource fetchoutlines
=
4513 inherit outlinesoucebase fetchoutlines
4514 method! calcactive
anchor =
4515 let rely = getanchory anchor in
4516 let rec loop n best bestd
=
4517 if n = Array.length m_items
4520 let _, _, kind
= m_items
.(n) in
4523 let orely = getanchory anchor in
4524 let d = abs
(orely - rely) in
4527 else loop (n+1) best bestd
4528 | Onone
| Oremote
_ | Olaunch
_
4529 | Oremotedest
_ | Ouri
_ | Ohistory
_ ->
4530 loop (n+1) best bestd
4536 let enteroutlinemode, enterbookmarkmode
, enterhistmode
=
4537 let mkselector sourcetype
=
4538 let fetchoutlines () =
4539 match sourcetype
with
4540 | `bookmarks
-> Array.of_list state
.bookmarks
4541 | `outlines
-> state
.outlines
4542 | `history
-> genhistoutlines ()
4545 if sourcetype
= `history
4546 then new outlinesoucebase
fetchoutlines
4547 else outlinesource fetchoutlines
4550 let outlines = fetchoutlines () in
4551 if Array.length
outlines = 0
4553 showtext ' ' errmsg
;
4557 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
4558 let anchor = getanchor
() in
4559 source#reset
anchor outlines;
4560 state
.text <- source#greetmsg
;
4562 coe (new outlinelistview ~zebra
:(sourcetype
=`history
) ~
source);
4563 G.postRedisplay "enter selector";
4566 let mkenter sourcetype errmsg
=
4567 let enter = mkselector sourcetype
in
4568 fun () -> enter errmsg
4570 mkenter `
outlines "document has no outline"
4571 , mkenter `bookmarks
"document has no bookmarks (yet)"
4572 , mkenter `history
"history is empty"
4575 let quickbookmark ?title
() =
4576 match state
.layout with
4582 let tm = Unix.localtime
(now
()) in
4584 "Quick (page %d) (bookmarked at %02d/%02d/%d %02d:%02d)"
4588 (tm.Unix.tm_year
+ 1900)
4591 | Some
title -> title
4593 state
.bookmarks
<- (title, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
4596 let setautoscrollspeed step goingdown
=
4597 let incr = max
1 ((abs step
) / 2) in
4598 let incr = if goingdown
then incr else -incr in
4599 let astep = boundastep state
.winh
(step
+ incr) in
4600 state
.autoscroll
<- Some
astep;
4604 match conf
.columns
with
4606 | Csingle
_ | Cmulti
_ -> state
.x != 0 || conf
.zoom > 1.0
4609 let panbound x = bound
x (-state
.w) state
.winw
;;
4611 let existsinrow pageno (columns
, coverA
, coverB
) p =
4612 let last = ((pageno - coverA
) mod columns
) + columns
in
4613 let rec any = function
4616 if l.pageno = coverA
- 1 || l.pageno = state
.pagecount
- coverB
4620 then (if l.pageno = last then false else any rest
)
4628 match state
.layout with
4630 let pageno = page_of_y state
.y in
4631 gotoghyll (getpagey
(pageno+1))
4633 match conf
.columns
with
4635 if conf
.presentation
&& rest
== [] && l.pageh
> l.pagey + l.pagevh
4637 let y = clamp (pgscale state
.winh
) in
4640 let pageno = min
(l.pageno+1) (state
.pagecount
-1) in
4641 gotoghyll (getpagey
pageno)
4642 | Cmulti
((c, _, _) as cl
, _) ->
4643 if conf
.presentation
4644 && (existsinrow l.pageno cl
4645 (fun l -> l.pageh
> l.pagey + l.pagevh))
4647 let y = clamp (pgscale state
.winh
) in
4650 let pageno = min
(l.pageno+c) (state
.pagecount
-1) in
4651 gotoghyll (getpagey
pageno)
4653 if l.pageno < state
.pagecount
- 1 || l.pagecol
< n - 1
4655 let pagey, pageh
= getpageyh
l.pageno in
4656 let pagey = pagey + pageh
* l.pagecol
in
4657 let ips = if l.pagecol
= 0 then 0 else conf
.interpagespace
in
4658 gotoghyll (pagey + pageh
+ ips)
4662 match state
.layout with
4664 let pageno = page_of_y state
.y in
4665 gotoghyll (getpagey
(pageno-1))
4667 match conf
.columns
with
4669 if conf
.presentation
&& l.pagey != 0
4671 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4673 let pageno = max
0 (l.pageno-1) in
4674 gotoghyll (getpagey
pageno)
4675 | Cmulti
((c, _, coverB
) as cl
, _) ->
4676 if conf
.presentation
&&
4677 (existsinrow l.pageno cl
(fun l -> l.pagey != 0))
4679 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4682 if l.pageno = state
.pagecount
- coverB
4686 let pageno = max
0 (l.pageno-decr) in
4687 gotoghyll (getpagey
pageno)
4695 let pageno = max
0 (l.pageno-1) in
4696 let pagey, pageh
= getpageyh
pageno in
4699 let pagey, pageh
= getpageyh
l.pageno in
4700 pagey + pageh
* (l.pagecol
-1) - conf
.interpagespace
4706 if emptystr conf
.savecmd
4707 then error
"don't know where to save modified document"
4709 let savecmd = Str.global_replace percentsre state
.path conf
.savecmd in
4712 (fun s -> error
"failed to obtain path to the saved copy: %s" s)
4717 let tmp = path ^
".tmp" in
4719 Unix.rename
tmp path;
4722 let viewkeyboard key mask
=
4724 let mode = state
.mode in
4725 state
.mode <- Textentry
(te, fun _ -> state
.mode <- mode);
4728 G.postRedisplay "view:enttext"
4730 let ctrl = Wsi.withctrl mask
in
4731 let key = Wsi.keypadtodigitkey
key in
4736 if hasunsavedchanges
()
4740 if conf
.angle
mod 360 = 0 && not
(isbirdseye state
.mode)
4743 match state
.lnava
with
4744 | None
-> LinkNav
(Ltgendir
0)
4745 | Some
pn -> LinkNav
(Ltexact
pn)
4747 gotoxy state
.x state
.y;
4749 else impmsg "keyboard link navigation does not work under rotation"
4752 begin match state
.mstate
with
4755 G.postRedisplay "kill rect";
4758 | Mscrolly
| Mscrollx
4761 begin match state
.mode with
4764 G.postRedisplay "esc leave linknav"
4768 match state
.ranchors
with
4770 | (path, password, anchor, origin
) :: rest
->
4771 state
.ranchors
<- rest
;
4772 state
.anchor <- anchor;
4773 state
.origin
<- origin
;
4774 state
.nameddest
<- E.s;
4775 opendoc path password
4780 gotoghyll (getnav ~
-1)
4791 Hashtbl.iter
(fun _ opaque ->
4793 Hashtbl.clear state
.prects
) state
.pagemap
;
4794 G.postRedisplay "dehighlight";
4796 | @slash
| @question
->
4797 let ondone isforw
s =
4798 cbput state
.hists
.pat
s;
4799 state
.searchpattern
<- s;
4802 let s = String.make
1 (Char.chr
key) in
4803 enttext (s, E.s, Some
(onhist state
.hists
.pat
),
4804 textentry, ondone (key = @slash
), true)
4806 | @plus
| @kpplus
| @equals
when ctrl ->
4807 let incr = if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01 in
4808 pivotzoom (conf
.zoom +. incr)
4810 | @plus
| @kpplus
->
4813 try int_of_string
s with exn
->
4814 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
;
4820 state
.text <- "page bias is now " ^ string_of_int
n;
4823 enttext ("page bias: ", E.s, None
, intentry, ondone, true)
4825 | @minus
| @kpminus
when ctrl ->
4826 let decr = if conf
.zoom -. 0.1 < 0.1 then 0.01 else 0.1 in
4827 pivotzoom (max
0.01 (conf
.zoom -. decr))
4829 | @minus
| @kpminus
->
4830 let ondone msg
= state
.text <- msg
in
4832 "option [acfhilpstvxACFPRSZTISM]: ", E.s, None
,
4833 optentry state
.mode, ondone, true
4838 then gotoxy 0 state
.y
4841 | (@1 | @2) when ctrl && conf
.fitmodel
!= FitPage
-> (* ctrl-1/2 *)
4843 match conf
.columns
with
4844 | Csingle
_ | Cmulti
_ -> 1
4845 | Csplit
(n, _) -> n
4847 let h = state
.winh
-
4848 conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0)
4850 let zoom = zoomforh state
.winw
h 0 cols in
4851 if zoom > 0.0 && (key = @2 || zoom < 1.0)
4856 match conf
.fitmodel
with
4857 | FitWidth
-> FitProportional
4858 | FitProportional
-> FitPage
4859 | FitPage
-> FitWidth
4861 state
.text <- "fit model: " ^
FMTE.to_string
fm;
4862 reqlayout conf
.angle
fm
4864 | @4 when ctrl -> (* ctrl-4 *)
4865 let zoom = getmaxw
() /. float state
.winw
in
4866 if zoom > 0.0 then setzoom zoom
4874 | (48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57)
4875 when not
ctrl -> (* 0..9 *)
4878 try int_of_string
s with exn
->
4879 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
;
4885 cbput state
.hists
.pag
(string_of_int
n);
4886 gotopage1 (n + conf
.pagebias
- 1) 0;
4889 let pageentry text key =
4890 match Char.unsafe_chr
key with
4891 | '
g'
-> TEdone
text
4892 | _ -> intentry text key
4894 let text = String.make
1 (Char.chr
key) in
4895 enttext (":", text, Some
(onhist state
.hists
.pag
),
4896 pageentry, ondone, true)
4899 conf
.scrollb
<- if conf
.scrollb
= 0 then (scrollbvv
lor scrollbhv
) else 0;
4900 G.postRedisplay "toggle scrollbar";
4903 state
.bzoom
<- not state
.bzoom
;
4905 showtext ' '
("block zoom " ^
if state
.bzoom
then "on" else "off")
4908 conf
.hlinks
<- not conf
.hlinks
;
4909 state
.text <- "highlightlinks " ^
if conf
.hlinks
then "on" else "off";
4910 G.postRedisplay "toggle highlightlinks";
4913 if conf
.angle
mod 360 = 0
4915 state
.glinks
<- true;
4916 let mode = state
.mode in
4919 (":", E.s, None
, linknentry, linknact gotounder, false),
4921 state
.glinks
<- false;
4925 G.postRedisplay "view:linkent(F)"
4927 else impmsg "hint mode does not work under rotation"
4930 state
.glinks
<- true;
4931 let mode = state
.mode in
4935 ":", E.s, None
, linknentry, linknact (fun under ->
4936 selstring (undertext under);
4940 state
.glinks
<- false;
4944 G.postRedisplay "view:linkent"
4947 begin match state
.autoscroll
with
4949 conf
.autoscrollstep
<- step
;
4950 state
.autoscroll
<- None
4952 if conf
.autoscrollstep
= 0
4953 then state
.autoscroll
<- Some
1
4954 else state
.autoscroll
<- Some conf
.autoscrollstep
4958 launchpath () (* XXX where do error messages go? *)
4961 setpresentationmode (not conf
.presentation
);
4962 showtext ' '
("presentation mode " ^
4963 if conf
.presentation
then "on" else "off");
4966 if List.mem
Wsi.Fullscreen state
.winstate
4967 then Wsi.reshape conf
.cwinw conf
.cwinh
4968 else Wsi.fullscreen
()
4971 search state
.searchpattern
false
4974 search state
.searchpattern
true
4977 begin match state
.layout with
4980 gotoghyll (getpagey
l.pageno)
4986 | @delete
| @kpdelete
-> (* delete *)
4990 showtext ' '
(describe_location ());
4993 begin match state
.layout with
4996 Wsi.reshape l.pagew
l.pageh
;
5001 enterbookmarkmode
()
5009 | @e when Buffer.length state
.errmsgs
> 0 ->
5014 match state
.layout with
5019 (s, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
5022 enttext ("bookmark: ", E.s, None
, textentry, ondone, true)
5026 showtext ' '
"Quick bookmark added";
5029 begin match state
.layout with
5031 let rect = getpdimrect
l.pagedimno
in
5035 (truncate
(1.8 *. (rect.(1) -. rect.(0))),
5036 truncate
(1.2 *. (rect.(3) -. rect.(0))))
5038 (truncate
(rect.(1) -. rect.(0)),
5039 truncate
(rect.(3) -. rect.(0)))
5041 let w = truncate
((float w)*.conf
.zoom)
5042 and h = truncate
((float h)*.conf
.zoom) in
5045 state
.anchor <- getanchor
();
5046 Wsi.reshape w (h + conf
.interpagespace
)
5048 G.postRedisplay "z";
5053 | @x -> state
.roam
()
5056 reqlayout (conf
.angle
+
5057 (if key = @Gt
then 30 else -30)) conf
.fitmodel
5061 bound
(conf
.colorscale
+. (if key = 93 then 0.1 else -0.1)) 0.0 1.0
5063 G.postRedisplay "brightness";
5065 | @c when state
.mode = View
->
5070 let m = (state
.winw
- state
.w) / 2 in
5071 gotoxy_and_clear_text m state
.y
5075 match state
.prevcolumns
with
5076 | None
-> (1, 0, 0), 1.0
5077 | Some
(columns
, z
) ->
5080 | Csplit
(c, _) -> -c, 0, 0
5081 | Cmulti
((c, a, b), _) -> c, a, b
5082 | Csingle
_ -> 1, 0, 0
5086 setcolumns View
c a b;
5089 | @down
| @up
when ctrl && Wsi.withshift mask
->
5090 let zoom, x = state
.prevzoom
in
5094 | @k
| @up
| @kpup
->
5095 begin match state
.autoscroll
with
5097 begin match state
.mode with
5098 | Birdseye beye
-> upbirdseye 1 beye
5103 then gotoxy_and_clear_text state
.x (clamp ~
-(state
.winh
/2))
5105 if not
(Wsi.withshift mask
) && conf
.presentation
5107 else gotoghyll1 true (clamp (-conf
.scrollstep
))
5111 setautoscrollspeed n false
5114 | @j
| @down
| @kpdown
->
5115 begin match state
.autoscroll
with
5117 begin match state
.mode with
5118 | Birdseye beye
-> downbirdseye 1 beye
5123 then gotoxy_and_clear_text state
.x (clamp (state
.winh
/2))
5125 if not
(Wsi.withshift mask
) && conf
.presentation
5127 else gotoghyll1 true (clamp (conf
.scrollstep
))
5131 setautoscrollspeed n true
5134 | @left | @right
| @kpleft
| @kpright
when not
(Wsi.withalt mask
) ->
5140 else conf
.hscrollstep
5142 let dx = if key = @left || key = @kpleft
then dx else -dx in
5143 gotoxy_and_clear_text (panbound (state
.x + dx)) state
.y
5146 G.postRedisplay "left/right"
5149 | @prior
| @kpprior
->
5153 match state
.layout with
5155 | l :: _ -> state
.y - l.pagey
5157 clamp (pgscale (-state
.winh
))
5161 | @next | @kpnext
->
5165 match List.rev state
.layout with
5167 | l :: _ -> getpagey
l.pageno
5169 clamp (pgscale state
.winh
)
5173 | @g | @home
| @kphome
->
5176 | @G
| @jend
| @kpend
->
5178 gotoghyll (clamp state
.maxy)
5180 | @right
| @kpright
when Wsi.withalt mask
->
5181 gotoghyll (getnav 1)
5182 | @left | @kpleft
when Wsi.withalt mask
->
5183 gotoghyll (getnav ~
-1)
5188 | @v when conf
.debug
->
5191 match getopaque l.pageno with
5194 let x0, y0, x1, y1 = pagebbox
opaque in
5195 let rect = (float x0, float y0,
5198 float x0, float y1) in
5200 let color = (0.0, 0.0, 1.0 /. (l.pageno mod 3 |> float), 0.5) in
5201 state
.rects
<- (l.pageno, color, rect) :: state
.rects
;
5203 G.postRedisplay "v";
5206 let mode = state
.mode in
5207 let cmd = ref E.s in
5208 let onleave = function
5209 | Cancel
-> state
.mode <- mode
5212 match getopaque l.pageno with
5213 | Some
opaque -> pipesel opaque !cmd
5214 | None
-> ()) state
.layout;
5218 cbput state
.hists
.sel
s;
5222 "| ", !cmd, Some
(onhist state
.hists
.sel
), textentry, ondone, true
5224 G.postRedisplay "|";
5225 state
.mode <- Textentry
(te, onleave);
5228 vlog "huh? %s" (Wsi.keyname
key)
5231 let linknavkeyboard key mask
linknav =
5232 let getpage pageno =
5233 let rec loop = function
5235 | l :: _ when l.pageno = pageno -> Some
l
5236 | _ :: rest
-> loop rest
5237 in loop state
.layout
5239 let doexact (pageno, n) =
5240 match getopaque pageno, getpage pageno with
5241 | Some
opaque, Some
l ->
5242 if key = @enter || key = @kpenter
5244 let under = getlink
opaque n in
5245 G.postRedisplay "link gotounder";
5252 Some
(findlink
opaque LDfirst
), -1
5255 Some
(findlink
opaque LDlast
), 1
5258 Some
(findlink
opaque (LDleft
n)), -1
5261 Some
(findlink
opaque (LDright
n)), 1
5264 Some
(findlink
opaque (LDup
n)), -1
5267 Some
(findlink
opaque (LDdown
n)), 1
5272 begin match findpwl
l.pageno dir with
5276 state
.mode <- LinkNav
(Ltgendir
dir);
5277 let y, h = getpageyh
pageno in
5280 then y + h - state
.winh
5285 begin match getopaque pageno, getpage pageno with
5286 | Some
opaque, Some
_ ->
5288 let ld = if dir > 0 then LDfirst
else LDlast
in
5291 begin match link with
5293 showlinktype (getlink
opaque m);
5294 state
.mode <- LinkNav
(Ltexact
(pageno, m));
5295 G.postRedisplay "linknav jpage";
5296 | Lnotfound
-> notfound dir
5302 begin match opt with
5303 | Some Lnotfound
-> pwl l dir;
5304 | Some
(Lfound
m) ->
5308 let _, y0, _, y1 = getlinkrect
opaque m in
5310 then gotopage1 l.pageno y0
5312 let d = fstate
.fontsize
+ 1 in
5313 if y1 - l.pagey > l.pagevh - d
5314 then gotopage1 l.pageno (y1 - state
.winh
+ d)
5315 else G.postRedisplay "linknav";
5317 showlinktype (getlink
opaque m);
5318 state
.mode <- LinkNav
(Ltexact
(l.pageno, m));
5321 | None
-> viewkeyboard key mask
5323 | _ -> viewkeyboard key mask
5327 begin match linknav with
5328 | Ltexact pa
-> state
.lnava
<- Some pa
5329 | Ltgendir
_ | Ltnotready
_ -> ()
5332 G.postRedisplay "leave linknav"
5336 | Ltgendir
_ | Ltnotready
_ -> viewkeyboard key mask
5337 | Ltexact exact
-> doexact exact
5340 let keyboard key mask
=
5341 if (key = @g && Wsi.withctrl mask
) && not
(istextentry state
.mode)
5342 then wcmd "interrupt"
5343 else state
.uioh <- state
.uioh#
key key mask
5346 let birdseyekeyboard key mask
5347 ((oconf
, leftx
, pageno, hooverpageno
, anchor) as beye
) =
5349 match conf
.columns
with
5351 | Cmulti
((c, _, _), _) -> c
5352 | Csplit
_ -> failwith
"bird's eye split mode"
5354 let pgh layout = List.fold_left
5355 (fun m l -> max
l.pageh
m) state
.winh
layout in
5357 | @l when Wsi.withctrl mask
->
5358 let y, h = getpageyh
pageno in
5359 let top = (state
.winh
- h) / 2 in
5360 gotoxy state
.x (max
0 (y - top))
5361 | @enter | @kpenter
-> leavebirdseye beye
false
5362 | @escape
-> leavebirdseye beye
true
5363 | @up
-> upbirdseye incr beye
5364 | @down
-> downbirdseye incr beye
5365 | @left -> upbirdseye 1 beye
5366 | @right
-> downbirdseye 1 beye
5369 begin match state
.layout with
5373 state
.mode <- Birdseye
(
5374 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5376 gotopage1 l.pageno 0;
5379 let layout = layout state
.x (state
.y-state
.winh
)
5381 (pgh state
.layout) in
5383 | [] -> gotoxy state
.x (clamp (-state
.winh
))
5385 state
.mode <- Birdseye
(
5386 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5388 gotopage1 l.pageno 0
5391 | [] -> gotoxy state
.x (clamp (-state
.winh
))
5395 begin match List.rev state
.layout with
5397 let layout = layout state
.x
5398 (state
.y + (pgh state
.layout))
5399 state
.winw state
.winh
in
5400 begin match layout with
5402 let incr = l.pageh
- l.pagevh in
5407 oconf
, leftx
, state
.pagecount
- 1, hooverpageno
, anchor
5409 G.postRedisplay "birdseye pagedown";
5411 else gotoxy state
.x (clamp (incr + conf
.interpagespace
*2));
5415 Birdseye
(oconf
, leftx
, l.pageno, hooverpageno
, anchor);
5416 gotopage1 l.pageno 0;
5419 | [] -> gotoxy state
.x (clamp state
.winh
)
5423 state
.mode <- Birdseye
(oconf
, leftx
, 0, hooverpageno
, anchor);
5427 let pageno = state
.pagecount
- 1 in
5428 state
.mode <- Birdseye
(oconf
, leftx
, pageno, hooverpageno
, anchor);
5429 if not
(pagevisible state
.layout pageno)
5432 match List.rev state
.pdims
with
5434 | (_, _, h, _) :: _ -> h
5438 (max
0 (getpagey
pageno - (state
.winh
- h - conf
.interpagespace
)))
5439 else G.postRedisplay "birdseye end";
5441 | _ -> viewkeyboard key mask
5446 match state
.mode with
5447 | Textentry
_ -> scalecolor 0.4
5449 | View
-> scalecolor 1.0
5450 | Birdseye
(_, _, pageno, hooverpageno
, _) ->
5451 if l.pageno = hooverpageno
5454 if l.pageno = pageno
5456 let c = scalecolor 1.0 in
5458 GlDraw.line_width
3.0;
5459 let dispx = l.pagedispx in
5461 (float (dispx-1)) (float (l.pagedispy-1))
5462 (float (dispx+l.pagevw+1))
5463 (float (l.pagedispy+l.pagevh+1))
5465 GlDraw.line_width
1.0;
5474 let postdrawpage l linkindexbase
=
5475 match getopaque l.pageno with
5477 if tileready l l.pagex
l.pagey
5479 let x = l.pagedispx - l.pagex
5480 and y = l.pagedispy - l.pagey in
5482 match conf
.columns
with
5483 | Csingle
_ | Cmulti
_ ->
5484 (if conf
.hlinks
then 1 else 0)
5486 && not
(isbirdseye state
.mode) then 2 else 0)
5490 match state
.mode with
5491 | Textentry
((_, s, _, _, _, _), _) when state
.glinks
-> s
5497 Hashtbl.find_all state
.prects
l.pageno |>
5498 List.iter
(fun vals
-> drawprect
opaque x y vals
);
5499 let n = postprocess
opaque hlmask x y (linkindexbase
, s, conf
.hfsize
) in
5501 then (state
.redisplay
<- true; 0)
5507 let scrollindicator () =
5508 let sbw, ph
, sh = state
.uioh#
scrollph in
5509 let sbh, pw, sw = state
.uioh#scrollpw
in
5514 else ((state
.winw
- sbw), state
.winw
, 0)
5518 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5519 GlDraw.color (0.64, 0.64, 0.64) ~
alpha:0.7;
5520 filledrect (float x0) 0. (float x1) (float state
.winh
);
5522 (float hx0
) (float (state
.winh
- sbh))
5523 (float (hx0
+ state
.winw
)) (float state
.winh
)
5525 GlDraw.color (0.0, 0.0, 0.0) ~
alpha:0.7;
5527 filledrect (float x0) ph
(float x1) (ph
+. sh);
5528 let pw = pw +. float hx0
in
5529 filledrect pw (float (state
.winh
- sbh)) (pw +. sw) (float state
.winh
);
5534 match state
.mstate
with
5535 | Mnone
| Mscrolly
| Mscrollx
| Mpan
_ | Mzoom
_ | Mzoomrect
_ ->
5538 | Msel
((x0, y0), (x1, y1)) ->
5539 let identify opaque l px py = Some
(opaque, l.pageno, px, py) in
5540 let o0,n0
,px0
,py0
= onppundermouse identify x0 y0 (~
< E.s, -1, 0, 0) in
5541 let _o1,n1
,px1
,py1
= onppundermouse identify x1 y1 (~
< E.s, -1, 0, 0) in
5542 if n0
!= -1 && n0
= n1
then seltext
o0 (px0
, py0
, px1
, py1
);
5549 GlDraw.color (0.0, 0.0, 1.0) ~
alpha:0.5;
5550 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5552 (fun (pageno, c, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) ->
5554 if l.pageno = pageno
5556 let dx = float (l.pagedispx - l.pagex
) in
5557 let dy = float (l.pagedispy - l.pagey) in
5558 let r, g, b, alpha = c in
5559 GlDraw.color (r, g, b) ~
alpha;
5560 filledrect2 (x0+.dx) (y0+.dy)
5572 begin match conf
.columns
, state
.layout with
5573 | Csingle
_, _ :: _ ->
5574 GlDraw.color (scalecolor2 conf
.bgcolor
);
5576 List.fold_left
(fun y l ->
5579 let x1 = l.pagedispx in
5580 let y1 = (l.pagedispy + l.pagevh) in
5581 filledrect (float x0) (float y0) (float x1) (float y1);
5582 let x0 = x1 + l.pagevw in
5583 let x1 = state
.winw
in
5584 filledrect1 (float x0) (float y0) (float x1) (float y1);
5588 and x1 = state
.winw
in
5590 and y1 = l.pagedispy in
5591 filledrect1 (float x0) (float y0) (float x1) (float y1);
5593 l.pagedispy + l.pagevh) 0 state
.layout
5596 and x1 = state
.winw
in
5598 and y1 = state
.winh
in
5599 filledrect1 (float x0) (float y0) (float x1) (float y1)
5600 | (Cmulti
_ | Csplit
_), _ | Csingle
_, [] ->
5601 GlClear.color (scalecolor2 conf
.bgcolor
);
5602 GlClear.clear
[`
color];
5604 List.iter
drawpage state
.layout;
5606 match state
.mode with
5607 | LinkNav
(Ltexact
(pageno, linkno
)) ->
5608 begin match getopaque pageno with
5610 let x0, y0, x1, y1 = getlinkrect
opaque linkno
in
5611 let color = (0.0, 0.0, 0.5, 0.5) in
5618 | None
-> state
.rects
5620 | LinkNav
(Ltgendir
_) | LinkNav
(Ltnotready
_)
5623 | View
-> state
.rects
5626 let rec postloop linkindexbase
= function
5628 let linkindexbase = linkindexbase + postdrawpage l linkindexbase in
5629 postloop linkindexbase rest
5633 postloop 0 state
.layout;
5635 begin match state
.mstate
with
5636 | Mzoomrect
((x0, y0), (x1, y1)) ->
5638 GlDraw.color (0.3, 0.3, 0.3) ~
alpha:0.5;
5639 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5640 filledrect (float x0) (float y0) (float x1) (float y1);
5644 | Mscrolly
| Mscrollx
5653 let zoomrect x y x1 y1 =
5656 and y0 = min
y y1 in
5657 let zoom = (float state
.w) /. float (x1 - x0) in
5660 if state
.w < state
.winw
5661 then (state
.winw
- state
.w) / 2
5664 match conf
.fitmodel
with
5665 | FitWidth
| FitProportional
-> simple ()
5667 match conf
.columns
with
5669 onppundermouse (fun _ l _ _ -> Some
l.pagedispx) x0 y0 x0
5670 | Cmulti
_ | Csingle
_ -> simple ()
5672 gotoxy ((state
.x + margin) - x0) (state
.y + y0);
5673 state
.anchor <- getanchor
();
5678 let annot inline
x y =
5679 match unproject x y with
5680 | Some
(opaque, n, ux
, uy
) ->
5682 addannot
opaque ux uy
text;
5683 wcmd "freepage %s" (~
> opaque);
5684 Hashtbl.remove state
.pagemap
(n, state
.gen
);
5686 gotoxy state
.x state
.y
5690 let ondone s = add s in
5691 let mode = state
.mode in
5692 state
.mode <- Textentry
(
5693 ("annotation: ", E.s, None
, textentry, ondone, true),
5694 fun _ -> state
.mode <- mode);
5697 G.postRedisplay "annot"
5699 add @@ getusertext E.s
5704 let g opaque l px py =
5705 match rectofblock
opaque px py with
5707 let x0 = a.(0) -. 20. in
5708 let x1 = a.(1) +. 20. in
5709 let y0 = a.(2) -. 20. in
5710 let zoom = (float state
.w) /. (x1 -. x0) in
5711 let pagey = getpagey
l.pageno in
5712 let margin = (state
.w - l.pagew
)/2 in
5713 let nx = -truncate
x0 - margin in
5714 gotoxy_and_clear_text nx (pagey + truncate
y0);
5715 state
.anchor <- getanchor
();
5720 match conf
.columns
with
5722 impmsg "block zooming does not work properly in split columns mode"
5723 | Cmulti
_ | Csingle
_ -> onppundermouse g x y ()
5727 let winw = state
.winw - 1 in
5728 let s = float x /. float winw in
5729 let destx = truncate
(float (state
.w + winw) *. s) in
5730 gotoxy_and_clear_text (winw - destx) state
.y;
5731 state
.mstate
<- Mscrollx
;
5735 let s = float y /. float state
.winh
in
5736 let desty = truncate
(float (state
.maxy -
5737 (if conf
.maxhfit
then state
.winh
else 0))
5739 gotoxy_and_clear_text state
.x desty;
5740 state
.mstate
<- Mscrolly
;
5743 let viewmulticlick clicks
x y mask
=
5744 let g opaque l px py =
5752 if markunder
opaque px py mark
5756 match getopaque l.pageno with
5758 | Some
opaque -> pipesel opaque cmd
5760 state
.roam
<- (fun () -> dopipe conf
.paxcmd
);
5761 if not
(Wsi.withctrl mask
) then dopipe conf
.selcmd
;
5766 G.postRedisplay "viewmulticlick";
5767 onppundermouse g x y (fun () -> impmsg "nothing to select") ();
5771 match conf
.columns
with
5773 | Csingle
_ | Cmulti
_ -> conf
.angle
mod 360 = 0
5776 let viewmouse button down
x y mask
=
5778 | n when (n == 4 || n == 5) && not down
->
5779 if Wsi.withctrl mask
5781 match state
.mstate
with
5782 | Mzoom
(oldn
, i
, (ftx
, fty
)) ->
5785 then abs
(ftx
- x) > 5 || abs
(fty
- y) > 5
5795 if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01
5797 if conf
.zoom -. 0.1 < 0.1 then -0.01 else -0.1
5799 let zoom = conf
.zoom -. incr in
5801 then pivotzoom ~
x ~
y zoom
5802 else pivotzoom zoom;
5803 state
.mstate
<- Mzoom
(n, 0, (x, y));
5805 state
.mstate
<- Mzoom
(n, i
+1, (ftx
, fty
));
5807 else state
.mstate
<- Mzoom
(n, 0, (ftx
, fty
))
5811 | Mscrolly
| Mscrollx
5813 | Mnone
-> state
.mstate
<- Mzoom
(n, 0, (0, 0))
5816 match state
.autoscroll
with
5817 | Some step
-> setautoscrollspeed step
(n=4)
5819 if conf
.wheelbypage
|| conf
.presentation
5828 then -conf
.scrollstep
5829 else conf
.scrollstep
5831 let incr = incr * 2 in
5832 let y = clamp incr in
5833 gotoxy_and_clear_text state
.x y
5836 | n when (n = 6 || n = 7) && not down
&& canpan () ->
5838 panbound (state
.x + (if n = 7 then -2 else 2) * conf
.hscrollstep
) in
5839 gotoxy_and_clear_text x state
.y
5841 | 1 when Wsi.withshift mask
->
5842 state
.mstate
<- Mnone
;
5845 match unproject x y with
5847 | Some
(_, pageno, ux
, uy
) ->
5848 let cmd = Printf.sprintf
5850 conf
.stcmd state
.path pageno ux uy
5852 match spawn
cmd [] with
5853 | (exception exn
) ->
5854 impmsg "execution of synctex command(%S) failed: %S"
5855 conf
.stcmd
@@ exntos exn
5859 | 1 when Wsi.withctrl mask
->
5862 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5863 state
.mstate
<- Mpan
(x, y)
5866 state
.mstate
<- Mnone
5871 if Wsi.withshift mask
5873 annot conf
.annotinline
x y;
5874 G.postRedisplay "addannot"
5878 Wsi.setcursor
Wsi.CURSOR_CYCLE
;
5879 state
.mstate
<- Mzoomrect
(p, p)
5882 match state
.mstate
with
5883 | Mzoomrect
((x0, y0), _) ->
5884 if abs
(x-x0) > 10 && abs
(y - y0) > 10
5885 then zoomrect x0 y0 x y
5888 G.postRedisplay "kill accidental zoom rect";
5892 | Mscrolly
| Mscrollx
5898 | 1 when vscrollhit x ->
5901 let _, position, sh = state
.uioh#
scrollph in
5902 if y > truncate
position && y < truncate
(position +. sh)
5903 then state
.mstate
<- Mscrolly
5906 state
.mstate
<- Mnone
5908 | 1 when y > state
.winh
- hscrollh () ->
5911 let _, position, sw = state
.uioh#scrollpw
in
5912 if x > truncate
position && x < truncate
(position +. sw)
5913 then state
.mstate
<- Mscrollx
5916 state
.mstate
<- Mnone
5918 | 1 when state
.bzoom
-> if not down
then zoomblock x y
5921 let dest = if down
then getunder x y else Unone
in
5922 begin match dest with
5926 | Unone
when down
->
5927 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5928 state
.mstate
<- Mpan
(x, y);
5930 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
5932 | Unone
| Utext
_ ->
5937 state
.mstate
<- Msel
((x, y), (x, y));
5938 G.postRedisplay "mouse select";
5942 match state
.mstate
with
5945 | Mzoom
_ | Mscrollx
| Mscrolly
->
5946 state
.mstate
<- Mnone
5948 | Mzoomrect
((x0, y0), _) ->
5952 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
5953 state
.mstate
<- Mnone
5955 | Msel
((x0, y0), (x1, y1)) ->
5956 let rec loop = function
5960 let a0 = l.pagedispy in
5961 let a1 = a0 + l.pagevh in
5962 let b0 = l.pagedispx in
5963 let b1 = b0 + l.pagevw in
5964 ((y0 >= a0 && y0 <= a1) || (y1 >= a0 && y1 <= a1))
5965 && ((x0 >= b0 && x0 <= b1) || (x1 >= b0 && x1 <= b1))
5969 match getopaque l.pageno with
5972 match Unix.pipe
() with
5973 | (exception exn
) ->
5974 impmsg "cannot create sel pipe: %s" @@
5978 Ne.clo fd
(fun msg
->
5979 dolog
"%s close failed: %s" what msg
)
5982 try spawn
cmd [r, 0; w, -1]
5984 dolog
"cannot execute %S: %s"
5991 G.postRedisplay "copysel";
5993 else clo "Msel pipe/w" w;
5994 clo "Msel pipe/r" r;
5996 dosel conf
.selcmd
();
5997 state
.roam
<- dosel conf
.paxcmd
;
6009 let birdseyemouse button down
x y mask
6010 (conf
, leftx
, _, hooverpageno
, anchor) =
6013 let rec loop = function
6016 if y > l.pagedispy && y < l.pagedispy + l.pagevh
6017 && x > l.pagedispx && x < l.pagedispx + l.pagevw
6019 leavebirdseye (conf
, leftx
, l.pageno, hooverpageno
, anchor) false;
6025 | _ -> viewmouse button down
x y mask
6031 method key key mask
=
6032 begin match state
.mode with
6033 | Textentry
textentry -> textentrykeyboard key mask
textentry
6034 | Birdseye
birdseye -> birdseyekeyboard key mask
birdseye
6035 | View
-> viewkeyboard key mask
6036 | LinkNav
linknav -> linknavkeyboard key mask
linknav
6040 method button button bstate
x y mask
=
6041 begin match state
.mode with
6043 | View
-> viewmouse button bstate
x y mask
6044 | Birdseye beye
-> birdseyemouse button bstate
x y mask beye
6049 method multiclick clicks
x y mask
=
6050 begin match state
.mode with
6052 | View
-> viewmulticlick clicks
x y mask
6059 begin match state
.mode with
6061 | View
| Birdseye
_ | LinkNav
_ ->
6062 match state
.mstate
with
6063 | Mzoom
_ | Mnone
-> ()
6068 state
.mstate
<- Mpan
(x, y);
6069 let x = if canpan () then panbound (state
.x + dx) else state
.x in
6071 gotoxy_and_clear_text x y
6074 state
.mstate
<- Msel
(a, (x, y));
6075 G.postRedisplay "motion select";
6078 let y = min state
.winh
(max
0 y) in
6082 let x = min state
.winw (max
0 x) in
6085 | Mzoomrect
(p0
, _) ->
6086 state
.mstate
<- Mzoomrect
(p0
, (x, y));
6087 G.postRedisplay "motion zoomrect";
6091 method pmotion
x y =
6092 begin match state
.mode with
6093 | Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor) ->
6094 let rec loop = function
6096 if hooverpageno
!= -1
6098 state
.mode <- Birdseye
(conf
, leftx
, pageno, -1, anchor);
6099 G.postRedisplay "pmotion birdseye no hoover";
6102 if y > l.pagedispy && y < l.pagedispy + l.pagevh
6103 && x > l.pagedispx && x < l.pagedispx + l.pagevw
6105 state
.mode <- Birdseye
(conf
, leftx
, pageno, l.pageno, anchor);
6106 G.postRedisplay "pmotion birdseye hoover";
6116 match state
.mstate
with
6117 | Mpan
_ | Msel
_ | Mzoom
_ | Mscrolly
| Mscrollx
| Mzoomrect
_ -> ()
6125 let past, _, _ = !r in
6127 let delta = now -. past in
6130 else r := (now, x, y)
6134 method infochanged
_ = ()
6137 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
6140 then 0.0, float state
.winh
6141 else scrollph state
.y maxy
6146 let fwinw = float (state
.winw - vscrollw ()) in
6148 let sw = fwinw /. float state
.w in
6149 let sw = fwinw *. sw in
6150 max
sw (float conf
.scrollh
)
6153 let maxx = state
.w + state
.winw in
6154 let x = state
.winw - state
.x in
6155 let percent = float x /. float maxx in
6156 (fwinw -. sw) *. percent
6158 hscrollh (), position, sw
6162 match state
.mode with
6163 | LinkNav
_ -> "links"
6164 | Textentry
_ -> "textentry"
6165 | Birdseye
_ -> "birdseye"
6168 findkeyhash conf
modename
6170 method eformsgs
= true
6171 method alwaysscrolly
= false
6174 let addrect pageno r g b a x0 y0 x1 y1 =
6175 Hashtbl.add state
.prects
pageno [|r; g; b; a; x0; y0; x1; y1|];
6179 let cl = splitatchar cmds ' '
in
6181 try Scanf.sscanf
s fmt
f
6183 adderrfmt "remote exec"
6184 "error processing '%S': %s\n" cmds
@@ exntos exn
6186 let rectx s pageno (r, g, b, a) x0 y0 x1 y1 =
6187 vlog "%s page %d color (%f %f %f %f) x0,y0,x1,y1 = %f %f %f %f"
6188 s pageno r g b a x0 y0 x1 y1;
6192 let _,w1,h1
,_ = getpagedim
pageno in
6193 let sw = float w1 /. float w
6194 and sh = float h1
/. float h in
6198 and y1s
= y1 *. sh in
6199 let rect = (x0s,y0s
,x1s
,y0s
,x1s
,y1s
,x0s,y1s
) in
6200 let color = (r, g, b, a) in
6201 if conf
.verbose
then debugrect rect;
6202 state
.rects <- (pageno, color, rect) :: state
.rects;
6207 | "reload", "" -> reload ()
6209 scan args
"%u %f %f"
6211 let cmd, _ = state
.geomcmds
in
6213 then gotopagexy !wtmode pageno x y
6216 gotopagexy !wtmode pageno x y;
6219 state
.reprf
<- f state
.reprf
6221 | "goto1", args
-> scan args
"%u %f" gotopage
6224 (fun _filename _pageno
->
6225 failwith
"gotounder (Uremote (filename, pageno))")
6228 (fun _filename _dest
->
6229 failwith
"gotounder (Uremotedest (filename, dest))")
6231 scan args
"%u %u %f %f %f %f"
6232 (fun pageno c x0 y0 x1 y1 ->
6233 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
6234 rectx "rect" pageno color x0 y0 x1 y1;
6237 scan args
"%u %f %f %f %f %f %f %f %f"
6238 (fun pageno r g b alpha x0 y0 x1 y1 ->
6239 addrect pageno r g b alpha x0 y0 x1 y1;
6240 G.postRedisplay "prect"
6243 scan args
"%u %f %f"
6246 match getopaque pageno with
6247 | Some
opaque -> opaque
6250 pgoto optopaque pageno x y;
6251 let rec fixx = function
6254 if l.pageno = pageno
6255 then gotoxy (state
.x - l.pagedispx) state
.y
6260 match conf
.columns
with
6261 | Csingle
_ | Csplit
_ -> 1
6262 | Cmulti
((n, _, _), _) -> n
6264 layout 0 state
.y (state
.winw * mult) state
.winh
6268 | "activatewin", "" -> Wsi.activatewin
()
6269 | "quit", "" -> raise Quit
6272 let l = Config.keys_of_string
keys in
6273 List.iter
(fun (k
, m) -> keyboard k
m) l
6275 adderrfmt "error processing keys" "`%S': %s\n" cmds
@@ exntos exn
6277 | "clearrects", "" ->
6278 Hashtbl.clear state
.prects
;
6279 G.postRedisplay "clearrects"
6281 adderrfmt "remote command"
6282 "error processing remote command: %S\n" cmds
;
6286 let scratch = Bytes.create
80 in
6287 let buf = Buffer.create
80 in
6289 match tempfailureretry
(Unix.read fd
scratch 0) 80 with
6290 | (exception Unix.Unix_error
(Unix.EAGAIN
, _, _)) -> None
6293 if Buffer.length
buf > 0
6295 let s = Buffer.contents
buf in
6303 match Bytes.index_from
scratch ppos '
\n'
with
6304 | pos -> if pos >= n then -1 else pos
6305 | (exception Not_found
) -> -1
6309 Buffer.add_subbytes
buf scratch ppos
(nlpos-ppos
);
6310 let s = Buffer.contents
buf in
6316 Buffer.add_subbytes
buf scratch ppos
(n-ppos
);
6322 let remoteopen path =
6323 try Some
(Unix.openfile
path [Unix.O_NONBLOCK
; Unix.O_RDONLY
] 0o0)
6325 adderrfmt "remoteopen" "error opening %S: %s" path @@ exntos exn
;
6330 let gcconfig = ref E.s in
6331 let trimcachepath = ref E.s in
6332 let rcmdpath = ref E.s in
6333 let pageno = ref None
in
6334 let rootwid = ref 0 in
6335 let openlast = ref false in
6336 let nofc = ref false in
6337 let doreap = ref false in
6338 let csspath = ref None
in
6339 selfexec := Sys.executable_name
;
6342 [("-p", Arg.String
(fun s -> state
.password <- s),
6343 "<password> Set password");
6347 Config.fontpath
:= s;
6348 selfexec := !selfexec ^
" -f " ^
Filename.quote
s;
6350 "<path> Set path to the user interface font");
6354 selfexec := !selfexec ^
" -c " ^
Filename.quote
s;
6355 Config.confpath
:= s),
6356 "<path> Set path to the configuration file");
6358 ("-last", Arg.Set
openlast, " Open last document");
6360 ("-page", Arg.Int
(fun pageno1
-> pageno := Some
(pageno1
-1)),
6361 "<page-number> Jump to page");
6363 ("-tcf", Arg.String
(fun s -> trimcachepath := s),
6364 "<path> Set path to the trim cache file");
6366 ("-dest", Arg.String
(fun s -> state
.nameddest
<- s),
6367 "<named-destination> Set named destination");
6369 ("-wtmode", Arg.Set
wtmode, " Operate in wt mode");
6370 ("-cxack", Arg.Set
cxack, " Cut corners");
6372 ("-remote", Arg.String
(fun s -> rcmdpath := s),
6373 "<path> Set path to the remote commands source");
6375 ("-origin", Arg.String
(fun s -> state
.origin
<- s),
6376 "<original-path> Set original path");
6378 ("-gc", Arg.Set_string
gcconfig,
6379 "<script-path> Collect garbage with the help of a script");
6381 ("-nofc", Arg.Set
nofc, " Do not use fontconfig");
6383 ("-v", Arg.Unit
(fun () ->
6385 "%s\nconfiguration path: %s\n"
6388 exit
0), " Print version and exit");
6390 ("-css", Arg.String
(fun s -> csspath := Some
s),
6391 "<css-path> Style sheet to use for EPUB/HTML");
6393 ("-embed", Arg.Set_int
rootwid,
6394 "<window-id> Embed into window")
6397 (fun s -> state
.path <- s)
6398 ("Usage: " ^
Sys.argv
.(0) ^
" [options] some.pdf\nOptions:");
6401 then selfexec := !selfexec ^
" -wtmode";
6403 let histmode = emptystr state
.path && not
!openlast in
6405 if not
(Config.load !openlast)
6406 then dolog
"failed to load configuration";
6408 begin match !pageno with
6409 | Some
pageno -> state
.anchor <- (pageno, 0.0, 0.0)
6413 if nonemptystr
!gcconfig
6416 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6417 | (exception exn
) -> error
"socketpair for gc failed: %s" @@ exntos exn
6420 match spawn
!gcconfig [(c, 0); (c, 1); (s, -1)] with
6421 | (exception exn
) -> error
"failed to execute gc script: %s" @@ exntos exn
6423 Ne.clo c @@ (fun s -> error
"failed to close gc fd %s" s);
6430 val mutable m_clicks
= 0
6431 val mutable m_click_x
= 0
6432 val mutable m_click_y
= 0
6433 val mutable m_lastclicktime
= infinity
6435 method private cleanup =
6436 state
.roam
<- noroam
;
6437 Hashtbl.iter
(fun _ opaque -> clearmark
opaque) state
.pagemap
6438 method expose
= G.postRedisplay "expose"
6442 | Wsi.Unobscured
-> "unobscured"
6443 | Wsi.PartiallyObscured
-> "partiallyobscured"
6444 | Wsi.FullyObscured
-> "fullyobscured"
6446 vlog "visibility change %s" name
6447 method display = display ()
6448 method map mapped
= vlog "mapped %b" mapped
6449 method reshape w h =
6452 method mouse
b d x y m =
6453 if d && canselect ()
6456 * http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx
6463 if abs
x - m_click_x
> 10
6464 || abs
y - m_click_y
> 10
6465 || abs_float
(t -. m_lastclicktime
) > 0.3
6467 m_clicks
<- m_clicks
+ 1;
6468 m_lastclicktime
<- t;
6472 G.postRedisplay "cleanup";
6473 state
.uioh <- state
.uioh#button
b d x y m;
6475 else state
.uioh <- state
.uioh#multiclick m_clicks
x y m
6480 m_lastclicktime
<- infinity
;
6481 state
.uioh <- state
.uioh#button
b d x y m
6485 state
.uioh <- state
.uioh#button
b d x y m
6488 state
.mpos
<- (x, y);
6489 state
.uioh <- state
.uioh#motion
x y
6490 method pmotion
x y =
6491 state
.mpos
<- (x, y);
6492 state
.uioh <- state
.uioh#pmotion
x y
6494 let mascm = m land (
6495 Wsi.altmask
+ Wsi.shiftmask
+ Wsi.ctrlmask
+ Wsi.metamask
6498 let x = state
.x and y = state
.y in
6500 if x != state
.x || y != state
.y then self#
cleanup
6502 match state
.keystate
with
6504 let km = k
, mascm in
6507 let modehash = state
.uioh#
modehash in
6508 try Hashtbl.find modehash km
6510 try Hashtbl.find (findkeyhash conf
"global") km
6511 with Not_found
-> KMinsrt
(k
, m)
6513 | KMinsrt
(k
, m) -> keyboard k
m
6514 | KMinsrl
l -> List.iter
(fun (k
, m) -> keyboard k
m) l
6515 | KMmulti
(l, r) -> state
.keystate
<- KSinto
(l, r)
6517 | KSinto
((k'
, m'
) :: [], insrt
) when k'
=k
&& m'
land mascm = m'
->
6518 List.iter
(fun (k
, m) -> keyboard k
m) insrt
;
6519 state
.keystate
<- KSnone
6520 | KSinto
((k'
, m'
) :: keys, insrt
) when k'
=k
&& m'
land mascm = m'
->
6521 state
.keystate
<- KSinto
(keys, insrt
)
6522 | KSinto
_ -> state
.keystate
<- KSnone
6525 state
.mpos
<- (x, y);
6526 state
.uioh <- state
.uioh#pmotion
x y
6527 method leave = state
.mpos
<- (-1, -1)
6528 method winstate wsl
= state
.winstate
<- wsl
6529 method quit
= raise Quit
6532 let wsfd, winw, winh
= Wsi.init
mu !rootwid conf
.cwinw conf
.cwinh platform
in
6534 setbgcol conf
.bgcolor
;
6537 if not
@@ List.exists
GlMisc.check_extension
6538 [ "GL_ARB_texture_rectangle"
6539 ; "GL_EXT_texture_recangle"
6540 ; "GL_NV_texture_rectangle" ]
6541 then (dolog
"OpenGL does not suppport rectangular textures"; exit
1);
6543 if substratis
(GlMisc.get_string `renderer
) 0 "Mesa DRI Intel("
6545 defconf
.sliceheight
<- 1024;
6546 defconf
.texcount
<- 32;
6547 defconf
.usepbo
<- true;
6551 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6552 | (exception exn
) ->
6553 dolog
"socketpair failed: %s" @@ exntos exn
;
6561 setcheckers conf
.checkers
;
6563 opengl_has_pbo := GlMisc.check_extension
"GL_ARB_pixel_buffer_object";
6565 begin match !csspath with
6567 | Some
"" -> conf
.css
<- E.s
6569 let css = filecontents
path in
6570 let l = String.length
css in
6572 if substratis
css (l-2) "\r\n"
6573 then String.sub css 0 (l-2)
6574 else (if css.[l-1] = '
\n'
6575 then String.sub css 0 (l-1)
6579 conf
.angle
, conf
.fitmodel
, (conf
.trimmargins
, conf
.trimfuzz
),
6580 conf
.texcount
, conf
.sliceheight
, conf
.mustoresize
, conf
.colorspace
,
6581 !Config.fontpath
, !trimcachepath, !opengl_has_pbo, not
!nofc
6583 List.iter
GlArray.enable
[`texture_coord
; `vertex
];
6585 reshape ~firsttime
:true winw winh
;
6589 Wsi.settitle
"llpp (history)";
6593 state
.text <- "Opening " ^
(mbtoutf8 state
.path);
6594 opendoc state
.path state
.password;
6598 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
6599 Sys.set_signal
Sys.sighup
(Sys.Signal_handle
(fun _ -> reload ()));
6602 match Unix.waitpid
[Unix.WNOHANG
] ~
-1 with
6603 | (exception (Unix.Unix_error
(Unix.ECHILD
, _, _))) -> ()
6604 | (exception exn
) -> dolog
"Unix.waitpid: %s" @@ exntos exn
6606 | _pid
, _status
-> reap ()
6608 Sys.set_signal
Sys.sigchld
(Sys.Signal_handle
(fun _ -> doreap := true));
6612 if nonemptystr
!rcmdpath
6613 then remoteopen !rcmdpath
6618 let rec loop deadline
=
6624 let r = [state
.ss; state
.wsfd] in
6628 | Some fd
-> fd
:: r
6632 state
.redisplay
<- false;
6639 if deadline
= infinity
6641 else max
0.0 (deadline
-. now)
6646 try Unix.select
r [] [] timeout
6647 with Unix.Unix_error
(Unix.EINTR
, _, _) -> [], [], []
6653 if state
.ghyll
== noghyll
6655 match state
.autoscroll
with
6656 | Some step
when step
!= 0 ->
6657 let y = state
.y + step
in
6658 let fy = if conf
.maxhfit
then state
.winh
else 0 in
6661 then state
.maxy - fy
6662 else if y >= state
.maxy - fy then 0 else y
6664 if state
.mode = View
6665 then gotoxy_and_clear_text state
.x y
6666 else gotoxy state
.x y;
6669 else deadline
+. 0.01
6674 let rec checkfds = function
6676 | fd
:: rest
when fd
= state
.ss ->
6677 let cmd = rcmd state
.ss in
6681 | fd
:: rest
when fd
= state
.wsfd ->
6685 | fd
:: rest
when Some fd
= !optrfd ->
6686 begin match remote fd
with
6687 | None
-> optrfd := remoteopen !rcmdpath;
6688 | opt -> optrfd := opt
6693 dolog
"select returned unknown descriptor";
6699 if deadline
= infinity
6703 match state
.autoscroll
with
6704 | Some step
when step
!= 0 -> deadline1
6705 | _ -> if state
.ghyll
== noghyll
then infinity
else deadline1
6710 match loop infinity
with
6712 Config.save leavebirdseye;
6713 if hasunsavedchanges
()
6715 | _ -> error
"umpossible - infinity reached"