@@ -1095,6 +1095,131 @@ def get_points(self):
10951095 return points
10961096
10971097
1098+ class LockableBbox (BboxBase ):
1099+ """
1100+ A :class:`Bbox` where some elements may be locked at certain values.
1101+
1102+ When the child bounding box changes, the bounds of this bbox will update
1103+ accordingly with the exception of the locked elements.
1104+ """
1105+ def __init__ (self , bbox , x0 = None , y0 = None , x1 = None , y1 = None , ** kwargs ):
1106+ """
1107+ Parameters
1108+ ----------
1109+ bbox : Bbox
1110+ The child bounding box to wrap.
1111+
1112+ x0 : float or None
1113+ The locked value for x0, or None to leave unlocked.
1114+
1115+ y0 : float or None
1116+ The locked value for y0, or None to leave unlocked.
1117+
1118+ x1 : float or None
1119+ The locked value for x1, or None to leave unlocked.
1120+
1121+ y1 : float or None
1122+ The locked value for y1, or None to leave unlocked.
1123+
1124+ """
1125+ if not bbox .is_bbox :
1126+ raise ValueError ("'bbox' is not a bbox" )
1127+
1128+ BboxBase .__init__ (self , ** kwargs )
1129+ self ._bbox = bbox
1130+ self .set_children (bbox )
1131+ self ._points = None
1132+ fp = [x0 , y0 , x1 , y1 ]
1133+ mask = [val is None for val in fp ]
1134+ self ._locked_points = np .ma .array (fp , np .float_ ,
1135+ mask = mask ).reshape ((2 , 2 ))
1136+
1137+ def __repr__ (self ):
1138+ return "LockableBbox(%r, %r)" % (self ._bbox , self ._locked_points )
1139+
1140+ def get_points (self ):
1141+ if self ._invalid :
1142+ points = self ._bbox .get_points ()
1143+ self ._points = np .where (self ._locked_points .mask ,
1144+ points ,
1145+ self ._locked_points )
1146+ self ._invalid = 0
1147+ return self ._points
1148+ get_points .__doc__ = Bbox .get_points .__doc__
1149+
1150+ if DEBUG :
1151+ _get_points = get_points
1152+
1153+ def get_points (self ):
1154+ points = self ._get_points ()
1155+ self ._check (points )
1156+ return points
1157+
1158+ @property
1159+ def locked_x0 (self ):
1160+ """
1161+ float or None: The value used for the locked x0.
1162+ """
1163+ if self ._locked_points .mask [0 , 0 ]:
1164+ return None
1165+ else :
1166+ return self ._locked_points [0 , 0 ]
1167+
1168+ @locked_x0 .setter
1169+ def locked_x0 (self , x0 ):
1170+ self ._locked_points .mask [0 , 0 ] = x0 is None
1171+ self ._locked_points .data [0 , 0 ] = x0
1172+ self .invalidate ()
1173+
1174+ @property
1175+ def locked_y0 (self ):
1176+ """
1177+ float or None: The value used for the locked y0.
1178+ """
1179+ if self ._locked_points .mask [0 , 1 ]:
1180+ return None
1181+ else :
1182+ return self ._locked_points [0 , 1 ]
1183+
1184+ @locked_y0 .setter
1185+ def locked_y0 (self , y0 ):
1186+ self ._locked_points .mask [0 , 1 ] = y0 is None
1187+ self ._locked_points .data [0 , 1 ] = y0
1188+ self .invalidate ()
1189+
1190+ @property
1191+ def locked_x1 (self ):
1192+ """
1193+ float or None: The value used for the locked x1.
1194+ """
1195+ if self ._locked_points .mask [1 , 0 ]:
1196+ return None
1197+ else :
1198+ return self ._locked_points [1 , 0 ]
1199+
1200+ @locked_x1 .setter
1201+ def locked_x1 (self , x1 ):
1202+ self ._locked_points .mask [1 , 0 ] = x1 is None
1203+ self ._locked_points .data [1 , 0 ] = x1
1204+ self .invalidate ()
1205+
1206+ @property
1207+ def locked_y1 (self ):
1208+ """
1209+ float or None: The value used for the locked y1.
1210+ """
1211+ if self ._locked_points .mask [1 , 1 ]:
1212+ return None
1213+ else :
1214+ return self ._locked_points [1 , 1 ]
1215+
1216+ @locked_y1 .setter
1217+ def locked_y1 (self , y1 ):
1218+ self ._locked_points .mask [1 , 1 ] = y1 is None
1219+ self ._locked_points .data [1 , 1 ] = y1
1220+ self .invalidate ()
1221+
1222+
10981223class Transform (TransformNode ):
10991224 """
11001225 The base class of all :class:`TransformNode` instances that
0 commit comments