123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361(**************************************************************************)(* Lablgtk *)(* *)(* This program is free software; you can redistribute it *)(* and/or modify it under the terms of the GNU Library General *)(* Public License as published by the Free Software Foundation *)(* version 2, with the exception described in file COPYING which *)(* comes with the library. *)(* *)(* This program 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 Library General Public License for more details. *)(* *)(* You should have received a copy of the GNU Library General *)(* Public License along with this program; if not, write to the *)(* Free Software Foundation, Inc., 59 Temple Place, Suite 330, *)(* Boston, MA 02111-1307 USA *)(* *)(* *)(**************************************************************************)(* $Id$ *)openStdLabels(** Menus *)typemenu_entry=[`Iofstring*(unit->unit)|`Cofstring*bool*(bool->unit)|`Rof(string*bool*(bool->unit))list|`Mofstring*menu_entrylist]letrecbuild_menumenu~(entries:menu_entrylist)=letf=newGMenu.factorymenuinList.iterentries~f:beginfunction|`I(label,callback)->ignore(f#add_itemlabel~callback)|`C(label,active,callback)->ignore(f#add_check_itemlabel~callback~active)|`R((label,active,callback)::l)->letr=f#add_radio_itemlabel~active~callbackinletgroup=r#groupinList.iterl~f:(fun(label,active,callback)->ignore(f#add_radio_itemlabel~active~callback~group))|`R[]->()|`M(label,entries)->letm=f#add_submenulabelinbuild_menum~entriesendletpopup_menu~entries=letmenu=GMenu.menu()inbuild_menumenu~entries;fun~button~time->ifentries=[]then()elsemenu#popup~button~time(** Dialogs *)letmOk="Ok"letmCancel="Cancel"letquestion_box?parent~title~buttons?(default=1)?iconmessage=letbutton_nb=ref0inletdestroy_with_parent=Gaux.may_map~f:(fun_->true)parentinletwindow=GWindow.dialog?parent?destroy_with_parent~modal:true~title()inlethbox=GPack.hbox~border_width:10~packing:window#vbox#add()inletbbox=window#action_areainbeginmatchiconwithNone->()|Somei->hbox#packi#coerce~padding:4end;ignore(GMisc.label~text:message~packing:hbox#add());(* the function called to create each button by iterating *)letreciter_buttonsn=function[]->()|button_label::q->letb=GButton.button~label:button_label~packing:(bbox#pack~expand:true~padding:4)()inb#connect#clicked~callback:(fun()->button_nb:=n;window#destroy());(* If it's the first button then give it the focus *)ifn=defaultthenb#grab_default()else();iter_buttons(n+1)qiniter_buttons1buttons;window#connect#destroy~callback:GMain.Main.quit;window#set_position`CENTER;window#show();GMain.Main.main();!button_nbletmessage_box?parent~title?icon?(ok=mOk)message=ignore(question_box?parent?icon~titlemessage~buttons:[ok])letinput_widget?parent~widget~event~get_text~bind_ok~expand~title?(ok=mOk)?(cancel=mCancel)message=letretour=refNoneinletdestroy_with_parent=Gaux.may_map~f:(fun_->true)parentinletwindow=GWindow.dialog?parent?destroy_with_parent~title~modal:true()inwindow#connect#destroy~callback:GMain.Main.quit;letmain_box=window#vboxinlethbox_boutons=window#action_areainletvbox_saisie=GPack.vbox~packing:(main_box#pack~expand:true)()inignore(GMisc.label~text:message~packing:(vbox_saisie#pack~padding:3)());vbox_saisie#packwidget~expand~padding:3;letwb_ok=GButton.button~label:ok~packing:(hbox_boutons#pack~expand:true~padding:3)()inwb_ok#grab_default();letwb_cancel=GButton.button~label:cancel~packing:(hbox_boutons#pack~expand:true~padding:3)()inletf_ok()=retour:=Some(get_text());window#destroy()inletf_cancel()=retour:=None;window#destroy()inwb_ok#connect#clickedf_ok;wb_cancel#connect#clickedf_cancel;(* the enter key is linked to the ok action *)(* the escape key is linked to the cancel action *)event#connect#key_press~callback:beginfunev->ifGdkEvent.Key.keyvalev=GdkKeysyms._Return&&bind_okthenf_ok();ifGdkEvent.Key.keyvalev=GdkKeysyms._Escapethenf_cancel();falseend;widget#misc#grab_focus();window#show();GMain.Main.main();!retourletinput_string?parent~title?ok?cancel?(text="")message=letwe_chaine=GEdit.entry~text()iniftext<>""thenwe_chaine#select_region0(we_chaine#text_length);input_widget?parent~widget:we_chaine#coerce~event:we_chaine#event~get_text:(fun()->we_chaine#text)~bind_ok:true~expand:false~title?ok?cancelmessageletinput_text?parent~title?ok?cancel?(text="")message=letwscroll=GBin.scrolled_window~vpolicy:`AUTOMATIC~hpolicy:`AUTOMATIC()inletwview_chaine=GText.view~editable:true~packing:wscroll#add()iniftext<>""thenbeginwview_chaine#buffer#inserttext;wview_chaine#buffer#move_mark`SEL_BOUND~where:wview_chaine#buffer#start_iter;end;input_widget?parent~widget:wscroll#coerce~event:wview_chaine#event~get_text:wview_chaine#buffer#get_text~bind_ok:false~expand:true~title?ok?cancelmessage(*
(**This variable contains the last directory where the user selected a file.*)
let last_dir = ref ""
let select_file ~title ?(dir = last_dir) ?(filename="") () =
let fs =
if Filename.is_relative filename then begin
if !dir <> "" then
let filename = Filename.concat !dir filename in
GWindow.file_selection ~modal:true ~title ~filename ()
else
GWindow.file_selection ~modal:true ~title ()
end else begin
dir := Filename.dirname filename;
GWindow.file_selection ~modal:true ~title ~filename ()
end
in
fs#connect#destroy ~callback: GMain.Main.quit;
let file = ref None in
fs#ok_button#connect#clicked ~callback:
begin fun () ->
file := Some fs#filename;
dir := Filename.dirname fs#filename;
fs#destroy ()
end;
fs # cancel_button # connect#clicked ~callback:fs#destroy;
fs # show ();
GMain.Main.main ();
!file
type 'a tree = [`L of 'a | `N of 'a * 'a tree list]
class ['a] tree_selection ~tree ~label ~info ?packing ?show () =
let main_box = GPack.vbox ?packing ?show () in
(* The scroll window used for the tree of the versions *)
let wscroll_tree = GBin.scrolled_window ~packing: main_box#add () in
(* The tree containing the versions *)
let wtree = GBroken.tree
~packing:wscroll_tree#add_with_viewport () in
(* the text widget used to display information on the selected node. *)
let wview = GText.view ~editable: false ~packing: main_box#pack () in
(* build the tree *)
object
inherit GObj.widget main_box#as_widget
val mutable selection = None
method selection = selection
method clear_selection () = selection <- None
method wtree = wtree
method wview = wview
initializer
let rec insert_node wt (t : 'a tree) =
let data, children =
match t with `L d -> d, [] | `N(d,c) -> d, c in
let item = GBroken.tree_item ~label: (label data) () in
wt#insert item ~pos: 0;
item#connect#select ~callback:
begin fun () ->
selection <- Some data;
wview#buffer#delete ~start: wview#buffer#start_iter ~stop:wview#buffer#end_iter ;
wview#buffer#insert ~iter: wview#buffer#start_iter (info data);
()
end;
item#connect#deselect ~callback:
begin fun () ->
selection <- None;
wview#buffer#set_text "";
end;
match children with
[] ->
(* nothing more to do *)
()
| l ->
(* create a subtree and expand it *)
let newtree = GBroken.tree () in
item#set_subtree newtree;
item#expand ();
(* insert the children *)
List.iter (insert_node newtree) (List.rev children)
in
insert_node wtree tree
end
let tree_selection_dialog ?parent ~tree ~label ~info ~title
?(ok=mOk) ?(cancel=mCancel) ?(width=300) ?(height=400)
?show () =
let destroy_with_parent = Gaux.may_map ~f:(fun _ -> true) parent in
let window = GWindow.dialog ?parent ?destroy_with_parent ~modal:true ~title ~width ~height ?show () in
(* the tree selection box *)
let ts = new tree_selection ~tree ~label ~info
~packing:window#vbox#add ()
in
(* the box containing the ok and cancel buttons *)
let hbox = window#action_area in
let bOk = GButton.button ~label: ok
~packing:(hbox#pack ~padding:4 ~expand: true) ()
in
let bCancel = GButton.button ~label: cancel
~packing:(hbox#pack ~padding:4 ~expand: true) ()
in
bOk#connect#clicked ~callback:window#destroy;
bCancel#connect#clicked
~callback:(fun _ -> ts#clear_selection () ; window#destroy ());
window#connect#destroy ~callback: GMain.Main.quit;
window#show ();
GMain.Main.main () ;
ts#selection
(** Misc *)
let autosize_clist wlist =
(* get the number of columns *)
let nb_columns = wlist#columns in
(* get the columns titles *)
let rec iter lacc i =
if i >= nb_columns then
lacc
else
let title = wlist#column_title i in
iter (lacc@[(" "^title^" ")]) (i+1)
in
let titles = iter [] 0 in
(* insert a row with the titles *)
wlist#insert ~row:0 titles;
(* use to clist columns_autosize method *)
wlist#columns_autosize ();
(* remove the inserted row *)
ignore (wlist#remove ~row: 0)
*)(** Shortcuts *)typekey_combination=[`A|`C|`S]list*chartype'ashortcut_specification={name:string;keys:key_combinationlist;message:'a;}(* mk_keys turns keys from a key_combination into a format which can be used in
* a GTK+ RC file. *)letmk_keys(mods,c)=letmods=List.map(function`A->"<Alt>"|`C->"<Control>"|`S->"<Shift>")modsin(String.concat""mods)^(String.make1(Char.uppercase_asciic))(* Signal creation for shortcuts unfortunately requires us to create an
* in-memory gtkrc file which this function do. *)letmake_gtkrc_stringg_typeshortcuts=letsp=Printf.sprintfinletb=Buffer.create4000inBuffer.add_stringb"binding \"Shortcuts\" {";StdLabels.List.itershortcuts~f:(funt->ListLabels.itert.keys~f:(funkeys->letkeys=mk_keyskeysinBuffer.add_stringb(sp"bind \"%s\" { \"%s\" () }"keyst.name)));Buffer.add_stringb"}";letclassname=Gobject.Type.nameg_typeinBuffer.add_stringb(sp"class \"%s\" binding \"Shortcuts\""classname);Buffer.contentsbletcreate_shortcuts~window:(win:#GWindow.window_skel)~shortcuts~callback=letwin=win#as_windowinletg_type=Gobject.get_typewininGtkMain.Rc.parse_string(make_gtkrc_stringg_typeshortcuts);ListLabels.itershortcuts~f:(funt->letsgn={GtkSignal.name=t.name;classe=`window;marshaller=GtkSignal.marshal_unit}inGtkSignal.signal_newt.nameg_type[`ACTION;`RUN_FIRST];ignore(GtkSignal.connect~sgn~callback:(fun()->callbackt.message)win))