@@ -2623,6 +2623,66 @@ def get_matrix(self):
26232623 self ._invalid = 0
26242624 return self ._mtx
26252625
2626+ class IndirectTransform (Transform ):
2627+ """
2628+ A transform that wraps a callable and resolves it lazily at draw time.
2629+
2630+ This is useful when the actual transform depends on something not
2631+ known until draw time, like another artist's bounding box.
2632+
2633+ Parameters
2634+ ----------
2635+ func : callable
2636+ A callable that takes no arguments and returns a `.Transform`
2637+ or `.BboxBase`.
2638+
2639+ Examples
2640+ --------
2641+ ::
2642+
2643+ tr = IndirectTransform(
2644+ lambda: BboxTransformTo(some_artist.get_window_extent())
2645+ )
2646+ """
2647+
2648+ input_dims = 2
2649+ output_dims = 2
2650+
2651+ def __init__ (self , func , ** kwargs ):
2652+ if not callable (func ):
2653+ raise TypeError (
2654+ f"func must be callable, not { type (func ).__name__ !r} "
2655+ )
2656+ super ().__init__ (** kwargs )
2657+ self ._func = func
2658+
2659+ def _resolve (self ):
2660+ """Call the wrapped function and return a proper Transform."""
2661+ result = self ._func ()
2662+ if isinstance (result , BboxBase ):
2663+ return BboxTransformTo (result )
2664+ elif isinstance (result , Transform ):
2665+ return result
2666+ raise TypeError (
2667+ f"func must return a Transform or BboxBase, "
2668+ f"not { type (result ).__name__ !r} "
2669+ )
2670+
2671+ def get_affine (self ):
2672+ return self ._resolve ().get_affine ()
2673+
2674+ def frozen (self ):
2675+ return self ._resolve ().frozen ()
2676+
2677+ def inverted (self ):
2678+ return self ._resolve ().inverted ()
2679+
2680+ def transform_affine (self , points ):
2681+ return self ._resolve ().transform_affine (points )
2682+
2683+ def transform_non_affine (self , points ):
2684+ return self ._resolve ().transform_non_affine (points )
2685+
26262686
26272687class BboxTransformTo (Affine2DBase ):
26282688 """
0 commit comments