diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs index a4055f2c9..38c77d950 100644 --- a/src/Greenshot.Base/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -190,12 +190,14 @@ namespace Greenshot.Base.Core /// /// Private helper method for the FindAutoCropRectangle /// - /// - /// - /// + /// IFastBitmap + /// Point + /// int + /// Rectangle with optional area to scan in /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference, Rectangle? area = null) { + area ??= new Rectangle(0, 0, fastBitmap.Width, fastBitmap.Height); Rectangle cropRectangle = Rectangle.Empty; Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); @@ -203,9 +205,9 @@ namespace Greenshot.Base.Core if (cropDifference > 0) { - for (int y = 0; y < fastBitmap.Height; y++) + for (int y = area.Value.Top; y < area.Value.Bottom; y++) { - for (int x = 0; x < fastBitmap.Width; x++) + for (int x = area.Value.Left; x < area.Value.Right; x++) { Color currentColor = fastBitmap.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); @@ -225,9 +227,9 @@ namespace Greenshot.Base.Core } else { - for (int y = 0; y < fastBitmap.Height; y++) + for (int y = area.Value.Top; y < area.Value.Bottom; y++) { - for (int x = 0; x < fastBitmap.Width; x++) + for (int x = area.Value.Left; x < area.Value.Right; x++) { Color currentColor = fastBitmap.GetColorAt(x, y); if (!referenceColor.Equals(currentColor)) @@ -243,7 +245,7 @@ namespace Greenshot.Base.Core } } - if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) + if (!(Point.Empty.Equals(min) && max.Equals(new Point(area.Value.Width - 1, area.Value.Height - 1)))) { if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { @@ -257,18 +259,20 @@ namespace Greenshot.Base.Core /// /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 /// - /// - /// + /// Image + /// int + /// Rectangle with optional area /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference, Rectangle? area = null) { + area ??= new Rectangle(0, 0, image.Width, image.Height); Rectangle cropRectangle = Rectangle.Empty; var checkPoints = new List { - new Point(0, 0), - new Point(0, image.Height - 1), - new Point(image.Width - 1, 0), - new Point(image.Width - 1, image.Height - 1) + new Point(area.Value.Left, area.Value.Top), + new Point(area.Value.Left, area.Value.Bottom - 1), + new Point(area.Value.Right - 1, area.Value.Top), + new Point(area.Value.Right - 1, area.Value.Bottom - 1) }; // Top Left // Bottom Left @@ -279,7 +283,7 @@ namespace Greenshot.Base.Core // find biggest area foreach (Point checkPoint in checkPoints) { - var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); + var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference, area); if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { cropRectangle = currentRectangle; @@ -295,7 +299,7 @@ namespace Greenshot.Base.Core /// /// Bitmap /// IEffect - /// + /// Matrix /// Bitmap public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) { diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs index 24abc2d25..3d420bfa3 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -78,6 +78,11 @@ namespace Greenshot.Base.Interfaces.Drawing bool InitContent(); + /// + /// Defines if the drawable container participates in undo / redo + /// + bool IsUndoable { get; } + void MakeBoundsChangeUndoable(bool allowMerge); EditStatus DefaultEditMode { get; } diff --git a/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs b/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs index fdbf72847..5af83b39e 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs @@ -21,6 +21,9 @@ namespace Greenshot.Base.Interfaces.Drawing { + /// + /// The IFieldAggregator defines the connections between fields and containers + /// public interface IFieldAggregator { void UnbindElement(IDrawableContainer dc); diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index 85cefe452..396a5702f 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -201,8 +201,16 @@ namespace Greenshot.Base.Interfaces /// A rectangle in the coordinate space of the surface. Rectangle ToImageCoordinates(Rectangle rc); + /// + /// Make it possible to undo the specified IMemento + /// + /// IMemento + /// bool to specify if the action can be merged, e.g. we do not want an undo for every part of a resize void MakeUndoable(IMemento memento, bool allowMerge); + /// + /// The IFieldAggregator + /// IFieldAggregator FieldAggregator { get; } /// diff --git a/src/Greenshot.Editor/Configuration/LanguageKeys.cs b/src/Greenshot.Editor/Configuration/LanguageKeys.cs index f15b113d4..b1f410e66 100644 --- a/src/Greenshot.Editor/Configuration/LanguageKeys.cs +++ b/src/Greenshot.Editor/Configuration/LanguageKeys.cs @@ -33,6 +33,7 @@ namespace Greenshot.Editor.Configuration contextmenu_capturefullscreen_right, contextmenu_capturefullscreen_bottom, contextmenu_captureie, + editor_autocrop_not_possible, editor_clipboardfailed, editor_close_on_save, editor_close_on_save_title, diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index 2324331f0..936a1a2c8 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -19,10 +19,12 @@ * along with this program. If not, see . */ + using System.Drawing; using System.Runtime.Serialization; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Editor.Drawing.Adorners; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -33,6 +35,29 @@ namespace Greenshot.Editor.Drawing /// public class CropContainer : DrawableContainer { + /// + /// Available Crop modes + /// + public enum CropModes + { + /// + /// crop all outside the selection rectangle + /// + Default, + /// + /// like default, but initially creates the selection rectangle + /// + AutoCrop, + /// + /// crop all inside the selection, anchors the selection to the top and bottom edges + /// + Vertical, + /// + /// crop all inside the selection, anchors the selection to the left and right edges + /// + Horizontal + } + public CropContainer(ISurface parent) : base(parent) { Init(); @@ -46,12 +71,65 @@ namespace Greenshot.Editor.Drawing private void Init() { - CreateDefaultAdorners(); + switch (GetFieldValue(FieldType.CROPMODE)) + { + case CropModes.Horizontal: + { + InitHorizontalCropOutStyle(); + break; + } + case CropModes.Vertical: + { + InitVerticalCropOutStyle(); + break; + } + default: + { + CreateDefaultAdorners(); + break; + } + } + } + + private void InitHorizontalCropOutStyle() + { + const int defaultHeight = 25; + + if (_parent?.Image is { } image) + { + Size = new Size(image.Width, defaultHeight); + } + CreateTopBottomAdorners(); + } + + private void InitVerticalCropOutStyle() + { + const int defaultWidth = 25; + + if (_parent?.Image is { } image) + { + Size = new Size(defaultWidth, image.Height); + } + + CreateLeftRightAdorners(); + } + + private void CreateTopBottomAdorners() + { + Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); + } + + private void CreateLeftRightAdorners() + { + Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); } protected override void InitializeFields() { AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); + AddField(GetType(), FieldType.CROPMODE, CropModes.Default); } public override void Invalidate() @@ -83,6 +161,7 @@ namespace Greenshot.Editor.Drawing return; } + using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); @@ -90,20 +169,104 @@ namespace Greenshot.Editor.Drawing DrawSelectionBorder(g, selectionRect); - // top - g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); - // left - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); - // right - g.FillRectangle(cropBrush, - new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); - // bottom - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); + switch (GetFieldValue(FieldType.CROPMODE)) + { + case CropModes.Horizontal: + case CropModes.Vertical: + { + //draw inside + g.FillRectangle(cropBrush, cropRectangle); + break; + } + default: + { + //draw outside + // top + g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); + // left + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); + // right + g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); + // bottom + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); + break; + } + } + + } /// /// No context menu for the CropContainer /// public override bool HasContextMenu => false; + + public override bool HandleMouseDown(int x, int y) + { + return GetFieldValue(FieldType.CROPMODE) switch + { + //force horizontal crop to left edge + CropModes.Horizontal => base.HandleMouseDown(0, y), + //force vertical crop to top edge + CropModes.Vertical => base.HandleMouseDown(x, 0), + _ => base.HandleMouseDown(x, y), + }; + } + + public override bool HandleMouseMove(int x, int y) + { + Invalidate(); + + switch (GetFieldValue(FieldType.CROPMODE)) + { + case CropModes.Horizontal: + { + //stick on left and right + //allow only horizontal changes + if (_parent?.Image is { } image) + { + _boundsAfterResize.X = 0; + _boundsAfterResize.Y = _boundsBeforeResize.Top; + _boundsAfterResize.Width = image.Width; + _boundsAfterResize.Height = y - _boundsAfterResize.Top; + } + break; + } + case CropModes.Vertical: + { + //stick on top and bottom + //allow only vertical changes + if (_parent?.Image is { } image) + { + _boundsAfterResize.X = _boundsBeforeResize.Left; + _boundsAfterResize.Y = 0; + _boundsAfterResize.Width = x - _boundsAfterResize.Left; + _boundsAfterResize.Height = image.Height; + } + break; + } + default: + { + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.Left; + _boundsAfterResize.Y = _boundsBeforeResize.Top; + _boundsAfterResize.Width = x - _boundsAfterResize.Left; + _boundsAfterResize.Height = y - _boundsAfterResize.Top; + break; + } + + } + ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); + + // apply scaled bounds to this DrawableContainer + ApplyBounds(_boundsAfterResize); + + Invalidate(); + return true; + } + + /// + /// Make sure this container is not undoable + public override bool IsUndoable => false; } -} \ No newline at end of file +} diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index 08abba3e2..b07974e61 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -472,13 +472,20 @@ namespace Greenshot.Editor.Drawing g.DrawRectangle(pen, rect); } + /// + public virtual bool IsUndoable => true; + /// /// Make a following bounds change on this drawablecontainer undoable! /// /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) + public virtual void MakeBoundsChangeUndoable(bool allowMerge) { - _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); + if (!IsUndoable) + { + return; + } + _parent?.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); } public void MoveBy(int dx, int dy) @@ -552,11 +559,10 @@ namespace Greenshot.Editor.Drawing protected void OnPropertyChanged(string propertyName) { - if (_propertyChanged != null) - { - _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); - Invalidate(); - } + if (_propertyChanged == null) return; + + _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); + Invalidate(); } /// @@ -567,7 +573,10 @@ namespace Greenshot.Editor.Drawing /// The new value public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) { - _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + if (IsUndoable) + { + _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + } Invalidate(); } diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index e89b78b70..9ab825e4a 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; +using System.Linq; using System.Threading; using System.Windows.Forms; using Greenshot.Base.Core; @@ -50,6 +51,11 @@ namespace Greenshot.Editor.Drawing { } + public DrawableContainerList(IEnumerable elements) + { + AddRange(elements); + } + public DrawableContainerList(Guid parentId) { ParentID = parentId; @@ -130,17 +136,21 @@ namespace Greenshot.Editor.Drawing } /// - /// Make a following bounds change on this containerlist undoable! + /// Make a following bounds change on this DrawableContainerList undoable! /// /// true means allow the moves to be merged public void MakeBoundsChangeUndoable(bool allowMerge) { - if (Count > 0 && Parent != null) + if (Count <= 0 || Parent == null) return; + // Take all containers to make undoable + var containersToClone = this.Where(c => c.IsUndoable).ToList(); + if (!containersToClone.Any()) { - var clone = new DrawableContainerList(); - clone.AddRange(this); - Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); + return; } + var clone = new DrawableContainerList(); + clone.AddRange(containersToClone); + Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); } /// @@ -291,16 +301,14 @@ namespace Greenshot.Editor.Drawing { return Rectangle.Empty; } - else - { - var result = this[0].DrawingBounds; - for (int i = 1; i < Count; i++) - { - result = Rectangle.Union(result, this[i].DrawingBounds); - } - return result; + var result = this[0].DrawingBounds; + for (int i = 1; i < Count; i++) + { + result = Rectangle.Union(result, this[i].DrawingBounds); } + + return result; } } @@ -309,7 +317,7 @@ namespace Greenshot.Editor.Drawing /// /// the to the bitmap related Graphics object /// Bitmap to draw - /// the rendermode in which the element is to be drawn + /// the RenderMode in which the element is to be drawn /// public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) { @@ -574,9 +582,7 @@ namespace Greenshot.Editor.Drawing return; } - var dc = this[index1]; - this[index1] = this[index2]; - this[index2] = dc; + (this[index1], this[index2]) = (this[index2], this[index1]); Parent.Modified = true; } diff --git a/src/Greenshot.Editor/Drawing/Fields/FieldType.cs b/src/Greenshot.Editor/Drawing/Fields/FieldType.cs index c3b732f4b..eead7452a 100644 --- a/src/Greenshot.Editor/Drawing/Fields/FieldType.cs +++ b/src/Greenshot.Editor/Drawing/Fields/FieldType.cs @@ -31,31 +31,33 @@ namespace Greenshot.Editor.Drawing.Fields [Serializable] 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 readonly IFieldType ARROWHEADS = new FieldType(nameof(ARROWHEADS)); + public static readonly IFieldType BLUR_RADIUS = new FieldType(nameof(BLUR_RADIUS)); + public static readonly IFieldType BRIGHTNESS = new FieldType(nameof(BRIGHTNESS)); + public static readonly IFieldType FILL_COLOR = new FieldType(nameof(FILL_COLOR)); + public static readonly IFieldType FONT_BOLD = new FieldType(nameof(FONT_BOLD)); + public static readonly IFieldType FONT_FAMILY = new FieldType(nameof(FONT_FAMILY)); + public static readonly IFieldType FONT_ITALIC = new FieldType(nameof(FONT_ITALIC)); + public static readonly IFieldType FONT_SIZE = new FieldType(nameof(FONT_SIZE)); + public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType(nameof(TEXT_HORIZONTAL_ALIGNMENT)); + public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType(nameof(TEXT_VERTICAL_ALIGNMENT)); + public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType(nameof(HIGHLIGHT_COLOR)); + public static readonly IFieldType LINE_COLOR = new FieldType(nameof(LINE_COLOR)); + public static readonly IFieldType LINE_THICKNESS = new FieldType(nameof(LINE_THICKNESS)); + public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType(nameof(MAGNIFICATION_FACTOR)); + public static readonly IFieldType PIXEL_SIZE = new FieldType(nameof(PIXEL_SIZE)); + public static readonly IFieldType PREVIEW_QUALITY = new FieldType(nameof(PREVIEW_QUALITY)); + public static readonly IFieldType SHADOW = new FieldType(nameof(SHADOW)); + public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType(nameof(PREPARED_FILTER_OBFUSCATE)); + public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType(nameof(PREPARED_FILTER_HIGHLIGHT)); + public static readonly IFieldType FLAGS = new FieldType(nameof(FLAGS)); + public static readonly IFieldType CROPMODE = new FieldType(nameof(CROPMODE)); + public static IFieldType[] Values = { ARROWHEADS, BLUR_RADIUS, BRIGHTNESS, FILL_COLOR, FONT_BOLD, FONT_FAMILY, FONT_ITALIC, FONT_SIZE, TEXT_HORIZONTAL_ALIGNMENT, TEXT_VERTICAL_ALIGNMENT, HIGHLIGHT_COLOR, - LINE_COLOR, LINE_THICKNESS, MAGNIFICATION_FACTOR, PIXEL_SIZE, PREVIEW_QUALITY, SHADOW, PREPARED_FILTER_OBFUSCATE, PREPARED_FILTER_HIGHLIGHT, FLAGS + LINE_COLOR, LINE_THICKNESS, MAGNIFICATION_FACTOR, PIXEL_SIZE, PREVIEW_QUALITY, SHADOW, PREPARED_FILTER_OBFUSCATE, PREPARED_FILTER_HIGHLIGHT, FLAGS, CROPMODE }; public string Name { get; set; } diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 7c27c8ce1..be40c7d1c 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -26,6 +26,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; using Greenshot.Base.Controls; @@ -710,7 +711,7 @@ namespace Greenshot.Editor.Drawing BinaryFormatter binaryRead = new BinaryFormatter(); IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead); loadedElements.Parent = this; - // Make sure the steplabels are sorted accoring to their number + // Make sure the steplabels are sorted according to their number _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); DeselectAllElements(); AddElements(loadedElements); @@ -972,16 +973,17 @@ namespace Greenshot.Editor.Drawing /// /// Auto crop the image /// + /// Rectangle with optional area to find a crop region /// true if cropped - public bool AutoCrop() + public bool AutoCrop(Rectangle? cropArea = null) { Rectangle cropRectangle; using (Image tmpImage = GetImageForExport()) { - cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); + cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference, cropArea); } - if (!IsCropPossible(ref cropRectangle)) + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.AutoCrop)) { return false; } @@ -1060,11 +1062,13 @@ namespace Greenshot.Editor.Drawing /// /// check if a crop is possible /// - /// + /// Rectangle adapted to the dimensions of the image + /// CropModes /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle) + public bool IsCropPossible(ref Rectangle cropRectangle, CropContainer.CropModes cropMode) { cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); + //Fitting the rectangle to the dimensions of the image if (cropRectangle.Left < 0) { cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); @@ -1085,6 +1089,21 @@ namespace Greenshot.Editor.Drawing cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); } + // special condition for vertical + if(cropMode == CropContainer.CropModes.Vertical && cropRectangle.Width == Image.Width) + { + //crop out the hole image is not allowed + return false; + } + + // special condition for vertical + if (cropMode == CropContainer.CropModes.Horizontal && cropRectangle.Height == Image.Height) + { + //crop out the hole image is not allowed + return false; + } + + //condition for all other crop modes if (cropRectangle.Height > 0 && cropRectangle.Width > 0) { return true; @@ -1101,16 +1120,15 @@ namespace Greenshot.Editor.Drawing /// Message itself public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) { - if (_surfaceMessage != null) + if (_surfaceMessage == null) return; + + var eventArgs = new SurfaceMessageEventArgs { - var eventArgs = new SurfaceMessageEventArgs - { - Message = message, - MessageType = messageType, - Surface = this - }; - _surfaceMessage(source, eventArgs); - } + Message = message, + MessageType = messageType, + Surface = this + }; + _surfaceMessage(source, eventArgs); } /// @@ -1118,16 +1136,15 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// new color - public void UpdateForegroundColorEvent(object source, Color color) + private void UpdateForegroundColorEvent(object source, Color color) { - if (_foregroundColorChanged != null) + if (_foregroundColorChanged == null) return; + + var eventArgs = new SurfaceForegroundColorEventArgs { - var eventArgs = new SurfaceForegroundColorEventArgs - { - Color = color, - }; - _foregroundColorChanged(source, eventArgs); - } + Color = color, + }; + _foregroundColorChanged(source, eventArgs); } /// @@ -1135,16 +1152,15 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// new color - public void UpdateBackgroundColorEvent(object source, Color color) + private void UpdateBackgroundColorEvent(object source, Color color) { - if (_lineThicknessChanged != null) + if (_lineThicknessChanged == null) return; + + var eventArgs = new SurfaceBackgroundColorEventArgs { - var eventArgs = new SurfaceBackgroundColorEventArgs - { - Color = color, - }; - _backgroundColorChanged(source, eventArgs); - } + Color = color, + }; + _backgroundColorChanged(source, eventArgs); } /// @@ -1152,16 +1168,15 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// new thickness - public void UpdateLineThicknessEvent(object source, int thickness) + private void UpdateLineThicknessEvent(object source, int thickness) { - if (_lineThicknessChanged != null) + if (_lineThicknessChanged == null) return; + + var eventArgs = new SurfaceLineThicknessEventArgs { - var eventArgs = new SurfaceLineThicknessEventArgs - { - Thickness = thickness, - }; - _lineThicknessChanged(source, eventArgs); - } + Thickness = thickness, + }; + _lineThicknessChanged(source, eventArgs); } /// @@ -1169,61 +1184,173 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// has shadow - public void UpdateShadowEvent(object source, bool hasShadow) + private void UpdateShadowEvent(object source, bool hasShadow) { - if (_shadowChanged != null) - { - var eventArgs = new SurfaceShadowEventArgs - { - HasShadow = hasShadow, - }; - _shadowChanged(source, eventArgs); - } + if (_shadowChanged == null) return; + + var eventArgs = new SurfaceShadowEventArgs + { + HasShadow = hasShadow, + }; + _shadowChanged(source, eventArgs); } /// /// Crop the surface /// - /// - /// + /// rectangle that remains + /// bool public bool ApplyCrop(Rectangle cropRectangle) { - if (IsCropPossible(ref cropRectangle)) + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Default)) return false; + + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Bitmap tmpImage; + // Make sure we have information, this this fails + try { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Bitmap tmpImage; - // Make sure we have information, this this fails - try - { - tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - } - catch (Exception ex) - { - ex.Data.Add("CropRectangle", cropRectangle); - ex.Data.Add("Width", Image.Width); - ex.Data.Add("Height", Image.Height); - ex.Data.Add("Pixelformat", Image.PixelFormat); - throw; - } - - Matrix matrix = new Matrix(); - matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - - // 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))) - { - _surfaceSizeChanged(this, null); - } - - Invalidate(); - return true; + tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; } - return false; + var matrix = new Matrix(); + matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // 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))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; + } + + /// + /// Crop out the surface + /// Splits the image in 3 parts(top, middle, bottom). Crop out the middle and joins top and bottom. + /// + /// rectangle of the middle part + /// bool + private bool ApplyHorizontalCrop(Rectangle cropRectangle) + { + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Horizontal)) return false; + + var imageRectangle = new Rectangle(Point.Empty, Image.Size); + var topRectangle = new Rectangle(0, 0, Image.Size.Width, cropRectangle.Top); + var bottomRectangle = new Rectangle(0, cropRectangle.Top + cropRectangle.Height, Image.Size.Width, Image.Size.Height - cropRectangle.Top - cropRectangle.Height); + + Bitmap newImage; + try + { + newImage = new Bitmap(Image.Size.Width, Image.Size.Height - cropRectangle.Height); + + using var graphics = Graphics.FromImage(newImage); + + var insertPositionTop = 0; + if (topRectangle.Height > 0) + { + graphics.DrawImage(Image, new Rectangle(0, insertPositionTop, topRectangle.Width, topRectangle.Height), topRectangle, GraphicsUnit.Pixel); + insertPositionTop += topRectangle.Height; + } + if (bottomRectangle.Height > 0) + { + graphics.DrawImage(Image, new Rectangle(0, insertPositionTop, bottomRectangle.Width, bottomRectangle.Height), bottomRectangle, GraphicsUnit.Pixel); + } + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; + } + var matrix = new Matrix(); + matrix.Translate(0, -(cropRectangle.Top + cropRectangle.Height), MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // Do not dispose otherwise we can't undo the image! + SetImage(newImage, false); + + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; + } + + /// + /// Crop out the surface + /// Splits the image in 3 parts(left, middle, right). Crop out the middle and joins top and bottom. + /// + /// rectangle of the middle part + /// bool + private bool ApplyVerticalCrop(Rectangle cropRectangle) + { + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Vertical)) return false; + + var imageRectangle = new Rectangle(Point.Empty, Image.Size); + var leftRectangle = new Rectangle(0, 0, cropRectangle.Left, Image.Size.Height); + var rightRectangle = new Rectangle(cropRectangle.Left + cropRectangle.Width, 0, Image.Size.Width - cropRectangle.Width - cropRectangle.Left, Image.Size.Height); + Bitmap newImage; + try + { + newImage = new Bitmap(Image.Size.Width - cropRectangle.Width, Image.Size.Height); + + using var graphics = Graphics.FromImage(newImage); + + var insertPositionLeft = 0; + if (leftRectangle.Width > 0) + { + graphics.DrawImage(Image, new Rectangle(insertPositionLeft, 0, leftRectangle.Width, leftRectangle.Height), leftRectangle , GraphicsUnit.Pixel); + insertPositionLeft += leftRectangle.Width; + } + + if (rightRectangle.Width > 0) + { + graphics.DrawImage(Image, new Rectangle(insertPositionLeft, 0, rightRectangle.Width, rightRectangle.Height), rightRectangle, GraphicsUnit.Pixel); + } + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; + } + var matrix = new Matrix(); + matrix.Translate(-cropRectangle.Left - cropRectangle.Width, 0, MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // Do not dispose otherwise we can't undo the image! + SetImage(newImage, false); + + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; } /// @@ -1255,15 +1382,14 @@ namespace Greenshot.Editor.Drawing { foreach (IAdorner adorner in drawableContainer.Adorners) { - if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) + if (!adorner.IsActive && !adorner.HitTest(mouseEventArgs.Location)) continue; + + if (adorner.Cursor != null) { - if (adorner.Cursor != null) - { - Cursor = adorner.Cursor; - } - - return adorner; + Cursor = adorner.Cursor; } + + return adorner; } } @@ -1494,48 +1620,47 @@ namespace Greenshot.Editor.Drawing Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; - if (_mouseDown) + if (!_mouseDown) return; + + if (_mouseDownElement != null) { - if (_mouseDownElement != null) + // an element is currently dragged + _mouseDownElement.Invalidate(); + selectedElements.Invalidate(); + // Move the element + if (_mouseDownElement.Selected) { - // an element is currently dragged - _mouseDownElement.Invalidate(); - selectedElements.Invalidate(); - // Move the element - if (_mouseDownElement.Selected) + if (!_isSurfaceMoveMadeUndoable) { - 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) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - _mouseDownElement.MakeBoundsChangeUndoable(false); - } - - // dragged element is not among selected elements -> just move dragged one - _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + selectedElements.MakeBoundsChangeUndoable(false); } - _mouseStart = currentMouse; - _mouseDownElement.Invalidate(); - _modified = true; + // dragged element has been selected before -> move all + selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); } - else if (_drawingElement != null) + else { - _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); - _modified = true; + if (!_isSurfaceMoveMadeUndoable) + { + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + _mouseDownElement.MakeBoundsChangeUndoable(false); + } + + // dragged element is not among selected elements -> just move dragged one + _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); } + + _mouseStart = currentMouse; + _mouseDownElement.Invalidate(); + _modified = true; + } + else if (_drawingElement != null) + { + _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); + _modified = true; } } @@ -1795,7 +1920,7 @@ namespace Greenshot.Editor.Drawing element.Invalidate(); } - if (makeUndoable) + if (makeUndoable && element.IsUndoable) { MakeUndoable(new AddElementMemento(this, element), false); } @@ -1811,11 +1936,17 @@ namespace Greenshot.Editor.Drawing public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) { // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToRemove); + DrawableContainerList cloned = new DrawableContainerList(elementsToRemove); + if (makeUndoable) { - MakeUndoable(new DeleteElementsMemento(this, cloned), false); + // Take all containers to make undoable + var undoableContainers = elementsToRemove.Where(c => c.IsUndoable).ToList(); + if (undoableContainers.Any()) + { + var undoableContainerList = new DrawableContainerList(undoableContainers); + MakeUndoable(new DeleteElementsMemento(this, undoableContainerList), false); + } } SuspendLayout(); @@ -1863,7 +1994,7 @@ namespace Greenshot.Editor.Drawing Invalidate(); } - if (makeUndoable) + if (makeUndoable && elementToRemove is { IsUndoable: true }) { MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); } @@ -1879,11 +2010,16 @@ namespace Greenshot.Editor.Drawing public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) { // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToAdd); + DrawableContainerList cloned = new DrawableContainerList(elementsToAdd); if (makeUndoable) { - MakeUndoable(new AddElementsMemento(this, cloned), false); + // Take all containers to make undoable + var undoableContainers = elementsToAdd.Where(c => c.IsUndoable).ToList(); + if (undoableContainers.Any()) + { + var undoableContainerList = new DrawableContainerList(undoableContainers); + MakeUndoable(new AddElementsMemento(this, undoableContainerList), false); + } } SuspendLayout(); @@ -1925,11 +2061,9 @@ namespace Greenshot.Editor.Drawing /// public void CutSelectedElements() { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - RemoveSelectedElements(); - } + if (!HasSelectedElements) return; + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + RemoveSelectedElements(); } /// @@ -1937,38 +2071,96 @@ namespace Greenshot.Editor.Drawing /// public void CopySelectedElements() { - if (HasSelectedElements) + if (!HasSelectedElements) return; + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + } + + /// + /// This method is called to confirm/cancel. + /// Called when pressing enter or using the "check" in the editor. + /// redirects to the specialized confirm/cancel method + /// + /// bool + public void Confirm(bool confirm) + { + if (DrawingMode == DrawingModes.Crop) { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + ConfirmCrop(confirm); + } + else + { + ConfirmSelectedConfirmableElements(confirm); } } /// - /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. + /// This method is called to confirm/cancel "confirmable" elements /// Called when pressing enter or using the "check" in the editor. + ///
+ /// For crop-container there is a dedicated method . ///
- /// + /// bool 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); foreach (IDrawableContainer dc in selectedDCs) - { - if (dc.Equals(_cropContainer)) - { - DrawingMode = DrawingModes.None; - // No undo memento for the cropcontainer itself, only for the effect - RemoveElement(_cropContainer, false); - if (confirm) - { - ApplyCrop(_cropContainer.Bounds); - } - - _cropContainer.Dispose(); - _cropContainer = null; - break; - } + { + throw new NotImplementedException($"No confirm/cancel defined for Container type {dc.GetType()}"); } + + // maybe the undo button has to be enabled + if (_movingElementChanged != null) + { + _movingElementChanged(this, new SurfaceElementEventArgs()); + } + } + + /// + /// This method is called to confirm/cancel the crop-container. + /// Called when pressing enter or using the "check" in the editor. + /// + /// bool + public void ConfirmCrop(bool confirm) + { + if (_cropContainer is not CropContainer e) return; + + if (confirm && selectedElements.Count > 0) + { + // No undo memento for the cropcontainer itself, only for the effect + RemoveElement(_cropContainer, false); + + _ = e.GetFieldValue(FieldType.CROPMODE) switch + { + CropContainer.CropModes.Horizontal => ApplyHorizontalCrop(_cropContainer.Bounds), + CropContainer.CropModes.Vertical => ApplyVerticalCrop(_cropContainer.Bounds), + _ => ApplyCrop(_cropContainer.Bounds) + }; + + _cropContainer.Dispose(); + _cropContainer = null; + } + else + { + RemoveCropContainer(); + } + + DrawingMode = DrawingModes.None; + + // maybe the undo button has to be enabled + if (_movingElementChanged != null) + { + _movingElementChanged(this, new SurfaceElementEventArgs()); + } + } + + public void RemoveCropContainer() + { + if (_cropContainer == null) return; + + RemoveElement(_cropContainer, false); + _cropContainer.Dispose(); + _cropContainer = null; } /// @@ -2144,13 +2336,13 @@ namespace Greenshot.Editor.Drawing /// /// Get the rectangle bounding all selected elements (in surface coordinates space), - /// or empty rectangle if nothing is selcted. + /// or empty rectangle if nothing is selected. /// public Rectangle GetSelectionRectangle() => ToSurfaceCoordinates(selectedElements.DrawingBounds); /// - /// Duplicate all the selecteded elements + /// Duplicate all the selected elements /// public void DuplicateSelectedElements() { @@ -2289,7 +2481,7 @@ namespace Greenshot.Editor.Drawing /// false if no keys were processed public bool ProcessCmdKey(Keys k) { - if (selectedElements.Count <= 0) return false; + if (selectedElements.Count <= 0 && k != Keys.Escape) return false; bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; int px = shiftModifier ? 10 : 1; @@ -2325,10 +2517,10 @@ namespace Greenshot.Editor.Drawing PushElementsToBottom(); break; case Keys.Enter: - ConfirmSelectedConfirmableElements(true); + Confirm(true); break; case Keys.Escape: - ConfirmSelectedConfirmableElements(false); + Confirm(false); break; case Keys.D0 | Keys.Control: case Keys.D0 | Keys.Shift | Keys.Control: @@ -2487,7 +2679,7 @@ namespace Greenshot.Editor.Drawing return _elements.CanPushDown(selectedElements); } - public void Element_FieldChanged(object sender, FieldChangedEventArgs e) + private void Element_FieldChanged(object sender, FieldChangedEventArgs e) { selectedElements.HandleFieldChangedEvent(sender, e); } @@ -2545,20 +2737,18 @@ namespace Greenshot.Editor.Drawing { return rc; } - else + + Point[] points = { - Point[] points = - { - rc.Location, rc.Location + rc.Size - }; - _inverseZoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } + rc.Location, rc.Location + rc.Size + }; + _inverseZoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/TextContainer.cs b/src/Greenshot.Editor/Drawing/TextContainer.cs index fdb718cbe..5a1f755ef 100644 --- a/src/Greenshot.Editor/Drawing/TextContainer.cs +++ b/src/Greenshot.Editor/Drawing/TextContainer.cs @@ -74,7 +74,7 @@ namespace Greenshot.Editor.Drawing { if ((text != null || newText == null) && string.Equals(text, newText)) return; - if (makeUndoable && allowUndoable) + if (makeUndoable && allowUndoable && IsUndoable) { makeUndoable = false; _parent.MakeUndoable(new TextChangeMemento(this), false); diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs index 82fecf559..90f62493e 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs @@ -98,8 +98,6 @@ namespace Greenshot.Editor.Forms { this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); this.preferencesToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); - this.autoCropToolStripMenuItem = new GreenshotToolStripMenuItem(); - this.toolStripSeparator17 = new System.Windows.Forms.ToolStripSeparator(); this.insert_window_toolstripmenuitem = new GreenshotToolStripMenuItem(); this.objectToolStripMenuItem = new GreenshotToolStripMenuItem(); this.addRectangleToolStripMenuItem = new GreenshotToolStripMenuItem(); @@ -144,8 +142,13 @@ namespace Greenshot.Editor.Forms { this.btnHelp = new GreenshotToolStripButton(); this.propertiesToolStrip = new ToolStripEx(); this.obfuscateModeButton = new BindableToolStripDropDownButton(); + this.cropModeButton = new BindableToolStripDropDownButton(); this.pixelizeToolStripMenuItem = new GreenshotToolStripMenuItem(); this.blurToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.defaultCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.verticalCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.horizontalCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.autoCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); this.highlightModeButton = new BindableToolStripDropDownButton(); this.textHighlightMenuItem = new GreenshotToolStripMenuItem(); this.areaHighlightMenuItem = new GreenshotToolStripMenuItem(); @@ -593,8 +596,6 @@ namespace Greenshot.Editor.Forms { this.toolStripSeparator12, this.preferencesToolStripMenuItem, this.toolStripSeparator5, - this.autoCropToolStripMenuItem, - this.toolStripSeparator17, this.insert_window_toolstripmenuitem}); this.editToolStripMenuItem.LanguageKey = "editor_edit"; this.editToolStripMenuItem.Name = "editToolStripMenuItem"; @@ -678,16 +679,6 @@ namespace Greenshot.Editor.Forms { // this.toolStripSeparator5.Name = "toolStripSeparator5"; // - // autoCropToolStripMenuItem - // - this.autoCropToolStripMenuItem.LanguageKey = "editor_autocrop"; - this.autoCropToolStripMenuItem.Name = "autoCropToolStripMenuItem"; - this.autoCropToolStripMenuItem.Click += new System.EventHandler(this.AutoCropToolStripMenuItemClick); - // - // toolStripSeparator17 - // - this.toolStripSeparator17.Name = "toolStripSeparator17"; - // // insert_window_toolstripmenuitem // this.insert_window_toolstripmenuitem.LanguageKey = "editor_insertwindow"; @@ -1082,6 +1073,7 @@ namespace Greenshot.Editor.Forms { this.toolStripSeparator10, this.btnConfirm, this.btnCancel, + this.cropModeButton, this.counterLabel, this.counterUpDown}); // @@ -1098,6 +1090,7 @@ namespace Greenshot.Editor.Forms { this.obfuscateModeButton.SelectedTag = FilterContainer.PreparedFilter.BLUR; this.obfuscateModeButton.Tag = FilterContainer.PreparedFilter.BLUR; // + this.obfuscateModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; // pixelizeToolStripMenuItem // this.pixelizeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("pixelizeToolStripMenuItem.Image"))); @@ -1111,6 +1104,55 @@ namespace Greenshot.Editor.Forms { this.blurToolStripMenuItem.LanguageKey = "editor_obfuscate_blur"; this.blurToolStripMenuItem.Name = "blurToolStripMenuItem"; this.blurToolStripMenuItem.Tag = FilterContainer.PreparedFilter.BLUR; + + // + // cropModeButton + // + this.cropModeButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.cropModeButton.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.defaultCropModeToolStripMenuItem, + this.verticalCropModeToolStripMenuItem, + this.horizontalCropModeToolStripMenuItem, + this.autoCropModeToolStripMenuItem}); + this.cropModeButton.Image = ((System.Drawing.Image)(resources.GetObject("btnCrop.Image"))); + this.cropModeButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.cropModeButton.LanguageKey = "editor_crop_mode"; + this.cropModeButton.Name = "cropModeButton"; + this.cropModeButton.SelectedTag = CropContainer.CropModes.Default; + this.cropModeButton.Tag = CropContainer.CropModes.Default; + this.cropModeButton.DropDownItemClicked += CropStyleDropDownItemClicked; + // + // defaultCropStyleToolStripMenuItem + // + this.defaultCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("btnCrop.Image"))); + this.defaultCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_default"; + this.defaultCropModeToolStripMenuItem.Name = "defaultCropModeToolStripMenuItem"; + this.defaultCropModeToolStripMenuItem.Tag = CropContainer.CropModes.Default; + + // + // verticalCropStyleToolStripMenuItem + // + this.verticalCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("CropVertical.Image"))); + this.verticalCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_vertical"; + this.verticalCropModeToolStripMenuItem.Name = "verticalCropModeToolStripMenuItem"; + this.verticalCropModeToolStripMenuItem.Tag = CropContainer.CropModes.Vertical; + + // + // horizontalCropStyleToolStripMenuItem + // + this.horizontalCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("CropHorizontal.Image"))); + this.horizontalCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_horizontal"; + this.horizontalCropModeToolStripMenuItem.Name = "horizontalCropModeToolStripMenuItem"; + this.horizontalCropModeToolStripMenuItem.Tag = CropContainer.CropModes.Horizontal; + + // + // autoCropModeToolStripMenuItem + // + this.autoCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("AutoCrop.Image"))); + this.autoCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_auto"; + this.autoCropModeToolStripMenuItem.Name = "autoCropModeToolStripMenuItem"; + this.autoCropModeToolStripMenuItem.Tag = CropContainer.CropModes.AutoCrop; + // // highlightModeButton // @@ -1126,6 +1168,7 @@ namespace Greenshot.Editor.Forms { this.highlightModeButton.Name = "highlightModeButton"; this.highlightModeButton.SelectedTag = FilterContainer.PreparedFilter.TEXT_HIGHTLIGHT; this.highlightModeButton.Tag = FilterContainer.PreparedFilter.TEXT_HIGHTLIGHT; + this.highlightModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; // // textHighlightMenuItem // @@ -1233,6 +1276,7 @@ namespace Greenshot.Editor.Forms { this.fontFamilyComboBox.Padding = new System.Windows.Forms.Padding(2,0,0,2); this.fontFamilyComboBox.GotFocus += new System.EventHandler(this.ToolBarFocusableElementGotFocus); this.fontFamilyComboBox.LostFocus += new System.EventHandler(this.ToolBarFocusableElementLostFocus); + this.fontFamilyComboBox.PropertyChanged += FontPropertyChanged; // // fontSizeLabel // @@ -1873,6 +1917,11 @@ namespace Greenshot.Editor.Forms { private BindableToolStripButton btnConfirm; private GreenshotToolStripMenuItem selectAllToolStripMenuItem; private BindableToolStripDropDownButton highlightModeButton; + private BindableToolStripDropDownButton cropModeButton; + private GreenshotToolStripMenuItem defaultCropModeToolStripMenuItem; + private GreenshotToolStripMenuItem verticalCropModeToolStripMenuItem; + private GreenshotToolStripMenuItem horizontalCropModeToolStripMenuItem; + private GreenshotToolStripMenuItem autoCropModeToolStripMenuItem; private GreenshotToolStripMenuItem pixelizeToolStripMenuItem; private GreenshotToolStripMenuItem blurToolStripMenuItem; private BindableToolStripDropDownButton obfuscateModeButton; diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 8ab283d0b..98a12a204 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -25,6 +25,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Threading; using System.Windows.Forms; using Greenshot.Base; @@ -181,6 +182,9 @@ namespace Greenshot.Editor.Forms UpdateUi(); + // Workaround: for the MouseWheel event which doesn't get to the panel + MouseWheel += PanelMouseWheel; + // Use best fit, for those capture modes where we can get huge images bool useBestFit = _surface.CaptureDetails.CaptureMode switch { @@ -280,11 +284,6 @@ namespace Greenshot.Editor.Forms // a smaller size than the initial panel size (as set by the forms designer) panel1.Height = 10; - fontFamilyComboBox.PropertyChanged += FontPropertyChanged; - - obfuscateModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; - highlightModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; - _toolbarButtons = new[] { btnCursor, btnRect, btnEllipse, btnText, btnLine, btnArrow, btnFreehand, btnHighlight, btnObfuscate, btnCrop, btnStepLabel, btnSpeechBubble @@ -293,9 +292,6 @@ namespace Greenshot.Editor.Forms pluginToolStripMenuItem.Visible = pluginToolStripMenuItem.DropDownItems.Count > 0; - // Workaround: for the MouseWheel event which doesn't get to the panel - MouseWheel += PanelMouseWheel; - // Make sure the value is set correctly when starting if (Surface != null) { @@ -727,7 +723,10 @@ namespace Greenshot.Editor.Forms private void BtnCropClick(object sender, EventArgs e) { + if (_surface.DrawingMode == DrawingModes.Crop) return; + _surface.DrawingMode = DrawingModes.Crop; + InitCropMode((CropContainer.CropModes)_surface.FieldAggregator.GetField(FieldType.CROPMODE).Value); RefreshFieldControls(); } @@ -1292,6 +1291,7 @@ namespace Greenshot.Editor.Forms new BidirectionalBinding(previewQualityUpDown, "Value", _surface.FieldAggregator.GetField(FieldType.PREVIEW_QUALITY), "Value", DecimalDoublePercentageConverter.GetInstance(), NotNullValidator.GetInstance()); new BidirectionalBinding(obfuscateModeButton, "SelectedTag", _surface.FieldAggregator.GetField(FieldType.PREPARED_FILTER_OBFUSCATE), "Value"); + new BidirectionalBinding(cropModeButton, "SelectedTag", _surface.FieldAggregator.GetField(FieldType.CROPMODE), "Value"); new BidirectionalBinding(highlightModeButton, "SelectedTag", _surface.FieldAggregator.GetField(FieldType.PREPARED_FILTER_HIGHLIGHT), "Value"); new BidirectionalBinding(counterUpDown, "Value", _surface, "CounterStart", DecimalIntConverter.GetInstance(), NotNullValidator.GetInstance()); } @@ -1321,12 +1321,13 @@ namespace Greenshot.Editor.Forms textHorizontalAlignmentButton.Visible = props.HasFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); textVerticalAlignmentButton.Visible = props.HasFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); shadowButton.Visible = props.HasFieldValue(FieldType.SHADOW); - counterLabel.Visible = counterUpDown.Visible = props.HasFieldValue(FieldType.FLAGS) - && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.COUNTER) == FieldFlag.COUNTER; - btnConfirm.Visible = btnCancel.Visible = props.HasFieldValue(FieldType.FLAGS) - && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE; + counterLabel.Visible = counterUpDown.Visible = props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag)props.GetFieldValue(FieldType.FLAGS)).HasFlag(FieldFlag.COUNTER); + + btnConfirm.Visible = btnCancel.Visible = props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS)).HasFlag(FieldFlag.CONFIRMABLE); + btnConfirm.Enabled = _surface.HasSelectedElements; obfuscateModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); + cropModeButton.Visible = props.HasFieldValue(FieldType.CROPMODE); highlightModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } else @@ -1582,6 +1583,39 @@ namespace Greenshot.Editor.Forms Invalidate(true); } + protected void CropStyleDropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) + { + InitCropMode((CropContainer.CropModes)e.ClickedItem.Tag); + + RefreshFieldControls(); + Invalidate(true); + } + + private void InitCropMode(CropContainer.CropModes mode) + { + var cropArea = _surface.Elements.FirstOrDefault(c => c is CropContainer)?.Bounds; + + _surface.DrawingMode = DrawingModes.None; + _surface.RemoveCropContainer(); + + if (mode == CropContainer.CropModes.AutoCrop) + { + if (!_surface.AutoCrop(cropArea)) + { + //not AutoCrop possible automatic switch to default crop mode + _surface.DrawingMode = DrawingModes.Crop; + _surface.FieldAggregator.GetField(FieldType.CROPMODE).Value = CropContainer.CropModes.Default; + this.cropModeButton.SelectedTag = CropContainer.CropModes.Default; + this.statusLabel.Text = Language.GetString(LangKey.editor_autocrop_not_possible); + } + } + else + { + _surface.DrawingMode = DrawingModes.Crop; + } + RefreshEditorControls(); + } + private void SelectAllToolStripMenuItemClick(object sender, EventArgs e) { _surface.SelectAllElements(); @@ -1590,14 +1624,14 @@ namespace Greenshot.Editor.Forms private void BtnConfirmClick(object sender, EventArgs e) { - _surface.ConfirmSelectedConfirmableElements(true); - RefreshFieldControls(); + _surface.Confirm(true); + RefreshEditorControls(); } private void BtnCancelClick(object sender, EventArgs e) { - _surface.ConfirmSelectedConfirmableElements(false); - RefreshFieldControls(); + _surface.Confirm(false); + RefreshEditorControls(); } private void Insert_window_toolstripmenuitemMouseEnter(object sender, EventArgs e) @@ -1643,14 +1677,6 @@ namespace Greenshot.Editor.Forms } } - private void AutoCropToolStripMenuItemClick(object sender, EventArgs e) - { - if (_surface.AutoCrop()) - { - RefreshFieldControls(); - } - } - private void AddBorderToolStripMenuItemClick(object sender, EventArgs e) { _surface.ApplyBitmapEffect(new BorderEffect()); @@ -1681,7 +1707,7 @@ namespace Greenshot.Editor.Forms cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, coreConfiguration.AutoCropDifference); } - if (_surface.IsCropPossible(ref cropRectangle)) + if (_surface.IsCropPossible(ref cropRectangle, CropContainer.CropModes.AutoCrop)) { _surface.ApplyCrop(cropRectangle); UpdateUndoRedoSurfaceDependencies(); diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.resx b/src/Greenshot.Editor/Forms/ImageEditorForm.resx index 57fe2f2c7..1c5b104fd 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.resx +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.resx @@ -1107,4 +1107,13 @@ 782, 17 + + ..\Resources\AutoCrop.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\CropHorizontal.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\CropVertical.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/src/Greenshot.Editor/Memento/AddElementMemento.cs b/src/Greenshot.Editor/Memento/AddElementMemento.cs index 1a95d19ce..b76858780 100644 --- a/src/Greenshot.Editor/Memento/AddElementMemento.cs +++ b/src/Greenshot.Editor/Memento/AddElementMemento.cs @@ -44,7 +44,7 @@ namespace Greenshot.Editor.Memento GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { //if (disposing) { } _drawableContainer = null; diff --git a/src/Greenshot.Editor/Memento/AddElementsMemento.cs b/src/Greenshot.Editor/Memento/AddElementsMemento.cs index 8649dec9b..0b11fac15 100644 --- a/src/Greenshot.Editor/Memento/AddElementsMemento.cs +++ b/src/Greenshot.Editor/Memento/AddElementsMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs b/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs index 1ffa8c16e..70dba9252 100644 --- a/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs +++ b/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs @@ -44,7 +44,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Memento/DeleteElementMemento.cs b/src/Greenshot.Editor/Memento/DeleteElementMemento.cs index 0acc19f83..1d744239d 100644 --- a/src/Greenshot.Editor/Memento/DeleteElementMemento.cs +++ b/src/Greenshot.Editor/Memento/DeleteElementMemento.cs @@ -45,7 +45,7 @@ namespace Greenshot.Editor.Memento GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) return; diff --git a/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs b/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs index e4b0b747e..509bbb016 100644 --- a/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs +++ b/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs b/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs index 428b0ff3d..b5b97e4cf 100644 --- a/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs @@ -34,30 +34,30 @@ namespace Greenshot.Editor.Memento { private readonly List _points = new(); private readonly List _sizes = new(); - private IDrawableContainerList _listOfdrawableContainer; + private IDrawableContainerList _listOfDrawableContainer; private void StoreBounds() { - foreach (IDrawableContainer drawableContainer in _listOfdrawableContainer) + foreach (IDrawableContainer drawableContainer in _listOfDrawableContainer) { _points.Add(drawableContainer.Location); _sizes.Add(drawableContainer.Size); } } - public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfdrawableContainer) + public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfDrawableContainer) { - _listOfdrawableContainer = listOfdrawableContainer; + _listOfDrawableContainer = listOfDrawableContainer; StoreBounds(); } public DrawableContainerBoundsChangeMemento(IDrawableContainer drawableContainer) { - _listOfdrawableContainer = new DrawableContainerList + _listOfDrawableContainer = new DrawableContainerList { drawableContainer }; - _listOfdrawableContainer.Parent = drawableContainer.Parent; + _listOfDrawableContainer.Parent = drawableContainer.Parent; StoreBounds(); } @@ -66,21 +66,21 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { - _listOfdrawableContainer?.Dispose(); + _listOfDrawableContainer?.Dispose(); } - _listOfdrawableContainer = null; + _listOfDrawableContainer = null; } public bool Merge(IMemento otherMemento) { if (otherMemento is not DrawableContainerBoundsChangeMemento other) return false; - if (ObjectExtensions.CompareLists(_listOfdrawableContainer, other._listOfdrawableContainer)) + if (ObjectExtensions.CompareLists(_listOfDrawableContainer, other._listOfDrawableContainer)) { // Lists are equal, as we have the state already we can ignore the new memento return true; @@ -91,10 +91,10 @@ namespace Greenshot.Editor.Memento public IMemento Restore() { - var oldState = new DrawableContainerBoundsChangeMemento(_listOfdrawableContainer); - for (int index = 0; index < _listOfdrawableContainer.Count; index++) + var oldState = new DrawableContainerBoundsChangeMemento(_listOfDrawableContainer); + for (int index = 0; index < _listOfDrawableContainer.Count; index++) { - IDrawableContainer drawableContainer = _listOfdrawableContainer[index]; + IDrawableContainer drawableContainer = _listOfDrawableContainer[index]; // Before drawableContainer.Invalidate(); drawableContainer.Left = _points[index].X; diff --git a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs index c6ba814c3..8c49614b4 100644 --- a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs @@ -52,7 +52,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) return; diff --git a/src/Greenshot.Editor/Memento/TextChangeMemento.cs b/src/Greenshot.Editor/Memento/TextChangeMemento.cs index 411dde53c..46f33592b 100644 --- a/src/Greenshot.Editor/Memento/TextChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/TextChangeMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Resources/AutoCrop.Image.png b/src/Greenshot.Editor/Resources/AutoCrop.Image.png new file mode 100644 index 000000000..1f9d86c4d Binary files /dev/null and b/src/Greenshot.Editor/Resources/AutoCrop.Image.png differ diff --git a/src/Greenshot.Editor/Resources/CropHorizontal.Image.png b/src/Greenshot.Editor/Resources/CropHorizontal.Image.png new file mode 100644 index 000000000..f8f321c15 Binary files /dev/null and b/src/Greenshot.Editor/Resources/CropHorizontal.Image.png differ diff --git a/src/Greenshot.Editor/Resources/CropVertical.Image.png b/src/Greenshot.Editor/Resources/CropVertical.Image.png new file mode 100644 index 000000000..fe1dea06e Binary files /dev/null and b/src/Greenshot.Editor/Resources/CropVertical.Image.png differ diff --git a/src/Greenshot/Languages/language-ar-SY.xml b/src/Greenshot/Languages/language-ar-SY.xml index c5c6edc84..a7363a326 100644 --- a/src/Greenshot/Languages/language-ar-SY.xml +++ b/src/Greenshot/Languages/language-ar-SY.xml @@ -62,6 +62,7 @@ انسخ المسار الي الذاكرة نسخ قص (C) + قص اداة التحديد (ESC) قص احذف diff --git a/src/Greenshot/Languages/language-ca-CA.xml b/src/Greenshot/Languages/language-ca-CA.xml index 9f92f7446..423c55006 100644 --- a/src/Greenshot/Languages/language-ca-CA.xml +++ b/src/Greenshot/Languages/language-ca-CA.xml @@ -92,6 +92,8 @@ Abans de crear un nou informe d'error, us agrairem que comproveu que l'error no Copia el camí al porta-retalls Copia Retalla(C) + Retalla + Autorretalla Eina de selecció (ESC) Retalla Esborra diff --git a/src/Greenshot/Languages/language-cs-CZ.xml b/src/Greenshot/Languages/language-cs-CZ.xml index 915fd3fe0..86d7f2207 100644 --- a/src/Greenshot/Languages/language-cs-CZ.xml +++ b/src/Greenshot/Languages/language-cs-CZ.xml @@ -93,6 +93,8 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Kopírovat cestu do schránky Kopírovat Oříznout (C) + Oříznout + Automatické oříznutí Výběr objektů (ESC) Vystřihnout Odstranit diff --git a/src/Greenshot/Languages/language-da-DK.xml b/src/Greenshot/Languages/language-da-DK.xml index 166774d34..b032e8aff 100644 --- a/src/Greenshot/Languages/language-da-DK.xml +++ b/src/Greenshot/Languages/language-da-DK.xml @@ -469,6 +469,9 @@ tidspunktet, fx 11_58_32 (plus filendelsen angivet i indstillingerne). Beskær (C) + + Beskær + Åbn billede fra udklipsholder diff --git a/src/Greenshot/Languages/language-de-DE.xml b/src/Greenshot/Languages/language-de-DE.xml index 062cdd6a5..a50ad0119 100644 --- a/src/Greenshot/Languages/language-de-DE.xml +++ b/src/Greenshot/Languages/language-de-DE.xml @@ -77,6 +77,7 @@ schnell zu finden. Vielen Dank :) Keine Anfangspunkt Automatisch zuschneiden + Automatisches Zuschneiden nicht möglich Hintergrundfarbe (0-9) Weichzeichner-Radius Fett @@ -92,6 +93,11 @@ schnell zu finden. Vielen Dank :) Pfad in Zwischenablage kopieren Kopieren Zuschneiden (C) + Zuschneiden - Modus + Zuschneiden + Vertikal ausschneiden + Horizontal ausschneiden + Automatisch zuschneiden Auswahlwerkzeug (Esc) Ausschneiden Gewähltes Element löschen diff --git a/src/Greenshot/Languages/language-de-x-franconia.xml b/src/Greenshot/Languages/language-de-x-franconia.xml index b989bcfe7..34da6f0b7 100644 --- a/src/Greenshot/Languages/language-de-x-franconia.xml +++ b/src/Greenshot/Languages/language-de-x-franconia.xml @@ -88,6 +88,8 @@ Dangschee, wassd scho :) Bfad in däi Zwischnblach nei Kobiern Zamschneidn (C) + Zamschneidn + Audomadisch zamschneidn Angriffln (ESC) Ausschneidn Wech mid dem Ding! diff --git a/src/Greenshot/Languages/language-el-GR.xml b/src/Greenshot/Languages/language-el-GR.xml index 14cb68bef..1feb74b51 100644 --- a/src/Greenshot/Languages/language-el-GR.xml +++ b/src/Greenshot/Languages/language-el-GR.xml @@ -93,6 +93,8 @@ Αντιγραφή της θέσης του αρχείου στο πρόχειρο Αντιγραφή Περικοπή (C) + Περικοπή + Αυτόματη Περικοπή Εργαλείο Επιλογής (ESC) Αποκοπή Διαγραφή diff --git a/src/Greenshot/Languages/language-en-US.xml b/src/Greenshot/Languages/language-en-US.xml index b575f549b..5cac2280d 100644 --- a/src/Greenshot/Languages/language-en-US.xml +++ b/src/Greenshot/Languages/language-en-US.xml @@ -78,6 +78,7 @@ Also, we would highly appreciate if you checked whether a tracker item already e None Start point Auto crop + Auto crop not possible Fill color (0-9) Blur radius Bold @@ -93,6 +94,11 @@ Also, we would highly appreciate if you checked whether a tracker item already e Copy path to clipboard Copy Crop (C) + Crop mode + Crop + Crop out vertically + Crop out horizontally + Auto crop Selection Tool (ESC) Cut Delete diff --git a/src/Greenshot/Languages/language-es-ES.xml b/src/Greenshot/Languages/language-es-ES.xml index b84aee912..0badf64a4 100644 --- a/src/Greenshot/Languages/language-es-ES.xml +++ b/src/Greenshot/Languages/language-es-ES.xml @@ -80,6 +80,8 @@ Antes de crear un nuevo informe de error, te agradeceríamos que comprobaras que Copiar ruta al portapapeles Copiar Recortar(C) + Recortar + Autorrecortar Herramienta de selección (ESC) Cortar Borrar diff --git a/src/Greenshot/Languages/language-et-EE.xml b/src/Greenshot/Languages/language-et-EE.xml index b358977e8..7a4b0dcc3 100644 --- a/src/Greenshot/Languages/language-et-EE.xml +++ b/src/Greenshot/Languages/language-et-EE.xml @@ -92,6 +92,8 @@ Me oleksime väga tänulik, kui te enne kontrolliksite, ega sellest veast pole j Kopeerige asukoht lõikelauale Kopeeri Lõika (C) + Lõika + Automaatne lõikus Valiku tööriist (ESC) Lõika Kustuta diff --git a/src/Greenshot/Languages/language-fa-IR.xml b/src/Greenshot/Languages/language-fa-IR.xml index 20e1da09f..2ab2c8242 100644 --- a/src/Greenshot/Languages/language-fa-IR.xml +++ b/src/Greenshot/Languages/language-fa-IR.xml @@ -67,6 +67,7 @@ Could not save Greenshot's configuration file. Please check access permissions f رونویس چیدن (C دکمه) + چیدن انتخابگر (ESC دکمه) برش diff --git a/src/Greenshot/Languages/language-fi-FI.xml b/src/Greenshot/Languages/language-fi-FI.xml index f66cc5013..a2f211b03 100644 --- a/src/Greenshot/Languages/language-fi-FI.xml +++ b/src/Greenshot/Languages/language-fi-FI.xml @@ -62,6 +62,7 @@ Olisi myös hyvä jos voisit tarkistaa onko virhe jo raportoitu aikaisemmin (voi Kopioi tiedostopolku leikepöydälle Kopioi Rajaa (C) + Rajaa Valintatyökalu (ESC) Leikkaa Poista diff --git a/src/Greenshot/Languages/language-fr-FR.xml b/src/Greenshot/Languages/language-fr-FR.xml index 53f8e21f6..50cde5788 100644 --- a/src/Greenshot/Languages/language-fr-FR.xml +++ b/src/Greenshot/Languages/language-fr-FR.xml @@ -93,6 +93,8 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si Copier Ajouter un compteur Recadrer (C) + Recadrer + Cadrage automatique Outil de sélection (ESC) Couper Supprimer diff --git a/src/Greenshot/Languages/language-fr-QC.xml b/src/Greenshot/Languages/language-fr-QC.xml index 17c0e5537..cf822fa16 100644 --- a/src/Greenshot/Languages/language-fr-QC.xml +++ b/src/Greenshot/Languages/language-fr-QC.xml @@ -78,6 +78,8 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si Copier le chemin vers le presse-papier Copier Rogner (C) + Rogner + Rognage automatique Outil de sélection (ESC) Couper Supprimer diff --git a/src/Greenshot/Languages/language-he-IL.xml b/src/Greenshot/Languages/language-he-IL.xml index 4df909d37..537f77067 100644 --- a/src/Greenshot/Languages/language-he-IL.xml +++ b/src/Greenshot/Languages/language-he-IL.xml @@ -63,6 +63,7 @@ Details about the GNU General Public License: העתק נתיב אל הלוח העתקה חתוך (C) + חתוך כלי בחירה (ESC) חיתוך מחיקה diff --git a/src/Greenshot/Languages/language-hu-HU.xml b/src/Greenshot/Languages/language-hu-HU.xml index 0d5a06df9..20035f3c5 100644 --- a/src/Greenshot/Languages/language-hu-HU.xml +++ b/src/Greenshot/Languages/language-hu-HU.xml @@ -63,6 +63,7 @@ Kérjük adjon összefoglaló leírást és csatoljon minden olyan információt Másolja a vágólapra Másolás Vágás eszköz (C) + Vágás eszköz Kiválasztó eszköz (ESC) Kivágás Törlés diff --git a/src/Greenshot/Languages/language-id-ID.xml b/src/Greenshot/Languages/language-id-ID.xml index e474cae59..df31cd624 100644 --- a/src/Greenshot/Languages/language-id-ID.xml +++ b/src/Greenshot/Languages/language-id-ID.xml @@ -93,6 +93,8 @@ Juga, kami sangat terbantu apabila anda mengecek laporan lain yang sama dengan k Kopi Buat penomor Potong (C) + Potong + Auto potong Alat seleksi (ESC) Gunting Hapus diff --git a/src/Greenshot/Languages/language-it-IT.xml b/src/Greenshot/Languages/language-it-IT.xml index 53fa10837..e52ecb1e1 100644 --- a/src/Greenshot/Languages/language-it-IT.xml +++ b/src/Greenshot/Languages/language-it-IT.xml @@ -98,6 +98,8 @@ Controlla i permessi di accesso per '{0}'. Copia percorso negli appunti Copia Ritaglia (C) + Ritaglia + Ritaglia Automaticamente Strumento di selezione (ESC) Taglia Elimina diff --git a/src/Greenshot/Languages/language-ja-JP.xml b/src/Greenshot/Languages/language-ja-JP.xml index c894b9573..03638f0dc 100644 --- a/src/Greenshot/Languages/language-ja-JP.xml +++ b/src/Greenshot/Languages/language-ja-JP.xml @@ -92,6 +92,8 @@ Greenshot には一切の保障がありません。GNU General Public License コピー カウンターを挿入する (I) 切り抜き (C) + 切り抜き + 自動切り抜き 選択ツール (ESC) 切り取り 削除 diff --git a/src/Greenshot/Languages/language-kab-DZ.xml b/src/Greenshot/Languages/language-kab-DZ.xml index 31930d2db..e3366a18a 100644 --- a/src/Greenshot/Languages/language-kab-DZ.xml +++ b/src/Greenshot/Languages/language-kab-DZ.xml @@ -93,6 +93,8 @@ Rnu ɣur-s, nḥemmel aṭas ma yella tesneqdeḍ aneqqis igebren ugur-agi. (Tze Nɣel Rnu Amesmiḍan Seggem (C) + Seggem + Aseggem awurman Afecku n ufran (ESC) Gzem Kkes diff --git a/src/Greenshot/Languages/language-ko-KR.xml b/src/Greenshot/Languages/language-ko-KR.xml index a332cea33..0bf90570e 100644 --- a/src/Greenshot/Languages/language-ko-KR.xml +++ b/src/Greenshot/Languages/language-ko-KR.xml @@ -92,6 +92,8 @@ Also, we would highly appreciate if you checked whether a tracker item already e 경로를 클립보드로 복사 복사 잘라내기 (C) + 잘라내기 + 자동 잘라내기 선택도구 (ESC) 잘라내기 삭제 diff --git a/src/Greenshot/Languages/language-lt-LT.xml b/src/Greenshot/Languages/language-lt-LT.xml index e84388901..9b1089811 100644 --- a/src/Greenshot/Languages/language-lt-LT.xml +++ b/src/Greenshot/Languages/language-lt-LT.xml @@ -61,6 +61,7 @@ Dėkojame už pagalbą :) Kopijuoti pilną failo vardą Коpijuoti Iškirpti (C) + Iškirpti Objektų pasirinkimas (ESC) Apkirpti Naikinti diff --git a/src/Greenshot/Languages/language-lv-LV.xml b/src/Greenshot/Languages/language-lv-LV.xml index c74e41326..acbe9eacb 100644 --- a/src/Greenshot/Languages/language-lv-LV.xml +++ b/src/Greenshot/Languages/language-lv-LV.xml @@ -92,6 +92,8 @@ Mēs būtu Tev pateicīgi, ja Tu vispirms pārbaudītu, vai kāds cits jau nav z Ievietot ceļu starpliktuvē Kopēt Apcirst (C) + Apcirst + Automātiski apcirst Atlases rīks (ESC) Izgriezt Izdzēst diff --git a/src/Greenshot/Languages/language-nl-NL.xml b/src/Greenshot/Languages/language-nl-NL.xml index 52e12a895..65c008c01 100644 --- a/src/Greenshot/Languages/language-nl-NL.xml +++ b/src/Greenshot/Languages/language-nl-NL.xml @@ -93,6 +93,8 @@ Controleer ook even of dit probleem mogelijk al gemeld is! Gebruik de zoekfuncti Locatie naar klembord kopiëren Kopiëren Bijsnijden (C) + Bijsnijden + Automatisch bijsnijden Selectiegereedschap (ESC) Knippen Verwijderen diff --git a/src/Greenshot/Languages/language-nn-NO.xml b/src/Greenshot/Languages/language-nn-NO.xml index 003b11b9a..edd8f31e7 100644 --- a/src/Greenshot/Languages/language-nn-NO.xml +++ b/src/Greenshot/Languages/language-nn-NO.xml @@ -80,6 +80,8 @@ Me sett òg pris på om du ved hjelp av søkefunksjonen på sida kan sjekke om d Kopier filstigen til utklyppstavla Kopier Skjer bildet [C] + Skjer bildet + Auto-skjer Peikarverktøy [Esc] Klypp ut Slett diff --git a/src/Greenshot/Languages/language-pl-PL.xml b/src/Greenshot/Languages/language-pl-PL.xml index 54e2fd993..7f908dba8 100644 --- a/src/Greenshot/Languages/language-pl-PL.xml +++ b/src/Greenshot/Languages/language-pl-PL.xml @@ -93,6 +93,8 @@ Będziemy wdzięczni, jeśli najpierw sprawdzisz, czy takie zdarzenie nie zosta Kopiuj ścieżkę do schowka Kopiuj Przytnij (C) + Przytnij (C) + Przytnij automatycznie Narzędzie wyboru (ESC) Wytnij Usuń diff --git a/src/Greenshot/Languages/language-pt-BR.xml b/src/Greenshot/Languages/language-pt-BR.xml index 8bfd938ed..e53603ccc 100644 --- a/src/Greenshot/Languages/language-pt-BR.xml +++ b/src/Greenshot/Languages/language-pt-BR.xml @@ -89,6 +89,7 @@ Copiar o caminho da pasta atual do arquivo para a Área de transferência Copiar Cortar (C) + Cortar Ferramenta de Seleção (ESC) Cortar Apagar diff --git a/src/Greenshot/Languages/language-pt-PT.xml b/src/Greenshot/Languages/language-pt-PT.xml index dabc42762..53a3ea424 100644 --- a/src/Greenshot/Languages/language-pt-PT.xml +++ b/src/Greenshot/Languages/language-pt-PT.xml @@ -92,6 +92,8 @@ Também apreciaremos muito se puder verificar se não existe já um relatório d Copiar atalho para a Área de transferência Copiar Recortar (C) + Recortar + Recortar auto Ferramenta de Selecção (ESC) Cortar Eliminar diff --git a/src/Greenshot/Languages/language-ro-RO.xml b/src/Greenshot/Languages/language-ro-RO.xml index 7e67ecb52..02fe86c3f 100644 --- a/src/Greenshot/Languages/language-ro-RO.xml +++ b/src/Greenshot/Languages/language-ro-RO.xml @@ -471,6 +471,9 @@ timpul curent, ex. 11_58_32 (plus extensia fișierului definită în setări) Taie (C) + + Taie + Deschide imaginea din clipboard diff --git a/src/Greenshot/Languages/language-ru-RU.xml b/src/Greenshot/Languages/language-ru-RU.xml index 42d85df80..f9973f349 100644 --- a/src/Greenshot/Languages/language-ru-RU.xml +++ b/src/Greenshot/Languages/language-ru-RU.xml @@ -93,6 +93,8 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Копировать путь в буфер обмена Копировать Обрезка (C) + Обрезка + Автообрезка Инструмент «Выделение» (ESC) Вырезать Удалить diff --git a/src/Greenshot/Languages/language-sk-SK.xml b/src/Greenshot/Languages/language-sk-SK.xml index f47c2bd5b..01c68e9ed 100644 --- a/src/Greenshot/Languages/language-sk-SK.xml +++ b/src/Greenshot/Languages/language-sk-SK.xml @@ -80,6 +80,8 @@ Tiež by sme velmi ocenili, keby ste najskôr skontrolovali, či už neexistuje Kopírovať cestu do schránky Kopírovať Orezať (C) + Orezať + Automatické orezanie Nástroj pre výber (ESC) Vystrihnúť Zmazať diff --git a/src/Greenshot/Languages/language-sl-SI.xml b/src/Greenshot/Languages/language-sl-SI.xml index fd0dc2bc4..ac102397a 100644 --- a/src/Greenshot/Languages/language-sl-SI.xml +++ b/src/Greenshot/Languages/language-sl-SI.xml @@ -78,6 +78,8 @@ Pred objavo preverite tudi ali je napaka že prijavlja s strani kakšnega drugeg Kopiraj pot na odložišče Kopiraj Obreži (C) + Obreži + Samodejno obreži Orodje za izbor (ESC) Kopiraj Briši diff --git a/src/Greenshot/Languages/language-sr-RS.xml b/src/Greenshot/Languages/language-sr-RS.xml index 6b624dd9c..9c669dba8 100644 --- a/src/Greenshot/Languages/language-sr-RS.xml +++ b/src/Greenshot/Languages/language-sr-RS.xml @@ -78,6 +78,8 @@ Умножи путању Умножи Опсеци (C) + Опсеци + Аутоматско опсецање Алатка за одабир (ESC) Исеци Обриши diff --git a/src/Greenshot/Languages/language-sv-SE.xml b/src/Greenshot/Languages/language-sv-SE.xml index 3fe2df709..c67bfe8fe 100644 --- a/src/Greenshot/Languages/language-sv-SE.xml +++ b/src/Greenshot/Languages/language-sv-SE.xml @@ -93,6 +93,8 @@ Innan du skickar uppskattar vi verkligen om du kontrollerar om felet redan blivi Kopiera sökväg till urklipp Kopiera Beskär (C) + Beskär + Autobeskärning Markeringsverktyg (ESC) Klipp ut Radera diff --git a/src/Greenshot/Languages/language-tr-TR.xml b/src/Greenshot/Languages/language-tr-TR.xml index b5a43f083..56011063c 100644 --- a/src/Greenshot/Languages/language-tr-TR.xml +++ b/src/Greenshot/Languages/language-tr-TR.xml @@ -78,6 +78,8 @@ Ayrıca bu hata için bir izleyici kaydının açılmış olup olmadığını da Yolu panoya kopyala Kopyala Kırp (C) + Kırp + Otomatik kırpma Seçim Aracı (ESC) Kes Sil diff --git a/src/Greenshot/Languages/language-uk-UA.xml b/src/Greenshot/Languages/language-uk-UA.xml index 850a5ea7f..1eae26c97 100644 --- a/src/Greenshot/Languages/language-uk-UA.xml +++ b/src/Greenshot/Languages/language-uk-UA.xml @@ -92,6 +92,8 @@ Greenshot постачається АБСОЛЮТНО БЕЗ ГАРАНТІЇ. Копіювати шлях у буфер обміну Копіювати Обрізати (С) + Обрізати + Автоматичне обрізання Інструмент вибору (Esc) Вирізати Видалити diff --git a/src/Greenshot/Languages/language-vi-VN.xml b/src/Greenshot/Languages/language-vi-VN.xml index a4b1a73c2..6ddfc7f9d 100644 --- a/src/Greenshot/Languages/language-vi-VN.xml +++ b/src/Greenshot/Languages/language-vi-VN.xml @@ -58,6 +58,7 @@ Chép đuờng dẫn tới clipboard. Chép Cắt (C) + Cắt Công cụ chọn (ESC) Cắt Xóa diff --git a/src/Greenshot/Languages/language-zh-CN.xml b/src/Greenshot/Languages/language-zh-CN.xml index 7325fff33..e69489c8c 100644 --- a/src/Greenshot/Languages/language-zh-CN.xml +++ b/src/Greenshot/Languages/language-zh-CN.xml @@ -84,6 +84,8 @@ 复制路径到剪贴板 复制 裁剪 (C) + 裁剪 + 自动裁剪 选择工具 (ESC) 剪切 刪除物件 diff --git a/src/Greenshot/Languages/language-zh-TW.xml b/src/Greenshot/Languages/language-zh-TW.xml index da3881d2c..69f5e6696 100644 --- a/src/Greenshot/Languages/language-zh-TW.xml +++ b/src/Greenshot/Languages/language-zh-TW.xml @@ -93,6 +93,8 @@ Greenshot 不對這個程式做任何擔保。這個程式是自由軟體,您 複製路徑到剪貼簿 複製 裁剪 (C) + 裁剪 + 自動裁剪 選取工具 (ESC) 剪下 刪除