Advice on clist

Serge Le Huitouze <[email protected]> Tue, 16 Nov 2010 12:28:00 +0100
Newsgroups gmane.comp.lang.ocaml.lib.gtk
Message-ID <[email protected]>
Hi there,

I'm willing to code a widget akin to multi-file selection.
After a lot of fiddling with lablgtk2 (and gtk) documentation, I finally
got something that seems to work.
I thought I'd take the liberty to post my small code (based on
Maxence Guesdon's "clist.ml" example in lablgtk's distribution) to
seek advice from you gurus!

It's very easy to try:
Just compile it:
  ocamlc -I +lablgtk2 -o ex_clist lablgtk.cma gtkInit.cmo ex_clist.ml
Then run it:
  ./ex_clist
You can add an entry (eventually, there will be a file-selection widget here),
remove the selected entry (if such exists) or clear all entries (if you have
at least one).

I'd like to have some feedback to know if that's the way one should write
such code.
In particular, am I right in managing the selected row by myself?
IIUC, there is no way to get the selected row from a clist, one has to do
it oneself by catching callback "select_row" and "unselect_row"...
[In contrast, I don't need to manage myself the number of rows, that I can
directly access via the "rows" method.]


Also, any stylistic remark (be it lablgtk or Ocaml oriented) is welcome!

Thanks for your time.

--Serge

---- START OF PROGRAM ------
open StdLabels
open GMain

let main () =
  let window = GWindow.window ~title:"Multifile" ~width:300 ~height:150 () in
  ignore (window#connect#destroy ~callback:Main.quit);

  let vbox = GPack.vbox ~border_width:5 ~packing:window#add () in
  let hbox = GPack.hbox ~packing:vbox#add () in
  let sb = GRange.scrollbar `VERTICAL ~packing:(hbox#pack ~from:`END) () in
  let clist = GList.clist ~titles:["_ENTRIES_"] ~shadow_type:`OUT
                          ~packing:hbox#add ~vadjustment:sb#adjustment () in

  (* Layout all the buttons before defining clist's callback to allow
   *  for enabling/disabling some of them *)
  let hbox = GPack.hbox ~packing:vbox#pack () in
  let button_add = GButton.button ~label:"Add entry" ~packing:hbox#add () in
  let button_remove = GButton.button ~label:"Remove" ~packing:hbox#add () in
  let button_clear = GButton.button ~label:"Clear" ~packing:hbox#add () in

  let curSelectedRow = ref None in
  let unselectRow () = curSelectedRow := None in
  let getSelectedRow () = match !curSelectedRow with None -> 0 | Some r -> r in

  let updateButtonsStatus () =
    begin
      button_clear#misc#set_sensitive (clist#rows != 0);
      button_remove#misc#set_sensitive (match !curSelectedRow with
None -> false | _ -> true)
    end in

  ignore (clist#connect#select_row ~callback:
    begin fun ~row ~column ~event ->
      curSelectedRow := Some row;
      updateButtonsStatus ()
    end);

  ignore (clist#connect#unselect_row ~callback:
    begin fun ~row ~column ~event ->
      unselectRow ();
      updateButtonsStatus ()
    end);

  let globalAddCnt = ref 0 in
  ignore (button_add#connect#clicked ~callback:
    begin fun () ->
      Printf.printf "A file-selection widget should be used\n";
      flush stdout;
      let new_entry =  Printf.sprintf "entry%d" !globalAddCnt in
      globalAddCnt := !globalAddCnt + 1;
      ignore (clist#append [new_entry]);
      updateButtonsStatus ()
    end);

  ignore (button_remove#connect#clicked ~callback:
    begin fun () ->
      clist#remove (getSelectedRow ());
      unselectRow ();
      updateButtonsStatus ()
    end);

  ignore (button_clear#connect#clicked ~callback:
    begin fun () ->
      clist#clear ();
      unselectRow ();
      updateButtonsStatus ()
    end);

  window#show ();
  updateButtonsStatus ();
  Main.main ()

let _ = main ()
---- END OF PROGRAM ------