/// <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(); } }
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> /// 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> /// 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); } }
/// <summary> /// Pushes the current clip onto the clip stack and sets clip of the graphics context to /// the intersection of the current clip and the given clip. /// </summary> /// <remarks> /// The intersection of the current local clip and the new local clip is also pushed onto /// the local clip stack. /// </remarks> /// <param name="aClip">The clip to push.</param> public virtual void PushClip(RectangleFx aClip) { RectangleFx newLocalClip = RectangleFxtensions.Intersect(LocalClip, graphics.ClipBounds); localClipStack.Push(newLocalClip); //RegionFx currentClip = Graphics.Clip; RectangleFx currentClip = Graphics.ClipBounds; clipStack.Push(currentClip); //aClip = aClip.Clone(); aClip.Intersects(currentClip); Graphics.ClipBounds = aClip; }
public override void SetViewPosition(float x, float y) { if (camera != null) { // If a scroll is in progress - we ignore new scrolls - // if we didn't, since the scrollbars depend on the camera location // we can end up with an infinite loo if (!scrollInProgress) { scrollInProgress = true; // Get the union of all the layers' bounds RectangleFx layerBounds = camera.UnionOfLayerFullBounds; Matrix matrix = camera.ViewMatrix; layerBounds = MatrixExtensions.Transform(matrix, layerBounds); // Union the camera view bounds RectangleFx viewBounds = camera.Bounds; layerBounds = RectangleFxtensions.Union(layerBounds, viewBounds); // Now find the new view position in view coordinates - // This is basically the distance from the lower right // corner of the window to the upper left corner of the // document // We then measure the offset from the lower right corner // of the document PointFx newPoint = new PointFx( layerBounds.X + layerBounds.Width - (x + viewBounds.Width), layerBounds.Y + layerBounds.Height - (y + viewBounds.Height)); // 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; } } }
/// <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); }
/// <summary> /// Returns the union of the two rectangles. If one rectangle is empty and one is not, /// the non-empty rectangle will be returned. /// </summary> /// <param name="rect1">The first rectangle.</param> /// <param name="rect2">The second rectangle.</param> /// <returns>The union of the two rectangles.</returns> public static RectangleFx AddRectToRect(RectangleFx rect1, RectangleFx rect2) { RectangleFx result = rect1; if (!result.IsEmpty) { if (!rect2.IsEmpty) { result = RectangleFxtensions.Union(result, rect2); } } else { result = rect2; } return(result); }
/// <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; } } }
/// <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); }
/// <summary> /// Gets the view position given the specified camera bounds. /// </summary> /// <param name="bounds"> /// The bounds for which the view position will be computed. /// </param> /// <returns>The view position.</returns> public virtual PointFx GetViewPosition(RectangleFx bounds) { PointFx pos = PointFx.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); pos = new PointFx((int)(bounds.X - layerBounds.X + 0.5), (int)(bounds.Y - layerBounds.Y + 0.5)); } return(pos); }
/// <summary> /// Gets a rectangle centered on the given point and inflated in the x and y directions /// by the given amounts. /// </summary> /// <param name="aCenterPoint">The center point for the inflated rectangle.</param> /// <param name="inflateX"> /// The amount to inflate the rectangle in the x direction. /// </param> /// <param name="inflateY"> /// The amount to inflate the rectangle in the y direction. /// </param> /// <returns>The inflated rectangle.</returns> public static RectangleFx InflatedRectangle(PointFx aCenterPoint, float inflateX, float inflateY) { System.Drawing.RectangleF r = new System.Drawing.RectangleF(aCenterPoint.X, aCenterPoint.Y, 0, 0); r.Inflate(inflateX, inflateY); return(RectangleFxtensions.ToRectangleFx(r)); }
/// <summary> /// Constructs a new PControl, wrapping the given /// <see cref="System.Windows.Forms.Control">System.Windows.Forms.Control</see> and /// setting the current canvas to the given canvas. /// </summary> /// <param name="control">The control to wrap.</param> /// <param name="currentCanvas"> /// The canvas to add the control to when <see cref="Editing"/> is turned on. /// </param> public PControl(Control control, PCanvas currentCanvas) { this.control = control; this.currentCanvas = currentCanvas; this.Bounds = RectangleFxtensions.ToRectangleFx(control.Bounds); }