@@ -312,7 +312,7 @@ impl Size {
312312}
313313
314314#[ pyclass( frozen) ]
315- #[ derive( Debug , Clone ) ]
315+ #[ derive( Debug , Clone , Copy ) ]
316316pub struct Region {
317317 #[ pyo3( get) ]
318318 pub x : i32 ,
@@ -736,7 +736,6 @@ impl Region {
736736 }
737737
738738 fn intersection ( & self , region : & Region ) -> Region {
739- // Unrolled because this method is used a lot
740739 let ( x1, y1, w1, h1) = ( self . x , self . y , self . width , self . height ) ;
741740 let ( cx1, cy1, w2, h2) = ( region. x , region. y , region. width , region. height ) ;
742741 let x2 = x1 + w1;
@@ -919,10 +918,73 @@ impl Region {
919918 height,
920919 }
921920 }
921+
922+ fn constrain (
923+ & self ,
924+ constrain_x : & str ,
925+ constrain_y : & str ,
926+ margin : & Spacing ,
927+ container : & Region ,
928+ ) -> Region {
929+ let margin_region = self . grow ( margin. _as_tuple ( ) ) ;
930+ let mut region = * self ;
931+
932+ fn compare_span (
933+ span_start : i32 ,
934+ span_end : i32 ,
935+ container_start : i32 ,
936+ container_end : i32 ,
937+ ) -> i32 {
938+ if span_start > container_start && span_end <= container_end {
939+ 0
940+ } else if span_start < container_start {
941+ -1
942+ } else {
943+ 1
944+ }
945+ }
946+
947+ if constrain_x == "inflect" || constrain_y == "inflect" {
948+ let x_axis = if constrain_x == "inflect" {
949+ -compare_span (
950+ margin_region. x ,
951+ margin_region. right ( ) ,
952+ container. x ,
953+ container. right ( ) ,
954+ )
955+ } else {
956+ 0
957+ } ;
958+ let y_axis = if constrain_y == "inflect" {
959+ -compare_span (
960+ margin_region. y ,
961+ margin_region. bottom ( ) ,
962+ container. y ,
963+ container. bottom ( ) ,
964+ )
965+ } else {
966+ 0
967+ } ;
968+ region = region. inflect ( x_axis, y_axis, Some ( * margin) )
969+ }
970+
971+ region. translate_inside (
972+ & container. shrink ( margin. _as_tuple ( ) ) ,
973+ constrain_x != "none" ,
974+ constrain_y != "none" ,
975+ )
976+ }
977+ }
978+
979+ enum SpacingDimensions {
980+ Single ( i32 ) ,
981+ Tuple1 ( i32 ) ,
982+ Tuple2 ( i32 , i32 ) ,
983+ Tuple4 ( i32 , i32 , i32 , i32 ) ,
922984}
923985
924986#[ pyclass( frozen) ]
925- #[ derive( Debug , Clone ) ]
987+ #[ derive( Debug , Clone , Copy ) ]
926988pub struct Spacing {
927989 #[ pyo3( get) ]
928990 pub top : i32 ,
@@ -936,8 +998,8 @@ pub struct Spacing {
936998
937999#[ pymethods]
9381000impl Spacing {
1001+ #[ new]
9391002 fn new (
940- & self ,
9411003 top : Option < i32 > ,
9421004 right : Option < i32 > ,
9431005 bottom : Option < i32 > ,
@@ -972,6 +1034,10 @@ impl Spacing {
9721034 4
9731035 }
9741036
1037+ fn _as_tuple ( & self ) -> ( i32 , i32 , i32 , i32 ) {
1038+ ( self . top , self . right , self . bottom , self . left )
1039+ }
1040+
9751041 #[ getter]
9761042 fn width ( & self ) -> i32 {
9771043 self . left + self . right
@@ -995,4 +1061,109 @@ impl Spacing {
9951061 fn __bool__ ( & self ) -> bool {
9961062 self . top != 0 || self . right != 0 || self . bottom != 0 || self . right != 0
9971063 }
1064+
1065+ #[ getter]
1066+ fn css ( & self ) -> String {
1067+ let Spacing {
1068+ top,
1069+ right,
1070+ bottom,
1071+ left,
1072+ } = * self ;
1073+ if top == right && right == bottom && bottom == left && left == top {
1074+ format ! ( "{}" , top)
1075+ } else if ( top, right) == ( bottom, left) {
1076+ format ! ( "{} {}" , top, right)
1077+ } else {
1078+ format ! ( "{} {} {} {}" , top, right, bottom, left)
1079+ }
1080+ }
1081+
1082+ #[ classmethod]
1083+ fn unpack ( _cls : & Bound < ' _ , PyType > , pad : & Bound < PyAny > ) -> PyResult < Spacing > {
1084+ if let Ok ( space) = pad. extract :: < i32 > ( ) {
1085+ Ok ( Spacing {
1086+ top : space,
1087+ right : space,
1088+ bottom : space,
1089+ left : space,
1090+ } )
1091+ } else if let Ok ( ( space, ) ) = pad. extract :: < ( i32 , ) > ( ) {
1092+ Ok ( Spacing {
1093+ top : space,
1094+ right : space,
1095+ bottom : space,
1096+ left : space,
1097+ } )
1098+ } else if let Ok ( ( top, right) ) = pad. extract :: < ( i32 , i32 ) > ( ) {
1099+ Ok ( Spacing {
1100+ top : top,
1101+ right : right,
1102+ bottom : top,
1103+ left : right,
1104+ } )
1105+ } else if let Ok ( ( top, right, bottom, left) ) = pad. extract :: < ( i32 , i32 , i32 , i32 ) > ( ) {
1106+ Ok ( Spacing {
1107+ top : top,
1108+ right : right,
1109+ bottom : bottom,
1110+ left : left,
1111+ } )
1112+ } else {
1113+ Err ( PyTypeError :: new_err (
1114+ "Expected integer or tuple of 1, 2, 4 integers" ,
1115+ ) )
1116+ }
1117+ }
1118+
1119+ #[ classmethod]
1120+ fn vertical ( _cls : & Bound < ' _ , PyType > , amount : i32 ) -> Spacing {
1121+ Spacing {
1122+ top : amount,
1123+ right : 0 ,
1124+ bottom : amount,
1125+ left : 0 ,
1126+ }
1127+ }
1128+
1129+ #[ classmethod]
1130+ fn horizontal ( _cls : & Bound < ' _ , PyType > , amount : i32 ) -> Spacing {
1131+ Spacing {
1132+ top : 0 ,
1133+ right : amount,
1134+ bottom : 0 ,
1135+ left : amount,
1136+ }
1137+ }
1138+
1139+ #[ classmethod]
1140+ fn all ( _cls : & Bound < ' _ , PyType > , amount : i32 ) -> Spacing {
1141+ Spacing {
1142+ top : amount,
1143+ right : amount,
1144+ bottom : amount,
1145+ left : amount,
1146+ }
1147+ }
1148+
1149+ fn grow_maximum ( & self , other : & Spacing ) -> Spacing {
1150+ let Spacing {
1151+ top,
1152+ right,
1153+ bottom,
1154+ left,
1155+ } = * self ;
1156+ let Spacing {
1157+ top : other_top,
1158+ right : other_right,
1159+ bottom : other_bottom,
1160+ left : other_left,
1161+ } = * other;
1162+ Spacing {
1163+ top : top. max ( other_top) ,
1164+ right : right. max ( other_right) ,
1165+ bottom : bottom. max ( other_bottom) ,
1166+ left : left. max ( other_left) ,
1167+ }
1168+ }
9981169}
0 commit comments