/// <summary> /// Removes any white space. The canvas may be panned and zoomed in to do this. /// </summary> /// <param name="aCamera">The camera whose view will be adjusted.</param> protected virtual void FillViewWhiteSpace(PCamera aCamera) { RectangleFx rootBounds = aCamera.Root.FullBounds; RectangleFx viewBounds = aCamera.ViewBounds; if (!rootBounds.Contains(aCamera.ViewBounds)) { aCamera.AnimateViewToPanToBounds(rootBounds, 0); aCamera.AnimateViewToPanToBounds(focusNode.GlobalFullBounds, 0); // center content. float dx = 0; float dy = 0; viewBounds = aCamera.ViewBounds; if (viewBounds.Width > rootBounds.Width) // then center along x axis. { float rootBoundsMinX = Math.Min(rootBounds.X, rootBounds.Right); float viewBoundsMinX = Math.Min(viewBounds.X, viewBounds.Right); float boundsCenterX = rootBoundsMinX + (rootBounds.Width / 2); float viewBoundsCenterX = viewBoundsMinX + (viewBounds.Width / 2); dx = viewBoundsCenterX - boundsCenterX; } if (viewBounds.Height > rootBounds.Height) // then center along y axis. { float rootBoundsMinY = Math.Min(rootBounds.Y, rootBounds.Right); float viewBoundsMinY = Math.Min(viewBounds.Y, viewBounds.Right); float boundsCenterY = rootBoundsMinY + (rootBounds.Height / 2); float viewBoundsCenterY = viewBoundsMinY + (viewBounds.Height / 2); dy = viewBoundsCenterY - boundsCenterY; } aCamera.TranslateViewBy(dx, dy); } }
/// <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); }
/// <summary> /// Invalidates the specified region of the canvas (adds it to the canvas's update region, /// which is the area that will be repainted at the next paint operation), and causes a paint /// message to be sent to the canvas. /// </summary> /// <param name="bounds">A rectangle object that represents the region to invalidate.</param> public virtual void InvalidateBounds(RectangleFx bounds) { PDebug.ProcessInvalidate(); if (regionManagement) { // Hack: Invalidate the bounds of the previously invalidated rectangle // and the current rectangle, since invalidating lots of small rectangles // causes a performance hit. if (invalidatedBounds.IsEmpty) { invalidatedBounds = bounds; } else { invalidatedBounds = RectangleFxtensions.Union(invalidatedBounds, bounds); } RectangleFx insetRect = new RectangleFx(invalidatedBounds.X - 1, invalidatedBounds.Y - 1, invalidatedBounds.Width + 2, invalidatedBounds.Height + 2); int x = (int)Math.Floor(insetRect.X); int y = (int)Math.Floor(insetRect.Y); int width = (int)Math.Ceiling(insetRect.Right - x); int height = (int)Math.Ceiling(insetRect.Bottom - y); Invalidate(new System.Drawing.Rectangle(x, y, width, height)); } else { Invalidate(); } }
/// <summary> /// Force this handle to relocate itself using its locator. /// </summary> public virtual void RelocateHandle() { if (locator != null) { RectangleFx b = Bounds; PointFx aPoint = locator.LocatePoint; if (locator is PNodeLocator) { PNode located = ((PNodeLocator)locator).Node; PNode parent = Parent; aPoint = located.LocalToGlobal(aPoint); aPoint = GlobalToLocal(aPoint); if (parent != located && parent is PCamera) { aPoint = ((PCamera)parent).ViewToLocal(aPoint); } } float newCenterX = aPoint.X; float newCenterY = aPoint.Y; PointFx bCenter = PUtil.CenterOfRectangle(b); if (newCenterX != bCenter.X || newCenterY != bCenter.Y) { CenterBoundsOnPoint(newCenterX, newCenterY); } } }
/// <summary> /// Expands the given rectangle to include the given point. /// </summary> /// <param name="rect">The rectangle to expand.</param> /// <param name="p">The point to include.</param> /// <returns>The expanded rectangle.</returns> public static RectangleFx AddPointToRect(RectangleFx rect, PointFx p) { float px = p.X; float py = p.Y; float rx = rect.X; float ry = rect.Y; float rw = rect.Width; float rh = rect.Height; if (rect == RectangleFx.Empty) { //rect.X = px; //rect.Y = py; //rect.Width = 0; //rect.Height = 0; rect = new RectangleFx(px, py, 0, 0); } else { float x1 = (rx <= px) ? rx : px; float y1 = (ry <= py) ? ry : py; float x2 = ((rx + rw) >= px) ? (rx + rw) : px; float y2 = ((ry + rh) >= py) ? (ry + rh) : py; //rect.X = x1; //rect.Y = y1; //rect.Width = x2 - x1; //rect.Height = y2 - y1; rect = new RectangleFx(x1, y1, x2 - x1, y2 - y1); } return(rect); }
/// <summary> /// Draws the control. /// </summary> protected override void Draw() { UpdateTimer(); Update(); // Clear to the default control background color. //Color backColor = new Color(BackColor.R, BackColor.G, BackColor.B); Microsoft.Xna.Framework.Color backColor = Microsoft.Xna.Framework.Color.LightCyan; GraphicsDevice.Clear(backColor); if (XnaGraphics != null && DrawingContext != null && Texture != null && SpriteFont != null) { PDebug.StartProcessingOutput(); // Clear the invalidatedBounds cache. invalidatedBounds = RectangleFx.Empty; PPaintContext paintContext = new PPaintContext(XnaGraphics, this); PaintPiccolo(paintContext); // Calling the base class OnPaint //base.OnPaint(pe); PDebug.EndProcessingOutput(paintContext); } }
/// <summary> /// Returns true if this path intersects the given rectangle. /// </summary> /// <remarks> /// This method first checks if the interior of the path intersects with the rectangle. /// If not, the method then checks if the path bounding the pen stroke intersects with /// the rectangle. If either of these cases are true, this method returns true. /// <para> /// <b>Performance Note</b>: For some paths, this method can be very slow. This is due /// to the implementation of IsVisible. The problem usually occurs when many lines are /// joined at very steep angles. See <see cref="PPath">PPath Overview</see> for workarounds. /// </para> /// </remarks> /// <param name="bounds">The rectangle to check for intersection.</param> /// <param name="matrix"> /// A matrix object that specifies a transform to apply to the path and bounds before /// checking for an intersection. /// </param> /// <returns>True if this path intersects the given rectangle; otherwise, false.</returns> public virtual bool Intersects(RectangleFx bounds, Matrix matrix) { if (base.Intersects(bounds)) { // Transform the bounds. if (!(matrix == Matrix.Identity)) { bounds = MatrixExtensions.Transform(matrix, bounds); } // Set the temp region to the transformed path. SetTempRegion(path, matrix, false); if (Brush != Color.Transparent && TEMP_REGION.IntersectsWith(bounds)) { return(true); } else if (pen != null) { // Set the temp region to the transformed, widened path. SetTempRegion(path, matrix, true); return(TEMP_REGION.IntersectsWith(bounds)); } } return(false); }
protected override void Paint(PPaintContext paintContext) { // make sure grid gets drawn on snap to grid boundaries. And // expand a little to make sure that entire view is filled. float bx = (X - (X % gridSpacing)) - gridSpacing; float by = (Y - (Y % gridSpacing)) - gridSpacing; float rightBorder = X + Width + gridSpacing; float bottomBorder = Y + Height + gridSpacing; XnaGraphics g = paintContext.Graphics; RectangleFx clip = paintContext.LocalClip; for (float x = bx; x < rightBorder; x += gridSpacing) { gridLine.Reset(); gridLine.AddLine(x, by, x, bottomBorder); if (PUtil.RectIntersectsPerpLine(clip, x, by, x, bottomBorder)) { g.DrawPath(gridPen, gridLine); } } for (float y = by; y < bottomBorder; y += gridSpacing) { gridLine.Reset(); gridLine.AddLine(bx, y, rightBorder, y); if (PUtil.RectIntersectsPerpLine(clip, bx, y, rightBorder, y)) { g.DrawPath(gridPen, gridLine); } } }
/// <summary> /// Returns the center of the given rectangle. /// </summary> /// <param name="r">The rectangle whose center point is desired.</param> /// <returns>The center point of the given rectangle.</returns> public static PointFx CenterOfRectangle(RectangleFx r) { float centerX = r.X + (r.Width / 2); float centerY = r.Y + (r.Height / 2); return(new PointFx(centerX, centerY)); }
/// <summary> /// This method is called to update the bounds whenever the underlying path changes. /// </summary> public virtual void UpdateBoundsFromPath() { updatingBoundsFromPath = true; if (path == null || path.PointCount == 0) { ResetBounds(); } else { try { TEMP_PATH.Reset(); TEMP_PATH.AddPath(path, false); if (pen != null && TEMP_PATH.PointCount > 0) { TEMP_PATH.Widen(pen); } RectangleFx b = TEMP_PATH.GetBounds(); SetBounds(b.X, b.Y, b.Width, b.Height); } catch (OutOfMemoryException) { //Catch the case where the path is a single point } } updatingBoundsFromPath = false; }
/// <summary> /// Pops a clip from both the clip stack and the local clip stack and sets the clip of the /// graphics context to the clip popped from the clip stack. /// </summary> public virtual void PopClip() { RectangleFx newClip = (RectangleFx)clipStack.Pop(); Graphics.ClipBounds = newClip; localClipStack.Pop(); }
/// <summary> /// Notify the cameras looking at this layer to paint their views. /// </summary> /// <param name="bounds"> /// The bounds to repaint, specified in the view coordinate system. /// </param> protected virtual void NotifyCameras(RectangleFx bounds) { foreach (PCamera each in cameras) { each.RepaintFromLayer(bounds, this); } }
public override PointFx GetViewPosition(RectangleFx bounds) { PointFx pos = PointFx.Empty; if (camera != null) { // First we compute the union of all the layers RectangleFx layerBounds = camera.UnionOfLayerFullBounds; // Then we put the bounds into camera coordinates and // union the camera bounds layerBounds = camera.ViewToLocal(layerBounds); layerBounds = RectangleFxtensions.Union(layerBounds, bounds); // Rather than finding the distance from the upper left corner // of the window to the upper left corner of the document - // we instead find the distance from the lower right corner // of the window to the upper left corner of the document // THEN we measure the offset from the lower right corner // of the document int x = (int)(layerBounds.Width - (bounds.X + bounds.Width - layerBounds.X) + 0.5); int y = (int)(layerBounds.Height - (bounds.Y + bounds.Height - layerBounds.Y) + 0.5); // Make sure the value isn't greater than the maximum x = (int)Math.Min(x, layerBounds.Width - 1); y = (int)Math.Min(y, layerBounds.Height - 1); pos = new PointFx(x, y); } return(pos); }
/// <summary> /// Overridden. Pass the given repaint request up the tree if the image cache is /// not currently being created. /// </summary> /// <param name="bounds"> /// The bounds to repaint, specified in the local coordinate system. /// </param> /// <param name="childOrThis"> /// If childOrThis does not equal this then this node's matrix will be applied to /// the bounds paramater. /// </param> public override void RepaintFrom(RectangleFx bounds, PNode childOrThis) { if (!validatingCache) { base.RepaintFrom(bounds, childOrThis); InvalidateCache(); } }
public override RectangleFx ComputeFullBounds() { RectangleFx result = UnionOfChildrenBounds; cachedChildBounds = result; result = new RectangleFx(result.X - INDENT, result.Y - INDENT, result.Width + 2 * INDENT, result.Height + 2 * INDENT); result = LocalToParent(result); return(result); }
/// <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) { RectangleFx b = new RectangleFx(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> /// Pushes the given matrix onto the matrix stack. /// </summary> /// <param name="aMatrix">The matrix to push.</param> public virtual void PushMatrix(Matrix aMatrix) { matrixStack.Push(new PTuple(PickedNode, aMatrix)); if (aMatrix != null) { RectangleFx pickBound = PickBounds; RectangleFx newPickBounds = MatrixExtensions.InverseTransform(aMatrix, pickBound); pickBoundsStack.Push(newPickBounds); } }
protected override bool ValidateFullBounds() { comparisonBounds = UnionOfChildrenBounds; if (!cachedChildBounds.Equals(comparisonBounds)) { PaintInvalid = true; } return(base.ValidateFullBounds()); }
//**************************************************************** // Painting - Methods for painting a PImage. //**************************************************************** /// <summary> /// Overridden. See <see cref="PNode.Paint">PNode.Paint</see>. /// </summary> protected override void Paint(PPaintContext paintContext) { if (rect != null) { RectangleFx b = Bounds; XnaGraphics g = paintContext.Graphics; g.DrawRectangle(this.Brush, rect); } }
//**************************************************************** // Painting - Methods for painting a PImage. //**************************************************************** /// <summary> /// Overridden. See <see cref="PNode.Paint">PNode.Paint</see>. /// </summary> protected override void Paint(PPaintContext paintContext) { if (Image != null) { RectangleFx b = Bounds; XnaGraphics g = paintContext.Graphics; g.DrawImage(image, b.ToRectangleF()); } }
/// <summary> /// Constructs a new PPickPath. /// </summary> /// <param name="aCamera">The camera that originated the pick action.</param> /// <param name="aScreenPickBounds">The bounds being picked.</param> public PPickPath(PCamera aCamera, RectangleFx aScreenPickBounds) { pickBoundsStack = new Stack(); bottomCamera = null; topCamera = aCamera; nodeStack = new Stack(); matrixStack = new Stack(); pickBoundsStack.Push(aScreenPickBounds); CURRENT_PICK_PATH = this; }
/// <summary> /// Mimics the standard <see cref="PCamera.AnimateViewToCenterBounds">AnimateViewToCenterBounds</see> /// but uses a cached image for performance rather than re-rendering the scene at each step /// </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> public PTransformActivity AnimateStaticViewToCenterBoundsFast(RectangleFx centerBounds, bool shouldScaleToFit, long duration) { if (duration == 0) { return(AnimateViewToCenterBounds(centerBounds, shouldScaleToFit, duration)); } Matrix newViewMatrix = CacheViewBounds(centerBounds, shouldScaleToFit); return(AnimateStaticViewToTransformFast(newViewMatrix, duration)); }
protected override void Paint(PPaintContext paintContext) { if (Brush != Color.Transparent) { XnaGraphics g = paintContext.Graphics; RectangleFx bounds = UnionOfChildrenBounds; bounds = new RectangleFx(bounds.X - INDENT, bounds.Y - INDENT, bounds.Width + 2 * INDENT, bounds.Height + 2 * INDENT); g.FillRectangle(Brush, bounds); } }
/// <summary> /// Repaint from one of the camera's layers. /// </summary> /// <param name="bounds">The bounds to repaint, in view coordinates.</param> /// <param name="repaintedLayer">The layer that was repainted.</param> /// <remarks> /// The repaint region needs to be transformed from view to local coordinates in /// this case. Unlike most repaint methods in piccolo this one must not modify /// the bounds parameter. /// </remarks> public virtual void RepaintFromLayer(RectangleFx bounds, PNode repaintedLayer) { bounds = ViewToLocal(bounds); bool boundsIntesects = Bounds.IntersectsWith(bounds); if (boundsIntesects) { RectangleFx tempRect = RectangleFxtensions.Intersect(bounds, Bounds); RepaintFrom(tempRect, repaintedLayer); } }
/// <summary> /// Returns true if the node's bounds intersects the bounds specified by the /// BoundsFilter. /// </summary> /// <remarks> /// For a node to be accepted, it must also satisfy the following conditions: /// it must be pickable, it must not be the marquee node, it must not be a /// selectable parent, and the it must not be a layer that is viewed by a camera /// that is a selectable parent /// </remarks> /// <param name="node">The node to test.</param> /// <returns>True if the node is accepted; otherwise, false.</returns> public virtual bool Accept(PNode node) { localBounds = bounds; localBounds = node.GlobalToLocal(localBounds); bool boundsIntersects = node.Intersects(localBounds); bool isMarquee = (node == selectionHandler.marquee); return(node.Pickable && boundsIntersects && !isMarquee && !selectionHandler.selectableParents.Contains(node) && !IsCameraLayer(node)); }
/// <summary> /// This method paints the bounds and full bounds of nodes when the appropriate debug /// flags are set. /// </summary> /// <param name="paintContext"> /// The paint context to use for painting debug information. /// </param> /// <remarks> /// Setting debugBounds and/or debugFullBounds flags is useful for visual debugging. /// </remarks> protected virtual void PaintDebugInfo(PPaintContext paintContext) { if (PDebug.DebugBounds || PDebug.DebugFullBounds) { PNodeList nodes = new PNodeList(); RectangleFx nodeBounds = RectangleFx.Empty; for (int i = 0; i < LayerCount; i++) { GetLayer(i).GetAllNodes(null, nodes); } GetAllNodes(null, nodes); foreach (PNode each in nodes) { if (PDebug.DebugBounds) { nodeBounds = each.Bounds; if (!nodeBounds.IsEmpty) { nodeBounds = each.LocalToGlobal(nodeBounds); nodeBounds = GlobalToLocal(nodeBounds); if (each == this || each.IsDescendentOf(this)) { nodeBounds = LocalToView(nodeBounds); } PaintDebugBounds(paintContext, boundsPen, nodeBounds); } } if (PDebug.DebugFullBounds) { nodeBounds = each.FullBounds; if (!nodeBounds.IsEmpty) { if (each.Parent != null) { nodeBounds = each.Parent.LocalToGlobal(nodeBounds); } nodeBounds = GlobalToLocal(nodeBounds); if (each == this || each.IsDescendentOf(this)) { nodeBounds = LocalToView(nodeBounds); } PaintDebugFullBounds(paintContext, fullBoundsBrush, nodeBounds); } } } } }
/// <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> /// 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); }
/// <summary> /// Overridden. If the repaint request comes from a child, then /// repaint the intersection of the clip's bounds and the requested /// repaint bounds. /// </summary> /// <param name="bounds"> /// The bounds to repaint, specified in the local coordinate system. /// </param> /// <param name="childOrThis"> /// If childOrThis does not equal this then this node's matrix will /// be applied to the bounds paramater. /// </param> public override void RepaintFrom(RectangleFx bounds, PNode childOrThis) { if (childOrThis != this) { bounds = RectangleFxtensions.Intersect(Bounds, bounds); base.RepaintFrom(bounds, childOrThis); } else { base.RepaintFrom(bounds, childOrThis); } }
public void UpdateRectangle() { // create a new bounds that contains both the press and current // drag point. RectangleFx r = RectangleFx.Empty; r = PUtil.AddPointToRect(r, pressPoint); r = PUtil.AddPointToRect(r, dragPoint); // Set the rectangles bounds. rectangle.PathReference.Reset(); rectangle.AddRectangle(r.X, r.Y, r.Width, r.Height); }