Пример #1
0
 /// <summary>
 /// Subclasses should override this method to get notified as the handle is dragged.
 /// </summary>
 /// <param name="sender">The source of this handle drag event.</param>
 /// <param name="size">The drag delta relative to the handle.</param>
 /// <param name="e">A PInputEventArgs that contains the event data.</param>
 public virtual void OnHandleDrag(object sender, SizeFx size, PInputEventArgs e)
 {
     if (HandleDrag != null)
     {
         HandleDrag(sender, size, e);
     }
 }
Пример #2
0
            public void DragHandleTwoHandler(object sender, SizeFx localDelta, PInputEventArgs e)
            {
                SizeFx parentDelta = LocalToParent(localDelta);

                PointTwo = new PointFx(PointTwo.X + parentDelta.Width, PointTwo.Y + parentDelta.Height);
                ((PHandle)sender).RelocateHandle();
            }
Пример #3
0
        /// <summary>
        /// Animates the camera's view to keep the focus node on the screen and at 100
        /// percent scale with minimal view movement.
        /// </summary>
        /// <param name="aCamera">The camera whose view will be animated.</param>
        /// <param name="aFocusNode">The focus node to animate to.</param>
        /// <param name="duration">The length of the animation.</param>
        /// <returns>
        /// The activity that animates the camera's view to the focus node.
        /// </returns>
        public virtual PActivity DirectCameraViewToFocus(PCamera aCamera, PNode aFocusNode, int duration)
        {
            Matrix originalViewMatrix = aCamera.ViewMatrix;

            // Scale the canvas to include
            SizeFx s = new SizeFx(1, 0);

            s = focusNode.GlobalToLocal(s);

            float   scaleFactor = s.Width / aCamera.ViewScale;
            PointFx scalePoint  = PUtil.CenterOfRectangle(focusNode.GlobalFullBounds);

            if (scaleFactor != 1)
            {
                aCamera.ScaleViewBy(scaleFactor, scalePoint.X, scalePoint.Y);
            }

            // Pan the canvas to include the view bounds with minimal canvas
            // movement.
            aCamera.AnimateViewToPanToBounds(focusNode.GlobalFullBounds, 0);

            // Get rid of any white space. The canvas may be panned and
            // zoomed in to do this. But make sure not stay constrained by max
            // magnification.
            //FillViewWhiteSpace(aCamera);

            Matrix resultingMatrix = aCamera.ViewMatrix;

            aCamera.ViewMatrix = originalViewMatrix;

            // Animate the canvas so that it ends up with the given
            // view transform.
            return(AnimateCameraViewMatrixTo(aCamera, resultingMatrix, duration));
        }
Пример #4
0
        /// <summary>
        /// Applies a previously set constraint to the camera's view matrix.
        /// </summary>
        public virtual void ApplyViewConstraints()
        {
            if (viewConstraint == CameraViewConstraint.None)
            {
                return;
            }

            RectangleFx layerBounds     = GlobalToLocal(UnionOfLayerFullBounds);
            SizeFx      constraintDelta = new SizeFx(0, 0);

            switch (viewConstraint)
            {
            case CameraViewConstraint.All:
                constraintDelta = PUtil.DeltaRequiredToContain(ViewBounds, layerBounds);
                break;

            case CameraViewConstraint.Center:
                PointFx layerLocation = PUtil.CenterOfRectangle(layerBounds);
                //layerBounds.Width = 0;
                //layerBounds.Height = 0;
                layerBounds     = new RectangleFx(layerLocation.X, layerLocation.Y, 0, 0);
                constraintDelta = PUtil.DeltaRequiredToContain(ViewBounds, layerBounds);
                break;
            }

            this.viewMatrix = MatrixExtensions.TranslateBy(viewMatrix, -constraintDelta.Width, -constraintDelta.Height);
        }
Пример #5
0
        /// <summary>
        /// Override this method to change the way bounds are computed. For example
        /// this is where you can control how lines are wrapped.
        /// </summary>
        public virtual void RecomputeBounds()
        {
            if (text != null && (ConstrainWidthToTextWidth || ConstrainHeightToTextHeight))
            {
                float textWidth;
                float textHeight;
                if (ConstrainWidthToTextWidth)
                {
                    textWidth  = Font.MeasureString(Text).X;
                    textHeight = Font.MeasureString(Text).Y;
                }
                else
                {
                    textWidth = Width;
                    SizeFx layoutSize = new SizeFx(textWidth, float.PositiveInfinity);
                    //textHeight = GRAPHICS.MeasureString(Text, Font, layoutSize.ToSizeF(), stringFormat).Height;
                    textHeight = Font.MeasureString(Text).Y;
                }

                float newWidth  = Width;
                float newHeight = Height;
                if (ConstrainWidthToTextWidth)
                {
                    newWidth = textWidth;
                }
                if (ConstrainHeightToTextHeight)
                {
                    newHeight = textHeight;
                }

                base.SetBounds(X, Y, newWidth, newHeight);
            }
        }
Пример #6
0
        /// <summary>
        /// Overridden.  See <see cref="PDragSequenceEventHandler.OnDrag">
        /// PDragSequenceEventHandler.OnDrag</see>.
        /// </summary>
        protected override void OnDrag(object sender, PInputEventArgs e)
        {
            base.OnDrag(sender, e);
            SizeFx s = e.GetDeltaRelativeTo(draggedNode);

            s = draggedNode.LocalToParent(s);
            draggedNode.OffsetBy(s.Width, s.Height);
        }
Пример #7
0
        protected void aNode_MouseDrag(object sender, PInputEventArgs e)
        {
            PNode  aNode = (PNode)sender;
            SizeFx delta = e.GetDeltaRelativeTo(aNode);

            aNode.TranslateBy(delta.Width, delta.Height);
            PrintEventCoords(e);
            e.Handled = true;
        }
Пример #8
0
            /// <summary>
            /// Overridden.  See <see cref="PDragSequenceEventHandler.OnDrag">
            /// PDragSequenceEventHandler.OnDrag</see>.
            /// </summary>
            protected override void OnDrag(object sender, PInputEventArgs e)
            {
                base.OnDrag(sender, e);
                SizeFx aDelta = e.GetDeltaRelativeTo(handle);

                if (aDelta.Width != 0 || aDelta.Height != 0)
                {
                    handle.OnHandleDrag(sender, aDelta, e);
                }
            }
Пример #9
0
        /// <summary>
        /// Pans the camera as the mouse is dragged.
        /// </summary>
        /// <param name="e">A PInputEventArgs that contains the event data.</param>
        protected virtual void Pan(PInputEventArgs e)
        {
            PCamera c = e.Camera;
            Vector2 l = new Vector2(e.Position.X, e.Position.Y);

            if (c.ViewBounds.Contains(l))
            {
                SizeFx s = e.Delta;
                c.TranslateViewBy(s.Width, s.Height);
            }
        }
Пример #10
0
        /// <summary>
        /// Return the delta required to center the rectangle b2 in the rectangle b1.
        /// </summary>
        /// <param name="b1">The first rectangle.</param>
        /// <param name="b2">The second rectangle.</param>
        /// <returns>The delta required to center b2 in b1.</returns>
        public static SizeFx DeltaRequiredToCenter(RectangleFx b1, RectangleFx b2)
        {
            SizeFx  result = SizeFx.Empty;
            PointFx sc     = CenterOfRectangle(b1);
            PointFx tc     = CenterOfRectangle(b2);
            float   xDelta = sc.X - tc.X;
            float   yDelta = sc.Y - tc.Y;

            result.Width  = xDelta;
            result.Height = yDelta;
            return(result);
        }
Пример #11
0
        /// <summary>
        /// Return the delta required for the rectangle b1 to contain the rectangle b2.
        /// </summary>
        /// <param name="b1">The first rectangle.</param>
        /// <param name="b2">The second rectangle.</param>
        /// <returns>The delta required for b1 to contain b2.</returns>
        public static SizeFx DeltaRequiredToContain(RectangleFx b1, RectangleFx b2)
        {
            SizeFx result = SizeFx.Empty;

            if (!b1.Contains(b2))
            {
                float b1MaxX = Math.Max(b1.X, b1.Right);
                float b1MinX = Math.Min(b1.X, b1.Right);
                float b1MaxY = Math.Max(b1.Y, b1.Bottom);
                float b1MinY = Math.Min(b1.Y, b1.Bottom);

                float b2MaxX = Math.Max(b2.X, b2.Right);
                float b2MinX = Math.Min(b2.X, b2.Right);
                float b2MaxY = Math.Max(b2.Y, b2.Bottom);
                float b2MinY = Math.Min(b2.Y, b2.Bottom);

                if (!(b2MaxX > b1MaxX && b2MinX < b1MinX))
                {
                    if (b2MaxX > b1MaxX || b2MinX < b1MinX)
                    {
                        float difMaxX = b2MaxX - b1MaxX;
                        float difMinX = b2MinX - b1MinX;
                        if (Math.Abs(difMaxX) < Math.Abs(difMinX))
                        {
                            result.Width = difMaxX;
                        }
                        else
                        {
                            result.Width = difMinX;
                        }
                    }
                }

                if (!(b2MaxY > b1MaxY && b2MinY < b1MinY))
                {
                    if (b2MaxY > b1MaxY || b2MinY < b1MinY)
                    {
                        float difMaxY = b2MaxY - b1MaxY;
                        float difMinY = b2MinY - b1MinY;
                        if (Math.Abs(difMaxY) < Math.Abs(difMinY))
                        {
                            result.Height = difMaxY;
                        }
                        else
                        {
                            result.Height = difMinY;
                        }
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Drags the nodes in a standard selection.
        /// </summary>
        /// <param name="e">A PInputEventArgs that contains the event data.</param>
        /// <remarks>
        /// <b>Notes to Inheritors:</b>  Subclasses can override this method to be notified
        /// while a standard selection is being dragged.
        /// <para>
        /// Overriding methods must still call <c>base.DragStandardSelection()</c> for correct
        /// behavior.
        /// </para>
        /// </remarks>
        protected virtual void DragStandardSelection(PInputEventArgs e)
        {
            // There was a press node, so drag selection
            SizeFx s = e.CanvasDelta;

            s = e.TopCamera.LocalToView(s);

            ICollection sel = selection.Keys;

            foreach (PNode node in sel)
            {
                s = node.Parent.GlobalToLocal(s);
                node.OffsetBy(s.Width, s.Height);
            }
        }
Пример #13
0
        /// <summary>
        /// Animates the camera's view to keep the control node on the screen and at 100
        /// percent scale with minimal view movement.
        /// </summary>
        /// <param name="aCamera">The camera whose view will be animated.</param>
        /// <param name="aControlNode">The control node to animate to.</param>
        /// <param name="path">The pick path through which the control node was picked.</param>
        /// <param name="duration">The length of the animation.</param>
        /// <returns>
        /// The activity that animates the camera's view to the control node.
        /// </returns>
        public virtual PActivity DirectCameraViewToControl(PCamera aCamera, PControl aControlNode, PPickPath path, int duration)
        {
            Matrix originalViewMatrix = aCamera.ViewMatrix;

            // Scale the canvas to include
            SizeFx s = new SizeFx(1, 0);

            s = aControlNode.GlobalToLocal(s);

            float   scaleFactor = s.Width / aCamera.ViewScale;
            PointFx scalePoint  = PUtil.CenterOfRectangle(aControlNode.GlobalFullBounds);

            if (scaleFactor != 1)
            {
                aCamera.ScaleViewBy(scaleFactor, scalePoint.X, scalePoint.Y);
            }

            // Pan the canvas to include the view bounds with minimal canvas
            // movement.
            aCamera.AnimateViewToPanToBounds(aControlNode.GlobalFullBounds, 0);

            // Get rid of any white space. The canvas may be panned and
            // zoomed in to do this. But make sure not stay constrained by max
            // magnification.
            //FillViewWhiteSpace(aCamera);

            Matrix resultingMatrix = aCamera.ViewMatrix;

            aCamera.ViewMatrix = originalViewMatrix;

            PControl controlNode = (PControl)aControlNode;

            // Animate the canvas so that it ends up with the given
            // view transform.
            PActivity animateCameraViewActivity = AnimateCameraViewMatrixTo(aCamera, resultingMatrix, duration);

            aCamera.Root.WaitForActivities();

            Matrix  pathTransform = path.GetPathTransformTo(controlNode);
            PointFx point         = new PointFx(controlNode.X, controlNode.Y);
            PointFx pf            = MatrixExtensions.Transform(pathTransform, point);

            controlNode.ControlLocation = new System.Drawing.Point((int)pf.X, (int)pf.Y);
            controlNode.CurrentCanvas   = path.TopCamera.Canvas;
            controlNode.Editing         = true;

            return(animateCameraViewActivity);
        }
Пример #14
0
        /// <summary>
        /// Caches the information necessary to animate from the current view bounds to the
        /// specified centerBounds
        /// </summary>
        /// <param name="centerBounds">The bounds to center the view on.</param>
        /// <param name="scaleToFit">
        /// Indicates whether the camera should scale it's view when necessary to fully fit
        /// the given bounds within the camera's view bounds.
        /// </param>
        /// <returns>The new view matrix to center the specified bounds.</returns>
        private Matrix CacheViewBounds(RectangleFx centerBounds, bool scaleToFit)
        {
            RectangleFx viewBounds = ViewBounds;

            // Initialize the image to the union of the current and destination bounds
            RectangleFx imageBounds = viewBounds;

            imageBounds = RectangleFxtensions.Union(imageBounds, centerBounds);

            AnimateViewToCenterBounds(imageBounds, scaleToFit, 0);

            imageAnimateBounds = ViewBounds;

            // Now create the actual cache image that we will use to animate fast

            System.Drawing.Image buffer = PaintBuffer;
            Color fBrush = Color.White;

            if (Brush != Color.Transparent)
            {
                fBrush = Brush;
            }
            ToImage(buffer, fBrush);

            // Do this after the painting above!
            imageAnimate = true;

            // Return the bounds to the previous viewbounds
            AnimateViewToCenterBounds(viewBounds, scaleToFit, 0);

            // The code below is just copied from animateViewToCenterBounds to create the
            // correct transform to center the specified bounds

            SizeFx delta     = PUtil.DeltaRequiredToCenter(viewBounds, centerBounds);
            Matrix newMatrix = ViewMatrix;

            newMatrix = MatrixExtensions.TranslateBy(newMatrix, delta.Width, delta.Height);

            if (scaleToFit)
            {
                float   s      = Math.Min(viewBounds.Width / centerBounds.Width, viewBounds.Height / centerBounds.Height);
                PointFx center = PUtil.CenterOfRectangle(centerBounds);
                newMatrix = MatrixExtensions.ScaleBy(newMatrix, s, center.X, center.Y);
            }

            return(newMatrix);
        }
Пример #15
0
        //****************************************************************
        // Animation - Methods to animate the camera's view.
        //****************************************************************

        /// <summary>
        /// Animate the camera's view from its current matrix when the activity starts
        /// to a new matrix that centers the given bounds in the camera layers' coordinate
        /// system into the camera's view bounds.
        /// </summary>
        /// <param name="centerBounds">The bounds to center the view on.</param>
        /// <param name="shouldScaleToFit">
        /// Indicates whether the camera should scale it's view when necessary to fully fit
        /// the given bounds within the camera's view bounds.
        /// </param>
        /// <param name="duration">The amount of time that the animation should take.</param>
        /// <returns>
        /// The newly scheduled activity, if the duration is greater than 0; else null.
        /// </returns>
        /// <remarks>
        /// If the duration is 0 then the view will be transformed immediately, and null will
        /// be returned.  Else a new PTransformActivity will get returned that is set to
        /// animate the camera’s view matrix to the new bounds. If shouldScaleToFit is true,
        /// then the camera will also scale its view so that the given bounds fit fully within
        /// the camera's view bounds, else the camera will maintain its original scale.
        /// </remarks>
        public virtual PTransformActivity AnimateViewToCenterBounds(RectangleFx centerBounds, bool shouldScaleToFit, long duration)
        {
            SizeFx delta     = PUtil.DeltaRequiredToCenter(ViewBounds, centerBounds);
            Matrix newMatrix = ViewMatrix;

            newMatrix = MatrixExtensions.TranslateBy(newMatrix, delta.Width, delta.Height);

            if (shouldScaleToFit)
            {
                float s = Math.Min(ViewBounds.Width / centerBounds.Width, ViewBounds.Height / centerBounds.Height);
                if (s != float.PositiveInfinity && s != 0)
                {
                    PointFx c = PUtil.CenterOfRectangle(centerBounds);
                    MatrixExtensions.ScaleBy(newMatrix, s, c.X, c.Y);
                }
            }

            return(AnimateViewToMatrix(newMatrix, duration));
        }
Пример #16
0
        /// <summary>
        /// Pan the camera's view from its current matrix when the activity starts to a new
        /// matrix so that the view bounds will contain (if possible, intersect if not
        /// possible) the new bounds in the camera layers' coordinate system.
        /// </summary>
        /// <param name="panToBounds">The bounds to pan the view to.</param>
        /// <param name="duration">The amount of time that the animation should take.</param>
        /// <returns>
        /// The newly scheduled activity, if the duration is greater than 0; else null.
        /// </returns>
        /// <remarks>
        /// If the duration is 0 then the view will be transformed immediately, and null will
        /// be returned. Else a new PTransformActivity will get returned that is set to
        /// animate the camera’s view matrix to the new bounds.
        /// </remarks>
        public virtual PTransformActivity AnimateViewToPanToBounds(RectangleFx panToBounds, long duration)
        {
            SizeFx delta = PUtil.DeltaRequiredToContain(ViewBounds, panToBounds);

            if (delta.Width != 0 || delta.Height != 0)
            {
                if (duration == 0)
                {
                    TranslateViewBy(-delta.Width, -delta.Height);
                }
                else
                {
                    Matrix m = ViewMatrix;
                    m = MatrixExtensions.TranslateBy(m, -delta.Width, -delta.Height);
                    return(AnimateViewToMatrix(m, duration));
                }
            }

            return(null);
        }
Пример #17
0
        /// <summary>
        /// Overridden.  Do auto-panning even when the mouse is not moving.
        /// </summary>
        /// <param name="sender">The source of the drag event.</param>
        /// <param name="e">A PInputEventArgs that contains the event data.</param>
        protected override void OnDragActivityStep(object sender, PInputEventArgs e)
        {
            base.OnDragActivityStep(sender, e);

            if (!autopan)
            {
                return;
            }

            PCamera     c = e.Camera;
            RectangleFx b = c.Bounds;
            PointFx     l = e.GetPositionRelativeTo(c);

            PUtil.OutCode outcode = PUtil.RectangleOutCode(l, b);
            SizeFx        delta   = SizeFx.Empty;

            if ((outcode & PUtil.OutCode.Top) != 0)
            {
                delta.Height = ValidatePanningDelta(-1.0f - (0.5f * Math.Abs(l.Y - b.Y)));
            }
            else if ((outcode & PUtil.OutCode.Bottom) != 0)
            {
                delta.Height = ValidatePanningDelta(1.0f + (0.5f * Math.Abs(l.Y - (b.Y + b.Height))));
            }

            if ((outcode & PUtil.OutCode.Right) != 0)
            {
                delta.Width = ValidatePanningDelta(1.0f + (0.5f * Math.Abs(l.X - (b.X + b.Width))));
            }
            else if ((outcode & PUtil.OutCode.Left) != 0)
            {
                delta.Width = ValidatePanningDelta(-1.0f - (0.5f * Math.Abs(l.X - b.X)));
            }

            delta = c.LocalToView(delta);

            if (delta.Width != 0 || delta.Height != 0)
            {
                c.TranslateViewBy(delta.Width, delta.Height);
            }
        }
        /// <summary>
        /// Gets the size of the view based on the specified camera bounds.
        /// </summary>
        /// <param name="bounds">The view bounds for which the view size will be computed.</param>
        /// <returns>The view size.</returns>
        public virtual SizeFx GetViewSize(RectangleFx bounds)
        {
            SizeFx size = SizeFx.Empty;

            if (camera != null)
            {
                // First we compute the union of all the layers
                RectangleFx layerBounds = UnionOfLayerFullBounds;

                // Then we put the bounds into camera coordinates and
                // union the camera bounds
                if (!layerBounds.IsEmpty)
                {
                    layerBounds = camera.ViewToLocal(layerBounds);
                }
                layerBounds = RectangleFxtensions.Union(layerBounds, bounds);

                size = new SizeFx((int)(layerBounds.Width + 0.5), (int)(layerBounds.Height + 0.5));
            }

            return(size);
        }
Пример #19
0
 /// <summary>
 /// Transform the size from the camera's local coordinate system to the camera's
 /// view coordinate system.
 /// </summary>
 /// <param name="size">
 /// The size in the camera's local coordinate system to be transformed.
 /// </param>
 /// <returns>The size in the camera's view coordinate system.</returns>
 public virtual SizeFx LocalToView(SizeFx size)
 {
     return(MatrixExtensions.InverseTransform(viewMatrix, size));
 }
Пример #20
0
 public override void OnHandleDrag(object sender, SizeFx size, PInputEventArgs e)
 {
     base.OnHandleDrag(sender, size, e);
     size = LocalToParent(size);
     Parent.TranslateBy(size.Width, size.Height);
 }
Пример #21
0
        /// <summary>
        /// Return the delta between the last and current mouse positions relative to a
        /// given node on the pick path.
        /// </summary>
        /// <param name="nodeOnPath">
        /// The returned delta will be in the local coordinate system of this node.
        /// </param>
        /// <returns>
        /// The delta between the last and current mouse positions relative to a given
        /// node on the pick path.
        /// </returns>
        public virtual SizeFx GetDeltaRelativeTo(PNode nodeOnPath)
        {
            SizeFx r = CanvasDelta;

            return(pickPath.CanvasToLocal(r, nodeOnPath));
        }
Пример #22
0
 /// <summary>
 /// Transform the size from the camera's view coordinate system to the camera's
 /// local coordinate system.
 /// </summary>
 /// <param name="size">
 /// The size in the camera's view coordinate system to be transformed.
 /// </param>
 /// <returns>The size in the camera's local coordinate system.</returns>
 public virtual SizeFx ViewToLocal(SizeFx size)
 {
     return(MatrixExtensions.Transform(viewMatrix, size));
 }
                protected override void OnDrag(object sender, PInputEventArgs e)
                {
                    SizeFx dim = e.Delta;

                    bev.viewedCanvas.Camera.TranslateViewBy(0 - dim.Width, 0 - dim.Height);
                }
Пример #24
0
 /// <summary>
 /// Override this method to customize the image cache creation process. For
 /// example if you want to create a shadow effect you would do that here. Fill
 /// in the cacheOffsetRef if needed to make your image cache line up with the
 /// nodes children.
 /// </summary>
 /// <param name="cacheOffsetRef">
 /// Set this value to apply an offset to the image cache.
 /// </param>
 /// <returns>The newly created image cache.</returns>
 public virtual Image CreateImageCache(ref SizeFx cacheOffsetRef)
 {
     return(ToImage());
 }
Пример #25
0
        /// <summary>
        /// Convert the given size from canvas coordinates, down the pick path (and through any
        /// camera view transforms applied to the path) to the local coordinates of the given node.
        /// </summary>
        /// <param name="canvasSize">The size in canvas coordinates.</param>
        /// <param name="nodeOnPath">
        /// The node for which the local coordinates will be computed.
        /// </param>
        /// <returns>The size in the local coordinates of the given node.</returns>
        public virtual SizeFx CanvasToLocal(SizeFx canvasSize, PNode nodeOnPath)
        {
            Matrix path = GetPathTransformTo(nodeOnPath);

            return(MatrixExtensions.InverseTransform(path, canvasSize));
        }
Пример #26
0
        /// <summary>
        /// Overridden.  Determines if this bounds handle or any of it's siblings need to be
        /// flipped.
        /// </summary>
        /// <param name="sender">The source of this handle drag event.</param>
        /// <param name="size">The drag delta relative to the handle.</param>
        /// <param name="e">A PInputEventArgs that contains the event data.</param>
        /// <remarks>
        /// While dragging the bounds handles, the node being resized may cross over itself and
        /// become reversed (if it is dragged through zero-width or zero-height).  In this case,
        /// the locators for some of the bounds handles will have to be flipped to the opposite
        /// side.
        /// </remarks>
        public override void OnHandleDrag(object sender, SizeFx size, PInputEventArgs e)
        {
            base.OnHandleDrag(sender, size, e);
            PBoundsLocator l = (PBoundsLocator)Locator;

            PNode       n = l.Node;
            RectangleFx b = n.Bounds;

            PNode parent = Parent;

            if (parent != n && parent is PCamera)
            {
                size = ((PCamera)parent).LocalToView(size);
            }

            size = LocalToGlobal(size);
            size = n.GlobalToLocal(size);

            float dx = size.Width;
            float dy = size.Height;

            switch (l.Side)
            {
            case Direction.North:
                b = new RectangleFx(b.X, b.Y + dy, b.Width, b.Height - dy);
                break;

            case Direction.South:
                b = new RectangleFx(b.X, b.Y, b.Width, b.Height + dy);
                break;

            case Direction.East:
                b = new RectangleFx(b.X, b.Y, b.Width + dx, b.Height);
                break;

            case Direction.West:
                b = new RectangleFx(b.X + dx, b.Y, b.Width - dx, b.Height);
                break;

            case Direction.NorthWest:
                b = new RectangleFx(b.X + dx, b.Y + dy, b.Width - dx, b.Height - dy);
                break;

            case Direction.SouthWest:
                b = new RectangleFx(b.X + dx, b.Y, b.Width - dx, b.Height + dy);
                break;

            case Direction.NorthEast:
                b = new RectangleFx(b.X, b.Y + dy, b.Width + dx, b.Height - dy);
                break;

            case Direction.SouthEast:
                b = new RectangleFx(b.X, b.Y, b.Width + dx, b.Height + dy);
                break;
            }

            bool flipX = false;
            bool flipY = false;

            if (b.Width < 0)
            {
                flipX = true;
                //b.Width = -b.Width;
                //b.X -= b.Width;
                float width = -b.Width;
                float x     = b.X - b.Width;
                b = new RectangleFx(x, b.Y, width, b.Height);
            }

            if (b.Height < 0)
            {
                flipY = true;
                //b.Height = -b.Height;
                //b.Y -= b.Height;
                float height = -b.Height;
                float y      = b.Y - b.Height;
                b = new RectangleFx(b.X, y, b.Width, y);
            }

            if (flipX || flipY)
            {
                FlipSiblingBoundsHandles(flipX, flipY);
            }

            n.Bounds = b;
        }