Made the re/undo code from the branch work in this, this is a manual copy as something went horribly wrong with the repository. Before building I first want to check if everything is there.[skip ci]

This commit is contained in:
Robin 2016-05-24 12:48:11 +02:00
commit 45615275cf
35 changed files with 1890 additions and 922 deletions

View file

@ -24,6 +24,7 @@ using System.Runtime.Serialization;
using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Plugin.Drawing;
using GreenshotPlugin.Interfaces.Drawing;
namespace Greenshot.Drawing {
/// <summary>
@ -45,10 +46,14 @@ namespace Greenshot.Drawing {
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();
}

View file

@ -29,6 +29,7 @@ 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;
@ -104,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) {
@ -124,10 +125,10 @@ namespace Greenshot.Drawing
}
[NonSerialized]
private TargetAdorner _targetGripper;
public TargetAdorner TargetGripper {
private TargetAdorner _targetAdorner;
public TargetAdorner TargetAdorner {
get {
return _targetGripper;
return _targetAdorner;
}
}
@ -305,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;
@ -335,9 +339,9 @@ namespace Greenshot.Drawing
/// <summary>
/// Initialize a target gripper
/// </summary>
protected void InitTargetGripper(Color gripperColor, Point location) {
_targetGripper = new TargetAdorner(this, location);
Adorners.Add(_targetGripper);
protected void InitAdorner(Color gripperColor, Point location) {
_targetAdorner = new TargetAdorner(this, location);
Adorners.Add(_targetAdorner);
}
/// <summary>
@ -478,6 +482,19 @@ namespace Greenshot.Drawing
}
protected virtual void SwitchParent(Surface newParent) {
if (newParent == Parent)
{
return;
}
if (_parent != null)
{
// Remove FieldAggregator
FieldAggregator fieldAggregator = _parent.FieldAggregator;
if (fieldAggregator != null)
{
fieldAggregator.UnbindElement(this);
}
}
_parent = newParent;
foreach(IFilter filter in Filters) {
@ -485,24 +502,6 @@ namespace Greenshot.Drawing
}
}
// 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() {
// TODO: This actually doesn't make sense...
// Place the container in a list, and you can't find it :)
return left.GetHashCode() ^ top.GetHashCode() ^ width.GetHashCode() ^ height.GetHashCode() ^ GetFields().GetHashCode();
}
protected void OnPropertyChanged(string propertyName) {
if (_propertyChanged != null) {
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
@ -516,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();
}
@ -531,7 +530,6 @@ namespace Greenshot.Drawing
if (e.Field.FieldType == FieldType.SHADOW) {
accountForShadowChange = true;
}
Invalidate();
}
/// <summary>

View file

@ -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);
}
}
@ -246,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);
}
}
@ -270,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,
@ -280,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;
}
@ -296,7 +312,7 @@ 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)) {
@ -312,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];
@ -331,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;
}
@ -347,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)) {
@ -363,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];
@ -397,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);
@ -437,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);
@ -448,48 +464,36 @@ namespace Greenshot.Drawing {
// Copy
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard));
item.Image = (Image)editorFormResources.GetObject("copyToolStripMenuItem.Image");
item.Image = ((Image)(editorFormResources.GetObject("copyToolStripMenuItem.Image")));
item.Click += delegate {
ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), this);
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this);
};
menu.Items.Add(item);
// Cut
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard));
item.Image = (Image)editorFormResources.GetObject("btnCut.Image");
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);
// Delete
item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement));
item.Image = (Image)editorFormResources.GetObject("removeObjectToolStripMenuItem.Image");
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;
}
}
@ -497,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;
@ -528,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();
@ -541,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
}
}

View file

@ -3,7 +3,7 @@
* 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/
* 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
@ -26,39 +26,48 @@ 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 readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
/// <summary>
/// called when a field's value has changed
/// </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 readonly List<Field> fields = new List<Field>();
private IDictionary<IFieldType, IField> fieldsByType = new Dictionary<IFieldType, IField>();
private IList<IField> fields = new List<IField>();
public AbstractFieldHolder() { }
[OnDeserialized]
private void OnFieldHolderDeserialized(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));
}
};
@ -66,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);
}
}

View file

@ -3,7 +3,7 @@
* 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/
* 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
@ -18,86 +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 {
readonly FieldChangedEventHandler fieldChangedEventHandler;
[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 OnFieldHolderWithChildrenDeserialized(StreamingContext context) {
[OnDeserialized()]
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;
}
@ -105,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;
}
}
}

View file

@ -3,7 +3,7 @@
* 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/
* 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
@ -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);
}
}
}

View file

@ -3,7 +3,7 @@
* 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/
* 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
@ -19,14 +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;
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
@ -38,35 +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 readonly List<IDrawableContainer> boundContainers;
private bool internalUpdateRunning;
public class FieldAggregator : AbstractFieldHolder
{
private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
private IDrawableContainerList boundContainers;
private bool internalUpdateRunning = false;
public FieldAggregator() {
foreach(FieldType fieldType in FieldType.Values) {
enum Status { IDLE, BINDING, UPDATING };
private static readonly ILog LOG = LogManager.GetLogger(typeof(FieldAggregator));
private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
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();
@ -74,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);
@ -180,5 +221,5 @@ namespace Greenshot.Drawing.Fields {
}
}
}
}
}

View file

@ -3,7 +3,7 @@
* 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/
* 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
@ -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);
}
}
}

View file

@ -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);

View file

@ -23,6 +23,7 @@ using System.Runtime.Serialization;
using Greenshot.Drawing.Fields;
using Greenshot.Drawing.Filters;
using GreenshotPlugin.Interfaces.Drawing;
namespace Greenshot.Drawing {
/// <summary>

View file

@ -28,6 +28,7 @@ using System.Drawing.Drawing2D;
using Greenshot.Core;
using log4net;
using System.Runtime.Serialization;
using GreenshotPlugin.Interfaces.Drawing;
namespace Greenshot.Drawing {
/// <summary>

View file

@ -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>

View file

@ -48,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,7 +59,7 @@ namespace Greenshot.Drawing
/// <param name="context"></param>
protected override void OnDeserialized(StreamingContext context)
{
InitTargetGripper(Color.Green, _storedTargetGripperLocation);
InitAdorner(Color.Green, _storedTargetGripperLocation);
}
#endregion
@ -88,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);
}
@ -114,9 +114,9 @@ namespace Greenshot.Drawing
Point newGripperLocation = _initialGripperPoint;
newGripperLocation.Offset(xOffset, yOffset);
if (TargetGripper.Location != newGripperLocation) {
if (TargetAdorner.Location != newGripperLocation) {
Invalidate();
TargetGripper.Location = newGripperLocation;
TargetAdorner.Location = newGripperLocation;
Invalidate();
}
return returnValue;
@ -178,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.Location.X, TargetGripper.Location.Y);
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
@ -190,7 +190,7 @@ 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.Location.X, TargetGripper.Location.Y);
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);
@ -207,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;

View file

@ -94,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);
}

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@ using Greenshot.Drawing.Fields;
using Greenshot.Helpers;
using Greenshot.Memento;
using Greenshot.Plugin.Drawing;
using GreenshotPlugin.Interfaces.Drawing;
using System;
using System.ComponentModel;
using System.Drawing;