mirror of
https://github.com/greenshot/greenshot
synced 2025-08-21 05:53:27 -07:00
Merge remote-tracking branch 'remotes/origin/master' into release/1.2.9
This commit is contained in:
commit
0323705513
276 changed files with 5382 additions and 3666 deletions
147
Greenshot/Drawing/Adorners/AbstractAdorner.cs
Normal file
147
Greenshot/Drawing/Adorners/AbstractAdorner.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
165
Greenshot/Drawing/Adorners/MoveAdorner.cs
Normal file
165
Greenshot/Drawing/Adorners/MoveAdorner.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
186
Greenshot/Drawing/Adorners/ResizeAdorner.cs
Normal file
186
Greenshot/Drawing/Adorners/ResizeAdorner.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
119
Greenshot/Drawing/Adorners/TargetAdorner.cs
Normal file
119
Greenshot/Drawing/Adorners/TargetAdorner.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,7 +79,7 @@ namespace Greenshot.Drawing {
|
|||
Top + currentStep + Height);
|
||||
|
||||
currentStep++;
|
||||
alpha = alpha - (basealpha / steps);
|
||||
alpha = alpha - basealpha / steps;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
*/
|
||||
|
||||
using System.Drawing;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Helpers;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
/// <summary>
|
||||
|
@ -30,13 +32,28 @@ 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);
|
||||
AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE);
|
||||
}
|
||||
|
||||
public override void Invalidate() {
|
||||
if (_parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_parent.Invalidate();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
@ -33,14 +34,26 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
[Serializable]
|
||||
public class CursorContainer : DrawableContainer, ICursorContainer {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(CursorContainer));
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,19 @@ using Greenshot.IniFile;
|
|||
using Greenshot.Memento;
|
||||
using Greenshot.Plugin;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using Greenshot.Plugin.Drawing.Adorners;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
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,12 +51,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 M12 = 1;
|
||||
private const int M21 = 2;
|
||||
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 {
|
||||
|
@ -73,16 +89,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);
|
||||
|
@ -99,7 +105,7 @@ namespace Greenshot.Drawing {
|
|||
remove{ _propertyChanged -= value; }
|
||||
}
|
||||
|
||||
public List<IFilter> Filters {
|
||||
public IList<IFilter> Filters {
|
||||
get {
|
||||
List<IFilter> ret = new List<IFilter>();
|
||||
foreach(IFieldHolder c in Children) {
|
||||
|
@ -117,16 +123,12 @@ 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 _targetAdorner;
|
||||
public TargetAdorner TargetAdorner {
|
||||
get {
|
||||
return _targetGripper;
|
||||
return _targetAdorner;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +162,6 @@ namespace Greenshot.Drawing {
|
|||
return;
|
||||
}
|
||||
left = value;
|
||||
DoLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +173,6 @@ namespace Greenshot.Drawing {
|
|||
return;
|
||||
}
|
||||
top = value;
|
||||
DoLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,6 @@ namespace Greenshot.Drawing {
|
|||
return;
|
||||
}
|
||||
width = value;
|
||||
DoLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +195,6 @@ namespace Greenshot.Drawing {
|
|||
return;
|
||||
}
|
||||
height = value;
|
||||
DoLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +218,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;
|
||||
|
@ -248,7 +259,6 @@ namespace Greenshot.Drawing {
|
|||
public DrawableContainer(Surface parent) {
|
||||
InitializeFields();
|
||||
_parent = parent;
|
||||
InitControls();
|
||||
}
|
||||
|
||||
public void Add(IFilter filter) {
|
||||
|
@ -296,7 +306,10 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
|
||||
public void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) {
|
||||
|
||||
if (_parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
|
||||
if (horizontalAlignment == HorizontalAlignment.Left) {
|
||||
Left = lineThickness/2;
|
||||
|
@ -322,188 +335,35 @@ namespace Greenshot.Drawing {
|
|||
public virtual bool InitContent() { return true; }
|
||||
|
||||
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
|
||||
}
|
||||
protected void InitAdorner(Color gripperColor, Point location) {
|
||||
_targetAdorner = new TargetAdorner(this, location);
|
||||
Adorners.Add(_targetAdorner);
|
||||
}
|
||||
|
||||
protected void InitGrippers() {
|
||||
|
||||
_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;
|
||||
}
|
||||
_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};
|
||||
/// <summary>
|
||||
/// Create the default adorners for a rectangle based container
|
||||
/// </summary>
|
||||
|
||||
_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;
|
||||
}
|
||||
protected void CreateDefaultAdorners() {
|
||||
if (Adorners.Count > 0)
|
||||
{
|
||||
LOG.Warn("Adorners are already defined!");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
// 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));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public bool hasFilters {
|
||||
get {
|
||||
return Filters.Count > 0;
|
||||
|
@ -558,43 +418,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>
|
||||
|
@ -606,10 +433,8 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
|
||||
public void MoveBy(int dx, int dy) {
|
||||
SuspendLayout();
|
||||
Left += dx;
|
||||
Top += dy;
|
||||
ResumeLayout();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -632,7 +457,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;
|
||||
|
@ -645,7 +469,6 @@ namespace Greenshot.Drawing {
|
|||
// apply scaled bounds to this DrawableContainer
|
||||
ApplyBounds(_boundsAfterResize);
|
||||
|
||||
ResumeLayout();
|
||||
Invalidate();
|
||||
return true;
|
||||
}
|
||||
|
@ -659,49 +482,26 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
|
||||
protected virtual void SwitchParent(Surface newParent) {
|
||||
// Target gripper
|
||||
if (_parent != null && _targetGripper != null) {
|
||||
_parent.Controls.Remove(_targetGripper);
|
||||
if (newParent == Parent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Normal grippers
|
||||
if (_parent != null && _grippers != null) {
|
||||
for (int i=0; i<_grippers.Length; i++) {
|
||||
_parent.Controls.Remove(_grippers[i]);
|
||||
if (_parent != null)
|
||||
{
|
||||
// Remove FieldAggregator
|
||||
FieldAggregator fieldAggregator = _parent.FieldAggregator;
|
||||
if (fieldAggregator != null)
|
||||
{
|
||||
fieldAggregator.UnbindElement(this);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
// drawablecontainers are regarded equal if they are of the same type and their bounds are equal. this should be sufficient.
|
||||
public override bool Equals(object obj) {
|
||||
bool ret = false;
|
||||
if (obj != null && GetType() == obj.GetType()) {
|
||||
DrawableContainer other = obj as DrawableContainer;
|
||||
if (other != null && left==other.left && top==other.top && width==other.width && height==other.height) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return left.GetHashCode() ^ top.GetHashCode() ^ width.GetHashCode() ^ height.GetHashCode() ^ GetFields().GetHashCode();
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged(string propertyName) {
|
||||
if (_propertyChanged != null) {
|
||||
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
@ -715,7 +515,7 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="fieldToBeChanged">The field to be changed</param>
|
||||
/// <param name="newValue">The new value</param>
|
||||
public virtual void BeforeFieldChange(Field fieldToBeChanged, object newValue) {
|
||||
public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) {
|
||||
_parent.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true);
|
||||
Invalidate();
|
||||
}
|
||||
|
@ -730,7 +530,6 @@ namespace Greenshot.Drawing {
|
|||
if (e.Field.FieldType == FieldType.SHADOW) {
|
||||
accountForShadowChange = true;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -775,26 +574,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() {
|
||||
|
|
|
@ -25,6 +25,7 @@ using Greenshot.Memento;
|
|||
using Greenshot.Plugin;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
@ -38,7 +39,8 @@ namespace Greenshot.Drawing {
|
|||
/// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DrawableContainerList : List<IDrawableContainer> {
|
||||
public class DrawableContainerList : List<IDrawableContainer>, IDrawableContainerList
|
||||
{
|
||||
private static readonly ComponentResourceManager editorFormResources = new ComponentResourceManager(typeof(ImageEditorForm));
|
||||
|
||||
public Guid ParentID {
|
||||
|
@ -116,14 +118,11 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="allowMerge">true means allow the moves to be merged</param>
|
||||
public void MakeBoundsChangeUndoable(bool allowMerge) {
|
||||
List<IDrawableContainer> movingList = new List<IDrawableContainer>();
|
||||
Surface surface = null;
|
||||
foreach(DrawableContainer dc in this) {
|
||||
movingList.Add(dc);
|
||||
surface = dc._parent;
|
||||
}
|
||||
if (movingList.Count > 0 && surface != null) {
|
||||
surface.MakeUndoable(new DrawableContainerBoundsChangeMemento(movingList), allowMerge);
|
||||
if (Count > 0 && Parent != null)
|
||||
{
|
||||
var clone = new DrawableContainerList();
|
||||
clone.AddRange(this);
|
||||
Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,26 +170,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>
|
||||
|
@ -266,9 +245,19 @@ namespace Greenshot.Drawing {
|
|||
/// <param name="renderMode">the rendermode in which the element is to be drawn</param>
|
||||
/// <param name="clipRectangle"></param>
|
||||
public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) {
|
||||
foreach(var drawableContainer in this) {
|
||||
var dc = (DrawableContainer) drawableContainer;
|
||||
if (dc.DrawingBounds.IntersectsWith(clipRectangle)) {
|
||||
if (Parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var drawableContainer in this)
|
||||
{
|
||||
var dc = (DrawableContainer)drawableContainer;
|
||||
if (dc.Parent == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (dc.DrawingBounds.IntersectsWith(clipRectangle))
|
||||
{
|
||||
dc.DrawContent(g, bitmap, renderMode, clipRectangle);
|
||||
}
|
||||
}
|
||||
|
@ -290,9 +279,16 @@ namespace Greenshot.Drawing {
|
|||
/// Invalidate the bounds of all the DC's in this list
|
||||
/// </summary>
|
||||
public void Invalidate() {
|
||||
foreach(var dc in this) {
|
||||
dc.Invalidate();
|
||||
if (Parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Rectangle region = Rectangle.Empty;
|
||||
foreach (var dc in this)
|
||||
{
|
||||
region = Rectangle.Union(region, dc.DrawingBounds);
|
||||
}
|
||||
Parent.Invalidate(region);
|
||||
}
|
||||
/// <summary>
|
||||
/// Indicates whether the given list of elements can be pulled up,
|
||||
|
@ -300,7 +296,7 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="elements">list of elements to pull up</param>
|
||||
/// <returns>true if the elements could be pulled up</returns>
|
||||
public bool CanPullUp(DrawableContainerList elements) {
|
||||
public bool CanPullUp(IDrawableContainerList elements) {
|
||||
if (elements.Count == 0 || elements.Count == Count) {
|
||||
return false;
|
||||
}
|
||||
|
@ -316,13 +312,13 @@ namespace Greenshot.Drawing {
|
|||
/// Pulls one or several elements up one level in hierarchy (z-index).
|
||||
/// </summary>
|
||||
/// <param name="elements">list of elements to pull up</param>
|
||||
public void PullElementsUp(DrawableContainerList elements) {
|
||||
public void PullElementsUp(IDrawableContainerList elements) {
|
||||
for(int i=Count-1; i>=0; i--) {
|
||||
var dc = this[i];
|
||||
if (!elements.Contains(dc)) {
|
||||
continue;
|
||||
}
|
||||
if (Count > (i+1) && !elements.Contains(this[i+1])) {
|
||||
if (Count > i+1 && !elements.Contains(this[i+1])) {
|
||||
SwapElements(i,i+1);
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +328,7 @@ namespace Greenshot.Drawing {
|
|||
/// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index).
|
||||
/// </summary>
|
||||
/// <param name="elements">of elements to pull to top</param>
|
||||
public void PullElementsToTop(DrawableContainerList elements) {
|
||||
public void PullElementsToTop(IDrawableContainerList elements) {
|
||||
var dcs = ToArray();
|
||||
for(int i=0; i<dcs.Length; i++) {
|
||||
var dc = dcs[i];
|
||||
|
@ -351,7 +347,7 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="elements">list of elements to push down</param>
|
||||
/// <returns>true if the elements could be pushed down</returns>
|
||||
public bool CanPushDown(DrawableContainerList elements) {
|
||||
public bool CanPushDown(IDrawableContainerList elements) {
|
||||
if (elements.Count == 0 || elements.Count == Count) {
|
||||
return false;
|
||||
}
|
||||
|
@ -367,7 +363,7 @@ namespace Greenshot.Drawing {
|
|||
/// Pushes one or several elements down one level in hierarchy (z-index).
|
||||
/// </summary>
|
||||
/// <param name="elements">list of elements to push down</param>
|
||||
public void PushElementsDown(DrawableContainerList elements) {
|
||||
public void PushElementsDown(IDrawableContainerList elements) {
|
||||
for(int i=0; i<Count; i++) {
|
||||
var dc = this[i];
|
||||
if (!elements.Contains(dc)) {
|
||||
|
@ -383,7 +379,7 @@ namespace Greenshot.Drawing {
|
|||
/// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index).
|
||||
/// </summary>
|
||||
/// <param name="elements">of elements to push to bottom</param>
|
||||
public void PushElementsToBottom(DrawableContainerList elements) {
|
||||
public void PushElementsToBottom(IDrawableContainerList elements) {
|
||||
var dcs = ToArray();
|
||||
for(int i=dcs.Length-1; i>=0; i--) {
|
||||
var dc = dcs[i];
|
||||
|
@ -417,7 +413,7 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="menu"></param>
|
||||
/// <param name="surface"></param>
|
||||
public virtual void AddContextMenuItems(ContextMenuStrip menu, Surface surface) {
|
||||
public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) {
|
||||
bool push = surface.Elements.CanPushDown(this);
|
||||
bool pull = surface.Elements.CanPullUp(this);
|
||||
|
||||
|
@ -457,7 +453,7 @@ namespace Greenshot.Drawing {
|
|||
// Duplicate
|
||||
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate));
|
||||
item.Click += delegate {
|
||||
DrawableContainerList dcs = this.Clone();
|
||||
IDrawableContainerList dcs = this.Clone();
|
||||
dcs.Parent = surface;
|
||||
dcs.MoveBy(10, 10);
|
||||
surface.AddElements(dcs);
|
||||
|
@ -470,7 +466,7 @@ namespace Greenshot.Drawing {
|
|||
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard));
|
||||
item.Image = ((Image)(editorFormResources.GetObject("copyToolStripMenuItem.Image")));
|
||||
item.Click += delegate {
|
||||
ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), this);
|
||||
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this);
|
||||
};
|
||||
menu.Items.Add(item);
|
||||
|
||||
|
@ -478,15 +474,8 @@ namespace Greenshot.Drawing {
|
|||
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard));
|
||||
item.Image = ((Image)(editorFormResources.GetObject("btnCut.Image")));
|
||||
item.Click += delegate {
|
||||
ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), this);
|
||||
List<DrawableContainer> containersToDelete = new List<DrawableContainer>();
|
||||
foreach (var drawableContainer in this) {
|
||||
var container = (DrawableContainer) drawableContainer;
|
||||
containersToDelete.Add(container);
|
||||
}
|
||||
foreach (var container in containersToDelete) {
|
||||
surface.RemoveElement(container, true);
|
||||
}
|
||||
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this);
|
||||
surface.RemoveElements(this, true);
|
||||
};
|
||||
menu.Items.Add(item);
|
||||
|
||||
|
@ -494,22 +483,17 @@ namespace Greenshot.Drawing {
|
|||
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement));
|
||||
item.Image = ((Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image")));
|
||||
item.Click += delegate {
|
||||
List<DrawableContainer> containersToDelete = new List<DrawableContainer>();
|
||||
foreach(var drawableContainer in this) {
|
||||
var container = (DrawableContainer) drawableContainer;
|
||||
containersToDelete.Add(container);
|
||||
}
|
||||
foreach (DrawableContainer container in containersToDelete) {
|
||||
surface.RemoveElement(container, true);
|
||||
}
|
||||
surface.RemoveElements(this, true);
|
||||
};
|
||||
menu.Items.Add(item);
|
||||
|
||||
// Reset
|
||||
bool canReset = false;
|
||||
foreach (var drawableContainer in this) {
|
||||
var container = (DrawableContainer) drawableContainer;
|
||||
if (container.HasDefaultSize) {
|
||||
foreach (var drawableContainer in this)
|
||||
{
|
||||
var container = (DrawableContainer)drawableContainer;
|
||||
if (container.HasDefaultSize)
|
||||
{
|
||||
canReset = true;
|
||||
}
|
||||
}
|
||||
|
@ -517,24 +501,29 @@ namespace Greenshot.Drawing {
|
|||
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize));
|
||||
//item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image")));
|
||||
item.Click += delegate {
|
||||
MakeBoundsChangeUndoable(false);
|
||||
foreach (var drawableContainer in this) {
|
||||
var container = (DrawableContainer) drawableContainer;
|
||||
if (!container.HasDefaultSize) {
|
||||
continue;
|
||||
}
|
||||
Size defaultSize = container.DefaultSize;
|
||||
container.Invalidate();
|
||||
container.MakeBoundsChangeUndoable(false);
|
||||
container.Width = defaultSize.Width;
|
||||
container.Height = defaultSize.Height;
|
||||
container.Invalidate();
|
||||
}
|
||||
surface.Invalidate();
|
||||
};
|
||||
menu.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ShowContextMenu(MouseEventArgs e, Surface surface) {
|
||||
public virtual void ShowContextMenu(MouseEventArgs e, ISurface surface)
|
||||
{
|
||||
if (!(surface is Surface))
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool hasMenu = false;
|
||||
foreach (var drawableContainer in this) {
|
||||
var container = (DrawableContainer) drawableContainer;
|
||||
|
@ -548,7 +537,8 @@ namespace Greenshot.Drawing {
|
|||
ContextMenuStrip menu = new ContextMenuStrip();
|
||||
AddContextMenuItems(menu, surface);
|
||||
if (menu.Items.Count > 0) {
|
||||
menu.Show(surface, e.Location);
|
||||
// TODO: cast should be somehow avoided
|
||||
menu.Show((Surface)surface, e.Location);
|
||||
while (true) {
|
||||
if (menu.Visible) {
|
||||
Application.DoEvents();
|
||||
|
@ -561,5 +551,32 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
private bool _disposedValue = false; // To detect redundant calls
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var drawableContainer in this)
|
||||
{
|
||||
drawableContainer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(true);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace Greenshot.Drawing {
|
|||
[Serializable()]
|
||||
public class EllipseContainer : DrawableContainer {
|
||||
public EllipseContainer(Surface parent) : base(parent) {
|
||||
CreateDefaultAdorners();
|
||||
}
|
||||
|
||||
protected override void InitializeFields() {
|
||||
|
@ -59,12 +60,15 @@ namespace Greenshot.Drawing {
|
|||
/// <summary>
|
||||
/// This allows another container to draw an ellipse
|
||||
/// </summary>
|
||||
/// <param name="caller"></param>
|
||||
/// <param name="rect"></param>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="renderMode"></param>
|
||||
/// <param name="lineThickness"></param>
|
||||
/// <param name="lineColor"></param>
|
||||
/// <param name="fillColor"></param>
|
||||
/// <param name="shadow"></param>
|
||||
public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) {
|
||||
|
||||
bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
|
||||
bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
|
||||
// draw shadow before anything else
|
||||
if (shadow && (lineVisible || Colors.IsVisible(fillColor))) {
|
||||
int basealpha = 100;
|
||||
|
|
|
@ -26,13 +26,16 @@ using System.Runtime.Serialization;
|
|||
using Greenshot.Configuration;
|
||||
using Greenshot.IniFile;
|
||||
using log4net;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing.Fields {
|
||||
namespace Greenshot.Drawing.Fields
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic IFieldHolder implementation, providing access to a set of fields
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class AbstractFieldHolder : IFieldHolder {
|
||||
public abstract class AbstractFieldHolder : IFieldHolder
|
||||
{
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder));
|
||||
private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
|
||||
|
||||
|
@ -41,26 +44,30 @@ namespace Greenshot.Drawing.Fields {
|
|||
/// </summary>
|
||||
[NonSerialized]
|
||||
private FieldChangedEventHandler fieldChanged;
|
||||
public event FieldChangedEventHandler FieldChanged {
|
||||
public event FieldChangedEventHandler FieldChanged
|
||||
{
|
||||
add { fieldChanged += value; }
|
||||
remove{ fieldChanged -= value; }
|
||||
remove { fieldChanged -= value; }
|
||||
}
|
||||
|
||||
|
||||
// we keep two Collections of our fields, dictionary for quick access, list for serialization
|
||||
// this allows us to use default serialization
|
||||
[NonSerialized]
|
||||
private Dictionary<FieldType, Field> fieldsByType = new Dictionary<FieldType, Field>();
|
||||
private List<Field> fields = new List<Field>();
|
||||
|
||||
public AbstractFieldHolder() {}
|
||||
|
||||
private IDictionary<IFieldType, IField> fieldsByType = new Dictionary<IFieldType, IField>();
|
||||
private IList<IField> fields = new List<IField>();
|
||||
|
||||
public AbstractFieldHolder() { }
|
||||
|
||||
[OnDeserialized]
|
||||
private void OnDeserialized(StreamingContext context) {
|
||||
fieldsByType = new Dictionary<FieldType, Field>();
|
||||
private void OnDeserialized(StreamingContext context)
|
||||
{
|
||||
fieldsByType = new Dictionary<IFieldType, IField>();
|
||||
// listen to changing properties
|
||||
foreach(Field field in fields) {
|
||||
foreach (Field field in fields)
|
||||
{
|
||||
field.PropertyChanged += delegate {
|
||||
if (fieldChanged != null) {
|
||||
if (fieldChanged != null)
|
||||
{
|
||||
fieldChanged(this, new FieldChangedEventArgs(field));
|
||||
}
|
||||
};
|
||||
|
@ -68,97 +75,124 @@ namespace Greenshot.Drawing.Fields {
|
|||
}
|
||||
}
|
||||
|
||||
public void AddField(Type requestingType, FieldType fieldType, object fieldValue) {
|
||||
public void AddField(Type requestingType, IFieldType fieldType, object fieldValue)
|
||||
{
|
||||
AddField(editorConfiguration.CreateField(requestingType, fieldType, fieldValue));
|
||||
}
|
||||
|
||||
public virtual void AddField(Field field) {
|
||||
if (fieldsByType != null && fieldsByType.ContainsKey(field.FieldType)) {
|
||||
if (LOG.IsDebugEnabled) {
|
||||
public virtual void AddField(IField field)
|
||||
{
|
||||
if (fieldsByType != null && fieldsByType.ContainsKey(field.FieldType))
|
||||
{
|
||||
if (LOG.IsDebugEnabled)
|
||||
{
|
||||
LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fields.Add(field);
|
||||
fieldsByType[field.FieldType] = field;
|
||||
field.PropertyChanged += delegate { if(fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); };
|
||||
field.PropertyChanged += delegate { if (fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); };
|
||||
}
|
||||
|
||||
public void RemoveField(Field field) {
|
||||
|
||||
public void RemoveField(IField field)
|
||||
{
|
||||
fields.Remove(field);
|
||||
fieldsByType.Remove(field.FieldType);
|
||||
field.PropertyChanged -= delegate {
|
||||
if (fieldChanged != null) {
|
||||
if (fieldChanged != null)
|
||||
{
|
||||
fieldChanged(this, new FieldChangedEventArgs(field));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<Field> GetFields() {
|
||||
|
||||
public IList<IField> GetFields()
|
||||
{
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
public Field GetField(FieldType fieldType) {
|
||||
try {
|
||||
|
||||
public IField GetField(IFieldType fieldType)
|
||||
{
|
||||
try
|
||||
{
|
||||
return fieldsByType[fieldType];
|
||||
} catch(KeyNotFoundException e) {
|
||||
}
|
||||
catch (KeyNotFoundException e)
|
||||
{
|
||||
throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public object GetFieldValue(FieldType fieldType) {
|
||||
|
||||
public object GetFieldValue(IFieldType fieldType)
|
||||
{
|
||||
return GetField(fieldType).Value;
|
||||
}
|
||||
|
||||
|
||||
#region convenience methods to save us some casts outside
|
||||
public string GetFieldValueAsString(FieldType fieldType) {
|
||||
public string GetFieldValueAsString(IFieldType fieldType)
|
||||
{
|
||||
return Convert.ToString(GetFieldValue(fieldType));
|
||||
}
|
||||
|
||||
public int GetFieldValueAsInt(FieldType fieldType) {
|
||||
|
||||
public int GetFieldValueAsInt(IFieldType fieldType)
|
||||
{
|
||||
return Convert.ToInt32(GetFieldValue(fieldType));
|
||||
}
|
||||
|
||||
public decimal GetFieldValueAsDecimal(FieldType fieldType) {
|
||||
|
||||
public decimal GetFieldValueAsDecimal(IFieldType fieldType)
|
||||
{
|
||||
return Convert.ToDecimal(GetFieldValue(fieldType));
|
||||
}
|
||||
|
||||
public double GetFieldValueAsDouble(FieldType fieldType) {
|
||||
|
||||
public double GetFieldValueAsDouble(IFieldType fieldType)
|
||||
{
|
||||
return Convert.ToDouble(GetFieldValue(fieldType));
|
||||
}
|
||||
|
||||
public float GetFieldValueAsFloat(FieldType fieldType) {
|
||||
|
||||
public float GetFieldValueAsFloat(IFieldType fieldType)
|
||||
{
|
||||
return Convert.ToSingle(GetFieldValue(fieldType));
|
||||
}
|
||||
|
||||
public bool GetFieldValueAsBool(FieldType fieldType) {
|
||||
|
||||
public bool GetFieldValueAsBool(IFieldType fieldType)
|
||||
{
|
||||
return Convert.ToBoolean(GetFieldValue(fieldType));
|
||||
}
|
||||
|
||||
public Color GetFieldValueAsColor(FieldType fieldType) {
|
||||
|
||||
public Color GetFieldValueAsColor(IFieldType fieldType)
|
||||
{
|
||||
return (Color)GetFieldValue(fieldType);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public bool HasField(FieldType fieldType) {
|
||||
|
||||
public bool HasField(IFieldType fieldType)
|
||||
{
|
||||
return fieldsByType.ContainsKey(fieldType);
|
||||
}
|
||||
|
||||
public bool HasFieldValue(FieldType fieldType) {
|
||||
|
||||
public bool HasFieldValue(IFieldType fieldType)
|
||||
{
|
||||
return HasField(fieldType) && fieldsByType[fieldType].HasValue;
|
||||
}
|
||||
|
||||
public void SetFieldValue(FieldType fieldType, object value) {
|
||||
try {
|
||||
|
||||
public void SetFieldValue(IFieldType fieldType, object value)
|
||||
{
|
||||
try
|
||||
{
|
||||
fieldsByType[fieldType].Value = value;
|
||||
} catch(KeyNotFoundException e) {
|
||||
throw new ArgumentException("Field '"+fieldType+"' does not exist in " + GetType(), e);
|
||||
}
|
||||
catch (KeyNotFoundException e)
|
||||
{
|
||||
throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnFieldChanged(object sender, FieldChangedEventArgs e){
|
||||
if (fieldChanged != null) {
|
||||
|
||||
protected void OnFieldChanged(object sender, FieldChangedEventArgs e)
|
||||
{
|
||||
if (fieldChanged != null)
|
||||
{
|
||||
fieldChanged(sender, e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,87 +18,110 @@
|
|||
* 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 GreenshotPlugin.Interfaces.Drawing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Greenshot.Drawing.Fields {
|
||||
namespace Greenshot.Drawing.Fields
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder,
|
||||
/// but has a List<IFieldHolder> of children.
|
||||
/// Field values are passed to and from children as well.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder {
|
||||
|
||||
[Serializable()]
|
||||
public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder
|
||||
{
|
||||
|
||||
FieldChangedEventHandler fieldChangedEventHandler;
|
||||
|
||||
|
||||
[NonSerialized]
|
||||
private EventHandler childrenChanged;
|
||||
public event EventHandler ChildrenChanged {
|
||||
public event EventHandler ChildrenChanged
|
||||
{
|
||||
add { childrenChanged += value; }
|
||||
remove { childrenChanged -= value; }
|
||||
}
|
||||
|
||||
|
||||
public List<IFieldHolder> Children = new List<IFieldHolder>();
|
||||
|
||||
public AbstractFieldHolderWithChildren() {
|
||||
|
||||
public AbstractFieldHolderWithChildren()
|
||||
{
|
||||
fieldChangedEventHandler = OnFieldChanged;
|
||||
}
|
||||
|
||||
|
||||
[OnDeserialized()]
|
||||
private void OnDeserialized(StreamingContext context) {
|
||||
private void OnDeserialized(StreamingContext context)
|
||||
{
|
||||
// listen to changing properties
|
||||
foreach(IFieldHolder fieldHolder in Children) {
|
||||
foreach (IFieldHolder fieldHolder in Children)
|
||||
{
|
||||
fieldHolder.FieldChanged += fieldChangedEventHandler;
|
||||
}
|
||||
if(childrenChanged != null) childrenChanged(this, EventArgs.Empty);
|
||||
if (childrenChanged != null) childrenChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void AddChild(IFieldHolder fieldHolder) {
|
||||
|
||||
public void AddChild(IFieldHolder fieldHolder)
|
||||
{
|
||||
Children.Add(fieldHolder);
|
||||
fieldHolder.FieldChanged += fieldChangedEventHandler;
|
||||
if(childrenChanged != null) childrenChanged(this, EventArgs.Empty);
|
||||
if (childrenChanged != null) childrenChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void RemoveChild(IFieldHolder fieldHolder) {
|
||||
|
||||
public void RemoveChild(IFieldHolder fieldHolder)
|
||||
{
|
||||
Children.Remove(fieldHolder);
|
||||
fieldHolder.FieldChanged -= fieldChangedEventHandler;
|
||||
if(childrenChanged != null) childrenChanged(this, EventArgs.Empty);
|
||||
if (childrenChanged != null) childrenChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public new List<Field> GetFields() {
|
||||
List<Field> ret = new List<Field>();
|
||||
|
||||
public new IList<IField> GetFields()
|
||||
{
|
||||
List<IField> ret = new List<IField>();
|
||||
ret.AddRange(base.GetFields());
|
||||
foreach(IFieldHolder fh in Children) {
|
||||
foreach (IFieldHolder fh in Children)
|
||||
{
|
||||
ret.AddRange(fh.GetFields());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public new Field GetField(FieldType fieldType) {
|
||||
Field ret = null;
|
||||
if(base.HasField(fieldType)) {
|
||||
|
||||
public new IField GetField(IFieldType fieldType)
|
||||
{
|
||||
IField ret = null;
|
||||
if (base.HasField(fieldType))
|
||||
{
|
||||
ret = base.GetField(fieldType);
|
||||
} else {
|
||||
foreach(IFieldHolder fh in Children) {
|
||||
if(fh.HasField(fieldType)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IFieldHolder fh in Children)
|
||||
{
|
||||
if (fh.HasField(fieldType))
|
||||
{
|
||||
ret = fh.GetField(fieldType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ret == null) {
|
||||
throw new ArgumentException("Field '"+fieldType+"' does not exist in " + GetType());
|
||||
if (ret == null)
|
||||
{
|
||||
throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public new bool HasField(FieldType fieldType) {
|
||||
|
||||
public new bool HasField(IFieldType fieldType)
|
||||
{
|
||||
bool ret = base.HasField(fieldType);
|
||||
if(!ret) {
|
||||
foreach(IFieldHolder fh in Children) {
|
||||
if(fh.HasField(fieldType)) {
|
||||
if (!ret)
|
||||
{
|
||||
foreach (IFieldHolder fh in Children)
|
||||
{
|
||||
if (fh.HasField(fieldType))
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
|
@ -106,16 +129,18 @@ namespace Greenshot.Drawing.Fields {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public new bool HasFieldValue(FieldType fieldType) {
|
||||
Field f = GetField(fieldType);
|
||||
|
||||
public new bool HasFieldValue(IFieldType fieldType)
|
||||
{
|
||||
IField f = GetField(fieldType);
|
||||
return f != null && f.HasValue;
|
||||
}
|
||||
|
||||
public new void SetFieldValue(FieldType fieldType, object value) {
|
||||
Field f = GetField(fieldType);
|
||||
if(f != null) f.Value = value;
|
||||
|
||||
public new void SetFieldValue(IFieldType fieldType, object value)
|
||||
{
|
||||
IField f = GetField(fieldType);
|
||||
if (f != null) f.Value = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@ namespace Greenshot.Drawing.Fields.Binding {
|
|||
/// </summary>
|
||||
public abstract class AbstractBindingConverter<T1,T2> : IBindingConverter
|
||||
{
|
||||
public AbstractBindingConverter() {}
|
||||
|
||||
public object convert(object o) {
|
||||
if(o == null) {
|
||||
return null;
|
||||
|
|
|
@ -29,35 +29,35 @@ namespace Greenshot.Drawing.Fields.Binding {
|
|||
/// behavior (e.g. when binding to a
|
||||
/// </summary>
|
||||
public class BidirectionalBinding {
|
||||
private INotifyPropertyChanged controlObject;
|
||||
private INotifyPropertyChanged fieldObject;
|
||||
private string controlPropertyName;
|
||||
private string fieldPropertyName;
|
||||
private bool updatingControl = false;
|
||||
private bool updatingField = false;
|
||||
private IBindingConverter converter;
|
||||
private IBindingValidator validator;
|
||||
private readonly INotifyPropertyChanged _controlObject;
|
||||
private readonly INotifyPropertyChanged _fieldObject;
|
||||
private readonly string _controlPropertyName;
|
||||
private readonly string _fieldPropertyName;
|
||||
private bool _updatingControl;
|
||||
private bool _updatingField;
|
||||
private IBindingConverter _converter;
|
||||
private readonly IBindingValidator _validator;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not null values are passed on to the other object.
|
||||
/// </summary>
|
||||
protected bool AllowSynchronizeNull = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Bind properties of two objects bidirectionally
|
||||
/// </summary>
|
||||
/// <param name="object1">Object containing 1st property to bind</param>
|
||||
/// <param name="property1">Property of 1st object to bind</param>
|
||||
/// <param name="object2">Object containing 2nd property to bind</param>
|
||||
/// <param name="property2">Property of 2nd object to bind</param>
|
||||
/// <param name="controlObject">Object containing 1st property to bind</param>
|
||||
/// <param name="controlPropertyName">Property of 1st object to bind</param>
|
||||
/// <param name="fieldObject">Object containing 2nd property to bind</param>
|
||||
/// <param name="fieldPropertyName">Property of 2nd object to bind</param>
|
||||
public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName) {
|
||||
this.controlObject = controlObject;
|
||||
this.fieldObject = fieldObject;
|
||||
this.controlPropertyName = controlPropertyName;
|
||||
this.fieldPropertyName = fieldPropertyName;
|
||||
_controlObject = controlObject;
|
||||
_fieldObject = fieldObject;
|
||||
_controlPropertyName = controlPropertyName;
|
||||
_fieldPropertyName = fieldPropertyName;
|
||||
|
||||
this.controlObject.PropertyChanged += ControlPropertyChanged;
|
||||
this.fieldObject.PropertyChanged += FieldPropertyChanged;
|
||||
_controlObject.PropertyChanged += ControlPropertyChanged;
|
||||
_fieldObject.PropertyChanged += FieldPropertyChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -69,7 +69,7 @@ namespace Greenshot.Drawing.Fields.Binding {
|
|||
/// <param name="fieldPropertyName">Property of 2nd object to bind</param>
|
||||
/// <param name="converter">taking care of converting the synchronized value to the correct target format and back</param>
|
||||
public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) {
|
||||
this.converter = converter;
|
||||
_converter = converter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -82,7 +82,7 @@ namespace Greenshot.Drawing.Fields.Binding {
|
|||
/// <param name="fieldPropertyName">Property of 2nd object to bind</param>
|
||||
/// <param name="validator">validator to intercept synchronization if the value does not match certain criteria</param>
|
||||
public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) {
|
||||
this.validator = validator;
|
||||
_validator = validator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -96,46 +96,46 @@ namespace Greenshot.Drawing.Fields.Binding {
|
|||
/// <param name="converter">taking care of converting the synchronized value to the correct target format and back</param>
|
||||
/// <param name="validator">validator to intercept synchronization if the value does not match certain criteria</param>
|
||||
public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter) {
|
||||
this.validator = validator;
|
||||
_validator = validator;
|
||||
}
|
||||
|
||||
public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e) {
|
||||
if (!updatingControl && e.PropertyName.Equals(controlPropertyName)) {
|
||||
updatingField = true;
|
||||
synchronize(controlObject, controlPropertyName, fieldObject, fieldPropertyName);
|
||||
updatingField = false;
|
||||
if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName)) {
|
||||
_updatingField = true;
|
||||
Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName);
|
||||
_updatingField = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e) {
|
||||
if (!updatingField && e.PropertyName.Equals(fieldPropertyName)) {
|
||||
updatingControl = true;
|
||||
synchronize(fieldObject, fieldPropertyName, controlObject, controlPropertyName);
|
||||
updatingControl = false;
|
||||
if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName)) {
|
||||
_updatingControl = true;
|
||||
Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName);
|
||||
_updatingControl = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) {
|
||||
PropertyInfo targetPropertyInfo = resolvePropertyInfo(targetObject, targetProperty);
|
||||
PropertyInfo sourcePropertyInfo = resolvePropertyInfo(sourceObject, sourceProperty);
|
||||
private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) {
|
||||
PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty);
|
||||
PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty);
|
||||
|
||||
if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite) {
|
||||
object bValue = sourcePropertyInfo.GetValue(sourceObject, null);
|
||||
if (converter != null && bValue != null) {
|
||||
bValue = converter.convert(bValue);
|
||||
if (_converter != null && bValue != null) {
|
||||
bValue = _converter.convert(bValue);
|
||||
}
|
||||
try {
|
||||
if (validator == null || validator.validate(bValue)) {
|
||||
if (_validator == null || _validator.validate(bValue)) {
|
||||
targetPropertyInfo.SetValue(targetObject, bValue, null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new MemberAccessException("Could not set property '"+targetProperty+"' to '"+bValue+"' ["+((bValue!=null)?bValue.GetType().Name:"")+"] on "+targetObject+". Probably other type than expected, IBindingCoverter to the rescue.", e);
|
||||
throw new MemberAccessException("Could not set property '"+targetProperty+"' to '"+bValue+"' ["+(bValue!=null?bValue.GetType().Name:"")+"] on "+targetObject+". Probably other type than expected, IBindingCoverter to the rescue.", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private PropertyInfo resolvePropertyInfo(object obj, string property) {
|
||||
private static PropertyInfo ResolvePropertyInfo(object obj, string property) {
|
||||
PropertyInfo ret = null;
|
||||
string[] properties = property.Split(".".ToCharArray());
|
||||
for(int i=0; i<properties.Length; i++) {
|
||||
|
@ -149,8 +149,8 @@ namespace Greenshot.Drawing.Fields.Binding {
|
|||
}
|
||||
|
||||
public IBindingConverter Converter {
|
||||
get { return converter; }
|
||||
set { converter = value; }
|
||||
get { return _converter; }
|
||||
set { _converter = value; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,36 +18,53 @@
|
|||
* 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 GreenshotPlugin.Interfaces.Drawing;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Greenshot.Drawing.Fields {
|
||||
namespace Greenshot.Drawing.Fields
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single field of a drawable element, i.e.
|
||||
/// line thickness of a rectangle.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Field : INotifyPropertyChanged {
|
||||
[field:NonSerialized]
|
||||
public class Field : IField
|
||||
{
|
||||
[field: NonSerialized]
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public object myValue;
|
||||
public object Value {
|
||||
get {
|
||||
return myValue;
|
||||
|
||||
private object _myValue;
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _myValue;
|
||||
}
|
||||
set {
|
||||
if (!Equals(myValue,value)) {
|
||||
myValue = value;
|
||||
if (PropertyChanged!=null) {
|
||||
set
|
||||
{
|
||||
if (!Equals(_myValue, value))
|
||||
{
|
||||
_myValue = value;
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs("Value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public FieldType FieldType;
|
||||
public string Scope;
|
||||
|
||||
public IFieldType FieldType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string Scope
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new Field instance, usually you should be using FieldFactory
|
||||
/// to create Fields.
|
||||
|
@ -59,70 +76,64 @@ namespace Greenshot.Drawing.Fields {
|
|||
/// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value
|
||||
/// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer))
|
||||
/// </param>
|
||||
public Field(FieldType fieldType, Type scope) {
|
||||
public Field(IFieldType fieldType, Type scope)
|
||||
{
|
||||
FieldType = fieldType;
|
||||
Scope = scope.Name;
|
||||
}
|
||||
public Field(FieldType fieldType, string scope) {
|
||||
public Field(IFieldType fieldType, string scope)
|
||||
{
|
||||
FieldType = fieldType;
|
||||
Scope = scope;
|
||||
}
|
||||
public Field(FieldType fieldType) {
|
||||
public Field(IFieldType fieldType)
|
||||
{
|
||||
FieldType = fieldType;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true if this field holds a value other than null.
|
||||
/// </summary>
|
||||
public bool HasValue {
|
||||
get{ return Value != null; }
|
||||
public bool HasValue
|
||||
{
|
||||
get { return Value != null; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a flat clone of this Field. The fields value itself is not cloned.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Field Clone() {
|
||||
public Field Clone()
|
||||
{
|
||||
Field ret = new Field(FieldType, Scope);
|
||||
ret.Value = Value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hashCode = 0;
|
||||
unchecked {
|
||||
unchecked
|
||||
{
|
||||
hashCode += 1000000009 * FieldType.GetHashCode();
|
||||
if (Scope != null)
|
||||
hashCode += 1000000021 * Scope.GetHashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
Field other = obj as Field;
|
||||
if (other == null) {
|
||||
if (other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return FieldType == other.FieldType && Equals(Scope, other.Scope);
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("[Field FieldType={1} Value={0} Scope={2}]", myValue, FieldType, Scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// EventHandler to be used when a field value changes
|
||||
/// </summary>
|
||||
public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs to be used with FieldChangedEventHandler
|
||||
/// </summary>
|
||||
public class FieldChangedEventArgs : EventArgs {
|
||||
public readonly Field Field;
|
||||
public FieldChangedEventArgs(Field field) {
|
||||
Field = field;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,18 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Greenshot.Configuration;
|
||||
using Greenshot.IniFile;
|
||||
using Greenshot.Plugin;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using GreenshotPlugin.Interfaces;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
using log4net;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
using Greenshot.Configuration;
|
||||
using Greenshot.IniFile;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Drawing.Fields {
|
||||
namespace Greenshot.Drawing.Fields
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the current set of properties for the editor.
|
||||
/// When one of EditorProperties' properties is updated, the change will be promoted
|
||||
|
@ -39,38 +42,47 @@ namespace Greenshot.Drawing.Fields {
|
|||
/// Properties that do not apply for ALL selected elements are null (or 0 respectively)
|
||||
/// If the property values of the selected elements differ, the value of the last bound element wins.
|
||||
/// </summary>
|
||||
public class FieldAggregator : AbstractFieldHolder {
|
||||
|
||||
private List<IDrawableContainer> boundContainers;
|
||||
public class FieldAggregator : AbstractFieldHolder
|
||||
{
|
||||
|
||||
private IDrawableContainerList boundContainers;
|
||||
private bool internalUpdateRunning = false;
|
||||
|
||||
enum Status {IDLE, BINDING, UPDATING};
|
||||
|
||||
|
||||
enum Status { IDLE, BINDING, UPDATING };
|
||||
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(FieldAggregator));
|
||||
private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
|
||||
|
||||
public FieldAggregator() {
|
||||
foreach(FieldType fieldType in FieldType.Values) {
|
||||
public FieldAggregator(ISurface parent)
|
||||
{
|
||||
foreach (FieldType fieldType in FieldType.Values)
|
||||
{
|
||||
Field field = new Field(fieldType, GetType());
|
||||
AddField(field);
|
||||
}
|
||||
boundContainers = new List<IDrawableContainer>();
|
||||
boundContainers = new DrawableContainerList();
|
||||
boundContainers.Parent = parent;
|
||||
}
|
||||
|
||||
public override void AddField(Field field) {
|
||||
|
||||
public override void AddField(IField field)
|
||||
{
|
||||
base.AddField(field);
|
||||
field.PropertyChanged += OwnPropertyChanged;
|
||||
}
|
||||
|
||||
public void BindElements(DrawableContainerList dcs) {
|
||||
foreach(DrawableContainer dc in dcs) {
|
||||
|
||||
public void BindElements(IDrawableContainerList dcs)
|
||||
{
|
||||
foreach (DrawableContainer dc in dcs)
|
||||
{
|
||||
BindElement(dc);
|
||||
}
|
||||
}
|
||||
|
||||
public void BindElement(IDrawableContainer dc) {
|
||||
public void BindElement(IDrawableContainer dc)
|
||||
{
|
||||
DrawableContainer container = dc as DrawableContainer;
|
||||
if (container != null && !boundContainers.Contains(container)) {
|
||||
if (container != null && !boundContainers.Contains(container))
|
||||
{
|
||||
boundContainers.Add(container);
|
||||
container.ChildrenChanged += delegate {
|
||||
UpdateFromBoundElements();
|
||||
|
@ -78,101 +90,126 @@ namespace Greenshot.Drawing.Fields {
|
|||
UpdateFromBoundElements();
|
||||
}
|
||||
}
|
||||
|
||||
public void BindAndUpdateElement(IDrawableContainer dc) {
|
||||
|
||||
public void BindAndUpdateElement(IDrawableContainer dc)
|
||||
{
|
||||
UpdateElement(dc);
|
||||
BindElement(dc);
|
||||
}
|
||||
|
||||
public void UpdateElement(IDrawableContainer dc) {
|
||||
|
||||
public void UpdateElement(IDrawableContainer dc)
|
||||
{
|
||||
DrawableContainer container = dc as DrawableContainer;
|
||||
if (container == null) {
|
||||
if (container == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
internalUpdateRunning = true;
|
||||
foreach(Field field in GetFields()) {
|
||||
if (container.HasField(field.FieldType) && field.HasValue) {
|
||||
foreach (Field field in GetFields())
|
||||
{
|
||||
if (container.HasField(field.FieldType) && field.HasValue)
|
||||
{
|
||||
//if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value);
|
||||
container.SetFieldValue(field.FieldType, field.Value);
|
||||
}
|
||||
}
|
||||
internalUpdateRunning = false;
|
||||
}
|
||||
|
||||
public void UnbindElement(IDrawableContainer dc) {
|
||||
if (boundContainers.Contains(dc)) {
|
||||
|
||||
public void UnbindElement(IDrawableContainer dc)
|
||||
{
|
||||
if (boundContainers.Contains(dc))
|
||||
{
|
||||
boundContainers.Remove(dc);
|
||||
UpdateFromBoundElements();
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ClearFields();
|
||||
boundContainers.Clear();
|
||||
boundContainers.Clear();
|
||||
UpdateFromBoundElements();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// sets all field values to null, however does not remove fields
|
||||
/// </summary>
|
||||
private void ClearFields() {
|
||||
private void ClearFields()
|
||||
{
|
||||
internalUpdateRunning = true;
|
||||
foreach(Field field in GetFields()) {
|
||||
foreach (Field field in GetFields())
|
||||
{
|
||||
field.Value = null;
|
||||
}
|
||||
internalUpdateRunning = false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates this instance using the respective fields from the bound elements.
|
||||
/// Fields that do not apply to every bound element are set to null, or 0 respectively.
|
||||
/// All other fields will be set to the field value of the least bound element.
|
||||
/// </summary>
|
||||
private void UpdateFromBoundElements() {
|
||||
private void UpdateFromBoundElements()
|
||||
{
|
||||
ClearFields();
|
||||
internalUpdateRunning = true;
|
||||
foreach(Field field in FindCommonFields()) {
|
||||
foreach (Field field in FindCommonFields())
|
||||
{
|
||||
SetFieldValue(field.FieldType, field.Value);
|
||||
}
|
||||
internalUpdateRunning = false;
|
||||
}
|
||||
|
||||
private List<Field> FindCommonFields() {
|
||||
List<Field> returnFields = null;
|
||||
if (boundContainers.Count > 0) {
|
||||
|
||||
private IList<IField> FindCommonFields()
|
||||
{
|
||||
IList<IField> returnFields = null;
|
||||
if (boundContainers.Count > 0)
|
||||
{
|
||||
// take all fields from the least selected container...
|
||||
DrawableContainer leastSelectedContainer = boundContainers[boundContainers.Count - 1] as DrawableContainer;
|
||||
if (leastSelectedContainer != null) {
|
||||
if (leastSelectedContainer != null)
|
||||
{
|
||||
returnFields = leastSelectedContainer.GetFields();
|
||||
for (int i = 0; i < boundContainers.Count - 1; i++) {
|
||||
for (int i = 0; i < boundContainers.Count - 1; i++)
|
||||
{
|
||||
DrawableContainer dc = boundContainers[i] as DrawableContainer;
|
||||
if (dc != null) {
|
||||
List<Field> fieldsToRemove = new List<Field>();
|
||||
foreach (Field f in returnFields) {
|
||||
if (dc != null)
|
||||
{
|
||||
IList<IField> fieldsToRemove = new List<IField>();
|
||||
foreach (IField field in returnFields)
|
||||
{
|
||||
// ... throw out those that do not apply to one of the other containers
|
||||
if (!dc.HasField(f.FieldType)) {
|
||||
fieldsToRemove.Add(f);
|
||||
if (!dc.HasField(field.FieldType))
|
||||
{
|
||||
fieldsToRemove.Add(field);
|
||||
}
|
||||
}
|
||||
foreach (Field f in fieldsToRemove) {
|
||||
returnFields.Remove(f);
|
||||
foreach (IField field in fieldsToRemove)
|
||||
{
|
||||
returnFields.Remove(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (returnFields == null) {
|
||||
returnFields = new List<Field>();
|
||||
if (returnFields == null)
|
||||
{
|
||||
returnFields = new List<IField>();
|
||||
}
|
||||
return returnFields;
|
||||
}
|
||||
|
||||
public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) {
|
||||
Field field = (Field) sender;
|
||||
if (!internalUpdateRunning && field.Value != null) {
|
||||
foreach(DrawableContainer drawableContainer in boundContainers) {
|
||||
if (drawableContainer.HasField(field.FieldType)) {
|
||||
Field drawableContainerField = drawableContainer.GetField(field.FieldType);
|
||||
|
||||
public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea)
|
||||
{
|
||||
IField field = (IField)sender;
|
||||
if (!internalUpdateRunning && field.Value != null)
|
||||
{
|
||||
foreach (DrawableContainer drawableContainer in boundContainers)
|
||||
{
|
||||
if (drawableContainer.HasField(field.FieldType))
|
||||
{
|
||||
IField drawableContainerField = drawableContainer.GetField(field.FieldType);
|
||||
// Notify before change, so we can e.g. invalidate the area
|
||||
drawableContainer.BeforeFieldChange(drawableContainerField, field.Value);
|
||||
|
||||
|
@ -184,5 +221,5 @@ namespace Greenshot.Drawing.Fields {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,38 +18,41 @@
|
|||
* 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 GreenshotPlugin.Interfaces.Drawing;
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Drawing.Fields {
|
||||
namespace Greenshot.Drawing.Fields
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines all FieldTypes + their default value.
|
||||
/// (The additional value is why this is not an enum)
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class FieldType {
|
||||
|
||||
public static readonly FieldType ARROWHEADS = new FieldType("ARROWHEADS");
|
||||
public static readonly FieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS");
|
||||
public static readonly FieldType BRIGHTNESS = new FieldType("BRIGHTNESS");
|
||||
public static readonly FieldType FILL_COLOR = new FieldType("FILL_COLOR");
|
||||
public static readonly FieldType FONT_BOLD = new FieldType("FONT_BOLD");
|
||||
public static readonly FieldType FONT_FAMILY = new FieldType("FONT_FAMILY");
|
||||
public static readonly FieldType FONT_ITALIC = new FieldType("FONT_ITALIC");
|
||||
public static readonly FieldType FONT_SIZE = new FieldType("FONT_SIZE");
|
||||
public static readonly FieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT");
|
||||
public static readonly FieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT");
|
||||
public static readonly FieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR");
|
||||
public static readonly FieldType LINE_COLOR = new FieldType("LINE_COLOR");
|
||||
public static readonly FieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS");
|
||||
public static readonly FieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR");
|
||||
public static readonly FieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE");
|
||||
public static readonly FieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY");
|
||||
public static readonly FieldType SHADOW = new FieldType("SHADOW");
|
||||
public static readonly FieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE");
|
||||
public static readonly FieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT");
|
||||
public static readonly FieldType FLAGS = new FieldType("FLAGS");
|
||||
|
||||
public static FieldType[] Values = new FieldType[]{
|
||||
public class FieldType : IFieldType
|
||||
{
|
||||
|
||||
public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS");
|
||||
public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS");
|
||||
public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS");
|
||||
public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR");
|
||||
public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD");
|
||||
public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY");
|
||||
public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC");
|
||||
public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE");
|
||||
public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT");
|
||||
public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT");
|
||||
public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR");
|
||||
public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR");
|
||||
public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS");
|
||||
public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR");
|
||||
public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE");
|
||||
public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY");
|
||||
public static readonly IFieldType SHADOW = new FieldType("SHADOW");
|
||||
public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE");
|
||||
public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT");
|
||||
public static readonly IFieldType FLAGS = new FieldType("FLAGS");
|
||||
|
||||
public static IFieldType[] Values = new IFieldType[]{
|
||||
ARROWHEADS,
|
||||
BLUR_RADIUS,
|
||||
BRIGHTNESS,
|
||||
|
@ -66,53 +69,55 @@ namespace Greenshot.Drawing.Fields {
|
|||
MAGNIFICATION_FACTOR,
|
||||
PIXEL_SIZE,
|
||||
PREVIEW_QUALITY,
|
||||
SHADOW,
|
||||
SHADOW,
|
||||
PREPARED_FILTER_OBFUSCATE,
|
||||
PREPARED_FILTER_HIGHLIGHT,
|
||||
PREPARED_FILTER_HIGHLIGHT,
|
||||
FLAGS
|
||||
};
|
||||
|
||||
[Flags]
|
||||
public enum Flag {
|
||||
NONE = 0,
|
||||
CONFIRMABLE = 1
|
||||
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
public string Name;
|
||||
private FieldType(string name) {
|
||||
|
||||
private FieldType(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
public override string ToString() {
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hashCode = 0;
|
||||
unchecked {
|
||||
unchecked
|
||||
{
|
||||
if (Name != null)
|
||||
hashCode += 1000000009 * Name.GetHashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
FieldType other = obj as FieldType;
|
||||
if (other == null)
|
||||
{
|
||||
return false;
|
||||
return Equals(Name,other.Name);
|
||||
}
|
||||
return Equals(Name, other.Name);
|
||||
}
|
||||
|
||||
public static bool operator ==(FieldType a, FieldType b) {
|
||||
return Equals(a,b);
|
||||
|
||||
public static bool operator ==(FieldType a, FieldType b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
public static bool operator !=(FieldType a, FieldType b) {
|
||||
return !Equals(a,b);
|
||||
|
||||
public static bool operator !=(FieldType a, FieldType b)
|
||||
{
|
||||
return !Equals(a, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
@ -52,7 +65,7 @@ namespace Greenshot.Drawing {
|
|||
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
|
||||
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
|
||||
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
|
||||
bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
|
||||
bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
|
||||
if (lineVisible) {
|
||||
graphics.SmoothingMode = SmoothingMode.HighSpeed;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
|
@ -69,7 +82,7 @@ namespace Greenshot.Drawing {
|
|||
Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height);
|
||||
graphics.DrawRectangle(shadowPen, shadowRect);
|
||||
currentStep++;
|
||||
alpha = alpha - (basealpha / steps);
|
||||
alpha = alpha - basealpha / steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
remove{ propertyChanged -= value; }
|
||||
}
|
||||
|
||||
private bool invert = false;
|
||||
private bool invert;
|
||||
public bool Invert {
|
||||
get {
|
||||
return invert;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* 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;
|
||||
using System.Drawing;
|
||||
using Greenshot.Drawing.Fields;
|
||||
|
@ -25,13 +26,10 @@ using Greenshot.Plugin.Drawing;
|
|||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using System.Drawing.Drawing2D;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Drawing.Filters {
|
||||
[Serializable()]
|
||||
public class BlurFilter : AbstractFilter {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(BlurFilter));
|
||||
|
||||
public double previewQuality;
|
||||
public double PreviewQuality {
|
||||
get { return previewQuality; }
|
||||
|
@ -43,7 +41,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d);
|
||||
}
|
||||
|
||||
public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
|
||||
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
|
||||
int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS);
|
||||
Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||
if (applyRect.Width == 0 || applyRect.Height == 0) {
|
||||
|
@ -54,7 +52,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
graphics.SetClip(applyRect);
|
||||
graphics.ExcludeClip(rect);
|
||||
}
|
||||
if (GDIplus.isBlurPossible(blurRadius)) {
|
||||
if (GDIplus.IsBlurPossible(blurRadius)) {
|
||||
GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false);
|
||||
} else {
|
||||
using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) {
|
||||
|
@ -63,7 +61,6 @@ namespace Greenshot.Drawing.Filters {
|
|||
}
|
||||
}
|
||||
graphics.Restore(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
|
||||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing.Filters {
|
||||
namespace Greenshot.Drawing.Filters
|
||||
{
|
||||
public interface IFilter : INotifyPropertyChanged, IFieldHolder {
|
||||
DrawableContainer Parent {get; set; }
|
||||
void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode);
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
int halfHeight = rect.Height / 2;
|
||||
int newWidth = rect.Width / magnificationFactor;
|
||||
int newHeight = rect.Height / magnificationFactor;
|
||||
Rectangle source = new Rectangle(rect.X + halfWidth - (newWidth / 2), rect.Y + halfHeight - (newHeight / 2), newWidth, newHeight);
|
||||
Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight);
|
||||
graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel);
|
||||
graphics.Restore(state);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Greenshot.Drawing.Filters {
|
|||
|
||||
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) {
|
||||
int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE);
|
||||
Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||
ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert);
|
||||
if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) {
|
||||
// Nothing to do
|
||||
return;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Helpers;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using log4net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
@ -35,21 +34,19 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
[Serializable]
|
||||
public class FreehandContainer : DrawableContainer {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(FreehandContainer));
|
||||
private static readonly float [] POINT_OFFSET = new float[]{0.5f, 0.25f, 0.75f};
|
||||
|
||||
[NonSerialized]
|
||||
private GraphicsPath freehandPath = new GraphicsPath();
|
||||
private Rectangle myBounds = Rectangle.Empty;
|
||||
private Point lastMouse = Point.Empty;
|
||||
private List<Point> capturePoints = new List<Point>();
|
||||
private bool isRecalculated = false;
|
||||
private readonly List<Point> capturePoints = new List<Point>();
|
||||
private bool isRecalculated;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public FreehandContainer(Surface parent) : base(parent) {
|
||||
Init();
|
||||
Width = parent.Width;
|
||||
Height = parent.Height;
|
||||
Top = 0;
|
||||
|
@ -61,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();
|
||||
|
||||
|
@ -80,11 +67,7 @@ namespace Greenshot.Drawing {
|
|||
RecalculatePath();
|
||||
}
|
||||
|
||||
[OnDeserialized]
|
||||
private void OnDeserialized(StreamingContext context) {
|
||||
InitGrippers();
|
||||
DoLayout();
|
||||
Init();
|
||||
protected override void OnDeserialized(StreamingContext context) {
|
||||
RecalculatePath();
|
||||
}
|
||||
|
||||
|
@ -119,7 +102,7 @@ namespace Greenshot.Drawing {
|
|||
public override bool HandleMouseMove(int mouseX, int mouseY) {
|
||||
Point previousPoint = capturePoints[capturePoints.Count-1];
|
||||
|
||||
if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= (2*EditorConfig.FreehandSensitivity)) {
|
||||
if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2*EditorConfig.FreehandSensitivity) {
|
||||
capturePoints.Add(new Point(mouseX, mouseY));
|
||||
}
|
||||
if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) {
|
||||
|
@ -232,7 +215,7 @@ namespace Greenshot.Drawing {
|
|||
if (!myBounds.IsEmpty) {
|
||||
int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS));
|
||||
int safetymargin = 10;
|
||||
return new Rectangle((myBounds.Left + Left) - (safetymargin+lineThickness), (myBounds.Top + Top) - (safetymargin+lineThickness), myBounds.Width + (2*(lineThickness+safetymargin)), myBounds.Height + (2*(lineThickness+safetymargin)));
|
||||
return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin));
|
||||
}
|
||||
return new Rectangle(0, 0, _parent.Width, _parent.Height);
|
||||
}
|
||||
|
@ -258,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) {
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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 GitHub https://github.com/greenshot/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.Windows.Forms;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
/// <summary>
|
||||
/// Grippers are the dragable edges of our containers
|
||||
/// </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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,11 +19,11 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Drawing.Filters;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
/// <summary>
|
||||
|
@ -43,8 +43,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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
@ -31,11 +32,23 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
[Serializable]
|
||||
public class IconContainer : DrawableContainer, IIconContainer {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(IconContainer));
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(IconContainer));
|
||||
|
||||
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) {
|
||||
|
|
|
@ -27,6 +27,8 @@ using GreenshotPlugin.Core;
|
|||
using System.Drawing.Drawing2D;
|
||||
using Greenshot.Core;
|
||||
using log4net;
|
||||
using System.Runtime.Serialization;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
/// <summary>
|
||||
|
@ -34,7 +36,7 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
[Serializable]
|
||||
public class ImageContainer : DrawableContainer, IImageContainer {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(ImageContainer));
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(ImageContainer));
|
||||
|
||||
private Image image;
|
||||
|
||||
|
@ -58,6 +60,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() {
|
||||
|
|
|
@ -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) {
|
||||
|
@ -86,7 +82,7 @@ namespace Greenshot.Drawing {
|
|||
Top + currentStep + Height);
|
||||
|
||||
currentStep++;
|
||||
alpha = alpha - (basealpha / steps);
|
||||
alpha = alpha - basealpha / steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,8 +109,6 @@ namespace Greenshot.Drawing {
|
|||
|
||||
protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() {
|
||||
return ScaleHelper.LineAngleRoundBehavior.Instance;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ using System;
|
|||
using System.Runtime.Serialization;
|
||||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Drawing.Filters;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
/// <summary>
|
||||
|
@ -37,15 +38,16 @@ namespace Greenshot.Drawing {
|
|||
base.InitializeFields();
|
||||
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) {
|
||||
|
|
38
Greenshot/Drawing/Positions.cs
Normal file
38
Greenshot/Drawing/Positions.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Position
|
||||
/// </summary>
|
||||
public enum Positions : int
|
||||
{
|
||||
TopLeft = 0,
|
||||
TopCenter = 1,
|
||||
TopRight = 2,
|
||||
MiddleRight = 3,
|
||||
BottomRight = 4,
|
||||
BottomCenter = 5,
|
||||
BottomLeft = 6,
|
||||
MiddleLeft = 7
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
@ -69,7 +86,7 @@ namespace Greenshot.Drawing {
|
|||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.None;
|
||||
|
||||
bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
|
||||
bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
|
||||
if (shadow && (lineVisible || Colors.IsVisible(fillColor))) {
|
||||
//draw shadow first
|
||||
int basealpha = 100;
|
||||
|
@ -86,7 +103,7 @@ namespace Greenshot.Drawing {
|
|||
rect.Height);
|
||||
graphics.DrawRectangle(shadowPen, shadowRect);
|
||||
currentStep++;
|
||||
alpha = alpha - (basealpha / steps);
|
||||
alpha = alpha - basealpha / steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,13 +35,13 @@ namespace Greenshot.Drawing {
|
|||
|
||||
public static GraphicsPath Create2(int x, int y, int width, int height, int radius) {
|
||||
GraphicsPath gp = new GraphicsPath();
|
||||
gp.AddLine(x + radius, y, x + width - (radius * 2), y); // Line
|
||||
gp.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90); // Corner
|
||||
gp.AddLine(x + width, y + radius, x + width, y + height - (radius * 2)); // Line
|
||||
gp.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90); // Corner
|
||||
gp.AddLine(x + width - (radius * 2), y + height, x + radius, y + height); // Line
|
||||
gp.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90); // Corner
|
||||
gp.AddLine(x, y + height - (radius * 2), x, y + radius); // Line
|
||||
gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line
|
||||
gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner
|
||||
gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line
|
||||
gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner
|
||||
gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line
|
||||
gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner
|
||||
gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line
|
||||
gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner
|
||||
gp.CloseFigure();
|
||||
|
||||
|
|
|
@ -21,17 +21,15 @@
|
|||
|
||||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Helpers;
|
||||
using Greenshot.Plugin;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
namespace Greenshot.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of SpeechbubbleContainer.
|
||||
/// </summary>
|
||||
|
@ -50,8 +48,8 @@ namespace Greenshot.Drawing {
|
|||
/// <param name="context"></param>
|
||||
[OnSerializing]
|
||||
private void SetValuesOnSerializing(StreamingContext context) {
|
||||
if (TargetGripper != null) {
|
||||
_storedTargetGripperLocation = TargetGripper.Location;
|
||||
if (TargetAdorner != null) {
|
||||
_storedTargetGripperLocation = TargetAdorner.Location;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,9 +57,9 @@ namespace Greenshot.Drawing {
|
|||
/// Restore the target gripper
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
[OnDeserialized]
|
||||
private void SetValuesOnDeserialized(StreamingContext context) {
|
||||
InitTargetGripper(Color.Green, _storedTargetGripperLocation);
|
||||
protected override void OnDeserialized(StreamingContext context)
|
||||
{
|
||||
InitAdorner(Color.Green, _storedTargetGripperLocation);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -90,9 +88,9 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <returns>true if the surface doesn't need to handle the event</returns>
|
||||
public override bool HandleMouseDown(int mouseX, int mouseY) {
|
||||
if (TargetGripper == null) {
|
||||
if (TargetAdorner == null) {
|
||||
_initialGripperPoint = new Point(mouseX, mouseY);
|
||||
InitTargetGripper(Color.Green, new Point(mouseX, mouseY));
|
||||
InitAdorner(Color.Green, new Point(mouseX, mouseY));
|
||||
}
|
||||
return base.HandleMouseDown(mouseX, mouseY);
|
||||
}
|
||||
|
@ -116,9 +114,9 @@ namespace Greenshot.Drawing {
|
|||
Point newGripperLocation = _initialGripperPoint;
|
||||
newGripperLocation.Offset(xOffset, yOffset);
|
||||
|
||||
if (TargetGripper.Location != newGripperLocation) {
|
||||
if (TargetAdorner.Location != newGripperLocation) {
|
||||
Invalidate();
|
||||
TargetGripperMove(newGripperLocation.X, newGripperLocation.Y);
|
||||
TargetAdorner.Location = newGripperLocation;
|
||||
Invalidate();
|
||||
}
|
||||
return returnValue;
|
||||
|
@ -180,7 +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 tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y);
|
||||
int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20;
|
||||
|
||||
// This should fix a problem with the tail being to wide
|
||||
|
@ -192,10 +190,10 @@ 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);
|
||||
int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y);
|
||||
|
||||
using (Matrix tailMatrix = new Matrix()) {
|
||||
tailMatrix.Translate(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2));
|
||||
tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);
|
||||
tailMatrix.Rotate(tailAngle);
|
||||
tail.Transform(tailMatrix);
|
||||
}
|
||||
|
@ -209,7 +207,7 @@ namespace Greenshot.Drawing {
|
|||
/// <param name="graphics"></param>
|
||||
/// <param name="renderMode"></param>
|
||||
public override void Draw(Graphics graphics, RenderMode renderMode) {
|
||||
if (TargetGripper == null) {
|
||||
if (TargetAdorner == null) {
|
||||
return;
|
||||
}
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
@ -223,7 +221,7 @@ namespace Greenshot.Drawing {
|
|||
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
|
||||
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
|
||||
|
||||
bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor));
|
||||
bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor);
|
||||
Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
|
||||
|
||||
if (Selected && renderMode == RenderMode.EDIT) {
|
||||
|
@ -253,7 +251,7 @@ namespace Greenshot.Drawing {
|
|||
graphics.DrawPath(shadowPen, bubbleClone);
|
||||
}
|
||||
currentStep++;
|
||||
alpha = alpha - (basealpha / steps);
|
||||
alpha = alpha - basealpha / steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -87,6 +94,10 @@ namespace Greenshot.Drawing {
|
|||
/// </summary>
|
||||
/// <param name="newParent"></param>
|
||||
protected override void SwitchParent(Surface newParent) {
|
||||
if (newParent == Parent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Parent != null) {
|
||||
((Surface)Parent).RemoveStepLabel(this);
|
||||
}
|
||||
|
@ -118,7 +129,7 @@ namespace Greenshot.Drawing {
|
|||
/// This makes it possible for the label to be placed exactly in the middle of the pointer.
|
||||
/// </summary>
|
||||
public override bool HandleMouseDown(int mouseX, int mouseY) {
|
||||
return base.HandleMouseDown(mouseX - (Width / 2), mouseY - (Height / 2));
|
||||
return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -146,8 +157,8 @@ namespace Greenshot.Drawing {
|
|||
|
||||
public override bool HandleMouseMove(int x, int y) {
|
||||
Invalidate();
|
||||
Left = x - (Width / 2);
|
||||
Top = y - (Height / 2);
|
||||
Left = x - Width / 2;
|
||||
Top = y - Height / 2;
|
||||
Invalidate();
|
||||
return true;
|
||||
}
|
||||
|
@ -167,7 +178,7 @@ namespace Greenshot.Drawing {
|
|||
|
||||
int widthAfter = rect.Width;
|
||||
int heightAfter = rect.Height;
|
||||
float factor = (((float)widthAfter / widthBefore) + ((float)heightAfter / heightBefore)) / 2;
|
||||
float factor = ((float)widthAfter / widthBefore + (float)heightAfter / heightBefore) / 2;
|
||||
|
||||
fontSize *= factor;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,8 +22,8 @@
|
|||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Helpers;
|
||||
using Greenshot.Memento;
|
||||
using Greenshot.Plugin;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
using GreenshotPlugin.Interfaces.Drawing;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
|
@ -72,7 +72,7 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
|
||||
internal void ChangeText(string newText, bool allowUndoable) {
|
||||
if ((text == null && newText != null) || !text.Equals(newText)) {
|
||||
if ((text == null && newText != null) || !string.Equals(text, newText)) {
|
||||
if (makeUndoable && allowUndoable) {
|
||||
makeUndoable = false;
|
||||
_parent.MakeUndoable(new TextChangeMemento(this), false);
|
||||
|
@ -98,9 +98,13 @@ namespace Greenshot.Drawing {
|
|||
AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -123,8 +127,10 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
|
||||
private void Init() {
|
||||
_stringFormat = new StringFormat();
|
||||
_stringFormat.Trimming = StringTrimming.EllipsisWord;
|
||||
_stringFormat = new StringFormat
|
||||
{
|
||||
Trimming = StringTrimming.EllipsisWord
|
||||
};
|
||||
|
||||
CreateTextBox();
|
||||
|
||||
|
@ -178,15 +184,18 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
// Only dispose the font, and re-create it, when a font field has changed.
|
||||
if (e.Field.FieldType.Name.StartsWith("FONT")) {
|
||||
_font.Dispose();
|
||||
_font = null;
|
||||
if (_font != null)
|
||||
{
|
||||
_font.Dispose();
|
||||
_font = null;
|
||||
}
|
||||
UpdateFormat();
|
||||
} else {
|
||||
UpdateAlignment();
|
||||
}
|
||||
UpdateTextBoxFormat();
|
||||
|
||||
if (_textBox.Visible) {
|
||||
if (_textBox != null && _textBox.Visible) {
|
||||
_textBox.Invalidate();
|
||||
}
|
||||
}
|
||||
|
@ -196,17 +205,19 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
|
||||
private void CreateTextBox() {
|
||||
_textBox = new TextBox();
|
||||
_textBox = new TextBox
|
||||
{
|
||||
ImeMode = ImeMode.On,
|
||||
Multiline = true,
|
||||
AcceptsTab = true,
|
||||
AcceptsReturn = true,
|
||||
BorderStyle = BorderStyle.None,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
_textBox.ImeMode = ImeMode.On;
|
||||
_textBox.Multiline = true;
|
||||
_textBox.AcceptsTab = true;
|
||||
_textBox.AcceptsReturn = true;
|
||||
_textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged);
|
||||
_textBox.LostFocus += textBox_LostFocus;
|
||||
_textBox.KeyDown += textBox_KeyDown;
|
||||
_textBox.BorderStyle = BorderStyle.None;
|
||||
_textBox.Visible = false;
|
||||
}
|
||||
|
||||
private void ShowTextBox() {
|
||||
|
@ -294,6 +305,7 @@ namespace Greenshot.Drawing {
|
|||
}
|
||||
}
|
||||
}
|
||||
_font?.Dispose();
|
||||
_font = new Font(fam, fontSize, fs, GraphicsUnit.Pixel);
|
||||
_textBox.Font = _font;
|
||||
}
|
||||
|
@ -332,8 +344,8 @@ namespace Greenshot.Drawing {
|
|||
if (lineThickness <= 1) {
|
||||
lineWidth = 0;
|
||||
}
|
||||
_textBox.Width = absRectangle.Width - (2 * lineWidth) + correction;
|
||||
_textBox.Height = absRectangle.Height - (2 * lineWidth) + correction;
|
||||
_textBox.Width = absRectangle.Width - 2 * lineWidth + correction;
|
||||
_textBox.Height = absRectangle.Height - 2 * lineWidth + correction;
|
||||
}
|
||||
|
||||
public override void ApplyBounds(RectangleF newBounds) {
|
||||
|
@ -390,7 +402,7 @@ namespace Greenshot.Drawing {
|
|||
DrawSelectionBorder(graphics, rect);
|
||||
}
|
||||
|
||||
if (text == null || text.Length == 0 ) {
|
||||
if (string.IsNullOrEmpty(text) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -411,11 +423,12 @@ namespace Greenshot.Drawing {
|
|||
/// <param name="drawingRectange"></param>
|
||||
/// <param name="lineThickness"></param>
|
||||
/// <param name="fontColor"></param>
|
||||
/// <param name="drawShadow"></param>
|
||||
/// <param name="stringFormat"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="font"></param>
|
||||
public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, Font font) {
|
||||
int textOffset = (lineThickness > 0) ? (int)Math.Ceiling(lineThickness / 2d) : 0;
|
||||
int textOffset = lineThickness > 0 ? (int)Math.Ceiling(lineThickness / 2d) : 0;
|
||||
// draw shadow before anything else
|
||||
if (drawShadow) {
|
||||
int basealpha = 100;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue