mirror of
https://github.com/greenshot/greenshot
synced 2025-07-05 20:42:14 -07:00
Co-authored-by: Robin Krom <robin@getgreenshot.org>
This commit is contained in:
parent
4a66a4dbe2
commit
56c26ac038
64 changed files with 865 additions and 310 deletions
|
@ -190,12 +190,14 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Private helper method for the FindAutoCropRectangle
|
||||
/// </summary>
|
||||
/// <param name="fastBitmap"></param>
|
||||
/// <param name="colorPoint"></param>
|
||||
/// <param name="cropDifference"></param>
|
||||
/// <param name="fastBitmap">IFastBitmap</param>
|
||||
/// <param name="colorPoint">Point</param>
|
||||
/// <param name="cropDifference">int</param>
|
||||
/// <param name="area">Rectangle with optional area to scan in</param>
|
||||
/// <returns>Rectangle</returns>
|
||||
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
|
|||
/// <summary>
|
||||
/// Get a rectangle for the image which crops the image of all colors equal to that on 0,0
|
||||
/// </summary>
|
||||
/// <param name="image"></param>
|
||||
/// <param name="cropDifference"></param>
|
||||
/// <param name="image">Image</param>
|
||||
/// <param name="cropDifference">int</param>
|
||||
/// <param name="area">Rectangle with optional area</param>
|
||||
/// <returns>Rectangle</returns>
|
||||
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<Point>
|
||||
{
|
||||
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
|
|||
/// </summary>
|
||||
/// <param name="sourceImage">Bitmap</param>
|
||||
/// <param name="effect">IEffect</param>
|
||||
/// <param name="matrix"></param>
|
||||
/// <param name="matrix">Matrix</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix)
|
||||
{
|
||||
|
|
|
@ -78,6 +78,11 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
|
||||
bool InitContent();
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the drawable container participates in undo / redo
|
||||
/// </summary>
|
||||
bool IsUndoable { get; }
|
||||
|
||||
void MakeBoundsChangeUndoable(bool allowMerge);
|
||||
|
||||
EditStatus DefaultEditMode { get; }
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
namespace Greenshot.Base.Interfaces.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// The IFieldAggregator defines the connections between fields and containers
|
||||
/// </summary>
|
||||
public interface IFieldAggregator
|
||||
{
|
||||
void UnbindElement(IDrawableContainer dc);
|
||||
|
|
|
@ -201,8 +201,16 @@ namespace Greenshot.Base.Interfaces
|
|||
/// <param name="rc">A rectangle in the coordinate space of the surface.</param>
|
||||
Rectangle ToImageCoordinates(Rectangle rc);
|
||||
|
||||
/// <summary>
|
||||
/// Make it possible to undo the specified IMemento
|
||||
/// </summary>
|
||||
/// <param name="memento">IMemento</param>
|
||||
/// <param name="allowMerge">bool to specify if the action can be merged, e.g. we do not want an undo for every part of a resize</param>
|
||||
void MakeUndoable(IMemento memento, bool allowMerge);
|
||||
|
||||
/// <summary>
|
||||
/// The IFieldAggregator
|
||||
/// </summary>
|
||||
IFieldAggregator FieldAggregator { get; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
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
|
|||
/// </summary>
|
||||
public class CropContainer : DrawableContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Available Crop modes
|
||||
/// </summary>
|
||||
public enum CropModes
|
||||
{
|
||||
/// <summary>
|
||||
/// crop all outside the selection rectangle
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// like default, but initially creates the selection rectangle
|
||||
/// </summary>
|
||||
AutoCrop,
|
||||
/// <summary>
|
||||
/// crop all inside the selection, anchors the selection to the top and bottom edges
|
||||
/// </summary>
|
||||
Vertical,
|
||||
/// <summary>
|
||||
/// crop all inside the selection, anchors the selection to the left and right edges
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No context menu for the CropContainer
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDrawableContainer"/>
|
||||
/// Make sure this container is not undoable
|
||||
public override bool IsUndoable => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -472,13 +472,20 @@ namespace Greenshot.Editor.Drawing
|
|||
g.DrawRectangle(pen, rect);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDrawableContainer"/>
|
||||
public virtual bool IsUndoable => true;
|
||||
|
||||
/// <summary>
|
||||
/// Make a following bounds change on this drawablecontainer undoable!
|
||||
/// </summary>
|
||||
/// <param name="allowMerge">true means allow the moves to be merged</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -567,7 +573,10 @@ namespace Greenshot.Editor.Drawing
|
|||
/// <param name="newValue">The new value</param>
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<IDrawableContainer> elements)
|
||||
{
|
||||
AddRange(elements);
|
||||
}
|
||||
|
||||
public DrawableContainerList(Guid parentId)
|
||||
{
|
||||
ParentID = parentId;
|
||||
|
@ -130,17 +136,21 @@ namespace Greenshot.Editor.Drawing
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a following bounds change on this containerlist undoable!
|
||||
/// Make a following bounds change on this DrawableContainerList undoable!
|
||||
/// </summary>
|
||||
/// <param name="allowMerge">true means allow the moves to be merged</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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
|
|||
/// </summary>
|
||||
/// <param name="g">the to the bitmap related Graphics object</param>
|
||||
/// <param name="bitmap">Bitmap to draw</param>
|
||||
/// <param name="renderMode">the rendermode in which the element is to be drawn</param>
|
||||
/// <param name="renderMode">the RenderMode in which the element is to be drawn</param>
|
||||
/// <param name="clipRectangle"></param>
|
||||
public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
|||
/// <summary>
|
||||
/// Auto crop the image
|
||||
/// </summary>
|
||||
/// <param name="cropArea">Rectangle with optional area to find a crop region</param>
|
||||
/// <returns>true if cropped</returns>
|
||||
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
|
|||
/// <summary>
|
||||
/// check if a crop is possible
|
||||
/// </summary>
|
||||
/// <param name="cropRectangle"></param>
|
||||
/// <param name="cropRectangle">Rectangle adapted to the dimensions of the image</param>
|
||||
/// <param name="cropMode">CropModes</param>
|
||||
/// <returns>true if this is possible</returns>
|
||||
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
|
|||
/// <param name="message">Message itself</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1118,16 +1136,15 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
/// <param name="source">Who send</param>
|
||||
/// <param name="color">new color</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1135,16 +1152,15 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
/// <param name="source">Who send</param>
|
||||
/// <param name="color">new color</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1152,16 +1168,15 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
/// <param name="source">Who send</param>
|
||||
/// <param name="thickness">new thickness</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1169,61 +1184,173 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
/// <param name="source">Who send</param>
|
||||
/// <param name="hasShadow">has shadow</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crop the surface
|
||||
/// </summary>
|
||||
/// <param name="cropRectangle"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="cropRectangle">rectangle that remains</param>
|
||||
/// <returns>bool</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crop out the surface
|
||||
/// Splits the image in 3 parts(top, middle, bottom). Crop out the middle and joins top and bottom.
|
||||
/// </summary>
|
||||
/// <param name="cropRectangle">rectangle of the middle part</param>
|
||||
/// <returns>bool</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crop out the surface
|
||||
/// Splits the image in 3 parts(left, middle, right). Crop out the middle and joins top and bottom.
|
||||
/// </summary>
|
||||
/// <param name="cropRectangle">rectangle of the middle part</param>
|
||||
/// <returns>bool</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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
|
|||
/// </summary>
|
||||
public void CutSelectedElements()
|
||||
{
|
||||
if (HasSelectedElements)
|
||||
{
|
||||
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
|
||||
RemoveSelectedElements();
|
||||
}
|
||||
if (!HasSelectedElements) return;
|
||||
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
|
||||
RemoveSelectedElements();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1937,38 +2071,96 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
public void CopySelectedElements()
|
||||
{
|
||||
if (HasSelectedElements)
|
||||
if (!HasSelectedElements) return;
|
||||
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="confirm">bool</param>
|
||||
public void Confirm(bool confirm)
|
||||
{
|
||||
if (DrawingMode == DrawingModes.Crop)
|
||||
{
|
||||
ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements);
|
||||
ConfirmCrop(confirm);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfirmSelectedConfirmableElements(confirm);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// <br/>
|
||||
/// For crop-container there is a dedicated method <see cref="ConfirmCrop(bool)"/>.
|
||||
/// </summary>
|
||||
/// <param name="confirm"></param>
|
||||
/// <param name="confirm">bool</param>
|
||||
public void ConfirmSelectedConfirmableElements(bool confirm)
|
||||
{
|
||||
// create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel)
|
||||
List<IDrawableContainer> selectedDCs = new List<IDrawableContainer>(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());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called to confirm/cancel the crop-container.
|
||||
/// Called when pressing enter or using the "check" in the editor.
|
||||
/// </summary>
|
||||
/// <param name="confirm">bool</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2144,13 +2336,13 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public Rectangle GetSelectionRectangle()
|
||||
=> ToSurfaceCoordinates(selectedElements.DrawingBounds);
|
||||
|
||||
/// <summary>
|
||||
/// Duplicate all the selecteded elements
|
||||
/// Duplicate all the selected elements
|
||||
/// </summary>
|
||||
public void DuplicateSelectedElements()
|
||||
{
|
||||
|
@ -2289,7 +2481,7 @@ namespace Greenshot.Editor.Drawing
|
|||
/// <returns>false if no keys were processed</returns>
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1107,4 +1107,13 @@
|
|||
<metadata name="zoomMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>782, 17</value>
|
||||
</metadata>
|
||||
<data name="AutoCrop.Image" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\AutoCrop.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CropHorizontal.Image" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CropHorizontal.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CropVertical.Image" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CropVertical.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
|
@ -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;
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace Greenshot.Editor.Memento
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
|
|
|
@ -34,30 +34,30 @@ namespace Greenshot.Editor.Memento
|
|||
{
|
||||
private readonly List<Point> _points = new();
|
||||
private readonly List<Size> _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;
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Greenshot.Editor.Memento
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing) return;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
|
|
BIN
src/Greenshot.Editor/Resources/AutoCrop.Image.png
Normal file
BIN
src/Greenshot.Editor/Resources/AutoCrop.Image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
src/Greenshot.Editor/Resources/CropHorizontal.Image.png
Normal file
BIN
src/Greenshot.Editor/Resources/CropHorizontal.Image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
src/Greenshot.Editor/Resources/CropVertical.Image.png
Normal file
BIN
src/Greenshot.Editor/Resources/CropVertical.Image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
|
@ -62,6 +62,7 @@
|
|||
<resource name="editor_copypathtoclipboard">انسخ المسار الي الذاكرة</resource>
|
||||
<resource name="editor_copytoclipboard">نسخ</resource>
|
||||
<resource name="editor_crop">قص (C)</resource>
|
||||
<resource name="editor_cropmode_default">قص</resource>
|
||||
<resource name="editor_cursortool">اداة التحديد (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">قص</resource>
|
||||
<resource name="editor_deleteelement">احذف</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Abans de crear un nou informe d'error, us agrairem que comproveu que l'error no
|
|||
<resource name="editor_copypathtoclipboard">Copia el camí al porta-retalls</resource>
|
||||
<resource name="editor_copytoclipboard">Copia</resource>
|
||||
<resource name="editor_crop">Retalla(C)</resource>
|
||||
<resource name="editor_cropmode_default">Retalla</resource>
|
||||
<resource name="editor_cropmode_auto">Autorretalla</resource>
|
||||
<resource name="editor_cursortool">Eina de selecció (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Retalla</resource>
|
||||
<resource name="editor_deleteelement">Esborra</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev
|
|||
<resource name="editor_copypathtoclipboard">Kopírovat cestu do schránky</resource>
|
||||
<resource name="editor_copytoclipboard">Kopírovat</resource>
|
||||
<resource name="editor_crop">Oříznout (C)</resource>
|
||||
<resource name="editor_cropmode_default">Oříznout</resource>
|
||||
<resource name="editor_cropmode_auto">Automatické oříznutí</resource>
|
||||
<resource name="editor_cursortool">Výběr objektů (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Vystřihnout</resource>
|
||||
<resource name="editor_deleteelement">Odstranit</resource>
|
||||
|
|
|
@ -469,6 +469,9 @@ tidspunktet, fx 11_58_32 (plus filendelsen angivet i indstillingerne).
|
|||
<resource name="editor_crop">
|
||||
Beskær (C)
|
||||
</resource>
|
||||
<resource name="editor_cropmode_default">
|
||||
Beskær
|
||||
</resource>
|
||||
<resource name="contextmenu_captureclipboard">
|
||||
Åbn billede fra udklipsholder
|
||||
</resource>
|
||||
|
|
|
@ -77,6 +77,7 @@ schnell zu finden. Vielen Dank :)</resource>
|
|||
<resource name="editor_arrowheads_none">Keine</resource>
|
||||
<resource name="editor_arrowheads_start">Anfangspunkt</resource>
|
||||
<resource name="editor_autocrop">Automatisch zuschneiden</resource>
|
||||
<resource name="editor_autocrop_not_possible">Automatisches Zuschneiden nicht möglich</resource>
|
||||
<resource name="editor_backcolor">Hintergrundfarbe (0-9)</resource>
|
||||
<resource name="editor_blur_radius">Weichzeichner-Radius</resource>
|
||||
<resource name="editor_bold">Fett</resource>
|
||||
|
@ -92,6 +93,11 @@ schnell zu finden. Vielen Dank :)</resource>
|
|||
<resource name="editor_copypathtoclipboard">Pfad in Zwischenablage kopieren</resource>
|
||||
<resource name="editor_copytoclipboard">Kopieren</resource>
|
||||
<resource name="editor_crop">Zuschneiden (C)</resource>
|
||||
<resource name="editor_crop_mode">Zuschneiden - Modus</resource>
|
||||
<resource name="editor_cropmode_default">Zuschneiden</resource>
|
||||
<resource name="editor_cropmode_vertical">Vertikal ausschneiden</resource>
|
||||
<resource name="editor_cropmode_horizontal">Horizontal ausschneiden</resource>
|
||||
<resource name="editor_cropmode_auto">Automatisch zuschneiden</resource>
|
||||
<resource name="editor_cursortool">Auswahlwerkzeug (Esc)</resource>
|
||||
<resource name="editor_cuttoclipboard">Ausschneiden</resource>
|
||||
<resource name="editor_deleteelement">Gewähltes Element löschen</resource>
|
||||
|
|
|
@ -88,6 +88,8 @@ Dangschee, wassd scho :)</resource>
|
|||
<resource name="editor_copypathtoclipboard">Bfad in däi Zwischnblach nei</resource>
|
||||
<resource name="editor_copytoclipboard">Kobiern</resource>
|
||||
<resource name="editor_crop">Zamschneidn (C)</resource>
|
||||
<resource name="editor_cropmode_default">Zamschneidn</resource>
|
||||
<resource name="editor_cropmode_auto">Audomadisch zamschneidn</resource>
|
||||
<resource name="editor_cursortool">Angriffln (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Ausschneidn</resource>
|
||||
<resource name="editor_deleteelement">Wech mid dem Ding!</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@
|
|||
<resource name="editor_copypathtoclipboard">Αντιγραφή της θέσης του αρχείου στο πρόχειρο</resource>
|
||||
<resource name="editor_copytoclipboard">Αντιγραφή</resource>
|
||||
<resource name="editor_crop">Περικοπή (C)</resource>
|
||||
<resource name="editor_cropmode_default">Περικοπή</resource>
|
||||
<resource name="editor_cropmode_auto">Αυτόματη Περικοπή</resource>
|
||||
<resource name="editor_cursortool">Εργαλείο Επιλογής (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Αποκοπή</resource>
|
||||
<resource name="editor_deleteelement">Διαγραφή</resource>
|
||||
|
|
|
@ -78,6 +78,7 @@ Also, we would highly appreciate if you checked whether a tracker item already e
|
|||
<resource name="editor_arrowheads_none">None</resource>
|
||||
<resource name="editor_arrowheads_start">Start point</resource>
|
||||
<resource name="editor_autocrop">Auto crop</resource>
|
||||
<resource name="editor_autocrop_not_possible">Auto crop not possible</resource>
|
||||
<resource name="editor_backcolor">Fill color (0-9)</resource>
|
||||
<resource name="editor_blur_radius">Blur radius</resource>
|
||||
<resource name="editor_bold">Bold</resource>
|
||||
|
@ -93,6 +94,11 @@ Also, we would highly appreciate if you checked whether a tracker item already e
|
|||
<resource name="editor_copypathtoclipboard">Copy path to clipboard</resource>
|
||||
<resource name="editor_copytoclipboard">Copy</resource>
|
||||
<resource name="editor_crop">Crop (C)</resource>
|
||||
<resource name="editor_crop_mode">Crop mode</resource>
|
||||
<resource name="editor_cropmode_default">Crop</resource>
|
||||
<resource name="editor_cropmode_vertical">Crop out vertically</resource>
|
||||
<resource name="editor_cropmode_horizontal">Crop out horizontally</resource>
|
||||
<resource name="editor_cropmode_auto">Auto crop</resource>
|
||||
<resource name="editor_cursortool">Selection Tool (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Cut</resource>
|
||||
<resource name="editor_deleteelement">Delete</resource>
|
||||
|
|
|
@ -80,6 +80,8 @@ Antes de crear un nuevo informe de error, te agradeceríamos que comprobaras que
|
|||
<resource name="editor_copypathtoclipboard">Copiar ruta al portapapeles</resource>
|
||||
<resource name="editor_copytoclipboard">Copiar</resource>
|
||||
<resource name="editor_crop">Recortar(C)</resource>
|
||||
<resource name="editor_cropmode_default">Recortar</resource>
|
||||
<resource name="editor_cropmode_auto">Autorrecortar</resource>
|
||||
<resource name="editor_cursortool">Herramienta de selección (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Cortar</resource>
|
||||
<resource name="editor_deleteelement">Borrar</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Me oleksime väga tänulik, kui te enne kontrolliksite, ega sellest veast pole j
|
|||
<resource name="editor_copypathtoclipboard">Kopeerige asukoht lõikelauale</resource>
|
||||
<resource name="editor_copytoclipboard">Kopeeri</resource>
|
||||
<resource name="editor_crop">Lõika (C)</resource>
|
||||
<resource name="editor_cropmode_default">Lõika</resource>
|
||||
<resource name="editor_cropmode_auto">Automaatne lõikus</resource>
|
||||
<resource name="editor_cursortool">Valiku tööriist (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Lõika</resource>
|
||||
<resource name="editor_deleteelement">Kustuta</resource>
|
||||
|
|
|
@ -67,6 +67,7 @@ Could not save Greenshot's configuration file. Please check access permissions f
|
|||
<resource name="editor_copytoclipboard">رونویس</resource>
|
||||
<resource name="editor_crop">چیدن
|
||||
(C دکمه)</resource>
|
||||
<resource name="editor_cropmode_default">چیدن</resource>
|
||||
<resource name="editor_cursortool">انتخابگر
|
||||
(ESC دکمه)</resource>
|
||||
<resource name="editor_cuttoclipboard">برش</resource>
|
||||
|
|
|
@ -62,6 +62,7 @@ Olisi myös hyvä jos voisit tarkistaa onko virhe jo raportoitu aikaisemmin (voi
|
|||
<resource name="editor_copypathtoclipboard">Kopioi tiedostopolku leikepöydälle</resource>
|
||||
<resource name="editor_copytoclipboard">Kopioi</resource>
|
||||
<resource name="editor_crop">Rajaa (C)</resource>
|
||||
<resource name="editor_cropmode_default">Rajaa</resource>
|
||||
<resource name="editor_cursortool">Valintatyökalu (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Leikkaa</resource>
|
||||
<resource name="editor_deleteelement">Poista</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si
|
|||
<resource name="editor_copytoclipboard">Copier</resource>
|
||||
<resource name="editor_counter">Ajouter un compteur</resource>
|
||||
<resource name="editor_crop">Recadrer (C)</resource>
|
||||
<resource name="editor_cropmode_default">Recadrer</resource>
|
||||
<resource name="editor_cropmode_auto">Cadrage automatique</resource>
|
||||
<resource name="editor_cursortool">Outil de sélection (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Couper</resource>
|
||||
<resource name="editor_deleteelement">Supprimer</resource>
|
||||
|
|
|
@ -78,6 +78,8 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si
|
|||
<resource name="editor_copypathtoclipboard">Copier le chemin vers le presse-papier</resource>
|
||||
<resource name="editor_copytoclipboard">Copier</resource>
|
||||
<resource name="editor_crop">Rogner (C)</resource>
|
||||
<resource name="editor_cropmode_default">Rogner</resource>
|
||||
<resource name="editor_cropmode_auto">Rognage automatique</resource>
|
||||
<resource name="editor_cursortool">Outil de sélection (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Couper</resource>
|
||||
<resource name="editor_deleteelement">Supprimer</resource>
|
||||
|
|
|
@ -63,6 +63,7 @@ Details about the GNU General Public License:</resource>
|
|||
<resource name="editor_copypathtoclipboard">העתק נתיב אל הלוח</resource>
|
||||
<resource name="editor_copytoclipboard">העתקה</resource>
|
||||
<resource name="editor_crop">חתוך (C)</resource>
|
||||
<resource name="editor_cropmode_default">חתוך</resource>
|
||||
<resource name="editor_cursortool">כלי בחירה (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">חיתוך</resource>
|
||||
<resource name="editor_deleteelement">מחיקה</resource>
|
||||
|
|
|
@ -63,6 +63,7 @@ Kérjük adjon összefoglaló leírást és csatoljon minden olyan információt
|
|||
<resource name="editor_copypathtoclipboard">Másolja a vágólapra</resource>
|
||||
<resource name="editor_copytoclipboard">Másolás</resource>
|
||||
<resource name="editor_crop">Vágás eszköz (C)</resource>
|
||||
<resource name="editor_cropmode_default">Vágás eszköz</resource>
|
||||
<resource name="editor_cursortool">Kiválasztó eszköz (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Kivágás</resource>
|
||||
<resource name="editor_deleteelement">Törlés</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Juga, kami sangat terbantu apabila anda mengecek laporan lain yang sama dengan k
|
|||
<resource name="editor_copytoclipboard">Kopi</resource>
|
||||
<resource name="editor_counter">Buat penomor</resource>
|
||||
<resource name="editor_crop">Potong (C)</resource>
|
||||
<resource name="editor_cropmode_default">Potong</resource>
|
||||
<resource name="editor_cropmode_auto">Auto potong</resource>
|
||||
<resource name="editor_cursortool">Alat seleksi (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Gunting</resource>
|
||||
<resource name="editor_deleteelement">Hapus</resource>
|
||||
|
|
|
@ -98,6 +98,8 @@ Controlla i permessi di accesso per '{0}'.</resource>
|
|||
<resource name="editor_copypathtoclipboard">Copia percorso negli appunti</resource>
|
||||
<resource name="editor_copytoclipboard">Copia</resource>
|
||||
<resource name="editor_crop">Ritaglia (C)</resource>
|
||||
<resource name="editor_cropmode_default">Ritaglia</resource>
|
||||
<resource name="editor_cropmode_auto">Ritaglia Automaticamente</resource>
|
||||
<resource name="editor_cursortool">Strumento di selezione (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Taglia</resource>
|
||||
<resource name="editor_deleteelement">Elimina</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Greenshot には一切の保障がありません。GNU General Public License
|
|||
<resource name="editor_copytoclipboard">コピー</resource>
|
||||
<resource name="editor_counter">カウンターを挿入する (I)</resource>
|
||||
<resource name="editor_crop">切り抜き (C)</resource>
|
||||
<resource name="editor_cropmode_default">切り抜き</resource>
|
||||
<resource name="editor_cropmode_auto">自動切り抜き</resource>
|
||||
<resource name="editor_cursortool">選択ツール (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">切り取り</resource>
|
||||
<resource name="editor_deleteelement">削除</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Rnu ɣur-s, nḥemmel aṭas ma yella tesneqdeḍ aneqqis igebren ugur-agi. (Tze
|
|||
<resource name="editor_copytoclipboard">Nɣel</resource>
|
||||
<resource name="editor_counter">Rnu Amesmiḍan</resource>
|
||||
<resource name="editor_crop">Seggem (C)</resource>
|
||||
<resource name="editor_cropmode_default">Seggem</resource>
|
||||
<resource name="editor_cropmode_auto">Aseggem awurman</resource>
|
||||
<resource name="editor_cursortool">Afecku n ufran (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Gzem</resource>
|
||||
<resource name="editor_deleteelement">Kkes</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Also, we would highly appreciate if you checked whether a tracker item already e
|
|||
<resource name="editor_copypathtoclipboard">경로를 클립보드로 복사</resource>
|
||||
<resource name="editor_copytoclipboard">복사</resource>
|
||||
<resource name="editor_crop">잘라내기 (C)</resource>
|
||||
<resource name="editor_cropmode_default">잘라내기</resource>
|
||||
<resource name="editor_cropmode_auto">자동 잘라내기</resource>
|
||||
<resource name="editor_cursortool">선택도구 (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">잘라내기</resource>
|
||||
<resource name="editor_deleteelement">삭제</resource>
|
||||
|
|
|
@ -61,6 +61,7 @@ Dėkojame už pagalbą :)</resource>
|
|||
<resource name="editor_copypathtoclipboard">Kopijuoti pilną failo vardą</resource>
|
||||
<resource name="editor_copytoclipboard">Коpijuoti</resource>
|
||||
<resource name="editor_crop">Iškirpti (C)</resource>
|
||||
<resource name="editor_cropmode_default">Iškirpti</resource>
|
||||
<resource name="editor_cursortool">Objektų pasirinkimas (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Apkirpti</resource>
|
||||
<resource name="editor_deleteelement">Naikinti</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Mēs būtu Tev pateicīgi, ja Tu vispirms pārbaudītu, vai kāds cits jau nav z
|
|||
<resource name="editor_copypathtoclipboard">Ievietot ceļu starpliktuvē</resource>
|
||||
<resource name="editor_copytoclipboard">Kopēt</resource>
|
||||
<resource name="editor_crop">Apcirst (C)</resource>
|
||||
<resource name="editor_cropmode_default">Apcirst</resource>
|
||||
<resource name="editor_cropmode_auto">Automātiski apcirst</resource>
|
||||
<resource name="editor_cursortool">Atlases rīks (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Izgriezt</resource>
|
||||
<resource name="editor_deleteelement">Izdzēst</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Controleer ook even of dit probleem mogelijk al gemeld is! Gebruik de zoekfuncti
|
|||
<resource name="editor_copypathtoclipboard">Locatie naar klembord kopiëren</resource>
|
||||
<resource name="editor_copytoclipboard">Kopiëren</resource>
|
||||
<resource name="editor_crop">Bijsnijden (C)</resource>
|
||||
<resource name="editor_cropmode_default">Bijsnijden</resource>
|
||||
<resource name="editor_cropmode_auto">Automatisch bijsnijden</resource>
|
||||
<resource name="editor_cursortool">Selectiegereedschap (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Knippen</resource>
|
||||
<resource name="editor_deleteelement">Verwijderen</resource>
|
||||
|
|
|
@ -80,6 +80,8 @@ Me sett òg pris på om du ved hjelp av søkefunksjonen på sida kan sjekke om d
|
|||
<resource name="editor_copypathtoclipboard">Kopier filstigen til utklyppstavla</resource>
|
||||
<resource name="editor_copytoclipboard">Kopier</resource>
|
||||
<resource name="editor_crop">Skjer bildet [C]</resource>
|
||||
<resource name="editor_cropmode_default">Skjer bildet</resource>
|
||||
<resource name="editor_cropmode_auto">Auto-skjer</resource>
|
||||
<resource name="editor_cursortool">Peikarverktøy [Esc]</resource>
|
||||
<resource name="editor_cuttoclipboard">Klypp ut</resource>
|
||||
<resource name="editor_deleteelement">Slett</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Będziemy wdzięczni, jeśli najpierw sprawdzisz, czy takie zdarzenie nie zosta
|
|||
<resource name="editor_copypathtoclipboard">Kopiuj ścieżkę do schowka</resource>
|
||||
<resource name="editor_copytoclipboard">Kopiuj</resource>
|
||||
<resource name="editor_crop">Przytnij (C)</resource>
|
||||
<resource name="editor_cropmode_default">Przytnij (C)</resource>
|
||||
<resource name="editor_cropmode_auto">Przytnij automatycznie</resource>
|
||||
<resource name="editor_cursortool">Narzędzie wyboru (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Wytnij</resource>
|
||||
<resource name="editor_deleteelement">Usuń</resource>
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
<resource name="editor_copypathtoclipboard">Copiar o caminho da pasta atual do arquivo para a Área de transferência</resource>
|
||||
<resource name="editor_copytoclipboard">Copiar</resource>
|
||||
<resource name="editor_crop">Cortar (C)</resource>
|
||||
<resource name="editor_cropmode_default">Cortar</resource>
|
||||
<resource name="editor_cursortool">Ferramenta de Seleção (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Cortar</resource>
|
||||
<resource name="editor_deleteelement">Apagar</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Também apreciaremos muito se puder verificar se não existe já um relatório d
|
|||
<resource name="editor_copypathtoclipboard">Copiar atalho para a Área de transferência</resource>
|
||||
<resource name="editor_copytoclipboard">Copiar</resource>
|
||||
<resource name="editor_crop">Recortar (C)</resource>
|
||||
<resource name="editor_cropmode_default">Recortar</resource>
|
||||
<resource name="editor_cropmode_auto">Recortar auto</resource>
|
||||
<resource name="editor_cursortool">Ferramenta de Selecção (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Cortar</resource>
|
||||
<resource name="editor_deleteelement">Eliminar</resource>
|
||||
|
|
|
@ -471,6 +471,9 @@ timpul curent, ex. 11_58_32 (plus extensia fișierului definită în setări)
|
|||
<resource name="editor_crop">
|
||||
Taie (C)
|
||||
</resource>
|
||||
<resource name="editor_cropmode_default">
|
||||
Taie
|
||||
</resource>
|
||||
<resource name="contextmenu_captureclipboard">
|
||||
Deschide imaginea din clipboard
|
||||
</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
|
|||
<resource name="editor_copypathtoclipboard">Копировать путь в буфер обмена</resource>
|
||||
<resource name="editor_copytoclipboard">Копировать</resource>
|
||||
<resource name="editor_crop">Обрезка (C)</resource>
|
||||
<resource name="editor_cropmode_default">Обрезка</resource>
|
||||
<resource name="editor_cropmode_auto">Автообрезка</resource>
|
||||
<resource name="editor_cursortool">Инструмент «Выделение» (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Вырезать</resource>
|
||||
<resource name="editor_deleteelement">Удалить</resource>
|
||||
|
|
|
@ -80,6 +80,8 @@ Tiež by sme velmi ocenili, keby ste najskôr skontrolovali, či už neexistuje
|
|||
<resource name="editor_copypathtoclipboard">Kopírovať cestu do schránky</resource>
|
||||
<resource name="editor_copytoclipboard">Kopírovať</resource>
|
||||
<resource name="editor_crop">Orezať (C)</resource>
|
||||
<resource name="editor_cropmode_default">Orezať</resource>
|
||||
<resource name="editor_cropmode_auto">Automatické orezanie</resource>
|
||||
<resource name="editor_cursortool">Nástroj pre výber (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Vystrihnúť</resource>
|
||||
<resource name="editor_deleteelement">Zmazať</resource>
|
||||
|
|
|
@ -78,6 +78,8 @@ Pred objavo preverite tudi ali je napaka že prijavlja s strani kakšnega drugeg
|
|||
<resource name="editor_copypathtoclipboard">Kopiraj pot na odložišče</resource>
|
||||
<resource name="editor_copytoclipboard">Kopiraj</resource>
|
||||
<resource name="editor_crop">Obreži (C)</resource>
|
||||
<resource name="editor_cropmode_default">Obreži</resource>
|
||||
<resource name="editor_cropmode_auto">Samodejno obreži</resource>
|
||||
<resource name="editor_cursortool">Orodje za izbor (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Kopiraj</resource>
|
||||
<resource name="editor_deleteelement">Briši</resource>
|
||||
|
|
|
@ -78,6 +78,8 @@
|
|||
<resource name="editor_copypathtoclipboard">Умножи путању</resource>
|
||||
<resource name="editor_copytoclipboard">Умножи</resource>
|
||||
<resource name="editor_crop">Опсеци (C)</resource>
|
||||
<resource name="editor_cropmode_default">Опсеци</resource>
|
||||
<resource name="editor_cropmode_auto">Аутоматско опсецање</resource>
|
||||
<resource name="editor_cursortool">Алатка за одабир (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Исеци</resource>
|
||||
<resource name="editor_deleteelement">Обриши</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Innan du skickar uppskattar vi verkligen om du kontrollerar om felet redan blivi
|
|||
<resource name="editor_copypathtoclipboard">Kopiera sökväg till urklipp</resource>
|
||||
<resource name="editor_copytoclipboard">Kopiera</resource>
|
||||
<resource name="editor_crop">Beskär (C)</resource>
|
||||
<resource name="editor_cropmode_default">Beskär</resource>
|
||||
<resource name="editor_cropmode_auto">Autobeskärning</resource>
|
||||
<resource name="editor_cursortool">Markeringsverktyg (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Klipp ut</resource>
|
||||
<resource name="editor_deleteelement">Radera</resource>
|
||||
|
|
|
@ -78,6 +78,8 @@ Ayrıca bu hata için bir izleyici kaydının açılmış olup olmadığını da
|
|||
<resource name="editor_copypathtoclipboard">Yolu panoya kopyala</resource>
|
||||
<resource name="editor_copytoclipboard">Kopyala</resource>
|
||||
<resource name="editor_crop">Kırp (C)</resource>
|
||||
<resource name="editor_cropmode_default">Kırp</resource>
|
||||
<resource name="editor_cropmode_auto">Otomatik kırpma</resource>
|
||||
<resource name="editor_cursortool">Seçim Aracı (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Kes</resource>
|
||||
<resource name="editor_deleteelement">Sil</resource>
|
||||
|
|
|
@ -92,6 +92,8 @@ Greenshot постачається АБСОЛЮТНО БЕЗ ГАРАНТІЇ.
|
|||
<resource name="editor_copypathtoclipboard">Копіювати шлях у буфер обміну</resource>
|
||||
<resource name="editor_copytoclipboard">Копіювати</resource>
|
||||
<resource name="editor_crop">Обрізати (С)</resource>
|
||||
<resource name="editor_cropmode_default">Обрізати</resource>
|
||||
<resource name="editor_cropmode_auto">Автоматичне обрізання</resource>
|
||||
<resource name="editor_cursortool">Інструмент вибору (Esc)</resource>
|
||||
<resource name="editor_cuttoclipboard">Вирізати</resource>
|
||||
<resource name="editor_deleteelement">Видалити</resource>
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
<resource name="editor_copypathtoclipboard">Chép đuờng dẫn tới clipboard.</resource>
|
||||
<resource name="editor_copytoclipboard">Chép</resource>
|
||||
<resource name="editor_crop">Cắt (C)</resource>
|
||||
<resource name="editor_cropmode_default">Cắt</resource>
|
||||
<resource name="editor_cursortool">Công cụ chọn (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">Cắt</resource>
|
||||
<resource name="editor_deleteelement">Xóa</resource>
|
||||
|
|
|
@ -84,6 +84,8 @@
|
|||
<resource name="editor_copypathtoclipboard">复制路径到剪贴板</resource>
|
||||
<resource name="editor_copytoclipboard">复制</resource>
|
||||
<resource name="editor_crop">裁剪 (C)</resource>
|
||||
<resource name="editor_cropmode_default">裁剪</resource>
|
||||
<resource name="editor_cropmode_auto">自动裁剪</resource>
|
||||
<resource name="editor_cursortool">选择工具 (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">剪切</resource>
|
||||
<resource name="editor_deleteelement">刪除物件</resource>
|
||||
|
|
|
@ -93,6 +93,8 @@ Greenshot 不對這個程式做任何擔保。這個程式是自由軟體,您
|
|||
<resource name="editor_copypathtoclipboard">複製路徑到剪貼簿</resource>
|
||||
<resource name="editor_copytoclipboard">複製</resource>
|
||||
<resource name="editor_crop">裁剪 (C)</resource>
|
||||
<resource name="editor_cropmode_default">裁剪</resource>
|
||||
<resource name="editor_cropmode_auto">自動裁剪</resource>
|
||||
<resource name="editor_cursortool">選取工具 (ESC)</resource>
|
||||
<resource name="editor_cuttoclipboard">剪下</resource>
|
||||
<resource name="editor_deleteelement">刪除</resource>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue