123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313(* --[[ TYPE DEFINITION *)typevalue=|Vsigofbool|Vboolofbool|Vintofint|Vfloatoffloattypeinput_type=|Sig|Boolofbool|Intof(int*int)*int|Floatof(float*float)*floattypeinput_desc=string*input_typetypeinput_win=|Inpofinput_desc|Frameofstring*input_win|HBoxofinput_winlist|VBoxofinput_winlist(* --]]*)(* --[[ UTILS *)letshort_string_of_input_type=function|Sig->"sig"|Bool_->"bool"|Int_->"int"|Float_->"float"letstring_of_input_type=function|Sig->"sig"|Boolb->"bool ("^(string_of_boolb)^")"|Int((i1,i2),default)->"int["^(string_of_inti1)^", "^(string_of_inti2)^"] "^"("^(string_of_intdefault)^")"|Float((f1,f2),default)->"float["^(string_of_floatf1)^", "^(string_of_floatf2)^"] "^"("^(string_of_floatdefault)^")"lettype_of_value=function|Vsig_->"sig"|Vbool_->"bool"|Vint_->"int"|Vfloat_->"float"letstring_of_value=function|Vsigb->ifbthen"Present"else"Absent"|Vboolb->string_of_boolb|Vinti->string_of_inti|Vfloatf->string_of_floatfletstring_of_input_desc(s,ty)=s^" : "^(short_string_of_input_typety)(* Get the list of all variables defined in win*)letget_inputswin=letrecaux=function|Inpi->[i]|Frame(_,w)->auxw|HBoxw_l->List.flatten(List.mapauxw_l)|VBoxw_l->List.flatten(List.mapauxw_l)inauxwin(* --]]*)(* --[[ INPUT *)(* The input class draws the right widget (depending on the type `typ` of the
* input) and updates the environment `env` (at initalization and each time
* the widget fires events).
* It uses `packing` to pack the widget. *)classinput(env:(string,value)Hashtbl.t)(packing:GObj.widget->unit)((name,typ):input_desc)=object(self)methodprivateinit_valv=(* check if the name `name` is already used in the environment *)ifHashtbl.memenvnamethenbeginPrintf.eprintf"Variable %s has been declared twice\n"name;exit1end;self#set_valvmethodprivateset_valv=(* check that v has the right type *)ignore(matchtyp,vwith|Sig,Vsig_|Bool_,Vbool_|Int_,Vint_|Float_,Vfloat_->()|_->Printf.eprintf"Variable %s has type %s but is assigned with a value of type %s."name(short_string_of_input_typetyp)(type_of_valuev);exit1);Hashtbl.addenvnamev;methodprivatemake_widget()=matchtypwith|Sig->self#make_sigpacking|Booldefault->self#make_boolpackingdefault|Int((i1,i2),default)->self#make_intpacking(i1,i2)default|Float((f1,f2),default)->self#make_floatpacking(f1,f2)default(* Button *)methodprivatemake_sigpacking=letwidget=GButton.button~label:("Trigger "^name)~packing:packing()in(* connect callback *)ignore(widget#connect#clicked~callback:(fun()->self#set_val(Vsigtrue)));self#init_val(Vsigfalse)(* Checkbox *)methodprivatemake_boolpackingdefault=letwidget=GButton.check_button~label:(string_of_input_desc(name,typ))~active:default~packing:packing()in(* connect callback *)ignore(widget#connect#toggled~callback:(fun()->self#set_val(Vboolwidget#active)));self#init_val(Vbooldefault)(* Frame with a scale inside *)methodprivatemake_intpacking(i1,i2)default=letget_labelv=Printf.sprintf"%s = %d"namevinletframe=GBin.frame~label:(get_labeldefault)~packing:packing()in(* There is a weird bug with GRange.scale: if the interval [lower, upper]
* is too small, the scale widget doesn't work properly.
* To reproduce the bug, run the following code:
*
let _ =
GMain.init ();
let screen = Gdk.Screen.default () in
let width = truncate (float (Gdk.Screen.width ~screen:screen ()) *. 0.1) in
let w = GWindow.window ~title:"test" ~width:width () in
let adj = GData.adjustment
~lower:0.
~upper:5. (* <-- change this value to something bigger
* (like 100.) to make it work *)
~value:1.
~step_incr:1.0
() in
ignore(GRange.scale `HORIZONTAL ~adjustment:adj ~draw_value:true
~value_pos:`LEFT ~digits:0 ~packing:w#add ());
ignore (w#connect#destroy ~callback:GMain.Main.quit);
ignore (w#misc#connect#show ~callback:w#show);
w#set_allow_shrink true;
w#show ();
GMain.Main.main()
*)letstep_incr=100.0inletlower=float_of_int(100*i1)inletupper=float_of_int(100*i2+100)inletvalue=float_of_int(100*default)inletadj=GData.adjustment~lower:lower~upper:upper~value:value~step_incr:step_incr()in(* create scale widget *)ignore(GRange.scale`HORIZONTAL~adjustment:adj~draw_value:false~packing:frame#add());(* connect callback *)ignore(adj#connect#value_changed(fun()->letnew_val=truncate(adj#value/.100.)inframe#set_label(Some(get_labelnew_val));self#set_val(Vintnew_val)));self#init_val(Vintdefault)(* Frame with a scale inside*)methodprivatemake_floatpacking(f1,f2)default=letget_labelv=if(v>-10000.&&v<-0.01)||(v>0.01&&v<10000.)||v=0.thenPrintf.sprintf"%s = %.2f"namevelse(* use scientific notation *)Printf.sprintf"%s = %.2e"namevinletframe=GBin.frame~label:(get_labeldefault)~packing:packing()in(* refer to make_int for weird GRange.scale bug*)letstep_incr=min1.(f2-.f1)inletlower=100.*.f1inletupper=100.*.f2+.10.inletvalue=100.*.defaultinletadj=GData.adjustment~lower:lower~upper:upper~value:value~step_incr:step_incr()in(* create scale widget *)ignore(GRange.scale`HORIZONTAL~adjustment:adj~draw_value:false~packing:frame#add());(* connect callback *)ignore(adj#connect#value_changed(fun()->letnew_val=(adj#value/.100.)inframe#set_label(Some(get_labelnew_val));self#set_val(Vfloatnew_val)));self#init_val(Vfloatdefault)initializerself#make_widget()endclasswindow(title:string)(win:input_win)=letinputs=get_inputswininletn_inputs=List.lengthinputsinletenv=Hashtbl.createn_inputsinobject(self)valw=GWindow.window~title:title~allow_shrink:false()methodprivatemake_windowpacking=function|Inpi->ignore(newinputenvpackingi)|Frame(s,w)->letframe=GBin.frame~label:s~packing:packing()inletalign=GBin.alignment~padding:(10,10,10,10)~packing:frame#add()inself#make_windowalign#addw|HBox(w_l)->lethbox=GPack.hbox~homogeneous:true~spacing:20~packing:packing()inList.iter(self#make_windowhbox#pack)w_l|VBox(w_l)->letvbox=GPack.vbox~spacing:20~packing:packing()inList.iter(self#make_windowvbox#pack)w_lmethodprivateget_valuename=tryHashtbl.findenvnamewithNot_found->Printf.eprintf"The value identifier %s is unbound\n"name;exit1methodget_signame=matchself#get_valuenamewith|Vsigs->ifsthenbeginHashtbl.addenvname(Vsigfalse);trueendelsefalse|v->Printf.eprintf"Cannot access variable (%s : %s) with method get_sig\n"name(type_of_valuev);exit1methodget_boolname=matchself#get_valuenamewith|Vboolb->b|v->Printf.eprintf"Cannot access variable (%s : %s) with method get_bool\n"name(type_of_valuev);exit1methodget_intname=matchself#get_valuenamewith|Vinti->i|v->Printf.eprintf"Cannot access variable (%s : %s) with method get_int\n"name(type_of_valuev);exit1methodget_floatname=matchself#get_valuenamewith|Vfloatf->f|v->Printf.eprintf"Cannot access variable (%s : %s) with method get_float\n"name(type_of_valuev);exit1methodresizewidthheight=w#resize~width:width~height:heightinitializerletalign=GBin.alignment~padding:(10,10,10,10)~packing:w#add()inself#make_windowalign#addwin;ignore(w#connect#destroy~callback:GMain.Main.quit);ignore(w#misc#connect#show~callback:w#show);w#show()end(* INTERFACE*)letmake_sigs=Inp(s,Sig)letmake_boolsb=Inp(s,Boolb)letmake_ints(i1,i2)def=Inp(s,Int((i1,i2),def))letmake_floats(f1,f2)def=Inp(s,Float((f1,f2),def))letframesw=Frame(s,w)lethboxw_l=HBoxw_lletvboxw_l=VBoxw_lletget_sig(w,s)=((),w#get_sigs)letget_bool(w,s)=w#get_boolsletget_int(w,s)=w#get_intsletget_float(w,s)=w#get_floatsletresize_window(w,width,height)=w#resizewidthheightletopen_window(title,win)=newwindowtitlewin(* (* TEST *)
let _ =
let _ = GMain.init () in (* initialize lablgtk2 *)
let test_window =
Frame ("Main",
VBox [ HBox [ Inp ("e", Sig); Inp ("f", Sig); Inp ("g", Sig) ];
Frame ("Some floats",
HBox [ Inp ("x", Float ((0.0, 9.0), 1.0)); Inp ("y", Float ((0., 90.), 3.))]);
Frame ("Some booleans",
HBox [ Inp ("b1", Bool true); Inp ("b2", Bool true); Inp ("b3", Bool true) ]);
HBox [ Inp ("x1", Int ((0, 100), 1)); Inp ("y1", Int ((1, 90), 3))]
]; )
in
let w = new window test_window in
GMain.Main.main (); *)