123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128(*********************************************************************************)(* OCaml-Stk *)(* *)(* Copyright (C) 2023-2024 INRIA All rights reserved. *)(* Author: Maxence Guesdon, INRIA Saclay *)(* *)(* This program is free software; you can redistribute it and/or modify *)(* it under the terms of the GNU General Public License as *)(* published by the Free Software Foundation, version 3 of the License. *)(* *)(* 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 General Public License for more details. *)(* *)(* You should have received a copy of the GNU 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 *)(* *)(* As a special exception, you have permission to link this program *)(* with the OCaml compiler and distribute executables, as long as you *)(* follow the requirements of the GNU GPL in regard to all of the *)(* software in the executable aside from the OCaml compiler. *)(* *)(* Contact: Maxence.Guesdon@inria.fr *)(* *)(*********************************************************************************)(** Geometry.
This module is used to represent and compute widget coordinates.
*)(** A geometry is rectangle. [x] and [y] are coordinates of top-left corner.*)typet={x:int;y:int;w:int(** width *);h:int(** height *)}letto_stringg=Printf.sprintf"{x=%d; y=%d; w=%d; h=%d}"g.xg.yg.wg.hletppfmtg=Format.fprintffmt"{x=%d; y=%d; w=%d; h=%d}"g.xg.yg.wg.h(** Convenient function to create a {!type-t}. *)letcreate~x~y~w~h={x;y;w;h}(** [seg_inter x1 w1 x2 w2] returns the intersection segment (left..right)
between segments [(x1..(x1+w1))] and [(x2..(x2+w2))], if any. *)letseg_interx1w1x2w2=let(xl,wl,xr,wr)=ifx1<=x2then(x1,w1,x2,w2)else(x2,w2,x1,w1)inifxl+wl<=xrthenNoneelseletx=xrinletw=(min(xl+wl)(xr+wr))-xinSome(x,w)(** Intersection between two rectangles, if any. *)letinterg1g2=matchseg_interg1.xg1.wg2.xg2.wwith|None->None|Some(x,w)->matchseg_interg1.yg1.hg2.yg2.hwith|None->None|Some(y,h)->Some{x;y;w;h}(** Union of two rectangles, i.e. returns the rectangle containing both. *)letuniong1g2=letx=ming1.xg2.xinlety=ming1.yg2.yinletx2=max(g1.x+g1.w)(g2.x+g2.w)inlety2=max(g1.y+g1.h)(g2.y+g2.h)in{x;y;w=x2-x;h=y2-y}(** Zero geometry, all fields set to [0]. *)letzero={x=0;y=0;w=0;h=0}letis_zerog=g=zero(** [inside ~x ~y g] returns [true] is point [(x, y)] is inside [g]. *)letinside~x~yg=g.x<=x&&x<=g.x+g.w-1&&g.y<=y&&y<=g.y+g.h-1(** [translate ~x ~y g] returns a new geometry, adding [x] (resp. [y]) to
[g.x] (resp. [g.y]) if specified. *)lettranslate?x?yg={gwithx=Option.fold~none:g.x~some:((+)g.x)x;y=Option.fold~none:g.y~some:((+)g.y)y;}(** [enlarge ~w ~h g] returns a new geometry whose width (resp. height)
is increased by [2 * w] (resp. [2 * h]). [g.x] (resp. [g.y]) is
translated by [-w] (resp. [-h]) so that the final geometry remains
centered with report to the original one.*)letenlarge?w?hg=let(x,w)=matchwwith|None->g.x,g.w|Somen->g.x-n,g.w+2*ninlet(y,h)=matchhwith|None->g.y,g.h|Somen->g.y-n,g.h+2*nin{x;y;w;h}(** [to_rect g] creates a {!Tsdl.Sdl.rect} from [g]. *)letto_rectg=Tsdl.Sdl.Rect.create~x:g.x~y:g.y~w:g.w~h:g.h(** [of_rect r] creates a geometry {!type-t} from a {!Tsdl.Sdl.rect}. *)letof_rectr=letmoduleR=Tsdl.Sdl.Rectin{x=R.xr;y=R.yr;w=R.wr;h=R.hr}(** [has_intersect g1 g2] returns [true] if [intersection g1 g2 <> None]. *)lethas_intersectg1g2=interg1g2<>None(** [remove_border g borders] returns a new geometry by removing borders
from [g]. It is ensured that the returned geometry has non-negative
width and height.
*)letremove_borderrtrbl=letx=r.x+minr.wtrbl.Props.leftinlety=r.y+minr.htrbl.topinletw=max0(r.w-trbl.left-trbl.right)inleth=max0(r.h-trbl.top-trbl.bottom)in{x;y;w;h}