Re: Pixbuf column for a tree custom model
Maxence Guesdon <[email protected]> Mon, 5 Jul 2010 20:48:12 +0200
| Newsgroups | gmane.comp.lang.ocaml.lib.gtk |
|---|---|
| Message-ID | <[email protected]> |
Le Mon, 5 Jul 2010 14:56:43 +0400, Dmitry Bely <[email protected]> a écrit : > Hi Maxence, > > Thanks a lot but that's not what I need. You describe how to create a > Gtk list store that holds pixbuf data; I know that. But my question > was about the custom model Oups, sorry, I read too fast. I made an attempt to modify the example custom_tree_generic.ml. Here is a modified version where I managed to display a pixbuf in an additional column, but I get warning about incompatible types: (ocaml:3769): GLib-GObject-WARNING **: unable to set property `pixbuf' of type `GdkPixbuf' from value of type `Caml' I may have missed something. The custom_tree_generic.ml example works fine on my system (but I had to make clean lablgtk to prevent some problem with ml_gtk_tree_....._visible_range). Hope this helps, Maxence > (http://www.tupelo-schneck.org/robert/custom-model), now integrated > into Lablgtk. There are some examples in Lablgtk distribution > (examples/custom_*.ml) with a custom_value method like > > method custom_value (t:Gobject.g_type) (row:custom_tree) ~column = > if column = 0 then `CAML (Obj.repr row) > else if column = 1 then > `BOOL (match row with File {finfo={fchecked=b}} -> b > | _ -> false ) > else if column = 2 then > `INT (5+(get_nb row)) > else assert false > > It illustrates that returning basic Ocaml types is trivial. But how to > return pixbuf? It's not clear to me. > > - Dmitry Bely > > BTW, custom_tree_generic.ml example does not work in my system. What > about you? > > On Mon, Jul 5, 2010 at 2:13 PM, Maxence Guesdon > <[email protected]> wrote: > > Le Mon, 5 Jul 2010 11:02:17 +0400, > > Dmitry Bely <[email protected]> a écrit : > > > >> Hello, > > > > Hello, > > > >> > >> How to return GdkPixbuf.pixbuf from a user-defined method > >> custom_get_value (custom_tree_model_type)? Probably it should be > >> `POINTER but I fail to see how to construct it from a pixbuf. Any > >> hints are greatly appreciated. > > > > You may hav a look at the Gmytree module included in cameleon2: > > http://svn.gna.org/viewcvs/cameleon/trunk/src/utils/gmytree.ml?rev=749&view=markup > > > > It gives a way to define a tree with a description of the columns. > > For a use case, you may look at > > http://svn.gna.org/viewcvs/cameleon/trunk/src/editor/ed_odoc.ml?rev=749&view=markup > > (in class view) > > > > The important part of Gmytree is; > > > > ... > > let tcols = new GTree.column_list in > > let disp_cols = List.map > > (function > > `String _ -> > > `String (tcols#add Gobject.Data.string) > > | `Pixmap _ -> > > `Pixbuf (tcols#add (Gobject.Data.gobject : > > GdkPixbuf.pixbuf Gobject.data_conv)) ) cols > > in > > let (datacol : 'a GTree.column) = tcols#add Gobject.Data.caml in > > let store = GTree.tree_store tcols in > > let view = GTree.view > > ~headers_visible: false > > ~model: store ~packing: wscroll#add_with_viewport () in > > let renderer = GTree.cell_renderer_text [] in > > let pix_renderer = GTree.cell_renderer_pixbuf [] in > > let _ = > > List.iter > > (fun c -> > > let col = > > match c with > > `String c -> GTree.view_column () ~renderer: (renderer, > > ["text", c]) | `Pixbuf c -> GTree.view_column () ~renderer: > > (pix_renderer, ["pixbuf",c]) in > > ignore (view#append_column col) > > ) > > disp_cols > > in > > ... > > > > Hope this helps, > > > > Maxence > > > > > > _______________________________________________ > > Lablgtk mailing list > > [email protected] > > http://yquem.inria.fr/cgi-bin/mailman/listinfo/lablgtk > > > > _______________________________________________ > Lablgtk mailing list > [email protected] > http://yquem.inria.fr/cgi-bin/mailman/listinfo/lablgtk _______________________________________________ Lablgtk mailing list [email protected] http://yquem.inria.fr/cgi-bin/mailman/listinfo/lablgtk
custom_tree_generic2.ml
(text/x-ocaml, 8.9 KB)
(**************************************************************************)
(* Lablgtk - Examples *)
(* *)
(* There is no specific licensing policy, but you may freely *)
(* take inspiration from the code, and copy parts of it in your *)
(* application. *)
(* *)
(**************************************************************************)
(* ../src/lablgtk2 -localdir custom_tree_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(TREE:sig type t
val sons: t -> t array
val custom_value: Gobject.g_type -> t -> column:int -> Gobject.basic
val column_list:GTree.column_list
end) =
struct
type custom_tree =
{finfo: TREE.t;
mutable sons: custom_tree array;
mutable parent: custom_tree option;
fidx: int (* invariant: parent.(fidx)==myself *) }
let inbound i a = i>=0 && i<Array.length a
(** The custom model itself *)
class custom_tree_class column_list =
object (self)
inherit
[custom_tree,custom_tree,unit,unit] GTree.custom_tree_model column_list
method custom_encode_iter cr = cr, (), ()
method custom_decode_iter cr () () = cr
val mutable num_roots : int = 0
val mutable roots : custom_tree array = [||]
method custom_get_iter (path:Gtk.tree_path) : custom_tree option =
let indices: int array = GTree.Path.get_indices path in
match indices with
| [||] ->
None
| _ ->
if inbound indices.(0) roots then
let result = ref (roots.(indices.(0))) in
try
for depth=1 to Array.length indices - 1 do
let index = indices.(depth) in
if inbound index !result.sons then
result:=!result.sons.(index)
else raise Not_found
done;
Some !result
with Not_found ->
None
else None
method custom_get_path (row:custom_tree) : Gtk.tree_path =
let current_row = ref row in
let path = ref [] in
while !current_row.parent <> None do
path := !current_row.fidx::!path;
current_row := match !current_row.parent with Some p -> p
| None -> assert false
done;
GTree.Path.create ((!current_row.fidx)::!path)
method custom_value (t:Gobject.g_type) (row:custom_tree) ~column =
TREE.custom_value t row.finfo ~column
method custom_iter_next (row:custom_tree) : custom_tree option =
let nidx = succ row.fidx in
match row.parent with
| None -> if inbound nidx roots then Some roots.(nidx)
else None
| Some parent ->
if inbound nidx parent.sons then
Some parent.sons.(nidx)
else None
method custom_iter_children (rowopt:custom_tree option) :custom_tree option =
match rowopt with
| None -> if inbound 0 roots then Some roots.(0) else None
| Some row -> if inbound 0 row.sons then Some row.sons.(0) else None
method custom_iter_has_child (row:custom_tree) : bool =
Array.length row.sons > 0
method custom_iter_n_children (rowopt:custom_tree option) : int =
match rowopt with
| None -> Array.length roots
| Some row -> Array.length row.sons
method custom_iter_nth_child (rowopt:custom_tree option) (n:int)
: custom_tree option =
match rowopt with
| None when inbound n roots -> Some roots.(n)
| Some row when inbound n row.sons -> Some (row.sons.(n))
| _ -> None
method custom_iter_parent (row:custom_tree) : custom_tree option =
row.parent
method append_tree (t:TREE.t) =
let rec make_forest root sons =
Array.mapi
(fun i t -> let result = {finfo=t; fidx=i; parent = Some root;
sons = [||] }
in
let sons = make_forest result (TREE.sons t) in
result.sons<-sons;
result)
sons
in
let pos = num_roots in
num_roots <- num_roots+1;
let root = { finfo = t; sons = [||];
parent = None;
fidx = pos }
in
let sons = make_forest root (TREE.sons t)
in
root.sons <- sons;
roots <-
Array.init num_roots (fun n -> if n = num_roots - 1 then root
else roots.(n))
end
let custom_tree () =
new custom_tree_class TREE.column_list
end
let pix_size = 16
let pix =
let f file =
GdkPixbuf.from_file_at_size file ~width: pix_size ~height: pix_size
in
f Sys.argv.(1)
module T=struct
type leaf = {mutable checked: bool; mutable lname: string; }
type t = Leaf of leaf | Node of string* t list
let sons t = match t with
| Leaf _ -> [||]
| Node (_,s)-> Array.of_list s
(** The columns in our custom model *)
let column_list = new GTree.column_list ;;
let col_file = (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 col_is_leaf = column_list#add Gobject.Data.boolean;;
let col_pb = (column_list#add Gobject.Data.caml: GdkPixbuf.pixbuf GTree.column);;
let custom_value _ t ~column =
match column with
| 0 -> (* col_file *) `CAML (Obj.repr t)
| 1 -> (* col_bool *) `BOOL false
| 2 -> (* col_int *) `INT 0
| 3 -> (* col_is_leaf*) `BOOL (match t with Leaf _ -> true | _ -> false)
| 4 -> (* col_pb *) `CAML (Obj.repr pix)
| _ -> assert false
end
module MODEL=MAKE(T)
let nb = ref 0
let make_tree n p =
let rec aux p0 =
if p=p0 then
begin
incr nb;
T.Leaf {T.lname = "Leaf "^string_of_int !nb; checked = false}
end
else begin
incr nb;
let name = "Node "^string_of_int !nb in
T.Node (name,aux_list n (succ p0))
end
and aux_list n p =
if n = 0 then []
else aux p::aux_list (n-1) p
in
aux 0
let fill_model t =
for i = 0 to 10000 do
t#append_tree (make_tree 1 1)
done
let create_view_and_model () : GTree.view =
let custom_tree = MODEL.custom_tree () in
fill_model custom_tree;
let view = GTree.view ~fixed_height_mode:true ~model:custom_tree () in
let renderer = GTree.cell_renderer_text [] in
let col_name = GTree.view_column ~title:"Name" ~renderer:(renderer,[]) () in
col_name#set_sizing `FIXED;
col_name#set_fixed_width 150;
col_name#set_cell_data_func
renderer
(fun model row ->
try
let data = model#get ~row ~column:T.col_file in
match data with
| T.Leaf {T.lname = s} | T.Node (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"
~renderer:(renderer,["visible", T.col_is_leaf])
()
in
col_tog#set_sizing `FIXED;
col_tog#set_fixed_width 10;
col_tog#set_cell_data_func
renderer
(fun model row ->
try
let data = model#get ~row ~column:T.col_file in
match data with
| T.Leaf {T.checked = b} -> 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_tree#custom_get_iter path in
match row with
| Some {MODEL.finfo=T.Leaf l} ->
l.T.checked <- not l.T.checked
| _ -> ()));
ignore (view#append_column col_tog);
let pix_renderer = GTree.cell_renderer_pixbuf [] in
let col_pb = GTree.view_column () ~renderer: (pix_renderer, ["pixbuf",T.col_pb]) in
col_pb#set_sizing `FIXED;
col_pb#set_fixed_width 16;
col_pb#set_cell_data_func
pix_renderer
(fun model row ->
try
pix_renderer#set_properties [ `PIXBUF pix ]
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_pb);
view
let _ =
ignore (GtkMain.Main.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 ();
GtkMain.Main.main ()