Merge remote-tracking branch 'remotes/origin/feature/BUG-1887_removed_grippers'

# Conflicts:
#	Greenshot/Drawing/DrawableContainer.cs
#	Greenshot/Drawing/SpeechbubbleContainer.cs
This commit is contained in:
Robin 2016-05-23 22:03:01 +02:00
commit 7872f2f7e4
30 changed files with 1016 additions and 419 deletions

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
/// <summary>
/// Returns the cursor for when the mouse is over the adorner
/// </summary>
public virtual Cursor Cursor
{
get
{
return Cursors.SizeAll;
}
}
public virtual IDrawableContainer Owner
{
get;
set;
}
/// <summary>
/// Test if the point is inside the adorner
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public virtual bool HitTest(Point point)
{
Rectangle hitBounds = Bounds;
hitBounds.Inflate(3, 3);
return hitBounds.Contains(point);
}
/// <summary>
/// Handle the mouse down
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs)
{
}
/// <summary>
/// Handle the mouse move
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs)
{
}
/// <summary>
/// Handle the mouse up
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs)
{
EditStatus = EditStatus.IDLE;
}
/// <summary>
/// Return the location of the adorner
/// </summary>
public virtual Point Location
{
get;
set;
}
/// <summary>
/// Return the bounds of the Adorner
/// </summary>
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);
}
}
/// <summary>
/// The adorner is active if the edit status is not idle or undrawn
/// </summary>
public virtual bool IsActive
{
get
{
return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN;
}
}
/// <summary>
/// Draw the adorner
/// </summary>
/// <param name="paintEventArgs">PaintEventArgs</param>
public virtual void Paint(PaintEventArgs paintEventArgs)
{
}
/// <summary>
/// We ignore the Transform, as the coordinates are directly bound to those of the owner
/// </summary>
/// <param name="matrix"></param>
public virtual void Transform(Matrix matrix)
{
}
}
}

View file

@ -0,0 +1,165 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
using Greenshot.Plugin.Drawing.Adorners;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Greenshot.Drawing.Adorners
{
/// <summary>
/// This is the adorner for the line based containers
/// </summary>
public class MoveAdorner : AbstractAdorner
{
private Rectangle _boundsBeforeResize = Rectangle.Empty;
private RectangleF _boundsAfterResize = RectangleF.Empty;
public Positions Position { get; private set; }
public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner)
{
Position = position;
}
/// <summary>
/// Returns the cursor for when the mouse is over the adorner
/// </summary>
public override Cursor Cursor
{
get
{
return Cursors.SizeAll;
}
}
/// <summary>
/// Handle the mouse down
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
{
EditStatus = EditStatus.RESIZING;
_boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height);
_boundsAfterResize = _boundsBeforeResize;
}
/// <summary>
/// Handle the mouse move
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
{
if (EditStatus != EditStatus.RESIZING)
{
return;
}
Owner.Invalidate();
Owner.MakeBoundsChangeUndoable(false);
// 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);
Owner.Invalidate();
}
/// <summary>
/// Return the location of the adorner
/// </summary>
public override Point Location {
get
{
int x = 0,y = 0;
switch (Position)
{
case Positions.TopLeft:
x = Owner.Left;
y = Owner.Top;
break;
case Positions.BottomLeft:
x = Owner.Left;
y = Owner.Top + Owner.Height;
break;
case Positions.MiddleLeft:
x = Owner.Left;
y = Owner.Top + (Owner.Height / 2);
break;
case Positions.TopCenter:
x = Owner.Left + (Owner.Width / 2);
y = Owner.Top;
break;
case Positions.BottomCenter:
x = Owner.Left + (Owner.Width / 2);
y = Owner.Top + Owner.Height;
break;
case Positions.TopRight:
x = Owner.Left + Owner.Width;
y = Owner.Top;
break;
case Positions.BottomRight:
x = Owner.Left + Owner.Width;
y = Owner.Top + Owner.Height;
break;
case Positions.MiddleRight:
x = Owner.Left + Owner.Width;
y = Owner.Top + (Owner.Height / 2);
break;
}
return new Point(x, y);
}
}
/// <summary>
/// Draw the adorner
/// </summary>
/// <param name="paintEventArgs">PaintEventArgs</param>
public override void Paint(PaintEventArgs paintEventArgs)
{
Graphics targetGraphics = paintEventArgs.Graphics;
Rectangle clipRectangle = paintEventArgs.ClipRectangle;
var bounds = Bounds;
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);
}
}
}

View file

@ -0,0 +1,186 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
using Greenshot.Plugin.Drawing.Adorners;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Greenshot.Drawing.Adorners
{
/// <summary>
/// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble
/// </summary>
public class ResizeAdorner : AbstractAdorner
{
private Rectangle _boundsBeforeResize = Rectangle.Empty;
private RectangleF _boundsAfterResize = RectangleF.Empty;
public Positions Position { get; private set; }
public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner)
{
Position = position;
}
/// <summary>
/// Returns the cursor for when the mouse is over the adorner
/// </summary>
public override Cursor Cursor
{
get
{
bool isNotSwitched = Owner.Width >= 0;
if (Owner.Height < 0)
{
isNotSwitched = !isNotSwitched;
}
switch (Position)
{
case Positions.TopLeft:
case Positions.BottomRight:
return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW;
case Positions.TopRight:
case Positions.BottomLeft:
return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE;
case Positions.MiddleLeft:
case Positions.MiddleRight:
return Cursors.SizeWE;
case Positions.TopCenter:
case Positions.BottomCenter:
return Cursors.SizeNS;
default:
return Cursors.SizeAll;
}
}
}
/// <summary>
/// Handle the mouse down
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
{
EditStatus = EditStatus.RESIZING;
_boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height);
_boundsAfterResize = _boundsBeforeResize;
}
/// <summary>
/// Handle the mouse move
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
{
if (EditStatus != EditStatus.RESIZING)
{
return;
}
Owner.Invalidate();
Owner.MakeBoundsChangeUndoable(false);
// 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);
Owner.Invalidate();
}
/// <summary>
/// Return the location of the adorner
/// </summary>
public override Point Location {
get
{
int x = 0,y = 0;
switch (Position)
{
case Positions.TopLeft:
x = Owner.Left;
y = Owner.Top;
break;
case Positions.BottomLeft:
x = Owner.Left;
y = Owner.Top + Owner.Height;
break;
case Positions.MiddleLeft:
x = Owner.Left;
y = Owner.Top + (Owner.Height / 2);
break;
case Positions.TopCenter:
x = Owner.Left + (Owner.Width / 2);
y = Owner.Top;
break;
case Positions.BottomCenter:
x = Owner.Left + (Owner.Width / 2);
y = Owner.Top + Owner.Height;
break;
case Positions.TopRight:
x = Owner.Left + Owner.Width;
y = Owner.Top;
break;
case Positions.BottomRight:
x = Owner.Left + Owner.Width;
y = Owner.Top + Owner.Height;
break;
case Positions.MiddleRight:
x = Owner.Left + Owner.Width;
y = Owner.Top + (Owner.Height / 2);
break;
}
return new Point(x, y);
}
}
/// <summary>
/// Draw the adorner
/// </summary>
/// <param name="paintEventArgs">PaintEventArgs</param>
public override void Paint(PaintEventArgs paintEventArgs)
{
Graphics targetGraphics = paintEventArgs.Graphics;
Rectangle clipRectangle = paintEventArgs.ClipRectangle;
var bounds = Bounds;
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);
}
}
}

View file

@ -0,0 +1,119 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
using Greenshot.Plugin.Drawing;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Greenshot.Drawing.Adorners
{
/// <summary>
/// This implements the special "gripper" for the Speech-Bubble tail
/// </summary>
public class TargetAdorner : AbstractAdorner
{
public TargetAdorner(IDrawableContainer owner, Point location) : base(owner)
{
Location = location;
}
/// <summary>
/// Handle the mouse down
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
{
EditStatus = EditStatus.MOVING;
}
/// <summary>
/// Handle the mouse move
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>
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);
// Check if gripper inside the parent (surface), if not we need to move it inside
// This was made for BUG-1682
if (!surfaceBounds.Contains(newGripperLocation))
{
if (newGripperLocation.X > surfaceBounds.Right)
{
newGripperLocation.X = surfaceBounds.Right - 5;
}
if (newGripperLocation.X < surfaceBounds.Left)
{
newGripperLocation.X = surfaceBounds.Left;
}
if (newGripperLocation.Y > surfaceBounds.Bottom)
{
newGripperLocation.Y = surfaceBounds.Bottom - 5;
}
if (newGripperLocation.Y < surfaceBounds.Top)
{
newGripperLocation.Y = surfaceBounds.Top;
}
}
Location = newGripperLocation;
Owner.Invalidate();
}
/// <summary>
/// Draw the adorner
/// </summary>
/// <param name="paintEventArgs">PaintEventArgs</param>
public override void Paint(PaintEventArgs paintEventArgs)
{
Graphics targetGraphics = paintEventArgs.Graphics;
Rectangle clipRectangle = paintEventArgs.ClipRectangle;
var bounds = Bounds;
targetGraphics.FillRectangle(Brushes.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height);
}
/// <summary>
/// Made sure this adorner is transformed
/// </summary>
/// <param name="matrix">Matrix</param>
public override void Transform(Matrix matrix)
{
if (matrix == null)
{
return;
}
Point[] points = new[] { Location };
matrix.TransformPoints(points);
Location = points[0];
}
}
}

View file

@ -20,6 +20,7 @@
*/
using System.Drawing;
using System.Runtime.Serialization;
using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
@ -30,8 +31,19 @@ namespace Greenshot.Drawing {
/// </summary>
public class CropContainer : DrawableContainer {
public CropContainer(Surface parent) : base(parent) {
Init();
}
protected override void OnDeserialized(StreamingContext streamingContext)
{
base.OnDeserialized(streamingContext);
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
protected override void InitializeFields() {
AddField(GetType(), FieldType.FLAGS, FieldType.Flag.CONFIRMABLE);
}

View file

@ -26,6 +26,7 @@ using System.Windows.Forms;
using Greenshot.Plugin.Drawing;
using System.Drawing.Drawing2D;
using log4net;
using System.Runtime.Serialization;
namespace Greenshot.Drawing {
/// <summary>
@ -38,9 +39,21 @@ namespace Greenshot.Drawing {
protected Cursor cursor;
public CursorContainer(Surface parent) : base(parent) {
Init();
}
public CursorContainer(Surface parent, string filename) : base(parent) {
protected override void OnDeserialized(StreamingContext streamingContext)
{
base.OnDeserialized(streamingContext);
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
public CursorContainer(Surface parent, string filename) : this(parent) {
Load(filename);
}

View file

@ -20,6 +20,7 @@
*/
using Greenshot.Configuration;
using Greenshot.Drawing.Adorners;
using Greenshot.Drawing.Fields;
using Greenshot.Drawing.Filters;
using Greenshot.Helpers;
@ -27,15 +28,18 @@ using Greenshot.IniFile;
using Greenshot.Memento;
using Greenshot.Plugin;
using Greenshot.Plugin.Drawing;
using Greenshot.Plugin.Drawing.Adorners;
using log4net;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
using System.Windows.Forms;
namespace Greenshot.Drawing {
namespace Greenshot.Drawing
{
/// <summary>
/// represents a rectangle, ellipse, label or whatever. Can contain filters, too.
/// serializable for clipboard support
@ -46,10 +50,23 @@ namespace Greenshot.Drawing {
public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer {
private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer));
protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection<EditorConfiguration>();
private bool _isMadeUndoable;
private const int M11 = 0;
private const int M22 = 3;
[OnDeserialized]
private void OnDeserializedInit(StreamingContext context)
{
_adorners = new List<IAdorner>();
OnDeserialized(context);
}
/// <summary>
/// Override to implement your own deserialization logic, like initializing properties which are not serialized
/// </summary>
/// <param name="streamingContext"></param>
protected virtual void OnDeserialized(StreamingContext streamingContext)
{
}
protected EditStatus _defaultEditMode = EditStatus.DRAWING;
public EditStatus DefaultEditMode {
@ -71,16 +88,6 @@ namespace Greenshot.Drawing {
if (!disposing) {
return;
}
if (_grippers != null) {
for (int i = 0; i < _grippers.Length; i++) {
if (_grippers[i] == null) {
continue;
}
_grippers[i].Dispose();
_grippers[i] = null;
}
_grippers = null;
}
FieldAggregator aggProps = _parent.FieldAggregator;
aggProps.UnbindElement(this);
@ -115,14 +122,10 @@ namespace Greenshot.Drawing {
get { return _parent; }
set { SwitchParent((Surface)value); }
}
[NonSerialized]
protected Gripper[] _grippers;
private bool layoutSuspended;
[NonSerialized]
private Gripper _targetGripper;
public Gripper TargetGripper {
private TargetAdorner _targetGripper;
public TargetAdorner TargetGripper {
get {
return _targetGripper;
}
@ -158,7 +161,6 @@ namespace Greenshot.Drawing {
return;
}
left = value;
DoLayout();
}
}
@ -170,7 +172,6 @@ namespace Greenshot.Drawing {
return;
}
top = value;
DoLayout();
}
}
@ -182,7 +183,6 @@ namespace Greenshot.Drawing {
return;
}
width = value;
DoLayout();
}
}
@ -194,7 +194,6 @@ namespace Greenshot.Drawing {
return;
}
height = value;
DoLayout();
}
}
@ -218,6 +217,19 @@ namespace Greenshot.Drawing {
}
}
/// <summary>
/// List of available Adorners
/// </summary>
[NonSerialized]
private IList<IAdorner> _adorners = new List<IAdorner>();
public IList<IAdorner> Adorners
{
get
{
return _adorners;
}
}
[NonSerialized]
// will store current bounds of this DrawableContainer before starting a resize
protected Rectangle _boundsBeforeResize = Rectangle.Empty;
@ -246,7 +258,6 @@ namespace Greenshot.Drawing {
public DrawableContainer(Surface parent) {
InitializeFields();
_parent = parent;
InitControls();
}
public void Add(IFilter filter) {
@ -303,7 +314,7 @@ namespace Greenshot.Drawing {
Left = _parent.Width - Width - lineThickness/2;
}
if (horizontalAlignment == HorizontalAlignment.Center) {
Left = _parent.Width / 2 - Width / 2 - lineThickness/2;
Left = (_parent.Width / 2) - (Width / 2) - lineThickness/2;
}
if (verticalAlignment == VerticalAlignment.TOP) {
@ -313,7 +324,7 @@ namespace Greenshot.Drawing {
Top = _parent.Height - Height - lineThickness/2;
}
if (verticalAlignment == VerticalAlignment.CENTER) {
Top = _parent.Height / 2 - Height / 2 - lineThickness/2;
Top = (_parent.Height / 2) - (Height / 2) - lineThickness/2;
}
}
@ -321,185 +332,32 @@ namespace Greenshot.Drawing {
public virtual void OnDoubleClick() {}
private void InitControls() {
InitGrippers();
DoLayout();
}
/// <summary>
/// Move the TargetGripper around, confined to the surface to solve BUG-1682
/// </summary>
/// <param name="newX"></param>
/// <param name="newY"></param>
protected virtual void TargetGripperMove(int newX, int newY) {
Point newGripperLocation = new Point(newX, newY);
Rectangle surfaceBounds = new Rectangle(0, 0, _parent.Width, _parent.Height);
// Check if gripper inside the parent (surface), if not we need to move it inside
// This was made for BUG-1682
if (!surfaceBounds.Contains(newGripperLocation)) {
if (newGripperLocation.X > surfaceBounds.Right) {
newGripperLocation.X = surfaceBounds.Right - 5;
}
if (newGripperLocation.X < surfaceBounds.Left) {
newGripperLocation.X = surfaceBounds.Left;
}
if (newGripperLocation.Y > surfaceBounds.Bottom) {
newGripperLocation.Y = surfaceBounds.Bottom - 5;
}
if (newGripperLocation.Y < surfaceBounds.Top) {
newGripperLocation.Y = surfaceBounds.Top;
}
}
_targetGripper.Left = newGripperLocation.X;
_targetGripper.Top = newGripperLocation.Y;
}
/// <summary>
/// Initialize a target gripper
/// </summary>
protected void InitTargetGripper(Color gripperColor, Point location) {
_targetGripper = new Gripper {
Cursor = Cursors.SizeAll,
BackColor = gripperColor,
Visible = false,
Parent = _parent,
Location = location
};
_targetGripper.MouseDown += GripperMouseDown;
_targetGripper.MouseUp += GripperMouseUp;
_targetGripper.MouseMove += GripperMouseMove;
if (_parent != null) {
_parent.Controls.Add(_targetGripper); // otherwise we'll attach them in switchParent
}
_targetGripper = new TargetAdorner(this, location);
Adorners.Add(_targetGripper);
}
protected void InitGrippers() {
/// <summary>
/// Create the default adorners for a rectangle based container
/// </summary>
_grippers = new Gripper[8];
for(int i=0; i<_grippers.Length; i++) {
_grippers[i] = new Gripper();
_grippers[i].Position = i;
_grippers[i].MouseDown += GripperMouseDown;
_grippers[i].MouseUp += GripperMouseUp;
_grippers[i].MouseMove += GripperMouseMove;
_grippers[i].Visible = false;
_grippers[i].Parent = _parent;
protected void CreateDefaultAdorners() {
if (Adorners.Count > 0)
{
LOG.Warn("Adorners are already defined!");
}
_grippers[Gripper.POSITION_TOP_CENTER].Cursor = Cursors.SizeNS;
_grippers[Gripper.POSITION_MIDDLE_RIGHT].Cursor = Cursors.SizeWE;
_grippers[Gripper.POSITION_BOTTOM_CENTER].Cursor = Cursors.SizeNS;
_grippers[Gripper.POSITION_MIDDLE_LEFT].Cursor = Cursors.SizeWE;
if (_parent != null) {
_parent.Controls.AddRange(_grippers); // otherwise we'll attach them in switchParent
}
}
public void SuspendLayout() {
layoutSuspended = true;
}
public void ResumeLayout() {
layoutSuspended = false;
DoLayout();
}
protected virtual void DoLayout() {
if (_grippers == null) {
return;
}
if (!layoutSuspended) {
int[] xChoords = {Left-2,Left+Width/2-2,Left+Width-2};
int[] yChoords = {Top-2,Top+Height/2-2,Top+Height-2};
_grippers[Gripper.POSITION_TOP_LEFT].Left = xChoords[0]; _grippers[Gripper.POSITION_TOP_LEFT].Top = yChoords[0];
_grippers[Gripper.POSITION_TOP_CENTER].Left = xChoords[1]; _grippers[Gripper.POSITION_TOP_CENTER].Top = yChoords[0];
_grippers[Gripper.POSITION_TOP_RIGHT].Left = xChoords[2]; _grippers[Gripper.POSITION_TOP_RIGHT].Top = yChoords[0];
_grippers[Gripper.POSITION_MIDDLE_RIGHT].Left = xChoords[2]; _grippers[Gripper.POSITION_MIDDLE_RIGHT].Top = yChoords[1];
_grippers[Gripper.POSITION_BOTTOM_RIGHT].Left = xChoords[2]; _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top = yChoords[2];
_grippers[Gripper.POSITION_BOTTOM_CENTER].Left = xChoords[1]; _grippers[Gripper.POSITION_BOTTOM_CENTER].Top = yChoords[2];
_grippers[Gripper.POSITION_BOTTOM_LEFT].Left = xChoords[0]; _grippers[Gripper.POSITION_BOTTOM_LEFT].Top = yChoords[2];
_grippers[Gripper.POSITION_MIDDLE_LEFT].Left = xChoords[0]; _grippers[Gripper.POSITION_MIDDLE_LEFT].Top = yChoords[1];
if((_grippers[Gripper.POSITION_TOP_LEFT].Left < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) ||
_grippers[Gripper.POSITION_TOP_LEFT].Left > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) {
_grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNWSE;
_grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNESW;
_grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNWSE;
_grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNESW;
} else if((_grippers[Gripper.POSITION_TOP_LEFT].Left > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) ||
_grippers[Gripper.POSITION_TOP_LEFT].Left < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) {
_grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNESW;
_grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNWSE;
_grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNESW;
_grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNWSE;
} else if (_grippers[Gripper.POSITION_TOP_LEFT].Left == _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left) {
_grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNS;
_grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNS;
} else if (_grippers[Gripper.POSITION_TOP_LEFT].Top == _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) {
_grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeWE;
_grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeWE;
}
}
}
private void GripperMouseDown(object sender, MouseEventArgs e) {
Gripper originatingGripper = (Gripper)sender;
if (originatingGripper != _targetGripper) {
Status = EditStatus.RESIZING;
_boundsBeforeResize = new Rectangle(left, top, width, height);
_boundsAfterResize = new RectangleF(_boundsBeforeResize.Left, _boundsBeforeResize.Top, _boundsBeforeResize.Width, _boundsBeforeResize.Height);
} else {
Status = EditStatus.MOVING;
}
_isMadeUndoable = false;
}
private void GripperMouseUp(object sender, MouseEventArgs e) {
Gripper originatingGripper = (Gripper)sender;
if (originatingGripper != _targetGripper) {
_boundsBeforeResize = Rectangle.Empty;
_boundsAfterResize = RectangleF.Empty;
_isMadeUndoable = false;
}
Status = EditStatus.IDLE;
Invalidate();
}
private void GripperMouseMove(object sender, MouseEventArgs e) {
Invalidate();
Gripper originatingGripper = (Gripper)sender;
int absX = originatingGripper.Left + e.X;
int absY = originatingGripper.Top + e.Y;
if (originatingGripper == _targetGripper && Status.Equals(EditStatus.MOVING)) {
TargetGripperMove(absX, absY);
} else if (Status.Equals(EditStatus.RESIZING)) {
// check if we already made this undoable
if (!_isMadeUndoable) {
// don't allow another undo until we are finished with this move
_isMadeUndoable = true;
// Make undo-able
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, originatingGripper.Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions());
// apply scaled bounds to this DrawableContainer
ApplyBounds(_boundsAfterResize);
ResumeLayout();
}
Invalidate();
// Create the GripperAdorners
Adorners.Add(new ResizeAdorner(this, Positions.TopLeft));
Adorners.Add(new ResizeAdorner(this, Positions.TopCenter));
Adorners.Add(new ResizeAdorner(this, Positions.TopRight));
Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft));
Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter));
Adorners.Add(new ResizeAdorner(this, Positions.BottomRight));
Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft));
Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight));
}
public bool hasFilters {
@ -556,43 +414,10 @@ namespace Greenshot.Drawing {
}
}
public virtual void ShowGrippers() {
if (_grippers != null) {
for (int i = 0; i < _grippers.Length; i++) {
if (_grippers[i].Enabled) {
_grippers[i].Show();
} else {
_grippers[i].Hide();
}
}
}
if (_targetGripper != null) {
if (_targetGripper.Enabled) {
_targetGripper.Show();
} else {
_targetGripper.Hide();
}
}
ResumeLayout();
}
public virtual void HideGrippers() {
SuspendLayout();
if (_grippers != null) {
for (int i = 0; i < _grippers.Length; i++) {
_grippers[i].Hide();
}
}
if (_targetGripper != null) {
_targetGripper.Hide();
}
}
public void ResizeTo(int width, int height, int anchorPosition) {
SuspendLayout();
Width = width;
Height = height;
ResumeLayout();
}
/// <summary>
@ -604,10 +429,8 @@ namespace Greenshot.Drawing {
}
public void MoveBy(int dx, int dy) {
SuspendLayout();
Left += dx;
Top += dy;
ResumeLayout();
}
/// <summary>
@ -630,7 +453,6 @@ namespace Greenshot.Drawing {
/// <returns>true if the event is handled, false if the surface needs to handle it</returns>
public virtual bool HandleMouseMove(int x, int y) {
Invalidate();
SuspendLayout();
// reset "workrbench" rectangle to current bounds
_boundsAfterResize.X = _boundsBeforeResize.Left;
@ -643,7 +465,6 @@ namespace Greenshot.Drawing {
// apply scaled bounds to this DrawableContainer
ApplyBounds(_boundsAfterResize);
ResumeLayout();
Invalidate();
return true;
}
@ -657,28 +478,8 @@ namespace Greenshot.Drawing {
}
protected virtual void SwitchParent(Surface newParent) {
// Target gripper
if (_parent != null && _targetGripper != null) {
_parent.Controls.Remove(_targetGripper);
}
// Normal grippers
if (_parent != null && _grippers != null) {
for (int i=0; i<_grippers.Length; i++) {
_parent.Controls.Remove(_grippers[i]);
}
} else if (_grippers == null) {
InitControls();
}
_parent = newParent;
// Target gripper
if (_parent != null && _targetGripper != null) {
_parent.Controls.Add(_targetGripper);
}
// Normal grippers
if (_grippers != null) {
_parent.Controls.AddRange(_grippers);
}
_parent = newParent;
foreach(IFilter filter in Filters) {
filter.Parent = this;
}
@ -775,26 +576,16 @@ namespace Greenshot.Drawing {
if (matrix == null) {
return;
}
SuspendLayout();
Point topLeft = new Point(Left, Top);
Point bottomRight = new Point(Left + Width, Top + Height);
Point[] points;
if (TargetGripper != null) {
points = new[] {topLeft, bottomRight, TargetGripper.Location};
} else {
points = new[] { topLeft, bottomRight };
}
Point[] points = new[] { topLeft, bottomRight };
matrix.TransformPoints(points);
Left = points[0].X;
Top = points[0].Y;
Width = points[1].X - points[0].X;
Height = points[1].Y - points[0].Y;
if (TargetGripper != null) {
TargetGripper.Location = points[points.Length-1];
}
ResumeLayout();
}
protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() {

View file

@ -171,26 +171,6 @@ namespace Greenshot.Drawing {
}
}
/// <summary>
/// Hides the grippers of all elements in the list.
/// </summary>
public void HideGrippers() {
foreach(var dc in this) {
dc.HideGrippers();
dc.Invalidate();
}
}
/// <summary>
/// Shows the grippers of all elements in the list.
/// </summary>
public void ShowGrippers() {
foreach(var dc in this) {
dc.ShowGrippers();
dc.Invalidate();
}
}
/// <summary>
/// Indicates whether on of the elements is clickable at the given location
/// </summary>

View file

@ -33,6 +33,7 @@ namespace Greenshot.Drawing {
[Serializable()]
public class EllipseContainer : DrawableContainer {
public EllipseContainer(Surface parent) : base(parent) {
CreateDefaultAdorners();
}
protected override void InitializeFields() {

View file

@ -53,7 +53,7 @@ namespace Greenshot.Drawing.Fields {
private readonly List<Field> fields = new List<Field>();
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
private void OnFieldHolderDeserialized(StreamingContext context) {
fieldsByType = new Dictionary<FieldType, Field>();
// listen to changing properties
foreach(Field field in fields) {

View file

@ -45,8 +45,8 @@ namespace Greenshot.Drawing.Fields {
fieldChangedEventHandler = OnFieldChanged;
}
[OnDeserialized()]
private void OnDeserialized(StreamingContext context) {
[OnDeserialized]
private void OnFieldHolderWithChildrenDeserialized(StreamingContext context) {
// listen to changing properties
foreach(IFieldHolder fieldHolder in Children) {
fieldHolder.FieldChanged += fieldChangedEventHandler;

View file

@ -24,6 +24,7 @@ using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
namespace Greenshot.Drawing {
/// <summary>
@ -40,6 +41,18 @@ namespace Greenshot.Drawing {
}
public FilterContainer(Surface parent) : base(parent) {
Init();
}
protected override void OnDeserialized(StreamingContext streamingContext)
{
base.OnDeserialized(streamingContext);
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
protected override void InitializeFields() {

View file

@ -47,7 +47,6 @@ namespace Greenshot.Drawing {
/// Constructor
/// </summary>
public FreehandContainer(Surface parent) : base(parent) {
Init();
Width = parent.Width;
Height = parent.Height;
Top = 0;
@ -59,16 +58,6 @@ namespace Greenshot.Drawing {
AddField(GetType(), FieldType.LINE_COLOR, Color.Red);
}
protected void Init() {
if (_grippers != null) {
for (int i = 0; i < _grippers.Length; i++) {
_grippers[i].Enabled = false;
_grippers[i].Visible = false;
}
}
}
public override void Transform(Matrix matrix) {
Point[] points = capturePoints.ToArray();
@ -78,11 +67,7 @@ namespace Greenshot.Drawing {
RecalculatePath();
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
InitGrippers();
DoLayout();
Init();
protected override void OnDeserialized(StreamingContext context) {
RecalculatePath();
}
@ -256,17 +241,6 @@ namespace Greenshot.Drawing {
return freehandPath.GetHashCode();
}
/// <summary>
/// This is overriden to prevent the grippers to be modified.
/// Might not be the best way...
/// </summary>
protected override void DoLayout() {
}
public override void ShowGrippers() {
ResumeLayout();
}
public override bool ClickableAt(int x, int y) {
bool returnValue = base.ClickableAt(x, y);
if (returnValue) {

View file

@ -42,8 +42,8 @@ namespace Greenshot.Drawing {
AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT);
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
protected override void OnDeserialized(StreamingContext context)
{
Init();
}

View file

@ -24,6 +24,7 @@ using System.IO;
using Greenshot.Plugin.Drawing;
using System.Drawing.Drawing2D;
using log4net;
using System.Runtime.Serialization;
namespace Greenshot.Drawing {
/// <summary>
@ -36,6 +37,18 @@ namespace Greenshot.Drawing {
protected Icon icon;
public IconContainer(Surface parent) : base(parent) {
Init();
}
protected override void OnDeserialized(StreamingContext streamingContext)
{
base.OnDeserialized(streamingContext);
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
public IconContainer(Surface parent, string filename) : base(parent) {

View file

@ -27,6 +27,7 @@ using GreenshotPlugin.Core;
using System.Drawing.Drawing2D;
using Greenshot.Core;
using log4net;
using System.Runtime.Serialization;
namespace Greenshot.Drawing {
/// <summary>
@ -58,6 +59,18 @@ namespace Greenshot.Drawing {
public ImageContainer(Surface parent) : base(parent) {
FieldChanged += BitmapContainer_OnFieldChanged;
Init();
}
protected override void OnDeserialized(StreamingContext streamingContext)
{
base.OnDeserialized(streamingContext);
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
protected override void InitializeFields() {

View file

@ -26,6 +26,7 @@ using System.Runtime.Serialization;
using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
using Greenshot.Drawing.Adorners;
namespace Greenshot.Drawing {
/// <summary>
@ -45,19 +46,14 @@ namespace Greenshot.Drawing {
AddField(GetType(), FieldType.SHADOW, true);
}
[OnDeserialized()]
private void OnDeserialized(StreamingContext context) {
InitGrippers();
DoLayout();
protected override void OnDeserialized(StreamingContext context)
{
Init();
}
protected void Init() {
if (_grippers != null) {
foreach (int index in new[] { 1, 2, 3, 5, 6, 7 }) {
_grippers[index].Enabled = false;
}
}
Adorners.Add(new MoveAdorner(this, Positions.TopLeft));
Adorners.Add(new MoveAdorner(this, Positions.BottomRight));
}
public override void Draw(Graphics graphics, RenderMode rm) {
@ -114,7 +110,5 @@ namespace Greenshot.Drawing {
protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() {
return ScaleHelper.LineAngleRoundBehavior.Instance;
}
}
}

View file

@ -38,14 +38,15 @@ namespace Greenshot.Drawing {
AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE);
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
protected override void OnDeserialized(StreamingContext context)
{
Init();
}
private void Init() {
FieldChanged += ObfuscateContainer_OnFieldChanged;
ConfigurePreparedFilters();
CreateDefaultAdorners();
}
protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) {

View file

@ -19,38 +19,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Drawing;
using System.Windows.Forms;
namespace Greenshot.Drawing {
namespace Greenshot.Drawing
{
/// <summary>
/// Grippers are the dragable edges of our containers
/// Position
/// </summary>
public class Gripper : Label {
/// <summary>
/// Constants for anchor/gripper position:
/// 0 1 2
/// 7 3
/// 6 5 4
/// </summary>
public const int POSITION_TOP_LEFT = 0;
public const int POSITION_TOP_CENTER = 1;
public const int POSITION_TOP_RIGHT = 2;
public const int POSITION_MIDDLE_RIGHT = 3;
public const int POSITION_BOTTOM_RIGHT = 4;
public const int POSITION_BOTTOM_CENTER = 5;
public const int POSITION_BOTTOM_LEFT = 6;
public const int POSITION_MIDDLE_LEFT = 7;
public int Position {
get;
set;
}
public Gripper() {
Width = 5;
Height = 5;
BackColor = Color.Black;
}
public enum Positions : int
{
TopLeft = 0,
TopCenter = 1,
TopRight = 2,
MiddleRight = 3,
BottomRight = 4,
BottomCenter = 5,
BottomLeft = 6,
MiddleLeft = 7
}
}

View file

@ -25,6 +25,7 @@ using System.Drawing.Drawing2D;
using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
using System.Runtime.Serialization;
namespace Greenshot.Drawing {
/// <summary>
@ -34,6 +35,22 @@ namespace Greenshot.Drawing {
public class RectangleContainer : DrawableContainer {
public RectangleContainer(Surface parent) : base(parent) {
Init();
}
/// <summary>
/// Do some logic to make sure all field are initiated correctly
/// </summary>
/// <param name="streamingContext">StreamingContext</param>
protected override void OnDeserialized(StreamingContext streamingContext)
{
base.OnDeserialized(streamingContext);
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
protected override void InitializeFields() {

View file

@ -28,7 +28,8 @@ using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Runtime.Serialization;
namespace Greenshot.Drawing {
namespace Greenshot.Drawing
{
/// <summary>
/// Description of SpeechbubbleContainer.
/// </summary>
@ -56,8 +57,8 @@ namespace Greenshot.Drawing {
/// Restore the target gripper
/// </summary>
/// <param name="context"></param>
[OnDeserialized]
private void SetValuesOnDeserialized(StreamingContext context) {
protected override void OnDeserialized(StreamingContext context)
{
InitTargetGripper(Color.Green, _storedTargetGripperLocation);
}
#endregion
@ -115,7 +116,7 @@ namespace Greenshot.Drawing {
if (TargetGripper.Location != newGripperLocation) {
Invalidate();
TargetGripperMove(newGripperLocation.X, newGripperLocation.Y);
TargetGripper.Location = newGripperLocation;
Invalidate();
}
return returnValue;
@ -177,8 +178,7 @@ namespace Greenshot.Drawing {
private GraphicsPath CreateTail() {
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
int tailLength = GeometryHelper.Distance2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetGripper.Left, TargetGripper.Top);
int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20;
int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetGripper.Left, TargetGripper.Top); int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20;
// This should fix a problem with the tail being to wide
tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth);
@ -189,7 +189,6 @@ namespace Greenshot.Drawing {
tail.AddLine(tailWidth, 0, 0, -tailLength);
tail.CloseFigure();
int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetGripper.Left, TargetGripper.Top);
using (Matrix tailMatrix = new Matrix()) {
tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);

View file

@ -45,6 +45,12 @@ namespace Greenshot.Drawing {
public StepLabelContainer(Surface parent) : base(parent) {
parent.AddStepLabel(this);
InitContent();
Init();
}
private void Init()
{
CreateDefaultAdorners();
}
#region Number serializing
@ -75,8 +81,9 @@ namespace Greenshot.Drawing {
/// Restore values that don't serialize
/// </summary>
/// <param name="context"></param>
[OnDeserialized]
private void SetValuesOnDeserialized(StreamingContext context) {
protected override void OnDeserialized(StreamingContext context)
{
Init();
_stringFormat = new StringFormat();
_stringFormat.Alignment = StringAlignment.Center;
_stringFormat.LineAlignment = StringAlignment.Center;

View file

@ -27,6 +27,7 @@ using Greenshot.IniFile;
using Greenshot.Memento;
using Greenshot.Plugin;
using Greenshot.Plugin.Drawing;
using Greenshot.Plugin.Drawing.Adorners;
using GreenshotPlugin.Controls;
using GreenshotPlugin.Core;
using log4net;
@ -40,7 +41,8 @@ using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
namespace Greenshot.Drawing {
namespace Greenshot.Drawing
{
/// <summary>
/// Description of Surface.
@ -991,12 +993,46 @@ namespace Greenshot.Drawing {
Invalidate();
}
/// <summary>
/// Check if an adorner was "hit", and change the cursor if so
/// </summary>
/// <param name="mouseEventArgs">MouseEventArgs</param>
/// <returns>IAdorner</returns>
private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs)
{
foreach(IDrawableContainer drawableContainer in selectedElements)
{
foreach(IAdorner adorner in drawableContainer.Adorners)
{
if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location))
{
if (adorner.Cursor != null)
{
Cursor = adorner.Cursor;
}
return adorner;
}
}
}
return null;
}
/// <summary>
/// This event handler is called when someone presses the mouse on a surface.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SurfaceMouseDown(object sender, MouseEventArgs e) {
// Handle Adorners
var adorner = FindActiveAdorner(e);
if (adorner != null)
{
adorner.MouseDown(sender, e);
return;
}
_mouseStart = e.Location;
// check contextmenu
@ -1068,6 +1104,15 @@ namespace Greenshot.Drawing {
/// <param name="sender"></param>
/// <param name="e"></param>
void SurfaceMouseUp(object sender, MouseEventArgs e) {
// Handle Adorners
var adorner = FindActiveAdorner(e);
if (adorner != null)
{
adorner.MouseUp(sender, e);
return;
}
Point currentMouse = new Point(e.X, e.Y);
_elements.Status = EditStatus.IDLE;
@ -1101,7 +1146,7 @@ namespace Greenshot.Drawing {
}
if (selectedElements.Count > 0) {
selectedElements.ShowGrippers();
selectedElements.Invalidate();
selectedElements.Selected = true;
}
@ -1129,6 +1174,14 @@ namespace Greenshot.Drawing {
/// <param name="sender"></param>
/// <param name="e"></param>
void SurfaceMouseMove(object sender, MouseEventArgs e) {
// Handle Adorners
var adorner = FindActiveAdorner(e);
if (adorner != null)
{
adorner.MouseMove(sender, e);
return;
}
Point currentMouse = e.Location;
if (DrawingMode != DrawingModes.None) {
@ -1140,7 +1193,7 @@ namespace Greenshot.Drawing {
if (_mouseDown) {
if (_mouseDownElement != null) { // an element is currently dragged
_mouseDownElement.Invalidate();
selectedElements.HideGrippers();
selectedElements.Invalidate();
// Move the element
if (_mouseDownElement.Selected) {
if (!_isSurfaceMoveMadeUndoable) {
@ -1211,10 +1264,10 @@ namespace Greenshot.Drawing {
/// This is the event handler for the Paint Event, try to draw as little as possible!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SurfacePaint(object sender, PaintEventArgs e) {
Graphics targetGraphics = e.Graphics;
Rectangle clipRectangle = e.ClipRectangle;
/// <param name="paintEventArgs">PaintEventArgs</param>
void SurfacePaint(object sender, PaintEventArgs paintEventArgs) {
Graphics targetGraphics = paintEventArgs.Graphics;
Rectangle clipRectangle = paintEventArgs.ClipRectangle;
if (Rectangle.Empty.Equals(clipRectangle)) {
LOG.Debug("Empty cliprectangle??");
return;
@ -1249,6 +1302,17 @@ namespace Greenshot.Drawing {
targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
_elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle);
}
// No clipping for the adorners
targetGraphics.ResetClip();
// Draw adorners last
foreach (var drawableContainer in selectedElements)
{
foreach(var adorner in drawableContainer.Adorners)
{
adorner.Paint(paintEventArgs);
}
}
}
private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) {
@ -1539,9 +1603,9 @@ namespace Greenshot.Drawing {
/// </summary>
/// <param name="container"></param>
public void DeselectElement(IDrawableContainer container) {
container.HideGrippers();
container.Selected = false;
selectedElements.Remove(container);
container.Invalidate();
FieldAggregator.UnbindElement(container);
if (_movingElementChanged != null) {
SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs();
@ -1557,10 +1621,9 @@ namespace Greenshot.Drawing {
if (HasSelectedElements) {
while(selectedElements.Count > 0) {
IDrawableContainer element = selectedElements[0];
element.Invalidate();
element.HideGrippers();
element.Selected = false;
selectedElements.Remove(element);
element.Invalidate();
FieldAggregator.UnbindElement(element);
}
if (_movingElementChanged != null) {
@ -1578,7 +1641,6 @@ namespace Greenshot.Drawing {
public void SelectElement(IDrawableContainer container) {
if (!selectedElements.Contains(container)) {
selectedElements.Add(container);
container.ShowGrippers();
container.Selected = true;
FieldAggregator.BindElement(container);
if (_movingElementChanged != null) {

View file

@ -98,8 +98,12 @@ namespace Greenshot.Drawing {
AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center);
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context) {
/// <summary>
/// Do some logic to make sure all field are initiated correctly
/// </summary>
/// <param name="streamingContext">StreamingContext</param>
protected override void OnDeserialized(StreamingContext streamingContext) {
base.OnDeserialized(streamingContext);
Init();
}

View file

@ -75,7 +75,12 @@
<Compile Include="Destinations\FileWithDialogDestination.cs" />
<Compile Include="Destinations\PickerDestination.cs" />
<Compile Include="Destinations\PrinterDestination.cs" />
<Compile Include="Drawing\Adorners\AbstractAdorner.cs" />
<Compile Include="Drawing\Adorners\MoveAdorner.cs" />
<Compile Include="Drawing\Adorners\ResizeAdorner.cs" />
<Compile Include="Drawing\Adorners\TargetAdorner.cs" />
<Compile Include="Drawing\ArrowContainer.cs" />
<Compile Include="Drawing\Positions.cs" />
<Compile Include="Drawing\StepLabelContainer.cs" />
<Compile Include="Drawing\ImageContainer.cs" />
<Compile Include="Drawing\CropContainer.cs" />
@ -101,9 +106,6 @@
<Compile Include="Drawing\Filters\MagnifierFilter.cs" />
<Compile Include="Drawing\Filters\PixelizationFilter.cs" />
<Compile Include="Drawing\Filters\BlurFilter.cs" />
<Compile Include="Drawing\Gripper.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Drawing\HighlightContainer.cs" />
<Compile Include="Drawing\IconContainer.cs" />
<Compile Include="Drawing\LineContainer.cs" />

View file

@ -116,15 +116,15 @@ namespace Greenshot.Helpers {
return GetAlignedRectangle(newRect, targetRect, alignment);
}
public static void RationalScale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) {
public static void RationalScale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) {
Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, ScaleOptions.Rational);
}
public static void CenteredScale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) {
public static void CenteredScale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) {
Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, ScaleOptions.Centered);
}
public static void Scale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) {
public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) {
Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, null);
}
@ -135,7 +135,7 @@ namespace Greenshot.Helpers {
/// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT</param>
/// <param name="resizeHandleCoords">coordinates of the used handle/gripper</param>
/// <param name="options">ScaleOptions to use when scaling</param>
public static void Scale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) {
public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) {
if(options == null) {
options = GetScaleOptions();
}
@ -154,7 +154,7 @@ namespace Greenshot.Helpers {
resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX);
resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY);
// scale again with opposing handle and mirrored coordinates
resizeHandlePosition = (resizeHandlePosition + 4) % 8;
resizeHandlePosition = (Positions)((((int)resizeHandlePosition) + 4) % 8);
scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords);
} else {
scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords);
@ -168,47 +168,47 @@ namespace Greenshot.Helpers {
/// <param name="originalRectangle">bounds of the current rectangle, scaled values will be written to this reference</param>
/// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT</param>
/// <param name="resizeHandleCoords">coordinates of the used handle/gripper</param>
private static void scale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) {
private static void scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) {
switch(resizeHandlePosition) {
case Gripper.POSITION_TOP_LEFT:
case Positions.TopLeft:
originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X;
originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y;
originalRectangle.X = resizeHandleCoords.X;
originalRectangle.Y = resizeHandleCoords.Y;
break;
case Gripper.POSITION_TOP_CENTER:
case Positions.TopCenter:
originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y;
originalRectangle.Y = resizeHandleCoords.Y;
break;
case Gripper.POSITION_TOP_RIGHT:
case Positions.TopRight:
originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left;
originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y;
originalRectangle.Y = resizeHandleCoords.Y;
break;
case Gripper.POSITION_MIDDLE_LEFT:
case Positions.MiddleLeft:
originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X;
originalRectangle.X = resizeHandleCoords.X;
break;
case Gripper.POSITION_MIDDLE_RIGHT:
case Positions.MiddleRight:
originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left;
break;
case Gripper.POSITION_BOTTOM_LEFT:
case Positions.BottomLeft:
originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X;
originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top;
originalRectangle.X = resizeHandleCoords.X;
break;
case Gripper.POSITION_BOTTOM_CENTER:
case Positions.BottomCenter:
originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top;
break;
case Gripper.POSITION_BOTTOM_RIGHT:
case Positions.BottomRight:
originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left;
originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top;
break;
@ -223,14 +223,14 @@ namespace Greenshot.Helpers {
/// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments
/// </summary>
/// <param name="originalRectangle">bounds of the current rectangle</param>
/// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT</param>
/// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see Position</param>
/// <param name="resizeHandleCoords">coordinates of the used handle/gripper, adjusted coordinates will be written to this reference</param>
private static void adjustCoordsForRationalScale(RectangleF originalRectangle, int resizeHandlePosition, ref PointF resizeHandleCoords) {
private static void adjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) {
float originalRatio = originalRectangle.Width / originalRectangle.Height;
float newWidth, newHeight, newRatio;
switch(resizeHandlePosition) {
case Gripper.POSITION_TOP_LEFT:
case Positions.TopLeft:
newWidth = originalRectangle.Right - resizeHandleCoords.X;
newHeight = originalRectangle.Bottom - resizeHandleCoords.Y;
newRatio = newWidth / newHeight;
@ -241,7 +241,7 @@ namespace Greenshot.Helpers {
}
break;
case Gripper.POSITION_TOP_RIGHT:
case Positions.TopRight:
newWidth = resizeHandleCoords.X - originalRectangle.Left;
newHeight = originalRectangle.Bottom - resizeHandleCoords.Y;
newRatio = newWidth / newHeight;
@ -252,7 +252,7 @@ namespace Greenshot.Helpers {
}
break;
case Gripper.POSITION_BOTTOM_LEFT:
case Positions.BottomLeft:
newWidth = originalRectangle.Right - resizeHandleCoords.X;
newHeight = resizeHandleCoords.Y - originalRectangle.Top;
newRatio = newWidth / newHeight;
@ -263,7 +263,7 @@ namespace Greenshot.Helpers {
}
break;
case Gripper.POSITION_BOTTOM_RIGHT:
case Positions.BottomRight:
newWidth = resizeHandleCoords.X - originalRectangle.Left;
newHeight = resizeHandleCoords.Y - originalRectangle.Top;
newRatio = newWidth / newHeight;
@ -282,10 +282,10 @@ namespace Greenshot.Helpers {
public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) {
Scale(boundsBeforeResize, Gripper.POSITION_TOP_LEFT, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior);
Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior);
}
public static void Scale(Rectangle boundsBeforeResize, int gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) {
public static void Scale(Rectangle boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) {
ScaleOptions opts = GetScaleOptions();

View file

@ -67,6 +67,7 @@
<Compile Include="IEInterop\IHTMLWindow3.cs" />
<Compile Include="IEInterop\IHTMLWindow4.cs" />
<Compile Include="IEInterop\IWebBrowser2.cs" />
<Compile Include="Interfaces\Drawing\Adorners\IAdorner.cs" />
<Compile Include="Interop\Base.cs" />
<Compile Include="Interop\ComProgIdAttribute.cs" />
<Compile Include="Interop\COMWrapper.cs" />

View file

@ -0,0 +1,91 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Greenshot.Plugin.Drawing.Adorners
{
public interface IAdorner
{
/// <summary>
/// Returns if this adorner is active
/// </summary>
bool IsActive { get; }
/// <summary>
/// The current edit status, this is needed to locate the adorner to send events to
/// </summary>
EditStatus EditStatus { get; }
/// <summary>
/// The owner of this adorner
/// </summary>
IDrawableContainer Owner { get; }
/// <summary>
/// Is the current point "over" the Adorner?
/// If this is the case, the
/// </summary>
/// <param name="point">Point to test</param>
/// <returns>true if so</returns>
bool HitTest(Point point);
/// <summary>
/// Handle the MouseDown event
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs">MouseEventArgs</param>
void MouseDown(object sender, MouseEventArgs mouseEventArgs);
/// <summary>
/// Handle the MouseUp event
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs">MouseEventArgs</param>
void MouseUp(object sender, MouseEventArgs mouseEventArgs);
/// <summary>
/// Handle the MouseMove event
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs">MouseEventArgs</param>
void MouseMove(object sender, MouseEventArgs mouseEventArgs);
/// <summary>
/// Gets the cursor that should be displayed for this behavior.
/// </summary>
Cursor Cursor { get; }
/// <summary>
/// Draw the adorner
/// </summary>
/// <param name="paintEventArgs">PaintEventArgs</param>
void Paint(PaintEventArgs paintEventArgs);
/// <summary>
/// Called if the owner is transformed
/// </summary>
/// <param name="matrix">Matrix</param>
void Transform(Matrix matrix);
}
}

View file

@ -24,6 +24,9 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using Greenshot.Plugin.Drawing.Adorners;
using System.Runtime.Serialization;
namespace Greenshot.Plugin.Drawing {
public enum RenderMode {EDIT, EXPORT};
@ -74,6 +77,8 @@ namespace Greenshot.Plugin.Drawing {
get;
}
void ApplyBounds(RectangleF newBounds);
bool hasFilters {
get;
}
@ -85,8 +90,6 @@ namespace Greenshot.Plugin.Drawing {
void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment);
void Invalidate();
bool ClickableAt(int x, int y);
void HideGrippers();
void ShowGrippers();
void MoveBy(int x, int y);
void Transform(Matrix matrix);
bool HandleMouseDown(int x, int y);
@ -97,6 +100,11 @@ namespace Greenshot.Plugin.Drawing {
EditStatus DefaultEditMode {
get;
}
/// <summary>
/// Available adorners for the DrawableContainer
/// </summary>
IList<IAdorner> Adorners { get; }
}
public interface ITextContainer: IDrawableContainer {

View file

@ -197,5 +197,7 @@ namespace Greenshot.Plugin {
get;
set;
}
int Width { get; }
int Height { get; }
}
}