Merge remote-tracking branch 'origin/release/1.3' into feature/dpi-aware-grippers

# Conflicts:
#	Greenshot/Drawing/Adorners/TargetAdorner.cs
This commit is contained in:
jklingen 2020-07-03 20:32:52 +02:00
commit 75a93e2aa3
30 changed files with 1847 additions and 903 deletions

View file

@ -56,7 +56,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))"> <ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))">
<PackageReference Include="Nerdbank.GitVersioning" Version="3.1.74"> <PackageReference Include="Nerdbank.GitVersioning" Version="3.1.91">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>

View file

@ -118,6 +118,18 @@ namespace Greenshot.Drawing.Adorners
} }
} }
/// <summary>
/// Return the bounds of the Adorner as displayed on the parent Surface
/// </summary>
protected virtual Rectangle BoundsOnSurface
{
get
{
Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location);
return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height);
}
}
/// <summary> /// <summary>
/// The adorner is active if the edit status is not idle or undrawn /// The adorner is active if the edit status is not idle or undrawn
/// </summary> /// </summary>

View file

@ -142,7 +142,7 @@ namespace Greenshot.Drawing.Adorners
{ {
Graphics targetGraphics = paintEventArgs.Graphics; Graphics targetGraphics = paintEventArgs.Graphics;
var bounds = Bounds; var bounds = BoundsOnSurface;
GraphicsState state = targetGraphics.Save(); GraphicsState state = targetGraphics.Save();
targetGraphics.SmoothingMode = SmoothingMode.None; targetGraphics.SmoothingMode = SmoothingMode.None;

View file

@ -169,7 +169,7 @@ namespace Greenshot.Drawing.Adorners
{ {
Graphics targetGraphics = paintEventArgs.Graphics; Graphics targetGraphics = paintEventArgs.Graphics;
var bounds = Bounds; var bounds = BoundsOnSurface;
GraphicsState state = targetGraphics.Save(); GraphicsState state = targetGraphics.Save();
targetGraphics.SmoothingMode = SmoothingMode.None; targetGraphics.SmoothingMode = SmoothingMode.None;

View file

@ -1,119 +1,119 @@
/* /*
* Greenshot - a free and open source screenshot tool * Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
* *
* For more information see: http://getgreenshot.org/ * For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or * the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Windows.Forms; using System.Windows.Forms;
using GreenshotPlugin.Interfaces.Drawing; using GreenshotPlugin.Interfaces.Drawing;
namespace Greenshot.Drawing.Adorners namespace Greenshot.Drawing.Adorners
{ {
/// <summary> /// <summary>
/// This implements the special "gripper" for the Speech-Bubble tail /// This implements the special "gripper" for the Speech-Bubble tail
/// </summary> /// </summary>
public class TargetAdorner : AbstractAdorner public class TargetAdorner : AbstractAdorner
{ {
public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) public TargetAdorner(IDrawableContainer owner, Point location) : base(owner)
{ {
Location = location; Location = location;
} }
/// <summary> /// <summary>
/// Handle the mouse down /// Handle the mouse down
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="mouseEventArgs"></param> /// <param name="mouseEventArgs"></param>
public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) public override void MouseDown(object sender, MouseEventArgs mouseEventArgs)
{ {
EditStatus = EditStatus.MOVING; EditStatus = EditStatus.MOVING;
} }
/// <summary> /// <summary>
/// Handle the mouse move /// Handle the mouse move
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="mouseEventArgs"></param> /// <param name="mouseEventArgs"></param>
public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) public override void MouseMove(object sender, MouseEventArgs mouseEventArgs)
{ {
if (EditStatus != EditStatus.MOVING) if (EditStatus != EditStatus.MOVING)
{ {
return; return;
} }
Owner.Invalidate(); Owner.Invalidate();
Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y);
Rectangle surfaceBounds = new Rectangle(0, 0, Owner.Parent.Width, Owner.Parent.Height); Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height);
// Check if gripper inside the parent (surface), if not we need to move it inside // Check if gripper inside the parent (surface), if not we need to move it inside
// This was made for BUG-1682 // This was made for BUG-1682
if (!surfaceBounds.Contains(newGripperLocation)) if (!imageBounds.Contains(newGripperLocation))
{ {
if (newGripperLocation.X > surfaceBounds.Right) if (newGripperLocation.X > imageBounds.Right)
{ {
newGripperLocation.X = surfaceBounds.Right - 5; newGripperLocation.X = imageBounds.Right - 5;
} }
if (newGripperLocation.X < surfaceBounds.Left) if (newGripperLocation.X < imageBounds.Left)
{ {
newGripperLocation.X = surfaceBounds.Left; newGripperLocation.X = imageBounds.Left;
} }
if (newGripperLocation.Y > surfaceBounds.Bottom) if (newGripperLocation.Y > imageBounds.Bottom)
{ {
newGripperLocation.Y = surfaceBounds.Bottom - 5; newGripperLocation.Y = imageBounds.Bottom - 5;
} }
if (newGripperLocation.Y < surfaceBounds.Top) if (newGripperLocation.Y < imageBounds.Top)
{ {
newGripperLocation.Y = surfaceBounds.Top; newGripperLocation.Y = imageBounds.Top;
} }
} }
Location = newGripperLocation; Location = newGripperLocation;
Owner.Invalidate(); Owner.Invalidate();
} }
/// <summary> /// <summary>
/// Draw the adorner /// Draw the adorner
/// </summary> /// </summary>
/// <param name="paintEventArgs">PaintEventArgs</param> /// <param name="paintEventArgs">PaintEventArgs</param>
public override void Paint(PaintEventArgs paintEventArgs) public override void Paint(PaintEventArgs paintEventArgs)
{ {
Graphics targetGraphics = paintEventArgs.Graphics; Graphics targetGraphics = paintEventArgs.Graphics;
var bounds = Bounds; var bounds = BoundsOnSurface;
targetGraphics.FillRectangle(Brushes.Green, bounds); targetGraphics.FillRectangle(Brushes.Green, bounds);
targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); targetGraphics.DrawRectangle(new Pen(Brushes.Green), bounds);
} }
/// <summary> /// <summary>
/// Made sure this adorner is transformed /// Made sure this adorner is transformed
/// </summary> /// </summary>
/// <param name="matrix">Matrix</param> /// <param name="matrix">Matrix</param>
public override void Transform(Matrix matrix) public override void Transform(Matrix matrix)
{ {
if (matrix == null) if (matrix == null)
{ {
return; return;
} }
Point[] points = new[] { Location }; Point[] points = new[] { Location };
matrix.TransformPoints(points); matrix.TransformPoints(points);
Location = points[0]; Location = points[0];
} }
} }
} }

View file

@ -56,7 +56,15 @@ namespace Greenshot.Drawing {
/// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw
/// (we create a transparent brown over the complete picture) /// (we create a transparent brown over the complete picture)
/// </summary> /// </summary>
public override Rectangle DrawingBounds => new Rectangle(0,0,_parent?.Width??0, _parent?.Height ?? 0); public override Rectangle DrawingBounds {
get {
if (_parent?.Image is Image image) {
return new Rectangle(0, 0, image.Width, image.Height);
} else {
return Rectangle.Empty;
}
}
}
public override void Draw(Graphics g, RenderMode rm) { public override void Draw(Graphics g, RenderMode rm) {
if (_parent == null) if (_parent == null)
@ -67,17 +75,18 @@ namespace Greenshot.Drawing {
using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100));
Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1);
Size imageSize = _parent.Image.Size;
DrawSelectionBorder(g, selectionRect); DrawSelectionBorder(g, selectionRect);
// top // top
g.FillRectangle(cropBrush, new Rectangle(0, 0, _parent.Width, cropRectangle.Top)); g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top));
// left // left
g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height));
// right // right
g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height));
// bottom // bottom
g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height))); g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height)));
} }
public override bool HasContextMenu { public override bool HasContextMenu {

View file

@ -33,7 +33,6 @@ using System.ComponentModel;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Windows.Forms;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Drawing.Adorners; using GreenshotPlugin.Interfaces.Drawing.Adorners;
@ -298,34 +297,7 @@ namespace Greenshot.Drawing
public virtual void Invalidate() { public virtual void Invalidate() {
if (Status != EditStatus.UNDRAWN) { if (Status != EditStatus.UNDRAWN) {
_parent?.Invalidate(DrawingBounds); _parent?.InvalidateElements(DrawingBounds);
}
}
public void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) {
if (_parent == null)
{
return;
}
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
if (horizontalAlignment == HorizontalAlignment.Left) {
Left = lineThickness/2;
}
if (horizontalAlignment == HorizontalAlignment.Right) {
Left = _parent.Width - Width - lineThickness/2;
}
if (horizontalAlignment == HorizontalAlignment.Center) {
Left = (_parent.Width / 2) - (Width / 2) - lineThickness/2;
}
if (verticalAlignment == VerticalAlignment.TOP) {
Top = lineThickness/2;
}
if (verticalAlignment == VerticalAlignment.BOTTOM) {
Top = _parent.Height - Height - lineThickness/2;
}
if (verticalAlignment == VerticalAlignment.CENTER) {
Top = (_parent.Height / 2) - (Height / 2) - lineThickness/2;
} }
} }

View file

@ -235,6 +235,30 @@ namespace Greenshot.Drawing {
return false; return false;
} }
/// <summary>
/// A rectangle containing DrawingBounds of all drawableContainers in this list,
/// or empty rectangle if nothing is there.
/// </summary>
public Rectangle DrawingBounds
{
get
{
if (Count == 0)
{
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;
}
}
}
/// <summary> /// <summary>
/// Triggers all elements in the list ot be redrawn. /// Triggers all elements in the list ot be redrawn.
/// </summary> /// </summary>
@ -286,7 +310,7 @@ namespace Greenshot.Drawing {
{ {
region = Rectangle.Union(region, dc.DrawingBounds); region = Rectangle.Union(region, dc.DrawingBounds);
} }
Parent.Invalidate(region); Parent.InvalidateElements(region);
} }
/// <summary> /// <summary>
/// Indicates whether the given list of elements can be pulled up, /// Indicates whether the given list of elements can be pulled up,
@ -523,9 +547,9 @@ namespace Greenshot.Drawing {
} }
} }
public virtual void ShowContextMenu(MouseEventArgs e, ISurface surface) public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface)
{ {
if (!(surface is Surface)) if (!(iSurface is Surface surface))
{ {
return; return;
} }
@ -542,8 +566,7 @@ namespace Greenshot.Drawing {
ContextMenuStrip menu = new ContextMenuStrip(); ContextMenuStrip menu = new ContextMenuStrip();
AddContextMenuItems(menu, surface); AddContextMenuItems(menu, surface);
if (menu.Items.Count > 0) { if (menu.Items.Count > 0) {
// TODO: cast should be somehow avoided menu.Show(surface, surface.ToSurfaceCoordinates(e.Location));
menu.Show((Surface)surface, e.Location);
while (true) { while (true) {
if (menu.Visible) { if (menu.Visible) {
Application.DoEvents(); Application.DoEvents();

View file

@ -35,13 +35,13 @@ namespace Greenshot.Drawing.Fields.Binding {
} }
protected override float convert(decimal o) { protected override float convert(decimal o) {
return Convert.ToInt16(o); return Convert.ToSingle(o);
} }
public static DecimalFloatConverter GetInstance() public static DecimalFloatConverter GetInstance()
{ {
return _uniqueInstance ??= new DecimalFloatConverter(); return _uniqueInstance ??= new DecimalFloatConverter();
} }
} }
} }

View file

@ -1,4 +1,4 @@
/* /*
* Greenshot - a free and open source screenshot tool * Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
* *
@ -35,13 +35,13 @@ namespace Greenshot.Drawing.Fields.Binding {
} }
protected override int convert(decimal o) { protected override int convert(decimal o) {
return Convert.ToInt16(o); return Convert.ToInt32(o);
} }
public static DecimalIntConverter GetInstance() public static DecimalIntConverter GetInstance()
{ {
return _uniqueInstance ??= new DecimalIntConverter(); return _uniqueInstance ??= new DecimalIntConverter();
} }
} }
} }

View file

@ -47,8 +47,8 @@ namespace Greenshot.Drawing {
/// Constructor /// Constructor
/// </summary> /// </summary>
public FreehandContainer(Surface parent) : base(parent) { public FreehandContainer(Surface parent) : base(parent) {
Width = parent.Width; Width = parent.Image.Width;
Height = parent.Height; Height = parent.Image.Height;
Top = 0; Top = 0;
Left = 0; Left = 0;
} }
@ -236,7 +236,14 @@ namespace Greenshot.Drawing {
int safetymargin = 10; int safetymargin = 10;
return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin)); return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin));
} }
return new Rectangle(0, 0, _parent?.Width??0, _parent?.Height?? 0); if (_parent?.Image is Image image)
{
return new Rectangle(0, 0, image.Width, image.Height);
}
else
{
return Rectangle.Empty;
}
} }
} }

View file

@ -1,4 +1,4 @@
/* /*
* Greenshot - a free and open source screenshot tool * Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
* *
@ -298,10 +298,39 @@ namespace Greenshot.Drawing
set set
{ {
_image = value; _image = value;
Size = _image.Size; UpdateSize();
} }
} }
[NonSerialized]
private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0);
[NonSerialized]
private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0);
[NonSerialized]
private Fraction _zoomFactor = Fraction.Identity;
public Fraction ZoomFactor
{
get => _zoomFactor;
set
{
_zoomFactor = value;
var inverse = _zoomFactor.Inverse();
_zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0);
_inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0);
UpdateSize();
}
}
/// <summary>
/// Sets the surface size as zoomed image size.
/// </summary>
private void UpdateSize()
{
var size = _image.Size;
Size = new Size((int)(size.Width * _zoomFactor), (int)(size.Height * _zoomFactor));
}
/// <summary> /// <summary>
/// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements.
/// e.g. used to decided if and which line thickness is shown when multiple elements are selected. /// e.g. used to decided if and which line thickness is shown when multiple elements are selected.
@ -458,7 +487,6 @@ namespace Greenshot.Drawing
// Set new values // Set new values
Image = newImage; Image = newImage;
Size = newImage.Size;
_modified = true; _modified = true;
} }
@ -790,9 +818,9 @@ namespace Greenshot.Drawing
return cursorContainer; return cursorContainer;
} }
public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor)
{ {
TextContainer textContainer = new TextContainer(this) {Text = text}; TextContainer textContainer = new TextContainer(this) {Text = text, Left = x, Top = y};
textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name);
textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); textContainer.SetFieldValue(FieldType.FONT_BOLD, bold);
textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic);
@ -803,8 +831,6 @@ namespace Greenshot.Drawing
textContainer.SetFieldValue(FieldType.SHADOW, shadow); textContainer.SetFieldValue(FieldType.SHADOW, shadow);
// Make sure the Text fits // Make sure the Text fits
textContainer.FitToText(); textContainer.FitToText();
// Align to Surface
textContainer.AlignToParent(horizontalAlignment, verticalAlignment);
//AggregatedProperties.UpdateElement(textContainer); //AggregatedProperties.UpdateElement(textContainer);
AddElement(textContainer); AddElement(textContainer);
@ -978,13 +1004,13 @@ namespace Greenshot.Drawing
{ {
cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top);
} }
if (cropRectangle.Left + cropRectangle.Width > Width) if (cropRectangle.Left + cropRectangle.Width > Image.Width)
{ {
cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height); cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height);
} }
if (cropRectangle.Top + cropRectangle.Height > Height) if (cropRectangle.Top + cropRectangle.Height > Image.Height)
{ {
cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top);
} }
if (cropRectangle.Height > 0 && cropRectangle.Width > 0) if (cropRectangle.Height > 0 && cropRectangle.Width > 0)
{ {
@ -1097,6 +1123,12 @@ namespace Greenshot.Drawing
return null; return null;
} }
/// <summary>
/// Translate mouse coordinates as if they were applied directly to unscaled image.
/// </summary>
private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e)
=> new MouseEventArgs(e.Button, e.Clicks, (int)(e.X / _zoomFactor), (int)(e.Y / _zoomFactor), e.Delta);
/// <summary> /// <summary>
/// This event handler is called when someone presses the mouse on a surface. /// This event handler is called when someone presses the mouse on a surface.
/// </summary> /// </summary>
@ -1104,6 +1136,7 @@ namespace Greenshot.Drawing
/// <param name="e"></param> /// <param name="e"></param>
private void SurfaceMouseDown(object sender, MouseEventArgs e) private void SurfaceMouseDown(object sender, MouseEventArgs e)
{ {
e = InverseZoomMouseCoordinates(e);
// Handle Adorners // Handle Adorners
var adorner = FindActiveAdorner(e); var adorner = FindActiveAdorner(e);
@ -1198,6 +1231,7 @@ namespace Greenshot.Drawing
/// <param name="e"></param> /// <param name="e"></param>
private void SurfaceMouseUp(object sender, MouseEventArgs e) private void SurfaceMouseUp(object sender, MouseEventArgs e)
{ {
e = InverseZoomMouseCoordinates(e);
// Handle Adorners // Handle Adorners
var adorner = FindActiveAdorner(e); var adorner = FindActiveAdorner(e);
@ -1287,6 +1321,8 @@ namespace Greenshot.Drawing
/// <param name="e"></param> /// <param name="e"></param>
private void SurfaceMouseMove(object sender, MouseEventArgs e) private void SurfaceMouseMove(object sender, MouseEventArgs e)
{ {
e = InverseZoomMouseCoordinates(e);
// Handle Adorners // Handle Adorners
var adorner = FindActiveAdorner(e); var adorner = FindActiveAdorner(e);
if (adorner != null) if (adorner != null)
@ -1382,6 +1418,25 @@ namespace Greenshot.Drawing
return GetImage(RenderMode.EXPORT); return GetImage(RenderMode.EXPORT);
} }
private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0)
{
rc = new Rectangle(
(int)(rc.X * scale),
(int)(rc.Y * scale),
(int)(rc.Width * scale) + 1,
(int)(rc.Height * scale) + 1
);
if (scale > 1)
{
inflateAmount = (int)(inflateAmount * scale);
}
rc.Inflate(inflateAmount, inflateAmount);
return rc;
}
public void InvalidateElements(Rectangle rc)
=> Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1));
/// <summary> /// <summary>
/// This is the event handler for the Paint Event, try to draw as little as possible! /// This is the event handler for the Paint Event, try to draw as little as possible!
/// </summary> /// </summary>
@ -1390,14 +1445,34 @@ namespace Greenshot.Drawing
private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) private void SurfacePaint(object sender, PaintEventArgs paintEventArgs)
{ {
Graphics targetGraphics = paintEventArgs.Graphics; Graphics targetGraphics = paintEventArgs.Graphics;
Rectangle clipRectangle = paintEventArgs.ClipRectangle; Rectangle targetClipRectangle = paintEventArgs.ClipRectangle;
if (Rectangle.Empty.Equals(clipRectangle)) if (Rectangle.Empty.Equals(targetClipRectangle))
{ {
LOG.Debug("Empty cliprectangle??"); LOG.Debug("Empty cliprectangle??");
return; return;
} }
if (_elements.HasIntersectingFilters(clipRectangle)) // Correction to prevent rounding errors at certain zoom levels.
// When zooming to N/M, clip rectangle top and left coordinates should be multiples of N.
if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1)
{
int horizontalCorrection = targetClipRectangle.Left % (int)_zoomFactor.Numerator;
int verticalCorrection = targetClipRectangle.Top % (int)_zoomFactor.Numerator;
if (horizontalCorrection != 0)
{
targetClipRectangle.X -= horizontalCorrection;
targetClipRectangle.Width += horizontalCorrection;
}
if (verticalCorrection != 0)
{
targetClipRectangle.Y -= verticalCorrection;
targetClipRectangle.Height += verticalCorrection;
}
}
Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2);
if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity)
{ {
if (_buffer != null) if (_buffer != null)
{ {
@ -1420,18 +1495,44 @@ namespace Greenshot.Drawing
//graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
//graphics.CompositingQuality = CompositingQuality.HighQuality; //graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
DrawBackground(graphics, clipRectangle); DrawBackground(graphics, imageClipRectangle);
graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
graphics.SetClip(targetGraphics); graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2));
_elements.Draw(graphics, _buffer, RenderMode.EDIT, clipRectangle); _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle);
}
if (_zoomFactor == Fraction.Identity)
{
targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
}
else
{
targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor);
if (_zoomFactor > Fraction.Identity)
{
DrawSharpImage(targetGraphics, _buffer, imageClipRectangle);
}
else
{
DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle);
}
targetGraphics.ResetTransform();
} }
targetGraphics.DrawImage(_buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel);
} }
else else
{ {
DrawBackground(targetGraphics, clipRectangle); DrawBackground(targetGraphics, targetClipRectangle);
targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); if (_zoomFactor == Fraction.Identity)
_elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle); {
targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
_elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle);
}
else
{
targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor);
DrawSmoothImage(targetGraphics, Image, imageClipRectangle);
_elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle);
targetGraphics.ResetTransform();
}
} }
// No clipping for the adorners // No clipping for the adorners
@ -1446,6 +1547,32 @@ namespace Greenshot.Drawing
} }
} }
private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle)
{
var state = targetGraphics.Save();
targetGraphics.SmoothingMode = SmoothingMode.HighQuality;
targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
targetGraphics.CompositingQuality = CompositingQuality.HighQuality;
targetGraphics.PixelOffsetMode = PixelOffsetMode.None;
targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
targetGraphics.Restore(state);
}
private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle)
{
var state = targetGraphics.Save();
targetGraphics.SmoothingMode = SmoothingMode.None;
targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
targetGraphics.CompositingQuality = CompositingQuality.HighQuality;
targetGraphics.PixelOffsetMode = PixelOffsetMode.None;
targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel);
targetGraphics.Restore(state);
}
private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle)
{ {
// check if we need to draw the checkerboard // check if we need to draw the checkerboard
@ -1753,43 +1880,79 @@ namespace Greenshot.Drawing
} }
else if (ClipboardHelper.ContainsImage(clipboard)) else if (ClipboardHelper.ContainsImage(clipboard))
{ {
int x = 10; Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
int y = 10;
// FEATURE-995: Added a check for the current mouse cursor location, to paste the image on that location.
var mousePositionOnControl = PointToClient(MousePosition);
if (ClientRectangle.Contains(mousePositionOnControl))
{
x = mousePositionOnControl.X;
y = mousePositionOnControl.Y;
}
foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard))
{ {
if (clipboardImage != null) if (clipboardImage != null)
{ {
DeselectAllElements(); DeselectAllElements();
IImageContainer container = AddImageContainer(clipboardImage as Bitmap, x, y); IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y);
SelectElement(container); SelectElement(container);
clipboardImage.Dispose(); clipboardImage.Dispose();
x += 10; pasteLocation.X += 10;
y += 10; pasteLocation.Y += 10;
} }
} }
} }
else if (ClipboardHelper.ContainsText(clipboard)) else if (ClipboardHelper.ContainsText(clipboard))
{ {
Point pasteLocation = GetPasteLocation(0.4f, 0.4f);
string text = ClipboardHelper.GetText(clipboard); string text = ClipboardHelper.GetText(clipboard);
if (text != null) if (text != null)
{ {
DeselectAllElements(); DeselectAllElements();
ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER, ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y,
FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent);
SelectElement(textContainer); SelectElement(textContainer);
} }
} }
} }
/// <summary>
/// Find a location to paste elements.
/// If mouse is over the surface - use it's position, otherwise use the visible area.
/// Return a point in image coordinate space.
/// </summary>
/// <param name="horizontalRatio">0.0f for the left edge of visible area, 1.0f for the right edge of visible area.</param>
/// <param name="verticalRatio">0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area.</param>
private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f)
{
var point = PointToClient(MousePosition);
var rc = GetVisibleRectangle();
if (!rc.Contains(point))
{
point = new Point(
rc.Left + (int)(rc.Width * horizontalRatio),
rc.Top + (int)(rc.Height * verticalRatio)
);
}
return ToImageCoordinates(point);
}
/// <summary>
/// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space).
/// </summary>
public Rectangle GetVisibleRectangle()
{
var bounds = Bounds;
var clientArea = Parent.ClientRectangle;
return new Rectangle(
Math.Max(0, -bounds.Left),
Math.Max(0, -bounds.Top),
clientArea.Width,
clientArea.Height
);
}
/// <summary>
/// Get the rectangle bounding all selected elements (in surface coordinates space),
/// or empty rectangle if nothing is selcted.
/// </summary>
public Rectangle GetSelectionRectangle()
=> ToSurfaceCoordinates(selectedElements.DrawingBounds);
/// <summary> /// <summary>
/// Duplicate all the selecteded elements /// Duplicate all the selecteded elements
/// </summary> /// </summary>
@ -2045,5 +2208,57 @@ namespace Greenshot.Drawing
{ {
return _elements.Contains(container); return _elements.Contains(container);
} }
public Point ToSurfaceCoordinates(Point point)
{
Point[] points = { point };
_zoomMatrix.TransformPoints(points);
return points[0];
}
public Rectangle ToSurfaceCoordinates(Rectangle rc)
{
if (_zoomMatrix.IsIdentity)
{
return rc;
}
else
{
Point[] points = { rc.Location, rc.Location + rc.Size };
_zoomMatrix.TransformPoints(points);
return new Rectangle(
points[0].X,
points[0].Y,
points[1].X - points[0].X,
points[1].Y - points[0].Y
);
}
}
public Point ToImageCoordinates(Point point)
{
Point[] points = { point };
_inverseZoomMatrix.TransformPoints(points);
return points[0];
}
public Rectangle ToImageCoordinates(Rectangle rc)
{
if (_inverseZoomMatrix.IsIdentity)
{
return rc;
}
else
{
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
);
}
}
} }
} }

View file

@ -22,6 +22,7 @@
using Greenshot.Drawing.Fields; using Greenshot.Drawing.Fields;
using Greenshot.Helpers; using Greenshot.Helpers;
using Greenshot.Memento; using Greenshot.Memento;
using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces.Drawing; using GreenshotPlugin.Interfaces.Drawing;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -155,6 +156,24 @@ namespace Greenshot.Drawing
FieldChanged += TextContainer_FieldChanged; FieldChanged += TextContainer_FieldChanged;
} }
protected override void SwitchParent(Surface newParent)
{
_parent.SizeChanged -= Parent_SizeChanged;
base.SwitchParent(newParent);
_parent.SizeChanged += Parent_SizeChanged;
}
private void Parent_SizeChanged(object sender, EventArgs e)
{
UpdateTextBoxPosition();
UpdateTextBoxFont();
}
public override void ApplyBounds(RectangleF newBounds)
{
base.ApplyBounds(newBounds);
UpdateTextBoxPosition();
}
public override void Invalidate() public override void Invalidate()
{ {
@ -255,7 +274,8 @@ namespace Greenshot.Drawing
AcceptsTab = true, AcceptsTab = true,
AcceptsReturn = true, AcceptsReturn = true,
BorderStyle = BorderStyle.None, BorderStyle = BorderStyle.None,
Visible = false Visible = false,
Font = new Font(FontFamily.GenericSansSerif, 1) // just need something non-default here
}; };
_textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged); _textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged);
@ -388,7 +408,6 @@ namespace Greenshot.Drawing
var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize); var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
_font?.Dispose(); _font?.Dispose();
_font = newFont; _font = newFont;
_textBox.Font = _font;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -400,7 +419,6 @@ namespace Greenshot.Drawing
var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize); var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize);
_font?.Dispose(); _font?.Dispose();
_font = newFont; _font = newFont;
_textBox.Font = _font;
} }
catch (Exception) catch (Exception)
{ {
@ -413,6 +431,8 @@ namespace Greenshot.Drawing
} }
} }
UpdateTextBoxFont();
UpdateAlignment(); UpdateAlignment();
} }
@ -423,12 +443,34 @@ namespace Greenshot.Drawing
} }
/// <summary> /// <summary>
/// This will create the textbox exactly to the inner size of the element /// Set TextBox font according to the TextContainer font and the parent zoom factor.
/// </summary>
private void UpdateTextBoxFont()
{
if (_textBox == null || _font == null)
{
return;
}
var textBoxFontScale = _parent?.ZoomFactor ?? Fraction.Identity;
var newFont = new Font(
_font.FontFamily,
_font.Size * textBoxFontScale,
_font.Style,
GraphicsUnit.Pixel
);
_textBox.Font.Dispose();
_textBox.Font = newFont;
}
/// <summary>
/// This will align the textbox exactly to the inner size of the element
/// is a bit of a hack, but for now it seems to work... /// is a bit of a hack, but for now it seems to work...
/// </summary> /// </summary>
private void UpdateTextBoxPosition() private void UpdateTextBoxPosition()
{ {
if (_textBox == null) if (_textBox == null || Parent == null)
{ {
return; return;
} }
@ -442,22 +484,20 @@ namespace Greenshot.Drawing
correction = -1; correction = -1;
} }
Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height);
_textBox.Left = absRectangle.Left + lineWidth; Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle);
_textBox.Top = absRectangle.Top + lineWidth; _textBox.Left = displayRectangle.X + lineWidth;
_textBox.Top = displayRectangle.Y + lineWidth;
if (lineThickness <= 1) if (lineThickness <= 1)
{ {
lineWidth = 0; lineWidth = 0;
} }
_textBox.Width = absRectangle.Width - 2 * lineWidth + correction; _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction;
_textBox.Height = absRectangle.Height - 2 * lineWidth + correction; _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction;
}
public override void ApplyBounds(RectangleF newBounds)
{
base.ApplyBounds(newBounds);
UpdateTextBoxPosition();
} }
/// <summary>
/// Set TextBox text align and fore color according to field values.
/// </summary>
private void UpdateTextBoxFormat() private void UpdateTextBoxFormat()
{ {
if (_textBox == null) if (_textBox == null)

View file

@ -194,6 +194,26 @@ namespace Greenshot {
this.alignLeftToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.alignLeftToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem();
this.alignCenterToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.alignCenterToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem();
this.alignRightToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.alignRightToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem();
this.zoomMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.zoomInMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoomOutMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoomMenuSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.zoomBestFitMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoomMenuSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.zoom25MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoom50MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoom66MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoom75MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoomMenuSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.zoomActualSizeMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoomMenuSeparator4 = new System.Windows.Forms.ToolStripSeparator();
this.zoom200MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoom300MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoom400MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoom600MenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.zoomStatusDropDownBtn = new System.Windows.Forms.ToolStripDropDownButton();
this.zoomMainMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.statusStripSpacer = new System.Windows.Forms.ToolStripStatusLabel();
this.topToolStripContainer.BottomToolStripPanel.SuspendLayout(); this.topToolStripContainer.BottomToolStripPanel.SuspendLayout();
this.topToolStripContainer.ContentPanel.SuspendLayout(); this.topToolStripContainer.ContentPanel.SuspendLayout();
this.topToolStripContainer.LeftToolStripPanel.SuspendLayout(); this.topToolStripContainer.LeftToolStripPanel.SuspendLayout();
@ -203,6 +223,7 @@ namespace Greenshot {
this.tableLayoutPanel1.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout();
this.toolsToolStrip.SuspendLayout(); this.toolsToolStrip.SuspendLayout();
this.menuStrip1.SuspendLayout(); this.menuStrip1.SuspendLayout();
this.zoomMenuStrip.SuspendLayout();
this.destinationsToolStrip.SuspendLayout(); this.destinationsToolStrip.SuspendLayout();
this.propertiesToolStrip.SuspendLayout(); this.propertiesToolStrip.SuspendLayout();
this.fileSavedStatusContextMenu.SuspendLayout(); this.fileSavedStatusContextMenu.SuspendLayout();
@ -238,7 +259,9 @@ namespace Greenshot {
this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.dimensionsLabel, this.dimensionsLabel,
this.statusLabel}); this.statusLabel,
this.statusStripSpacer,
this.zoomStatusDropDownBtn});
this.statusStrip1.Location = new System.Drawing.Point(0, 0); this.statusStrip1.Location = new System.Drawing.Point(0, 0);
this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(785, 24); this.statusStrip1.Size = new System.Drawing.Size(785, 24);
@ -538,6 +561,7 @@ namespace Greenshot {
this.editToolStripMenuItem, this.editToolStripMenuItem,
this.objectToolStripMenuItem, this.objectToolStripMenuItem,
this.pluginToolStripMenuItem, this.pluginToolStripMenuItem,
this.zoomMainMenuItem,
this.helpToolStripMenuItem}); this.helpToolStripMenuItem});
this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.BackColor = System.Drawing.SystemColors.Control; this.menuStrip1.BackColor = System.Drawing.SystemColors.Control;
@ -1624,6 +1648,171 @@ namespace Greenshot {
this.alignRightToolStripMenuItem.Name = "alignRightToolStripMenuItem"; this.alignRightToolStripMenuItem.Name = "alignRightToolStripMenuItem";
this.alignRightToolStripMenuItem.Tag = System.Drawing.StringAlignment.Far; this.alignRightToolStripMenuItem.Tag = System.Drawing.StringAlignment.Far;
// //
// zoomMainMenuItem
//
this.zoomMainMenuItem.DropDown = this.zoomMenuStrip;
this.zoomMainMenuItem.Name = "zoomMainMenuItem";
this.zoomMainMenuItem.Size = new System.Drawing.Size(51, 20);
this.zoomMainMenuItem.Text = "Zoom";
//
// zoomMenuStrip
//
this.zoomMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.zoomInMenuItem,
this.zoomOutMenuItem,
this.zoomMenuSeparator1,
this.zoomBestFitMenuItem,
this.zoomMenuSeparator2,
this.zoom25MenuItem,
this.zoom50MenuItem,
this.zoom66MenuItem,
this.zoom75MenuItem,
this.zoomMenuSeparator3,
this.zoomActualSizeMenuItem,
this.zoomMenuSeparator4,
this.zoom200MenuItem,
this.zoom300MenuItem,
this.zoom400MenuItem,
this.zoom600MenuItem});
this.zoomMenuStrip.Name = "zoomMenuStrip";
this.zoomMenuStrip.Size = new System.Drawing.Size(210, 292);
//
// zoomInMenuItem
//
this.zoomInMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomInMenuItem.Image")));
this.zoomInMenuItem.Name = "zoomInMenuItem";
this.zoomInMenuItem.ShortcutKeyDisplayString = "Ctrl++";
this.zoomInMenuItem.Size = new System.Drawing.Size(209, 22);
this.zoomInMenuItem.Text = "Zoom In";
this.zoomInMenuItem.Click += new System.EventHandler(this.ZoomInMenuItemClick);
//
// zoomOutMenuItem
//
this.zoomOutMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomOutMenuItem.Image")));
this.zoomOutMenuItem.Name = "zoomOutMenuItem";
this.zoomOutMenuItem.ShortcutKeyDisplayString = "Ctrl+-";
this.zoomOutMenuItem.Size = new System.Drawing.Size(209, 22);
this.zoomOutMenuItem.Text = "Zoom Out";
this.zoomOutMenuItem.Click += new System.EventHandler(this.ZoomOutMenuItemClick);
//
// zoomMenuSeparator1
//
this.zoomMenuSeparator1.Name = "zoomMenuSeparator1";
this.zoomMenuSeparator1.Size = new System.Drawing.Size(206, 6);
//
// zoomBestFitMenuItem
//
this.zoomBestFitMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomBestFitMenuItem.Image")));
this.zoomBestFitMenuItem.Name = "zoomBestFitMenuItem";
this.zoomBestFitMenuItem.ShortcutKeyDisplayString = "Ctrl+9";
this.zoomBestFitMenuItem.Size = new System.Drawing.Size(209, 22);
this.zoomBestFitMenuItem.Text = "Best Fit";
this.zoomBestFitMenuItem.Click += new System.EventHandler(this.ZoomBestFitMenuItemClick);
//
// zoomMenuSeparator2
//
this.zoomMenuSeparator2.Name = "zoomMenuSeparator2";
this.zoomMenuSeparator2.Size = new System.Drawing.Size(206, 6);
//
// zoom25MenuItem
//
this.zoom25MenuItem.Name = "zoom25MenuItem";
this.zoom25MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom25MenuItem.Tag = "1/4";
this.zoom25MenuItem.Text = "25%";
this.zoom25MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoom50MenuItem
//
this.zoom50MenuItem.Name = "zoom50MenuItem";
this.zoom50MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom50MenuItem.Tag = "1/2";
this.zoom50MenuItem.Text = "50%";
this.zoom50MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoom66MenuItem
//
this.zoom66MenuItem.Name = "zoom66MenuItem";
this.zoom66MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom66MenuItem.Tag = "2/3";
this.zoom66MenuItem.Text = "66%";
this.zoom66MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoom75MenuItem
//
this.zoom75MenuItem.Name = "zoom75MenuItem";
this.zoom75MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom75MenuItem.Tag = "3/4";
this.zoom75MenuItem.Text = "75%";
this.zoom75MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoomMenuSeparator3
//
this.zoomMenuSeparator3.Name = "zoomMenuSeparator3";
this.zoomMenuSeparator3.Size = new System.Drawing.Size(206, 6);
//
// zoomActualSizeMenuItem
//
this.zoomActualSizeMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomActualSizeMenuItem.Image")));
this.zoomActualSizeMenuItem.Name = "zoomActualSizeMenuItem";
this.zoomActualSizeMenuItem.ShortcutKeyDisplayString = "Ctrl+0";
this.zoomActualSizeMenuItem.Size = new System.Drawing.Size(209, 22);
this.zoomActualSizeMenuItem.Tag = "1/1";
this.zoomActualSizeMenuItem.Text = "100% - Actual Size";
this.zoomActualSizeMenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoomMenuSeparator4
//
this.zoomMenuSeparator4.Name = "zoomMenuSeparator4";
this.zoomMenuSeparator4.Size = new System.Drawing.Size(206, 6);
//
// zoom200MenuItem
//
this.zoom200MenuItem.Name = "zoom200MenuItem";
this.zoom200MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom200MenuItem.Tag = "2/1";
this.zoom200MenuItem.Text = "200%";
this.zoom200MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoom300MenuItem
//
this.zoom300MenuItem.Name = "zoom300MenuItem";
this.zoom300MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom300MenuItem.Tag = "3/1";
this.zoom300MenuItem.Text = "300%";
this.zoom300MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoom400MenuItem
//
this.zoom400MenuItem.Name = "zoom400MenuItem";
this.zoom400MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom400MenuItem.Tag = "4/1";
this.zoom400MenuItem.Text = "400%";
this.zoom400MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// zoom600MenuItem
//
this.zoom600MenuItem.Name = "zoom600MenuItem";
this.zoom600MenuItem.Size = new System.Drawing.Size(209, 22);
this.zoom600MenuItem.Tag = "6/1";
this.zoom600MenuItem.Text = "600%";
this.zoom600MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick);
//
// statusStripSpacer
//
this.statusStripSpacer.Name = "statusStripSpacer";
this.statusStripSpacer.Size = new System.Drawing.Size(599, 19);
this.statusStripSpacer.Spring = true;
//
// zoomStatusDropDownBtn
//
this.zoomStatusDropDownBtn.DropDown = this.zoomMenuStrip;
this.zoomStatusDropDownBtn.Image = ((System.Drawing.Image)(resources.GetObject("zoomStatusDropDownBtn.Image")));
this.zoomStatusDropDownBtn.ImageTransparentColor = System.Drawing.Color.Magenta;
this.zoomStatusDropDownBtn.Name = "zoomStatusDropDownBtn";
this.zoomStatusDropDownBtn.Size = new System.Drawing.Size(64, 22);
this.zoomStatusDropDownBtn.Text = "100%";
//
// ImageEditorForm // ImageEditorForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@ -1645,6 +1834,7 @@ namespace Greenshot {
this.statusStrip1.ResumeLayout(true); this.statusStrip1.ResumeLayout(true);
this.tableLayoutPanel1.ResumeLayout(true); this.tableLayoutPanel1.ResumeLayout(true);
this.toolsToolStrip.ResumeLayout(true); this.toolsToolStrip.ResumeLayout(true);
this.zoomMenuStrip.ResumeLayout(false);
this.menuStrip1.ResumeLayout(true); this.menuStrip1.ResumeLayout(true);
this.destinationsToolStrip.ResumeLayout(true); this.destinationsToolStrip.ResumeLayout(true);
this.propertiesToolStrip.ResumeLayout(true); this.propertiesToolStrip.ResumeLayout(true);
@ -1794,5 +1984,25 @@ namespace Greenshot {
private Greenshot.Controls.ToolStripColorButton btnLineColor; private Greenshot.Controls.ToolStripColorButton btnLineColor;
private GreenshotPlugin.Controls.GreenshotToolStripMenuItem autoCropToolStripMenuItem; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem autoCropToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator17; private System.Windows.Forms.ToolStripSeparator toolStripSeparator17;
private System.Windows.Forms.ContextMenuStrip zoomMenuStrip;
private System.Windows.Forms.ToolStripMenuItem zoomInMenuItem;
private System.Windows.Forms.ToolStripMenuItem zoomOutMenuItem;
private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator1;
private System.Windows.Forms.ToolStripMenuItem zoomBestFitMenuItem;
private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator2;
private System.Windows.Forms.ToolStripMenuItem zoom25MenuItem;
private System.Windows.Forms.ToolStripMenuItem zoom50MenuItem;
private System.Windows.Forms.ToolStripMenuItem zoom66MenuItem;
private System.Windows.Forms.ToolStripMenuItem zoom75MenuItem;
private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator3;
private System.Windows.Forms.ToolStripMenuItem zoomActualSizeMenuItem;
private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator4;
private System.Windows.Forms.ToolStripMenuItem zoom200MenuItem;
private System.Windows.Forms.ToolStripMenuItem zoom300MenuItem;
private System.Windows.Forms.ToolStripMenuItem zoom400MenuItem;
private System.Windows.Forms.ToolStripMenuItem zoom600MenuItem;
private System.Windows.Forms.ToolStripDropDownButton zoomStatusDropDownBtn;
private System.Windows.Forms.ToolStripMenuItem zoomMainMenuItem;
private System.Windows.Forms.ToolStripStatusLabel statusStripSpacer;
} }
} }

View file

@ -66,6 +66,11 @@ namespace Greenshot {
// whether part of the editor controls are disabled depending on selected item(s) // whether part of the editor controls are disabled depending on selected item(s)
private bool _controlsDisabledDueToConfirmable; private bool _controlsDisabledDueToConfirmable;
/// <summary>
/// All provided zoom values (in percents) in ascending order.
/// </summary>
private readonly Fraction[] ZOOM_VALUES = new Fraction[] { (1, 4), (1, 2), (2, 3), (3, 4), (1 ,1), (2, 1), (3, 1), (4, 1), (6, 1) };
/// <summary> /// <summary>
/// An Implementation for the IImageEditor, this way Plugins have access to the HWND handles wich can be used with Win32 API calls. /// An Implementation for the IImageEditor, this way Plugins have access to the HWND handles wich can be used with Win32 API calls.
/// </summary> /// </summary>
@ -422,20 +427,14 @@ namespace Greenshot {
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private void SurfaceSizeChanged(object sender, EventArgs e) { private void SurfaceSizeChanged(object sender, EventArgs e)
if (EditorConfiguration.MatchSizeToCapture) { {
// Set editor's initial size to the size of the surface plus the size of the chrome if (EditorConfiguration.MatchSizeToCapture)
Size imageSize = Surface.Image.Size; {
Size currentFormSize = Size; Size = GetOptimalWindowSize();
Size currentImageClientSize = panel1.ClientSize;
int minimumFormWidth = 650;
int minimumFormHeight = 530;
int newWidth = Math.Max(minimumFormWidth, currentFormSize.Width - currentImageClientSize.Width + imageSize.Width);
int newHeight = Math.Max(minimumFormHeight, currentFormSize.Height - currentImageClientSize.Height + imageSize.Height);
Size = new Size(newWidth, newHeight);
} }
dimensionsLabel.Text = Surface.Image.Width + "x" + Surface.Image.Height; dimensionsLabel.Text = Surface.Image.Width + "x" + Surface.Image.Height;
ImageEditorFormResize(sender, new EventArgs()); AlignCanvasPositionAfterResize();
} }
public ISurface Surface { public ISurface Surface {
@ -862,15 +861,34 @@ namespace Greenshot {
case Keys.Oemcomma: // Rotate CCW Ctrl + , case Keys.Oemcomma: // Rotate CCW Ctrl + ,
RotateCcwToolstripButtonClick(sender, e); RotateCcwToolstripButtonClick(sender, e);
break; break;
case Keys.OemPeriod: // Rotate CW Ctrl + . case Keys.OemPeriod: // Rotate CW Ctrl + .
RotateCwToolstripButtonClick(sender, e); RotateCwToolstripButtonClick(sender, e);
break; break;
case Keys.Add: // Ctrl + + case Keys.Add: // Ctrl + Num+
case Keys.Oemplus: // Ctrl + + case Keys.Oemplus: // Ctrl + +
ZoomInMenuItemClick(sender, e);
break;
case Keys.Subtract: // Ctrl + Num-
case Keys.OemMinus: // Ctrl + -
ZoomOutMenuItemClick(sender, e);
break;
case Keys.NumPad0: // Ctrl + Num0
case Keys.D0: // Ctrl + 0
ZoomSetValueMenuItemClick(zoomActualSizeMenuItem, e);
break;
case Keys.NumPad9: // Ctrl + Num9
case Keys.D9: // Ctrl + 9
ZoomBestFitMenuItemClick(sender, e);
break;
}
} else if (e.Modifiers.Equals(Keys.Control | Keys.Shift)) {
switch (e.KeyCode) {
case Keys.Add: // Ctrl + Shift + Num+
case Keys.Oemplus: // Ctrl + Shift + +
EnlargeCanvasToolStripMenuItemClick(sender, e); EnlargeCanvasToolStripMenuItemClick(sender, e);
break; break;
case Keys.Subtract: // Ctrl + - case Keys.Subtract: // Ctrl + Shift + Num-
case Keys.OemMinus: // Ctrl + - case Keys.OemMinus: // Ctrl + Shift + -
ShrinkCanvasToolStripMenuItemClick(sender, e); ShrinkCanvasToolStripMenuItemClick(sender, e);
break; break;
} }
@ -1446,28 +1464,178 @@ namespace Greenshot {
} }
private void ImageEditorFormResize(object sender, EventArgs e) { private void ImageEditorFormResize(object sender, EventArgs e) {
AlignCanvasPositionAfterResize();
}
private void AlignCanvasPositionAfterResize() {
if (Surface?.Image == null || panel1 == null) { if (Surface?.Image == null || panel1 == null) {
return; return;
} }
Size imageSize = Surface.Image.Size;
Size currentClientSize = panel1.ClientSize;
var canvas = Surface as Control; var canvas = Surface as Control;
Size canvasSize = canvas.Size;
Size currentClientSize = panel1.ClientSize;
Panel panel = (Panel) canvas?.Parent; Panel panel = (Panel) canvas?.Parent;
if (panel == null) { if (panel == null) {
return; return;
} }
int offsetX = -panel.HorizontalScroll.Value; int offsetX = -panel.HorizontalScroll.Value;
int offsetY = -panel.VerticalScroll.Value; int offsetY = -panel.VerticalScroll.Value;
if (currentClientSize.Width > imageSize.Width) { if (currentClientSize.Width > canvasSize.Width) {
canvas.Left = offsetX + (currentClientSize.Width - imageSize.Width) / 2; canvas.Left = offsetX + (currentClientSize.Width - canvasSize.Width) / 2;
} else { } else {
canvas.Left = offsetX + 0; canvas.Left = offsetX + 0;
} }
if (currentClientSize.Height > imageSize.Height) { if (currentClientSize.Height > canvasSize.Height) {
canvas.Top = offsetY + (currentClientSize.Height - imageSize.Height) / 2; canvas.Top = offsetY + (currentClientSize.Height - canvasSize.Height) / 2;
} else { } else {
canvas.Top = offsetY + 0; canvas.Top = offsetY + 0;
} }
} }
/// <summary>
/// Compute a size as a sum of surface size and chrome.
/// Upper bound is working area of the screen. Lower bound is fixed value.
/// </summary>
private Size GetOptimalWindowSize() {
var surfaceSize = (Surface as Control).Size;
var chromeSize = GetChromeSize();
var newWidth = chromeSize.Width + surfaceSize.Width;
var newHeight = chromeSize.Height + surfaceSize.Height;
// Upper bound. Don't make it bigger than the available working area.
var maxWindowSize = GetAvailableScreenSpace();
newWidth = Math.Min(newWidth, maxWindowSize.Width);
newHeight = Math.Min(newHeight, maxWindowSize.Height);
// Lower bound. Don't make it smaller than a fixed value.
int minimumFormWidth = 650;
int minimumFormHeight = 530;
newWidth = Math.Max(minimumFormWidth, newWidth);
newHeight = Math.Max(minimumFormHeight, newHeight);
return new Size(newWidth, newHeight);
}
private Size GetChromeSize()
=> Size - panel1.ClientSize;
/// <summary>
/// Compute a size that the form can take without getting out of working area of the screen.
/// </summary>
private Size GetAvailableScreenSpace() {
var screen = Screen.FromControl(this);
var screenBounds = screen.Bounds;
var workingArea = screen.WorkingArea;
if (Left > screenBounds.Left && Top > screenBounds.Top) {
return new Size(workingArea.Right - Left, workingArea.Bottom - Top);
} else {
return workingArea.Size;
}
}
private void ZoomInMenuItemClick(object sender, EventArgs e) {
var zoomValue = Surface.ZoomFactor;
var nextIndex = Array.FindIndex(ZOOM_VALUES, v => v > zoomValue);
var nextValue = nextIndex < 0 ? ZOOM_VALUES[ZOOM_VALUES.Length - 1] : ZOOM_VALUES[nextIndex];
ZoomSetValue(nextValue);
}
private void ZoomOutMenuItemClick(object sender, EventArgs e) {
var zoomValue = Surface.ZoomFactor;
var nextIndex = Array.FindLastIndex(ZOOM_VALUES, v => v < zoomValue);
var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex];
ZoomSetValue(nextValue);
}
private void ZoomSetValueMenuItemClick(object sender, EventArgs e) {
var senderMenuItem = (ToolStripMenuItem)sender;
var nextValue = Fraction.Parse((string)senderMenuItem.Tag);
ZoomSetValue(nextValue);
}
private void ZoomBestFitMenuItemClick(object sender, EventArgs e) {
var maxWindowSize = GetAvailableScreenSpace();
var chromeSize = GetChromeSize();
var maxImageSize = maxWindowSize - chromeSize;
var imageSize = Surface.Image.Size;
static bool isFit(Fraction scale, int source, int boundary)
=> (int)(source * scale) <= boundary;
var nextIndex = Array.FindLastIndex(
ZOOM_VALUES,
zoom => isFit(zoom, imageSize.Width, maxImageSize.Width)
&& isFit(zoom, imageSize.Height, maxImageSize.Height)
);
var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex];
ZoomSetValue(nextValue);
}
private void ZoomSetValue(Fraction value) {
var surface = Surface as Surface;
var panel = surface?.Parent as Panel;
if (panel == null)
{
return;
}
if (value == Surface.ZoomFactor)
{
return;
}
// Store scroll position
var rc = surface.GetVisibleRectangle(); // use visible rc by default
var size = surface.Size;
if (value > Surface.ZoomFactor) // being smart on zoom-in
{
var selection = surface.GetSelectionRectangle();
selection.Intersect(rc);
if (selection != Rectangle.Empty)
{
rc = selection; // zoom to visible part of selection
}
else
{
// if image fits completely to currently visible rc and there are no things to focus on
// - prefer top left corner to zoom-in as less disorienting for screenshots
if (size.Width < rc.Width)
{
rc.Width = 0;
}
if (size.Height < rc.Height)
{
rc.Height = 0;
}
}
}
var horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width;
var verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height;
// Set the new zoom value
Surface.ZoomFactor = value;
Size = GetOptimalWindowSize();
AlignCanvasPositionAfterResize();
// Update zoom controls
zoomStatusDropDownBtn.Text = ((int)(100 * (double)value)).ToString() + "%";
var valueString = value.ToString();
foreach (var item in zoomMenuStrip.Items) {
if (item is ToolStripMenuItem menuItem) {
menuItem.Checked = menuItem.Tag as string == valueString;
}
}
// Restore scroll position
rc = surface.GetVisibleRectangle();
size = surface.Size;
panel.AutoScrollPosition = new Point(
(int)(horizontalCenter * size.Width) - rc.Width / 2,
(int)(verticalCenter * size.Height) - rc.Height / 2
);
}
} }
} }

View file

@ -937,6 +937,84 @@
BIhPAPEZIL7CAAQ6fptA+D+IJskFIM2cgtoMKm6rQfg/iEY3oB9oC8jWozBbgXquAvFykGYQkDJuZlBy BIhPAPEZIL7CAAQ6fptA+D+IJskFIM2cgtoMKm6rQfg/iEY3oB9oC8jWozBbgXquAvFykGYQkDJuZlBy
WQvC/0E0QRfANIJoLmF9BnXPHTD8H8QmyQD9wBMMSPg/iE20ATK6uQwWUTeR8X8Qn2gDHJOfM6Dh/yA+ WQvC/0E0QRfANIJoLmF9BnXPHTD8H8QmyQD9wBMMSPg/iE20ATK6uQwWUTeR8X8Qn2gDHJOfM6Dh/yA+
igHkZijqZSZyXQAA4IG1TpHFZ2gAAAAASUVORK5CYII= igHkZijqZSZyXQAA4IG1TpHFZ2gAAAAASUVORK5CYII=
</value>
</data>
<data name="zoomInMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJKSURBVDhPY/j//z+DX8FVDBxZ/ZAhqeWVRkrbm7lA
fB+If0HpuSBxkDxIHU4DIqruB0bXPrzftODpia0n3+668/zLiaNXPh3oXf7yFEgcJA9SBzbALeMsCvbI
Oq/hk3fx/rSND3ccufH60MuPP259+vb7+etPP28/evPt7PztT3b5AuVB6sAGWMUcQMdz83svnth96cWB
q48/ngBpBor9B9FP3n47d+3JpxMlEy6dAqkDG6Djtwkd35+77e72M/feXbj78suDd19+fQCK/QfRID5I
fOme+3tA6sAGqLitRse/dp5/fgCkGMj+j44/fvv97PC118eA7F9gA5Rc1qLj+wu239sNsgmk+Ofvv5+B
Yv9BNDgsPv68tWrfw0MgdWAD1D13oOO52W3nz+6/+urw/ZdfT4M0AcXgYQAMyHPF3RcvgdSBDXBwcGCw
s7NjsLW1ZbCxsWEwd8q0Mgo+/GLe5gdnbz77fBoU+mCbgfSz998vbtj/6pRxyMn7egHHILGAbIC1tbU8
0JDijsl7/ltFXnjVOOP5pZNXvpx+/u7H9VNXv5zpmPvymk3crfvmkdcDDYPPQNIBzACgRi03N/eaHTv2
/BcVFWtWs2qxc0x+PheI7wPxLyg91z7xiYZF1E0GFAOAtlsEBga3HTly5r+iolIPCwuLqpJxCYNTyisM
DDSAAcUAoO3eCQkpEy5evPtfT89gGlCzMRAzEG2Aubl5ya1br/7b2zvPY2VldQFpJskAPT09LRERkRag
5hiYZhAWlrEhzgDy8X8GAJItIDq7n94UAAAAAElFTkSuQmCC
</value>
</data>
<data name="zoomOutMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIySURBVDhPY/j//z+DtrY2g559IYNfwVU4jqx+yJDU
8kojpe3NXCC+D8S/oPRckDhIHqQObACyRhiOqLofGF378H7Tgqcntp58u+vO8y8njl75dKB3+ctTIHGQ
PEgd2AC3jLMo2CPrvIZP3sX70zY+3HHkxutDj958O/vk7bdzIAxiz9/+ZJcvUB6kDmyAVcwBdDw3v/fi
id2XXhy4+vjjCZhmGL725NOJkgmXToHUgQ3Q8duEju/P3XZ3+5l77y7cffnlAToGiS/dc38PSB3YABW3
1ej4187zzw+AFAPZ/9Hxx2+/nx2+9voYkP0LbICSy1p0fH/B9nu7QTaBFH/69vs5Mn798eetVfseHgKp
Axug7rkDHc/Nbjt/dv/VV4fvv/x6Gj0MgAF5rrj74iWQOrABDg4ODHZ2dgy2trYMNjY2DOZOmVZGwYdf
zNv84OzNZ59RDHj2/vvFDftfnTIOOXlfL+AYJBaQDbC2tpYHGlLcMXnPf6vIC68aZzy/dPLKl9PP3/24
furqlzMdc19es4m7dd888nqgYfAZSDqAGQDUqOXm5l6zY8ee/6KiYs1qVi12jsnP5wLxfSD+BaXn2ic+
0bCIusmAYgDQdovAwOC2I0fO/FdUVOphYWFRVTIuYXBKeYWBgQYwoBgAtN07ISFlwsWLd//r6RlMA2o2
BmIGog0wNzcvuXXr1X97e+d5rKysLiDNJBmgp6enJSIi0gLUHAPTDMLCMjbEGUA+/s8AAJUZIgOF4ptY
AAAAAElFTkSuQmCC
</value>
</data>
<data name="zoomBestFitMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJISURBVDhPnZLLaxNRFIfvIvkLTF0J0uAjNDKoWaTk
bS1RUYshLowWqZqFD/BBs/KxUEMoaKEgiJuRbqRQ6UaojTqUYGpJYmpMSFuMxklK2mmmmba2kzSZINd7
pk1p4qa6+Djn3vs73x24gzDGSKvVIsp6B3XcntzEdS+LLnt5jdtXoAksQdqoNOzDOeRkwdbBGufuso4L
D7Lso/7Z0HBYeP+DE0OfkiuB3oF8BPbhHHKywH51oo7j12OaUzfj7ADDhTJ8MbNclOZWSlUOgH5wdD50
mpxDThYYOgON0Ld646F0XsyQHgOFpYpcgZywNuPpS0QgJwsOdLxphKXfpkdAQHq8KErL0EOFNfSvGJaB
nCzYY3/diPQuxgUgmBfWMHx6Tih9gQrrX6XqXHBqYRxyskDdPtQI2z/y8wMISI8r1d+rMAwV1iAYHM1+
hJws2H/C3wh9wxebyC4UZ0iPAV4oyxVYKkpc95N4AnKywGazIYvFgsxmMzKZTEjfds1w2BmcH2JmvxdW
K5svAIjlKj8cLCR1Z8MsdWZ8/RW2CoxG424i6e55xmCD6yv/8AWXCCfFz9xieToyKUZ76PyU6WKK1bum
HYec0fX/oCYggy12+7H7fj+Dm5p2Pt5n8FqOXOFoAkuQNiptvZTTtJ7/huoE5PZWh8PpGxuL4uZm9VOF
QrFXrfOgNjf/F0SA6gTk9pNdXe6+eDyNKergczKsI6BtC/R6vSeV4rHVevSlUqlsh+F/ElAU1aJSqbxk
uLM2DOzYZdqe4P/B6A86Ah9NBTgWLgAAAABJRU5ErkJggg==
</value>
</data>
<data name="zoomActualSizeMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJXSURBVDhPnZLda1JhHMefC/0Lcl0FMelFZhwqLxy+
t4YV1UjsImvFKi+qQS9MuujlohIZ1GAQjG7O2k0ERdALpW3SZNpQ0zllall6NKwzj1OWczId8fT8zuaY
drO6+PBwvs/393kezjkIY4ykUimitNdQ19XoGqabGXTOyknMtjmawBBqqysNOexDjxesH6xz4gZjOHU7
w9wd+eF96yuMfmPL3o8zJdfA05wfctiHHi/QXwg2cPBSSHLkcpgZepVxeD7nJ+YXaz9LlWU2X6p+/T5X
CT62Z0ePkn3o8QJFt6sZ+spA2DsWmXVlC5VMrzWESYZBQp6nYtmS1zIY8UOPF+zqet0MQ79L2kEQSBWn
i+XaPMlwMldOQwY8cTJO6PGCbfrnzdTeh1i+CMDJJFu7AeCO5SehxwvEnS+aYUbsqTEY5n4tJarLvxdI
hmGF9wCCZx8yE9DjBTsPOZqhe22h4HiUc8+VqtnT1/2YZBhWuAV5kVN998MR6PECnU6HNBoNUqvVSKVS
IXnHRcVeo3t2+E06mOYW4zBUp7BQTb0c5/yy4z6GOja58hXWC5RK5VYi6et/6MQK0zR35xEb8c2UP7HF
pbg/Wg7007mY6kyCkZvihj3GwMp/UBeQwTa9/sAth8OJW1o239uhsGr2nWdpAkOora609mxW0n7yC2oQ
kNPbDQajzeMJ4NZW8QOBQLBdLLOgDjP3F0SAGgTk9MM9PebBcDiJKWr3EBmWEdCGBXK53JJIcFir3T8s
FAo7YfifBBRFtYlEIisZ7q4PA5u2qDYm+H8w+gNv9h/ta4LougAAAABJRU5ErkJggg==
</value>
</data>
<data name="zoomStatusDropDownBtn.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHYSURBVDhPY8AH4ltfa6S0vZ6b3Pr6PhD/AtEgPkgcqgQ3
iKi6Hxhd8/B+0/ynJ7acfLvrzrPPJ45c+Xigd9nLUyBxkDxUKSZwyzmj4Z176f7UjQ92HL7++tCjN9/O
Pn7z7RwIg9jztz3e5QOUB6mDakEFVjH75xb0Xjyx++KLA1cefToO0wzD1558OlE84eJpkDqoFlSg7bvp
/pytd3aADMCFl+6+vwekDqoFFSi7rf614/xzuGJ0Fzx+++3soauvjoHUQbWgAiXnNffn77i3G6wZqBib
ASv3PTgEUgfVggrUPLfPzWo/d3bv5VeH77/4fBrdgEevv54r7rpwCaQOqgUVWDpmWhkGHXoxf/P9szef
fkIx4Nn7b5fW73t5yjj45H2doKOYsWBpaSlvbW1d3DF5z3/LyAuvGqY/vXTiyqfTz999v37qyucz7fNe
XrOOvXXfNOIaZjqwsbHRcnV1r9mxY89/UVHRZlXLZjuH5GdzHZOf3XdMevYLRIP49vFPMW0G2moRGBjc
duTImf8KCko9bGxsqlApwgBos098fPKEixfv/tfT05/KyspqDJUiDpiZmZXcuvXqv52d8zxmZmYXqDDx
wMDAQEtYWLgFaHMMVIhegIEBADK7VwLsrsplAAAAAElFTkSuQmCC
</value> </value>
</data> </data>
<data name="btnStepLabel01.Image" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="btnStepLabel01.Image" type="System.Resources.ResXFileRef, System.Windows.Forms">
@ -1026,4 +1104,7 @@
<metadata name="fileSavedStatusContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="fileSavedStatusContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
<metadata name="zoomMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>782, 17</value>
</metadata>
</root> </root>

View file

@ -17,7 +17,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Tools.InnoSetup" version="6.0.3" GeneratePathProperty="true" /> <PackageReference Include="Tools.InnoSetup" version="6.0.4" GeneratePathProperty="true" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

File diff suppressed because it is too large Load diff

View file

@ -95,7 +95,7 @@ namespace GreenshotOfficePlugin.OfficeExport
var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings); ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings);
var base64String = Convert.ToBase64String(pngStream.GetBuffer()); var base64String = Convert.ToBase64String(pngStream.GetBuffer());
var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Width, surfaceToUpload.Height); var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height);
var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name); var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name);
LOG.InfoFormat("Sending XML: {0}", pageChangesXml); LOG.InfoFormat("Sending XML: {0}", pageChangesXml);
oneNoteApplication.ComObject.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false); oneNoteApplication.ComObject.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false);

View file

@ -0,0 +1,152 @@
using System;
using System.Text.RegularExpressions;
namespace GreenshotPlugin.Core
{
/// <summary>
/// Basic Fraction (Rational) numbers with features only needed to represent scale factors.
/// </summary>
public readonly struct Fraction : IEquatable<Fraction>, IComparable<Fraction>
{
public static Fraction Identity { get; } = new Fraction(1, 1);
public uint Numerator { get; }
public uint Denominator { get; }
public Fraction(uint numerator, uint denominator)
{
if (denominator == 0)
{
throw new ArgumentException("Can't divide by zero.", nameof(denominator));
}
if (numerator == 0)
{
throw new ArgumentException("Zero is not supported by this implementation.", nameof(numerator));
}
var gcd = GreatestCommonDivisor(numerator, denominator);
Numerator = numerator / gcd;
Denominator = denominator / gcd;
}
public Fraction Inverse()
=> new Fraction(Denominator, Numerator);
#region Parse
private static readonly Regex PARSE_REGEX = new Regex(@"^([1-9][0-9]*)\/([1-9][0-9]*)$", RegexOptions.Compiled);
public static bool TryParse(string str, out Fraction result)
{
var match = PARSE_REGEX.Match(str);
if (!match.Success)
{
result = Identity;
return false;
}
var numerator = uint.Parse(match.Groups[1].Value);
var denominator = uint.Parse(match.Groups[2].Value);
result = new Fraction(numerator, denominator);
return true;
}
public static Fraction Parse(string str)
=> TryParse(str, out var result)
? result
: throw new ArgumentException($"Could not parse the input \"{str}\".", nameof(str));
#endregion
#region Overrides, interface implementations
public override string ToString()
=> $"{Numerator}/{Denominator}";
public override bool Equals(object obj)
=> obj is Fraction fraction && Equals(fraction);
public bool Equals(Fraction other)
=> Numerator == other.Numerator && Denominator == other.Denominator;
public override int GetHashCode()
{
unchecked
{
int hashCode = -1534900553;
hashCode = hashCode * -1521134295 + Numerator.GetHashCode();
hashCode = hashCode * -1521134295 + Denominator.GetHashCode();
return hashCode;
}
}
public int CompareTo(Fraction other)
=> (int)(Numerator * other.Denominator) - (int)(other.Numerator * Denominator);
#endregion
#region Equality operators
public static bool operator ==(Fraction left, Fraction right)
=> left.Equals(right);
public static bool operator !=(Fraction left, Fraction right)
=> !(left == right);
#endregion
#region Comparison operators
public static bool operator <(Fraction left, Fraction right)
=> left.CompareTo(right) < 0;
public static bool operator <=(Fraction left, Fraction right)
=> left.CompareTo(right) <= 0;
public static bool operator >(Fraction left, Fraction right)
=> left.CompareTo(right) > 0;
public static bool operator >=(Fraction left, Fraction right)
=> left.CompareTo(right) >= 0;
#endregion
#region Scale operators
public static Fraction operator *(Fraction left, Fraction right)
=> new Fraction(left.Numerator * right.Numerator, left.Denominator * right.Denominator);
public static Fraction operator *(Fraction left, uint right)
=> new Fraction(left.Numerator * right, left.Denominator);
public static Fraction operator *(uint left, Fraction right)
=> new Fraction(left * right.Numerator, right.Denominator);
public static Fraction operator /(Fraction left, Fraction right)
=> new Fraction(left.Numerator * right.Denominator, left.Denominator * right.Numerator);
public static Fraction operator /(Fraction left, uint right)
=> new Fraction(left.Numerator, left.Denominator * right);
public static Fraction operator /(uint left, Fraction right)
=> new Fraction(left * right.Denominator, right.Numerator);
#endregion
#region Type conversion operators
public static implicit operator double(Fraction fraction)
=> 1.0 * fraction.Numerator / fraction.Denominator;
public static implicit operator float(Fraction fraction)
=> 1.0f * fraction.Numerator / fraction.Denominator;
public static implicit operator Fraction(uint number)
=> new Fraction(number, 1u);
public static implicit operator Fraction((uint numerator, uint demoninator) tuple)
=> new Fraction(tuple.numerator, tuple.demoninator);
#endregion
private static uint GreatestCommonDivisor(uint a, uint b)
=> (b != 0) ? GreatestCommonDivisor(b, a % b) : a;
}
}

View file

@ -41,7 +41,7 @@ namespace GreenshotPlugin.Core
public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6; public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6;
public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1; public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1;
/// <summary> /// <summary>
/// Test if the current OS is Windows 8.0 /// Test if the current OS is Windows 8.0
/// </summary> /// </summary>
@ -102,6 +102,11 @@ namespace GreenshotPlugin.Core
/// <returns>true if we are running on Windows XP or later</returns> /// <returns>true if we are running on Windows XP or later</returns>
public static bool IsWindowsXpOrLater { get; } = WinVersion.Major >= 5 || WinVersion.Major == 5 && WinVersion.Minor >= 1; public static bool IsWindowsXpOrLater { get; } = WinVersion.Major >= 5 || WinVersion.Major == 5 && WinVersion.Minor >= 1;
/// <summary>
/// Returns the windows build number
/// </summary>
public static int BuildVersion => WinVersion.Build;
/// <summary> /// <summary>
/// Test if the current Windows version is 10 and the build number or later /// Test if the current Windows version is 10 and the build number or later
/// See the build numbers <a href="https://en.wikipedia.org/wiki/Windows_10_version_history">here</a> /// See the build numbers <a href="https://en.wikipedia.org/wiki/Windows_10_version_history">here</a>

View file

@ -15,7 +15,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="0.10.9" /> <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="0.10.9" />
<PackageReference Include="log4net" version="2.0.8" /> <PackageReference Include="log4net" version="2.0.8" />
<PackageReference Include="Svg" Version="3.0.102" /> <PackageReference Include="Svg" Version="3.1.1" />
<Reference Include="Accessibility" /> <Reference Include="Accessibility" />
<Reference Include="CustomMarshalers" /> <Reference Include="CustomMarshalers" />
</ItemGroup> </ItemGroup>

View file

@ -102,7 +102,6 @@ namespace GreenshotPlugin.Interfaces.Drawing
get; get;
set; set;
} }
void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment);
void Invalidate(); void Invalidate();
bool ClickableAt(int x, int y); bool ClickableAt(int x, int y);
void MoveBy(int x, int y); void MoveBy(int x, int y);
@ -152,6 +151,10 @@ namespace GreenshotPlugin.Interfaces.Drawing
get; get;
set; set;
} }
Rectangle DrawingBounds
{
get;
}
void MakeBoundsChangeUndoable(bool allowMerge); void MakeBoundsChangeUndoable(bool allowMerge);
void Transform(Matrix matrix); void Transform(Matrix matrix);
void MoveBy(int dx, int dy); void MoveBy(int dx, int dy);

View file

@ -23,6 +23,7 @@ using System;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using GreenshotPlugin.Core;
using GreenshotPlugin.Effects; using GreenshotPlugin.Effects;
using GreenshotPlugin.Interfaces.Drawing; using GreenshotPlugin.Interfaces.Drawing;
@ -84,8 +85,8 @@ namespace GreenshotPlugin.Interfaces
/// The TextContainer will be "re"sized to the text size. /// The TextContainer will be "re"sized to the text size.
/// </summary> /// </summary>
/// <param name="text">String to show</param> /// <param name="text">String to show</param>
/// <param name="horizontalAlignment">Left, Center, Right</param> /// <param name="x">Where to put the container, X coordinate in the Image coordinate space</param>
/// <param name="verticalAlignment">TOP, CENTER, BOTTOM</param> /// <param name="y">Where to put the container, Y coordinate in the Image coordinate space</param>
/// <param name="family">FontFamily</param> /// <param name="family">FontFamily</param>
/// <param name="size">Font Size in float</param> /// <param name="size">Font Size in float</param>
/// <param name="italic">bool true if italic</param> /// <param name="italic">bool true if italic</param>
@ -94,7 +95,7 @@ namespace GreenshotPlugin.Interfaces
/// <param name="borderSize">size of border (0 for none)</param> /// <param name="borderSize">size of border (0 for none)</param>
/// <param name="color">Color of string</param> /// <param name="color">Color of string</param>
/// <param name="fillColor">Color of background (e.g. Color.Transparent)</param> /// <param name="fillColor">Color of background (e.g. Color.Transparent)</param>
ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor); ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor);
IImageContainer AddImageContainer(Image image, int x, int y); IImageContainer AddImageContainer(Image image, int x, int y);
ICursorContainer AddCursorContainer(Cursor cursor, int x, int y); ICursorContainer AddCursorContainer(Cursor cursor, int x, int y);
@ -147,8 +148,13 @@ namespace GreenshotPlugin.Interfaces
/// <param name="container"></param> /// <param name="container"></param>
/// <returns>This returns false if the container is deleted but still in the undo stack</returns> /// <returns>This returns false if the container is deleted but still in the undo stack</returns>
bool IsOnSurface(IDrawableContainer container); bool IsOnSurface(IDrawableContainer container);
void Invalidate(Rectangle rectangleToInvalidate);
void Invalidate(); void Invalidate();
/// <summary>
/// Invalidates the specified region of the Surface.
/// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image.
/// </summary>
/// <param name="rectangleToInvalidate">Bounding rectangle for updated elements, in the coordinate space of the Image.</param>
void InvalidateElements(Rectangle rectangleToInvalidate);
bool Modified bool Modified
{ {
get; get;
@ -186,9 +192,32 @@ namespace GreenshotPlugin.Interfaces
get; get;
set; set;
} }
int Width { get; }
int Height { get; } /// <summary>
/// Zoom value applied to the surface.
/// </summary>
Fraction ZoomFactor { get; set; }
/// <summary>
/// Translate a point from image coorditate space to surface coordinate space.
/// </summary>
/// <param name="point">A point in the coordinate space of the image.</param>
Point ToSurfaceCoordinates(Point point);
/// <summary>
/// Translate a rectangle from image coorditate space to surface coordinate space.
/// </summary>
/// <param name="rc">A rectangle in the coordinate space of the image.</param>
Rectangle ToSurfaceCoordinates(Rectangle rc);
/// <summary>
/// Translate a point from surface coorditate space to image coordinate space.
/// </summary>
/// <param name="point">A point in the coordinate space of the surface.</param>
Point ToImageCoordinates(Point point);
/// <summary>
/// Translate a rectangle from surface coorditate space to image coordinate space.
/// </summary>
/// <param name="rc">A rectangle in the coordinate space of the surface.</param>
Rectangle ToImageCoordinates(Rectangle rc);
void MakeUndoable(IMemento memento, bool allowMerge); void MakeUndoable(IMemento memento, bool allowMerge);
} }
} }

View file

@ -35,7 +35,9 @@ namespace GreenshotWin10Plugin
[Plugin("Win10", false)] [Plugin("Win10", false)]
public sealed class Win10Plugin : IGreenshotPlugin public sealed class Win10Plugin : IGreenshotPlugin
{ {
public void Dispose() private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10Plugin));
public void Dispose()
{ {
Dispose(true); Dispose(true);
} }
@ -58,8 +60,10 @@ namespace GreenshotWin10Plugin
/// <returns>true if plugin is initialized, false if not (doesn't show)</returns> /// <returns>true if plugin is initialized, false if not (doesn't show)</returns>
public bool Initialize() public bool Initialize()
{ {
if (!WindowsVersion.IsWindows10OrLater) // Here we check if the build version of Windows is actually what we support
if (!WindowsVersion.IsWindows10BuildOrLater(17763))
{ {
Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion);
return false; return false;
} }