File: tmkEntry.ml

package info (click to toggle)
ocaml-curses 1.0.2-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 328 kB
  • ctags: 869
  • sloc: ml: 2,832; ansic: 673; makefile: 140; sh: 10
file content (108 lines) | stat: -rw-r--r-- 3,218 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
open TmkStruct

(****************************************************************************************
 * La classe Entry
 ****************************************************************************************)

let real_class_entry = Class.create "Entry" [TmkWidget.real_class_widget]

class entry parent = object (self)
  inherit TmkWidget.widget as super

  val terminal = parent#terminal

  val mutable text = String.create 128
  val mutable text_length = 0
  val mutable text_offset = 0
  val mutable cursor = 0

  val mutable accept_key = function _ -> true

  method real_class = real_class_entry
  method parent = parent
  method terminal = terminal
  method can_focus = true

  method class_get_size _ =
    (2, 1)

  method class_draw () =
    super#class_draw ();
    Curses.wattrset window attribute;
    ignore (Curses.wmove window geometry.Geom.y geometry.Geom.x);
    Curses.whline window 32 geometry.Geom.w;
    ignore (Curses.waddnstr window text text_offset
      (min (text_length - text_offset) geometry.Geom.w));
    if self#has_focus then
      self#set_cursor (geometry.Geom.x + cursor - text_offset,
      geometry.Geom.y)

  method cursor = cursor

  method move_cursor pos =
    let pos = min (max pos 0) text_length in
    cursor <- pos;
    if cursor < text_offset || cursor >= text_offset + geometry.Geom.w then (
      text_offset <- max 0 (cursor - geometry.Geom.w / 2);
      self#queue_redraw ()
    );
    if self#has_focus then
      terminal#set_cursor
	(geometry.Geom.x + cursor - text_offset, geometry.Geom.y)

  method insert_string string =
    let len = String.length string in
    let lt = String.length text in
    if text_length + len > lt then (
      let rec aux t =
	if t >= text_length + len then t - lt
	else aux (t * 2) in
      let t = aux (lt * 2) in
      text <- text ^ (String.create t)
    );
    String.blit text cursor text (cursor + len) (text_length - cursor);
    String.blit string 0 text cursor len;
    text_length <- text_length + len;
    self#move_cursor (cursor + len);
    self#queue_redraw ()

  method delete pos len =
    if pos < 0 || pos + len > text_length then
      invalid_arg "Entry#delete";
    String.blit text (pos + len) text pos (text_length - pos - len);
    text_length <- text_length - len;
    if cursor > pos then
      self#move_cursor (max pos (cursor - len));
    self#queue_redraw ()

  method class_key_event key =
    if key >= 32 && key <= 126 || key >= 160 && key <= 255 then (
      let char = char_of_int key in
      if accept_key char then
    	let string = String.make 1 char in
	self#insert_string string
      else
	ignore (Curses.beep ());
      true
    ) else if key = Curses.Key.right then (
      self#move_cursor (succ cursor);
      true
    ) else if key = Curses.Key.left then (
      self#move_cursor (pred cursor);
      true
    ) else if key = Curses.Key.backspace then (
      if cursor > 0 then
	self#delete (pred cursor) 1;
      true
    ) else if key = Curses.Key.dc then (
      if cursor < text_length then
	self#delete cursor 1;
      true
    ) else
      super#class_key_event key

  initializer
    parent#add self#coerce;
    String.blit "foobar" 0 text 0 6;
    text_length <- 6
end