123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107(** group layouts into tabs *)openB_utilsmoduleLayout=B_layoutmoduleTrigger=B_triggermoduleDraw=B_drawmoduleButton=B_buttonmoduleStyle=B_style(* warning: not thread safe ? we modify the dest_room *)moduleW=B_widgetletbg_on=Style.gradientDraw.[opaqueButton.color_off;opaqueButton.color_off;opaqueButton.color_on](* Style.gradient Draw.[opaque white;opaque pale_grey;opaque pale_grey;opaque pale_grey];; *)letbg_off=Style.SolidDraw.(opaqueButton.color_off)(* Style.gradient Draw.[opaque pale_grey;opaque grey;opaque grey;opaque grey];; *)(* On attache tous les rooms dans le layout (en mode "superposition"), et on met
en show=true celui qu'on veut. ça permet de les nettoyer correctement tous à
l'extinction. Cependant, ce n'est pas optimisé au cas où il y a des millions
de tabs (peu probable ...) car la boucle de display va les passer tous en
revue pour trouver celui à montrer. Au départ on ne mettait dans le layout
que le tab actif; l'inconvénient était que tous les autres n'étaient pas
"visibles" par bogue, et donc n'étaient pas nettoyés en quittant. D'autre
part, ça forçait à "modifier" le contenu du layout à chaque changement de tab
actif, ce qui n'est pas très joli. *)letcreate_one?slidetitleroomdest_room=letl=W.create_empty(W.Button(Button.create~bg_on~bg_offtitle))in(* the first action sets the button to 'pressed' when we click (button_down)
on it. Below we will add another action to reset all other buttons to 'not
pressed' *)letonpressw__=letb=W.get_buttonwin(* TODO skip this if the tab is already selected *)ifnot(Button.is_pressedb)thenbeginButton.pressb;Layout.iter_rooms(funl->Layout.set_showlfalse)dest_room;Layout.set_showroomtrue;do_optionslide(funfrom->Layout.slide_in~from~dst:dest_roomroom);W.updatew;(* or refresh only layout ? *)endinletc=W.connect_mainllonpressTrigger.buttons_downinW.add_connectionlc;l(** create tabs from a assoc list ("title"; layout) *)(* TODO, return a function that can be called to activate tab #i *)letcreate(*?(circular = true)*)?slide?(adjust=Layout.Fit)?(expand=true)?canvas?(name="tabs")list=iflist=[]thenfailwith"Cannot create empty tabs"elsebeginlet_,first_room=List.hdlistinletall_rooms=List.mapsndlistinList.iter(funl->Layout.set_showlfalse)all_rooms;Layout.set_showfirst_roomtrue;letdest_room=(* Layout.flat ~sep:0 ~adjust ?canvas [first_room] in *)Layout.superpose?canvasall_roomsin(* begin (\* we fix initial geometry *\)
* let open Layout in
* let maxw, maxh =
* List.fold_left (fun m (_,r) -> max m (getx r + width r)) 0 list,
* List.fold_left (fun m (_,r) -> max m (gety r + height r)) 0 list in
* match adjust with
* | Nothing -> (\* we fix the size to the maximum of all tabs *\)
* set_width dest_room maxw;
* set_height dest_room maxh
* | Width ->
* set_height dest_room maxh
* | Height ->
* set_width dest_room maxw
* | Fit -> ()
* end; *)letlabels=List.map(fun(title,layout)->create_one?slidetitlelayoutdest_room)listinletreset_other_labelsw__=List.iter(funb->ifnot(W.equalwb)thenButton.reset(W.get_buttonb))labels;(* + refresh ? *)inList.iter(funl->letc=W.connect_mainllreset_other_labelsTrigger.buttons_downinW.add_connectionlc)labels;(* we activate the first label (TODO: choose which one) *)letfirst_l=List.hdlabelsinButton.press(W.get_buttonfirst_l);letmenu=Layout.flat_of_w~name:(name^".menu")?canvas~sep:0labelsinifexpand(* we set the same width to all labels... do better? *)thenbeginletw=Layout.widthdest_roominLayout.set_widthmenuw;List.iter(funr->Layout.set_widthr(w/3))(Layout.get_roomsmenu)(* TODO ajuster le dernier w - n(w/3)... *)end;Layout.reflat~margins:0menu;(* TODO since reflat uses an animation, it's not so easy to insert a
correct resize function. *)(* on ajoute une ligne ?? *)(* let hline = Layout.empty ~w:(Layout.width menu) ~h:1 ~background:(Layout.color_bg Draw.(opaque dark_grey)) () in *)Layout.tower~name~sep:0~adjust?canvas[menu;(*hline;*)dest_room]end