123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- using PaintDotNet.Measurement.HistoryMementos;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Windows.Forms;
- namespace PaintDotNet.Measurement.Tools
- {
- public class PaintBrushTool : Tool
- {
- private bool mouseDown;
- private Brush brush;
- private MouseButtons mouseButton;
- private List<Rectangle> savedRects;
- private PointF lastMouseXY;
- private PointF lastNorm;
- private PointF lastDir;
- private RenderArgs renderArgs;
- private BitmapLayer bitmapLayer;
- private Cursor cursorMouseDown;
- private Cursor cursorMouseUp;
- private BrushPreviewRenderer previewRenderer;
- protected override bool SupportsInk
- {
- get
- {
- return true;
- }
- }
- protected override void OnMouseEnter()
- {
- this.previewRenderer.Visible = true;
- base.OnMouseEnter();
- }
- protected override void OnMouseLeave()
- {
- this.previewRenderer.Visible = false;
- base.OnMouseLeave();
- }
- protected override void OnActivate()
- {
- base.OnActivate();
- cursorMouseUp = new Cursor(PdnResources.GetResourceStream("Cursors.PaintBrushToolCursor.cur"));
- cursorMouseDown = new Cursor(PdnResources.GetResourceStream("Cursors.PaintBrushToolCursorMouseDown.cur"));
- Cursor = cursorMouseUp;
- this.savedRects = new List<Rectangle>();
- if (ActiveLayer != null)
- {
- bitmapLayer = (BitmapLayer)ActiveLayer;
- renderArgs = new RenderArgs(bitmapLayer.Surface);
- }
- else
- {
- bitmapLayer = null;
- renderArgs = null;
- }
- this.previewRenderer = new BrushPreviewRenderer(this.RendererList);
- this.RendererList.Add(this.previewRenderer, false);
- mouseDown = false;
- }
- protected override void OnDeactivate()
- {
- if (mouseDown)
- {
- OnStylusUp(new StylusEventArgs(mouseButton, 0, lastMouseXY.X, lastMouseXY.Y, 0));
- }
- this.RendererList.Remove(this.previewRenderer);
- this.previewRenderer.Dispose();
- this.previewRenderer = null;
- this.savedRects = null;
- if (renderArgs != null)
- {
- renderArgs.Dispose();
- renderArgs = null;
- }
- bitmapLayer = null;
- if (cursorMouseUp != null)
- {
- cursorMouseUp.Dispose();
- cursorMouseUp = null;
- }
- if (cursorMouseDown != null)
- {
- cursorMouseDown.Dispose();
- cursorMouseDown = null;
- }
- base.OnDeactivate();
- }
- private float GetWidth(float Pressure)
- {
- return Pressure * Pressure * AppEnvironment.PenInfo().Width * 0.5f;
- }
- protected override void OnStylusDown(StylusEventArgs e)
- {
- base.OnStylusDown(e);
- if (mouseDown)
- {
- return;
- }
- ClearSavedMemory();
- this.previewRenderer.Visible = false;
- Cursor = cursorMouseDown;
- if (((e.Button & MouseButtons.Left) == MouseButtons.Left) ||
- ((e.Button & MouseButtons.Right) == MouseButtons.Right))
- {
- mouseButton = e.Button;
- if ((mouseButton & MouseButtons.Left) == MouseButtons.Left)
- {
- brush = AppEnvironment.CreateBrush(false);
- }
- else if ((mouseButton & MouseButtons.Right) == MouseButtons.Right)
- {
- brush = AppEnvironment.CreateBrush(true);
- }
- lastMouseXY.X = e.Fx;
- lastMouseXY.Y = e.Fy;
- mouseDown = true;
- mouseButton = e.Button;
- using (PdnRegion clipRegion = Selection.CreateRegion())
- {
- renderArgs.Graphics.SetClip(clipRegion.GetRegionReadOnly(), CombineMode.Replace);
- }
- this.OnStylusMove(new StylusEventArgs(e.Button, e.Clicks, unchecked(e.Fx + 0.01f), e.Fy, e.Delta, e.Pressure));
- }
- }
- private PointF[] MakePolygon(PointF a, PointF b, PointF c, PointF d)
- {
- PointF dirA = new PointF(a.X - b.X, a.Y - b.Y);
- PointF dirB = new PointF(c.X - d.X, c.Y - d.Y);
- // Swap points as necessary to keep the polygon winding one direction
- if (dirA.X * dirB.X + dirA.Y * dirB.Y > 0)
- {
- return new PointF[] { a, b, d, c };
- }
- else
- {
- return new PointF[] { a, b, c, d };
- }
- }
- protected override void OnMouseMove(MouseEventArgs e)
- {
- if (this.mouseDown && e.Button != MouseButtons.None)
- {
- // This is done so that if drawing falls behind due to a
- // large queue of stylus inputs, it won't do any updates
- // until it's done. This is accomplished by only updating
- // when a MouseMove is caught
- Update();
- }
- base.OnMouseMove(e);
- }
- protected override void OnStylusMove(StylusEventArgs e)
- {
- base.OnStylusMove(e);
- PointF currMouseXY = new PointF(e.Fx, e.Fy);
- if (mouseDown && ((e.Button & mouseButton) != MouseButtons.None))
- {
- float pressure = GetWidth(e.Pressure);
- float length;
- PointF a = lastMouseXY;
- PointF b = currMouseXY;
- PointF dir = new PointF(b.X - a.X, b.Y - a.Y);
- PointF norm;
- PointF[] poly;
- RectangleF dotRect = Utility.RectangleFromCenter(currMouseXY, pressure);
- if (pressure > 0.5f)
- {
- renderArgs.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
- }
- else
- {
- renderArgs.Graphics.PixelOffsetMode = PixelOffsetMode.None;
- }
- // save direction before normalizing
- lastDir = dir;
- // normalize
- length = Utility.Magnitude(dir);
- dir.X /= length;
- dir.Y /= length;
- // compute normal vector, calculate perpendicular offest from stroke for width
- norm = new PointF(dir.Y, -dir.X);
- norm.X *= pressure;
- norm.Y *= pressure;
- a.X -= dir.X * 0.1666f;
- a.Y -= dir.Y * 0.1666f;
- lastNorm = norm;
- poly = MakePolygon(
- new PointF(a.X - lastNorm.X, a.Y - lastNorm.Y),
- new PointF(a.X + lastNorm.X, a.Y + lastNorm.Y),
- new PointF(b.X + norm.X, b.Y + norm.Y),
- new PointF(b.X - norm.X, b.Y - norm.Y));
- RectangleF saveRect = RectangleF.Union(
- dotRect,
- RectangleF.Union(
- Utility.PointsToRectangle(poly[0], poly[1]),
- Utility.PointsToRectangle(poly[2], poly[3])));
- saveRect.Inflate(2.0f, 2.0f); // account for anti-aliasing
- saveRect.Intersect(ActiveLayer.Bounds);
- // drawing outside of the canvas is a no-op, so don't do anything in that case!
- // also make sure we're within the clip region
- if (saveRect.Width > 0 && saveRect.Height > 0 && renderArgs.Graphics.IsVisible(saveRect))
- {
- Rectangle saveRectRounded = Utility.RoundRectangle(saveRect);
- saveRectRounded.Intersect(ActiveLayer.Bounds);
- if (saveRectRounded.Width > 0 && saveRectRounded.Height > 0)
- {
- SaveRegion(null, saveRectRounded);
- this.savedRects.Add(saveRectRounded);
- if (AppEnvironment.AntiAliasing())
- {
- renderArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
- }
- else
- {
- renderArgs.Graphics.SmoothingMode = SmoothingMode.None;
- }
- renderArgs.Graphics.CompositingMode = AppEnvironment.GetCompositingMode();
- renderArgs.Graphics.FillEllipse(brush, dotRect);
- // bail out early if the mouse hasn't even moved. If we don't bail out, we'll get a 0-distance move, which will result in a div-by-0
- if (lastMouseXY != currMouseXY)
- {
- renderArgs.Graphics.FillPolygon(brush, poly, FillMode.Winding);
- }
- }
- bitmapLayer.Invalidate(saveRectRounded);
- }
- lastNorm = norm;
- lastMouseXY = currMouseXY;
- }
- else
- {
- lastMouseXY = currMouseXY;
- lastNorm = PointF.Empty;
- lastDir = PointF.Empty;
- this.previewRenderer.BrushSize = AppEnvironment.PenInfo().Width / 2.0f;
- }
- this.previewRenderer.BrushLocation = currMouseXY;
- }
- protected override void OnStylusUp(StylusEventArgs e)
- {
- base.OnStylusUp(e);
- Cursor = cursorMouseUp;
- if (mouseDown)
- {
- this.previewRenderer.Visible = true;
- mouseDown = false;
- if (this.savedRects.Count > 0)
- {
- PdnRegion saveMeRegion = Utility.RectanglesToRegion(this.savedRects.ToArray());
- HistoryMemento ha = new BitmapHistoryMemento(Name, Image, DocumentWorkspace,
- ActiveLayerIndex, saveMeRegion, this.ScratchSurface);
- //HistoryStack.PushNewMemento(ha);
- saveMeRegion.Dispose();
- this.savedRects.Clear();
- this.ClearSavedMemory();
- }
- this.brush.Dispose();
- this.brush = null;
- }
- }
- public PaintBrushTool(IDocumentWorkspace documentWorkspace)
- : base(documentWorkspace,
- PdnResources.GetImageResource("Icons.PaintBrushToolIcon.png"),
- PdnResources.GetString("PaintBrushTool.Name"),
- PdnResources.GetString("PaintBrushTool.HelpText"),
- 'b',
- false,
- ToolBarConfigItems.Brush | ToolBarConfigItems.Pen | ToolBarConfigItems.Antialiasing | ToolBarConfigItems.AlphaBlending)
- {
- // initialize any state information you need
- mouseDown = false;
- }
- }
- }
|