protected override void OnLift(MouseEventArgs e) { PdnGraphicsPath liftPath = Selection.CreatePath(); PdnRegion liftRegion = Selection.CreateRegion(); this.ourContext.LiftedPixels = new MaskedSurface(activeLayer.Surface, liftPath); HistoryMemento bitmapAction = new BitmapHistoryMemento( Name, Image, DocumentWorkspace, ActiveLayerIndex, this.ourContext.poLiftedPixelsGuid); this.currentHistoryMementos.Add(bitmapAction); // If the user is holding down the control key, we want to *copy* the pixels // and not "lift and erase" if ((ModifierKeys & Keys.Control) == Keys.None) { ColorBgra fill = AppEnvironment.SecondaryColor; fill.A = 0; UnaryPixelOp op = new UnaryPixelOps.Constant(fill); op.Apply(this.renderArgs.Surface, liftRegion); } liftRegion.Dispose(); liftRegion = null; liftPath.Dispose(); liftPath = null; }
protected override SegmentedList <PointDouble> CreateShape(SegmentedList <PointDouble> tracePoints) { RectDouble num5; PointDouble a = tracePoints[0]; PointDouble b = tracePoints[tracePoints.Count - 1]; PointDouble num3 = new PointDouble(b.X - a.X, b.Y - a.Y); double num4 = Math.Sqrt((num3.X * num3.X) + (num3.Y * num3.Y)); if ((base.ModifierKeys & Keys.Shift) != Keys.None) { PointDouble center = new PointDouble((a.X + b.X) / 2.0, (a.Y + b.Y) / 2.0); double num7 = num4 / 2.0; num5 = RectDouble.FromCenter(center, (double)(num7 * 2.0)); } else { num5 = RectDoubleUtil.FromPixelPoints(a, b); } PdnGraphicsPath path = new PdnGraphicsPath(); path.AddEllipse(num5.ToGdipRectangleF()); using (Matrix matrix = new Matrix()) { path.Flatten(matrix, 0.1f); } SegmentedList <PointDouble> list = new SegmentedList <PointDouble>(path.PathPoints.Select <PointF, PointDouble>(pt => pt.ToDoublePoint()), 7); path.Dispose(); return(list); }
private static Surface CreateThumbnail(SurfaceForClipboard surfaceForClipboard) { const int thumbLength96dpi = 120; int thumbSizeOurDpi = SystemLayer.UI.ScaleWidth(thumbLength96dpi); Surface surface = surfaceForClipboard.MaskedSurface.SurfaceReadOnly; PdnGraphicsPath maskPath = surfaceForClipboard.MaskedSurface.CreatePath(); Rectangle bounds = surfaceForClipboard.Bounds; Surface thumb = CreateThumbnail(surface, maskPath, bounds, thumbSizeOurDpi); maskPath.Dispose(); return(thumb); }
public override HistoryMemento OnExecute(IHistoryWorkspace historyWorkspace) { if (historyWorkspace.Selection.IsEmpty) { return(null); } else { SelectionHistoryMemento sha = new SelectionHistoryMemento( StaticName, StaticImage, historyWorkspace); //PdnGraphicsPath selectedPath = historyWorkspace.Selection.GetPathReadOnly(); PdnGraphicsPath selectedPath = historyWorkspace.Selection.CreatePath(); PdnGraphicsPath boundsOutline = new PdnGraphicsPath(); boundsOutline.AddRectangle(historyWorkspace.Document.Bounds); PdnGraphicsPath clippedPath = PdnGraphicsPath.Combine(selectedPath, CombineMode.Intersect, boundsOutline); PdnGraphicsPath invertedPath = PdnGraphicsPath.Combine(clippedPath, CombineMode.Xor, boundsOutline); selectedPath.Dispose(); selectedPath = null; clippedPath.Dispose(); clippedPath = null; EnterCriticalRegion(); historyWorkspace.Selection.PerformChanging(); historyWorkspace.Selection.Reset(); historyWorkspace.Selection.SetContinuation(invertedPath, CombineMode.Replace, true); historyWorkspace.Selection.CommitContinuation(); historyWorkspace.Selection.PerformChanged(); boundsOutline.Dispose(); boundsOutline = null; return(sha); } }
public override HistoryMemento OnExecute(IHistoryWorkspace historyWorkspace) { if (historyWorkspace.Selection.IsEmpty) { return null; } else { SelectionHistoryMemento sha = new SelectionHistoryMemento( StaticName, StaticImage, historyWorkspace); //PdnGraphicsPath selectedPath = historyWorkspace.Selection.GetPathReadOnly(); PdnGraphicsPath selectedPath = historyWorkspace.Selection.CreatePath(); PdnGraphicsPath boundsOutline = new PdnGraphicsPath(); boundsOutline.AddRectangle(historyWorkspace.Document.Bounds); PdnGraphicsPath clippedPath = PdnGraphicsPath.Combine(selectedPath, CombineMode.Intersect, boundsOutline); PdnGraphicsPath invertedPath = PdnGraphicsPath.Combine(clippedPath, CombineMode.Xor, boundsOutline); selectedPath.Dispose(); selectedPath = null; clippedPath.Dispose(); clippedPath = null; EnterCriticalRegion(); historyWorkspace.Selection.PerformChanging(); historyWorkspace.Selection.Reset(); historyWorkspace.Selection.SetContinuation(invertedPath, CombineMode.Replace, true); historyWorkspace.Selection.CommitContinuation(); historyWorkspace.Selection.PerformChanged(); boundsOutline.Dispose(); boundsOutline = null; return sha; } }
protected override List <PointF> CreateShape(List <Point> tracePoints) { Point a = tracePoints[0]; Point b = tracePoints[tracePoints.Count - 1]; Point dir = new Point(b.X - a.X, b.Y - a.Y); float len = (float)Math.Sqrt(dir.X * dir.X + dir.Y * dir.Y); RectangleF rectF; if ((ModifierKeys & Keys.Shift) != 0) { PointF center = new PointF((float)(a.X + b.X) / 2.0f, (float)(a.Y + b.Y) / 2.0f); float radius = len / 2; rectF = Rectangle.Truncate(Utility.RectangleFromCenter(center, radius)); } else { rectF = Utility.PointsToRectangle(a, b); } Rectangle rect = Utility.RoundRectangle(rectF); PdnGraphicsPath path = new PdnGraphicsPath(); path.AddEllipse(rect); // Avoid asymmetrical circles where the left or right side of the ellipse has a pixel jutting out using (Matrix m = new Matrix()) { m.Reset(); m.Translate(-0.5f, -0.5f, MatrixOrder.Append); path.Transform(m); } path.Flatten(Utility.IdentityMatrix, 0.1f); PointF[] pointsF = path.PathPoints; path.Dispose(); return(new List <PointF>(pointsF)); }
protected override List<PointF> CreateShape(List<Point> tracePoints) { Point a = tracePoints[0]; Point b = tracePoints[tracePoints.Count - 1]; Point dir = new Point(b.X - a.X, b.Y - a.Y); float len = (float)Math.Sqrt(dir.X * dir.X + dir.Y * dir.Y); RectangleF rectF; if ((ModifierKeys & Keys.Shift) != 0) { PointF center = new PointF((float)(a.X + b.X) / 2.0f, (float)(a.Y + b.Y) / 2.0f); float radius = len / 2; rectF = Rectangle.Truncate(Utility.RectangleFromCenter(center, radius)); } else { rectF = Utility.PointsToRectangle(a, b); } Rectangle rect = Utility.RoundRectangle(rectF); PdnGraphicsPath path = new PdnGraphicsPath(); path.AddEllipse(rect); // Avoid asymmetrical circles where the left or right side of the ellipse has a pixel jutting out using (Matrix m = new Matrix()) { m.Reset(); m.Translate(-0.5f, -0.5f, MatrixOrder.Append); path.Transform(m); } path.Flatten(Utility.IdentityMatrix, 0.1f); PointF[] pointsF = path.PathPoints; path.Dispose(); return new List<PointF>(pointsF); }
private void OnMouseMoveImpl(MouseEventArgs e, StringBuilder sbLogger) { if (!this.tracking) { sbLogger.Append("1 "); Cursor cursor = this.moveToolCursor; for (int i = 0; i < this.moveNubs.Length; ++i) { sbLogger.Append("2 "); MoveNubRenderer nub = this.moveNubs[i]; sbLogger.Append("3 "); if (nub.Visible && nub.IsPointTouching(new Point(e.X, e.Y), true)) { sbLogger.Append("4 "); cursor = this.handCursor; break; } } this.Cursor = cursor; sbLogger.Append("5 "); } else { sbLogger.Append("6 "); if (this.context.currentMode != Mode.Translate) { sbLogger.Append("7 "); this.Cursor = this.handCursorMouseDown; } sbLogger.Append("8 "); Point newMouseXY = new Point(e.X, e.Y); Point newOffset = new Point(newMouseXY.X - context.startMouseXY.X, newMouseXY.Y - context.startMouseXY.Y); PreRender(); this.dontDrop = true; sbLogger.Append("9 "); Selection.PerformChanging(); using (Matrix translateMatrix = new Matrix()) { RectangleF rect; translateMatrix.Reset(); if (this.context.baseTransform != null) { Selection.SetInterimTransform(this.context.baseTransform); } Matrix interim = Selection.GetInterimTransformCopy(); switch (this.context.currentMode) { case Mode.Translate: translateMatrix.Translate((float)newOffset.X, (float)newOffset.Y, MatrixOrder.Append); break; case Mode.Rotate: rect = this.context.liftedBounds; PointF center = new PointF(rect.X + (rect.Width / 2.0f), rect.Y + (rect.Height / 2.0f)); center = Utility.TransformOnePoint(interim, center); double theta1 = Math.Atan2(context.startMouseXY.Y - center.Y, context.startMouseXY.X - center.X); double theta2 = Math.Atan2(e.Y - center.Y, e.X - center.X); double thetaDelta = theta2 - theta1; this.angleDelta = (float)(thetaDelta * (180.0f / Math.PI)); float angle = this.context.startAngle + this.angleDelta; if ((ModifierKeys & Keys.Shift) != 0) { angle = ConstrainAngle(angle); angleDelta = angle - this.context.startAngle; } translateMatrix.RotateAt(angleDelta, center, MatrixOrder.Append); this.rotateNub.Location = center; this.rotateNub.Angle = this.context.startAngle + angleDelta; break; case Mode.Scale: PointF xyAxes = GetEdgeVector(this.context.startEdge); PointF xAxis = new PointF(xyAxes.X, 0); PointF yAxis = new PointF(0, xyAxes.Y); PointF edgeX = Utility.TransformOneVector(interim, xAxis); PointF edgeY = Utility.TransformOneVector(interim, yAxis); PointF edgeXN = Utility.NormalizeVector2(edgeX); PointF edgeYN = Utility.NormalizeVector2(edgeY); PointF xu; float xulen; PointF xv; Utility.GetProjection((PointF)newOffset, edgeXN, out xu, out xulen, out xv); PointF yu; float yulen; PointF yv; Utility.GetProjection((PointF)newOffset, edgeYN, out yu, out yulen, out yv); PdnGraphicsPath startPath2 = this.context.startPath.Clone(); RectangleF sp2Bounds = startPath2.GetBounds(); PointF sp2BoundsCenter = new PointF((sp2Bounds.Left + sp2Bounds.Right) / 2.0f, (sp2Bounds.Top + sp2Bounds.Bottom) / 2.0f); float tAngle = Utility.GetAngleOfTransform(interim); bool isFlipped = Utility.IsTransformFlipped(interim); using (Matrix spm = new Matrix()) { spm.Reset(); spm.RotateAt(-tAngle, sp2BoundsCenter, MatrixOrder.Append); translateMatrix.RotateAt(-tAngle, sp2BoundsCenter, MatrixOrder.Append); startPath2.Transform(spm); } RectangleF spBounds2 = startPath2.GetBounds(); startPath2.Dispose(); startPath2 = null; float xTranslate; float yTranslate; bool allowConstrain; Edge theEdge = this.context.startEdge; // If the transform is flipped, then GetTransformAngle will return 180 degrees // even though no rotation has actually taken place. Thus we have to scratch // our head and go "hmm, let's make some adjustments to this." Otherwise stretching // the top and bottom nubs goes in the wrong direction. if (isFlipped) { theEdge = FlipEdgeVertically(theEdge); } switch (theEdge) { default: throw new InvalidEnumArgumentException(); case Edge.TopLeft: allowConstrain = true; xTranslate = -spBounds2.X - spBounds2.Width; yTranslate = -spBounds2.Y - spBounds2.Height; break; case Edge.Top: allowConstrain = false; xTranslate = 0; yTranslate = -spBounds2.Y - spBounds2.Height; break; case Edge.TopRight: allowConstrain = true; xTranslate = -spBounds2.X; yTranslate = -spBounds2.Y - spBounds2.Height; break; case Edge.Left: allowConstrain = false; xTranslate = -spBounds2.X - spBounds2.Width; yTranslate = 0; break; case Edge.Right: allowConstrain = false; xTranslate = -spBounds2.X; yTranslate = 0; break; case Edge.BottomLeft: allowConstrain = true; xTranslate = -spBounds2.X - spBounds2.Width; yTranslate = -spBounds2.Y; break; case Edge.Bottom: allowConstrain = false; xTranslate = 0; yTranslate = -spBounds2.Y; break; case Edge.BottomRight: allowConstrain = true; xTranslate = -spBounds2.X; yTranslate = -spBounds2.Y; break; } translateMatrix.Translate(xTranslate, yTranslate, MatrixOrder.Append); float newWidth = spBounds2.Width + xulen; float newHeight = spBounds2.Height + yulen; float xScale = newWidth / spBounds2.Width; float yScale = newHeight / spBounds2.Height; if (allowConstrain && (this.ModifierKeys & Keys.Shift) != 0) { ConstrainScaling(this.context.liftedBounds, spBounds2.Width, spBounds2.Height, newWidth, newHeight, out xScale, out yScale); } translateMatrix.Scale(xScale, yScale, MatrixOrder.Append); translateMatrix.Translate(-xTranslate, -yTranslate, MatrixOrder.Append); translateMatrix.RotateAt(+tAngle, sp2BoundsCenter, MatrixOrder.Append); break; default: throw new InvalidEnumArgumentException(); } this.context.deltaTransform.Reset(); this.context.deltaTransform.Multiply(this.context.liftTransform, MatrixOrder.Append); this.context.deltaTransform.Multiply(translateMatrix, MatrixOrder.Append); translateMatrix.Multiply(this.context.baseTransform, MatrixOrder.Prepend); Selection.SetInterimTransform(translateMatrix); interim.Dispose(); interim = null; } // advertise our angle of rotation to any host (i.e. mainform) that might want to use that information this.hostShouldShowAngle = this.rotateNub.Visible; this.hostAngle = -this.rotateNub.Angle; Selection.PerformChanged(); dontDrop = false; Render(newOffset, true); Update(); sbLogger.Append("a "); this.context.offset = newOffset; sbLogger.Append("b "); if (this.enableOutline) { DocumentWorkspace.ResetOutlineWhiteOpacity(); } sbLogger.Append("c "); } sbLogger.Append("d "); }
protected void RenderShape() { // create the Pen we will use to draw with Pen outlinePen = null; Brush interiorBrush = null; PenInfo pi = AppEnvironment.PenInfo; BrushInfo bi = AppEnvironment.BrushInfo; ColorBgra primary = AppEnvironment.PrimaryColor; ColorBgra secondary = AppEnvironment.SecondaryColor; if (!ForceShapeDrawType && AppEnvironment.ShapeDrawType == ShapeDrawType.Interior) { Utility.Swap(ref primary, ref secondary); } // Initialize pens and brushes to the correct colors if ((mouseButton & MouseButtons.Left) == MouseButtons.Left) { outlinePen = pi.CreatePen(AppEnvironment.BrushInfo, primary.ToColor(), secondary.ToColor()); interiorBrush = bi.CreateBrush(secondary.ToColor(), primary.ToColor()); } else if ((mouseButton & MouseButtons.Right) == MouseButtons.Right) { outlinePen = pi.CreatePen(AppEnvironment.BrushInfo, secondary.ToColor(), primary.ToColor()); interiorBrush = bi.CreateBrush(primary.ToColor(), secondary.ToColor()); } if (!this.UseDashStyle) { outlinePen.DashStyle = DashStyle.Solid; } outlinePen.LineJoin = LineJoin.MiterClipped; outlinePen.MiterLimit = 2; // redraw the old saveSurface if (interiorSaveRegion != null) { RestoreRegion(interiorSaveRegion); interiorSaveRegion.Dispose(); interiorSaveRegion = null; } if (outlineSaveRegion != null) { RestoreRegion(outlineSaveRegion); outlineSaveRegion.Dispose(); outlineSaveRegion = null; } // anti-aliasing? Don't mind if I do if (AppEnvironment.AntiAliasing) { renderArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias; } else { renderArgs.Graphics.SmoothingMode = SmoothingMode.None; } // also set the pixel offset mode renderArgs.Graphics.PixelOffsetMode = GetPixelOffsetMode(); // figure out how we're going to draw ShapeDrawType drawType; if (ForceShapeDrawType) { drawType = ForcedShapeDrawType; } else { drawType = AppEnvironment.ShapeDrawType; } // get the region we want to save points = this.TrimShapePath(points); PointF[] pointsArray = points.ToArray(); PdnGraphicsPath shapePath = CreateShapePath(pointsArray); if (shapePath != null) { // create non-optimized interior region PdnRegion interiorRegion = new PdnRegion(shapePath); // create non-optimized outline region PdnRegion outlineRegion; using (PdnGraphicsPath outlinePath = (PdnGraphicsPath)shapePath.Clone()) { try { outlinePath.Widen(outlinePen); outlineRegion = new PdnRegion(outlinePath); } // Sometimes GDI+ gets cranky if we have a very small shape (e.g. all points // are coincident). catch (OutOfMemoryException) { outlineRegion = new PdnRegion(shapePath); } } // create optimized outlineRegion for purposes of rendering, if it is possible to do so // shapes will often provide an "optimized" region that circumvents the fact that // we'd otherwise get a region that encompasses the outline *and* the interior, thus // slowing rendering significantly in many cases. RectangleF[] optimizedOutlineRegion = GetOptimizedShapeOutlineRegion(pointsArray, shapePath); PdnRegion invalidOutlineRegion; if (optimizedOutlineRegion != null) { Utility.InflateRectanglesInPlace(optimizedOutlineRegion, (int)(outlinePen.Width + 2)); invalidOutlineRegion = Utility.RectanglesToRegion(optimizedOutlineRegion); } else { invalidOutlineRegion = Utility.SimplifyAndInflateRegion(outlineRegion, Utility.DefaultSimplificationFactor, (int)(outlinePen.Width + 2)); } // create optimized interior region PdnRegion invalidInteriorRegion = Utility.SimplifyAndInflateRegion(interiorRegion, Utility.DefaultSimplificationFactor, 3); PdnRegion invalidRegion = new PdnRegion(); invalidRegion.MakeEmpty(); // set up alpha blending renderArgs.Graphics.CompositingMode = AppEnvironment.GetCompositingMode(); SaveRegion(invalidOutlineRegion, invalidOutlineRegion.GetBoundsInt()); this.outlineSaveRegion = invalidOutlineRegion; if ((drawType & ShapeDrawType.Outline) != 0) { shapePath.Draw(renderArgs.Graphics, outlinePen); } invalidRegion.Union(invalidOutlineRegion); // draw shape if ((drawType & ShapeDrawType.Interior) != 0) { SaveRegion(invalidInteriorRegion, invalidInteriorRegion.GetBoundsInt()); this.interiorSaveRegion = invalidInteriorRegion; renderArgs.Graphics.FillPath(interiorBrush, shapePath); invalidRegion.Union(invalidInteriorRegion); } else { invalidInteriorRegion.Dispose(); invalidInteriorRegion = null; } bitmapLayer.Invalidate(invalidRegion); invalidRegion.Dispose(); invalidRegion = null; outlineRegion.Dispose(); outlineRegion = null; interiorRegion.Dispose(); interiorRegion = null; } Update(); if (shapePath != null) { shapePath.Dispose(); shapePath = null; } outlinePen.Dispose(); interiorBrush.Dispose(); }
public bool PerformAction() { bool success = true; if (this.documentWorkspace.Selection.IsEmpty || !(this.documentWorkspace.ActiveLayer is BitmapLayer)) { return(false); } try { using (new WaitCursorChanger(this.documentWorkspace)) { Utility.GCFullCollect(); PdnRegion selectionRegion = this.documentWorkspace.Selection.CreateRegion(); PdnGraphicsPath selectionOutline = this.documentWorkspace.Selection.CreatePath(); BitmapLayer activeLayer = (BitmapLayer)this.documentWorkspace.ActiveLayer; RenderArgs renderArgs = new RenderArgs(activeLayer.Surface); MaskedSurface maskedSurface = new MaskedSurface(renderArgs.Surface, selectionOutline); SurfaceForClipboard surfaceForClipboard = new SurfaceForClipboard(maskedSurface); Rectangle selectionBounds = Utility.GetRegionBounds(selectionRegion); if (selectionBounds.Width > 0 && selectionBounds.Height > 0) { Surface copySurface = new Surface(selectionBounds.Width, selectionBounds.Height); Bitmap copyBitmap = copySurface.CreateAliasedBitmap(); Bitmap copyOpaqueBitmap = new Bitmap(copySurface.Width, copySurface.Height, PixelFormat.Format24bppRgb); using (Graphics copyBitmapGraphics = Graphics.FromImage(copyBitmap)) { copyBitmapGraphics.Clear(Color.White); } maskedSurface.Draw(copySurface, -selectionBounds.X, -selectionBounds.Y); using (Graphics copyOpaqueBitmapGraphics = Graphics.FromImage(copyOpaqueBitmap)) { copyOpaqueBitmapGraphics.Clear(Color.White); copyOpaqueBitmapGraphics.DrawImage(copyBitmap, 0, 0); } DataObject dataObject = new DataObject(); dataObject.SetData(DataFormats.Bitmap, copyOpaqueBitmap); dataObject.SetData(surfaceForClipboard); int retryCount = 2; while (retryCount >= 0) { try { using (new WaitCursorChanger(this.documentWorkspace)) { Clipboard.SetDataObject(dataObject, true); } break; } catch { if (retryCount == 0) { success = false; Utility.ErrorBox(this.documentWorkspace, PdnResources.GetString("CopyAction.Error.TransferToClipboard")); } else { Thread.Sleep(200); } } finally { --retryCount; } } copySurface.Dispose(); copyBitmap.Dispose(); copyOpaqueBitmap.Dispose(); } selectionRegion.Dispose(); selectionOutline.Dispose(); renderArgs.Dispose(); maskedSurface.Dispose(); } } catch (OutOfMemoryException) { success = false; Utility.ErrorBox(this.documentWorkspace, PdnResources.GetString("CopyAction.Error.OutOfMemory")); } catch (Exception) { success = false; Utility.ErrorBox(this.documentWorkspace, PdnResources.GetString("CopyAction.Error.Generic")); } Utility.GCFullCollect(); return(success); }