From 5b2d5b1397957020ff08e03a30e82dc287addc79 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 23 May 2016 15:39:21 +0200 Subject: [PATCH] Fixed most adorner related drawing issues, need to test a few more (freehand) --- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 147 ++++++++++++++++++ Greenshot/Drawing/Adorners/GripperAdorner.cs | 130 ++++++---------- Greenshot/Drawing/Adorners/TargetAdorner.cs | 83 ++-------- Greenshot/Drawing/DrawableContainer.cs | 1 + Greenshot/Drawing/Surface.cs | 11 +- Greenshot/Greenshot.csproj | 1 + .../Interfaces/Drawing/Adorners/IAdorner.cs | 10 ++ 7 files changed, 223 insertions(+), 160 deletions(-) create mode 100644 Greenshot/Drawing/Adorners/AbstractAdorner.cs diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs new file mode 100644 index 000000000..685ec779f --- /dev/null +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -0,0 +1,147 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Plugin.Drawing; +using Greenshot.Plugin.Drawing.Adorners; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System; + +namespace Greenshot.Drawing.Adorners +{ + public class AbstractAdorner : IAdorner + { + public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; + + protected Size _size = new Size(4, 4); + + public AbstractAdorner(IDrawableContainer owner) + { + Owner = owner; + } + + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public virtual Cursor Cursor + { + get + { + return Cursors.SizeAll; + } + } + + public virtual IDrawableContainer Owner + { + get; + set; + } + + /// + /// Test if the point is inside the adorner + /// + /// + /// + public virtual bool HitTest(Point point) + { + Rectangle hitBounds = Bounds; + hitBounds.Inflate(3, 3); + return hitBounds.Contains(point); + } + + /// + /// Handle the mouse down + /// + /// + /// + public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + } + + /// + /// Handle the mouse move + /// + /// + /// + public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + } + + /// + /// Handle the mouse up + /// + /// + /// + public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.IDLE; + } + + /// + /// Return the location of the adorner + /// + public virtual Point Location + { + get; + set; + } + + /// + /// Return the bounds of the Adorner + /// + public virtual Rectangle Bounds + { + get + { + Point location = Location; + return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); + } + } + + /// + /// The adorner is active if the edit status is not idle or undrawn + /// + public virtual bool IsActive + { + get + { + return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; + } + } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + public virtual void Paint(PaintEventArgs paintEventArgs) + { + } + + /// + /// We ignore the Transform, as the coordinates are directly bound to those of the owner + /// + /// + public virtual void Transform(Matrix matrix) + { + } + } +} diff --git a/Greenshot/Drawing/Adorners/GripperAdorner.cs b/Greenshot/Drawing/Adorners/GripperAdorner.cs index 532fdcedb..a550f5195 100644 --- a/Greenshot/Drawing/Adorners/GripperAdorner.cs +++ b/Greenshot/Drawing/Adorners/GripperAdorner.cs @@ -20,49 +20,49 @@ */ using Greenshot.Helpers; -using Greenshot.Plugin; using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing.Adorners; -using System; using System.Drawing; -using System.Windows.Forms; using System.Drawing.Drawing2D; +using System.Windows.Forms; namespace Greenshot.Drawing.Adorners { /// /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble /// - public class GripperAdorner : IAdorner + public class GripperAdorner : AbstractAdorner { private Rectangle _boundsBeforeResize = Rectangle.Empty; private RectangleF _boundsAfterResize = RectangleF.Empty; - private EditStatus _editStatus; public Positions Position { get; private set; } - public GripperAdorner(IDrawableContainer owner, Positions position) + public GripperAdorner(IDrawableContainer owner, Positions position) : base(owner) { - Owner = owner; Position = position; } /// /// Returns the cursor for when the mouse is over the adorner /// - public Cursor Cursor + public override Cursor Cursor { get { - bool horizontalSwitched = Owner.Width < 0; + bool isNotSwitched = Owner.Width >= 0; + if (Owner.Height < 0) + { + isNotSwitched = !isNotSwitched; + } switch (Position) { case Positions.TopLeft: case Positions.BottomRight: - return horizontalSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; + return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; case Positions.TopRight: case Positions.BottomLeft: - return horizontalSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; + return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; case Positions.MiddleLeft: case Positions.MiddleRight: return Cursors.SizeWE; @@ -75,30 +75,14 @@ namespace Greenshot.Drawing.Adorners } } - public IDrawableContainer Owner - { - get; - set; - } - - /// - /// Test if the point is inside the adorner - /// - /// - /// - public bool HitTest(Point point) - { - return Bounds.Contains(point); - } - /// /// Handle the mouse down /// /// /// - public void MouseDown(object sender, MouseEventArgs mouseEventArgs) + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) { - _editStatus = EditStatus.RESIZING; + EditStatus = EditStatus.RESIZING; _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); _boundsAfterResize = _boundsBeforeResize; } @@ -108,51 +92,39 @@ namespace Greenshot.Drawing.Adorners /// /// /// - public void MouseMove(object sender, MouseEventArgs mouseEventArgs) + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) { - Owner.Invalidate(); - int absX = Owner.Left + mouseEventArgs.X; - int absY = Owner.Top + mouseEventArgs.Y; - - if (_editStatus.Equals(EditStatus.RESIZING)) + if (EditStatus != EditStatus.RESIZING) { - Owner.MakeBoundsChangeUndoable(false); - - //SuspendLayout(); - - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; - - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions()); - - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); - - //ResumeLayout(); - Owner.DoLayout(); + return; } Owner.Invalidate(); - } + Owner.MakeBoundsChangeUndoable(false); + + //SuspendLayout(); + + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.X; + _boundsAfterResize.Y = _boundsBeforeResize.Y; + _boundsAfterResize.Width = _boundsBeforeResize.Width; + _boundsAfterResize.Height = _boundsBeforeResize.Height; + + // calculate scaled rectangle + ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + + // apply scaled bounds to this DrawableContainer + Owner.ApplyBounds(_boundsAfterResize); + + //ResumeLayout(); + Owner.DoLayout(); - /// - /// Handle the mouse up - /// - /// - /// - public void MouseUp(object sender, MouseEventArgs mouseEventArgs) - { - _editStatus = EditStatus.IDLE; Owner.Invalidate(); } /// /// Return the location of the adorner /// - public Point Location { + public override Point Location { get { int x = 0,y = 0; @@ -195,38 +167,26 @@ namespace Greenshot.Drawing.Adorners } } - /// - /// Return the bounds of the Adorner - /// - public Rectangle Bounds - { - get - { - Point location = Location; - Size size = new Size(10, 10); - return new Rectangle(location.X - (size.Width / 2), location.Y - (size.Height / 2), size.Width, size.Height); - } - } - /// /// Draw the adorner /// /// PaintEventArgs - public void Paint(PaintEventArgs paintEventArgs) + public override void Paint(PaintEventArgs paintEventArgs) { Graphics targetGraphics = paintEventArgs.Graphics; Rectangle clipRectangle = paintEventArgs.ClipRectangle; var bounds = Bounds; - targetGraphics.DrawRectangle(Pens.Black, bounds.X, bounds.Y, bounds.Width , bounds.Height); - } + GraphicsState state = targetGraphics.Save(); + + targetGraphics.SmoothingMode = SmoothingMode.None; + targetGraphics.CompositingMode = CompositingMode.SourceCopy; + targetGraphics.PixelOffsetMode = PixelOffsetMode.Half; + targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; + + targetGraphics.FillRectangle(Brushes.Black, bounds.X, bounds.Y, bounds.Width , bounds.Height); + targetGraphics.Restore(state); - /// - /// We ignore the Transform, as the coordinates are directly bound to those of the owner - /// - /// - public void Transform(Matrix matrix) - { } } } diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs index 965bed5a6..a2817421e 100644 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -30,51 +30,22 @@ namespace Greenshot.Drawing.Adorners /// /// This implements the special "gripper" for the Speech-Bubble tail /// - public class TargetAdorner : IAdorner + public class TargetAdorner : AbstractAdorner { - private EditStatus _editStatus; - public TargetAdorner(IDrawableContainer owner, Point location) + public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) { - Owner = owner; Location = location; } - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public Cursor Cursor - { - get - { - return Cursors.SizeAll; - } - } - - public IDrawableContainer Owner - { - get; - set; - } - - /// - /// Test if the point is inside the adorner - /// - /// - /// - public bool HitTest(Point point) - { - return Bounds.Contains(point); - } - /// /// Handle the mouse down /// /// /// - public void MouseDown(object sender, MouseEventArgs mouseEventArgs) + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) { - _editStatus = EditStatus.MOVING; + EditStatus = EditStatus.MOVING; } /// @@ -82,8 +53,13 @@ namespace Greenshot.Drawing.Adorners /// /// /// - public void MouseMove(object sender, MouseEventArgs mouseEventArgs) + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) { + if (EditStatus != EditStatus.MOVING) + { + return; + } + Owner.Invalidate(); Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); Rectangle surfaceBounds = new Rectangle(0, 0, Owner.Parent.Width, Owner.Parent.Height); @@ -113,57 +89,24 @@ namespace Greenshot.Drawing.Adorners Owner.Invalidate(); } - /// - /// Handle the mouse up - /// - /// - /// - public void MouseUp(object sender, MouseEventArgs mouseEventArgs) - { - _editStatus = EditStatus.IDLE; - Owner.Invalidate(); - } - - /// - /// Return the location of the adorner - /// - public Point Location - { - get; - set; - } - - /// - /// Return the bounds of the Adorner - /// - public Rectangle Bounds - { - get - { - Point location = Location; - Size size = new Size(10, 10); - return new Rectangle(location.X - (size.Width / 2), location.Y - (size.Height / 2), size.Width, size.Height); - } - } - /// /// Draw the adorner /// /// PaintEventArgs - public void Paint(PaintEventArgs paintEventArgs) + public override void Paint(PaintEventArgs paintEventArgs) { Graphics targetGraphics = paintEventArgs.Graphics; Rectangle clipRectangle = paintEventArgs.ClipRectangle; var bounds = Bounds; - targetGraphics.DrawRectangle(Pens.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height); + targetGraphics.FillRectangle(Brushes.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height); } /// /// Made sure this adorner is transformed /// /// Matrix - public void Transform(Matrix matrix) + public override void Transform(Matrix matrix) { if (matrix == null) { diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index cdd7125d6..56f84c25d 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -331,6 +331,7 @@ namespace Greenshot.Drawing /// protected void InitTargetGripper(Color gripperColor, Point location) { _targetGripper = new TargetAdorner(this, location); + Adorners.Add(_targetGripper); } protected void InitGrippers() { diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 2dd451493..71ebc154a 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -998,13 +998,14 @@ namespace Greenshot.Drawing { /// /// MouseEventArgs /// IAdorner - private IAdorner AdornersHitTest(MouseEventArgs mouseEventArgs) + private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) { foreach(IDrawableContainer drawableContainer in selectedElements) { foreach(IAdorner adorner in drawableContainer.Adorners) { - if (adorner.HitTest(mouseEventArgs.Location)) + + if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) { if (adorner.Cursor != null) { @@ -1025,7 +1026,7 @@ namespace Greenshot.Drawing { void SurfaceMouseDown(object sender, MouseEventArgs e) { // Handle Adorners - var adorner = AdornersHitTest(e); + var adorner = FindActiveAdorner(e); if (adorner != null) { adorner.MouseDown(sender, e); @@ -1102,7 +1103,7 @@ namespace Greenshot.Drawing { void SurfaceMouseUp(object sender, MouseEventArgs e) { // Handle Adorners - var adorner = AdornersHitTest(e); + var adorner = FindActiveAdorner(e); if (adorner != null) { adorner.MouseUp(sender, e); @@ -1171,7 +1172,7 @@ namespace Greenshot.Drawing { /// void SurfaceMouseMove(object sender, MouseEventArgs e) { // Handle Adorners - var adorner = AdornersHitTest(e); + var adorner = FindActiveAdorner(e); if (adorner != null) { adorner.MouseMove(sender, e); diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 8a1c1de40..d92465c41 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -75,6 +75,7 @@ + diff --git a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs index cf3c3fa70..27f825de4 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs @@ -27,6 +27,16 @@ namespace Greenshot.Plugin.Drawing.Adorners { public interface IAdorner { + /// + /// Returns if this adorner is active + /// + bool IsActive { get; } + + /// + /// The current edit status, this is needed to locate the adorner to send events to + /// + EditStatus EditStatus { get; } + /// /// The owner of this adorner ///