File: custom_list_generic.ml

package info (click to toggle)
lablgtk3 3.1.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,796 kB
  • sloc: ml: 40,890; ansic: 22,312; makefile: 133; sh: 17
file content (184 lines) | stat: -rw-r--r-- 5,868 bytes parent folder | download | duplicates (3)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
(**************************************************************************)
(*    Lablgtk - Examples                                                  *)
(*                                                                        *)
(*    This code is in the public domain.                                  *)
(*    You may freely copy parts of it in your application.                *)
(*                                                                        *)
(**************************************************************************)

(* ../src/lablgtk2 -localdir custom_list_generic.ml *)

let debug = false
let () = 
  if debug then begin 
  Gc.set { (Gc.get()) with Gc.verbose = 0x00d; space_overhead = 0 };
  ignore (Gc.create_alarm (fun () -> 
  let s = Gc.stat () in
  Format.printf "blocks=%d words=%d@."
  s.Gc.live_blocks
  s.Gc.live_words))
  end



module MAKE(A:sig type t 
                     val custom_value: Gobject.g_type -> t -> column:int -> Gobject.basic
                     val column_list:GTree.column_list
	    end) = 
struct
  type custom_list =
      {finfo: A.t; 
       fidx: int (* invariant: root.(fidx)==myself *) }
        
  module H = Hashtbl

  let inbound i a = i>=0 && i<Array.length a
    
  (** The custom model itself *)
  class custom_list_class column_list =
  object (self)
    inherit 
      [custom_list,custom_list,unit,unit] GTree.custom_tree_model column_list

    method custom_encode_iter cr = cr, (), ()
    method custom_decode_iter cr () () = cr

    val mutable last_idx = 0
    val mutable roots : (int,custom_list) H.t = H.create 19
    method private find_opt i = 
      try Some (H.find roots i) with Not_found -> None
    method custom_flags = [`LIST_ONLY]
    method custom_get_iter (path:Gtk.tree_path) : custom_list option =
      let indices: int array  = GTree.Path.get_indices path in
      match indices with
      | [||] ->      
          None
      | [|i|] -> self#find_opt i
      | _ -> failwith "Invalid Path of depth > 1 in a list"

    method custom_get_path (row:custom_list) : Gtk.tree_path =
      GTree.Path.create [row.fidx]

    method custom_value (t:Gobject.g_type) (row:custom_list) ~column =
      A.custom_value t row.finfo ~column

    method custom_iter_next (row:custom_list) : custom_list option =
      let nidx = succ row.fidx in
	self#find_opt nidx
	  
    method custom_iter_children (rowopt:custom_list option) :custom_list option =
      match rowopt with
      | None -> self#find_opt 0
      | Some _ -> None

    method custom_iter_has_child (row:custom_list) : bool = false

    method custom_iter_n_children (rowopt:custom_list option) : int =
      match rowopt with
      | None -> H.length roots
      | Some _ -> assert false

    method custom_iter_nth_child (rowopt:custom_list option) (n:int) 
      : custom_list option =
      match rowopt with
      | None -> self#find_opt n
      | _ -> None 

    method custom_iter_parent (row:custom_list) : custom_list option = None

    method insert (t:A.t) =
      let e = {finfo=t; fidx= last_idx } in
      self#custom_row_inserted (GTree.Path.create [last_idx]) e;
      H.add roots last_idx e;
      last_idx <- last_idx+1;

  end

  let custom_list () = 
    new custom_list_class A.column_list
end

module L=struct
  type t = {mutable checked: bool; mutable lname: string; }

  (** The columns in our custom model *)
  let column_list = new GTree.column_list ;;
  let col_full = (column_list#add Gobject.Data.caml: t GTree.column);;
  let col_bool = column_list#add Gobject.Data.boolean;;
  let col_int = column_list#add Gobject.Data.int;;
 

  let custom_value _ t ~column = 
    match column with
    | 0 -> (* col_full *) `CAML (Obj.repr t)
    | 1 -> (* col_bool *) `BOOL false
    | 2 -> (* col_int *) `INT 0
    | _ -> assert false

end

module MODEL=MAKE(L)

let fill_model t =
  for i= 0 to 10 do
    t#insert {L.lname = "Elt "^string_of_int i; checked=i mod 2 = 0}
  done

let create_view_and_model () : GTree.view =
  let custom_list = MODEL.custom_list () in
  fill_model custom_list;
  let view = GTree.view ~model:custom_list () in
  let renderer = GTree.cell_renderer_text [] in
  let col_name = GTree.view_column ~title:"Name" ~renderer:(renderer,[]) () in
  col_name#set_cell_data_func 
    renderer
    (fun model row -> 
       try
	 let data = model#get ~row ~column:L.col_full in
	 match data with 
	 | {L.lname = s} -> 
	     renderer#set_properties [ `TEXT s ];
       with exn -> 
	 let s = GtkTree.TreePath.to_string (model#get_path row) in
	 Format.printf "Accessing %s, got '%s' @." s (Printexc.to_string exn));
  ignore (view#append_column col_name);
  
  let renderer = GTree.cell_renderer_toggle [] in
  let col_tog = GTree.view_column ~title:"Check me" 
    ~renderer:(renderer,[])
    ()
  in
  col_tog#set_cell_data_func 
    renderer
    (fun model row -> 
       try
	 let {L.checked = b} = model#get ~row ~column:L.col_full in
         renderer#set_properties [ `ACTIVE b ]
       with exn -> 
	 let s = GtkTree.TreePath.to_string (model#get_path row) in
	 Format.printf "Accessing %s, got '%s' @." s (Printexc.to_string exn));
  
  ignore(renderer#connect#toggled 
           (fun path -> 
              let row = custom_list#custom_get_iter path in
              match row with 
              | Some {MODEL.finfo=l} -> 
                  l.L.checked <- not l.L.checked
              | _ -> ()));
  ignore (view#append_column col_tog);
  Glib.Timeout.add ~ms:10000 ~callback:(fun () -> 
					 fill_model custom_list; false);
  view

let _ =
  GMain.init ();
  let window = GWindow.window ~width:200 ~height:400 () in
  ignore 
    (window#event#connect#delete 
       ~callback:(fun _ -> exit 0));
  let scrollwin = GBin.scrolled_window ~packing:window#add () in
  let view = create_view_and_model () in
  scrollwin#add view#coerce;
  window#show ();
  GMain.main ()