6 let sh = float (maxy
+ !S.winh
) /. float !S.winh
in
7 let sh = float !S.winh
/. sh in
8 let sh = max
sh (float conf
.scrollh
) in
10 let percent = float y
/. float maxy
in
11 let position = (float !S.winh
-. sh) *. percent in
14 if position +. sh > float !S.winh
15 then float !S.winh
-. sh
20 let isbirdseye = function
22 | Textentry _
| View
| LinkNav _
-> false
24 let istextentry = function
26 | Birdseye _
| View
| LinkNav _
-> false
29 if !S.uioh#alwaysscrolly
|| ((conf
.scrollb
land scrollbvv
!= 0)
30 && (!S.maxy
> !S.winh
))
37 else x
> !S.winw
- vscrollw ()
39 let firstof first active
=
40 if first
> active
|| abs
(first
- active
) > fstate
.maxrows
- 1
41 then max
0 (active
- (fstate
.maxrows
/2))
44 let calcfirst first active
=
47 let rows = active
- first
in
48 if rows > fstate
.maxrows
then active
- fstate
.maxrows
else first
52 let len = String.length
!S.text
in
53 let x0 = if conf
.leftscroll
then vscrollw () else 0 in
57 | Textentry _
| View
| LinkNav _
->
58 let h, _
, _
= !S.uioh#scrollpw
in
64 x
(float (!S.winh
- (fstate
.fontsize
+ 4) - hscrollh))
65 (x
+.w
) (float (!S.winh
- hscrollh))
68 let w = float (!S.winw
- 1 - vscrollw ()) in
69 if !S.progress
>= 0.0 && !S.progress
< 1.0
71 GlDraw.color
(0.3, 0.3, 0.3);
72 let w1 = w *. !S.progress
in
74 GlDraw.color
(0.0, 0.0, 0.0);
75 rect (float x0+.w1) (float x0+.w-.w1)
78 GlDraw.color
(0.0, 0.0, 0.0);
82 GlDraw.color
(1.0, 1.0, 1.0);
85 (if conf
.leftscroll
then x0 + 2 else x0 + if len > 0 then 8 else 2)
86 (!S.winh
- hscrollh - 5) s
;
90 | Textentry
((prefix
, text
, _
, _
, _
, _
), _
) ->
93 then Printf.sprintf
"%s%s_ [%s]" prefix text
!S.text
94 else Printf.sprintf
"%s%s_" prefix text
98 | Birdseye _
| View
| LinkNav _
-> !S.text
103 if not
(istextentry !S.mode
) && !S.uioh#eformsgs
105 let s1 = "(press 'e' to review error messages)" in
106 if nonemptystr
s then s ^
" " ^
s1 else s1
114 let textentrykeyboard
115 key mask
((c
, text
, opthist
, onkey
, ondone
, cancelonempty
), onleave
) =
118 S.mode
:= Textentry
(te
, onleave
);
120 postRedisplay
"textentrykeyboard enttext";
125 | Some
(action
, _
) ->
126 let te = (c
, action cmd
, opthist
, onkey
, ondone
, cancelonempty
) in
127 S.mode
:= Textentry
(te, onleave
);
128 postRedisplay
"textentry histaction"
131 let kt = Wsi.ks2kt key
in
132 match [@warning
"-fragile-match"] kt with
134 if emptystr text
&& cancelonempty
137 postRedisplay
"textentrykeyboard after cancel";
140 let s = withoutlastutf8 text
in
141 enttext (c
, s, opthist
, onkey
, ondone
, cancelonempty
)
146 postRedisplay
"textentrykeyboard after confirm"
148 | Up
-> histaction HCprev
149 | Down
-> histaction HCnext
150 | Home
-> histaction HCfirst
151 | End
-> histaction HClast
156 begin match opthist
with
158 | Some
(_
, onhistcancel
) -> onhistcancel
()
162 postRedisplay
"textentrykeyboard after cancel2"
164 else enttext (c
, E.s, opthist
, onkey
, ondone
, cancelonempty
)
168 | Insert
when Wsi.withshift mask
->
169 let s = getcmdoutput
(fun s ->
170 prerr_endline
("error pasting: " ^
s)) conf
.pastecmd
in
171 enttext (c
, s, opthist
, onkey
, ondone
, cancelonempty
)
173 | Code _
| Ascii _
->
174 begin match onkey text
kt with
178 postRedisplay
"textentrykeyboard after confirm2";
180 | TEcont text
-> enttext (c
, text
, opthist
, onkey
, ondone
, cancelonempty
);
184 postRedisplay
"textentrykeyboard after cancel3";
187 S.mode
:= Textentry
(te, onleave
);
188 postRedisplay
"textentrykeyboard switch";
190 | _
-> vlog
"unhandled key"
192 class type lvsource
=
194 method getitemcount
: int
195 method getitem
: int -> (string * int)
196 method hasaction
: int -> bool
197 method exit
: uioh
:uioh
->
203 method getactive
: int
204 method getfirst
: int
206 method getminfo
: (int * int) array
209 class virtual lvsourcebase
=
211 val mutable m_active
= 0
212 val mutable m_first
= 0
213 val mutable m_pan
= 0
214 method getactive
= m_active
215 method getfirst
= m_first
216 method getpan
= m_pan
217 method getminfo
: (int * int) array
= E.a
220 let coe s = (s :> uioh
)
221 let setuioh uioh
= S.uioh
:= coe uioh
223 let changetitle uioh
=
224 let title = uioh#
title in
225 Wsi.settitle
@@ if emptystr
title then "llpp" else title ^
" - llpp";
227 class listview ~zebra ~helpmode ~
(source
:lvsource
) ~trusted ~modehash
=
229 val m_pan
= source#getpan
230 val m_first
= source#getfirst
231 val m_active
= source#getactive
233 val m_prev_uioh
= !S.uioh
235 method private elemunder y
=
239 let n = y
/ (fstate
.fontsize
+1) in
240 if m_first
+ n < source#getitemcount
242 if source#hasaction
(m_first
+ n)
243 then Some
(m_first
+ n)
250 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
251 GlDraw.color
(0., 0., 0.) ~alpha
:0.85;
252 filledrect
0. 0. (float !S.winw
) (float !S.winh
);
253 GlDraw.color
(1., 1., 1.);
254 Gl.enable `texture_2d
;
255 let fs = fstate
.fontsize
in
257 let hw = !S.winw
/3 in
258 let ww = fstate
.wwidth
in
259 let tabw = 17.0*.ww in
260 let itemcount = source#getitemcount
in
261 let minfo = source#getminfo
in
265 GlMat.translate ~x
:(float conf
.scrollbw
) ();
267 let x0 = 0.0 and x1
= float (!S.winw
- conf
.scrollbw
- 1) in
269 if not
((row
- m_first
) > fstate
.maxrows
)
271 if row
>= 0 && row
< itemcount
273 let (s, level
) = source#getitem row
in
274 let y = (row
- m_first
) * nfs in
275 let x = 5.0 +. (float (level
+ m_pan
)) *. ww in
278 (let c = if row
land 1 = 0 then 1.0 else 0.92 in (c,c,c));
282 Gl.disable `texture_2d
;
283 let alpha = if source#hasaction row
then 0.9 else 0.3 in
284 GlDraw.color
(1., 1., 1.) ~
alpha;
285 linerect
(x0 +. 1.) (float (y + 1)) (x1
) (float (y + fs + 3));
286 Gl.enable `texture_2d
;
289 if zebra
&& row
land 1 = 1
293 GlDraw.color
(c,c,c);
294 let drawtabularstring s =
296 let x'
= truncate
(x0 +. x) in
297 let s1, s2
= splitatchar
s '
\000'
in
299 then Ffi.drawstr fs x'
(y+nfs) s
305 let s'
= withoutlastutf8
s in
306 let s = s' ^
Utf8syms.ellipsis
in
307 let w = Ffi.measurestr
fs s in
308 if float x'
+. w +. ww < float (hw + x'
)
313 if float x'
+. ww +. Ffi.measurestr
fs s1 > float (hw + x'
)
317 ignore
(Ffi.drawstr fs x'
(y+nfs) s1);
318 Ffi.drawstr fs (hw + x'
) (y+nfs) s2
322 let x = if helpmode
&& row
> 0 then x +. ww else x in
323 let s1, s2
= splitatchar
s '
\t'
in
326 let nx = drawstr x s1 in
328 let x = x +. (max
tabw sw) in
331 let len = String.length
s - 2 in
332 if len > 0 && s.[0] = '
\xc2'
&& s.[1] = '
\xb7'
334 let s = String.sub
s 2 len in
335 let x = if not helpmode
then x +. ww else x in
336 GlDraw.color
(1.2, 1.2, 1.2);
337 let vinc = Ffi.drawstr (fs+fs/4)
338 (truncate
(x -. ww)) (y+nfs) s in
339 GlDraw.color
(1., 1., 1.);
340 vinc +. (float fs *. 0.8)
344 ignore
(drawtabularstring s);
350 GlDraw.color
(1.0, 1.0, 1.0) ~
alpha:0.5;
353 if (row
- m_first
) <= fstate
.maxrows
355 if row
>= 0 && row
< itemcount
357 let (s, level
) = source#getitem row
in
358 let pos0 = Ne.index
s '
\000'
in
359 let y = (row
- m_first
) * nfs in
360 let x = float (level
+ m_pan
) *. ww in
361 let (first
, last
) = minfo.(row
) in
363 if pos0 > 0 && first
> pos0
364 then String.sub
s (pos0+1) (first
-pos0-1)
365 else String.sub
s 0 first
367 let suffix = String.sub
s first
(last
- first
) in
368 let w1 = Ffi.measurestr fstate
.fontsize
prefix in
369 let w2 = Ffi.measurestr fstate
.fontsize
suffix in
370 let x = x +. if conf
.leftscroll
then xadj else 5.0 in
371 let x = if pos0 > 0 && first
> pos0 then x +. float hw else x in
373 and y0
= float (y+2) in
375 and y1
= float (y+fs+3) in
376 filledrect
x0 y0
x1 y1
;
379 Gl.disable `texture_2d
;
380 if Array.length
minfo > 0 then loop m_first
;
385 method nextcurlevel incr
=
386 let len = source#getitemcount
in
388 if m_active
>= 0 && m_active
< len
389 then snd
(source#getitem m_active
)
399 let _, l
= source#getitem i
in
400 if l
<= curlevel then i
else flow (i
+incr
)
403 let active = flow (m_active
+incr
) in
404 let first = calcfirst m_first
active in
405 postRedisplay
"listview nextcurlevel";
406 {< m_active
= active; m_first
= first >}
408 method updownlevel incr
=
409 let len = source#getitemcount
in
411 if m_active
>= 0 && m_active
< len
412 then snd
(source#getitem m_active
)
419 if i
= -1 then 0 else
420 let _, l
= source#getitem i
in
421 if l
!= curlevel then i
else flow (i
+incr
)
424 let active = flow m_active
in
425 let first = calcfirst m_first
active in
426 postRedisplay
"listview updownlevel";
427 {< m_active
= active; m_first
= first >}
429 method private key1 key mask
=
430 let set1 active first qsearch
=
431 coe {< m_active
= active; m_first
= first; m_qsearch
= qsearch
>}
433 let search active pattern incr
=
434 let active = if active = -1 then m_first
else active in
437 if n >= 0 && n < source#getitemcount
439 let s, _ = source#getitem
n in
440 match Str.search_forward re
s 0 with
441 | exception Not_found
-> loop (n + incr
)
448 let qpat = Str.quote pattern
in
449 match Str.regexp_case_fold
qpat with
452 dolog
"regexp_case_fold for `%S' failed: %S\n" qpat @@
453 Printexc.to_string exn
;
456 let itemcount = source#getitemcount
in
457 let find start incr
=
459 if i
= -1 || i
= itemcount
462 if source#hasaction i
469 let set active first =
470 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
472 coe {< m_active
= active; m_first
= first; m_qsearch
= E.s >}
475 let isvisible first n = n >= first && n - first <= fstate
.maxrows
in
477 let incr1 = if incr
> 0 then 1 else -1 in
478 if isvisible m_first m_active
481 let next = m_active
+ incr
in
483 if next < 0 || next >= itemcount
487 if abs
(m_active
- next) > fstate
.maxrows
493 let first = m_first
+ incr
in
494 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
496 let next = m_active
+ incr
in
497 let next = bound
next 0 (itemcount - 1) in
504 if isvisible first next
511 let first = min
next m_first
in
513 if abs
(next - first) > fstate
.maxrows
519 let first = m_first
+ incr
in
520 let first = bound
first 0 (itemcount - 1) in
522 let next = m_active
+ incr
in
523 let next = bound
next 0 (itemcount - 1) in
524 let next = find next incr1 in
526 if next = -1 || abs
(m_active
- first) > fstate
.maxrows
528 let active = if m_active
= -1 then next else m_active
in
533 if isvisible first active
539 postRedisplay
"listview navigate";
543 let kt = Wsi.ks2kt key
in
544 match [@warning
"-fragile-match"] kt with
545 | Ascii
(('r'
|'
s'
) as c) when Wsi.withctrl mask
->
546 let incr = if c = 'r'
then -1 else 1 in
548 match search (m_active
+ incr) m_qsearch
incr with
550 S.text
:= m_qsearch ^
" [not found]";
554 active, firstof m_first
active
556 postRedisplay
"listview ctrl-r/s";
557 set1 active first m_qsearch
;
559 | Insert
when Wsi.withctrl mask
->
560 if m_active
>= 0 && m_active
< source#getitemcount
562 let s, _ = source#getitem m_active
in
563 selstring conf
.selcmd
s;
568 if emptystr m_qsearch
571 let qsearch = withoutlastutf8 m_qsearch
in
575 postRedisplay
"listview empty qsearch";
576 set1 m_active m_first
E.s;
580 match search m_active
qsearch ~
-1 with
582 S.text
:= qsearch ^
" [not found]";
586 active, firstof m_first
active
588 postRedisplay
"listview backspace qsearch";
589 set1 active first qsearch
592 | Ascii
_ | Code
_ ->
594 match [@warning
"-partial-match"] kt with
595 | Ascii
c -> String.make
1 c
596 | Code code
-> Ffi.toutf8 code
598 let pattern = m_qsearch ^
utf8 in
600 match search m_active
pattern 1 with
602 S.text
:= pattern ^
" [not found]";
606 active, firstof m_first
active
608 postRedisplay
"listview qsearch add";
609 set1 active first pattern;
613 if emptystr m_qsearch
615 postRedisplay
"list view escape";
617 let mx, my = state.mpos in
620 Option.value ~default
:m_prev_uioh
@@
621 source#exit ~uioh
:(coe self
) ~cancel
:true ~
active:m_active
622 ~
first:m_first ~pan
:m_pan
625 postRedisplay
"list view kill qsearch";
626 coe {< m_qsearch
= E.s >}
631 let self = {< m_qsearch
= E.s >} in
633 postRedisplay
"listview enter";
634 let cancel = not
(m_active
>= 0 && m_active
< source#getitemcount
) in
635 source#exit ~uioh
:(coe self) ~
cancel
636 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
638 Option.value ~default
:m_prev_uioh
opt
643 | Prior
-> navigate ~
-(fstate
.maxrows
)
644 | Next
-> navigate fstate
.maxrows
648 postRedisplay
"listview right";
649 coe {< m_pan
= m_pan
- 1 >}
653 postRedisplay
"listview left";
654 coe {< m_pan
= m_pan
+ 1 >}
657 let active = find 0 1 in
658 postRedisplay
"listview home";
662 let first = max
0 (itemcount - fstate
.maxrows
) in
663 let active = find (itemcount - 1) ~
-1 in
664 postRedisplay
"listview end";
669 method key key mask
=
672 textentrykeyboard key mask
te;
674 | Birdseye
_ | View
| LinkNav
_ -> self#key1 key mask
676 method button button down
x y _ =
679 | 1 when vscrollhit x ->
680 postRedisplay
"listview scroll";
683 let _, position, sh = self#
scrollph in
684 if y > truncate
position && y < truncate
(position +. sh)
686 S.mstate
:= Mscrolly
;
690 let s = float (max
0 (y - conf
.scrollh
)) /. float !S.winh
in
691 let first = truncate
(s *. float source#getitemcount
) in
692 let first = min source#getitemcount
first in
693 Some
(coe {< m_first
= first; m_active
= first >})
699 begin match self#elemunder
y with
701 postRedisplay
"listview click";
702 source#exit ~uioh
:(coe {< m_active
= n >})
703 ~
cancel:false ~
active:n ~
first:m_first ~pan
:m_pan
704 | _ -> Some
(coe self)
706 | n when (n == 4 || n == 5) && not down
->
707 let len = source#getitemcount
in
709 if n = 5 && m_first
+ fstate
.maxrows
>= len
712 let first = m_first
+ (if n == 4 then -1 else 1) in
713 bound
first 0 (len - 1)
715 postRedisplay
"listview wheel";
716 Some
(coe {< m_first
= first >})
717 | n when (n = 6 || n = 7) && not down
->
718 let inc = if n = 7 then -1 else 1 in
719 postRedisplay
"listview hwheel";
720 Some
(coe {< m_pan
= m_pan
+ inc >})
721 | _ -> Some
(coe self)
723 Option.value ~default
:m_prev_uioh
opt
725 method multiclick
_ x y = self#button
1 true x y
730 let s = float (max
0 (y - conf
.scrollh
)) /. float !S.winh
in
731 let first = truncate
(s *. float source#getitemcount
) in
732 let first = min source#getitemcount
first in
733 postRedisplay
"listview motion";
734 coe {< m_first
= first; m_active
= first >}
743 if x < !S.winw
- conf
.scrollbw
746 match self#elemunder
y with
747 | None
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
; m_active
748 | Some
n -> Wsi.setcursor
Wsi.CURSOR_INFO
; n
752 then (postRedisplay
"listview pmotion"; {< m_active
= n >})
757 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
761 method infochanged
_ = ()
763 method scrollpw
= (0, 0.0, 0.0)
765 let nfs = fstate
.fontsize
+ 1 in
766 let y = m_first
* nfs in
767 let itemcount = source#getitemcount
in
768 let maxi = max
0 (itemcount - fstate
.maxrows
) in
769 let maxy = maxi * nfs in
770 let p, h = scrollph y maxy in
773 method modehash
= modehash
774 method eformsgs
= false
775 method alwaysscrolly
= true
780 let len = source#getitemcount
in
782 if dy
> 0 && m_first
+ fstate
.maxrows
>= len
785 let first = m_first
+ dy
/ 10 in
786 bound
first 0 (len - 1)
788 postRedisplay
"listview wheel";
789 {< m_first
= first >}
795 method zoom
_ _ _ = ()