123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251(* Code for resolving name grid lines and areas *)openStyleopenGeometry(* Resolver that takes grid lines names and area names as input and can then be
used to resolve line names of grid placement properties into line numbers *)typet={row_lines:(string,intlist)Hashtbl.t;(* Map of row line names to line numbers. Each line name may correspond to
multiple lines *)column_lines:(string,intlist)Hashtbl.t;(* Map of column line names to line numbers. Each line name may correspond
to multiple lines *)area_column_count:int;(* Number of columns implied by grid area definitions *)area_row_count:int;(* Number of rows implied by grid area definitions *)mutableexplicit_column_count:int;(* The number of explicit columns in the grid. This is an *input* to the
NamedLineResolver and is used when computing the fallback line when a
non-existent named line is specified *)mutableexplicit_row_count:int;(* The number of explicit rows in the grid. This is an *input* to the
NamedLineResolver and is used when computing the fallback line when a
non-existent named line is specified *)}(* Utility function to create or update an entry in a line name map *)letupsert_line_name_mapmapkeyvalue=matchHashtbl.find_optmapkeywith|Somelines->Hashtbl.replacemapkey(lines@[value])|None->Hashtbl.addmapkey[value](* Create and initialise a new NamedLineResolver *)letcreatestylecolumn_auto_repetitionsrow_auto_repetitions=letcolumn_lines=Hashtbl.create16inletrow_lines=Hashtbl.create16inletarea_column_count=ref0inletarea_row_count=ref0in(* Process grid template areas *)List.iter(funarea->area_column_count:=max!area_column_count(max1(Grid.Template_area.column_endarea)-1);area_row_count:=max!area_row_count(max1(Grid.Template_area.row_endarea)-1);letcol_start_name=Printf.sprintf"%s-start"(Grid.Template_area.namearea)inupsert_line_name_mapcolumn_linescol_start_name(Grid.Template_area.column_startarea);letcol_end_name=Printf.sprintf"%s-end"(Grid.Template_area.namearea)inupsert_line_name_mapcolumn_linescol_end_name(Grid.Template_area.column_endarea);letrow_start_name=Printf.sprintf"%s-start"(Grid.Template_area.namearea)inupsert_line_name_maprow_linesrow_start_name(Grid.Template_area.row_startarea);letrow_end_name=Printf.sprintf"%s-end"(Grid.Template_area.namearea)inupsert_line_name_maprow_linesrow_end_name(Grid.Template_area.row_endarea))(grid_template_areasstyle);(* Process grid template columns *)letcurrent_line=ref0inletcolumn_tracks=grid_template_columnsstyleinletcolumn_line_names=grid_template_column_namesstyleinletcolumn_tracks_ref=refcolumn_tracksinList.iter(funline_names->incrcurrent_line;List.iter(funline_name->upsert_line_name_mapcolumn_linesline_name!current_line)line_names;match!column_tracks_refwith|Grid.Template_component.Repeatrep::rest->column_tracks_ref:=rest;letrepeat_count=matchGrid.Repetition.countrepwith|Grid.Repetition_count.Countcount->count|Grid.Repetition_count.Auto_fill|Grid.Repetition_count.Auto_fit->column_auto_repetitionsinfor_=0torepeat_count-1doList.iter(funline_name_set->List.iter(funline_name->upsert_line_name_mapcolumn_linesline_name!current_line)line_name_set;incrcurrent_line)(Grid.Repetition.line_namesrep);(* Last line name set collapses with following line name set *)decrcurrent_linedone;(* Last line name set collapses with following line name set *)decrcurrent_line|_::rest->column_tracks_ref:=rest|[]->())column_line_names;(* Sort and dedup lines for each column name *)Hashtbl.iter(funnamelines->letsorted=List.sort_uniqInt.comparelinesinHashtbl.replacecolumn_linesnamesorted)column_lines;(* Process grid template rows - similar logic *)letcurrent_line=ref0inletrow_tracks=grid_template_rowsstyleinletrow_line_names=grid_template_row_namesstyleinletrow_tracks_ref=refrow_tracksinList.iter(funline_names->incrcurrent_line;List.iter(funline_name->upsert_line_name_maprow_linesline_name!current_line)line_names;match!row_tracks_refwith|Grid.Template_component.Repeatrep::rest->row_tracks_ref:=rest;letrepeat_count=matchGrid.Repetition.countrepwith|Grid.Repetition_count.Countcount->count|Grid.Repetition_count.Auto_fill|Grid.Repetition_count.Auto_fit->row_auto_repetitionsinfor_=0torepeat_count-1doList.iter(funline_name_set->List.iter(funline_name->upsert_line_name_maprow_linesline_name!current_line)line_name_set;incrcurrent_line)(Grid.Repetition.line_namesrep);(* Last line name set collapses with following line name set *)decrcurrent_linedone;(* Last line name set collapses with following line name set *)decrcurrent_line|_::rest->row_tracks_ref:=rest|[]->())row_line_names;(* Sort and dedup lines for each row name *)Hashtbl.iter(funnamelines->letsorted=List.sort_uniqInt.comparelinesinHashtbl.replacerow_linesnamesorted)row_lines;{area_column_count=!area_column_count;area_row_count=!area_row_count;explicit_column_count=0;(* Overwritten later *)explicit_row_count=0;row_lines;column_lines;}(* Get the number of columns defined by the grid areas *)letarea_column_countt=t.area_column_count(* Get the number of rows defined by the grid areas *)letarea_row_countt=t.area_row_count(* Set the number of columns in the explicit grid *)letset_explicit_column_counttcount=t.explicit_column_count<-count(* Set the number of rows in the explicit grid *)letset_explicit_row_counttcount=t.explicit_row_count<-count(* Get the number of columns in the explicit grid *)letexplicit_column_countt=t.explicit_column_count(* Get the number of rows in the explicit grid *)letexplicit_row_countt=t.explicit_row_count(* Find a line index by name *)letfind_line_indextnameidxaxis=letlines_map=matchaxiswith`Row->t.row_lines|`Column->t.column_linesinmatchHashtbl.find_optlines_mapnamewith|None->0(* Fallback to 0 if named line not found *)|Somelines->(* idx is 1-based, so we need to convert to 0-based index *)letzero_based_idx=ifidx>0thenidx-1elseList.lengthlines+idxinifzero_based_idx>=0&&zero_based_idx<List.lengthlinesthenList.nthlineszero_based_idxelse0(* Fallback to 0 if index out of bounds *)(* Resolve named lines for a grid placement *)letresolve_line_namestlineaxis=letresolve_singleplacement=matchplacementwith|Grid.Placement.Named_line(name,idx)->Grid.Placement.Line(find_line_indextnameidxaxis)|_->placementin{Geometry.Line.start=resolve_singleline.Geometry.Line.start;end_=resolve_singleline.Geometry.Line.end_;}(* Resolve named lines for row axis *)letresolve_row_namestline=resolve_line_namestline`Row(* Resolve named lines for column axis *)letresolve_column_namestline=resolve_line_namestline`Column(* Resolve absolutely positioned grid tracks *)letresolve_absolutely_positioned_grid_tracksoz_placement=letopenGrid.Origin_zero_placementinmatch(oz_placement.Line.start,oz_placement.Line.end_)with|Linetrack1,Linetrack2->iftrack1=track2thenLine.{start=Sometrack1;end_=Some(track1+1)}elseLine.{start=Some(mintrack1track2);end_=Some(maxtrack1track2)}|Linetrack,Spanspan->Line.{start=Sometrack;end_=Some(track+span)}|Linetrack,Auto->Line.{start=Sometrack;end_=None}|Spanspan,Linetrack->Line.{start=Some(track-span);end_=Sometrack}|Auto,Linetrack->Line.{start=None;end_=Sometrack}|_->Line.{start=None;end_=None}