/// <summary>
        /// Overridden.  Sets the bounds of the target node.
        /// </summary>
        /// <param name="x">The new x coordinate of the bounds.</param>
        /// <param name="y">The new y coordinate of the bounds.</param>
        /// <param name="width">The new width of the bounds.</param>
        /// <param name="height">The new height of the bounds.</param>
        /// <returns>True if the bounds have changed; otherwise, false.</returns>
        /// <remarks>
        /// These bounds are stored in the local coordinate system of the target node.
        /// </remarks>
        public override bool SetBounds(float x, float y, float width, float height)
        {
            RectangleF b = new RectangleF(x, y, width, height);

            b             = camera.LocalToGlobal(b);
            b             = camera.LocalToView(b);
            b             = target.GlobalToLocal(b);
            target.Bounds = b;
            return(base.SetBounds(x, y, width, height));
        }
        /// <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>
        /// Sets the view position in a manner consistent with standardized scrolling.
        /// </summary>
        /// <param name="x">The x coordinate of the new position.</param>
        /// <param name="y">The y coordinate of the new position.</param>
        public virtual void SetViewPosition(float x, float y)
        {
            if (camera != null)
            {
                // Only process this scroll if a scroll is not already in progress;
                // otherwise, we could end up with an infinite loop, since the
                // scrollbars depend on the camera location.
                if (!scrollInProgress)
                {
                    scrollInProgress = true;

                    // Get the union of all the layers' bounds
                    RectangleFx layerBounds = UnionOfLayerFullBounds;

                    Matrix matrix = camera.ViewMatrix;
                    layerBounds = MatrixExtensions.Transform(matrix, layerBounds);

                    // Union the camera bounds
                    RectangleFx viewBounds = camera.Bounds;
                    layerBounds = RectangleFxtensions.Union(layerBounds, viewBounds);

                    // Now find the new view position in view coordinates
                    PointFx newPoint = new PointFx(layerBounds.X + x, layerBounds.Y + y);

                    // Now transform the new view position into global coords
                    newPoint = camera.LocalToView(newPoint);

                    // Compute the new matrix values to put the camera at the
                    // correct location
                    float[] elements = MatrixExtensions.GetElements(matrix);
                    elements[4] = -(elements[0] * newPoint.X + elements[1] * newPoint.Y);
                    elements[5] = -(elements[2] * newPoint.X + elements[3] * newPoint.Y);

                    matrix = MatrixExtensions.SetElements(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5]);

                    // Now actually set the camera's transform
                    camera.ViewMatrix = matrix;
                    scrollInProgress  = false;
                }
            }
        }