diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/Greenshot/Configuration/EditorConfiguration.cs index 3d3240273..52039eac2 100644 --- a/Greenshot/Configuration/EditorConfiguration.cs +++ b/Greenshot/Configuration/EditorConfiguration.cs @@ -26,6 +26,7 @@ using Greenshot.Drawing.Fields; using GreenshotPlugin.UnmanagedHelpers; using Greenshot.IniFile; using Greenshot.Core; +using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Configuration { /// @@ -75,7 +76,8 @@ namespace Greenshot.Configuration { /// FieldType of the field to construct /// /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope - public Field CreateField(Type requestingType, FieldType fieldType, object preferredDefaultValue) { + public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue) + { string requestingTypeName = requestingType.Name; string requestedField = requestingTypeName + "." + fieldType.Name; object fieldValue = preferredDefaultValue; @@ -101,8 +103,9 @@ namespace Greenshot.Configuration { returnField.Value = fieldValue; return returnField; } - - public void UpdateLastFieldValue(Field field) { + + public void UpdateLastFieldValue(IField field) + { string requestedField = field.Scope + "." + field.FieldType.Name; // Check if the configuration exists if (LastUsedFieldValues == null) { @@ -110,9 +113,9 @@ namespace Greenshot.Configuration { } // check if settings for the requesting type exist, if not create! if (LastUsedFieldValues.ContainsKey(requestedField)) { - LastUsedFieldValues[requestedField] = field.myValue; + LastUsedFieldValues[requestedField] = field.Value; } else { - LastUsedFieldValues.Add(requestedField, field.myValue); + LastUsedFieldValues.Add(requestedField, field.Value); } } diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs index e1bf7a78a..96b03d3b5 100644 --- a/Greenshot/Drawing/CropContainer.cs +++ b/Greenshot/Drawing/CropContainer.cs @@ -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 { /// @@ -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(); } diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index f65480b2b..1c42a066d 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -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 Filters { + public IList Filters { get { List ret = new List(); 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 /// /// Initialize a target gripper /// - 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); } /// @@ -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 /// /// The field to be changed /// The new value - 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(); } /// diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index 692295966..597db8f3e 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -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. /// [Serializable] - public class DrawableContainerList : List { + public class DrawableContainerList : List, IDrawableContainerList + { private static readonly ComponentResourceManager editorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); public Guid ParentID { @@ -116,14 +118,11 @@ namespace Greenshot.Drawing { /// /// true means allow the moves to be merged public void MakeBoundsChangeUndoable(bool allowMerge) { - List movingList = new List(); - 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 { /// the rendermode in which the element is to be drawn /// 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 /// 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); } /// /// Indicates whether the given list of elements can be pulled up, @@ -280,7 +296,7 @@ namespace Greenshot.Drawing { /// /// list of elements to pull up /// true if the elements could be pulled up - 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). /// /// list of elements to pull up - 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). /// /// of elements to pull to top - public void PullElementsToTop(DrawableContainerList elements) { + public void PullElementsToTop(IDrawableContainerList elements) { var dcs = ToArray(); for(int i=0; i /// list of elements to push down /// true if the elements could be pushed down - 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). /// /// list of elements to push down - public void PushElementsDown(DrawableContainerList elements) { + public void PushElementsDown(IDrawableContainerList elements) { for(int i=0; i /// of elements to push to bottom - 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 { /// /// /// - 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 containersToDelete = new List(); - 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 containersToDelete = new List(); - 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 } } diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs index 1c4a98037..203f590c3 100644 --- a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -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 +{ /// /// Basic IFieldHolder implementation, providing access to a set of fields /// [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(); + private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); /// /// called when a field's value has changed /// [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 fieldsByType = new Dictionary(); - private readonly List fields = new List(); + private IDictionary fieldsByType = new Dictionary(); + private IList fields = new List(); + + public AbstractFieldHolder() { } [OnDeserialized] - private void OnFieldHolderDeserialized(StreamingContext context) { - fieldsByType = new Dictionary(); + private void OnDeserialized(StreamingContext context) + { + fieldsByType = new Dictionary(); // 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 GetFields() { + + public IList 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); } } diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs index a81308d0e..ae610a5fa 100644 --- a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -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 . */ + +using GreenshotPlugin.Interfaces.Drawing; using System; using System.Collections.Generic; using System.Runtime.Serialization; -namespace Greenshot.Drawing.Fields { +namespace Greenshot.Drawing.Fields +{ /// /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, /// but has a List of children. /// Field values are passed to and from children as well. /// - [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 Children = new List(); - - 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 GetFields() { - List ret = new List(); + + public new IList GetFields() + { + List ret = new List(); 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; } - + } } diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs index 28246a6cc..cee59f0c6 100644 --- a/Greenshot/Drawing/Fields/Field.cs +++ b/Greenshot/Drawing/Fields/Field.cs @@ -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 . */ + +using GreenshotPlugin.Interfaces.Drawing; using System; using System.ComponentModel; -namespace Greenshot.Drawing.Fields { +namespace Greenshot.Drawing.Fields +{ /// /// Represents a single field of a drawable element, i.e. /// line thickness of a rectangle. /// [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; + } + /// /// 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)) /// - 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; } /// /// Returns true if this field holds a value other than null. /// - public bool HasValue { - get{ return Value != null; } + public bool HasValue + { + get { return Value != null; } } - + /// /// Creates a flat clone of this Field. The fields value itself is not cloned. /// /// - 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); - } - } - - - /// - /// EventHandler to be used when a field value changes - /// - public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); - - /// - /// EventArgs to be used with FieldChangedEventHandler - /// - 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); } } } diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs index 476233f73..7c2e7558f 100644 --- a/Greenshot/Drawing/Fields/FieldAggregator.cs +++ b/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -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 . */ +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 +{ /// /// 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. /// - public class FieldAggregator : AbstractFieldHolder { - - private readonly List boundContainers; - private bool internalUpdateRunning; + public class FieldAggregator : AbstractFieldHolder + { - private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); + 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(); + + public FieldAggregator(ISurface parent) + { + foreach (FieldType fieldType in FieldType.Values) + { Field field = new Field(fieldType, GetType()); AddField(field); } - boundContainers = new List(); + 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(); } - + /// /// sets all field values to null, however does not remove fields /// - private void ClearFields() { + private void ClearFields() + { internalUpdateRunning = true; - foreach(Field field in GetFields()) { + foreach (Field field in GetFields()) + { field.Value = null; } internalUpdateRunning = false; } - + /// /// 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. /// - 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 FindCommonFields() { - List returnFields = null; - if (boundContainers.Count > 0) { + + private IList FindCommonFields() + { + IList 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 fieldsToRemove = new List(); - foreach (Field f in returnFields) { + if (dc != null) + { + IList fieldsToRemove = new List(); + 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(); + if (returnFields == null) + { + returnFields = new List(); } 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 { } } - } + } } diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs index 4469f86cf..3090e3e51 100644 --- a/Greenshot/Drawing/Fields/FieldType.cs +++ b/Greenshot/Drawing/Fields/FieldType.cs @@ -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 . */ +using GreenshotPlugin.Interfaces.Drawing; using System; -namespace Greenshot.Drawing.Fields { +namespace Greenshot.Drawing.Fields +{ /// /// Defines all FieldTypes + their default value. /// (The additional value is why this is not an enum) /// [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); } - } - - } diff --git a/Greenshot/Drawing/Filters/IFilter.cs b/Greenshot/Drawing/Filters/IFilter.cs index 5840e9650..f2ff0640c 100644 --- a/Greenshot/Drawing/Filters/IFilter.cs +++ b/Greenshot/Drawing/Filters/IFilter.cs @@ -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); diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs index 5b8b783e2..fc871e4fe 100644 --- a/Greenshot/Drawing/HighlightContainer.cs +++ b/Greenshot/Drawing/HighlightContainer.cs @@ -23,6 +23,7 @@ using System.Runtime.Serialization; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; +using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { /// diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs index ca1742195..0b286fcea 100644 --- a/Greenshot/Drawing/ImageContainer.cs +++ b/Greenshot/Drawing/ImageContainer.cs @@ -28,6 +28,7 @@ using System.Drawing.Drawing2D; using Greenshot.Core; using log4net; using System.Runtime.Serialization; +using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { /// diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs index 032291527..1805f86d2 100644 --- a/Greenshot/Drawing/ObfuscateContainer.cs +++ b/Greenshot/Drawing/ObfuscateContainer.cs @@ -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 { /// diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs index e86c52be5..e3e74e113 100644 --- a/Greenshot/Drawing/SpeechbubbleContainer.cs +++ b/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -48,8 +48,8 @@ namespace Greenshot.Drawing /// [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 /// protected override void OnDeserialized(StreamingContext context) { - InitTargetGripper(Color.Green, _storedTargetGripperLocation); + InitAdorner(Color.Green, _storedTargetGripperLocation); } #endregion @@ -88,9 +88,9 @@ namespace Greenshot.Drawing /// /// true if the surface doesn't need to handle the event 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 /// /// public override void Draw(Graphics graphics, RenderMode renderMode) { - if (TargetGripper == null) { + if (TargetAdorner == null) { return; } graphics.SmoothingMode = SmoothingMode.HighQuality; diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs index 636fd4540..45dce668e 100644 --- a/Greenshot/Drawing/StepLabelContainer.cs +++ b/Greenshot/Drawing/StepLabelContainer.cs @@ -94,6 +94,10 @@ namespace Greenshot.Drawing { /// /// protected override void SwitchParent(Surface newParent) { + if (newParent == Parent) + { + return; + } if (Parent != null) { ((Surface)Parent).RemoveStepLabel(this); } diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 13dec90c0..8b56d16f3 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -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 @@ -30,10 +30,10 @@ using Greenshot.Plugin.Drawing; using Greenshot.Plugin.Drawing.Adorners; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using GreenshotPlugin.Interfaces.Drawing; using log4net; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; @@ -43,14 +43,14 @@ using System.Windows.Forms; namespace Greenshot.Drawing { - /// /// Description of Surface. /// - public class Surface : Control, ISurface { - private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); - public static int Count; - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + public class Surface : Control, ISurface + { + private static ILog LOG = LogManager.GetLogger(typeof(Surface)); + public static int Count = 0; + private static CoreConfiguration conf = IniConfig.GetIniSection(); // Property to identify the Surface ID private Guid _uniqueId = Guid.NewGuid(); @@ -58,11 +58,14 @@ namespace Greenshot.Drawing /// /// The GUID of the surface /// - public Guid ID { - get { + public Guid ID + { + get + { return _uniqueId; } - set { + set + { _uniqueId = value; } } @@ -72,41 +75,53 @@ namespace Greenshot.Drawing /// [NonSerialized] private SurfaceElementEventHandler _movingElementChanged; - public event SurfaceElementEventHandler MovingElementChanged { - add { + public event SurfaceElementEventHandler MovingElementChanged + { + add + { _movingElementChanged += value; } - remove { + remove + { _movingElementChanged -= value; } } [NonSerialized] private SurfaceDrawingModeEventHandler _drawingModeChanged; - public event SurfaceDrawingModeEventHandler DrawingModeChanged { - add { + public event SurfaceDrawingModeEventHandler DrawingModeChanged + { + add + { _drawingModeChanged += value; } - remove { + remove + { _drawingModeChanged -= value; } } [NonSerialized] private SurfaceSizeChangeEventHandler _surfaceSizeChanged; - public event SurfaceSizeChangeEventHandler SurfaceSizeChanged { - add { + public event SurfaceSizeChangeEventHandler SurfaceSizeChanged + { + add + { _surfaceSizeChanged += value; } - remove { + remove + { _surfaceSizeChanged -= value; } } [NonSerialized] private SurfaceMessageEventHandler _surfaceMessage; - public event SurfaceMessageEventHandler SurfaceMessage { - add { + public event SurfaceMessageEventHandler SurfaceMessage + { + add + { _surfaceMessage += value; } - remove { + remove + { _surfaceMessage -= value; } } @@ -171,7 +186,7 @@ namespace Greenshot.Drawing /// all selected elements, do not serialize /// [NonSerialized] - private readonly DrawableContainerList selectedElements; + private readonly IDrawableContainerList selectedElements; /// /// the element we are drawing with, do not serialize @@ -212,10 +227,15 @@ namespace Greenshot.Drawing /// private readonly List _stepLabels = new List(); - public void AddStepLabel(StepLabelContainer stepLabel) { - _stepLabels.Add(stepLabel); + public void AddStepLabel(StepLabelContainer stepLabel) + { + if (!_stepLabels.Contains(stepLabel)) + { + _stepLabels.Add(stepLabel); + } } - public void RemoveStepLabel(StepLabelContainer stepLabel) { + public void RemoveStepLabel(StepLabelContainer stepLabel) + { _stepLabels.Remove(stepLabel); } @@ -224,13 +244,17 @@ namespace Greenshot.Drawing /// /// can be null, if not the counting stops here /// number of steplabels before the supplied container - public int CountStepLabels(IDrawableContainer stopAtContainer) { + public int CountStepLabels(IDrawableContainer stopAtContainer) + { int number = 1; - foreach (var possibleThis in _stepLabels) { - if (possibleThis.Equals(stopAtContainer)) { + foreach (var possibleThis in _stepLabels) + { + if (possibleThis.Equals(stopAtContainer)) + { break; } - if (IsOnSurface(possibleThis)) { + if (IsOnSurface(possibleThis)) + { number++; } } @@ -240,12 +264,12 @@ namespace Greenshot.Drawing /// /// all elements on the surface, needed with serialization /// - private readonly DrawableContainerList _elements; + private readonly IDrawableContainerList _elements; /// /// all elements on the surface, needed with serialization /// - private FieldAggregator _fieldAggregator = new FieldAggregator(); + private FieldAggregator _fieldAggregator; /// /// the cursor container, needed with serialization as we need a direct acces to it. @@ -269,11 +293,14 @@ namespace Greenshot.Drawing /// The image is the actual captured image, needed with serialization /// private Image _image; - public Image Image { - get { + public Image Image + { + get + { return _image; } - set { + set + { _image = value; Size = _image.Size; } @@ -283,11 +310,14 @@ namespace Greenshot.Drawing /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. /// - public FieldAggregator FieldAggregator { - get { + public FieldAggregator FieldAggregator + { + get + { return _fieldAggregator; } - set { + set + { _fieldAggregator = value; } } @@ -295,8 +325,10 @@ namespace Greenshot.Drawing /// /// The cursor container has it's own accessor so we can find and remove this (when needed) /// - public IDrawableContainer CursorContainer { - get { + public IDrawableContainer CursorContainer + { + get + { return _cursorContainer; } } @@ -304,8 +336,10 @@ namespace Greenshot.Drawing /// /// A simple getter to ask if this surface has a cursor /// - public bool HasCursor { - get { + public bool HasCursor + { + get + { return _cursorContainer != null; } } @@ -313,7 +347,8 @@ namespace Greenshot.Drawing /// /// A simple helper method to remove the cursor from the surface /// - public void RemoveCursor() { + public void RemoveCursor() + { RemoveElement(_cursorContainer, true); _cursorContainer = null; } @@ -321,11 +356,14 @@ namespace Greenshot.Drawing /// /// The brush which is used to draw the transparent background /// - public Brush TransparencyBackgroundBrush { - get { + public Brush TransparencyBackgroundBrush + { + get + { return _transparencyBackgroundBrush; } - set { + set + { _transparencyBackgroundBrush = value; } } @@ -333,11 +371,14 @@ namespace Greenshot.Drawing /// /// Are the keys on this surface locked? /// - public bool KeysLocked { - get { + public bool KeysLocked + { + get + { return _keysLocked; } - set { + set + { _keysLocked = value; } } @@ -345,11 +386,14 @@ namespace Greenshot.Drawing /// /// Is this surface modified? This is only true if the surface has not been exported. /// - public bool Modified { - get { + public bool Modified + { + get + { return _modified; } - set { + set + { _modified = value; } } @@ -357,11 +401,14 @@ namespace Greenshot.Drawing /// /// The DrawingMode property specifies the mode for drawing, more or less the element type. /// - public DrawingModes DrawingMode { - get {return _drawingMode;} - set { + public DrawingModes DrawingMode + { + get { return _drawingMode; } + set + { _drawingMode = value; - if (_drawingModeChanged != null) { + if (_drawingModeChanged != null) + { SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs(); eventArgs.DrawingMode = _drawingMode; _drawingModeChanged.Invoke(this, eventArgs); @@ -374,11 +421,14 @@ namespace Greenshot.Drawing /// /// Property for accessing the last save "full" path /// - public string LastSaveFullPath { - get { + public string LastSaveFullPath + { + get + { return _lastSaveFullPath; } - set { + set + { _lastSaveFullPath = value; } } @@ -386,7 +436,8 @@ namespace Greenshot.Drawing /// /// Property for accessing the URL to which the surface was recently uploaded /// - public string UploadURL { + public string UploadURL + { get; set; } @@ -394,11 +445,14 @@ namespace Greenshot.Drawing /// /// Property for accessing the capture details /// - public ICaptureDetails CaptureDetails { - get { + public ICaptureDetails CaptureDetails + { + get + { return _captureDetails; } - set { + set + { _captureDetails = value; } } @@ -406,7 +460,9 @@ namespace Greenshot.Drawing /// /// Base Surface constructor /// - public Surface() : base(){ + public Surface() : base() + { + _fieldAggregator = new FieldAggregator(this); Count++; _elements = new DrawableContainerList(_uniqueId); selectedElements = new DrawableContainerList(_uniqueId); @@ -429,15 +485,17 @@ namespace Greenshot.Drawing DoubleBuffered = true; SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true); } - + /// /// Private method, the current image is disposed the new one will stay. /// /// The new image /// true if the old image needs to be disposed, when using undo this should not be true!! - private void SetImage(Image newImage, bool dispose) { + private void SetImage(Image newImage, bool dispose) + { // Dispose - if (_image != null && dispose) { + if (_image != null && dispose) + { _image.Dispose(); } @@ -452,7 +510,8 @@ namespace Greenshot.Drawing /// Surface constructor with an image /// /// - public Surface(Image newImage) : this() { + public Surface(Image newImage) : this() + { LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat); SetImage(newImage, true); } @@ -461,13 +520,16 @@ namespace Greenshot.Drawing /// Surface contructor with a capture /// /// - public Surface(ICapture capture) : this(capture.Image) { + public Surface(ICapture capture) : this(capture.Image) + { // check if cursor is captured, and visible - if (capture.Cursor != null && capture.CursorVisible) { + if (capture.Cursor != null && capture.CursorVisible) + { Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); // check if cursor is on the capture, otherwise we leave it out. - if (cursorRect.IntersectsWith(captureRect)) { + if (cursorRect.IntersectsWith(captureRect)) + { _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); SelectElement(_cursorContainer); } @@ -478,34 +540,43 @@ namespace Greenshot.Drawing _captureDetails = capture.CaptureDetails; } - protected override void Dispose(bool disposing) { - if (disposing) { + protected override void Dispose(bool disposing) + { + if (disposing) + { Count--; LOG.Debug("Disposing surface!"); - if (_buffer != null) { + if (_buffer != null) + { _buffer.Dispose(); _buffer = null; } - if (_transparencyBackgroundBrush != null) { + if (_transparencyBackgroundBrush != null) + { _transparencyBackgroundBrush.Dispose(); _transparencyBackgroundBrush = null; } // Cleanup undo/redo stacks - while (_undoStack != null && _undoStack.Count > 0) { + while (_undoStack != null && _undoStack.Count > 0) + { _undoStack.Pop().Dispose(); } - while (_redoStack != null && _redoStack.Count > 0) { + while (_redoStack != null && _redoStack.Count > 0) + { _redoStack.Pop().Dispose(); } - foreach (IDrawableContainer container in _elements) { + foreach (IDrawableContainer container in _elements) + { container.Dispose(); } - if (_undrawnElement != null) { + if (_undrawnElement != null) + { _undrawnElement.Dispose(); _undrawnElement = null; } - if (_cropContainer != null) { + if (_cropContainer != null) + { _cropContainer.Dispose(); _cropContainer = null; } @@ -516,32 +587,38 @@ namespace Greenshot.Drawing /// /// Undo the last action /// - public void Undo() { - if (_undoStack.Count > 0) { + public void Undo() + { + if (_undoStack.Count > 0) + { _inUndoRedo = true; IMemento top = _undoStack.Pop(); _redoStack.Push(top.Restore()); _inUndoRedo = false; } - } + } /// /// Undo an undo (=redo) /// - public void Redo() { - if (_redoStack.Count > 0) { + public void Redo() + { + if (_redoStack.Count > 0) + { _inUndoRedo = true; IMemento top = _redoStack.Pop(); _undoStack.Push(top.Restore()); _inUndoRedo = false; } } - + /// /// Returns if the surface can do a undo /// - public bool CanUndo { - get { + public bool CanUndo + { + get + { return _undoStack.Count > 0; } } @@ -549,8 +626,10 @@ namespace Greenshot.Drawing /// /// Returns if the surface can do a redo /// - public bool CanRedo { - get { + public bool CanRedo + { + get + { return _redoStack.Count > 0; } } @@ -558,11 +637,10 @@ namespace Greenshot.Drawing /// /// Get the language key for the undo action /// - public LangKey UndoActionLanguageKey { - get { - if (CanUndo) { - return _undoStack.Peek().ActionLanguageKey; - } + public LangKey UndoActionLanguageKey + { + get + { return LangKey.none; } } @@ -570,11 +648,10 @@ namespace Greenshot.Drawing /// /// Get the language key for redo action /// - public LangKey RedoActionLanguageKey { - get { - if (CanRedo) { - return _redoStack.Peek().ActionLanguageKey; - } + public LangKey RedoActionLanguageKey + { + get + { return LangKey.none; } } @@ -584,19 +661,25 @@ namespace Greenshot.Drawing /// /// The memento implementing the undo /// Allow changes to be merged - public void MakeUndoable(IMemento memento, bool allowMerge) { - if (_inUndoRedo) { + public void MakeUndoable(IMemento memento, bool allowMerge) + { + if (_inUndoRedo) + { throw new InvalidOperationException("Invoking do within an undo/redo action."); } - if (memento != null) { + if (memento != null) + { bool allowPush = true; - if (_undoStack.Count > 0 && allowMerge) { + if (_undoStack.Count > 0 && allowMerge) + { // Check if merge is possible allowPush = !_undoStack.Peek().Merge(memento); } - if (allowPush) { + if (allowPush) + { // Clear the redo-stack and dispose - while(_redoStack.Count > 0) { + while (_redoStack.Count > 0) + { _redoStack.Pop().Dispose(); } _undoStack.Push(memento); @@ -610,14 +693,18 @@ namespace Greenshot.Drawing /// /// /// - public long SaveElementsToStream(Stream streamWrite) { + public long SaveElementsToStream(Stream streamWrite) + { long bytesWritten = 0; - try { + try + { long lengtBefore = streamWrite.Length; BinaryFormatter binaryWrite = new BinaryFormatter(); binaryWrite.Serialize(streamWrite, _elements); bytesWritten = streamWrite.Length - lengtBefore; - } catch (Exception e) { + } + catch (Exception e) + { LOG.Error("Error serializing elements to stream.", e); } return bytesWritten; @@ -627,20 +714,24 @@ namespace Greenshot.Drawing /// This loads elements from a stream, among others this is used to load a surface. /// /// - public void LoadElementsFromStream(Stream streamRead) { - try { + public void LoadElementsFromStream(Stream streamRead) + { + try + { BinaryFormatter binaryRead = new BinaryFormatter(); - DrawableContainerList loadedElements = (DrawableContainerList) binaryRead.Deserialize(streamRead); + IDrawableContainerList loadedElements = (IDrawableContainerList)binaryRead.Deserialize(streamRead); loadedElements.Parent = this; // Make sure the steplabels are sorted accoring to their number - _stepLabels.Sort(delegate(StepLabelContainer p1, StepLabelContainer p2) { + _stepLabels.Sort(delegate (StepLabelContainer p1, StepLabelContainer p2) { return p1.Number.CompareTo(p2.Number); }); DeselectAllElements(); AddElements(loadedElements); SelectElements(loadedElements); FieldAggregator.BindElements(loadedElements); - } catch (Exception e) { + } + catch (Exception e) + { LOG.Error("Error serializing elements from stream.", e); } } @@ -650,11 +741,14 @@ namespace Greenshot.Drawing /// But here an element is created which is not yet draw, thus "undrawnElement". /// The element is than used while drawing on the surface. /// - private void CreateUndrawnElement() { - if(_undrawnElement != null) { + private void CreateUndrawnElement() + { + if (_undrawnElement != null) + { FieldAggregator.UnbindElement(_undrawnElement); } - switch (DrawingMode) { + switch (DrawingMode) + { case DrawingModes.Rect: _undrawnElement = new RectangleContainer(this); break; @@ -696,13 +790,15 @@ namespace Greenshot.Drawing _undrawnElement = null; break; } - if (_undrawnElement != null) { + if (_undrawnElement != null) + { FieldAggregator.BindElement(_undrawnElement); } } #region Plugin interface implementations - public IImageContainer AddImageContainer(Image image, int x, int y) { + public IImageContainer AddImageContainer(Image image, int x, int y) + { ImageContainer bitmapContainer = new ImageContainer(this); bitmapContainer.Image = image; bitmapContainer.Left = x; @@ -711,7 +807,8 @@ namespace Greenshot.Drawing return bitmapContainer; } - public IImageContainer AddImageContainer(string filename, int x, int y) { + public IImageContainer AddImageContainer(string filename, int x, int y) + { ImageContainer bitmapContainer = new ImageContainer(this); bitmapContainer.Load(filename); bitmapContainer.Left = x; @@ -719,7 +816,8 @@ namespace Greenshot.Drawing AddElement(bitmapContainer); return bitmapContainer; } - public IIconContainer AddIconContainer(Icon icon, int x, int y) { + public IIconContainer AddIconContainer(Icon icon, int x, int y) + { IconContainer iconContainer = new IconContainer(this); iconContainer.Icon = icon; iconContainer.Left = x; @@ -727,7 +825,8 @@ namespace Greenshot.Drawing AddElement(iconContainer); return iconContainer; } - public IIconContainer AddIconContainer(string filename, int x, int y) { + public IIconContainer AddIconContainer(string filename, int x, int y) + { IconContainer iconContainer = new IconContainer(this); iconContainer.Load(filename); iconContainer.Left = x; @@ -735,7 +834,8 @@ namespace Greenshot.Drawing AddElement(iconContainer); return iconContainer; } - public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) { + public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) + { CursorContainer cursorContainer = new CursorContainer(this); cursorContainer.Cursor = cursor; cursorContainer.Left = x; @@ -743,7 +843,8 @@ namespace Greenshot.Drawing AddElement(cursorContainer); return cursorContainer; } - public ICursorContainer AddCursorContainer(string filename, int x, int y) { + public ICursorContainer AddCursorContainer(string filename, int x, int y) + { CursorContainer cursorContainer = new CursorContainer(this); cursorContainer.Load(filename); cursorContainer.Left = x; @@ -752,7 +853,8 @@ namespace Greenshot.Drawing return cursorContainer; } - public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) { + public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) + { TextContainer textContainer = new TextContainer(this); textContainer.Text = text; textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); @@ -776,19 +878,28 @@ namespace Greenshot.Drawing #region DragDrop - private void OnDragEnter(object sender, DragEventArgs e) { - if(LOG.IsDebugEnabled) { + private void OnDragEnter(object sender, DragEventArgs e) + { + if (LOG.IsDebugEnabled) + { LOG.Debug("DragEnter got following formats: "); - foreach(string format in ClipboardHelper.GetFormats(e.Data)) { + foreach (string format in ClipboardHelper.GetFormats(e.Data)) + { LOG.Debug(format); } } - if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) { - e.Effect=DragDropEffects.None; - } else { - if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) { + if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) + { + e.Effect = DragDropEffects.None; + } + else + { + if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) + { e.Effect = DragDropEffects.Copy; - } else { + } + else + { e.Effect = DragDropEffects.None; } } @@ -799,14 +910,19 @@ namespace Greenshot.Drawing /// /// /// - private void OnDragDrop(object sender, DragEventArgs e) { + private void OnDragDrop(object sender, DragEventArgs e) + { Point mouse = PointToClient(new Point(e.X, e.Y)); - if (e.Data.GetDataPresent("Text")) { + if (e.Data.GetDataPresent("Text")) + { string possibleUrl = ClipboardHelper.GetText(e.Data); // Test if it's an url and try to download the image so we have it in the original form - if (possibleUrl != null && possibleUrl.StartsWith("http")) { - using (Image image = NetworkHelper.DownloadImage(possibleUrl)) { - if (image != null) { + if (possibleUrl != null && possibleUrl.StartsWith("http")) + { + using (Image image = NetworkHelper.DownloadImage(possibleUrl)) + { + if (image != null) + { AddImageContainer(image, mouse.X, mouse.Y); return; } @@ -814,25 +930,29 @@ namespace Greenshot.Drawing } } - foreach (Image image in ClipboardHelper.GetImages(e.Data)) { + foreach (Image image in ClipboardHelper.GetImages(e.Data)) + { AddImageContainer(image, mouse.X, mouse.Y); mouse.Offset(10, 10); image.Dispose(); } } - + #endregion /// /// Auto crop the image /// /// true if cropped - public bool AutoCrop() { + public bool AutoCrop() + { Rectangle cropRectangle; - using (Image tmpImage = GetImageForExport()) { + using (Image tmpImage = GetImageForExport()) + { cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); } - if (!IsCropPossible(ref cropRectangle)) { + if (!IsCropPossible(ref cropRectangle)) + { return false; } DeselectAllElements(); @@ -855,10 +975,12 @@ namespace Greenshot.Drawing /// A simple clear /// /// The color for the background - public void Clear(Color newColor) { + public void Clear(Color newColor) + { //create a blank bitmap the same size as original Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); - if (newBitmap != null) { + if (newBitmap != null) + { // Make undoable MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); SetImage(newBitmap, false); @@ -870,29 +992,37 @@ namespace Greenshot.Drawing /// Apply a bitmap effect to the surface /// /// - public void ApplyBitmapEffect(IEffect effect) { + public void ApplyBitmapEffect(IEffect effect) + { BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait"); backgroundForm.Show(); Application.DoEvents(); - try { + try + { Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); Matrix matrix = new Matrix(); Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); - if (newImage != null) { + if (newImage != null) + { // Make sure the elements move according to the offset the effect made the bitmap move _elements.Transform(matrix); // Make undoable MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); SetImage(newImage, false); Invalidate(); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) { + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { _surfaceSizeChanged(this, null); } - } else { + } + else + { // clean up matrix, as it hasn't been used in the undo stack. matrix.Dispose(); } - } finally { + } + finally + { // Always close the background form backgroundForm.CloseDialog(); } @@ -903,34 +1033,42 @@ namespace Greenshot.Drawing /// /// /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle) { + public bool IsCropPossible(ref Rectangle cropRectangle) + { cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); - if (cropRectangle.Left < 0) { + if (cropRectangle.Left < 0) + { cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); } - if (cropRectangle.Top < 0) { + if (cropRectangle.Top < 0) + { cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); } - if (cropRectangle.Left + cropRectangle.Width > Width) { + if (cropRectangle.Left + cropRectangle.Width > Width) + { cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height); } - if (cropRectangle.Top + cropRectangle.Height > Height) { + if (cropRectangle.Top + cropRectangle.Height > Height) + { cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); } - if (cropRectangle.Height > 0 && cropRectangle.Width > 0) { + if (cropRectangle.Height > 0 && cropRectangle.Width > 0) + { return true; } return false; } - + /// /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area /// /// Who send /// Type of message /// Message itself - public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) { - if (_surfaceMessage != null) { + public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) + { + if (_surfaceMessage != null) + { SurfaceMessageEventArgs eventArgs = new SurfaceMessageEventArgs(); eventArgs.Message = message; eventArgs.MessageType = messageType; @@ -944,14 +1082,19 @@ namespace Greenshot.Drawing /// /// /// - public bool ApplyCrop(Rectangle cropRectangle) { - if (IsCropPossible(ref cropRectangle)) { + public bool ApplyCrop(Rectangle cropRectangle) + { + if (IsCropPossible(ref cropRectangle)) + { Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); Bitmap tmpImage; // Make sure we have information, this this fails - try { + try + { tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - } catch (Exception ex) { + } + catch (Exception ex) + { ex.Data.Add("CropRectangle", cropRectangle); ex.Data.Add("Width", Image.Width); ex.Data.Add("Height", Image.Height); @@ -967,7 +1110,8 @@ namespace Greenshot.Drawing // Do not dispose otherwise we can't undo the image! SetImage(tmpImage, false); _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) { + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) + { _surfaceSizeChanged(this, null); } Invalidate(); @@ -982,17 +1126,19 @@ namespace Greenshot.Drawing /// /// /// - public void UndoBackgroundChange(Image previous, Matrix matrix) { + public void UndoBackgroundChange(Image previous, Matrix matrix) + { SetImage(previous, false); - if (matrix != null) { + if (matrix != null) + { _elements.Transform(matrix); } - if (_surfaceSizeChanged != null) { + if (_surfaceSizeChanged != null) + { _surfaceSizeChanged(this, null); } Invalidate(); } - /// /// Check if an adorner was "hit", and change the cursor if so /// @@ -1000,11 +1146,11 @@ namespace Greenshot.Drawing /// IAdorner private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) { - foreach(IDrawableContainer drawableContainer in selectedElements) + foreach (IDrawableContainer drawableContainer in selectedElements) { - foreach(IAdorner adorner in drawableContainer.Adorners) + foreach (IAdorner adorner in drawableContainer.Adorners) { - + if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) { if (adorner.Cursor != null) @@ -1023,7 +1169,8 @@ namespace Greenshot.Drawing /// /// /// - void SurfaceMouseDown(object sender, MouseEventArgs e) { + void SurfaceMouseDown(object sender, MouseEventArgs e) + { // Handle Adorners var adorner = FindActiveAdorner(e); @@ -1034,21 +1181,27 @@ namespace Greenshot.Drawing } _mouseStart = e.Location; - + // check contextmenu - if (e.Button == MouseButtons.Right) { - DrawableContainerList selectedList = null; - if (selectedElements != null && selectedElements.Count > 0) { + if (e.Button == MouseButtons.Right) + { + IDrawableContainerList selectedList = null; + if (selectedElements != null && selectedElements.Count > 0) + { selectedList = selectedElements; - } else { + } + else + { // Single element IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - if (rightClickedContainer != null) { + if (rightClickedContainer != null) + { selectedList = new DrawableContainerList(ID); selectedList.Add(rightClickedContainer); } } - if (selectedList != null && selectedList.Count > 0) { + if (selectedList != null && selectedList.Count > 0) + { selectedList.ShowContextMenu(e, this); } return; @@ -1057,28 +1210,30 @@ namespace Greenshot.Drawing _mouseDown = true; _isSurfaceMoveMadeUndoable = false; - if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) { + if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) + { RemoveElement(_cropContainer, false); _cropContainer = null; _drawingElement = null; } - if (_drawingElement == null && DrawingMode != DrawingModes.None) { - if (_undrawnElement == null) { + if (_drawingElement == null && DrawingMode != DrawingModes.None) + { + if (_undrawnElement == null) + { DeselectAllElements(); - if (_undrawnElement == null) { + if (_undrawnElement == null) + { CreateUndrawnElement(); } } _drawingElement = _undrawnElement; // if a new element has been drawn, set location and register it - if (_drawingElement != null) { - if (_undrawnElement != null) + if (_drawingElement != null) + { + _drawingElement.Status = _undrawnElement.DefaultEditMode; + if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) { - _drawingElement.Status = _undrawnElement.DefaultEditMode; - } - _drawingElement.PropertyChanged += ElementPropertyChanged; - if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) { _drawingElement.Left = _mouseStart.X; _drawingElement.Top = _mouseStart.Y; } @@ -1086,13 +1241,16 @@ namespace Greenshot.Drawing _drawingElement.Selected = true; } _undrawnElement = null; - } else { + } + else + { // check whether an existing element was clicked // we save mouse down element separately from selectedElements (checked on mouse up), // since it could be moved around before it is actually selected _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - if (_mouseDownElement != null) { + if (_mouseDownElement != null) + { _mouseDownElement.Status = EditStatus.MOVING; } } @@ -1103,7 +1261,8 @@ namespace Greenshot.Drawing /// /// /// - void SurfaceMouseUp(object sender, MouseEventArgs e) { + void SurfaceMouseUp(object sender, MouseEventArgs e) + { // Handle Adorners var adorner = FindActiveAdorner(e); @@ -1116,48 +1275,66 @@ namespace Greenshot.Drawing Point currentMouse = new Point(e.X, e.Y); _elements.Status = EditStatus.IDLE; - if (_mouseDownElement != null) { + if (_mouseDownElement != null) + { _mouseDownElement.Status = EditStatus.IDLE; } _mouseDown = false; _mouseDownElement = null; - if (DrawingMode == DrawingModes.None) { + if (DrawingMode == DrawingModes.None) + { // check whether an existing element was clicked IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y); bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - if (element != null) { + if (element != null) + { element.Invalidate(); bool alreadySelected = selectedElements.Contains(element); - if (shiftModifier) { - if (alreadySelected) { + if (shiftModifier) + { + if (alreadySelected) + { DeselectElement(element); - } else { + } + else + { SelectElement(element); } - } else { - if (!alreadySelected) { + } + else + { + if (!alreadySelected) + { DeselectAllElements(); SelectElement(element); } } - } else if(!shiftModifier) { + } + else if (!shiftModifier) + { DeselectAllElements(); } } - - if (selectedElements.Count > 0) { + + if (selectedElements.Count > 0) + { selectedElements.Invalidate(); selectedElements.Selected = true; } - if (_drawingElement != null) { - if (!_drawingElement.InitContent()) { + if (_drawingElement != null) + { + if (!_drawingElement.InitContent()) + { _elements.Remove(_drawingElement); _drawingElement.Invalidate(); - } else { + } + else + { _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); _drawingElement.Invalidate(); - if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) { + if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) + { _drawingElement.Width = 25; _drawingElement.Height = 25; } @@ -1173,7 +1350,8 @@ namespace Greenshot.Drawing /// /// /// - void SurfaceMouseMove(object sender, MouseEventArgs e) { + void SurfaceMouseMove(object sender, MouseEventArgs e) + { // Handle Adorners var adorner = FindActiveAdorner(e); if (adorner != null) @@ -1184,27 +1362,37 @@ namespace Greenshot.Drawing Point currentMouse = e.Location; - if (DrawingMode != DrawingModes.None) { + if (DrawingMode != DrawingModes.None) + { Cursor = Cursors.Cross; - } else { + } + else + { Cursor = Cursors.Default; } - if (_mouseDown) { - if (_mouseDownElement != null) { // an element is currently dragged + if (_mouseDown) + { + if (_mouseDownElement != null) + { // an element is currently dragged _mouseDownElement.Invalidate(); selectedElements.Invalidate(); // Move the element - if (_mouseDownElement.Selected) { - if (!_isSurfaceMoveMadeUndoable) { + if (_mouseDownElement.Selected) + { + if (!_isSurfaceMoveMadeUndoable) + { // Only allow one undoable per mouse-down/move/up "cycle" _isSurfaceMoveMadeUndoable = true; selectedElements.MakeBoundsChangeUndoable(false); } // dragged element has been selected before -> move all selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } else { - if (!_isSurfaceMoveMadeUndoable) { + } + else + { + if (!_isSurfaceMoveMadeUndoable) + { // Only allow one undoable per mouse-down/move/up "cycle" _isSurfaceMoveMadeUndoable = true; _mouseDownElement.MakeBoundsChangeUndoable(false); @@ -1215,19 +1403,22 @@ namespace Greenshot.Drawing _mouseStart = currentMouse; _mouseDownElement.Invalidate(); _modified = true; - } else if (_drawingElement != null) { + } + else if (_drawingElement != null) + { _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); _modified = true; } } } - + /// /// This event handler is called when the surface is double clicked. /// /// /// - void SurfaceDoubleClick(object sender, MouseEventArgs e) { + void SurfaceDoubleClick(object sender, MouseEventArgs e) + { selectedElements.OnDoubleClick(); selectedElements.Invalidate(); } @@ -1237,11 +1428,13 @@ namespace Greenshot.Drawing /// /// /// - private Image GetImage(RenderMode renderMode) { + private Image GetImage(RenderMode renderMode) + { // Generate a copy of the original image with a dpi equal to the default... Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare); // otherwise we would have a problem drawing the image to the surface... :( - using (Graphics graphics = Graphics.FromImage(clone)) { + using (Graphics graphics = Graphics.FromImage(clone)) + { // Do not set the following, the containers need to decide themselves //graphics.SmoothingMode = SmoothingMode.HighQuality; //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; @@ -1256,7 +1449,8 @@ namespace Greenshot.Drawing /// This returns the image "result" of this surface, with all the elements rendered on it. /// /// - public Image GetImageForExport() { + public Image GetImageForExport() + { return GetImage(RenderMode.EXPORT); } @@ -1265,27 +1459,34 @@ namespace Greenshot.Drawing /// /// /// PaintEventArgs - void SurfacePaint(object sender, PaintEventArgs paintEventArgs) { + void SurfacePaint(object sender, PaintEventArgs paintEventArgs) + { Graphics targetGraphics = paintEventArgs.Graphics; Rectangle clipRectangle = paintEventArgs.ClipRectangle; - if (Rectangle.Empty.Equals(clipRectangle)) { + if (Rectangle.Empty.Equals(clipRectangle)) + { LOG.Debug("Empty cliprectangle??"); return; } - if (_elements.HasIntersectingFilters(clipRectangle)) { - if (_buffer != null) { - if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) { + if (_elements.HasIntersectingFilters(clipRectangle)) + { + if (_buffer != null) + { + if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) + { _buffer.Dispose(); _buffer = null; } } - if (_buffer == null) { + if (_buffer == null) + { _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution); LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); } // Elements might need the bitmap, so we copy the part we need - using (Graphics graphics = Graphics.FromImage(_buffer)) { + using (Graphics graphics = Graphics.FromImage(_buffer)) + { // do not set the following, the containers need to decide this themselves! //graphics.SmoothingMode = SmoothingMode.HighQuality; //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; @@ -1297,7 +1498,9 @@ namespace Greenshot.Drawing _elements.Draw(graphics, _buffer, RenderMode.EDIT, clipRectangle); } targetGraphics.DrawImage(_buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel); - } else { + } + else + { DrawBackground(targetGraphics, clipRectangle); targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); _elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle); @@ -1308,35 +1511,32 @@ namespace Greenshot.Drawing // Draw adorners last foreach (var drawableContainer in selectedElements) { - foreach(var adorner in drawableContainer.Adorners) + foreach (var adorner in drawableContainer.Adorners) { adorner.Paint(paintEventArgs); } } } - private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) { + private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) + { // check if we need to draw the checkerboard - if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) { + if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) + { targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle); - } else { + } + else + { targetGraphics.Clear(BackColor); } } - + /// /// Draw a checkboard when capturing with transparency /// /// PaintEventArgs - protected override void OnPaintBackground(PaintEventArgs e) { - } - - /// - /// Wrapper for makeUndoable flag which was introduced later, will call AddElement with makeundoable set to true - /// - /// the new element - public void AddElement(IDrawableContainer element) { - AddElement(element, true); + protected override void OnPaintBackground(PaintEventArgs e) + { } /// @@ -1344,39 +1544,88 @@ namespace Greenshot.Drawing /// /// the new element /// true if the adding should be undoable - public void AddElement(IDrawableContainer element, bool makeUndoable) { + /// true if invalidate needs to be called + public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true) + { _elements.Add(element); DrawableContainer container = element as DrawableContainer; - if (container != null) { + if (container != null) + { container.FieldChanged += element_FieldChanged; } - element.PropertyChanged += ElementPropertyChanged; - if (element.Status == EditStatus.UNDRAWN) { + element.Parent = this; + if (element.Status == EditStatus.UNDRAWN) + { element.Status = EditStatus.IDLE; } - element.Invalidate(); - if (makeUndoable) { + if (element.Selected) + { + // Use false, as the element is invalidated when invalidate == true anyway + SelectElement(element, false); + } + if (invalidate) + { + element.Invalidate(); + } + if (makeUndoable) + { MakeUndoable(new AddElementMemento(this, element), false); } _modified = true; } + /// + /// Remove the list of elements + /// + /// IDrawableContainerList + /// flag specifying if the remove needs to be undoable + public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) + { + // fix potential issues with iterating a changing list + DrawableContainerList cloned = new DrawableContainerList(); + cloned.AddRange(elementsToRemove); + if (makeUndoable) + { + MakeUndoable(new DeleteElementsMemento(this, cloned), false); + } + SuspendLayout(); + foreach (var drawableContainer in cloned) + { + RemoveElement(drawableContainer, false, false, false); + } + ResumeLayout(); + Invalidate(); + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); + eventArgs.Elements = cloned; + _movingElementChanged(this, eventArgs); + } + } + /// /// Remove an element of the elements list /// /// Element to remove /// flag specifying if the remove needs to be undoable - public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable) { - DeselectElement(elementToRemove); + /// flag specifying if an surface invalidate needs to be called + public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true) + { + DeselectElement(elementToRemove, generateEvents); _elements.Remove(elementToRemove); DrawableContainer element = elementToRemove as DrawableContainer; - if (element != null) { + if (element != null) + { element.FieldChanged -= element_FieldChanged; } - elementToRemove.PropertyChanged -= ElementPropertyChanged; + element.Parent = null; // Do not dispose, the memento should!! element.Dispose(); - Invalidate(); - if (makeUndoable) { + if (invalidate) + { + Invalidate(); + } + if (makeUndoable) + { MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); } _modified = true; @@ -1385,43 +1634,52 @@ namespace Greenshot.Drawing /// /// Add the supplied elements to the surface /// - /// - public void AddElements(DrawableContainerList elementsToAdd) { - foreach(IDrawableContainer element in elementsToAdd) { - AddElement(element, true); + /// DrawableContainerList + /// true if the adding should be undoable + /// true if invalidate needs to be called + public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) + { + // fix potential issues with iterating a changing list + DrawableContainerList cloned = new DrawableContainerList(); + cloned.AddRange(elementsToAdd); + if (makeUndoable) + { + MakeUndoable(new AddElementsMemento(this, cloned), false); } + SuspendLayout(); + foreach (var element in cloned) + { + element.Selected = true; + AddElement(element, false, false); + } + ResumeLayout(); + Invalidate(); } /// /// Returns if this surface has selected elements /// /// - public bool HasSelectedElements { - get { - return selectedElements != null && selectedElements.Count > 0; + public bool HasSelectedElements + { + get + { + return (selectedElements != null && selectedElements.Count > 0); } } /// /// Remove all the selected elements /// - public void RemoveSelectedElements() { - if (HasSelectedElements) { - // As RemoveElement will remove the element from the selectedElements list we need to copy the element - // to another list. - List elementsToRemove = new List(); - foreach (DrawableContainer element in selectedElements) { - // Collect to remove later - elementsToRemove.Add(element); - } - // Remove now - foreach(DrawableContainer element in elementsToRemove) { - RemoveElement(element, true); - } - selectedElements.Clear(); - if (_movingElementChanged != null) { + public void RemoveSelectedElements() + { + if (HasSelectedElements) + { + // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. + RemoveElements(selectedElements); + if (_movingElementChanged != null) + { SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); - eventArgs.Elements = selectedElements; _movingElementChanged(this, eventArgs); } } @@ -1430,9 +1688,11 @@ namespace Greenshot.Drawing /// /// Cut the selected elements from the surface to the clipboard /// - public void CutSelectedElements() { - if (HasSelectedElements) { - ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), selectedElements); + public void CutSelectedElements() + { + if (HasSelectedElements) + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); RemoveSelectedElements(); } } @@ -1440,9 +1700,11 @@ namespace Greenshot.Drawing /// /// Copy the selected elements to the clipboard /// - public void CopySelectedElements() { - if (HasSelectedElements) { - ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), selectedElements); + public void CopySelectedElements() + { + if (HasSelectedElements) + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); } } @@ -1451,24 +1713,23 @@ namespace Greenshot.Drawing /// Called when pressing enter or using the "check" in the editor. /// /// - public void ConfirmSelectedConfirmableElements(bool confirm){ + public void ConfirmSelectedConfirmableElements(bool confirm) + { // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) List selectedDCs = new List(selectedElements); - if (_cropContainer == null) + foreach (IDrawableContainer dc in selectedDCs) { - return; - } - foreach (IDrawableContainer dc in selectedDCs){ - if (dc.Equals(_cropContainer)){ + if (dc.Equals(_cropContainer)) + { DrawingMode = DrawingModes.None; // No undo memento for the cropcontainer itself, only for the effect RemoveElement(_cropContainer, false); - if (confirm) { + if (confirm) + { ApplyCrop(_cropContainer.Bounds); } _cropContainer.Dispose(); _cropContainer = null; - break; } } } @@ -1476,78 +1737,106 @@ namespace Greenshot.Drawing /// /// Paste all the elements that are on the clipboard /// - public void PasteElementFromClipboard() { + public void PasteElementFromClipboard() + { IDataObject clipboard = ClipboardHelper.GetDataObject(); List formats = ClipboardHelper.GetFormats(clipboard); - if (formats == null || formats.Count == 0) { + if (formats == null || formats.Count == 0) + { return; } - if (LOG.IsDebugEnabled) { + if (LOG.IsDebugEnabled) + { LOG.Debug("List of clipboard formats available for pasting:"); - foreach(string format in formats) { + foreach (string format in formats) + { LOG.Debug("\tgot format: " + format); } } - if (formats.Contains(typeof(DrawableContainerList).FullName)) { - DrawableContainerList dcs = (DrawableContainerList)ClipboardHelper.GetFromDataObject(clipboard, typeof(DrawableContainerList)); - if (dcs != null) { + if (formats.Contains(typeof(IDrawableContainerList).FullName)) + { + IDrawableContainerList dcs = (IDrawableContainerList)ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList)); + if (dcs != null) + { // Make element(s) only move 10,10 if the surface is the same Point moveOffset; - bool isSameSurface = dcs.ParentID == _uniqueId; + bool isSameSurface = (dcs.ParentID == _uniqueId); dcs.Parent = this; - if (isSameSurface) { + if (isSameSurface) + { moveOffset = new Point(10, 10); - } else { + } + else + { moveOffset = Point.Empty; } - // Here a fix for bug #1475, first calculate the bounds of the complete DrawableContainerList + // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList Rectangle drawableContainerListBounds = Rectangle.Empty; - foreach (IDrawableContainer element in dcs) { - if (drawableContainerListBounds == Rectangle.Empty) { + foreach (IDrawableContainer element in dcs) + { + if (drawableContainerListBounds == Rectangle.Empty) + { drawableContainerListBounds = element.DrawingBounds; - } else { + } + else + { drawableContainerListBounds = Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); } } // And find a location inside the target surface to paste to bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; - if (!containersCanFit) { + if (!containersCanFit) + { Point containersLocation = drawableContainerListBounds.Location; containersLocation.Offset(moveOffset); - if (!Bounds.Contains(containersLocation)) { + if (!Bounds.Contains(containersLocation)) + { // Easy fix for same surface - if (isSameSurface) { + if (isSameSurface) + { moveOffset = new Point(-10, -10); - } else { + } + else + { // For different surface, which is most likely smaller, we move to "10,10" moveOffset = new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); } } - } else { + } + else + { Rectangle moveContainerListBounds = drawableContainerListBounds; moveContainerListBounds.Offset(moveOffset); // check if the element is inside - if (!Bounds.Contains(moveContainerListBounds)) { + if (!Bounds.Contains(moveContainerListBounds)) + { // Easy fix for same surface - if (isSameSurface) { + if (isSameSurface) + { moveOffset = new Point(-10, -10); - } else { + } + else + { // For different surface, which is most likely smaller int offsetX = 0; int offsetY = 0; - if (drawableContainerListBounds.Right > Bounds.Right) { + if (drawableContainerListBounds.Right > Bounds.Right) + { offsetX = Bounds.Right - drawableContainerListBounds.Right; // Correction for the correction - if (drawableContainerListBounds.Left + offsetX < 0) { + if (drawableContainerListBounds.Left + offsetX < 0) + { offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX); } } - if (drawableContainerListBounds.Bottom > Bounds.Bottom) { + if (drawableContainerListBounds.Bottom > Bounds.Bottom) + { offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom; // Correction for the correction - if (drawableContainerListBounds.Top + offsetY < 0) { + if (drawableContainerListBounds.Top + offsetY < 0) + { offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY); } } @@ -1561,11 +1850,15 @@ namespace Greenshot.Drawing DeselectAllElements(); SelectElements(dcs); } - } else if (ClipboardHelper.ContainsImage(clipboard)) { + } + else if (ClipboardHelper.ContainsImage(clipboard)) + { int x = 10; int y = 10; - foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) { - if (clipboardImage != null) { + foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) + { + if (clipboardImage != null) + { DeselectAllElements(); IImageContainer container = AddImageContainer(clipboardImage as Bitmap, x, y); SelectElement(container); @@ -1574,9 +1867,12 @@ namespace Greenshot.Drawing y += 10; } } - } else if (ClipboardHelper.ContainsText(clipboard)) { + } + else if (ClipboardHelper.ContainsText(clipboard)) + { string text = ClipboardHelper.GetText(clipboard); - if (text != null) { + if (text != null) + { DeselectAllElements(); ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER, FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); @@ -1584,78 +1880,99 @@ namespace Greenshot.Drawing } } } - + /// /// Duplicate all the selecteded elements /// - public void DuplicateSelectedElements() { + public void DuplicateSelectedElements() + { LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); - DrawableContainerList dcs = selectedElements.Clone(); + IDrawableContainerList dcs = selectedElements.Clone(); dcs.Parent = this; - dcs.MoveBy(10,10); + dcs.MoveBy(10, 10); AddElements(dcs); DeselectAllElements(); SelectElements(dcs); } - + /// /// Deselect the specified element /// /// - public void DeselectElement(IDrawableContainer container) { + public void DeselectElement(IDrawableContainer container, bool generateEvents = true) + { container.Selected = false; selectedElements.Remove(container); - container.Invalidate(); FieldAggregator.UnbindElement(container); - if (_movingElementChanged != null) { + if (generateEvents && _movingElementChanged != null) + { SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); eventArgs.Elements = selectedElements; _movingElementChanged(this, eventArgs); } } + /// + /// Deselect the specified elements + /// + /// + public void DeselectElements(IDrawableContainerList elements) + { + if (elements.Count == 0) + { + return; + } + while (elements.Count > 0) + { + var element = elements[0]; + DeselectElement(element, false); + } + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); + eventArgs.Elements = selectedElements; + _movingElementChanged(this, eventArgs); + } + Invalidate(); + } + /// /// Deselect all the selected elements /// - public void DeselectAllElements() { - if (HasSelectedElements) { - while(selectedElements.Count > 0) { - IDrawableContainer element = selectedElements[0]; - element.Selected = false; - selectedElements.Remove(element); - element.Invalidate(); - FieldAggregator.UnbindElement(element); - } - if (_movingElementChanged != null) { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); - eventArgs.Elements = selectedElements; - _movingElementChanged(this, eventArgs); - } - } + public void DeselectAllElements() + { + DeselectElements(selectedElements); } /// /// Select the supplied element /// /// - public void SelectElement(IDrawableContainer container) { - if (!selectedElements.Contains(container)) { + public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) + { + if (!selectedElements.Contains(container)) + { selectedElements.Add(container); container.Selected = true; FieldAggregator.BindElement(container); - if (_movingElementChanged != null) { + if (generateEvents && _movingElementChanged != null) + { SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); eventArgs.Elements = selectedElements; _movingElementChanged(this, eventArgs); } - container.Invalidate(); + if (invalidate) + { + container.Invalidate(); + } } } /// /// Select all elements, this is called when Ctrl+A is pressed /// - public void SelectAllElements() { + public void SelectAllElements() + { SelectElements(_elements); } @@ -1663,10 +1980,21 @@ namespace Greenshot.Drawing /// Select the supplied elements /// /// - public void SelectElements(DrawableContainerList elements) { - foreach(DrawableContainer element in elements) { - SelectElement(element); + public void SelectElements(IDrawableContainerList elements) + { + SuspendLayout(); + foreach (DrawableContainer element in elements) + { + SelectElement(element, false, false); } + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); + eventArgs.Elements = selectedElements; + _movingElementChanged(this, eventArgs); + } + ResumeLayout(); + Invalidate(); } /// @@ -1674,13 +2002,16 @@ namespace Greenshot.Drawing /// /// Keys /// false if no keys were processed - public bool ProcessCmdKey(Keys k) { - if (selectedElements.Count > 0) { + public bool ProcessCmdKey(Keys k) + { + if (selectedElements.Count > 0) + { bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; int px = shiftModifier ? 10 : 1; Point moveBy = Point.Empty; - - switch (k) { + + switch (k) + { case Keys.Left: case Keys.Left | Keys.Shift: moveBy = new Point(-px, 0); @@ -1721,7 +2052,8 @@ namespace Greenshot.Drawing default: return false; } - if (!Point.Empty.Equals(moveBy)) { + if (!Point.Empty.Equals(moveBy)) + { selectedElements.MakeBoundsChangeUndoable(true); selectedElements.MoveBy(moveBy.X, moveBy.Y); } @@ -1733,8 +2065,10 @@ namespace Greenshot.Drawing /// /// Property for accessing the elements on the surface /// - public DrawableContainerList Elements { - get { + public IDrawableContainerList Elements + { + get + { return _elements; } } @@ -1742,60 +2076,64 @@ namespace Greenshot.Drawing /// /// pulls selected elements up one level in hierarchy /// - public void PullElementsUp() { + public void PullElementsUp() + { _elements.PullElementsUp(selectedElements); _elements.Invalidate(); } - + /// /// pushes selected elements up to top in hierarchy /// - public void PullElementsToTop() { + public void PullElementsToTop() + { _elements.PullElementsToTop(selectedElements); _elements.Invalidate(); } - + /// /// pushes selected elements down one level in hierarchy /// - public void PushElementsDown() { + public void PushElementsDown() + { _elements.PushElementsDown(selectedElements); _elements.Invalidate(); } - + /// /// pushes selected elements down to bottom in hierarchy /// - public void PushElementsToBottom() { + public void PushElementsToBottom() + { _elements.PushElementsToBottom(selectedElements); _elements.Invalidate(); } - + /// /// indicates whether the selected elements could be pulled up in hierarchy /// /// true if selected elements could be pulled up, false otherwise - public bool CanPullSelectionUp() { + public bool CanPullSelectionUp() + { return _elements.CanPullUp(selectedElements); } - + /// /// indicates whether the selected elements could be pushed down in hierarchy /// /// true if selected elements could be pushed down, false otherwise - public bool CanPushSelectionDown() { + public bool CanPushSelectionDown() + { return _elements.CanPushDown(selectedElements); } - - public void ElementPropertyChanged(object sender, PropertyChangedEventArgs e) { - //Invalidate(); - } - - public void element_FieldChanged(object sender, FieldChangedEventArgs e) { + + public void element_FieldChanged(object sender, FieldChangedEventArgs e) + { selectedElements.HandleFieldChangedEvent(sender, e); } - public bool IsOnSurface(IDrawableContainer container) { + public bool IsOnSurface(IDrawableContainer container) + { return _elements.Contains(container); } } diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index 1b369ea78..96792de69 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -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; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index e72052944..5f8252549 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -30,8 +30,10 @@ using Greenshot.Help; using Greenshot.Helpers; using Greenshot.IniFile; using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using GreenshotPlugin.Interfaces.Drawing; using GreenshotPlugin.UnmanagedHelpers; using log4net; using System; @@ -56,7 +58,7 @@ namespace Greenshot { private Surface _surface; private GreenshotToolStripButton[] _toolbarButtons; - private static readonly string[] SupportedClipboardFormats = {typeof(string).FullName, "Text", typeof(DrawableContainerList).FullName}; + private static readonly string[] SupportedClipboardFormats = {typeof(string).FullName, "Text", typeof(IDrawableContainerList).FullName}; private bool _originalBoldCheckState; private bool _originalItalicCheckState; @@ -1045,8 +1047,8 @@ namespace Greenshot { textVerticalAlignmentButton.Visible = props.HasFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); shadowButton.Visible = props.HasFieldValue(FieldType.SHADOW); btnConfirm.Visible = btnCancel.Visible = props.HasFieldValue(FieldType.FLAGS) - && ((FieldType.Flag)props.GetFieldValue(FieldType.FLAGS)&FieldType.Flag.CONFIRMABLE) == FieldType.Flag.CONFIRMABLE; - + && ((FieldFlag)props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE; + obfuscateModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); highlightModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } else { @@ -1078,9 +1080,10 @@ namespace Greenshot { FieldAggregator props = _surface.FieldAggregator; // if a confirmable element is selected, we must disable most of the controls // since we demand confirmation or cancel for confirmable element - if (props.HasFieldValue(FieldType.FLAGS) && ((FieldType.Flag)props.GetFieldValue(FieldType.FLAGS) & FieldType.Flag.CONFIRMABLE) == FieldType.Flag.CONFIRMABLE) { + if (props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag)props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE) + { // disable most controls - if(!_controlsDisabledDueToConfirmable) { + if (!_controlsDisabledDueToConfirmable) { ToolStripItemEndisabler.Disable(menuStrip1); ToolStripItemEndisabler.Disable(destinationsToolStrip); ToolStripItemEndisabler.Disable(toolsToolStrip); diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 0fc6043a0..8e743d8b7 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -112,7 +112,6 @@ - @@ -215,13 +214,14 @@ + + - diff --git a/Greenshot/Memento/AddElementMemento.cs b/Greenshot/Memento/AddElementMemento.cs index 98a70214e..c7f21dbde 100644 --- a/Greenshot/Memento/AddElementMemento.cs +++ b/Greenshot/Memento/AddElementMemento.cs @@ -47,12 +47,6 @@ namespace Greenshot.Memento { _surface = null; } - public LangKey ActionLanguageKey { - get { - return LangKey.none; - } - } - public bool Merge(IMemento otherMemento) { return false; } diff --git a/Greenshot/Memento/AddElementsMemento.cs b/Greenshot/Memento/AddElementsMemento.cs new file mode 100644 index 000000000..ce566c3c2 --- /dev/null +++ b/Greenshot/Memento/AddElementsMemento.cs @@ -0,0 +1,77 @@ +/* + * 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 . + */ +using Greenshot.Drawing; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Memento +{ + /// + /// The AddElementMemento makes it possible to undo adding an element + /// + public class AddElementsMemento : IMemento + { + private IDrawableContainerList _containerList; + private Surface _surface; + + public AddElementsMemento(Surface surface, IDrawableContainerList containerList) + { + _surface = surface; + _containerList = containerList; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_containerList != null) + { + _containerList.Dispose(); + } + } + _containerList = null; + _surface = null; + } + + public bool Merge(IMemento otherMemento) + { + return false; + } + + public IMemento Restore() + { + // Store the selected state, as it's overwritten by the RemoveElement + bool selected = _containerList.Selected; + + var oldState = new DeleteElementsMemento(_surface, _containerList); + + _surface.RemoveElements(_containerList, false); + + // After, so everything is gone + _surface.Invalidate(); + return oldState; + } + } +} diff --git a/Greenshot/Memento/ChangeFieldHolderMemento.cs b/Greenshot/Memento/ChangeFieldHolderMemento.cs index 03a04ab5d..7314f097a 100644 --- a/Greenshot/Memento/ChangeFieldHolderMemento.cs +++ b/Greenshot/Memento/ChangeFieldHolderMemento.cs @@ -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,47 +18,54 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -using System; -using Greenshot.Plugin.Drawing; -using Greenshot.Drawing.Fields; -using Greenshot.Configuration; -namespace Greenshot.Memento { +using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Interfaces.Drawing; + +namespace Greenshot.Memento +{ /// /// The ChangeFieldHolderMemento makes it possible to undo-redo an IDrawableContainer move /// - public class ChangeFieldHolderMemento : IMemento { - private IDrawableContainer drawableContainer; - private readonly Field fieldToBeChanged; - private readonly object oldValue; - - public ChangeFieldHolderMemento(IDrawableContainer drawableContainer, Field fieldToBeChanged) { - this.drawableContainer = drawableContainer; - this.fieldToBeChanged = fieldToBeChanged; - oldValue = fieldToBeChanged.Value; + public class ChangeFieldHolderMemento : IMemento + { + private IDrawableContainer _drawableContainer; + private IField _fieldToBeChanged; + private object _oldValue; + + public ChangeFieldHolderMemento(IDrawableContainer drawableContainer, IField fieldToBeChanged) + { + _drawableContainer = drawableContainer; + _fieldToBeChanged = fieldToBeChanged; + _oldValue = fieldToBeChanged.Value; } - public void Dispose() { + public void Dispose() + { Dispose(true); - GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) { - //if (disposing) { } - drawableContainer = null; - } - - public LangKey ActionLanguageKey { - get { - return LangKey.none; + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_drawableContainer != null) + { + _drawableContainer.Dispose(); + } } + _drawableContainer = null; } - public bool Merge(IMemento otherMemento) { + public bool Merge(IMemento otherMemento) + { ChangeFieldHolderMemento other = otherMemento as ChangeFieldHolderMemento; - if (other != null) { - if (other.drawableContainer.Equals(drawableContainer)) { - if (other.fieldToBeChanged.Equals(fieldToBeChanged)) { + if (other != null) + { + if (other._drawableContainer.Equals(_drawableContainer)) + { + if (other._fieldToBeChanged.Equals(_fieldToBeChanged)) + { // Match, do not store anything as the initial state is what we want. return true; } @@ -67,13 +74,14 @@ namespace Greenshot.Memento { return false; } - public IMemento Restore() { + public IMemento Restore() + { // Before - drawableContainer.Invalidate(); - ChangeFieldHolderMemento oldState = new ChangeFieldHolderMemento(drawableContainer, fieldToBeChanged); - fieldToBeChanged.Value = oldValue; + _drawableContainer.Invalidate(); + ChangeFieldHolderMemento oldState = new ChangeFieldHolderMemento(_drawableContainer, _fieldToBeChanged); + _fieldToBeChanged.Value = _oldValue; // After - drawableContainer.Invalidate(); + _drawableContainer.Invalidate(); return oldState; } } diff --git a/Greenshot/Memento/DeleteElementMemento.cs b/Greenshot/Memento/DeleteElementMemento.cs index b715e26a8..dc1d012de 100644 --- a/Greenshot/Memento/DeleteElementMemento.cs +++ b/Greenshot/Memento/DeleteElementMemento.cs @@ -50,13 +50,6 @@ namespace Greenshot.Memento { } } - public LangKey ActionLanguageKey { - get { - //return LangKey.editor_deleteelement; - return LangKey.none; - } - } - public bool Merge(IMemento otherMemento) { return false; } diff --git a/Greenshot/Memento/DeleteElementsMemento.cs b/Greenshot/Memento/DeleteElementsMemento.cs new file mode 100644 index 000000000..d01bc3089 --- /dev/null +++ b/Greenshot/Memento/DeleteElementsMemento.cs @@ -0,0 +1,72 @@ +/* + * 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 . + */ +using Greenshot.Drawing; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Memento +{ + /// + /// The DeleteElementMemento makes it possible to undo deleting an element + /// + public class DeleteElementsMemento : IMemento + { + private IDrawableContainerList _containerList; + private Surface _surface; + + public DeleteElementsMemento(Surface surface, IDrawableContainerList containerList) + { + _surface = surface; + _containerList = containerList; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_containerList != null) + { + _containerList.Dispose(); + } + } + _containerList = null; + _surface = null; + } + + public bool Merge(IMemento otherMemento) + { + return false; + } + + public IMemento Restore() + { + AddElementsMemento oldState = new AddElementsMemento(_surface, _containerList); + _surface.AddElements(_containerList, false); + // After + _surface.Invalidate(); + return oldState; + } + } +} diff --git a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs b/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs index 940fbd4ee..123d260f0 100644 --- a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs @@ -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,61 +18,70 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -using System; +using Greenshot.Drawing; +using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Core; using System.Collections.Generic; using System.Drawing; -using Greenshot.Configuration; -using Greenshot.Plugin.Drawing; -using GreenshotPlugin.Core; - -namespace Greenshot.Memento { +namespace Greenshot.Memento +{ /// /// The DrawableContainerBoundsChangeMemento makes it possible to undo-redo an IDrawableContainer resize & move /// - public class DrawableContainerBoundsChangeMemento : IMemento { - readonly List points = new List(); - readonly List sizes = new List(); - List listOfdrawableContainer; - - private void StoreBounds() { - foreach(IDrawableContainer drawableContainer in listOfdrawableContainer) { + public class DrawableContainerBoundsChangeMemento : IMemento + { + List points = new List(); + List sizes = new List(); + IDrawableContainerList listOfdrawableContainer; + + private void StoreBounds() + { + foreach (IDrawableContainer drawableContainer in listOfdrawableContainer) + { points.Add(drawableContainer.Location); sizes.Add(drawableContainer.Size); } } - public DrawableContainerBoundsChangeMemento(List listOfdrawableContainer) { + public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfdrawableContainer) + { this.listOfdrawableContainer = listOfdrawableContainer; StoreBounds(); } - public DrawableContainerBoundsChangeMemento(IDrawableContainer drawableContainer) { - listOfdrawableContainer = new List(); + public DrawableContainerBoundsChangeMemento(IDrawableContainer drawableContainer) + { + listOfdrawableContainer = new DrawableContainerList(); listOfdrawableContainer.Add(drawableContainer); + listOfdrawableContainer.Parent = drawableContainer.Parent; StoreBounds(); } - public void Dispose() { + public void Dispose() + { Dispose(true); - GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) { - // if (disposing) { } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (listOfdrawableContainer != null) + { + listOfdrawableContainer.Dispose(); + } + } listOfdrawableContainer = null; } - public LangKey ActionLanguageKey { - get { - return LangKey.none; - } - } - - public bool Merge(IMemento otherMemento) { - DrawableContainerBoundsChangeMemento other = otherMemento as DrawableContainerBoundsChangeMemento; - if (other != null) { - if (Objects.CompareLists(listOfdrawableContainer, other.listOfdrawableContainer)) { + public bool Merge(IMemento otherMemento) + { + var other = otherMemento as DrawableContainerBoundsChangeMemento; + if (other != null) + { + if (Objects.CompareLists(listOfdrawableContainer, other.listOfdrawableContainer)) + { // Lists are equal, as we have the state already we can ignore the new memento return true; } @@ -80,9 +89,11 @@ namespace Greenshot.Memento { return false; } - public IMemento Restore() { - DrawableContainerBoundsChangeMemento oldState = new DrawableContainerBoundsChangeMemento(listOfdrawableContainer); - for(int index = 0; index < listOfdrawableContainer.Count; index++) { + public IMemento Restore() + { + var oldState = new DrawableContainerBoundsChangeMemento(listOfdrawableContainer); + for (int index = 0; index < listOfdrawableContainer.Count; index++) + { IDrawableContainer drawableContainer = listOfdrawableContainer[index]; // Before drawableContainer.Invalidate(); diff --git a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs b/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs index 9c8935abc..32f371261 100644 --- a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs +++ b/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs @@ -44,7 +44,6 @@ namespace Greenshot.Memento { public void Dispose() { Dispose(true); - GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { @@ -64,13 +63,6 @@ namespace Greenshot.Memento { public bool Merge(IMemento otherMemento) { return false; } - - public LangKey ActionLanguageKey { - get { - //return LangKey.editor_crop; - return LangKey.none; - } - } public IMemento Restore() { SurfaceBackgroundChangeMemento oldState = new SurfaceBackgroundChangeMemento(_surface, _matrix); diff --git a/Greenshot/Memento/TextChangeMemento.cs b/Greenshot/Memento/TextChangeMemento.cs index 716b9e171..d7b9a8d54 100644 --- a/Greenshot/Memento/TextChangeMemento.cs +++ b/Greenshot/Memento/TextChangeMemento.cs @@ -37,7 +37,6 @@ namespace Greenshot.Memento { public void Dispose() { Dispose(true); - GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { @@ -46,12 +45,6 @@ namespace Greenshot.Memento { } } - public LangKey ActionLanguageKey { - get { - return LangKey.none; - } - } - public bool Merge(IMemento otherMemento) { TextChangeMemento other = otherMemento as TextChangeMemento; if (other != null) { diff --git a/GreenshotPlugin/Core/OperatingSystemExtensions.cs b/GreenshotPlugin/Core/OperatingSystemExtensions.cs index 769547e03..ffe07bc6f 100644 --- a/GreenshotPlugin/Core/OperatingSystemExtensions.cs +++ b/GreenshotPlugin/Core/OperatingSystemExtensions.cs @@ -55,7 +55,7 @@ namespace GreenshotPlugin.Core /// true if we are running on Windows 8 or later public static bool IsWindows8OrLater(this OperatingSystem operatingSystem) { - return (operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 2) || operatingSystem.Version.Major >= 6; + return (operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 2) || operatingSystem.Version.Major > 6; } /// @@ -65,7 +65,7 @@ namespace GreenshotPlugin.Core /// true if we are running on Windows 7 or later public static bool IsWindows7OrLater(this OperatingSystem operatingSystem) { - return (operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 1) || operatingSystem.Version.Major >= 6; + return (operatingSystem.Version.Major == 6 && operatingSystem.Version.Minor >= 1) || operatingSystem.Version.Major > 6; } /// diff --git a/GreenshotPlugin/Core/WindowsHelper.cs b/GreenshotPlugin/Core/WindowsHelper.cs index 855dd79be..1a829b4a5 100644 --- a/GreenshotPlugin/Core/WindowsHelper.cs +++ b/GreenshotPlugin/Core/WindowsHelper.cs @@ -1017,7 +1017,11 @@ namespace GreenshotPlugin.Core { // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) captureRectangle.Inflate(borderSize.Width, borderSize.Height); } else { - captureRectangle.Inflate(-1, -1); + // TODO: Also 8.x? + if (Environment.OSVersion.IsWindows10()) + { + captureRectangle.Inflate(-1, -1); + } if (autoMode) { // check if the capture fits diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 8bc85a253..86922e91e 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -68,6 +68,9 @@ + + + diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index afae80489..02e52cd65 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -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 @@ -25,65 +25,80 @@ using System.Drawing.Imaging; using System.Windows.Forms; using System.ComponentModel; using System.Collections.Generic; +using GreenshotPlugin.Interfaces.Drawing; using Greenshot.Plugin.Drawing.Adorners; -using System.Runtime.Serialization; -namespace Greenshot.Plugin.Drawing { - public enum RenderMode {EDIT, EXPORT}; - public enum EditStatus {UNDRAWN, DRAWING, MOVING, RESIZING, IDLE}; +namespace Greenshot.Plugin.Drawing +{ + public enum RenderMode { EDIT, EXPORT }; + public enum EditStatus { UNDRAWN, DRAWING, MOVING, RESIZING, IDLE }; - public interface IDrawableContainer : INotifyPropertyChanged, IDisposable { - ISurface Parent { - get; - } - bool Selected { + public interface IDrawableContainer : INotifyPropertyChanged, IDisposable + { + ISurface Parent + { get; set; } - - int Left { + bool Selected + { get; set; } - - int Top { + + int Left + { get; set; } - - int Width { + + int Top + { get; set; } - - int Height { + + int Width + { get; set; } - - Point Location { + + int Height + { + get; + set; + } + + Point Location + { get; } - Size Size { - get; - } - - Rectangle Bounds { + Size Size + { get; } - Rectangle DrawingBounds { + Rectangle Bounds + { + get; + } + + Rectangle DrawingBounds + { get; } void ApplyBounds(RectangleF newBounds); - - bool hasFilters { + + bool hasFilters + { get; } - EditStatus Status { + EditStatus Status + { get; set; } @@ -97,7 +112,8 @@ namespace Greenshot.Plugin.Drawing { bool HandleMouseMove(int x, int y); bool InitContent(); void MakeBoundsChangeUndoable(bool allowMerge); - EditStatus DefaultEditMode { + EditStatus DefaultEditMode + { get; } @@ -107,38 +123,91 @@ namespace Greenshot.Plugin.Drawing { IList Adorners { get; } } - public interface ITextContainer: IDrawableContainer { - string Text { + public interface IDrawableContainerList : IList, IDisposable + { + Guid ParentID + { + get; + } + + bool Selected + { + get; + set; + } + + ISurface Parent + { + get; + set; + } + EditStatus Status + { + get; + set; + } + void MakeBoundsChangeUndoable(bool allowMerge); + void Transform(Matrix matrix); + void MoveBy(int dx, int dy); + bool ClickableAt(int x, int y); + IDrawableContainer ClickableElementAt(int x, int y); + void OnDoubleClick(); + bool HasIntersectingFilters(Rectangle clipRectangle); + bool IntersectsWith(Rectangle clipRectangle); + void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); + void Invalidate(); + void PullElementsToTop(IDrawableContainerList elements); + bool CanPushDown(IDrawableContainerList elements); + void PullElementsUp(IDrawableContainerList elements); + bool CanPullUp(IDrawableContainerList elements); + void PushElementsDown(IDrawableContainerList elements); + void PushElementsToBottom(IDrawableContainerList elements); + void ShowContextMenu(MouseEventArgs e, ISurface surface); + void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); + } + + public interface ITextContainer : IDrawableContainer + { + string Text + { get; set; } void FitToText(); } - public interface IImageContainer: IDrawableContainer { - Image Image { + public interface IImageContainer : IDrawableContainer + { + Image Image + { get; set; } void Load(string filename); } - public interface ICursorContainer: IDrawableContainer { - Cursor Cursor { + public interface ICursorContainer : IDrawableContainer + { + Cursor Cursor + { get; set; } void Load(string filename); } - public interface IIconContainer: IDrawableContainer { - Icon Icon { + public interface IIconContainer : IDrawableContainer + { + Icon Icon + { get; set; } void Load(string filename); } - public interface IMetafileContainer: IDrawableContainer { - Metafile Metafile { + public interface IMetafileContainer : IDrawableContainer + { + Metafile Metafile + { get; set; } diff --git a/GreenshotPlugin/Interfaces/Drawing/IField.cs b/GreenshotPlugin/Interfaces/Drawing/IField.cs new file mode 100644 index 000000000..515c8b107 --- /dev/null +++ b/GreenshotPlugin/Interfaces/Drawing/IField.cs @@ -0,0 +1,84 @@ +/* + * 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 . + */ + +using System; +using System.ComponentModel; + +namespace GreenshotPlugin.Interfaces.Drawing +{ + [Flags] + public enum FieldFlag + { + NONE = 0, + CONFIRMABLE = 1 + } + public interface IFieldType + { + string Name + { + get; + set; + } + } + + public interface IField : INotifyPropertyChanged + { + object Value + { + get; + set; + } + IFieldType FieldType + { + get; + set; + } + string Scope + { + get; + set; + } + bool HasValue + { + get; + } + } + /// + /// EventHandler to be used when a field value changes + /// + public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); + + /// + /// EventArgs to be used with FieldChangedEventHandler + /// + public class FieldChangedEventArgs : EventArgs + { + public IField Field + { + get; + private set; + } + public FieldChangedEventArgs(IField field) + { + Field = field; + } + } +} diff --git a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs new file mode 100644 index 000000000..5e6f9e15b --- /dev/null +++ b/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +using System.Collections.Generic; + +namespace GreenshotPlugin.Interfaces.Drawing +{ + /// + /// Any element holding Fields must provide access to it. + /// AbstractFieldHolder is the basic implementation. + /// If you need the fieldHolder to have child fieldHolders, + /// you should consider using IFieldHolderWithChildren. + /// + public interface IFieldHolder + { + + event FieldChangedEventHandler FieldChanged; + + void AddField(IField field); + void RemoveField(IField field); + IList GetFields(); + IField GetField(IFieldType fieldType); + bool HasField(IFieldType fieldType); + void SetFieldValue(IFieldType fieldType, object value); + } + + /// + /// Extended fieldHolder which has fieldHolder children. + /// Implementations should pass field values to and from + /// their children. + /// AbstractFieldHolderWithChildren is the basic implementation. + /// + public interface IFieldHolderWithChildren : IFieldHolder + { + void AddChild(IFieldHolder fieldHolder); + void RemoveChild(IFieldHolder fieldHolder); + } +} diff --git a/GreenshotPlugin/Interfaces/Drawing/IMemento.cs b/GreenshotPlugin/Interfaces/Drawing/IMemento.cs new file mode 100644 index 000000000..1d5971c55 --- /dev/null +++ b/GreenshotPlugin/Interfaces/Drawing/IMemento.cs @@ -0,0 +1,43 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; + +namespace Greenshot.Memento { + /// + /// Description of IMemento. + /// + public interface IMemento : IDisposable { + /// + /// Restores target to the state memorized by this memento. + /// + /// + /// A memento of the state before restoring + /// + IMemento Restore(); + + /// + /// Try to merge the current memento with another, preventing loads of items on the stack + /// + /// The memento to try to merge with + /// + bool Merge(IMemento other); + } +} diff --git a/GreenshotPlugin/Interfaces/Generic.cs b/GreenshotPlugin/Interfaces/Generic.cs index 29a66597f..ca0ea04b7 100644 --- a/GreenshotPlugin/Interfaces/Generic.cs +++ b/GreenshotPlugin/Interfaces/Generic.cs @@ -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,63 +18,74 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +using Greenshot.Core; +using Greenshot.Memento; +using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Interfaces.Drawing; using System; using System.Drawing; +using System.IO; using System.Windows.Forms; -using Greenshot.Plugin.Drawing; -using System.IO; -using System.Collections.Generic; -using Greenshot.Core; - -namespace Greenshot.Plugin { +namespace Greenshot.Plugin +{ /// /// Alignment Enums for possitioning /// //public enum HorizontalAlignment {LEFT, CENTER, RIGHT}; - public enum VerticalAlignment {TOP, CENTER, BOTTOM}; + public enum VerticalAlignment { TOP, CENTER, BOTTOM }; - public enum SurfaceMessageTyp { + public enum SurfaceMessageTyp + { FileSaved, Error, Info, UploadedUri } - public class SurfaceMessageEventArgs : EventArgs { - public SurfaceMessageTyp MessageType { + public class SurfaceMessageEventArgs : EventArgs + { + public SurfaceMessageTyp MessageType + { get; set; } - public string Message { + public string Message + { get; set; } - public ISurface Surface { + public ISurface Surface + { get; set; } } - public class SurfaceElementEventArgs : EventArgs { - public IList Elements { + public class SurfaceElementEventArgs : EventArgs + { + public IDrawableContainerList Elements + { get; set; } } - public class SurfaceDrawingModeEventArgs : EventArgs { - public DrawingModes DrawingMode { + public class SurfaceDrawingModeEventArgs : EventArgs + { + public DrawingModes DrawingMode + { get; set; } } - + public delegate void SurfaceSizeChangeEventHandler(object sender, EventArgs e); public delegate void SurfaceMessageEventHandler(object sender, SurfaceMessageEventArgs e); public delegate void SurfaceElementEventHandler(object sender, SurfaceElementEventArgs e); public delegate void SurfaceDrawingModeEventHandler(object sender, SurfaceDrawingModeEventArgs e); - public enum DrawingModes { + public enum DrawingModes + { None, Rect, Ellipse, @@ -93,7 +104,8 @@ namespace Greenshot.Plugin { /// /// The interface to the Surface object, so Plugins can use it. /// - public interface ISurface : IDisposable { + public interface ISurface : IDisposable + { event SurfaceSizeChangeEventHandler SurfaceSizeChanged; event SurfaceMessageEventHandler SurfaceMessage; event SurfaceDrawingModeEventHandler DrawingModeChanged; @@ -102,11 +114,17 @@ namespace Greenshot.Plugin { /// /// Unique ID of the Surface /// - Guid ID { + Guid ID + { get; set; } + IDrawableContainerList Elements + { + get; + } + /// /// Get/Set the image to the Surface /// get will give the image as is currently visible @@ -116,18 +134,19 @@ namespace Greenshot.Plugin { /// The setter will clone the passed bitmap and dispose it when the Surface is disposed /// This means that the supplied image needs to be disposed by the calling code (if needed!) /// - Image Image { + Image Image + { get; set; } - + /// /// Get the current Image from the Editor for Exporting (save/upload etc) /// Don't forget to call image.Dispose() when finished!!! /// /// Bitmap Image GetImageForExport(); - + /// /// Add a TextContainer, at the given location, to the Surface. /// The TextContainer will be "re"sized to the text size. @@ -154,7 +173,8 @@ namespace Greenshot.Plugin { long SaveElementsToStream(Stream stream); void LoadElementsFromStream(Stream stream); - bool HasSelectedElements { + bool HasSelectedElements + { get; } void RemoveSelectedElements(); @@ -162,9 +182,32 @@ namespace Greenshot.Plugin { void CopySelectedElements(); void PasteElementFromClipboard(); void DuplicateSelectedElements(); - void DeselectElement(IDrawableContainer container); + void DeselectElement(IDrawableContainer container, bool generateEvents = true); void DeselectAllElements(); - void SelectElement(IDrawableContainer container); + + /// + /// Add an element to the surface + /// + /// IDrawableContainerList + /// Should it be placed on the undo stack? + void AddElements(IDrawableContainerList elements, bool makeUndoable = true); + void RemoveElements(IDrawableContainerList elements, bool makeUndoable = true); + void SelectElements(IDrawableContainerList elements); + + /// + /// Add an element to the surface + /// + /// IDrawableContainer + /// Should it be placed on the undo stack? + /// Should it be invalidated (draw) + void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true); + + /// + /// Select the supplied container + /// + /// IDrawableContainer + /// false to skip invalidation + void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true); /// /// Is the supplied container "on" the surface? /// @@ -173,31 +216,46 @@ namespace Greenshot.Plugin { bool IsOnSurface(IDrawableContainer container); void Invalidate(Rectangle rectangleToInvalidate); void Invalidate(); - bool Modified { + bool Modified + { get; set; } - string LastSaveFullPath { + string LastSaveFullPath + { get; set; } - string UploadURL { + string UploadURL + { get; set; } - void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable); + /// + /// Remove an element of the elements list + /// + /// Element to remove + /// flag specifying if the remove needs to be undoable + /// flag specifying if an surface invalidate needs to be called + /// flag specifying if the deselect needs to generate an event + void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true); + void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message); void ApplyBitmapEffect(IEffect effect); void RemoveCursor(); - bool HasCursor { + bool HasCursor + { get; } - ICaptureDetails CaptureDetails { + ICaptureDetails CaptureDetails + { get; set; } int Width { get; } int Height { get; } + + void MakeUndoable(IMemento memento, bool allowMerge); } } \ No newline at end of file