Saves and restores a layout.
Pass a laid-out graph to the constructor, which saves the graph's vertex locations and group rectangles in private data. Call to restore the vertex locations and group rectangles to their saved values.

The number of vertices and group rectangles must remain constant between the two calls.

Inheritance: LayoutsBase
    Composite
    (
        Double compositeWidth,
        Double compositeHeight,
        String headerText,
        String footerText,
        System.Drawing.Font headerFooterFont,
        IEnumerable<LegendControlBase> legendControls
    )
    {
        Debug.Assert(compositeWidth > 0);
        Debug.Assert(compositeHeight > 0);
        Debug.Assert(headerFooterFont != null);
        Debug.Assert(legendControls != null);
        AssertValid();

        // Note:
        //
        // Don't try taking a shortcut by using
        // NodeXLControl.CopyGraphToBitmap() to get an image of the graph and
        // then compositing the image with the other elements.  That would work
        // if the caller were creating an image, but if it were creating an XPS
        // document, the graph would no longer be scalable.

        Double dScreenDpi =
            WpfGraphicsUtil.GetScreenDpi(m_oNodeXLControl).Width;

        // The NodeXLControl can't be a child of two logical trees, so
        // disconnect it from its parent after saving the current vertex
        // locations.

        m_oLayoutSaver = new LayoutSaver(m_oNodeXLControl.Graph);

        Debug.Assert(m_oNodeXLControl.Parent is Panel);
        m_oParentPanel = (Panel)m_oNodeXLControl.Parent;
        UIElementCollection oParentChildren = m_oParentPanel.Children;
        m_iChildIndex = oParentChildren.IndexOf(m_oNodeXLControl);
        oParentChildren.Remove(m_oNodeXLControl);

        m_oGraphImageScaler = new GraphImageScaler(m_oNodeXLControl);

        m_oGraphImageCenterer = new NodeXLControl.GraphImageCenterer(
            m_oNodeXLControl);

        // The header and footer are rendered as Label controls.  The legend is
        // rendered as a set of Image controls.

        Label oHeaderLabel, oFooterLabel;
        IEnumerable<Image> oLegendImages;
        Double dHeaderHeight, dTotalLegendHeight, dFooterHeight;

        CreateHeaderOrFooterLabel(headerText, compositeWidth, headerFooterFont,
            out oHeaderLabel, out dHeaderHeight);

        CreateLegendImages(legendControls, compositeWidth, out oLegendImages,
            out dTotalLegendHeight);

        CreateHeaderOrFooterLabel(footerText, compositeWidth, headerFooterFont,
            out oFooterLabel, out dFooterHeight);

        m_oNodeXLControl.Width = compositeWidth;

        m_oNodeXLControl.Height = Math.Max(10,
            compositeHeight - dHeaderHeight - dTotalLegendHeight
            - dFooterHeight);

        // Adjust the control's graph scale so that the graph's vertices and
        // edges will be the same relative size in the composite that they are
        // in the control.

        m_oGraphImageScaler.SetGraphScale(
            (Int32)WpfGraphicsUtil.WpfToPx(compositeWidth, dScreenDpi),
            (Int32)WpfGraphicsUtil.WpfToPx(m_oNodeXLControl.Height, dScreenDpi),
            dScreenDpi);

        // Adjust the NodeXLControl's translate transforms so that the
        // composite will be centered on the same point on the graph that the
        // NodeXLControl is centered on.

        m_oGraphImageCenterer.CenterGraphImage( new Size(compositeWidth,
            m_oNodeXLControl.Height) );

        StackPanel oStackPanel = new StackPanel();
        UIElementCollection oStackPanelChildren = oStackPanel.Children;

        // To avoid a solid black line at the bottom of the header or the top
        // of the footer, which is caused by rounding errors, make the
        // StackPanel background color the same as the header and footer.

        oStackPanel.Background = HeaderFooterBackgroundBrush;

        if (oHeaderLabel != null)
        {
            oStackPanelChildren.Add(oHeaderLabel);
        }

        // Wrap the NodeXLControl in a Grid to clip it.

        m_oGrid = new Grid();
        m_oGrid.Width = m_oNodeXLControl.Width;
        m_oGrid.Height = m_oNodeXLControl.Height;
        m_oGrid.ClipToBounds = true;
        m_oGrid.Children.Add(m_oNodeXLControl);

        oStackPanelChildren.Add(m_oGrid);

        foreach (Image oLegendImage in oLegendImages)
        {
            oStackPanelChildren.Add(oLegendImage);
        }

        if (oFooterLabel != null)
        {
            oStackPanelChildren.Add(oFooterLabel);
        }

        Size oCompositeSize = new Size(compositeWidth, compositeHeight);
        Rect oCompositeRectangle = new Rect(new Point(), oCompositeSize);

        oStackPanel.Measure(oCompositeSize);
        oStackPanel.Arrange(oCompositeRectangle);
        oStackPanel.UpdateLayout();

        return (oStackPanel);
    }
    CopyGraphToBitmap
    (
        Int32 bitmapWidthPx,
        Int32 bitmapHeightPx
    )
    {
        const String MethodName = "CopyGraphToBitmap";

        this.ArgumentChecker.CheckArgumentPositive(MethodName, "bitmapWidthPx",
            bitmapWidthPx);

        this.ArgumentChecker.CheckArgumentPositive(MethodName, "bitmapHeightPx",
            bitmapHeightPx);

        CheckIfLayingOutGraph(MethodName);

        // Save the current vertex locations.

        LayoutSaver oLayoutSaver = new LayoutSaver(this.Graph);

        // Adjust the control's graph scale so that the graph's vertices and
        // edges will be the same relative size in the image that they are in
        // the control.

        GraphImageScaler oGraphImageScaler = new GraphImageScaler(this);

        oGraphImageScaler.SetGraphScale(bitmapWidthPx, bitmapHeightPx,
            WpfGraphicsUtil.GetScreenDpi(this).Width);

        // Adjust the control's transforms so that the image will be centered
        // on the same point on the graph that the control is centered on.

        GraphImageCenterer oGraphImageCenterer = new GraphImageCenterer(this);

        oGraphImageCenterer.CenterGraphImage(
            new Size(bitmapWidthPx, bitmapHeightPx) );

        // Transform the graph's layout to the specified size.

        Double dOriginalActualWidth = this.ActualWidth;
        Double dOriginalActualHeight = this.ActualHeight;

        Rect oBitmapRectangle = new Rect(0, 0,
            (Double)bitmapWidthPx, (Double)bitmapHeightPx);

        TransformLayout(oBitmapRectangle);

        Debug.Assert(m_eLayoutState == LayoutState.Stable);

        DrawGraph(oBitmapRectangle);

        System.Drawing.Bitmap oBitmap = WpfGraphicsUtil.VisualToBitmap(this,
            bitmapWidthPx, bitmapHeightPx);

        // Restore the original layout.
        //
        // NOTE:
        //
        // Don't try calling TransformLayout() again using the original
        // rectangle.  The first call to TransformLayout() lost "resolution" if
        // the layout was transformed to a smaller rectangle, and attempting to
        // reverse the transform will yield poor results.

        oLayoutSaver.RestoreLayout();

        oGraphImageScaler.RestoreGraphScale();

        oBitmapRectangle =
            new Rect(0, 0, dOriginalActualWidth, dOriginalActualHeight);

        Debug.Assert(m_eLayoutState == LayoutState.Stable);

        DrawGraph(oBitmapRectangle);

        oGraphImageCenterer.RestoreCenter();

        return (oBitmap);
    }