| 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;        }    }}
 |