Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file notebook.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453(** Notebook widget. *)openMiscopenTsdlopenWidgetopenContaineropenPack(** The ["active_page"] property, representing the 0-based index
of the active (i.e. displayed) page in a notebook. *)letactive_page=Props.int_prop~inherits:false"active_page"(** Property ["tab_props"] to store properties used for notebook tabs. *)lettab_props=Props.props_prop~default:(Props.empty())"tab_props"(** Notebook widget.
A notebook widget is a [[Widget.widget] Container.container], i.e. a
widget containing contents widgets (the pages), each one being associated to
a widget representing this page in the list of displayed tabs.
A notebook can be oriented vertically (tabs are on the left and
and are packed vertically) or horizontally (tabs are on top and
and are packed horizontally).
*)classnotebook?(class_="notebook")?name?props()=object(self)inherit[Widget.widget]Container.container~class_?name?props()assuper(**/**)valmutabletab_box=newPack.box()methodprivatetab_box=tab_boxmethodorientation=self#get_pProps.orientationmethodset_orientationo=self#set_pProps.orientationo;tab_box#set_pProps.orientationo(**/**)methodactive_page=self#opt_pactive_page(** Make page [p] the active page (0-based index). *)methodset_active_pagep=self#set_active_page_~force:falsep(**/**)methodprivateset_active_page_?(force=false)p=Log.debug(funm->m"%s#set_active_page_ %d"self#mep);(*Log.warn (fun m ->
List.iter
(fun c -> m "begin %s#set_active_page_ child %s visible: %b" self#me
c.widget#me c.widget#visible) children);*)letlen=List.lengthself#childreninifp<0||p>=lenthenfalseelse(let()=matchself#active_pagewith|Someprevwhenprev<len&&(prev<>p||force)->(letc=List.nthself#childrenprevinc.widget#set_visiblefalse;Log.debug(funm->m"%s#set_active_page_: set is_focus to false for %s"self#mec.widget#me);c.widget#set_pProps.is_focusfalse;matchc.data#parentwith|None->()|Somep->p#set_selectedfalse)|_->()inletc=List.nthself#childrenpinc.widget#set_visibletrue;let()=matchc.data#parentwith|None->()|Somep->p#set_selectedtrueinself#set_pactive_pagep;Log.debug(funm->m"%s#set_active_page_: set is_focus to true for %s"self#mec.widget#me);c.widget#set_pProps.is_focustrue;(*Log.warn (fun m ->
List.iter
(fun c -> m "end %s#set_active_page_ child %s visible: %b" self#me
c.widget#me c.widget#visible) children);*)true)method!wtree=N(self#coerce,tab_box#wtree::List.map(func->c.widget#wtree)children)methodprivatetab_widget_by_coords~x~y=List.find_opt(funw->G.inside~x~yw#geometry)tab_box#children_widgetsmethod!privatechild_by_coords~x~y=let(px,py)=letg=tab_box#geometryin(x-g.x-g_inner.x,y-g.y-g_inner.y)inList.find_opt(func->G.inside~x:px~y:pyc.data#geometry||(c.widget#visible&&G.inside~x~yc.widget#geometry))childrenmethodprivatetabs_width=tab_box#min_widthmethodprivatetabs_height=tab_box#min_heightmethod!privatemin_width_=letwidth_tabs=self#tabs_widthinsuper#min_width_+(matchself#orientationwith|Props.Horizontal->maxwidth_tabs(matchself#active_pagewith|None->0|Somep->matchList.nth_optself#childrenpwith|None->0|Somec->c.widget#min_width)|Vertical->width_tabs+(matchself#active_pagewith|None->0|Somep->matchList.nth_optself#childrenpwith|None->0|Somec->c.widget#min_width))method!privatemin_height_=letheight_tabs=self#tabs_heightinsuper#min_height_+(matchself#orientationwith|Horizontal->height_tabs+(matchself#active_pagewith|None->0|Somep->matchList.nth_optself#childrenpwith|None->0|Somec->c.widget#min_height)|Vertical->maxheight_tabs(matchself#active_pagewith|None->0|Somep->matchList.nth_optself#childrenpwith|None->0|Somec->c.widget#min_height))method!max_width=Nonemethod!max_height=Nonemethodprivatepack_label?posw=letp=self#get_ptab_propsinletb=Bin.bin~props:p()inLog.debug(funm->m"%s props: %a"b#meProps.ppp);b#set_handle_hoveringtrue;let_=b#connectWidget.Clicked(funbev->ifbev.button=1thenmatchtab_box#widget_indexb#as_widgetwith|None->false|Somep->self#set_active_page_pelsefalse)inb#set_childw;let(vexpand,hexpand)=matchself#orientationwith|Horizontal->(None,Some0)|Vertical->(Some0,None)intab_box#pack?pos?hexpand?vexpand~data:wb#as_widget;bmethodprivatepack_pos?pos~labelw=Log.debug(funm->m"%s#add %s"self#mew#me);letold_len=List.lengthself#childreninw#set_visiblefalse;matchsuper#add?poswlabel#coercewith|false->None|true->self#pack_label?poslabel;matchself#widget_indexwwith|None->None|Some0whenold_len<=0->(* setting active page will set widget visibilty to true and
will trigger a need_resize in our container *)ifself#set_active_page_0thenSome0else(Log.err(funm->m"%s#set_active_page_: page not set active ??"self#me);None)|Somen->matchself#active_pagewith|None->Log.err(funm->m"%s: no active page but page added in position %d"self#men);ifself#set_active_page_0thenSome0elseNone|Somep->let_=ifn<=pthenself#set_active_page_~force:true(p+1)elsefalseinSomep(**/**)(** [#pack ~label w] adds a new page with contents widget [w]
and label widget [label]. Optional argument [pos] can be
used to specify a 0-based position for the new page. Default
is to append the page. *)methodpack?pos~labelw=let_=self#pack_pos?pos~labelwin()(**/**)method!child_reparentedw=self#unpackw(**/**)(** [unpack w] removes the page corresponding to the (contents) widget [w]. *)methodunpack(w:Widget.widget)=matchself#widget_indexwwith|None->()|Somei->letc=List.nthself#childreniinLog.debug(funm->m"%s#unpack %s List.nth self#children %d done"self#mew#mei);matchsuper#removewwith|false->()|true->(matchc.data#parentwith|None->Log.warn(funm->m"Tab label %s has no parent!"c.data#me)|Somep->tab_box#unpackp);matchself#active_pagewith|None->self#need_resize|Somep->ifp=ithen(* removing the active page *)letlen=List.lengthself#childreniniflen<=0then((* no more pages *)Props.set_optpropsactive_pageNone;self#need_resize;self#need_render~layer:(self#get_pProps.layer)g)else((* set active page the next one, or the previous one
if the removed page was the last one *)letp=ifi<lenthenielsemax(len-1)(i-1)inlet_=self#set_active_page_pin())elseifp<ithenself#need_resizeelse(* active page > i, decrement the active page *)let_=self#set_active_page_(p-1)in()(** [remove_page i] removes the page at index [i]. *)methodremove_pagei=matchList.nth_optchildreniwith|None->Log.warn(funm->m"%s#remove_page i=%d page not found"self#mei);|Somec->self#unpackc.widget(**/**)methodprivateset_geometry_tab_box=letg=matchself#orientationwith|Horizontal->G.{x=0;y=0;w=g_inner.w;h=tab_box#min_height}|Vertical->G.{x=0;y=0;w=tab_box#min_width;h=g_inner.h}intab_box#set_geometrygmethod!set_geometrygeom=super#set_geometrygeom;Log.debug(funm->m"%s#set_geometry g=%a"self#meG.ppg);self#set_geometry_tab_box;letremain=letgt=tab_box#geometryinmatchself#orientationwith|Horizontal->lety=gt.y+gt.hinG.{x=0;y;w=g_inner.w;h=g_inner.h-y}|Vertical->letx=gt.x+gt.winG.{x;y=0;w=g_inner.w-x;h=g_inner.h}inList.iter(func->c.widget#set_geometryremain)self#childrenmethod!privaterender_me~layerrend~offset:(x,y)rg=letoff_x=g.x+g_inner.xinletoff_y=g.y+g_inner.yinletoffset=(x+off_x,y+off_y)inletrg=G.translate~x:(-off_x)~y:(-off_y)rgintab_box#render~layerrend~offsetrg;matchself#active_pagewith|None->()|Somep->matchList.nth_optself#childrenpwith|None->()|Somec->c.widget#render~layer~offsetrendrgmethod!child_need_resizew=ifOid.equalw#idtab_box#idthenself#need_resizeelsesuper#child_need_resizewmethod!on_sdl_event_down~oldpospose=ifself#sensitivethenmatchletf(x,y)=(x-g.x-g_inner.x,y-g.y-g_inner.y)inletoldpos=Option.mapfoldposinletpos=Option.mapfposinmatchSdl.Event.(enum(getetyp))with|`Key_down|`Key_up|`Text_input|`Text_editing->(matchList.find_opt(func->c.widget#get_pProps.is_focus)childrenwith|None->false|Somec->c.widget#on_sdl_event_down~oldpospose)|_->List.fold_left(funaccw->if(matcholdposwith|Some(x,y)->G.inside~x~yw#geometry|None->false)||matchposwith|Some(x,y)->G.inside~x~yw#geometry|None->truethen((*Log.warn (fun m -> m "%s#on_sdl_event_down: propagating event to %s"
self#me w#me);*)letb=w#on_sdl_event_down~oldposposeinacc||b)elseacc)false(letl=matchself#active_pagewith|None->[]|Somep->matchList.nth_optself#childrenpwith|None->[]|Somec->[c.widget]inl@[tab_box#as_widget])with|true->true|false->self#on_sdl_eventposeelsefalsemethod!leaf_widget_at~x~y=letx=x-g.x-g_inner.xinlety=y-g.y-g_inner.yinmatchself#child_by_coords~x~ywith|None->None|Somec->ifG.inside~x~yc.widget#geometrythenc.widget#leaf_widget_at~x~yelselet(px,py)=letg=tab_box#geometryin(x-g.x-g_inner.x,y-g.y-g_inner.y)inc.data#leaf_widget_at~x:px~y:pymethod!next_widget?inside~looppredw=matchwwith|Somewwhenw#equaltab_box#coerce->super#next_widget?inside~looppredNone|_->tab_box#next_widget?inside~looppredwmethod!prev_widget?inside~looppredw=letreciter=function|[]->tab_box#prev_widget?inside~looppredNone|c::qwhenpredc.widget->Somec.widget|c::q->matchc.widget#prev_widget?inside~looppredNonewith|None->iterq|x->xinmatchwwith|None->iter(List.revchildren)|Somewwhenw#equaltab_box#coerce->(matchinside,parentwith|Somei,_whenself#equali->ifloopthenself#prev_widget?inside~looppredNoneelseNone|_,None->None|_,Somep->p#prev_widget?inside~looppred(Someself#coerce))|Somew->letrecfind=function|[]->iter[]|c::qwhenc.widget#equalw->iterq|_::q->findqinfind(List.revchildren)initializertab_box#set_parent?with_rend:with_renderer(Someself#coerce)end(** Convenient function to create a {!class-notebook}.
Default [orientation] is [Horizontal].
The [class_] argument defaults to ["vnotebook"] if [orientation]
is [Vertical] or ["hnotebook"] if [orientation] is [Horizontal].
See {!Widget.widget_arguments} for other arguments. *)letnotebook?(orientation=Props.Horizontal)?class_?name?props?pack()=letclass_=matchclass_with|None->Printf.sprintf"%cnotebook"(matchorientationwithProps.Vertical->'v'|Horizontal->'h')|Somes->sinletw=newnotebook~class_?name?props()inw#set_orientationorientation;Widget.may_pack?packw;w(** Same as {!val-notebook} but orientation is already fixed to [Horizontal].*)lethnotebook?class_?name?props?pack()=notebook~orientation:Horizontal?class_?name?props?pack()(** Same as {!val-notebook} but orientation is already fixed to [Vertical].*)letvnotebook?class_?name?props?pack()=notebook~orientation:Vertical?class_?name?props?pack()