public static void BoundRectTransform(RectTransform bounded,
        RectTransform bounds,
        RectTransform extent=null)
    {
        extent = extent ?? bounded; // allow you to bound less than the whole assembly

        // work in world space because it's easier
        var extentRect = extent.GetWorldRect();
        var boundsRect = bounds.GetWorldRect();

        // push the tooltip rect into the division
        float pushR = Mathf.Max(0f, boundsRect.xMin - extentRect.xMin);
        float pushU = Mathf.Max(0f, boundsRect.yMin - extentRect.yMin);

        float pushL = Mathf.Min(0f, boundsRect.xMax - extentRect.xMax);
        float pushD = Mathf.Min(0f, boundsRect.yMax - extentRect.yMax);

        var push = new Vector2(pushL + pushR, pushU + pushD);

        bounded.position += (Vector3) push;
    }
    /// <summary>
    /// Reposition the tooltip so that it is within the bounds but not within
    /// the source
    /// </summary>
    public static void RepositionTooltip(RectTransform tooltip,
        RectTransform source,
        RectTransform bounds,
        RectTransform extent=null,
        TooltipBias bias=TooltipBias.Down)
    {
        Vector3 position = source.GetWorldRect().center;
        position.z = tooltip.position.z;

        tooltip.position = position;

        extent = extent ?? tooltip; // allow you to bound less than the whole assembly

        // work in world space because it's easier
        var extentRect = extent.GetWorldRect();
        var sourceRect = source.GetWorldRect();
        var boundsRect = bounds.GetWorldRect();

        // divide the bounds into four overlapping rectangles on each side of
        // the source rect
        var xMinRect = Rect.MinMaxRect(boundsRect.xMin, boundsRect.yMin,
                                       sourceRect.xMin, boundsRect.yMax);
        var yMinRect = Rect.MinMaxRect(boundsRect.xMin, boundsRect.yMin,
                                       boundsRect.xMax, sourceRect.yMin);
        var xMaxRect = Rect.MinMaxRect(sourceRect.xMax, boundsRect.yMin,
                                       boundsRect.xMax, boundsRect.yMax);
        var yMaxRect = Rect.MinMaxRect(boundsRect.xMin, sourceRect.yMax,
                                       boundsRect.xMax, boundsRect.yMax);

        Rect[] rects;

        if (bias == TooltipBias.Down)
        {
            rects = new[] { yMinRect, yMaxRect, xMinRect, xMaxRect };
        }
        else if (bias == TooltipBias.Up)
        {
            rects = new[] { yMaxRect, yMinRect, xMinRect, xMaxRect };
        }
        else if (bias == TooltipBias.Left)
        {
            rects = new[] { xMinRect, xMaxRect, yMinRect, yMaxRect };
        }
        else
        {
            rects = new[] { xMaxRect, xMinRect, yMinRect, yMaxRect };
        }

        //  bounds                     bounds
        //+------------------------+ +--------+--------+------+
        //|                        | |        |        |      |
        //|                        | |        |        |      |
        //|          yMax          | |  xMin  |        | xMax |
        //|                        | |        |        |      |
        //|                        | |        |        |      |
        //+--------+--------+------+ |        +--------+      |
        //|        |        |      | |        |        |      |
        //|        | source |      | |        | source |      |
        //|        |        |      | |        |        |      |
        //+--------+--------+------+ |        +--------+      |
        //|          yMin          | |        |        |      |
        //|                        | |        |        |      |
        //+------------------------+ +--------+--------+------+

        // find the first division in which the tooltip rect will fit
        for (int i = 0; i < rects.Length; ++i)
        {
            Rect rect = rects[i];

            if (extentRect.width  <= rect.width
             && extentRect.height <= rect.height)
            {
                // push the tooltip rect into the division
                float pushR = Mathf.Max(0f, rect.xMin - extentRect.xMin);
                float pushU = Mathf.Max(0f, rect.yMin - extentRect.yMin);

                float pushL = Mathf.Min(0f, rect.xMax - extentRect.xMax);
                float pushD = Mathf.Min(0f, rect.yMax - extentRect.yMax);

                var push = new Vector2(pushL + pushR, pushU + pushD);

                tooltip.position += (Vector3) push;

                break;
            }
        }
    }