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
89 l
.pagedispx l
.pagedispy
93 let debugrect (x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
) =
99 }|} x0 y0 x1 y1 x2 y2 x3 y3
;
102 let isbirdseye = function
104 | Textentry _
| View
| LinkNav _
-> false
107 let istextentry = function
108 | Textentry _
-> true
109 | Birdseye _
| View
| LinkNav _
-> false
112 let wtmode = ref false;;
113 let cxack = ref false;;
115 let pgscale h
= truncate
(float h
*. conf
.pgscale);;
118 if state
.uioh#alwaysscrolly
|| ((conf
.scrollb
land scrollbhv
!= 0)
119 && (state
.w
> state
.winw
))
125 if state
.uioh#alwaysscrolly
|| ((conf
.scrollb
land scrollbvv
!= 0)
126 && (state
.maxy
> state
.winh
))
134 else x
> state
.winw
- vscrollw ()
138 fstate
.fontsize
<- n
;
139 fstate
.wwidth
<- measurestr fstate
.fontsize
"w";
140 fstate
.maxrows
<- (state
.winh
- fstate
.fontsize
- 1) / (fstate
.fontsize
+ 1);
146 else Printf.kprintf ignore fmt
150 if emptystr conf
.pathlauncher
151 then dolog
"%s" state
.path
153 let command = Str.global_replace percentsre state
.path conf
.pathlauncher
in
154 match spawn
command [] with
157 dolog
"failed to execute `%s': %s" command @@ exntos exn
163 let postRedisplay who
=
164 vlog "redisplay for [%S]" who
;
165 state
.redisplay
<- true;
169 let getopaque pageno
=
170 try Some
(Hashtbl.find state
.pagemap
(pageno
, state
.gen
))
171 with Not_found
-> None
174 let pagetranslatepoint l x y
=
175 let dy = y
- l
.pagedispy
in
176 let y = dy + l
.pagey
in
177 let dx = x
- l
.pagedispx
in
178 let x = dx + l
.pagex
in
182 let onppundermouse g
x y d
=
185 begin match getopaque l
.pageno
with
187 let x0 = l
.pagedispx
in
188 let x1 = x0 + l
.pagevw
in
189 let y0 = l
.pagedispy
in
190 let y1 = y0 + l
.pagevh
in
191 if y >= y0 && y <= y1 && x >= x0 && x <= x1
193 let px, py
= pagetranslatepoint l
x y in
194 match g opaque l
px py
with
207 let g opaque l
px py
=
210 match rectofblock opaque
px py
with
211 | Some
[|x0;x1;y0;y1|] ->
212 let rect = (x0, y0, x1, y0, x1, y1, x0, y1) in
213 let color = (0.0, 0.0, 1.0 /. (l
.pageno
mod 3 |> float), 0.5) in
214 state
.rects
<- [l
.pageno
, color, rect];
215 G.postRedisplay "getunder";
218 let under = whatsunder opaque
px py
in
219 if under = Unone
then None
else Some
under
221 onppundermouse g x y Unone
226 match unproject opaque
x y with
227 | Some
(x, y) -> Some
(Some
(opaque
, l
.pageno
, x, y))
230 onppundermouse g x y None
;
234 state
.text
<- Printf.sprintf
"%c%s" c s
;
235 G.postRedisplay "showtext";
239 Format.ksprintf
(fun s
-> showtext '
!' s
) fmt
;
242 let pipesel opaque cmd
=
245 match Unix.pipe
() with
246 | (exception exn
) -> dolog
"pipesel cannot create pipe: %S" @@ exntos exn
;
248 let doclose what fd
=
249 Ne.clo fd
(fun msg
-> dolog
"%s close failed: %s" what msg
)
252 try spawn cmd
[r
, 0; w
, -1]
254 dolog
"cannot execute %S: %s" cmd
@@ exntos exn
;
260 G.postRedisplay "pipesel";
262 else doclose "pipesel pipe/w" w
;
263 doclose "pipesel pipe/r" r
;
267 let g opaque l
px py
=
268 if markunder opaque
px py conf
.paxmark
271 match getopaque l
.pageno
with
273 | Some opaque
-> pipesel opaque conf
.paxcmd
278 G.postRedisplay "paxunder";
279 if conf
.paxmark
= Mark_page
282 match getopaque l
.pageno
with
284 | Some opaque
-> clearmark opaque
) state
.layout
;
285 state
.roam
<- onppundermouse g x y (fun () -> impmsg "whoopsie daisy");
289 match Unix.pipe
() with
290 | (exception exn
) -> impmsg "pipe failed: %s" @@ exntos exn
293 Ne.clo fd
(fun msg
-> impmsg "failed to close %s: %s" cap msg
)
296 try spawn conf
.selcmd
[r
, 0; w
, -1]
298 impmsg "failed to execute %s: %s" conf
.selcmd
@@ exntos exn
;
304 let l = String.length s
in
305 let bytes = Bytes.unsafe_of_string s
in
306 let n = tempfailureretry
(Unix.write w
bytes 0) l in
308 then impmsg "failed to write %d characters to sel pipe, wrote %d"
311 impmsg "failed to write to sel pipe: %s" @@ exntos exn
314 clo "selstring pipe/r" r
;
315 clo "selstring pipe/w" w
;
318 let undertext = function
321 | Utext s
-> "font: " ^ s
322 | Uannotation
(opaque
, slinkindex
) ->
323 "annotation: " ^ getannotcontents opaque slinkindex
326 let updateunder x y =
327 match getunder x y with
328 | Unone
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
330 if conf
.underinfo
then showtext 'u'
("ri: " ^ uri
);
331 Wsi.setcursor
Wsi.CURSOR_INFO
333 if conf
.underinfo
then showtext '
f'
("ont: " ^ s
);
334 Wsi.setcursor
Wsi.CURSOR_TEXT
336 if conf
.underinfo
then showtext 'a'
"nnotation";
337 Wsi.setcursor
Wsi.CURSOR_INFO
340 let showlinktype under =
341 if conf
.underinfo
&& under != Unone
342 then showtext ' '
@@ undertext under
345 let intentry_with_suffix text key
=
347 if key
>= 32 && key
< 127
349 let c = Char.chr key
in
354 | 'k'
| 'm'
| '
g'
| 'K'
| 'M'
| 'G'
->
355 addchar
text @@ asciilower
c
357 state
.text <- Printf.sprintf
"invalid key (%d, `%c')" key
c;
360 state
.text <- Printf.sprintf
"invalid key %d" key
;
368 let b = Buffer.create
16 in
371 let b = Buffer.to_bytes
b in
372 wcmd state
.ss
b @@ Bytes.length
b
376 let nogeomcmds cmds
=
378 | s
, [] -> emptystr s
382 let layoutN ((columns
, coverA
, coverB
), b) x y sw sh
=
383 let rec fold accu
n =
384 if n = Array.length
b
387 let pdimno, dx, vy
, (_
, w
, h
, xoff
) = b.(n) in
390 || n = state
.pagecount
- coverB
391 || (n - coverA
) mod columns
= columns
- 1)
397 let pagey = max
0 (y - vy
) in
398 let pagedispy = if pagey > 0 then 0 else vy
- y in
399 let pagedispx, pagex
=
401 if n = coverA
- 1 || n = state
.pagecount
- coverB
402 then x + (sw
- w
) / 2
410 let vw = sw
- pagedispx in
411 let pw = w
- pagex
in
414 let pagevh = min
(h
- pagey) (sh
- pagedispy) in
415 if pagevw > 0 && pagevh > 0
426 ; pagedispx = pagedispx
427 ; pagedispy = pagedispy
439 if Array.length
b = 0
441 else List.rev
(fold [] (page_of_y
y))
444 let layoutS (columns
, b) x y sw sh
=
445 let rec fold accu n =
446 if n = Array.length
b
449 let pdimno, px, vy
, (_
, pagew
, pageh
, xoff
) = b.(n) in
457 let pagey = max
0 (y - vy
) in
458 let pagedispy = if pagey > 0 then 0 else vy
- y in
459 let pagedispx, pagex
=
473 let pagecolw = pagew
/columns
in
476 then pagedispx + ((sw
- pagecolw) / 2)
480 let vw = sw
- pagedispx in
481 let pw = pagew
- pagex
in
484 let pagevw = min
pagevw pagecolw in
485 let pagevh = min
(pageh
- pagey) (sh
- pagedispy) in
486 if pagevw > 0 && pagevh > 0
497 ; pagedispx = pagedispx
498 ; pagedispy = pagedispy
499 ; pagecol
= n mod columns
513 let layout x y sw sh
=
514 if nogeomcmds state
.geomcmds
516 match conf
.columns
with
517 | Csingle
b -> layoutN ((1, 0, 0), b) x y sw sh
518 | Cmulti
c -> layoutN c x y sw sh
519 | Csplit s
-> layoutS s
x y sw sh
524 let y = state
.y + incr
in
526 let y = min
y (state
.maxy
- (if conf
.maxhfit
then state
.winh
else 0)) in
531 let tilex = l.pagex
mod conf
.tilew
in
532 let tiley = l.pagey mod conf
.tileh
in
534 let col = l.pagex
/ conf
.tilew
in
535 let row = l.pagey / conf
.tileh
in
537 let rec rowloop row y0 dispy h
=
541 let dh = conf
.tileh
- y0 in
543 let rec colloop col x0 dispx w
=
547 let dw = conf
.tilew
- x0 in
549 f col row dispx dispy
x0 y0 dw dh;
550 colloop (col+1) 0 (dispx
+dw) (w
-dw)
553 colloop col tilex l.pagedispx l.pagevw;
554 rowloop (row+1) 0 (dispy
+dh) (h
-dh)
557 if l.pagevw > 0 && l.pagevh > 0
558 then rowloop row tiley l.pagedispy l.pagevh;
561 let gettileopaque l col row =
563 l.pageno
, state
.gen
, conf
.colorspace
, conf
.angle
, l.pagew
, l.pageh
, col, row
565 try Some
(Hashtbl.find state
.tilemap
key)
566 with Not_found
-> None
569 let puttileopaque l col row gen colorspace angle opaque size elapsed
=
570 let key = l.pageno
, gen
, colorspace
, angle
, l.pagew
, l.pageh
, col, row in
571 Hashtbl.add state
.tilemap
key (opaque
, size
, elapsed
)
574 let filledrect2 x0 y0 x1 y1 x2 y2 x3 y3
=
575 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x1; y1; x2
; y2
; x3
; y3
|];
576 GlArray.vertex `two state
.vraw
;
577 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
580 let filledrect1 x0 y0 x1 y1 = filledrect2 x0 y0 x0 y1 x1 y0 x1 y1;;
582 let filledrect x0 y0 x1 y1 =
583 GlArray.disable `texture_coord
;
584 filledrect1 x0 y0 x1 y1;
585 GlArray.enable `texture_coord
;
588 let linerect x0 y0 x1 y1 =
589 GlArray.disable `texture_coord
;
590 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x0; y1; x1; y1; x1; y0 |];
591 GlArray.vertex `two state
.vraw
;
592 GlArray.draw_arrays `line_loop ~first
:0 ~count
:4;
593 GlArray.enable `texture_coord
;
596 let drawtiles l color =
599 let f col row x y tilex tiley w h
=
600 match gettileopaque l col row with
601 | Some
(opaque
, _
, t
) ->
602 let params = x, y, w
, h
, tilex, tiley in
604 then GlTex.env
(`mode `blend
);
605 drawtile
params opaque
;
607 then GlTex.env
(`mode `modulate
);
611 let s = Printf.sprintf
615 let w = measurestr fstate
.fontsize
s in
616 GlDraw.color (0.0, 0.0, 0.0);
617 filledrect (float (x-2))
620 (float (y + fstate
.fontsize
+ 2));
622 drawstring fstate
.fontsize
x (y + fstate
.fontsize
- 1) s;
629 let lw = state
.winw
- x in
632 let lh = state
.winh
- y in
636 then GlTex.env
(`mode `blend
);
637 begin match state
.checkerstexid
with
639 Gl.enable `texture_2d
;
640 GlTex.bind_texture ~target
:`texture_2d id
;
644 and y1 = float (y+h
) in
646 let tw = float w /. 16.0
647 and th
= float h
/. 16.0 in
648 let tx0 = float tilex /. 16.0
649 and ty0
= float tiley /. 16.0 in
651 and ty1
= ty0
+. th
in
652 Raw.sets_float state
.vraw ~pos
:0
653 [| x0; y0; x0; y1; x1; y0; x1; y1 |];
654 Raw.sets_float state
.traw ~pos
:0
655 [| tx0; ty0
; tx0; ty1
; tx1; ty0
; tx1; ty1
|];
656 GlArray.vertex `two state
.vraw
;
657 GlArray.tex_coord `two state
.traw
;
658 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
659 Gl.disable `texture_2d
;
662 GlDraw.color (1.0, 1.0, 1.0);
663 filledrect (float x) (float y) (float (x+w)) (float (y+h
));
666 then GlTex.env
(`mode `modulate
);
667 if w > 128 && h
> fstate
.fontsize
+ 10
669 let c = if conf
.invert
then 1.0 else 0.0 in
670 GlDraw.color (c, c, c);
673 then (col*conf
.tilew
, row*conf
.tileh
)
676 drawstring2 fstate
.fontsize
x y "Loading %d [%d,%d]" l.pageno
c r
;
685 let pagevisible layout n = List.exists
(fun l -> l.pageno
= n) layout;;
687 let tilevisible1 l x y =
689 and ax1
= l.pagex
+ l.pagevw
691 and ay1
= l.pagey + l.pagevh in
695 let bx1 = min
(bx0 + conf
.tilew
) l.pagew
696 and by1
= min
(by0
+ conf
.tileh
) l.pageh
in
698 let rx0 = max
ax0 bx0
699 and ry0
= max ay0 by0
700 and rx1
= min ax1
bx1
701 and ry1
= min ay1 by1
in
703 let nonemptyintersection = rx1
> rx0 && ry1
> ry0
in
707 let tilevisible layout n x y =
708 let rec findpageinlayout m
= function
709 | l :: rest
when l.pageno
= n ->
710 tilevisible1 l x y || (
711 match conf
.columns
with
712 | Csplit
(c, _
) when c > m
-> findpageinlayout (m
+1) rest
717 | _
:: rest
-> findpageinlayout 0 rest
720 findpageinlayout 0 layout;
723 let tileready l x y =
724 tilevisible1 l x y &&
725 gettileopaque l (x/conf
.tilew
) (y/conf
.tileh
) != None
728 let tilepage n p
layout =
729 let rec loop = function
733 let f col row _ _ _ _ _ _
=
734 if state
.currently
= Idle
736 match gettileopaque l col row with
739 let x = col*conf
.tilew
740 and y = row*conf
.tileh
in
742 let w = l.pagew
- x in
746 let h = l.pageh
- y in
751 then getpbo
w h conf
.colorspace
754 wcmd "tile %s %d %d %d %d %s"
755 (~
> p
) x y w h (~
> pbo);
758 l, p
, conf
.colorspace
, conf
.angle
,
759 state
.gen
, col, row, conf
.tilew
, conf
.tileh
768 if nogeomcmds state
.geomcmds
772 let preloadlayout x y sw sh
=
773 let y = if y < sh
then 0 else y - sh
in
774 let x = min
0 (x + sw
) in
782 if state
.currently
!= Idle
787 begin match getopaque l.pageno
with
789 wcmd "page %d %d" l.pageno
l.pagedimno
;
790 state
.currently
<- Loading
(l, state
.gen
);
792 tilepage l.pageno opaque pages
;
797 if nogeomcmds state
.geomcmds
803 if conf
.preload && state
.currently
= Idle
804 then load (preloadlayout state
.x state
.y state
.winw state
.winh
);
807 let layoutready layout =
808 let rec fold all ls
=
811 let seen = ref false in
812 let allvisible = ref true in
813 let foo col row _ _ _ _ _ _
=
815 allvisible := !allvisible &&
816 begin match gettileopaque l col row with
822 fold (!seen && !allvisible) rest
825 let alltilesvisible = fold true layout in
830 let y = bound
y 0 state
.maxy
in
831 let y, layout, proceed
=
832 match conf
.maxwait
with
833 | Some time
when state
.ghyll
== noghyll
->
834 begin match state
.throttle
with
836 let layout = layout x y state
.winw state
.winh
in
837 let ready = layoutready layout in
841 state
.throttle
<- Some
(layout, y, now
());
843 else G.postRedisplay "gotoxy showall (None)";
845 | Some
(_
, _
, started
) ->
846 let dt = now
() -. started
in
849 state
.throttle
<- None
;
850 let layout = layout x y state
.winw state
.winh
in
852 G.postRedisplay "maxwait";
859 let layout = layout x y state
.winw state
.winh
in
860 if not
!wtmode || layoutready layout
861 then G.postRedisplay "gotoxy ready";
868 state
.layout <- layout;
869 begin match state
.mode
with
872 | Ltexact
(pageno
, linkno
) ->
873 let rec loop = function
875 state
.lnava
<- Some
(pageno
, linkno
);
876 state
.mode
<- LinkNav
(Ltgendir
0)
877 | l :: _
when l.pageno
= pageno
->
878 begin match getopaque pageno
with
879 | None
-> state
.mode
<- LinkNav
(Ltnotready
(pageno
, 0))
881 let x0, y0, x1, y1 = getlinkrect opaque linkno
in
882 if not
(x0 >= l.pagex
&& x1 <= l.pagex
+ l.pagevw
883 && y0 >= l.pagey && y1 <= l.pagey + l.pagevh)
884 then state
.mode
<- LinkNav
(Ltgendir
0)
886 | _
:: rest
-> loop rest
889 | Ltnotready _
| Ltgendir _
-> ()
895 begin match state
.mode
with
896 | Birdseye
(conf
, leftx
, pageno
, hooverpageno
, anchor
) ->
897 if not
(pagevisible layout pageno
)
899 match state
.layout with
902 state
.mode
<- Birdseye
(
903 conf
, leftx
, l.pageno
, hooverpageno
, anchor
908 | Ltnotready
(_
, dir
)
911 let rec loop = function
914 match getopaque l.pageno
with
915 | None
-> Ltnotready
(l.pageno
, dir
)
920 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
922 if dir
> 0 then LDfirst
else LDlast
928 | Lnotfound
-> loop rest
930 showlinktype (getlink opaque
n);
931 Ltexact
(l.pageno
, n)
935 state
.mode
<- LinkNav
linknav
943 state
.ghyll
<- noghyll
;
946 let mx, my
= state
.mpos
in
951 let conttiling pageno opaque
=
952 tilepage pageno opaque
954 then preloadlayout state
.x state
.y state
.winw state
.winh
958 let gotoxy_and_clear_text x y =
959 if not conf
.verbose
then state
.text <- E.s;
963 let getanchory (n, top
, dtop
) =
964 let y, h = getpageyh
n in
967 let ips = calcips
h in
968 y + truncate
(top
*.float h -. dtop
*.float ips) + ips;
970 y + truncate
(top
*.float h -. dtop
*.float conf
.interpagespace
)
973 let gotoanchor anchor
=
974 gotoxy state
.x (getanchory anchor
);
978 cbput state
.hists
.nav
(getanchor
());
982 let anchor = cbgetc state
.hists
.nav dir
in
986 let gotoghyll1 single
y =
988 (* http://devmaster.net/forums/topic/9796-ease-in-ease-out-algorithm/ *)
990 let s x = 3.0*.x**2.0 -. 2.0*.x**3.0 in
992 then s (float f /. float a
)
995 then 1.0 -. s ((float (f-b) /. float (n-b)))
1001 let ins = float a
*. 0.5
1002 and outs
= float (n-b) *. 0.5 in
1004 ins +. outs
+. float ones
1006 let rec set nab
y sy
=
1007 let (_N
, _A
, _B
), y =
1010 let scl = if y > sy
then 2 else -2 in
1011 let _N, _
, _
= nab
in
1012 (_N,0,_N), y+conf
.scrollstep
*scl
1014 let sum = summa
_N _A _B
in
1015 let dy = float (y - sy
) in
1019 then state
.ghyll
<- noghyll
1022 let s = scroll n _N _A _B
in
1023 let y1 = y1 +. ((s *. dy) /. sum) in
1024 gotoxy_and_clear_text state
.x (truncate
y1);
1025 state
.ghyll
<- gf (n+1) y1;
1029 | Some
y'
when single
-> set nab
y' state
.y
1030 | Some
y'
-> set (_N/2, 1, 1) y' state
.y
1032 gf 0 (float state
.y)
1035 match conf
.ghyllscroll
with
1036 | Some nab
when not conf
.presentation
->
1037 if state
.ghyll
== noghyll
1038 then set nab
y state
.y
1039 else state
.ghyll
(Some
y)
1041 gotoxy_and_clear_text state
.x y
1044 let gotoghyll = gotoghyll1 false;;
1046 let gotopage n top
=
1047 let y, h = getpageyh
n in
1048 let y = y + (truncate
(top
*. float h)) in
1052 let gotopage1 n top
=
1053 let y = getpagey
n in
1058 let invalidate s f =
1059 state
.redisplay
<- false;
1064 match state
.geomcmds
with
1065 | ps
, [] when emptystr ps
->
1067 state
.geomcmds
<- s, [];
1070 state
.geomcmds
<- ps
, [s, f];
1072 | ps
, (s'
, _
) :: rest
when s'
= s ->
1073 state
.geomcmds
<- ps
, ((s, f) :: rest
);
1076 state
.geomcmds
<- ps
, ((s, f) :: cmds
);
1080 Hashtbl.iter
(fun _ opaque
->
1081 wcmd "freepage %s" (~
> opaque
);
1083 Hashtbl.clear state
.pagemap
;
1087 if not
(Queue.is_empty state
.tilelru
)
1089 Queue.iter
(fun (k
, p
, s) ->
1090 wcmd "freetile %s" (~
> p
);
1091 state
.memused
<- state
.memused
- s;
1092 Hashtbl.remove state
.tilemap k
;
1094 state
.uioh#infochanged Memused
;
1095 Queue.clear state
.tilelru
;
1101 let h = truncate
(float h*.conf
.zoom
) in
1102 let d = conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0) in
1106 let opendoc path password
=
1108 state
.password
<- password
;
1109 state
.gen
<- state
.gen
+ 1;
1110 state
.docinfo
<- [];
1111 state
.outlines
<- [||];
1114 setaalevel conf
.aalevel
;
1116 if emptystr state
.origin
1120 Wsi.settitle
("llpp " ^
(mbtoutf8
(Filename.basename
titlepath)));
1121 wcmd "open %d %d %d %s\000%s\000%s\000"
1122 (btod
!wtmode) (btod
!cxack) (btod conf
.usedoccss
)
1123 path password conf
.css
;
1124 invalidate "reqlayout"
1126 wcmd "reqlayout %d %d %d %s\000"
1127 conf
.angle
(FMTE.to_int conf
.fitmodel
)
1128 (stateh state
.winh
) state
.nameddest
1131 let sl = keystostrlist conf
in
1133 function | [] -> accu
1134 | s :: rest
-> loop ((s, 0, Noaction
) :: accu) rest
1135 in makehelp
() @ (("", 0, Noaction
) :: loop [] sl) |> Array.of_list
1139 state
.anchor <- getanchor
();
1140 opendoc state
.path state
.password
;
1144 let c = c *. conf
.colorscale
in
1148 let scalecolor2 (r
, g, b) =
1149 (r
*. conf
.colorscale
, g *. conf
.colorscale
, b *. conf
.colorscale
);
1152 let docolumns columns
=
1155 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1156 let rec loop pageno
pdimno pdim
y ph pdims
=
1157 if pageno
= state
.pagecount
1160 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1162 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1163 pdimno+1, pdim
, rest
1167 let x = max
0 (((state
.winw
- w) / 2) - xoff
) in
1169 y + (if conf
.presentation
1170 then (if pageno
= 0 then calcips
h else calcips ph
+ calcips
h)
1171 else (if pageno
= 0 then 0 else conf
.interpagespace
)
1174 a.(pageno
) <- (pdimno, x, y, pdim
);
1175 loop (pageno
+1) pdimno pdim
(y + h) h pdims
1177 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 state
.pdims
;
1178 conf
.columns
<- Csingle
a;
1180 | Cmulti
((columns
, coverA
, coverB
), _
) ->
1181 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1182 let rec loop pageno
pdimno pdim
x y rowh pdims
=
1184 if m
= pageno
then () else
1185 let (pdimno, x, y, ((_
, _
, h, _
) as pdim
)) = a.(m
) in
1188 let y = y + (rowh
- h) / 2 in
1189 a.(m
) <- (pdimno, x, y, pdim
);
1193 if pageno
= state
.pagecount
1194 then fixrow (((pageno
- 1) / columns
) * columns
)
1196 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1198 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1199 pdimno+1, pdim
, rest
1204 if pageno
= coverA
- 1 || pageno
= state
.pagecount
- coverB
1206 let x = (state
.winw
- w) / 2 in
1208 if conf
.presentation
then calcips
h else conf
.interpagespace
in
1209 x, y + ips + rowh
, h
1212 if (pageno
- coverA
) mod columns
= 0
1214 let x = max
0 (state
.winw
- state
.w) / 2 in
1216 if conf
.presentation
1218 let ips = calcips
h in
1219 y + (if pageno
= 0 then 0 else calcips rowh
+ ips)
1221 y + (if pageno
= 0 then 0 else conf
.interpagespace
)
1225 else x, y, max rowh
h
1229 if pageno
> 1 && (pageno
- coverA
) mod columns
= 0
1232 if pageno
= columns
&& conf
.presentation
1234 let ips = calcips rowh
in
1235 for i
= 0 to pred columns
1237 let (pdimno, x, y, pdim
) = a.(i
) in
1238 a.(i
) <- (pdimno, x, y+ips, pdim
)
1244 fixrow (pageno
- columns
);
1249 a.(pageno
) <- (pdimno, x, y, pdim
);
1250 let x = x + w + xoff
*2 + conf
.interpagespace
in
1251 loop (pageno
+1) pdimno pdim
x y rowh' pdims
1253 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 0 state
.pdims
;
1254 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), a);
1257 let a = Array.make
(state
.pagecount
*c) (-1, -1, -1, (-1, -1, -1, -1)) in
1258 let rec loop pageno
pdimno pdim
y pdims
=
1259 if pageno
= state
.pagecount
1262 let pdimno, ((_
, w, h, _
) as pdim
), pdims
=
1264 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1265 pdimno+1, pdim
, rest
1270 let rec loop1 n x y =
1271 if n = c then y else (
1272 a.(pageno
*c + n) <- (pdimno, x, y, pdim
);
1273 loop1 (n+1) (x+cw) (y + h + conf
.interpagespace
)
1276 let y = loop1 0 0 y in
1277 loop (pageno
+1) pdimno pdim
y pdims
1279 loop 0 ~
-1 (-1,-1,-1,-1) 0 state
.pdims
;
1280 conf
.columns
<- Csplit
(c, a);
1284 docolumns conf
.columns
;
1285 state
.maxy
<- calcheight
();
1286 if state
.reprf
== noreprf
1288 match state
.mode
with
1289 | Birdseye
(_
, _
, pageno
, _
, _
) ->
1290 let y, h = getpageyh pageno
in
1291 let top = (state
.winh
- h) / 2 in
1292 gotoxy state
.x (max
0 (y - top))
1296 let y = getanchory state
.anchor in
1297 let y = min
y (state
.maxy
- state
.winh
) in
1302 state
.reprf
<- noreprf
;
1306 let reshape ?
(firsttime
=false) w h =
1307 GlDraw.viewport ~
x:0 ~
y:0 ~
w ~
h;
1308 if not firsttime
&& nogeomcmds state
.geomcmds
1309 then state
.anchor <- getanchor
();
1312 let w = truncate
(float w *. conf
.zoom
) in
1315 setfontsize fstate
.fontsize
;
1316 GlMat.mode `modelview
;
1317 GlMat.load_identity
();
1319 GlMat.mode `projection
;
1320 GlMat.load_identity
();
1321 GlMat.rotate ~
x:1.0 ~angle
:180.0 ();
1322 GlMat.translate ~
x:~
-.1.0 ~
y:~
-.1.0 ();
1323 GlMat.scale3
(2.0 /. float state
.winw
, 2.0 /. float state
.winh
, 1.0);
1328 else float state
.x /. float state
.w
1330 invalidate "geometry"
1334 then state
.x <- truncate
(relx *. float w);
1336 match conf
.columns
with
1338 | Cmulti
((c, _
, _
), _
) -> (w - (c-1)*conf
.interpagespace
) / c
1339 | Csplit
(c, _
) -> w * c
1341 wcmd "geometry %d %d %d"
1342 w (stateh h) (FMTE.to_int conf
.fitmodel
)
1347 let len = String.length state
.text in
1348 let x0 = if conf
.leftscroll
then vscrollw () else 0 in
1351 match state
.mode
with
1352 | Textentry _
| View
| LinkNav _
->
1353 let h, _
, _
= state
.uioh#scrollpw
in
1358 filledrect x (float (state
.winh
- (fstate
.fontsize
+ 4) - hscrollh))
1359 (x+.w) (float (state
.winh
- hscrollh))
1362 let w = float (state
.winw
- 1 - vscrollw ()) in
1363 if state
.progress
>= 0.0 && state
.progress
< 1.0
1365 GlDraw.color (0.3, 0.3, 0.3);
1366 let w1 = w *. state
.progress
in
1368 GlDraw.color (0.0, 0.0, 0.0);
1369 rect (float x0+.w1) (float x0+.w-.w1)
1372 GlDraw.color (0.0, 0.0, 0.0);
1376 GlDraw.color (1.0, 1.0, 1.0);
1379 (if conf
.leftscroll
then x0 + 2 else x0 + if len > 0 then 8 else 2)
1380 (state
.winh
- hscrollh - 5) s;
1383 match state
.mode
with
1384 | Textentry
((prefix
, text, _
, _
, _
, _
), _
) ->
1388 Printf.sprintf
"%s%s_ [%s]" prefix
text state
.text
1390 Printf.sprintf
"%s%s_" prefix
text
1396 | LinkNav _
-> state
.text
1401 if not
(istextentry state
.mode
) && state
.uioh#eformsgs
1403 let s1 = "(press 'e' to review error messasges)" in
1404 if nonemptystr
s then s ^
" " ^
s1 else s1
1414 let len = Queue.length state
.tilelru
in
1416 match state
.throttle
with
1419 then preloadlayout state
.x state
.y state
.winw state
.winh
1421 | Some
(layout, _
, _
) ->
1425 if state
.memused
<= conf
.memlimit
1430 let (k
, p
, s) as lruitem
= Queue.pop state
.tilelru
in
1431 let n, gen
, colorspace
, angle
, pagew
, pageh
, col, row = k
in
1432 let (_
, pw, ph
, _
) = getpagedim
n in
1434 && colorspace
= conf
.colorspace
1435 && angle
= conf
.angle
1439 let x = col*conf
.tilew
1440 and y = row*conf
.tileh
in
1441 tilevisible (Lazy.force_val
layout) n x y
1443 then Queue.push lruitem state
.tilelru
1446 wcmd "freetile %s" (~
> p
);
1447 state
.memused
<- state
.memused
- s;
1448 state
.uioh#infochanged Memused
;
1449 Hashtbl.remove state
.tilemap k
;
1457 let onpagerect pageno
f =
1459 match conf
.columns
with
1460 | Cmulti
(_
, b) -> b
1462 | Csplit
(_
, b) -> b
1464 if pageno
>= 0 && pageno
< Array.length
b
1466 let (_
, _
, _
, (_
, w, h, _
)) = b.(pageno
) in
1470 let gotopagexy1 wtmode pageno
x y =
1471 let _,w1,h1
,leftx
= getpagedim pageno
in
1472 let top = y /. (float h1
) in
1473 let left = x /. (float w1) in
1474 let py, w, h = getpageywh pageno
in
1475 let wh = state
.winh
in
1476 let x = left *. (float w) in
1477 let x = leftx
+ state
.x + truncate
x in
1479 if x < 0 || x >= state
.winw
1483 let pdy = truncate
(top *. float h) in
1484 let y'
= py + pdy in
1485 let dy = y'
- state
.y in
1487 if x != state
.x || not
(dy > 0 && dy < wh)
1489 if conf
.presentation
1491 if abs
(py - y'
) > wh
1498 if state
.x != sx || state
.y != sy
1503 let ww = state
.winw
in
1505 and qy
= pdy / wh in
1507 and y = py + qy
* wh in
1508 let x = if -x + ww > w1 then -(w1-ww) else x
1509 and y'
= if y + wh > state
.maxy
then state
.maxy
- wh else y in
1511 if conf
.presentation
1513 if abs
(py - y'
) > wh
1522 gotoxy_and_clear_text x y;
1524 else gotoxy_and_clear_text state
.x state
.y;
1527 let gotopagexy wtmode pageno
x y =
1528 match state
.mode
with
1529 | Birdseye
_ -> gotopage pageno
0.0
1532 | LinkNav
_ -> gotopagexy1 wtmode pageno
x y
1535 let getpassword () =
1536 let passcmd = getenvwithdef
"LLPP_ASKPASS" conf
.passcmd in
1541 impmsg "error getting password: %s" s;
1542 dolog
"%s" s) passcmd;
1545 let pgoto opaque pageno
x y =
1546 let pdimno = getpdimno pageno
in
1547 let x, y = project opaque pageno
pdimno x y in
1548 gotopagexy false pageno
x y;
1552 (* dolog "%S" cmds; *)
1553 let spl = splitatchar cmds ' '
in
1555 try Scanf.sscanf
s fmt
f
1557 dolog
"error processing '%S': %s" cmds
@@ exntos exn
;
1560 let addoutline outline
=
1561 match state
.currently
with
1562 | Outlining outlines
->
1563 state
.currently
<- Outlining
(outline
:: outlines
)
1564 | Idle
-> state
.currently
<- Outlining
[outline
]
1567 dolog
"invalid outlining state";
1568 logcurrently state
.currently
1573 state
.uioh#infochanged Pdim
;
1575 | "clearrects", "" ->
1576 state
.rects
<- state
.rects1
;
1577 G.postRedisplay "clearrects";
1579 | "continue", args
->
1580 let n = scan args
"%u" (fun n -> n) in
1581 state
.pagecount
<- n;
1582 begin match state
.currently
with
1584 state
.currently
<- Idle
;
1585 state
.outlines
<- Array.of_list
(List.rev
l)
1591 let cur, cmds
= state
.geomcmds
in
1593 then failwith
"umpossible";
1595 begin match List.rev cmds
with
1597 state
.geomcmds
<- E.s, [];
1598 state
.throttle
<- None
;
1602 state
.geomcmds
<- s, List.rev rest
;
1604 if conf
.maxwait
= None
&& not
!wtmode
1605 then G.postRedisplay "continue";
1612 then showtext ' ' args
1615 Buffer.add_string state
.errmsgs args
;
1616 state
.newerrmsgs
<- true;
1617 G.postRedisplay "error message"
1619 | "progress", args
->
1620 let progress, text =
1623 f, String.sub args pos
(String.length args
- pos
))
1626 state
.progress <- progress;
1627 G.postRedisplay "progress"
1629 | "firstmatch", args
->
1630 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1631 scan args
"%u %d %f %f %f %f %f %f %f %f"
1632 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1633 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1635 let y = (getpagey
pageno) + truncate
y0 in
1643 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1644 state
.rects1
<- [pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)]
1647 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1648 scan args
"%u %d %f %f %f %f %f %f %f %f"
1649 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1650 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1652 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1654 (pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) :: state
.rects1
1657 let pageopaques, t
= scan args
"%s %f" (fun p t
-> p
, t
) in
1658 let pageopaque = ~
< pageopaques in
1659 begin match state
.currently
with
1660 | Loading
(l, gen
) ->
1661 vlog "page %d took %f sec" l.pageno t
;
1662 Hashtbl.replace state
.pagemap
(l.pageno, gen
) pageopaque;
1663 begin match state
.throttle
with
1665 let preloadedpages =
1667 then preloadlayout state
.x state
.y state
.winw state
.winh
1672 List.fold_left
(fun s l -> IntSet.add
l.pageno s)
1673 IntSet.empty
preloadedpages
1676 Hashtbl.fold (fun ((pageno, _) as key) opaque
accu ->
1677 if not
(IntSet.mem
pageno set)
1679 wcmd "freepage %s" (~
> opaque
);
1685 List.iter
(Hashtbl.remove state
.pagemap
) evictedpages;
1688 state
.currently
<- Idle
;
1691 tilepage l.pageno pageopaque state
.layout;
1693 load preloadedpages;
1694 let visible = pagevisible state
.layout l.pageno in
1697 match state
.mode
with
1698 | LinkNav
(Ltnotready
(pageno, dir
)) ->
1699 if pageno = l.pageno
1704 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
1706 if dir
> 0 then LDfirst
else LDlast
1709 findlink
pageopaque ld
1714 showlinktype (getlink
pageopaque n);
1715 state
.mode
<- LinkNav
(Ltexact
(l.pageno, n))
1717 | LinkNav
(Ltgendir
_)
1718 | LinkNav
(Ltexact
_)
1724 if visible && layoutready state
.layout
1726 G.postRedisplay "page";
1730 | Some
(layout, _, _) ->
1731 state
.currently
<- Idle
;
1732 tilepage l.pageno pageopaque layout;
1739 dolog
"Inconsistent loading state";
1740 logcurrently state
.currently
;
1745 let (x, y, opaques
, size
, t
) =
1746 scan args
"%u %u %s %u %f"
1747 (fun x y p size t
-> (x, y, p
, size
, t
))
1749 let opaque = ~
< opaques
in
1750 begin match state
.currently
with
1751 | Tiling
(l, pageopaque, cs
, angle
, gen
, col, row, tilew
, tileh
) ->
1752 vlog "tile %d [%d,%d] took %f sec" l.pageno col row t
;
1755 if tilew
!= conf
.tilew
|| tileh
!= conf
.tileh
1757 wcmd "freetile %s" (~
> opaque);
1758 state
.currently
<- Idle
;
1762 puttileopaque l col row gen cs angle
opaque size t
;
1763 state
.memused
<- state
.memused
+ size
;
1764 state
.uioh#infochanged Memused
;
1766 Queue.push
((l.pageno, gen
, cs
, angle
, l.pagew
, l.pageh
, col, row),
1767 opaque, size
) state
.tilelru
;
1770 match state
.throttle
with
1771 | None
-> state
.layout
1772 | Some
(layout, _, _) -> layout
1775 state
.currently
<- Idle
;
1777 && conf
.colorspace
= cs
1778 && conf
.angle
= angle
1779 && tilevisible layout l.pageno x y
1780 then conttiling l.pageno pageopaque;
1782 begin match state
.throttle
with
1784 preload state
.layout;
1786 && conf
.colorspace
= cs
1787 && conf
.angle
= angle
1788 && tilevisible state
.layout l.pageno x y
1789 && (not
!wtmode || layoutready state
.layout)
1790 then G.postRedisplay "tile nothrottle";
1792 | Some
(layout, y, _) ->
1793 let ready = layoutready layout in
1797 state
.layout <- layout;
1798 state
.throttle
<- None
;
1799 G.postRedisplay "throttle";
1808 dolog
"Inconsistent tiling state";
1809 logcurrently state
.currently
;
1814 let (n, w, h, _) as pdim
=
1815 scan args
"%u %u %u %u" (fun n w h x -> n, w, h, x)
1818 match conf
.fitmodel
with
1820 | FitPage
| FitProportional
->
1821 match conf
.columns
with
1822 | Csplit
_ -> (n, w, h, 0)
1823 | Csingle
_ | Cmulti
_ -> pdim
1825 state
.pdims
<- pdim :: state
.pdims
;
1826 state
.uioh#infochanged Pdim
1829 let (l, n, t
, h, pos
) =
1830 scan args
"%u %u %d %u %n"
1831 (fun l n t
h pos
-> l, n, t
, h, pos
)
1833 let s = String.sub args pos
(String.length args
- pos
) in
1834 addoutline (s, l, Oanchor
(n, float t
/. float h, 0.0))
1837 let (l, len, pos
) = scan args
"%u %u %n" (fun l len pos
-> l, len, pos
) in
1838 let s = String.sub args pos
len in
1839 let pos2 = pos
+ len + 1 in
1840 let uri = String.sub args
pos2 (String.length args
- pos2) in
1841 addoutline (s, l, Ouri
uri)
1844 let (l, pos
) = scan args
"%u %n" (fun l pos
-> l, pos
) in
1845 let s = String.sub args pos
(String.length args
- pos
) in
1846 addoutline (s, l, Onone
)
1850 scan args
"%u %d %d" (fun n l t
-> n, l, t
)
1852 state
.reprf
<- (fun () -> gotopagexy !wtmode n (float l) (float t
))
1855 let c, v
= splitatchar args '
\t'
in
1866 if let len = String.length
c in
1867 len > 6 && ((String.sub
c (len-4) 4) = "date")
1869 if String.length v
>= 7 && v
.[0] = 'D'
&& v
.[1] = '
:'
1871 let b = Buffer.create
10 in
1872 Printf.bprintf
b "%s\t" c;
1875 Buffer.add_substring
b v p
l;
1876 Buffer.add_char
b c;
1877 with exn
-> Buffer.add_string
b @@ exntos exn
1885 Buffer.add_char
b '
['
;
1886 Buffer.add_string
b v
;
1887 Buffer.add_char
b '
]'
;
1894 state
.docinfo
<- (1, s) :: state
.docinfo
1897 state
.docinfo
<- List.rev state
.docinfo
;
1898 state
.uioh#infochanged Docinfo
1902 then Wsi.settitle
"Wrong password";
1903 let password = getpassword () in
1904 if emptystr
password
1905 then error
"document is password protected"
1906 else opendoc state
.path
password
1909 error
"unknown cmd `%S'" cmds
1914 let action = function
1915 | HCprev
-> cbget cb ~
-1
1916 | HCnext
-> cbget cb
1
1917 | HCfirst
-> cbget cb ~
-(cb
.rc)
1918 | HClast
-> cbget cb
(cb
.len - 1 - cb
.rc)
1919 and cancel
() = cb
.rc <- rc
1923 let search pattern forward
=
1924 match conf
.columns
with
1925 | Csplit
_ -> impmsg "searching does not work properly in split columns mode"
1928 if nonemptystr pattern
1931 match state
.layout with
1934 l.pageno, (l.pagey + if forward
then 0 else 0*l.pagevh)
1936 wcmd "search %d %d %d %d,%s\000"
1937 (btod conf
.icase
) pn py (btod forward
) pattern
;
1940 let intentry text key =
1942 if key >= 32 && key < 127
1944 let c = Char.chr
key in
1946 | '
0'
.. '
9'
-> addchar
text c
1948 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key c;
1951 state
.text <- Printf.sprintf
"invalid key (%d)" key;
1962 let l = String.length
s in
1963 let rec loop pos
n =
1967 let m = Char.code
s.[pos
] - (if pos
= 0 && l > 1 then 96 else 97) in
1968 loop (pos
+1) (n*26 + m)
1971 let rec loop n = function
1974 match getopaque l.pageno with
1975 | None
-> loop n rest
1977 let m = getlinkcount
opaque in
1980 let under = getlink
opaque n in
1983 else loop (n-m) rest
1985 loop n state
.layout;
1989 let linknentry text key =
1990 if key >= 32 && key < 127
1992 let text = addchar
text (Char.chr
key) in
1993 linknact (fun under -> state
.text <- undertext under) text;
1996 state
.text <- Printf.sprintf
"invalid key %d" key;
2001 let textentry text key =
2002 if Wsi.isspecialkey
key
2004 else TEcont
(text ^ toutf8
key)
2007 let reqlayout angle fitmodel
=
2008 match state
.throttle
with
2010 if nogeomcmds state
.geomcmds
2011 then state
.anchor <- getanchor
();
2012 conf
.angle
<- angle
mod 360;
2015 match state
.mode
with
2016 | LinkNav
_ -> state
.mode
<- View
2021 conf
.fitmodel
<- fitmodel
;
2025 wcmd "reqlayout %d %d %d"
2026 conf
.angle
(FMTE.to_int conf
.fitmodel
) (stateh state
.winh
)
2031 let settrim trimmargins trimfuzz
=
2032 if nogeomcmds state
.geomcmds
2033 then state
.anchor <- getanchor
();
2034 conf
.trimmargins
<- trimmargins
;
2035 conf
.trimfuzz
<- trimfuzz
;
2036 let x0, y0, x1, y1 = trimfuzz
in
2038 "settrim" (fun () ->
2039 wcmd "settrim %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1);
2044 match state
.throttle
with
2046 let zoom = max
0.0001 zoom in
2047 if zoom <> conf
.zoom
2049 state
.prevzoom
<- (conf
.zoom, state
.x);
2051 reshape state
.winw state
.winh
;
2052 state
.text <- Printf.sprintf
"zoom is now %-5.2f" (zoom *. 100.0);
2055 | Some
(layout, y, started
) ->
2057 match conf
.maxwait
with
2061 let dt = now
() -. started
in
2069 let pivotzoom ?
(vw=min state
.w state
.winw
)
2070 ?
(vh
=min
(state
.maxy
-state
.y) state
.winh
)
2071 ?
(x=vw/2) ?
(y=vh
/2) zoom =
2072 let w = float state
.w /. zoom in
2073 let hw = w /. 2.0 in
2074 let ratio = float vh
/. float vw in
2075 let hh = hw *. ratio in
2076 let x0 = if zoom < 1.0 then 0.0 else float x -. hw in
2077 let y0 = float y -. hh in
2078 gotoxy (state
.x - truncate
x0) (state
.y + truncate
y0);
2082 let pivotzoom ?
vw ?vh ?
x ?
y zoom =
2083 if nogeomcmds state
.geomcmds
then pivotzoom ?
vw ?vh ?
x ?
y zoom
2086 let setcolumns mode columns coverA coverB
=
2087 state
.prevcolumns
<- Some
(conf
.columns
, conf
.zoom);
2091 then impmsg "split mode doesn't work in bird's eye"
2093 conf
.columns
<- Csplit
(-columns
, E.a);
2101 conf
.columns
<- Csingle
E.a;
2106 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), E.a);
2110 reshape state
.winw state
.winh
;
2113 let resetmstate () =
2114 state
.mstate
<- Mnone
;
2115 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
2118 let enterbirdseye () =
2119 let zoom = float conf
.thumbw
/. float state
.winw
in
2120 let birdseyepageno =
2121 let cy = state
.winh
/ 2 in
2125 let rec fold best
= function
2128 let d = cy - (l.pagedispy + l.pagevh/2)
2129 and dbest
= cy - (best
.pagedispy + best
.pagevh/2) in
2130 if abs
d < abs dbest
2139 { conf
with zoom = conf
.zoom },
2140 state
.x, birdseyepageno, -1, getanchor
()
2144 conf
.presentation
<- false;
2145 conf
.interpagespace
<- 10;
2146 conf
.hlinks
<- false;
2147 conf
.fitmodel
<- FitPage
;
2149 conf
.maxwait
<- None
;
2151 match conf
.beyecolumns
with
2154 Cmulti
((c, 0, 0), E.a)
2155 | None
-> Csingle
E.a
2159 state
.text <- Printf.sprintf
"birds eye mode on (zoom %3.1f%%)"
2164 reshape state
.winw state
.winh
;
2167 let leavebirdseye (c, leftx
, pageno, _, anchor) goback
=
2169 conf
.zoom <- c.zoom;
2170 conf
.presentation
<- c.presentation
;
2171 conf
.interpagespace
<- c.interpagespace
;
2172 conf
.maxwait
<- c.maxwait
;
2173 conf
.hlinks
<- c.hlinks
;
2174 conf
.fitmodel
<- c.fitmodel
;
2175 conf
.beyecolumns
<- (
2176 match conf
.columns
with
2177 | Cmulti
((c, _, _), _) -> Some
c
2179 | Csplit
_ -> failwith
"leaving bird's eye split mode"
2182 match c.columns
with
2183 | Cmulti
(c, _) -> Cmulti
(c, E.a)
2184 | Csingle
_ -> Csingle
E.a
2185 | Csplit
(c, _) -> Csplit
(c, E.a)
2189 state
.text <- Printf.sprintf
"birds eye mode off (zoom %3.1f%%)"
2192 reshape state
.winw state
.winh
;
2193 state
.anchor <- if goback
then anchor else (pageno, 0.0, 1.0);
2197 let togglebirdseye () =
2198 match state
.mode
with
2199 | Birdseye vals
-> leavebirdseye vals
true
2200 | View
-> enterbirdseye ()
2201 | Textentry
_ | LinkNav
_ -> ()
2204 let upbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2205 let pageno = max
0 (pageno - incr
) in
2206 let rec loop = function
2207 | [] -> gotopage1 pageno 0
2208 | l :: _ when l.pageno = pageno ->
2209 if l.pagedispy >= 0 && l.pagey = 0
2210 then G.postRedisplay "upbirdseye"
2211 else gotopage1 pageno 0
2212 | _ :: rest
-> loop rest
2216 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor)
2219 let downbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2220 let pageno = min
(state
.pagecount
- 1) (pageno + incr
) in
2221 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor);
2222 let rec loop = function
2224 let y, h = getpageyh
pageno in
2225 let dy = (y - state
.y) - (state
.winh
- h - conf
.interpagespace
) in
2226 gotoxy state
.x (clamp dy)
2227 | l :: _ when l.pageno = pageno ->
2228 if l.pagevh != l.pageh
2229 then gotoxy state
.x (clamp (l.pageh
- l.pagevh + conf
.interpagespace
))
2230 else G.postRedisplay "downbirdseye"
2231 | _ :: rest
-> loop rest
2237 let optentry mode
_ key =
2238 let btos b = if b then "on" else "off" in
2239 if key >= 32 && key < 127
2241 let c = Char.chr
key in
2245 try conf
.scrollstep
<- int_of_string
s with exn
->
2246 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2248 TEswitch
("scroll step: ", E.s, None
, intentry, ondone, true)
2253 conf
.autoscrollstep
<- boundastep state
.winh
(int_of_string
s);
2254 if state
.autoscroll
<> None
2255 then state
.autoscroll
<- Some conf
.autoscrollstep
2257 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2259 TEswitch
("auto scroll step: ", E.s, None
, intentry, ondone, true)
2264 let n, a, b = multicolumns_of_string
s in
2265 setcolumns mode
n a b;
2267 state
.text <- Printf.sprintf
"bad columns `%s': %s" s @@ exntos exn
2269 TEswitch
("columns: ", E.s, None
, textentry, ondone, true)
2274 let zoom = float (int_of_string
s) /. 100.0 in
2277 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2279 TEswitch
("zoom: ", E.s, None
, intentry, ondone, true)
2284 conf
.thumbw
<- bound
(int_of_string
s) 2 4096;
2286 Printf.sprintf
"thumbnail width is set to %d" conf
.thumbw
;
2287 begin match mode
with
2289 leavebirdseye beye
false;
2296 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2298 TEswitch
("thumbnail width: ", E.s, None
, intentry, ondone, true)
2302 match int_of_string
s with
2303 | angle
-> reqlayout angle conf
.fitmodel
2306 Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2308 TEswitch
("rotation: ", E.s, None
, intentry, ondone, true)
2311 conf
.icase
<- not conf
.icase
;
2312 TEdone
("case insensitive search " ^
(btos conf
.icase
))
2315 conf
.preload <- not conf
.preload;
2316 gotoxy state
.x state
.y;
2317 TEdone
("preload " ^
(btos conf
.preload))
2320 conf
.verbose
<- not conf
.verbose
;
2321 TEdone
("verbose " ^
(btos conf
.verbose
))
2324 conf
.debug
<- not conf
.debug
;
2325 TEdone
("debug " ^
(btos conf
.debug
))
2328 conf
.maxhfit
<- not conf
.maxhfit
;
2329 state
.maxy
<- calcheight
();
2330 TEdone
("maxhfit " ^
(btos conf
.maxhfit
))
2333 conf
.crophack
<- not conf
.crophack
;
2334 TEdone
("crophack " ^
btos conf
.crophack
)
2338 match conf
.maxwait
with
2340 conf
.maxwait
<- Some infinity
;
2341 "always wait for page to complete"
2343 conf
.maxwait
<- None
;
2344 "show placeholder if page is not ready"
2349 conf
.underinfo
<- not conf
.underinfo
;
2350 TEdone
("underinfo " ^
btos conf
.underinfo
)
2353 conf
.savebmarks
<- not conf
.savebmarks
;
2354 TEdone
("persistent bookmarks " ^
btos conf
.savebmarks
)
2360 match state
.layout with
2365 conf
.interpagespace
<- int_of_string
s;
2366 docolumns conf
.columns
;
2367 state
.maxy
<- calcheight
();
2368 let y = getpagey
pageno in
2369 gotoxy state
.x (y + py)
2372 Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
2374 TEswitch
("vertical margin: ", E.s, None
, intentry, ondone, true)
2378 match conf
.fitmodel
with
2379 | FitProportional
-> FitWidth
2380 | FitWidth
| FitPage
-> FitProportional
2382 reqlayout conf
.angle
fm;
2383 TEdone
("proportional display " ^
btos (fm == FitProportional
))
2386 settrim (not conf
.trimmargins
) conf
.trimfuzz
;
2387 TEdone
("trim margins " ^
btos conf
.trimmargins
)
2390 conf
.invert
<- not conf
.invert
;
2391 TEdone
("invert colors " ^
btos conf
.invert
)
2395 cbput state
.hists
.sel
s;
2398 TEswitch
("selection command: ", E.s, Some
(onhist state
.hists
.sel
),
2399 textentry, ondone, true)
2403 then conf
.pax
<- Some
(ref (0.0, 0, 0))
2404 else conf
.pax
<- None
;
2405 TEdone
("PAX " ^
btos (conf
.pax
!= None
))
2408 state
.text <- Printf.sprintf
"bad option %d `%c'" key c;
2414 class type lvsource
=
2416 method getitemcount
: int
2417 method getitem
: int -> (string * int)
2418 method hasaction
: int -> bool
2426 method getactive
: int
2427 method getfirst
: int
2429 method getminfo
: (int * int) array
2432 class virtual lvsourcebase
= object
2433 val mutable m_active
= 0
2434 val mutable m_first
= 0
2435 val mutable m_pan
= 0
2436 method getactive
= m_active
2437 method getfirst
= m_first
2438 method getpan
= m_pan
2439 method getminfo
: (int * int) array
= E.a
2442 let textentrykeyboard
2443 key _mask
((c, text, opthist
, onkey
, ondone, cancelonempty
), onleave
) =
2445 let key = Wsi.keypadtodigitkey
key in
2447 state
.mode
<- Textentry
(te
, onleave
);
2449 G.postRedisplay "textentrykeyboard enttext";
2451 let histaction cmd
=
2454 | Some
(action, _) ->
2457 (c, action cmd
, opthist
, onkey
, ondone, cancelonempty
), onleave
2459 G.postRedisplay "textentry histaction"
2463 if emptystr
text && cancelonempty
2466 G.postRedisplay "textentrykeyboard after cancel";
2469 let s = withoutlastutf8
text in
2470 enttext (c, s, opthist
, onkey
, ondone, cancelonempty
)
2472 | @enter
| @kpenter
->
2475 G.postRedisplay "textentrykeyboard after confirm"
2477 | @up
| @kpup
-> histaction HCprev
2478 | @down
| @kpdown
-> histaction HCnext
2479 | @home
| @kphome
-> histaction HCfirst
2480 | @jend
| @kpend
-> histaction HClast
2485 begin match opthist
with
2487 | Some
(_, onhistcancel
) -> onhistcancel
()
2491 G.postRedisplay "textentrykeyboard after cancel2"
2494 enttext (c, E.s, opthist
, onkey
, ondone, cancelonempty
)
2497 | @delete
| @kpdelete
-> ()
2499 | _ when key != 0 && not
(Wsi.isspecialkey
key) ->
2500 begin match onkey
text key with
2504 G.postRedisplay "textentrykeyboard after confirm2";
2507 enttext (c, text, opthist
, onkey
, ondone, cancelonempty
);
2511 G.postRedisplay "textentrykeyboard after cancel3"
2514 state
.mode
<- Textentry
(te
, onleave
);
2515 G.postRedisplay "textentrykeyboard switch";
2519 vlog "unhandled key %s" (Wsi.keyname
key)
2522 let firstof first active
=
2523 if first
> active
|| abs
(first
- active
) > fstate
.maxrows
- 1
2524 then max
0 (active
- (fstate
.maxrows
/2))
2528 let calcfirst first active
=
2531 let rows = active
- first
in
2532 if rows > fstate
.maxrows
then active
- fstate
.maxrows
else first
2536 let scrollph y maxy
=
2537 let sh = float (maxy
+ state
.winh
) /. float state
.winh
in
2538 let sh = float state
.winh
/. sh in
2539 let sh = max
sh (float conf
.scrollh
) in
2541 let percent = float y /. float maxy
in
2542 let position = (float state
.winh
-. sh) *. percent in
2545 if position +. sh > float state
.winh
2546 then float state
.winh
-. sh
2552 let adderrmsg src msg
=
2553 Buffer.add_string state
.errmsgs msg
;
2554 state
.newerrmsgs
<- true;
2558 let adderrfmt src fmt
=
2559 Format.ksprintf
(fun s -> adderrmsg src
s) fmt
;
2562 let coe s = (s :> uioh
);;
2564 class listview ~zebra ~helpmode ~
(source
:lvsource
) ~trusted ~modehash
=
2566 val m_pan
= source#getpan
2567 val m_first
= source#getfirst
2568 val m_active
= source#getactive
2570 val m_prev_uioh
= state
.uioh
2572 method private elemunder
y =
2576 let n = y / (fstate
.fontsize
+1) in
2577 if m_first
+ n < source#getitemcount
2579 if source#hasaction
(m_first
+ n)
2580 then Some
(m_first
+ n)
2587 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
2588 GlDraw.color (0., 0., 0.) ~alpha
:0.85;
2589 filledrect 0. 0. (float state
.winw
) (float state
.winh
);
2590 GlDraw.color (1., 1., 1.);
2591 Gl.enable `texture_2d
;
2592 let fs = fstate
.fontsize
in
2594 let hw = state
.winw
/3 in
2595 let ww = fstate
.wwidth
in
2596 let tabw = 17.0*.ww in
2597 let itemcount = source#getitemcount
in
2598 let minfo = source#getminfo
in
2602 GlMat.translate ~
x:(float conf
.scrollbw
) ();
2604 let x0 = 0.0 and x1 = float (state
.winw
- conf
.scrollbw
- 1) in
2606 if (row - m_first
) > fstate
.maxrows
2609 if row >= 0 && row < itemcount
2611 let (s, level
) = source#getitem
row in
2612 let y = (row - m_first
) * nfs in
2613 let x = 5.0 +. (float (level
+ m_pan
)) *. ww in
2616 (let c = if row land 1 = 0 then 1.0 else 0.92 in (c,c,c));
2620 Gl.disable `texture_2d
;
2621 let alpha = if source#hasaction
row then 0.9 else 0.3 in
2622 GlDraw.color (1., 1., 1.) ~
alpha;
2623 linerect (x0 +. 1.) (float (y + 1)) (x1) (float (y + fs + 3));
2624 Gl.enable `texture_2d
;
2627 if zebra
&& row land 1 = 1
2631 GlDraw.color (c,c,c);
2632 let drawtabularstring s =
2634 let x'
= truncate
(x0 +. x) in
2635 let s1, s2
= splitatchar
s '
\000'
in
2637 then drawstring1 fs x'
(y+nfs) s
2643 let s'
= withoutlastutf8
s in
2644 let s = s' ^
"@Uellipsis" in
2645 let w = measurestr
fs s in
2646 if float x'
+. w +. ww < float (hw + x'
)
2651 if float x'
+. ww +. measurestr
fs s1 > float (hw + x'
)
2655 ignore
(drawstring1 fs x'
(y+nfs) s1);
2656 drawstring1 fs (hw + x'
) (y+nfs) s2
2660 let x = if helpmode
&& row > 0 then x +. ww else x in
2661 let s1, s2
= splitatchar
s '
\t'
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
2695 if row >= 0 && row < itemcount
2697 let (s, level
) = source#getitem
row in
2698 let pos0 = nindex
s '
\000'
in
2699 let y = (row - m_first
) * nfs in
2700 let x = float (level
+ m_pan
) *. ww in
2701 let (first
, last
) = minfo.(row) in
2703 if pos0 > 0 && first
> pos0
2704 then String.sub s (pos0+1) (first
-pos0-1)
2705 else String.sub s 0 first
2707 let suffix = String.sub s first
(last
- first
) in
2708 let w1 = measurestr fstate
.fontsize
prefix in
2709 let w2 = measurestr fstate
.fontsize
suffix in
2710 let x = x +. if conf
.leftscroll
then xadj else 5.0 in
2711 let x = if pos0 > 0 && first
> pos0 then x +. float hw else x in
2713 and y0 = float (y+2) in
2715 and y1 = float (y+fs+3) in
2716 filledrect x0 y0 x1 y1;
2720 Gl.disable `texture_2d
;
2721 if Array.length
minfo > 0 then loop m_first
;
2726 method updownlevel incr
=
2727 let len = source#getitemcount
in
2729 if m_active
>= 0 && m_active
< len
2730 then snd
(source#getitem m_active
)
2734 if i
= len then i
-1 else if i
= -1 then 0 else
2735 let _, l = source#getitem i
in
2736 if l != curlevel then i
else flow (i
+incr
)
2738 let active = flow m_active
in
2739 let first = calcfirst m_first
active in
2740 G.postRedisplay "outline updownlevel";
2741 {< m_active
= active; m_first
= first >}
2743 method private key1
key mask
=
2744 let set1 active first qsearch
=
2745 coe {< m_active
= active; m_first
= first; m_qsearch
= qsearch
>}
2747 let search active pattern incr
=
2748 let active = if active = -1 then m_first
else active in
2751 if n >= 0 && n < source#getitemcount
2753 let s, _ = source#getitem
n in
2754 match Str.search_forward re
s 0 with
2755 | (exception Not_found
) -> loop (n + incr
)
2762 let qpat = Str.quote pattern
in
2763 match Str.regexp_case_fold
qpat with
2766 adderrfmt "listview key1" "regexp_case_fold for `%S' failed: %S\n"
2767 qpat @@ Printexc.to_string exn
;
2770 let itemcount = source#getitemcount
in
2771 let find start incr
=
2773 if i
= -1 || i
= itemcount
2776 if source#hasaction i
2778 else find (i
+ incr
)
2783 let set active first =
2784 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2786 coe {< m_active
= active; m_first
= first; m_qsearch
= E.s >}
2789 let isvisible first n = n >= first && n - first <= fstate
.maxrows
in
2791 let incr1 = if incr
> 0 then 1 else -1 in
2792 if isvisible m_first m_active
2795 let next = m_active
+ incr
in
2797 if next < 0 || next >= itemcount
2799 else find next incr1
2801 if abs
(m_active
- next) > fstate
.maxrows
2807 let first = m_first
+ incr
in
2808 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2810 let next = m_active
+ incr
in
2811 let next = bound
next 0 (itemcount - 1) in
2818 if isvisible first next
2825 let first = min
next m_first
in
2827 if abs
(next - first) > fstate
.maxrows
2833 let first = m_first
+ incr
in
2834 let first = bound
first 0 (itemcount - 1) in
2836 let next = m_active
+ incr
in
2837 let next = bound
next 0 (itemcount - 1) in
2838 let next = find next incr1 in
2840 if next = -1 || abs
(m_active
- first) > fstate
.maxrows
2842 let active = if m_active
= -1 then next else m_active
in
2847 if isvisible first active
2853 G.postRedisplay "listview navigate";
2857 | (@r
|@s) when Wsi.withctrl mask
->
2858 let incr = if key = @r
then -1 else 1 in
2860 match search (m_active
+ incr) m_qsearch
incr with
2862 state
.text <- m_qsearch ^
" [not found]";
2865 state
.text <- m_qsearch
;
2866 active, firstof m_first
active
2868 G.postRedisplay "listview ctrl-r/s";
2869 set1 active first m_qsearch
;
2871 | @insert
when Wsi.withctrl mask
->
2872 if m_active
>= 0 && m_active
< source#getitemcount
2874 let s, _ = source#getitem m_active
in
2880 if emptystr m_qsearch
2883 let qsearch = withoutlastutf8 m_qsearch
in
2887 G.postRedisplay "listview empty qsearch";
2888 set1 m_active m_first
E.s;
2892 match search m_active
qsearch ~
-1 with
2894 state
.text <- qsearch ^
" [not found]";
2897 state
.text <- qsearch;
2898 active, firstof m_first
active
2900 G.postRedisplay "listview backspace qsearch";
2901 set1 active first qsearch
2904 | key when (key != 0 && not
(Wsi.isspecialkey
key)) ->
2905 let pattern = m_qsearch ^ toutf8
key in
2907 match search m_active
pattern 1 with
2909 state
.text <- pattern ^
" [not found]";
2912 state
.text <- pattern;
2913 active, firstof m_first
active
2915 G.postRedisplay "listview qsearch add";
2916 set1 active first pattern;
2920 if emptystr m_qsearch
2922 G.postRedisplay "list view escape";
2923 let mx, my
= state
.mpos
in
2927 source#exit ~uioh
:(coe self
)
2928 ~cancel
:true ~
active:m_active ~
first:m_first ~pan
:m_pan
2930 | None
-> m_prev_uioh
2935 G.postRedisplay "list view kill qsearch";
2936 coe {< m_qsearch
= E.s >}
2939 | @enter
| @kpenter
->
2941 let self = {< m_qsearch
= E.s >} in
2943 G.postRedisplay "listview enter";
2944 if m_active
>= 0 && m_active
< source#getitemcount
2946 source#exit ~uioh
:(coe self) ~cancel
:false
2947 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2950 source#exit ~uioh
:(coe self) ~cancel
:true
2951 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2954 begin match opt with
2955 | None
-> m_prev_uioh
2959 | @delete
| @kpdelete
->
2962 | @up
| @kpup
-> navigate ~
-1
2963 | @down
| @kpdown
-> navigate 1
2964 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows
)
2965 | @next | @kpnext
-> navigate fstate
.maxrows
2967 | @right
| @kpright
->
2969 G.postRedisplay "listview right";
2970 coe {< m_pan
= m_pan
- 1 >}
2972 | @left | @kpleft
->
2974 G.postRedisplay "listview left";
2975 coe {< m_pan
= m_pan
+ 1 >}
2977 | @home
| @kphome
->
2978 let active = find 0 1 in
2979 G.postRedisplay "listview home";
2983 let first = max
0 (itemcount - fstate
.maxrows
) in
2984 let active = find (itemcount - 1) ~
-1 in
2985 G.postRedisplay "listview end";
2988 | key when (key = 0 || Wsi.isspecialkey
key) ->
2992 dolog
"listview unknown key %#x" key; coe self
2994 method key key mask
=
2995 match state
.mode
with
2996 | Textentry te
-> textentrykeyboard key mask te
; coe self
2999 | LinkNav
_ -> self#key1
key mask
3001 method button button down
x y _ =
3004 | 1 when vscrollhit x ->
3005 G.postRedisplay "listview scroll";
3008 let _, position, sh = self#
scrollph in
3009 if y > truncate
position && y < truncate
(position +. sh)
3011 state
.mstate
<- Mscrolly
;
3015 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3016 let first = truncate
(s *. float source#getitemcount
) in
3017 let first = min source#getitemcount
first in
3018 Some
(coe {< m_first
= first; m_active
= first >})
3020 state
.mstate
<- Mnone
;
3024 begin match self#elemunder
y with
3026 G.postRedisplay "listview click";
3027 source#exit ~uioh
:(coe {< m_active
= n >})
3028 ~cancel
:false ~
active:n ~
first:m_first ~pan
:m_pan
3032 | n when (n == 4 || n == 5) && not down
->
3033 let len = source#getitemcount
in
3035 if n = 5 && m_first
+ fstate
.maxrows
>= len
3039 let first = m_first
+ (if n == 4 then -1 else 1) in
3040 bound
first 0 (len - 1)
3042 G.postRedisplay "listview wheel";
3043 Some
(coe {< m_first
= first >})
3044 | n when (n = 6 || n = 7) && not down
->
3045 let inc = if n = 7 then -1 else 1 in
3046 G.postRedisplay "listview hwheel";
3047 Some
(coe {< m_pan
= m_pan
+ inc >})
3052 | None
-> m_prev_uioh
3055 method multiclick
_ x y = self#button
1 true x y
3058 match state
.mstate
with
3060 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3061 let first = truncate
(s *. float source#getitemcount
) in
3062 let first = min source#getitemcount
first in
3063 G.postRedisplay "listview motion";
3064 coe {< m_first
= first; m_active
= first >}
3072 method pmotion
x y =
3073 if x < state
.winw
- conf
.scrollbw
3076 match self#elemunder
y with
3077 | None
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
; m_active
3078 | Some
n -> Wsi.setcursor
Wsi.CURSOR_INFO
; n
3082 then (G.postRedisplay "listview pmotion"; {< m_active
= n >})
3087 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
3091 method infochanged
_ = ()
3093 method scrollpw
= (0, 0.0, 0.0)
3095 let nfs = fstate
.fontsize
+ 1 in
3096 let y = m_first
* nfs in
3097 let itemcount = source#getitemcount
in
3098 let maxi = max
0 (itemcount - fstate
.maxrows
) in
3099 let maxy = maxi * nfs in
3100 let p, h = scrollph y maxy in
3103 method modehash
= modehash
3104 method eformsgs
= false
3105 method alwaysscrolly
= true
3108 class outlinelistview ~zebra ~source
=
3109 let settext autonarrow
s =
3112 let ss = source#statestr
in
3116 else "{" ^
ss ^
"} [" ^
s ^
"]"
3117 else state
.text <- s
3123 ~source
:(source
:> lvsource
)
3125 ~modehash
:(findkeyhash conf
"outline")
3128 val m_autonarrow
= false
3130 method! key key mask
=
3132 if emptystr state
.text
3134 else fstate
.maxrows - 2
3136 let calcfirst first active =
3139 let rows = active - first in
3140 if rows > maxrows then active - maxrows else first
3144 let active = m_active
+ incr in
3145 let active = bound
active 0 (source#getitemcount
- 1) in
3146 let first = calcfirst m_first
active in
3147 G.postRedisplay "outline navigate";
3148 coe {< m_active
= active; m_first
= first >}
3150 let navscroll first =
3152 let dist = m_active
- first in
3158 else first + maxrows
3161 G.postRedisplay "outline navscroll";
3162 coe {< m_first
= first; m_active
= active >}
3164 let ctrl = Wsi.withctrl mask
in
3169 then (source#denarrow
; E.s)
3171 let pattern = source#renarrow
in
3172 if nonemptystr m_qsearch
3173 then (source#narrow m_qsearch
; m_qsearch
)
3177 settext (not m_autonarrow
) text;
3178 G.postRedisplay "toggle auto narrowing";
3179 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= not m_autonarrow
>}
3181 | @slash
when emptystr m_qsearch
&& not m_autonarrow
->
3183 G.postRedisplay "toggle auto narrowing";
3184 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= true >}
3187 source#narrow m_qsearch
;
3189 then source#add_narrow_pattern m_qsearch
;
3190 G.postRedisplay "outline ctrl-n";
3191 coe {< m_first
= 0; m_active
= 0 >}
3194 let active = source#calcactive
(getanchor
()) in
3195 let first = firstof m_first
active in
3196 G.postRedisplay "outline ctrl-s";
3197 coe {< m_first
= first; m_active
= active >}
3200 G.postRedisplay "outline ctrl-u";
3201 if m_autonarrow
&& nonemptystr m_qsearch
3203 ignore
(source#renarrow
);
3204 settext m_autonarrow
E.s;
3205 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3208 source#del_narrow_pattern
;
3209 let pattern = source#renarrow
in
3211 if emptystr
pattern then E.s else "Narrowed to " ^
pattern
3213 settext m_autonarrow
text;
3214 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3218 let first = max
0 (m_active
- (fstate
.maxrows / 2)) in
3219 G.postRedisplay "outline ctrl-l";
3220 coe {< m_first
= first >}
3222 | @tab
when m_autonarrow
->
3223 if nonemptystr m_qsearch
3225 G.postRedisplay "outline list view tab";
3226 source#add_narrow_pattern m_qsearch
;
3228 coe {< m_qsearch
= E.s >}
3232 | @escape
when m_autonarrow
->
3233 if nonemptystr m_qsearch
3234 then source#add_narrow_pattern m_qsearch
;
3237 | @enter
| @kpenter
when m_autonarrow
->
3238 if nonemptystr m_qsearch
3239 then source#add_narrow_pattern m_qsearch
;
3242 | key when m_autonarrow
&& (not
(Wsi.isspecialkey
key)) ->
3243 let pattern = m_qsearch ^ toutf8
key in
3244 G.postRedisplay "outlinelistview autonarrow add";
3245 source#narrow
pattern;
3246 settext true pattern;
3247 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3249 | key when m_autonarrow
&& key = @backspace
->
3250 if emptystr m_qsearch
3253 let pattern = withoutlastutf8 m_qsearch
in
3254 G.postRedisplay "outlinelistview autonarrow backspace";
3255 ignore
(source#renarrow
);
3256 source#narrow
pattern;
3257 settext true pattern;
3258 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3260 | @up
| @kpup
when ctrl ->
3261 navscroll (max
0 (m_first
- 1))
3263 | @down
| @kpdown
when ctrl ->
3264 navscroll (min
(source#getitemcount
- 1) (m_first
+ 1))
3266 | @up
| @kpup
-> navigate ~
-1
3267 | @down
| @kpdown
-> navigate 1
3268 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows)
3269 | @next | @kpnext
-> navigate fstate
.maxrows
3271 | @right
| @kpright
->
3275 G.postRedisplay "outline ctrl right";
3276 {< m_pan
= m_pan
+ 1 >}
3278 else self#updownlevel
1
3282 | @left | @kpleft
->
3286 G.postRedisplay "outline ctrl left";
3287 {< m_pan
= m_pan
- 1 >}
3289 else self#updownlevel ~
-1
3293 | @home
| @kphome
->
3294 G.postRedisplay "outline home";
3295 coe {< m_first
= 0; m_active
= 0 >}
3298 let active = source#getitemcount
- 1 in
3299 let first = max
0 (active - fstate
.maxrows) in
3300 G.postRedisplay "outline end";
3301 coe {< m_active
= active; m_first
= first >}
3303 | _ -> super#
key key mask
3306 let genhistoutlines () =
3308 |> List.sort
(fun (_, c1
, _, _, _, _) (_, c2
, _, _, _, _) ->
3309 compare c2
.lastvisit c1
.lastvisit
)
3311 (fun ((path
, c, _, _, _, origin
) as hist
) ->
3312 let path = if nonemptystr origin
then origin
else path in
3313 let base = mbtoutf8
@@ Filename.basename
path in
3314 (base ^
"\000" ^
c.title
, 1, Ohistory hist
)
3319 let gotohist (path, c, bookmarks
, x, anchor, origin
) =
3320 Config.save
leavebirdseye;
3321 state
.anchor <- anchor;
3322 state
.bookmarks
<- bookmarks
;
3323 state
.origin
<- origin
;
3326 let x0, y0, x1, y1 = conf
.trimfuzz
in
3327 wcmd "trimset %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1;
3328 reshape ~firsttime
:true state
.winw state
.winh
;
3329 opendoc path origin
;
3333 let makecheckers () =
3334 (* Based on lablGL-1.04/LablGlut/examples/lablGL/checker.ml which had
3336 converted by Issac Trotts. July 25, 2002 *)
3337 let image = GlPix.create `ubyte ~format
:`luminance ~width
:2 ~height
:2 in
3338 Raw.sets_string
(GlPix.to_raw
image) ~pos
:0 "\255\200\200\255";
3339 let id = GlTex.gen_texture
() in
3340 GlTex.bind_texture ~target
:`texture_2d
id;
3341 GlPix.store
(`unpack_alignment
1);
3342 GlTex.image2d
image;
3343 List.iter
(GlTex.parameter ~target
:`texture_2d
)
3344 [ `mag_filter `nearest
; `min_filter `nearest
];
3348 let setcheckers enabled
=
3349 match state
.checkerstexid
with
3351 if enabled
then state
.checkerstexid
<- Some
(makecheckers ())
3353 | Some checkerstexid
->
3356 GlTex.delete_texture checkerstexid
;
3357 state
.checkerstexid
<- None
;
3361 let describe_location () =
3362 let fn = page_of_y state
.y in
3363 let ln = page_of_y
(state
.y + state
.winh
- 1) in
3364 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
3368 else (100. *. (float state
.y /. float maxy))
3372 Printf.sprintf
"page %d of %d [%.2f%%]"
3373 (fn+1) state
.pagecount
percent
3376 "pages %d-%d of %d [%.2f%%]"
3377 (fn+1) (ln+1) state
.pagecount
percent
3380 let setpresentationmode v
=
3381 let n = page_of_y state
.y in
3382 state
.anchor <- (n, 0.0, 1.0);
3383 conf
.presentation
<- v
;
3384 if conf
.fitmodel
= FitPage
3385 then reqlayout conf
.angle conf
.fitmodel
;
3389 let setbgcol (r
, g, b) =
3391 let r = r *. 255.0 |> truncate
3392 and g = g *. 255.0 |> truncate
3393 and b = b *. 255.0 |> truncate
in
3394 r lsl 16 |> (lor) (g lsl 8) |> (lor) b
3396 Wsi.setwinbgcol
col;
3400 let btos b = if b then "@Uradical" else E.s in
3401 let showextended = ref false in
3402 let leave mode
_ = state
.mode
<- mode
in
3405 val mutable m_l
= []
3406 val mutable m_a
= E.a
3407 val mutable m_prev_uioh
= nouioh
3408 val mutable m_prev_mode
= View
3410 inherit lvsourcebase
3412 method reset prev_mode prev_uioh
=
3413 m_a
<- Array.of_list
(List.rev m_l
);
3415 m_prev_mode
<- prev_mode
;
3416 m_prev_uioh
<- prev_uioh
;
3418 method int name get
set =
3424 try set (int_of_string
s)
3426 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3430 let te = name ^
": ", E.s, None
, intentry, ondone, true in
3431 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3435 method int_with_suffix name get
set =
3437 (name
, `intws get
, 1,
3441 try set (int_of_string_with_suffix
s)
3443 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3448 name ^
": ", E.s, None
, intentry_with_suffix, ondone, true
3450 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3454 method bool ?
(offset
=1) ?
(btos=btos) name get
set =
3456 (name
, `
bool (btos, get
), offset
, Action
(
3463 method color name get
set =
3465 (name
, `
color get
, 1,
3468 let invalid = (nan
, nan
, nan
) in
3471 try color_of_string
s
3473 state
.text <- Printf.sprintf
"bad color `%s': %s"
3480 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3481 state
.text <- color_to_string
(get
());
3482 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3486 method string name get
set =
3488 (name
, `
string get
, 1,
3491 let ondone s = set s in
3492 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3493 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3497 method colorspace name get
set =
3499 (name
, `
string get
, 1,
3504 inherit lvsourcebase
3507 m_active
<- CSTE.to_int conf
.colorspace
;
3510 method getitemcount
=
3511 Array.length
CSTE.names
3514 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3515 ignore
(uioh
, first, pan
);
3516 if not cancel
then set active;
3518 method hasaction
_ = true
3522 let modehash = findkeyhash conf
"info" in
3523 coe (new listview ~zebra
:false ~helpmode
:false
3524 ~
source ~trusted
:true ~
modehash)
3527 method paxmark name get
set =
3529 (name
, `
string get
, 1,
3534 inherit lvsourcebase
3537 m_active
<- MTE.to_int conf
.paxmark
;
3540 method getitemcount
= Array.length
MTE.names
3541 method getitem
n = (MTE.names
.(n), 0)
3542 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3543 ignore
(uioh
, first, pan
);
3544 if not cancel
then set active;
3546 method hasaction
_ = true
3550 let modehash = findkeyhash conf
"info" in
3551 coe (new listview ~zebra
:false ~helpmode
:false
3552 ~
source ~trusted
:true ~
modehash)
3555 method fitmodel name get
set =
3557 (name
, `
string get
, 1,
3562 inherit lvsourcebase
3565 m_active
<- FMTE.to_int conf
.fitmodel
;
3568 method getitemcount
= Array.length
FMTE.names
3569 method getitem
n = (FMTE.names
.(n), 0)
3570 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3571 ignore
(uioh
, first, pan
);
3572 if not cancel
then set active;
3574 method hasaction
_ = true
3578 let modehash = findkeyhash conf
"info" in
3579 coe (new listview ~zebra
:false ~helpmode
:false
3580 ~
source ~trusted
:true ~
modehash)
3583 method caption
s offset
=
3584 m_l
<- (s, `empty
, offset
, Noaction
) :: m_l
3586 method caption2
s f offset
=
3587 m_l
<- (s, `
string f, offset
, Noaction
) :: m_l
3589 method getitemcount
= Array.length m_a
3592 let tostr = function
3593 | `
int f -> string_of_int
(f ())
3594 | `intws
f -> string_with_suffix_of_int
(f ())
3596 | `
color f -> color_to_string
(f ())
3597 | `
bool (btos, f) -> btos (f ())
3600 let name, t
, offset
, _ = m_a
.(n) in
3601 ((let s = tostr t
in
3603 then Printf.sprintf
"%s\t%s" name s
3607 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3612 match m_a
.(active) with
3613 | _, _, _, Action
f -> f uioh
3614 | _, _, _, Noaction
-> uioh
3625 method hasaction
n =
3627 | _, _, _, Action
_ -> true
3628 | _, _, _, Noaction
-> false
3630 initializer m_active
<- 1
3633 let rec fillsrc prevmode prevuioh
=
3634 let sep () = src#caption
E.s 0 in
3635 let colorp name get
set =
3637 (fun () -> color_to_string
(get
()))
3640 let c = color_of_string
v in
3644 Printf.sprintf
"bad color `%s': %s" v @@ exntos exn
3647 let oldmode = state
.mode
in
3648 let birdseye = isbirdseye state
.mode
in
3650 src#caption
(if birdseye then "Setup (Bird's eye)" else "Setup") 0;
3652 src#
bool "presentation mode"
3653 (fun () -> conf
.presentation
)
3654 (fun v -> setpresentationmode v);
3656 src#
bool "ignore case in searches"
3657 (fun () -> conf
.icase
)
3658 (fun v -> conf
.icase
<- v);
3661 (fun () -> conf
.preload)
3662 (fun v -> conf
.preload <- v);
3664 src#
bool "highlight links"
3665 (fun () -> conf
.hlinks
)
3666 (fun v -> conf
.hlinks
<- v);
3668 src#
bool "under info"
3669 (fun () -> conf
.underinfo
)
3670 (fun v -> conf
.underinfo
<- v);
3672 src#
bool "persistent bookmarks"
3673 (fun () -> conf
.savebmarks
)
3674 (fun v -> conf
.savebmarks
<- v);
3676 src#fitmodel
"fit model"
3677 (fun () -> FMTE.to_string conf
.fitmodel
)
3678 (fun v -> reqlayout conf
.angle
(FMTE.of_int
v));
3680 src#
bool "trim margins"
3681 (fun () -> conf
.trimmargins
)
3682 (fun v -> settrim v conf
.trimfuzz
; fillsrc prevmode prevuioh
);
3684 src#
bool "persistent location"
3685 (fun () -> conf
.jumpback
)
3686 (fun v -> conf
.jumpback
<- v);
3689 src#
int "inter-page space"
3690 (fun () -> conf
.interpagespace
)
3692 conf
.interpagespace
<- n;
3693 docolumns conf
.columns
;
3695 match state
.layout with
3700 state
.maxy <- calcheight
();
3701 let y = getpagey
pageno in
3702 gotoxy state
.x (y + py)
3706 (fun () -> conf
.pagebias
)
3707 (fun v -> conf
.pagebias
<- v);
3709 src#
int "scroll step"
3710 (fun () -> conf
.scrollstep
)
3711 (fun n -> conf
.scrollstep
<- n);
3713 src#
int "horizontal scroll step"
3714 (fun () -> conf
.hscrollstep
)
3715 (fun v -> conf
.hscrollstep
<- v);
3717 src#
int "auto scroll step"
3719 match state
.autoscroll
with
3721 | _ -> conf
.autoscrollstep
)
3723 let n = boundastep state
.winh
n in
3724 if state
.autoscroll
<> None
3725 then state
.autoscroll
<- Some
n;
3726 conf
.autoscrollstep
<- n);
3729 (fun () -> truncate
(conf
.zoom *. 100.))
3730 (fun v -> pivotzoom ((float v) /. 100.));
3733 (fun () -> conf
.angle
)
3734 (fun v -> reqlayout v conf
.fitmodel
);
3736 src#
int "scroll bar width"
3737 (fun () -> conf
.scrollbw
)
3740 reshape state
.winw state
.winh
;
3743 src#
int "scroll handle height"
3744 (fun () -> conf
.scrollh
)
3745 (fun v -> conf
.scrollh
<- v;);
3747 src#
int "thumbnail width"
3748 (fun () -> conf
.thumbw
)
3750 conf
.thumbw
<- min
4096 v;
3753 leavebirdseye beye
false;
3760 let mode = state
.mode in
3761 src#
string "columns"
3763 match conf
.columns
with
3765 | Cmulti
(multi
, _) -> multicolumns_to_string multi
3766 | Csplit
(count
, _) -> "-" ^ string_of_int count
3769 let n, a, b = multicolumns_of_string
v in
3770 setcolumns mode n a b);
3773 src#caption
"Pixmap cache" 0;
3774 src#int_with_suffix
"size (advisory)"
3775 (fun () -> conf
.memlimit
)
3776 (fun v -> conf
.memlimit
<- v);
3780 Printf.sprintf
"%s bytes, %d tiles"
3781 (string_with_suffix_of_int state
.memused
)
3782 (Hashtbl.length state
.tilemap
)) 1;
3785 src#caption
"Layout" 0;
3786 src#caption2
"Dimension"
3788 Printf.sprintf
"%dx%d (virtual %dx%d)"
3789 state
.winw state
.winh
3794 src#caption2
"Position" (fun () ->
3795 Printf.sprintf
"%dx%d" state
.x state
.y
3798 src#caption2
"Position" (fun () -> describe_location ()) 1
3802 src#
bool ~offset
:0 ~
btos:(fun v -> if v then "(on)" else "(off)")
3803 "Save these parameters as global defaults at exit"
3804 (fun () -> conf
.bedefault
)
3805 (fun v -> conf
.bedefault
<- v)
3809 let btos b = if b then "@Ulguillemet" else "@Urguillemet" in
3810 src#
bool ~offset
:0 ~
btos "Extended parameters"
3811 (fun () -> !showextended)
3812 (fun v -> showextended := v; fillsrc prevmode prevuioh
);
3816 (fun () -> conf
.checkers
)
3817 (fun v -> conf
.checkers
<- v; setcheckers v);
3818 src#
bool "update cursor"
3819 (fun () -> conf
.updatecurs
)
3820 (fun v -> conf
.updatecurs
<- v);
3821 src#
bool "scroll-bar on the left"
3822 (fun () -> conf
.leftscroll
)
3823 (fun v -> conf
.leftscroll
<- v);
3825 (fun () -> conf
.verbose
)
3826 (fun v -> conf
.verbose
<- v);
3827 src#
bool "invert colors"
3828 (fun () -> conf
.invert
)
3829 (fun v -> conf
.invert
<- v);
3831 (fun () -> conf
.maxhfit
)
3832 (fun v -> conf
.maxhfit
<- v);
3834 (fun () -> conf
.pax
!= None
)
3837 then conf
.pax
<- Some
(ref (now
(), 0, 0))
3838 else conf
.pax
<- None
);
3839 src#
string "uri launcher"
3840 (fun () -> conf
.urilauncher
)
3841 (fun v -> conf
.urilauncher
<- v);
3842 src#
string "path launcher"
3843 (fun () -> conf
.pathlauncher
)
3844 (fun v -> conf
.pathlauncher
<- v);
3845 src#
string "tile size"
3846 (fun () -> Printf.sprintf
"%dx%d" conf
.tilew conf
.tileh
)
3849 let w, h = Scanf.sscanf
v "%dx%d" (fun w h -> w, h) in
3850 conf
.tilew
<- max
64 w;
3851 conf
.tileh
<- max
64 h;
3854 state
.text <- Printf.sprintf
"bad tile size `%s': %s"
3857 src#
int "texture count"
3858 (fun () -> conf
.texcount
)
3861 then conf
.texcount
<- v
3862 else impmsg "failed to set texture count please retry later"
3864 src#
int "slice height"
3865 (fun () -> conf
.sliceheight
)
3867 conf
.sliceheight
<- v;
3868 wcmd "sliceh %d" conf
.sliceheight
;
3870 src#
int "anti-aliasing level"
3871 (fun () -> conf
.aalevel
)
3873 conf
.aalevel
<- bound
v 0 8;
3874 state
.anchor <- getanchor
();
3875 opendoc state
.path state
.password;
3877 src#
string "page scroll scaling factor"
3878 (fun () -> string_of_float conf
.pgscale)
3881 let s = float_of_string
v in
3884 state
.text <- Printf.sprintf
3885 "bad page scroll scaling factor `%s': %s" v
3889 src#
int "ui font size"
3890 (fun () -> fstate
.fontsize
)
3891 (fun v -> setfontsize (bound
v 5 100));
3892 src#
int "hint font size"
3893 (fun () -> conf
.hfsize
)
3894 (fun v -> conf
.hfsize
<- bound
v 5 100);
3895 colorp "background color"
3896 (fun () -> conf
.bgcolor
)
3897 (fun v -> conf
.bgcolor
<- v; setbgcol v);
3898 src#
bool "crop hack"
3899 (fun () -> conf
.crophack
)
3900 (fun v -> conf
.crophack
<- v);
3901 src#
string "trim fuzz"
3902 (fun () -> irect_to_string conf
.trimfuzz
)
3905 conf
.trimfuzz
<- irect_of_string
v;
3907 then settrim true conf
.trimfuzz
;
3909 state
.text <- Printf.sprintf
"bad irect `%s': %s" v
3912 src#
string "throttle"
3914 match conf
.maxwait
with
3915 | None
-> "show place holder if page is not ready"
3918 then "wait for page to fully render"
3920 "wait " ^ string_of_float
time
3921 ^
" seconds before showing placeholder"
3925 let f = float_of_string
v in
3927 then conf
.maxwait
<- None
3928 else conf
.maxwait
<- Some
f
3930 state
.text <- Printf.sprintf
"bad time `%s': %s" v
3933 src#
string "ghyll scroll"
3935 match conf
.ghyllscroll
with
3937 | Some nab
-> ghyllscroll_to_string nab
3940 try conf
.ghyllscroll
<- ghyllscroll_of_string
v
3943 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v msg
3945 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v
3948 src#
string "selection command"
3949 (fun () -> conf
.selcmd
)
3950 (fun v -> conf
.selcmd
<- v);
3951 src#
string "synctex command"
3952 (fun () -> conf
.stcmd
)
3953 (fun v -> conf
.stcmd
<- v);
3954 src#
string "pax command"
3955 (fun () -> conf
.paxcmd
)
3956 (fun v -> conf
.paxcmd
<- v);
3957 src#
string "ask password command"
3958 (fun () -> conf
.passcmd)
3959 (fun v -> conf
.passcmd <- v);
3960 src#
string "save path command"
3961 (fun () -> conf
.savecmd
)
3962 (fun v -> conf
.savecmd
<- v);
3963 src#colorspace
"color space"
3964 (fun () -> CSTE.to_string conf
.colorspace
)
3966 conf
.colorspace
<- CSTE.of_int
v;
3970 src#paxmark
"pax mark method"
3971 (fun () -> MTE.to_string conf
.paxmark
)
3972 (fun v -> conf
.paxmark
<- MTE.of_int
v);
3973 if bousable
() && !opengl_has_pbo
3976 (fun () -> conf
.usepbo
)
3977 (fun v -> conf
.usepbo
<- v);
3978 src#
bool "mouse wheel scrolls pages"
3979 (fun () -> conf
.wheelbypage
)
3980 (fun v -> conf
.wheelbypage
<- v);
3981 src#
bool "open remote links in a new instance"
3982 (fun () -> conf
.riani
)
3983 (fun v -> conf
.riani
<- v);
3984 src#
bool "edit annotations inline"
3985 (fun () -> conf
.annotinline
)
3986 (fun v -> conf
.annotinline
<- v);
3987 src#
bool "coarse positioning in presentation mode"
3988 (fun () -> conf
.coarseprespos
)
3989 (fun v -> conf
.coarseprespos
<- v);
3990 src#
bool "use document CSS"
3991 (fun () -> conf
.usedoccss
)
3993 conf
.usedoccss
<- v;
3994 state
.anchor <- getanchor
();
3995 opendoc state
.path state
.password;
4000 src#caption
"Document" 0;
4001 List.iter
(fun (_, s) -> src#caption
s 1) state
.docinfo
;
4002 src#caption2
"Pages"
4003 (fun () -> string_of_int state
.pagecount
) 1;
4004 src#caption2
"Dimensions"
4005 (fun () -> string_of_int
(List.length state
.pdims
)) 1;
4006 if nonemptystr conf
.css
4007 then src#caption2
"CSS" (fun () -> conf
.css
) 1;
4011 src#caption
"Trimmed margins" 0;
4012 src#caption2
"Dimensions"
4013 (fun () -> string_of_int
(List.length state
.pdims
)) 1;
4017 src#caption
"OpenGL" 0;
4018 src#caption
(Printf.sprintf
"Vendor\t%s" (GlMisc.get_string `vendor
)) 1;
4019 src#caption
(Printf.sprintf
"Renderer\t%s" (GlMisc.get_string `renderer
)) 1;
4022 src#caption
"Location" 0;
4023 if nonemptystr state
.origin
4024 then src#caption
("Orign\t" ^ mbtoutf8 state
.origin
) 1;
4025 src#caption
("Path\t" ^ mbtoutf8 state
.path) 1;
4027 src#reset prevmode prevuioh
;
4032 let prevmode = state
.mode
4033 and prevuioh
= state
.uioh in
4034 fillsrc prevmode prevuioh
;
4035 let source = (src :> lvsource
) in
4036 let modehash = findkeyhash conf
"info" in
4039 inherit listview ~zebra
:false ~helpmode
:false
4040 ~
source ~trusted
:true ~
modehash as super
4041 val mutable m_prevmemused
= 0
4042 method! infochanged
= function
4044 if m_prevmemused
!= state
.memused
4046 m_prevmemused
<- state
.memused
;
4047 G.postRedisplay "memusedchanged";
4049 | Pdim
-> G.postRedisplay "pdimchanged"
4050 | Docinfo
-> fillsrc prevmode prevuioh
4052 method! key key mask
=
4053 if not
(Wsi.withctrl mask
)
4056 | @left | @kpleft
-> coe (self#updownlevel ~
-1)
4057 | @right
| @kpright
-> coe (self#updownlevel
1)
4058 | _ -> super#
key key mask
4059 else super#
key key mask
4061 G.postRedisplay "info";
4067 inherit lvsourcebase
4068 method getitemcount
= Array.length state
.help
4070 let s, l, _ = state
.help
.(n) in
4073 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4077 match state
.help
.(active) with
4078 | _, _, Action
f -> Some
(f uioh)
4079 | _, _, Noaction
-> Some
uioh
4088 method hasaction
n =
4089 match state
.help
.(n) with
4090 | _, _, Action
_ -> true
4091 | _, _, Noaction
-> false
4097 let modehash = findkeyhash conf
"help" in
4099 state
.uioh <- coe (new listview
4100 ~zebra
:false ~helpmode
:true
4101 ~
source ~trusted
:true ~
modehash);
4102 G.postRedisplay "help";
4108 inherit lvsourcebase
4109 val mutable m_items
= E.a
4111 method getitemcount
= 1 + Array.length m_items
4116 else m_items
.(n-1), 0
4118 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4123 then Buffer.clear state
.errmsgs
;
4130 method hasaction
n =
4134 state
.newerrmsgs
<- false;
4135 let l = Str.split newlinere
(Buffer.contents state
.errmsgs
) in
4136 m_items
<- Array.of_list
l
4145 let source = (msgsource :> lvsource
) in
4146 let modehash = findkeyhash conf
"listview" in
4149 inherit listview ~zebra
:false ~helpmode
:false
4150 ~
source ~trusted
:false ~
modehash as super
4153 then msgsource#reset
;
4156 G.postRedisplay "msgs";
4160 let editor = getenvwithdef
"EDITOR" E.s in
4164 let tmppath = Filename.temp_file
"llpp" "note" in
4167 let oc = open_out
tmppath in
4171 let execstr = editor ^
" " ^
tmppath in
4173 match spawn
execstr [] with
4174 | (exception exn
) ->
4175 impmsg "spawn(%S) failed: %s" execstr @@ exntos exn
;
4178 match Unix.waitpid
[] pid with
4179 | (exception exn
) ->
4180 impmsg "waitpid(%d) failed: %s" pid @@ exntos exn
;
4184 | Unix.WEXITED
0 -> filecontents
tmppath
4186 impmsg "editor process(%s) exited abnormally: %d" execstr n;
4188 | Unix.WSIGNALED
n ->
4189 impmsg "editor process(%s) was killed by signal %d" execstr n;
4191 | Unix.WSTOPPED
n ->
4192 impmsg "editor(%s) process was stopped by signal %d" execstr n;
4195 match Unix.unlink
tmppath with
4196 | (exception exn
) ->
4197 impmsg "failed to ulink %S: %s" tmppath @@ exntos exn
;
4202 let enterannotmode opaque slinkindex
=
4205 inherit lvsourcebase
4206 val mutable m_text
= E.s
4207 val mutable m_items
= E.a
4209 method getitemcount
= Array.length m_items
4212 let label, _func
= m_items
.(n) in
4215 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4216 ignore
(uioh, first, pan
);
4219 let _label, func
= m_items
.(active) in
4224 method hasaction
n = nonemptystr
@@ fst m_items
.(n)
4227 let rec split accu b i
=
4229 if p = String.length
s
4230 then (String.sub s b (p-b), unit) :: accu
4232 if (i
> 70 && s.[p] = ' '
) || s.[p] = '
\r'
|| s.[p] = '
\n'
4234 let ss = if i
= 0 then E.s else String.sub s b i
in
4235 split ((ss, unit)::accu) (p+1) 0
4240 wcmd "freepage %s" (~
> opaque);
4242 Hashtbl.fold (fun key opaque'
accu ->
4243 if opaque'
= opaque'
4244 then key :: accu else accu) state
.pagemap
[]
4246 List.iter
(Hashtbl.remove state
.pagemap
) keys;
4248 gotoxy state
.x state
.y
4251 delannot
opaque slinkindex
;
4254 let edit inline
() =
4259 modannot
opaque slinkindex
s;
4265 let mode = state
.mode in
4268 ("annotation: ", m_text
, None
, textentry, update, true),
4269 fun _ -> state
.mode <- mode);
4273 let s = getusertext m_text
in
4278 ( "[Copy]", fun () -> selstring m_text
)
4279 :: ("[Delete]", dele)
4280 :: ("[Edit]", edit conf
.annotinline
)
4282 :: split [] 0 0 |> List.rev
|> Array.of_list
4289 let s = getannotcontents
opaque slinkindex
in
4292 let source = (msgsource :> lvsource
) in
4293 let modehash = findkeyhash conf
"listview" in
4294 state
.uioh <- coe (object
4295 inherit listview ~zebra
:false ~helpmode
:false
4296 ~
source ~trusted
:false ~
modehash
4298 G.postRedisplay "enterannotmode";
4301 let gotoremote spec
=
4302 let filename, dest
= splitatchar spec '#'
in
4303 let getpath filename =
4305 if nonemptystr
filename
4307 if Filename.is_relative
filename
4309 let dir = Filename.dirname state
.path in
4311 if Filename.is_implicit
dir
4312 then Filename.concat
(Sys.getcwd
()) dir
4315 Filename.concat
dir filename
4319 if Sys.file_exists
path
4323 let path = getpath filename in
4327 let cmd = Lazy.force_val lcmd
in
4328 match spawn
cmd with
4330 | (exception exn
) ->
4331 dolog
"failed to execute `%s': %s" cmd @@ exntos exn
4333 let anchor = getanchor
() in
4334 let ranchor = state
.path, state
.password, anchor, state
.origin
in
4335 state
.origin
<- E.s;
4336 state
.ranchors
<- ranchor :: state
.ranchors
;
4339 if substratis spec
0 "page="
4341 match Scanf.sscanf spec
"page=%d" (fun n -> n) with
4343 state
.anchor <- (pageno, 0.0, 0.0);
4344 dospawn @@ lazy (Printf.sprintf
"%s -page %d %S" !selfexec pageno path);
4346 adderrfmt "error parsing remote destination" "page: %s" @@ exntos exn
4348 state
.nameddest
<- dest
;
4349 dospawn @@ lazy (!selfexec ^
" " ^
path ^
" -dest " ^ dest
)
4353 let gotounder = function
4354 | Ulinkuri
s when isexternallink
s ->
4355 if substratis
s 0 "file://"
4356 then gotoremote @@ String.sub s 7 (String.length
s - 7)
4359 let pageno, x, y = uritolocation
s in
4361 gotopagexy !wtmode pageno x y
4362 | Utext
_ | Unone
-> ()
4363 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
4366 let gotooutline (_, _, kind
) =
4370 let (pageno, y, _) = anchor in
4372 (if conf
.presentation
then (pageno, y, 1.0) else anchor)
4376 | Ouri
uri -> gotounder (Ulinkuri
uri)
4377 | Olaunch _cmd
-> failwith
"gotounder (Ulaunch cmd)"
4378 | Oremote _remote
-> failwith
"gotounder (Uremote remote)"
4379 | Ohistory hist
-> gotohist hist
4380 | Oremotedest _remotedest
-> failwith
"gotounder (Uremotedest remotedest)"
4383 class outlinesoucebase fetchoutlines
= object (self)
4384 inherit lvsourcebase
4385 val mutable m_items
= E.a
4386 val mutable m_minfo
= E.a
4387 val mutable m_orig_items
= E.a
4388 val mutable m_orig_minfo
= E.a
4389 val mutable m_narrow_patterns
= []
4390 val mutable m_gen
= -1
4392 method getitemcount
= Array.length m_items
4395 let s, n, _ = m_items
.(n) in
4398 method exit ~
(uioh:uioh) ~cancel ~
active ~
(first:int) ~pan
:
4400 ignore
(uioh, first);
4402 if m_narrow_patterns
= []
4403 then m_orig_items
, m_orig_minfo
4404 else m_items
, m_minfo
4411 gotooutline m_items
.(active);
4419 method hasaction
(_:int) = true
4422 if Array.length m_items
!= Array.length m_orig_items
4425 match m_narrow_patterns
with
4427 | many
-> String.concat
"@Uellipsis" (List.rev many
)
4429 "Narrowed to " ^
s ^
" (ctrl-u to restore)"
4433 match m_narrow_patterns
with
4436 | head
:: _ -> "@Uellipsis" ^ head
4438 method narrow
pattern =
4439 match Str.regexp_case_fold
pattern with
4440 | (exception _) -> ()
4442 let rec loop accu minfo n =
4445 m_items
<- Array.of_list
accu;
4446 m_minfo
<- Array.of_list
minfo;
4449 let (s, _, _) as o = m_items
.(n) in
4451 match Str.search_forward re
s 0 with
4452 | (exception Not_found
) -> accu, minfo
4453 | first -> o :: accu, (first, Str.match_end
()) :: minfo
4455 loop accu minfo (n-1)
4457 loop [] [] (Array.length m_items
- 1)
4459 method! getminfo
= m_minfo
4462 m_orig_items
<- fetchoutlines
();
4463 m_minfo
<- m_orig_minfo
;
4464 m_items
<- m_orig_items
4466 method add_narrow_pattern
pattern =
4467 m_narrow_patterns
<- pattern :: m_narrow_patterns
4469 method del_narrow_pattern
=
4470 match m_narrow_patterns
with
4471 | _ :: rest
-> m_narrow_patterns
<- rest
4476 match m_narrow_patterns
with
4477 | pattern :: [] -> self#narrow
pattern; pattern
4479 List.fold_left
(fun accu pattern ->
4480 self#narrow
pattern;
4481 pattern ^
"@Uellipsis" ^
accu) E.s list
4483 method calcactive
(_:anchor) = 0
4485 method reset
anchor items =
4486 if state
.gen
!= m_gen
4488 m_orig_items
<- items;
4490 m_narrow_patterns
<- [];
4492 m_orig_minfo
<- E.a;
4496 if items != m_orig_items
4498 m_orig_items
<- items;
4499 if m_narrow_patterns
== []
4500 then m_items
<- items;
4503 let active = self#calcactive
anchor in
4505 m_first
<- firstof m_first
active
4509 let outlinesource fetchoutlines
=
4511 inherit outlinesoucebase fetchoutlines
4512 method! calcactive
anchor =
4513 let rely = getanchory anchor in
4514 let rec loop n best bestd
=
4515 if n = Array.length m_items
4518 let _, _, kind
= m_items
.(n) in
4521 let orely = getanchory anchor in
4522 let d = abs
(orely - rely) in
4525 else loop (n+1) best bestd
4526 | Onone
| Oremote
_ | Olaunch
_
4527 | Oremotedest
_ | Ouri
_ | Ohistory
_ ->
4528 loop (n+1) best bestd
4534 let enteroutlinemode, enterbookmarkmode
, enterhistmode
=
4535 let mkselector sourcetype
=
4536 let fetchoutlines () =
4537 match sourcetype
with
4538 | `bookmarks
-> Array.of_list state
.bookmarks
4539 | `outlines
-> state
.outlines
4540 | `history
-> genhistoutlines ()
4543 if sourcetype
= `history
4544 then new outlinesoucebase
fetchoutlines
4545 else outlinesource fetchoutlines
4548 let outlines = fetchoutlines () in
4549 if Array.length
outlines = 0
4551 showtext ' ' errmsg
;
4555 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
4556 let anchor = getanchor
() in
4557 source#reset
anchor outlines;
4558 state
.text <- source#greetmsg
;
4560 coe (new outlinelistview ~zebra
:(sourcetype
=`history
) ~
source);
4561 G.postRedisplay "enter selector";
4564 let mkenter sourcetype errmsg
=
4565 let enter = mkselector sourcetype
in
4566 fun () -> enter errmsg
4568 mkenter `
outlines "document has no outline"
4569 , mkenter `bookmarks
"document has no bookmarks (yet)"
4570 , mkenter `history
"history is empty"
4573 let quickbookmark ?title
() =
4574 match state
.layout with
4580 let tm = Unix.localtime
(now
()) in
4582 "Quick (page %d) (bookmarked at %02d/%02d/%d %02d:%02d)"
4586 (tm.Unix.tm_year
+ 1900)
4589 | Some
title -> title
4591 state
.bookmarks
<- (title, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
4594 let setautoscrollspeed step goingdown
=
4595 let incr = max
1 ((abs step
) / 2) in
4596 let incr = if goingdown
then incr else -incr in
4597 let astep = boundastep state
.winh
(step
+ incr) in
4598 state
.autoscroll
<- Some
astep;
4602 match conf
.columns
with
4604 | Csingle
_ | Cmulti
_ -> state
.x != 0 || conf
.zoom > 1.0
4607 let panbound x = bound
x (-state
.w) state
.winw
;;
4609 let existsinrow pageno (columns
, coverA
, coverB
) p =
4610 let last = ((pageno - coverA
) mod columns
) + columns
in
4611 let rec any = function
4614 if l.pageno = coverA
- 1 || l.pageno = state
.pagecount
- coverB
4618 then (if l.pageno = last then false else any rest
)
4626 match state
.layout with
4628 let pageno = page_of_y state
.y in
4629 gotoghyll (getpagey
(pageno+1))
4631 match conf
.columns
with
4633 if conf
.presentation
&& rest
== [] && l.pageh
> l.pagey + l.pagevh
4635 let y = clamp (pgscale state
.winh
) in
4638 let pageno = min
(l.pageno+1) (state
.pagecount
-1) in
4639 gotoghyll (getpagey
pageno)
4640 | Cmulti
((c, _, _) as cl
, _) ->
4641 if conf
.presentation
4642 && (existsinrow l.pageno cl
4643 (fun l -> l.pageh
> l.pagey + l.pagevh))
4645 let y = clamp (pgscale state
.winh
) in
4648 let pageno = min
(l.pageno+c) (state
.pagecount
-1) in
4649 gotoghyll (getpagey
pageno)
4651 if l.pageno < state
.pagecount
- 1 || l.pagecol
< n - 1
4653 let pagey, pageh
= getpageyh
l.pageno in
4654 let pagey = pagey + pageh
* l.pagecol
in
4655 let ips = if l.pagecol
= 0 then 0 else conf
.interpagespace
in
4656 gotoghyll (pagey + pageh
+ ips)
4660 match state
.layout with
4662 let pageno = page_of_y state
.y in
4663 gotoghyll (getpagey
(pageno-1))
4665 match conf
.columns
with
4667 if conf
.presentation
&& l.pagey != 0
4669 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4671 let pageno = max
0 (l.pageno-1) in
4672 gotoghyll (getpagey
pageno)
4673 | Cmulti
((c, _, coverB
) as cl
, _) ->
4674 if conf
.presentation
&&
4675 (existsinrow l.pageno cl
(fun l -> l.pagey != 0))
4677 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4680 if l.pageno = state
.pagecount
- coverB
4684 let pageno = max
0 (l.pageno-decr) in
4685 gotoghyll (getpagey
pageno)
4693 let pageno = max
0 (l.pageno-1) in
4694 let pagey, pageh
= getpageyh
pageno in
4697 let pagey, pageh
= getpageyh
l.pageno in
4698 pagey + pageh
* (l.pagecol
-1) - conf
.interpagespace
4704 if emptystr conf
.savecmd
4705 then error
"don't know where to save modified document"
4707 let savecmd = Str.global_replace percentsre state
.path conf
.savecmd in
4710 (fun s -> error
"failed to obtain path to the saved copy: %s" s)
4715 let tmp = path ^
".tmp" in
4717 Unix.rename
tmp path;
4720 let viewkeyboard key mask
=
4722 let mode = state
.mode in
4723 state
.mode <- Textentry
(te, fun _ -> state
.mode <- mode);
4726 G.postRedisplay "view:enttext"
4728 let ctrl = Wsi.withctrl mask
in
4729 let key = Wsi.keypadtodigitkey
key in
4734 if hasunsavedchanges
()
4738 if conf
.angle
mod 360 = 0 && not
(isbirdseye state
.mode)
4741 match state
.lnava
with
4742 | None
-> LinkNav
(Ltgendir
0)
4743 | Some
pn -> LinkNav
(Ltexact
pn)
4745 gotoxy state
.x state
.y;
4747 else impmsg "keyboard link navigation does not work under rotation"
4750 begin match state
.mstate
with
4753 G.postRedisplay "kill rect";
4756 | Mscrolly
| Mscrollx
4759 begin match state
.mode with
4762 | Ltexact pl
-> state
.lnava
<- Some pl
4763 | Ltgendir
_ | Ltnotready
_ -> state
.lnava
<- None
4766 G.postRedisplay "esc leave linknav"
4770 match state
.ranchors
with
4772 | (path, password, anchor, origin
) :: rest
->
4773 state
.ranchors
<- rest
;
4774 state
.anchor <- anchor;
4775 state
.origin
<- origin
;
4776 state
.nameddest
<- E.s;
4777 opendoc path password
4782 gotoghyll (getnav ~
-1)
4793 Hashtbl.iter
(fun _ opaque ->
4795 Hashtbl.clear state
.prects
) state
.pagemap
;
4796 G.postRedisplay "dehighlight";
4798 | @slash
| @question
->
4799 let ondone isforw
s =
4800 cbput state
.hists
.pat
s;
4801 state
.searchpattern
<- s;
4804 let s = String.make
1 (Char.chr
key) in
4805 enttext (s, E.s, Some
(onhist state
.hists
.pat
),
4806 textentry, ondone (key = @slash
), true)
4808 | @plus
| @kpplus
| @equals
when ctrl ->
4809 let incr = if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01 in
4810 pivotzoom (conf
.zoom +. incr)
4812 | @plus
| @kpplus
->
4815 try int_of_string
s with exn
->
4816 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
;
4822 state
.text <- "page bias is now " ^ string_of_int
n;
4825 enttext ("page bias: ", E.s, None
, intentry, ondone, true)
4827 | @minus
| @kpminus
when ctrl ->
4828 let decr = if conf
.zoom -. 0.1 < 0.1 then 0.01 else 0.1 in
4829 pivotzoom (max
0.01 (conf
.zoom -. decr))
4831 | @minus
| @kpminus
->
4832 let ondone msg
= state
.text <- msg
in
4834 "option [acfhilpstvxACFPRSZTISM]: ", E.s, None
,
4835 optentry state
.mode, ondone, true
4840 then gotoxy 0 state
.y
4843 | (@1 | @2) when ctrl && conf
.fitmodel
!= FitPage
-> (* ctrl-1/2 *)
4845 match conf
.columns
with
4846 | Csingle
_ | Cmulti
_ -> 1
4847 | Csplit
(n, _) -> n
4849 let h = state
.winh
-
4850 conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0)
4852 let zoom = zoomforh state
.winw
h 0 cols in
4853 if zoom > 0.0 && (key = @2 || zoom < 1.0)
4858 match conf
.fitmodel
with
4859 | FitWidth
-> FitProportional
4860 | FitProportional
-> FitPage
4861 | FitPage
-> FitWidth
4863 state
.text <- "fit model: " ^
FMTE.to_string
fm;
4864 reqlayout conf
.angle
fm
4866 | @4 when ctrl -> (* ctrl-4 *)
4867 let zoom = getmaxw
() /. float state
.winw
in
4868 if zoom > 0.0 then setzoom zoom
4876 | (48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57)
4877 when not
ctrl -> (* 0..9 *)
4880 try int_of_string
s with exn
->
4881 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exn
;
4887 cbput state
.hists
.pag
(string_of_int
n);
4888 gotopage1 (n + conf
.pagebias
- 1) 0;
4891 let pageentry text key =
4892 match Char.unsafe_chr
key with
4893 | '
g'
-> TEdone
text
4894 | _ -> intentry text key
4896 let text = String.make
1 (Char.chr
key) in
4897 enttext (":", text, Some
(onhist state
.hists
.pag
),
4898 pageentry, ondone, true)
4901 conf
.scrollb
<- if conf
.scrollb
= 0 then (scrollbvv
lor scrollbhv
) else 0;
4902 G.postRedisplay "toggle scrollbar";
4905 state
.bzoom
<- not state
.bzoom
;
4907 showtext ' '
("block zoom " ^
if state
.bzoom
then "on" else "off")
4910 conf
.hlinks
<- not conf
.hlinks
;
4911 state
.text <- "highlightlinks " ^
if conf
.hlinks
then "on" else "off";
4912 G.postRedisplay "toggle highlightlinks";
4915 if conf
.angle
mod 360 = 0
4917 state
.glinks
<- true;
4918 let mode = state
.mode in
4921 (":", E.s, None
, linknentry, linknact gotounder, false),
4923 state
.glinks
<- false;
4927 G.postRedisplay "view:linkent(F)"
4929 else impmsg "hint mode does not work under rotation"
4932 state
.glinks
<- true;
4933 let mode = state
.mode in
4937 ":", E.s, None
, linknentry, linknact (fun under ->
4938 selstring (undertext under);
4942 state
.glinks
<- false;
4946 G.postRedisplay "view:linkent"
4949 begin match state
.autoscroll
with
4951 conf
.autoscrollstep
<- step
;
4952 state
.autoscroll
<- None
4954 if conf
.autoscrollstep
= 0
4955 then state
.autoscroll
<- Some
1
4956 else state
.autoscroll
<- Some conf
.autoscrollstep
4960 launchpath () (* XXX where do error messages go? *)
4963 setpresentationmode (not conf
.presentation
);
4964 showtext ' '
("presentation mode " ^
4965 if conf
.presentation
then "on" else "off");
4968 if List.mem
Wsi.Fullscreen state
.winstate
4969 then Wsi.reshape conf
.cwinw conf
.cwinh
4970 else Wsi.fullscreen
()
4973 search state
.searchpattern
false
4976 search state
.searchpattern
true
4979 begin match state
.layout with
4982 gotoghyll (getpagey
l.pageno)
4988 | @delete
| @kpdelete
-> (* delete *)
4992 showtext ' '
(describe_location ());
4995 begin match state
.layout with
4998 Wsi.reshape l.pagew
l.pageh
;
5003 enterbookmarkmode
()
5011 | @e when Buffer.length state
.errmsgs
> 0 ->
5016 match state
.layout with
5021 (s, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
5024 enttext ("bookmark: ", E.s, None
, textentry, ondone, true)
5028 showtext ' '
"Quick bookmark added";
5031 begin match state
.layout with
5033 let rect = getpdimrect
l.pagedimno
in
5037 (truncate
(1.8 *. (rect.(1) -. rect.(0))),
5038 truncate
(1.2 *. (rect.(3) -. rect.(0))))
5040 (truncate
(rect.(1) -. rect.(0)),
5041 truncate
(rect.(3) -. rect.(0)))
5043 let w = truncate
((float w)*.conf
.zoom)
5044 and h = truncate
((float h)*.conf
.zoom) in
5047 state
.anchor <- getanchor
();
5048 Wsi.reshape w (h + conf
.interpagespace
)
5050 G.postRedisplay "z";
5055 | @x -> state
.roam
()
5058 reqlayout (conf
.angle
+
5059 (if key = @Gt
then 30 else -30)) conf
.fitmodel
5063 bound
(conf
.colorscale
+. (if key = 93 then 0.1 else -0.1)) 0.0 1.0
5065 G.postRedisplay "brightness";
5067 | @c when state
.mode = View
->
5072 let m = (state
.winw
- state
.w) / 2 in
5073 gotoxy_and_clear_text m state
.y
5077 match state
.prevcolumns
with
5078 | None
-> (1, 0, 0), 1.0
5079 | Some
(columns
, z
) ->
5082 | Csplit
(c, _) -> -c, 0, 0
5083 | Cmulti
((c, a, b), _) -> c, a, b
5084 | Csingle
_ -> 1, 0, 0
5088 setcolumns View
c a b;
5091 | @down
| @up
when ctrl && Wsi.withshift mask
->
5092 let zoom, x = state
.prevzoom
in
5096 | @k
| @up
| @kpup
->
5097 begin match state
.autoscroll
with
5099 begin match state
.mode with
5100 | Birdseye beye
-> upbirdseye 1 beye
5105 then gotoxy_and_clear_text state
.x (clamp ~
-(state
.winh
/2))
5107 if not
(Wsi.withshift mask
) && conf
.presentation
5109 else gotoghyll1 true (clamp (-conf
.scrollstep
))
5113 setautoscrollspeed n false
5116 | @j
| @down
| @kpdown
->
5117 begin match state
.autoscroll
with
5119 begin match state
.mode with
5120 | Birdseye beye
-> downbirdseye 1 beye
5125 then gotoxy_and_clear_text state
.x (clamp (state
.winh
/2))
5127 if not
(Wsi.withshift mask
) && conf
.presentation
5129 else gotoghyll1 true (clamp (conf
.scrollstep
))
5133 setautoscrollspeed n true
5136 | @left | @right
| @kpleft
| @kpright
when not
(Wsi.withalt mask
) ->
5142 else conf
.hscrollstep
5144 let dx = if key = @left || key = @kpleft
then dx else -dx in
5145 gotoxy_and_clear_text (panbound (state
.x + dx)) state
.y
5148 G.postRedisplay "left/right"
5151 | @prior
| @kpprior
->
5155 match state
.layout with
5157 | l :: _ -> state
.y - l.pagey
5159 clamp (pgscale (-state
.winh
))
5163 | @next | @kpnext
->
5167 match List.rev state
.layout with
5169 | l :: _ -> getpagey
l.pageno
5171 clamp (pgscale state
.winh
)
5175 | @g | @home
| @kphome
->
5178 | @G
| @jend
| @kpend
->
5180 gotoghyll (clamp state
.maxy)
5182 | @right
| @kpright
when Wsi.withalt mask
->
5183 gotoghyll (getnav 1)
5184 | @left | @kpleft
when Wsi.withalt mask
->
5185 gotoghyll (getnav ~
-1)
5190 | @v when conf
.debug
->
5193 match getopaque l.pageno with
5196 let x0, y0, x1, y1 = pagebbox
opaque in
5197 let rect = (float x0, float y0,
5200 float x0, float y1) in
5202 let color = (0.0, 0.0, 1.0 /. (l.pageno mod 3 |> float), 0.5) in
5203 state
.rects
<- (l.pageno, color, rect) :: state
.rects
;
5205 G.postRedisplay "v";
5208 let mode = state
.mode in
5209 let cmd = ref E.s in
5210 let onleave = function
5211 | Cancel
-> state
.mode <- mode
5214 match getopaque l.pageno with
5215 | Some
opaque -> pipesel opaque !cmd
5216 | None
-> ()) state
.layout;
5220 cbput state
.hists
.sel
s;
5224 "| ", !cmd, Some
(onhist state
.hists
.sel
), textentry, ondone, true
5226 G.postRedisplay "|";
5227 state
.mode <- Textentry
(te, onleave);
5230 vlog "huh? %s" (Wsi.keyname
key)
5233 let linknavkeyboard key mask
linknav =
5234 let getpage pageno =
5235 let rec loop = function
5237 | l :: _ when l.pageno = pageno -> Some
l
5238 | _ :: rest
-> loop rest
5239 in loop state
.layout
5241 let doexact (pageno, n) =
5242 match getopaque pageno, getpage pageno with
5243 | Some
opaque, Some
l ->
5244 if key = @enter || key = @kpenter
5246 let under = getlink
opaque n in
5247 G.postRedisplay "link gotounder";
5254 Some
(findlink
opaque LDfirst
), -1
5257 Some
(findlink
opaque LDlast
), 1
5260 Some
(findlink
opaque (LDleft
n)), -1
5263 Some
(findlink
opaque (LDright
n)), 1
5266 Some
(findlink
opaque (LDup
n)), -1
5269 Some
(findlink
opaque (LDdown
n)), 1
5274 begin match findpwl
l.pageno dir with
5278 state
.mode <- LinkNav
(Ltgendir
dir);
5279 let y, h = getpageyh
pageno in
5282 then y + h - state
.winh
5287 begin match getopaque pageno, getpage pageno with
5288 | Some
opaque, Some
_ ->
5290 let ld = if dir > 0 then LDfirst
else LDlast
in
5293 begin match link with
5295 showlinktype (getlink
opaque m);
5296 state
.mode <- LinkNav
(Ltexact
(pageno, m));
5297 G.postRedisplay "linknav jpage";
5298 | Lnotfound
-> notfound dir
5304 begin match opt with
5305 | Some Lnotfound
-> pwl l dir;
5306 | Some
(Lfound
m) ->
5310 let _, y0, _, y1 = getlinkrect
opaque m in
5312 then gotopage1 l.pageno y0
5314 let d = fstate
.fontsize
+ 1 in
5315 if y1 - l.pagey > l.pagevh - d
5316 then gotopage1 l.pageno (y1 - state
.winh
+ d)
5317 else G.postRedisplay "linknav";
5319 showlinktype (getlink
opaque m);
5320 state
.mode <- LinkNav
(Ltexact
(l.pageno, m));
5323 | None
-> viewkeyboard key mask
5325 | _ -> viewkeyboard key mask
5329 begin match linknav with
5330 | Ltexact pa
-> state
.lnava
<- Some pa
5331 | Ltgendir
_ | Ltnotready
_ -> ()
5334 G.postRedisplay "leave linknav"
5338 | Ltgendir
_ | Ltnotready
_ -> viewkeyboard key mask
5339 | Ltexact exact
-> doexact exact
5342 let keyboard key mask
=
5343 if (key = @g && Wsi.withctrl mask
) && not
(istextentry state
.mode)
5344 then wcmd "interrupt"
5345 else state
.uioh <- state
.uioh#
key key mask
5348 let birdseyekeyboard key mask
5349 ((oconf
, leftx
, pageno, hooverpageno
, anchor) as beye
) =
5351 match conf
.columns
with
5353 | Cmulti
((c, _, _), _) -> c
5354 | Csplit
_ -> failwith
"bird's eye split mode"
5356 let pgh layout = List.fold_left
5357 (fun m l -> max
l.pageh
m) state
.winh
layout in
5359 | @l when Wsi.withctrl mask
->
5360 let y, h = getpageyh
pageno in
5361 let top = (state
.winh
- h) / 2 in
5362 gotoxy state
.x (max
0 (y - top))
5363 | @enter | @kpenter
-> leavebirdseye beye
false
5364 | @escape
-> leavebirdseye beye
true
5365 | @up
-> upbirdseye incr beye
5366 | @down
-> downbirdseye incr beye
5367 | @left -> upbirdseye 1 beye
5368 | @right
-> downbirdseye 1 beye
5371 begin match state
.layout with
5375 state
.mode <- Birdseye
(
5376 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5378 gotopage1 l.pageno 0;
5381 let layout = layout state
.x (state
.y-state
.winh
)
5383 (pgh state
.layout) in
5385 | [] -> gotoxy state
.x (clamp (-state
.winh
))
5387 state
.mode <- Birdseye
(
5388 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5390 gotopage1 l.pageno 0
5393 | [] -> gotoxy state
.x (clamp (-state
.winh
))
5397 begin match List.rev state
.layout with
5399 let layout = layout state
.x
5400 (state
.y + (pgh state
.layout))
5401 state
.winw state
.winh
in
5402 begin match layout with
5404 let incr = l.pageh
- l.pagevh in
5409 oconf
, leftx
, state
.pagecount
- 1, hooverpageno
, anchor
5411 G.postRedisplay "birdseye pagedown";
5413 else gotoxy state
.x (clamp (incr + conf
.interpagespace
*2));
5417 Birdseye
(oconf
, leftx
, l.pageno, hooverpageno
, anchor);
5418 gotopage1 l.pageno 0;
5421 | [] -> gotoxy state
.x (clamp state
.winh
)
5425 state
.mode <- Birdseye
(oconf
, leftx
, 0, hooverpageno
, anchor);
5429 let pageno = state
.pagecount
- 1 in
5430 state
.mode <- Birdseye
(oconf
, leftx
, pageno, hooverpageno
, anchor);
5431 if not
(pagevisible state
.layout pageno)
5434 match List.rev state
.pdims
with
5436 | (_, _, h, _) :: _ -> h
5440 (max
0 (getpagey
pageno - (state
.winh
- h - conf
.interpagespace
)))
5441 else G.postRedisplay "birdseye end";
5443 | _ -> viewkeyboard key mask
5448 match state
.mode with
5449 | Textentry
_ -> scalecolor 0.4
5451 | View
-> scalecolor 1.0
5452 | Birdseye
(_, _, pageno, hooverpageno
, _) ->
5453 if l.pageno = hooverpageno
5456 if l.pageno = pageno
5458 let c = scalecolor 1.0 in
5460 GlDraw.line_width
3.0;
5461 let dispx = l.pagedispx in
5463 (float (dispx-1)) (float (l.pagedispy-1))
5464 (float (dispx+l.pagevw+1))
5465 (float (l.pagedispy+l.pagevh+1))
5467 GlDraw.line_width
1.0;
5476 let postdrawpage l linkindexbase
=
5477 match getopaque l.pageno with
5479 if tileready l l.pagex
l.pagey
5481 let x = l.pagedispx - l.pagex
5482 and y = l.pagedispy - l.pagey in
5484 match conf
.columns
with
5485 | Csingle
_ | Cmulti
_ ->
5486 (if conf
.hlinks
then 1 else 0)
5488 && not
(isbirdseye state
.mode) then 2 else 0)
5492 match state
.mode with
5493 | Textentry
((_, s, _, _, _, _), _) when state
.glinks
-> s
5499 Hashtbl.find_all state
.prects
l.pageno |>
5500 List.iter
(fun vals
-> drawprect
opaque x y vals
);
5501 let n = postprocess
opaque hlmask x y (linkindexbase
, s, conf
.hfsize
) in
5503 then (state
.redisplay
<- true; 0)
5509 let scrollindicator () =
5510 let sbw, ph
, sh = state
.uioh#
scrollph in
5511 let sbh, pw, sw = state
.uioh#scrollpw
in
5516 else ((state
.winw
- sbw), state
.winw
, 0)
5520 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5521 GlDraw.color (0.64, 0.64, 0.64) ~
alpha:0.7;
5522 filledrect (float x0) 0. (float x1) (float state
.winh
);
5524 (float hx0
) (float (state
.winh
- sbh))
5525 (float (hx0
+ state
.winw
)) (float state
.winh
)
5527 GlDraw.color (0.0, 0.0, 0.0) ~
alpha:0.7;
5529 filledrect (float x0) ph
(float x1) (ph
+. sh);
5530 let pw = pw +. float hx0
in
5531 filledrect pw (float (state
.winh
- sbh)) (pw +. sw) (float state
.winh
);
5536 match state
.mstate
with
5537 | Mnone
| Mscrolly
| Mscrollx
| Mpan
_ | Mzoom
_ | Mzoomrect
_ ->
5540 | Msel
((x0, y0), (x1, y1)) ->
5541 let identify opaque l px py = Some
(opaque, l.pageno, px, py) in
5542 let o0,n0
,px0
,py0
= onppundermouse identify x0 y0 (~
< E.s, -1, 0, 0) in
5543 let _o1,n1
,px1
,py1
= onppundermouse identify x1 y1 (~
< E.s, -1, 0, 0) in
5544 if n0
!= -1 && n0
= n1
then seltext
o0 (px0
, py0
, px1
, py1
);
5551 GlDraw.color (0.0, 0.0, 1.0) ~
alpha:0.5;
5552 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5554 (fun (pageno, c, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) ->
5556 if l.pageno = pageno
5558 let dx = float (l.pagedispx - l.pagex
) in
5559 let dy = float (l.pagedispy - l.pagey) in
5560 let r, g, b, alpha = c in
5561 GlDraw.color (r, g, b) ~
alpha;
5562 filledrect2 (x0+.dx) (y0+.dy)
5574 begin match conf
.columns
, state
.layout with
5575 | Csingle
_, _ :: _ ->
5576 GlDraw.color (scalecolor2 conf
.bgcolor
);
5578 List.fold_left
(fun y l ->
5581 let x1 = l.pagedispx in
5582 let y1 = (l.pagedispy + l.pagevh) in
5583 filledrect (float x0) (float y0) (float x1) (float y1);
5584 let x0 = x1 + l.pagevw in
5585 let x1 = state
.winw
in
5586 filledrect1 (float x0) (float y0) (float x1) (float y1);
5590 and x1 = state
.winw
in
5592 and y1 = l.pagedispy in
5593 filledrect1 (float x0) (float y0) (float x1) (float y1);
5595 l.pagedispy + l.pagevh) 0 state
.layout
5598 and x1 = state
.winw
in
5600 and y1 = state
.winh
in
5601 filledrect1 (float x0) (float y0) (float x1) (float y1)
5602 | (Cmulti
_ | Csplit
_), _ | Csingle
_, [] ->
5603 GlClear.color (scalecolor2 conf
.bgcolor
);
5604 GlClear.clear
[`
color];
5606 List.iter
drawpage state
.layout;
5608 match state
.mode with
5609 | LinkNav
(Ltexact
(pageno, linkno
)) ->
5610 begin match getopaque pageno with
5612 let x0, y0, x1, y1 = getlinkrect
opaque linkno
in
5613 let color = (0.0, 0.0, 0.5, 0.5) in
5620 | None
-> state
.rects
5622 | LinkNav
(Ltgendir
_) | LinkNav
(Ltnotready
_)
5625 | View
-> state
.rects
5628 let rec postloop linkindexbase
= function
5630 let linkindexbase = linkindexbase + postdrawpage l linkindexbase in
5631 postloop linkindexbase rest
5635 postloop 0 state
.layout;
5637 begin match state
.mstate
with
5638 | Mzoomrect
((x0, y0), (x1, y1)) ->
5640 GlDraw.color (0.3, 0.3, 0.3) ~
alpha:0.5;
5641 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5642 filledrect (float x0) (float y0) (float x1) (float y1);
5646 | Mscrolly
| Mscrollx
5655 let zoomrect x y x1 y1 =
5658 and y0 = min
y y1 in
5659 let zoom = (float state
.w) /. float (x1 - x0) in
5662 if state
.w < state
.winw
5663 then (state
.winw
- state
.w) / 2
5666 match conf
.fitmodel
with
5667 | FitWidth
| FitProportional
-> simple ()
5669 match conf
.columns
with
5671 onppundermouse (fun _ l _ _ -> Some
l.pagedispx) x0 y0 x0
5672 | Cmulti
_ | Csingle
_ -> simple ()
5674 gotoxy ((state
.x + margin) - x0) (state
.y + y0);
5675 state
.anchor <- getanchor
();
5680 let annot inline
x y =
5681 match unproject x y with
5682 | Some
(opaque, n, ux
, uy
) ->
5684 addannot
opaque ux uy
text;
5685 wcmd "freepage %s" (~
> opaque);
5686 Hashtbl.remove state
.pagemap
(n, state
.gen
);
5688 gotoxy state
.x state
.y
5692 let ondone s = add s in
5693 let mode = state
.mode in
5694 state
.mode <- Textentry
(
5695 ("annotation: ", E.s, None
, textentry, ondone, true),
5696 fun _ -> state
.mode <- mode);
5699 G.postRedisplay "annot"
5701 add @@ getusertext E.s
5706 let g opaque l px py =
5707 match rectofblock
opaque px py with
5709 let x0 = a.(0) -. 20. in
5710 let x1 = a.(1) +. 20. in
5711 let y0 = a.(2) -. 20. in
5712 let zoom = (float state
.w) /. (x1 -. x0) in
5713 let pagey = getpagey
l.pageno in
5714 let margin = (state
.w - l.pagew
)/2 in
5715 let nx = -truncate
x0 - margin in
5716 gotoxy_and_clear_text nx (pagey + truncate
y0);
5717 state
.anchor <- getanchor
();
5722 match conf
.columns
with
5724 impmsg "block zooming does not work properly in split columns mode"
5725 | Cmulti
_ | Csingle
_ -> onppundermouse g x y ()
5729 let winw = state
.winw - 1 in
5730 let s = float x /. float winw in
5731 let destx = truncate
(float (state
.w + winw) *. s) in
5732 gotoxy_and_clear_text (winw - destx) state
.y;
5733 state
.mstate
<- Mscrollx
;
5737 let s = float y /. float state
.winh
in
5738 let desty = truncate
(float (state
.maxy -
5739 (if conf
.maxhfit
then state
.winh
else 0))
5741 gotoxy_and_clear_text state
.x desty;
5742 state
.mstate
<- Mscrolly
;
5745 let viewmulticlick clicks
x y mask
=
5746 let g opaque l px py =
5754 if markunder
opaque px py mark
5758 match getopaque l.pageno with
5760 | Some
opaque -> pipesel opaque cmd
5762 state
.roam
<- (fun () -> dopipe conf
.paxcmd
);
5763 if not
(Wsi.withctrl mask
) then dopipe conf
.selcmd
;
5768 G.postRedisplay "viewmulticlick";
5769 onppundermouse g x y (fun () -> impmsg "nothing to select") ();
5773 match conf
.columns
with
5775 | Csingle
_ | Cmulti
_ -> conf
.angle
mod 360 = 0
5778 let viewmouse button down
x y mask
=
5780 | n when (n == 4 || n == 5) && not down
->
5781 if Wsi.withctrl mask
5783 match state
.mstate
with
5784 | Mzoom
(oldn
, i
, (ftx
, fty
)) ->
5787 then abs
(ftx
- x) > 5 || abs
(fty
- y) > 5
5797 if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01
5799 if conf
.zoom -. 0.1 < 0.1 then -0.01 else -0.1
5801 let zoom = conf
.zoom -. incr in
5803 then pivotzoom ~
x ~
y zoom
5804 else pivotzoom zoom;
5805 state
.mstate
<- Mzoom
(n, 0, (x, y));
5807 state
.mstate
<- Mzoom
(n, i
+1, (ftx
, fty
));
5809 else state
.mstate
<- Mzoom
(n, 0, (ftx
, fty
))
5813 | Mscrolly
| Mscrollx
5815 | Mnone
-> state
.mstate
<- Mzoom
(n, 0, (0, 0))
5818 match state
.autoscroll
with
5819 | Some step
-> setautoscrollspeed step
(n=4)
5821 if conf
.wheelbypage
|| conf
.presentation
5830 then -conf
.scrollstep
5831 else conf
.scrollstep
5833 let incr = incr * 2 in
5834 let y = clamp incr in
5835 gotoxy_and_clear_text state
.x y
5838 | n when (n = 6 || n = 7) && not down
&& canpan () ->
5840 panbound (state
.x + (if n = 7 then -2 else 2) * conf
.hscrollstep
) in
5841 gotoxy_and_clear_text x state
.y
5843 | 1 when Wsi.withshift mask
->
5844 state
.mstate
<- Mnone
;
5847 match unproject x y with
5849 | Some
(_, pageno, ux
, uy
) ->
5850 let cmd = Printf.sprintf
5852 conf
.stcmd state
.path pageno ux uy
5854 match spawn
cmd [] with
5855 | (exception exn
) ->
5856 impmsg "execution of synctex command(%S) failed: %S"
5857 conf
.stcmd
@@ exntos exn
5861 | 1 when Wsi.withctrl mask
->
5864 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5865 state
.mstate
<- Mpan
(x, y)
5868 state
.mstate
<- Mnone
5873 if Wsi.withshift mask
5875 annot conf
.annotinline
x y;
5876 G.postRedisplay "addannot"
5880 Wsi.setcursor
Wsi.CURSOR_CYCLE
;
5881 state
.mstate
<- Mzoomrect
(p, p)
5884 match state
.mstate
with
5885 | Mzoomrect
((x0, y0), _) ->
5886 if abs
(x-x0) > 10 && abs
(y - y0) > 10
5887 then zoomrect x0 y0 x y
5890 G.postRedisplay "kill accidental zoom rect";
5894 | Mscrolly
| Mscrollx
5900 | 1 when vscrollhit x ->
5903 let _, position, sh = state
.uioh#
scrollph in
5904 if y > truncate
position && y < truncate
(position +. sh)
5905 then state
.mstate
<- Mscrolly
5908 state
.mstate
<- Mnone
5910 | 1 when y > state
.winh
- hscrollh () ->
5913 let _, position, sw = state
.uioh#scrollpw
in
5914 if x > truncate
position && x < truncate
(position +. sw)
5915 then state
.mstate
<- Mscrollx
5918 state
.mstate
<- Mnone
5920 | 1 when state
.bzoom
-> if not down
then zoomblock x y
5923 let dest = if down
then getunder x y else Unone
in
5924 begin match dest with
5928 | Unone
when down
->
5929 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5930 state
.mstate
<- Mpan
(x, y);
5932 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
5934 | Unone
| Utext
_ ->
5939 state
.mstate
<- Msel
((x, y), (x, y));
5940 G.postRedisplay "mouse select";
5944 match state
.mstate
with
5947 | Mzoom
_ | Mscrollx
| Mscrolly
->
5948 state
.mstate
<- Mnone
5950 | Mzoomrect
((x0, y0), _) ->
5954 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
5955 state
.mstate
<- Mnone
5957 | Msel
((x0, y0), (x1, y1)) ->
5958 let rec loop = function
5962 let a0 = l.pagedispy in
5963 let a1 = a0 + l.pagevh in
5964 let b0 = l.pagedispx in
5965 let b1 = b0 + l.pagevw in
5966 ((y0 >= a0 && y0 <= a1) || (y1 >= a0 && y1 <= a1))
5967 && ((x0 >= b0 && x0 <= b1) || (x1 >= b0 && x1 <= b1))
5971 match getopaque l.pageno with
5974 match Unix.pipe
() with
5975 | (exception exn
) ->
5976 impmsg "cannot create sel pipe: %s" @@
5980 Ne.clo fd
(fun msg
->
5981 dolog
"%s close failed: %s" what msg
)
5984 try spawn
cmd [r, 0; w, -1]
5986 dolog
"cannot execute %S: %s"
5993 G.postRedisplay "copysel";
5995 else clo "Msel pipe/w" w;
5996 clo "Msel pipe/r" r;
5998 dosel conf
.selcmd
();
5999 state
.roam
<- dosel conf
.paxcmd
;
6011 let birdseyemouse button down
x y mask
6012 (conf
, leftx
, _, hooverpageno
, anchor) =
6015 let rec loop = function
6018 if y > l.pagedispy && y < l.pagedispy + l.pagevh
6019 && x > l.pagedispx && x < l.pagedispx + l.pagevw
6021 leavebirdseye (conf
, leftx
, l.pageno, hooverpageno
, anchor) false;
6027 | _ -> viewmouse button down
x y mask
6033 method key key mask
=
6034 begin match state
.mode with
6035 | Textentry
textentry -> textentrykeyboard key mask
textentry
6036 | Birdseye
birdseye -> birdseyekeyboard key mask
birdseye
6037 | View
-> viewkeyboard key mask
6038 | LinkNav
linknav -> linknavkeyboard key mask
linknav
6042 method button button bstate
x y mask
=
6043 begin match state
.mode with
6045 | View
-> viewmouse button bstate
x y mask
6046 | Birdseye beye
-> birdseyemouse button bstate
x y mask beye
6051 method multiclick clicks
x y mask
=
6052 begin match state
.mode with
6054 | View
-> viewmulticlick clicks
x y mask
6061 begin match state
.mode with
6063 | View
| Birdseye
_ | LinkNav
_ ->
6064 match state
.mstate
with
6065 | Mzoom
_ | Mnone
-> ()
6070 state
.mstate
<- Mpan
(x, y);
6071 let x = if canpan () then panbound (state
.x + dx) else state
.x in
6073 gotoxy_and_clear_text x y
6076 state
.mstate
<- Msel
(a, (x, y));
6077 G.postRedisplay "motion select";
6080 let y = min state
.winh
(max
0 y) in
6084 let x = min state
.winw (max
0 x) in
6087 | Mzoomrect
(p0
, _) ->
6088 state
.mstate
<- Mzoomrect
(p0
, (x, y));
6089 G.postRedisplay "motion zoomrect";
6093 method pmotion
x y =
6094 begin match state
.mode with
6095 | Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor) ->
6096 let rec loop = function
6098 if hooverpageno
!= -1
6100 state
.mode <- Birdseye
(conf
, leftx
, pageno, -1, anchor);
6101 G.postRedisplay "pmotion birdseye no hoover";
6104 if y > l.pagedispy && y < l.pagedispy + l.pagevh
6105 && x > l.pagedispx && x < l.pagedispx + l.pagevw
6107 state
.mode <- Birdseye
(conf
, leftx
, pageno, l.pageno, anchor);
6108 G.postRedisplay "pmotion birdseye hoover";
6118 match state
.mstate
with
6119 | Mpan
_ | Msel
_ | Mzoom
_ | Mscrolly
| Mscrollx
| Mzoomrect
_ -> ()
6127 let past, _, _ = !r in
6129 let delta = now -. past in
6132 else r := (now, x, y)
6136 method infochanged
_ = ()
6139 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
6142 then 0.0, float state
.winh
6143 else scrollph state
.y maxy
6148 let fwinw = float (state
.winw - vscrollw ()) in
6150 let sw = fwinw /. float state
.w in
6151 let sw = fwinw *. sw in
6152 max
sw (float conf
.scrollh
)
6155 let maxx = state
.w + state
.winw in
6156 let x = state
.winw - state
.x in
6157 let percent = float x /. float maxx in
6158 (fwinw -. sw) *. percent
6160 hscrollh (), position, sw
6164 match state
.mode with
6165 | LinkNav
_ -> "links"
6166 | Textentry
_ -> "textentry"
6167 | Birdseye
_ -> "birdseye"
6170 findkeyhash conf
modename
6172 method eformsgs
= true
6173 method alwaysscrolly
= false
6176 let addrect pageno r g b a x0 y0 x1 y1 =
6177 Hashtbl.add state
.prects
pageno [|r; g; b; a; x0; y0; x1; y1|];
6181 let cl = splitatchar cmds ' '
in
6183 try Scanf.sscanf
s fmt
f
6185 adderrfmt "remote exec"
6186 "error processing '%S': %s\n" cmds
@@ exntos exn
6188 let rectx s pageno (r, g, b, a) x0 y0 x1 y1 =
6189 vlog "%s page %d color (%f %f %f %f) x0,y0,x1,y1 = %f %f %f %f"
6190 s pageno r g b a x0 y0 x1 y1;
6194 let _,w1,h1
,_ = getpagedim
pageno in
6195 let sw = float w1 /. float w
6196 and sh = float h1
/. float h in
6200 and y1s
= y1 *. sh in
6201 let rect = (x0s,y0s
,x1s
,y0s
,x1s
,y1s
,x0s,y1s
) in
6202 let color = (r, g, b, a) in
6203 if conf
.verbose
then debugrect rect;
6204 state
.rects <- (pageno, color, rect) :: state
.rects;
6209 | "reload", "" -> reload ()
6211 scan args
"%u %f %f"
6213 let cmd, _ = state
.geomcmds
in
6215 then gotopagexy !wtmode pageno x y
6218 gotopagexy !wtmode pageno x y;
6221 state
.reprf
<- f state
.reprf
6223 | "goto1", args
-> scan args
"%u %f" gotopage
6226 (fun _filename _pageno
->
6227 failwith
"gotounder (Uremote (filename, pageno))")
6230 (fun _filename _dest
->
6231 failwith
"gotounder (Uremotedest (filename, dest))")
6233 scan args
"%u %u %f %f %f %f"
6234 (fun pageno c x0 y0 x1 y1 ->
6235 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
6236 rectx "rect" pageno color x0 y0 x1 y1;
6239 scan args
"%u %f %f %f %f %f %f %f %f"
6240 (fun pageno r g b alpha x0 y0 x1 y1 ->
6241 addrect pageno r g b alpha x0 y0 x1 y1;
6242 G.postRedisplay "prect"
6245 scan args
"%u %f %f"
6248 match getopaque pageno with
6249 | Some
opaque -> opaque
6252 pgoto optopaque pageno x y;
6253 let rec fixx = function
6256 if l.pageno = pageno
6257 then gotoxy (state
.x - l.pagedispx) state
.y
6262 match conf
.columns
with
6263 | Csingle
_ | Csplit
_ -> 1
6264 | Cmulti
((n, _, _), _) -> n
6266 layout 0 state
.y (state
.winw * mult) state
.winh
6270 | "activatewin", "" -> Wsi.activatewin
()
6271 | "quit", "" -> raise Quit
6274 let l = Config.keys_of_string
keys in
6275 List.iter
(fun (k
, m) -> keyboard k
m) l
6277 adderrfmt "error processing keys" "`%S': %s\n" cmds
@@ exntos exn
6279 | "clearrects", "" ->
6280 Hashtbl.clear state
.prects
;
6281 G.postRedisplay "clearrects"
6283 adderrfmt "remote command"
6284 "error processing remote command: %S\n" cmds
;
6288 let scratch = Bytes.create
80 in
6289 let buf = Buffer.create
80 in
6291 match tempfailureretry
(Unix.read fd
scratch 0) 80 with
6292 | (exception Unix.Unix_error
(Unix.EAGAIN
, _, _)) -> None
6295 if Buffer.length
buf > 0
6297 let s = Buffer.contents
buf in
6305 match Bytes.index_from
scratch ppos '
\n'
with
6306 | pos
-> if pos
>= n then -1 else pos
6307 | (exception Not_found
) -> -1
6311 Buffer.add_subbytes
buf scratch ppos
(nlpos-ppos
);
6312 let s = Buffer.contents
buf in
6318 Buffer.add_subbytes
buf scratch ppos
(n-ppos
);
6324 let remoteopen path =
6325 try Some
(Unix.openfile
path [Unix.O_NONBLOCK
; Unix.O_RDONLY
] 0o0)
6327 adderrfmt "remoteopen" "error opening %S: %s" path @@ exntos exn
;
6332 let gcconfig = ref E.s in
6333 let trimcachepath = ref E.s in
6334 let rcmdpath = ref E.s in
6335 let pageno = ref None
in
6336 let rootwid = ref 0 in
6337 let openlast = ref false in
6338 let nofc = ref false in
6339 let doreap = ref false in
6340 let csspath = ref None
in
6341 selfexec := Sys.executable_name
;
6344 [("-p", Arg.String
(fun s -> state
.password <- s),
6345 "<password> Set password");
6349 Config.fontpath
:= s;
6350 selfexec := !selfexec ^
" -f " ^
Filename.quote
s;
6352 "<path> Set path to the user interface font");
6356 selfexec := !selfexec ^
" -c " ^
Filename.quote
s;
6357 Config.confpath
:= s),
6358 "<path> Set path to the configuration file");
6360 ("-last", Arg.Set
openlast, " Open last document");
6362 ("-page", Arg.Int
(fun pageno1
-> pageno := Some
(pageno1
-1)),
6363 "<page-number> Jump to page");
6365 ("-tcf", Arg.String
(fun s -> trimcachepath := s),
6366 "<path> Set path to the trim cache file");
6368 ("-dest", Arg.String
(fun s -> state
.nameddest
<- s),
6369 "<named-destination> Set named destination");
6371 ("-wtmode", Arg.Set
wtmode, " Operate in wt mode");
6372 ("-cxack", Arg.Set
cxack, " Cut corners");
6374 ("-remote", Arg.String
(fun s -> rcmdpath := s),
6375 "<path> Set path to the source of remote commands");
6377 ("-gc", Arg.Set_string
gcconfig,
6378 "<path> Collect garbage with the help of a script");
6380 ("-nofc", Arg.Set
nofc, " Do not use fontconfig");
6382 ("-v", Arg.Unit
(fun () ->
6384 "%s\nconfiguration path: %s\n"
6387 exit
0), " Print version and exit");
6389 ("-css", Arg.String
(fun s -> csspath := Some
s),
6390 "<path> Set path to the style sheet to use with EPUB/HTML");
6392 ("-embed", Arg.Set_int
rootwid, "<window-id> Embed into window");
6394 ("-origin", Arg.String
(fun s -> state
.origin
<- s),
6395 "<origin> <undocumented>");
6398 (fun s -> state
.path <- s)
6399 ("Usage: " ^
Sys.argv
.(0) ^
" [options] some.pdf\nOptions:");
6402 then selfexec := !selfexec ^
" -wtmode";
6404 let histmode = emptystr state
.path && not
!openlast in
6406 if not
(Config.load !openlast)
6407 then dolog
"failed to load configuration";
6409 begin match !pageno with
6410 | Some
pageno -> state
.anchor <- (pageno, 0.0, 0.0)
6414 if nonemptystr
!gcconfig
6417 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6418 | (exception exn
) -> error
"socketpair for gc failed: %s" @@ exntos exn
6421 match spawn
!gcconfig [(c, 0); (c, 1); (s, -1)] with
6422 | (exception exn
) -> error
"failed to execute gc script: %s" @@ exntos exn
6424 Ne.clo c @@ (fun s -> error
"failed to close gc fd %s" s);
6431 val mutable m_clicks
= 0
6432 val mutable m_click_x
= 0
6433 val mutable m_click_y
= 0
6434 val mutable m_lastclicktime
= infinity
6436 method private cleanup =
6437 state
.roam
<- noroam
;
6438 Hashtbl.iter
(fun _ opaque -> clearmark
opaque) state
.pagemap
6439 method expose
= G.postRedisplay "expose"
6443 | Wsi.Unobscured
-> "unobscured"
6444 | Wsi.PartiallyObscured
-> "partiallyobscured"
6445 | Wsi.FullyObscured
-> "fullyobscured"
6447 vlog "visibility change %s" name
6448 method display = display ()
6449 method map mapped
= vlog "mapped %b" mapped
6450 method reshape w h =
6453 method mouse
b d x y m =
6454 if d && canselect ()
6457 * http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx
6464 if abs
x - m_click_x
> 10
6465 || abs
y - m_click_y
> 10
6466 || abs_float
(t -. m_lastclicktime
) > 0.3
6468 m_clicks
<- m_clicks
+ 1;
6469 m_lastclicktime
<- t;
6473 G.postRedisplay "cleanup";
6474 state
.uioh <- state
.uioh#button
b d x y m;
6476 else state
.uioh <- state
.uioh#multiclick m_clicks
x y m
6481 m_lastclicktime
<- infinity
;
6482 state
.uioh <- state
.uioh#button
b d x y m
6486 state
.uioh <- state
.uioh#button
b d x y m
6489 state
.mpos
<- (x, y);
6490 state
.uioh <- state
.uioh#motion
x y
6491 method pmotion
x y =
6492 state
.mpos
<- (x, y);
6493 state
.uioh <- state
.uioh#pmotion
x y
6495 let mascm = m land (
6496 Wsi.altmask
+ Wsi.shiftmask
+ Wsi.ctrlmask
+ Wsi.metamask
6499 let x = state
.x and y = state
.y in
6501 if x != state
.x || y != state
.y then self#
cleanup
6503 match state
.keystate
with
6505 let km = k
, mascm in
6508 let modehash = state
.uioh#
modehash in
6509 try Hashtbl.find modehash km
6511 try Hashtbl.find (findkeyhash conf
"global") km
6512 with Not_found
-> KMinsrt
(k
, m)
6514 | KMinsrt
(k
, m) -> keyboard k
m
6515 | KMinsrl
l -> List.iter
(fun (k
, m) -> keyboard k
m) l
6516 | KMmulti
(l, r) -> state
.keystate
<- KSinto
(l, r)
6518 | KSinto
((k'
, m'
) :: [], insrt
) when k'
=k
&& m'
land mascm = m'
->
6519 List.iter
(fun (k
, m) -> keyboard k
m) insrt
;
6520 state
.keystate
<- KSnone
6521 | KSinto
((k'
, m'
) :: keys, insrt
) when k'
=k
&& m'
land mascm = m'
->
6522 state
.keystate
<- KSinto
(keys, insrt
)
6523 | KSinto
_ -> state
.keystate
<- KSnone
6526 state
.mpos
<- (x, y);
6527 state
.uioh <- state
.uioh#pmotion
x y
6528 method leave = state
.mpos
<- (-1, -1)
6529 method winstate wsl
= state
.winstate
<- wsl
6530 method quit
= raise Quit
6533 let wsfd, winw, winh
= Wsi.init
mu !rootwid conf
.cwinw conf
.cwinh platform
in
6535 setbgcol conf
.bgcolor
;
6538 if not
@@ List.exists
GlMisc.check_extension
6539 [ "GL_ARB_texture_rectangle"
6540 ; "GL_EXT_texture_recangle"
6541 ; "GL_NV_texture_rectangle" ]
6542 then (dolog
"OpenGL does not suppport rectangular textures"; exit
1);
6544 if substratis
(GlMisc.get_string `renderer
) 0 "Mesa DRI Intel("
6546 defconf
.sliceheight
<- 1024;
6547 defconf
.texcount
<- 32;
6548 defconf
.usepbo
<- true;
6552 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6553 | (exception exn
) ->
6554 dolog
"socketpair failed: %s" @@ exntos exn
;
6562 setcheckers conf
.checkers
;
6564 opengl_has_pbo := GlMisc.check_extension
"GL_ARB_pixel_buffer_object";
6566 begin match !csspath with
6568 | Some
"" -> conf
.css
<- E.s
6570 let css = filecontents
path in
6571 let l = String.length
css in
6573 if substratis
css (l-2) "\r\n"
6574 then String.sub css 0 (l-2)
6575 else (if css.[l-1] = '
\n'
6576 then String.sub css 0 (l-1)
6580 conf
.angle
, conf
.fitmodel
, (conf
.trimmargins
, conf
.trimfuzz
),
6581 conf
.texcount
, conf
.sliceheight
, conf
.mustoresize
, conf
.colorspace
,
6582 !Config.fontpath
, !trimcachepath, !opengl_has_pbo, not
!nofc
6584 List.iter
GlArray.enable
[`texture_coord
; `vertex
];
6586 reshape ~firsttime
:true winw winh
;
6590 Wsi.settitle
"llpp (history)";
6594 state
.text <- "Opening " ^
(mbtoutf8 state
.path);
6595 opendoc state
.path state
.password;
6599 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
6600 Sys.set_signal
Sys.sighup
(Sys.Signal_handle
(fun _ -> reload ()));
6603 match Unix.waitpid
[Unix.WNOHANG
] ~
-1 with
6604 | (exception (Unix.Unix_error
(Unix.ECHILD
, _, _))) -> ()
6605 | (exception exn
) -> dolog
"Unix.waitpid: %s" @@ exntos exn
6607 | _pid
, _status
-> reap ()
6609 Sys.set_signal
Sys.sigchld
(Sys.Signal_handle
(fun _ -> doreap := true));
6613 if nonemptystr
!rcmdpath
6614 then remoteopen !rcmdpath
6619 let rec loop deadline
=
6625 let r = [state
.ss; state
.wsfd] in
6629 | Some fd
-> fd
:: r
6633 state
.redisplay
<- false;
6640 if deadline
= infinity
6642 else max
0.0 (deadline
-. now)
6647 try Unix.select
r [] [] timeout
6648 with Unix.Unix_error
(Unix.EINTR
, _, _) -> [], [], []
6654 if state
.ghyll
== noghyll
6656 match state
.autoscroll
with
6657 | Some step
when step
!= 0 ->
6658 let y = state
.y + step
in
6659 let fy = if conf
.maxhfit
then state
.winh
else 0 in
6662 then state
.maxy - fy
6663 else if y >= state
.maxy - fy then 0 else y
6665 if state
.mode = View
6666 then gotoxy_and_clear_text state
.x y
6667 else gotoxy state
.x y;
6670 else deadline
+. 0.01
6675 let rec checkfds = function
6677 | fd
:: rest
when fd
= state
.ss ->
6678 let cmd = rcmd state
.ss in
6682 | fd
:: rest
when fd
= state
.wsfd ->
6686 | fd
:: rest
when Some fd
= !optrfd ->
6687 begin match remote fd
with
6688 | None
-> optrfd := remoteopen !rcmdpath;
6689 | opt -> optrfd := opt
6694 dolog
"select returned unknown descriptor";
6700 if deadline
= infinity
6704 match state
.autoscroll
with
6705 | Some step
when step
!= 0 -> deadline1
6706 | _ -> if state
.ghyll
== noghyll
then infinity
else deadline1
6711 match loop infinity
with
6713 Config.save leavebirdseye;
6714 if hasunsavedchanges
()
6716 | _ -> error
"umpossible - infinity reached"