123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)type('a,'b)column=?title:string->'blist->('a->'blist)->GTree.view_columnclasstypevirtual['a]custom=objectinherit['a,'a,unit,unit]GTree.custom_tree_modelmethodreload:unitendclasstype['a]columns=objectmethodview:GTree.view(** the tree *)methodscroll:GBin.scrolled_window(** scrolled tree (build on demand) *)methodcoerce:GObj.widget(** widget of the scroll *)methodpack:(GObj.widget->unit)->unit(** packs the scroll *)methodreload:unit(** Structure has changed *)methodupdate_all:unit(** (only) Content of rows has changed *)methodupdate_row:'a->unitmethodinsert_row:'a->unitmethodset_focus:'a->GTree.view_column->unitmethodon_click:('a->GTree.view_column->unit)->unitmethodon_right_click:('a->GTree.view_column->unit)->unitmethodon_double_click:('a->GTree.view_column->unit)->unitmethodset_selection_mode:Gtk.Tags.selection_mode->unitmethodon_selection:(unit->unit)->unitmethodcount_selected:intmethoditer_selected:('a->unit)->unitmethodis_selected:'a->boolmethodadd_column_text:('a,GTree.cell_properties_text)columnmethodadd_column_pixbuf:('a,GTree.cell_properties_pixbuf)columnmethodadd_column_toggle:('a,GTree.cell_properties_toggle)columnmethodadd_column_empty:GTree.view_column(** Add an empty column that always appears after the columns created
by the other [add_column] methods. *)endclasstype['a]listmodel=objectmethodreload:unitmethodsize:intmethodindex:'a->intmethodget:int->'aendclasstype['a]treemodel=objectmethodreload:unitmethodhas_child:'a->boolmethodchildren:'aoption->intmethodchild_at:'aoption->int->'amethodparent:'a->'aoptionmethodindex:'a->intend(* -------------------------------------------------------------------------- *)(* --- Columns --- *)(* -------------------------------------------------------------------------- *)letadd_column(view:GTree.view)emptydata?titlerendererrender=beginletcolumn=GTree.view_column?title~renderer:(renderer,[])()incolumn#set_resizabletrue;(* column#set_sizing `FIXED ; *)column#set_cell_data_funcrenderer(funmodeliter->letprops=matchdata(model#get_pathiter)with|None->[]|Somee->rendereinrenderer#set_propertiesprops);ignore(view#append_columncolumn);beginmatchemptywith|None->()|Somee->ignore(view#move_columne~after:column)end;columnendclass['a]makecolumns?packing?width?height(view:GTree.view)(model:'a#custom)=object(self)valmutablescroll=Noneinitializermatchpackingwith|Somepacking->self#packpacking|None->()methodscroll=matchscrollwith|None->lets=GBin.scrolled_window?width?height()ins#addview#coerce;scroll<-Somes;s|Somes->smethodpackpacking=packingself#scroll#coercemethodview=viewmethodcoerce=self#scroll#coercemethodupdate_all=GtkBase.Widget.queue_drawview#as_tree_viewmethodupdate_rowx=try(*TODO : get the rectangle for raw and use queue_draw_area
See : http://www.gtkforums.com/viewtopic.php?t=1716
Sadly this is not available in LablGtk2 yet...*)model#custom_row_changed(model#custom_get_pathx)xwithNot_found->()methodinsert_rowx=tryletpath=model#custom_get_pathxinmodel#custom_row_insertedpathxwithNot_found->()methodreload=begin(* Delete all nodes in view *)letroot=GTree.Path.create[0]inmodel#foreach(fun_p_i->(* Do not use p since the path is changed by the call
to custom_row_deleted*)model#custom_row_deletedroot;false);(* Then call model *)model#reload;endmethodon_right_clickf=letcallbackevt=letopenGdkEventinifButton.buttonevt=3thenbeginletx=int_of_float(Button.xevt)inlety=int_of_float(Button.yevt)inmatchview#get_path_at_pos~x~ywith|Some(path,col,_,_)->beginmatchmodel#custom_get_iterpathwith|None->false|Someitem->let()=fitemcolinfalseend|_->falseendelsefalseinignore(view#event#connect#button_release~callback)methodon_clickf=letcallback()=matchview#get_cursor()with|Somepath,Somecol->beginmatchmodel#custom_get_iterpathwith|None->()|Someitem->fitemcolend|_->()inignore(view#connect#cursor_changed~callback)methodon_double_clickf=letcallbackpathcol=matchmodel#custom_get_iterpathwith|None->()|Someitem->fitemcolinignore(view#connect#row_activated~callback)methodis_selecteditem=tryview#selection#path_is_selected(model#custom_get_pathitem)withNot_found->falsemethodon_selectionf=ignore(view#selection#connect#changed~callback:f)methodset_selection_mode=view#selection#set_modemethodcount_selected=view#selection#count_selected_rowsmethoditer_selectedf=List.iter(funp->matchmodel#custom_get_iterpwith|None->()|Someitem->fitem)view#selection#get_selected_rowsmethodset_focusitemcol=tryletpath=model#custom_get_pathiteminview#scroll_to_cellpathcol;view#selection#select_pathpath;withNot_found->()valmutableempty:GTree.view_columnoption=Nonemethodadd_column_text?titlepropsrender=letcell=GTree.cell_renderer_textpropsinadd_columnviewemptymodel#custom_get_iter?titlecellrendermethodadd_column_pixbuf?titlepropsrender=letcell=GTree.cell_renderer_pixbufpropsinadd_columnviewemptymodel#custom_get_iter?titlecellrendermethodadd_column_toggle?titlepropsrender=letcell=GTree.cell_renderer_togglepropsinadd_columnviewemptymodel#custom_get_iter?titlecellrendermethodadd_column_empty=letcolumn=GTree.view_column~title:""()inempty<-Somecolumn;ignore(view#append_columncolumn);columnend(* -------------------------------------------------------------------------- *)(* --- Gtk List Model --- *)(* -------------------------------------------------------------------------- *)class['a]glist_model(m:'alistmodel)=objectmethodreload=m#reloadinherit['a,'a,unit,unit]GTree.custom_tree_model(newGTree.column_list)method!custom_flags=[`LIST_ONLY]methodcustom_decode_itera()()=amethodcustom_encode_itera=(a,(),())methodcustom_get_iterpath=letidx:intarray=GtkTree.TreePath.get_indicespathinmatchidxwith|[||]->None|[|i|]->(trylete=m#getiinSomeewithNot_found->None)|_->failwith"Invalid path of depth>1 in a list"methodcustom_get_pathe=GtkTree.TreePath.create[m#indexe]methodcustom_value(_:Gobject.g_type)(_:'a)~column:_=failwith"GwList: empty columns"methodcustom_iter_childrene=matchewith|Nonewhen(m#size>0)->Some(m#get0)|_->Nonemethodcustom_iter_has_child(_:'a)=falsemethodcustom_iter_n_children=function|Some_->failwith"GwList: no children"|None->m#sizemethodcustom_iter_nth_childrk=matchrwith|Some_->failwith"GwList: no nth-child"|None->ifk<m#sizethenSome(m#getk)elseNonemethodcustom_iter_parent(_:'a)=Nonemethodcustom_iter_nexte=letr=tryletk=succ(m#indexe)inifk<m#sizethenSome(m#getk)elseNonewithNot_found->Noneinrend(* -------------------------------------------------------------------------- *)(* --- Gtk List View --- *)(* -------------------------------------------------------------------------- *)class['a]list?packing?width?height?(headers=true)?(rules=true)(m:'alistmodel)=letmodel=newglist_modelminletview=GTree.view~model~headers_visible:headers~rules_hint:rules~show:true()inobjectinherit['a]makecolumns?packing?width?heightviewmodelend(* -------------------------------------------------------------------------- *)(* --- Gtk Tree Model --- *)(* -------------------------------------------------------------------------- *)letrecget_itermridxk=ifk>=Array.lengthidxthenrelseleta=m#child_atridx.(k)inget_iterm(Somea)idx(succk)letrecget_pathksma=letks=m#indexa::ksinmatchm#parentawith|None->ks|Someb->get_pathksmbclass['a]gtree_model(m:'atreemodel)=objectmethodreload=m#reloadinherit['a,'a,unit,unit]GTree.custom_tree_model(newGTree.column_list)methodcustom_decode_itera()()=amethodcustom_encode_itera=(a,(),())methodcustom_get_iterpath=letidx=GtkTree.TreePath.get_indicespathinifArray.lengthidx=0thenNoneelseleta=m#child_atNoneidx.(0)inget_iterm(Somea)idx1methodcustom_get_pathe=letks=get_path[]meinGtkTree.TreePath.createksmethodcustom_value(_:Gobject.g_type)(_:'a)~column:(_:int):Gobject.basic=Format.eprintf"Wtable.custom_value@.";assertfalsemethodcustom_iter_childrenr=letnode=matchrwithNone->true|Somef->m#has_childfinifnode&&m#childrenr>0thenSome(m#child_atr0)elseNonemethodcustom_iter_has_childr=m#has_childr&&m#children(Somer)>0methodcustom_iter_n_children=m#childrenmethodcustom_iter_nth_childrk=ifk<m#childrenrthenSome(m#child_atrk)elseNonemethodcustom_iter_parentr=m#parentrmethodcustom_iter_nexte=letp=m#parenteinletk=succ(m#indexe)inifk<m#childrenpthenSome(m#child_atpk)elseNoneend(* -------------------------------------------------------------------------- *)(* --- Gtk Tree View --- *)(* -------------------------------------------------------------------------- *)class['a]tree?packing?width?height?(headers=true)?(rules=true)(m:'atreemodel)=letmodel=newgtree_modelminletview=GTree.view~model~headers_visible:headers~rules_hint:rules~show:true()inobjectinherit['a]makecolumns?packing?width?heightviewmodelend